firebase-tools 11.3.0 → 11.4.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/README.md +8 -15
- package/lib/apiv2.js +5 -0
- package/lib/checkValidTargetFilters.js +3 -2
- package/lib/command.js +1 -0
- package/lib/commands/hosting-clone.js +5 -0
- package/lib/commands/login-ci.js +2 -0
- package/lib/database/rulesConfig.js +35 -8
- package/lib/deploy/functions/backend.js +6 -4
- package/lib/deploy/functions/build.js +107 -95
- package/lib/deploy/functions/ensure.js +1 -1
- package/lib/deploy/functions/params.js +5 -2
- package/lib/deploy/functions/prepare.js +3 -3
- package/lib/deploy/functions/pricing.js +3 -2
- package/lib/deploy/functions/prompts.js +1 -1
- package/lib/deploy/functions/release/fabricator.js +8 -7
- package/lib/deploy/functions/release/index.js +4 -0
- package/lib/deploy/functions/runtimes/discovery/parsing.js +19 -8
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +115 -107
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +53 -21
- package/lib/deploy/functions/services/storage.js +6 -0
- package/lib/deploy/hosting/convertConfig.js +87 -16
- package/lib/deploy/hosting/deploy.js +1 -1
- package/lib/deploy/index.js +1 -1
- package/lib/deploy/storage/prepare.js +29 -6
- package/lib/emulator/controller.js +0 -1
- package/lib/emulator/functionsEmulator.js +3 -0
- package/lib/emulator/functionsEmulatorRuntime.js +1 -1
- package/lib/emulator/functionsEmulatorShared.js +6 -11
- package/lib/emulator/storage/files.js +19 -22
- package/lib/emulator/storage/metadata.js +6 -6
- package/lib/emulator/storage/persistence.js +26 -12
- package/lib/extensions/displayExtensionInfo.js +1 -101
- package/lib/extensions/emulator/triggerHelper.js +2 -2
- package/lib/extensions/updateHelper.js +1 -7
- package/lib/functional.js +16 -1
- package/lib/functions/env.js +47 -2
- package/lib/gcp/cloudfunctions.js +21 -8
- package/lib/gcp/cloudfunctionsv2.js +43 -19
- package/lib/gcp/cloudscheduler.js +25 -13
- package/lib/gcp/cloudtasks.js +4 -3
- package/lib/gcp/iam.js +20 -17
- package/lib/gcp/proto.js +18 -6
- package/lib/gcp/resourceManager.js +25 -3
- package/lib/index.js +1 -1
- package/lib/previews.js +1 -1
- package/lib/rc.js +3 -9
- package/lib/requireAuth.js +4 -0
- package/lib/rulesDeploy.js +40 -3
- package/npm-shrinkwrap.json +48 -37
- package/package.json +7 -4
|
@@ -23,35 +23,46 @@ function assertKeyTypes(prefix, yaml, schema) {
|
|
|
23
23
|
if (!schema[key] || schema[key] === "omit") {
|
|
24
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
|
+
let schemaType = schema[key];
|
|
27
27
|
if (typeof schemaType === "function") {
|
|
28
28
|
if (!schemaType(value)) {
|
|
29
|
-
|
|
29
|
+
const friendlyName = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
30
|
+
throw new error_1.FirebaseError(`${friendlyName} ${fullKey} failed validation`);
|
|
30
31
|
}
|
|
32
|
+
continue;
|
|
31
33
|
}
|
|
32
|
-
|
|
34
|
+
if (value === null) {
|
|
35
|
+
if (schemaType.endsWith("?")) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
throw new error_1.FirebaseError(`Expected ${fullKey}} to be type ${schemaType}; was null`);
|
|
39
|
+
}
|
|
40
|
+
if (schemaType.endsWith("?")) {
|
|
41
|
+
schemaType = schemaType.slice(0, schemaType.length - 1);
|
|
42
|
+
}
|
|
43
|
+
if (schemaType === "string") {
|
|
33
44
|
if (typeof value !== "string") {
|
|
34
|
-
throw new error_1.FirebaseError(`Expected ${fullKey} to be string; was ${typeof value}`);
|
|
45
|
+
throw new error_1.FirebaseError(`Expected ${fullKey} to be type string; was ${typeof value}`);
|
|
35
46
|
}
|
|
36
47
|
}
|
|
37
48
|
else if (schemaType === "number") {
|
|
38
49
|
if (typeof value !== "number") {
|
|
39
|
-
throw new error_1.FirebaseError(`Expected ${fullKey} to be
|
|
50
|
+
throw new error_1.FirebaseError(`Expected ${fullKey} to be type number; was ${typeof value}`);
|
|
40
51
|
}
|
|
41
52
|
}
|
|
42
53
|
else if (schemaType === "boolean") {
|
|
43
54
|
if (typeof value !== "boolean") {
|
|
44
|
-
throw new error_1.FirebaseError(`Expected ${fullKey} to be
|
|
55
|
+
throw new error_1.FirebaseError(`Expected ${fullKey} to be type boolean; was ${typeof value}`);
|
|
45
56
|
}
|
|
46
57
|
}
|
|
47
58
|
else if (schemaType === "array") {
|
|
48
59
|
if (!Array.isArray(value)) {
|
|
49
|
-
throw new error_1.FirebaseError(`Expected ${fullKey} to be
|
|
60
|
+
throw new error_1.FirebaseError(`Expected ${fullKey} to be type array; was ${typeof value}`);
|
|
50
61
|
}
|
|
51
62
|
}
|
|
52
63
|
else if (schemaType === "object") {
|
|
53
64
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
54
|
-
throw new error_1.FirebaseError(`Expected ${fullKey} to be
|
|
65
|
+
throw new error_1.FirebaseError(`Expected ${fullKey} to be type object; was ${typeof value}`);
|
|
55
66
|
}
|
|
56
67
|
}
|
|
57
68
|
else {
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
-
var t = {};
|
|
4
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
-
t[p] = s[p];
|
|
6
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
-
t[p[i]] = s[p[i]];
|
|
10
|
-
}
|
|
11
|
-
return t;
|
|
12
|
-
};
|
|
13
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
3
|
exports.backendFromV1Alpha1 = exports.buildFromV1Alpha1 = void 0;
|
|
15
4
|
const backend = require("../../backend");
|
|
@@ -17,6 +6,7 @@ const build = require("../../build");
|
|
|
17
6
|
const proto_1 = require("../../../../gcp/proto");
|
|
18
7
|
const parsing_1 = require("./parsing");
|
|
19
8
|
const error_1 = require("../../../../error");
|
|
9
|
+
const functional_1 = require("../../../../functional");
|
|
20
10
|
const CHANNEL_NAME_REGEX = new RegExp("(projects\\/" +
|
|
21
11
|
"(?<project>(?:\\d+)|(?:[A-Za-z]+[A-Za-z\\d-]*[A-Za-z\\d]?))\\/)?" +
|
|
22
12
|
"locations\\/" +
|
|
@@ -28,10 +18,12 @@ function buildFromV1Alpha1(yaml, project, region, runtime) {
|
|
|
28
18
|
(0, parsing_1.requireKeys)("", manifest, "endpoints");
|
|
29
19
|
(0, parsing_1.assertKeyTypes)("", manifest, {
|
|
30
20
|
specVersion: "string",
|
|
21
|
+
params: "array",
|
|
31
22
|
requiredAPIs: "array",
|
|
32
23
|
endpoints: "object",
|
|
33
24
|
});
|
|
34
25
|
const bd = build.empty();
|
|
26
|
+
bd.params = manifest.params || [];
|
|
35
27
|
bd.requiredAPIs = parseRequiredAPIs(manifest);
|
|
36
28
|
for (const id of Object.keys(manifest.endpoints)) {
|
|
37
29
|
const me = manifest.endpoints[id];
|
|
@@ -49,6 +41,7 @@ function backendFromV1Alpha1(yaml, project, region, runtime) {
|
|
|
49
41
|
(0, parsing_1.requireKeys)("", manifest, "endpoints");
|
|
50
42
|
(0, parsing_1.assertKeyTypes)("", manifest, {
|
|
51
43
|
specVersion: "string",
|
|
44
|
+
params: "array",
|
|
52
45
|
requiredAPIs: "array",
|
|
53
46
|
endpoints: "object",
|
|
54
47
|
});
|
|
@@ -79,29 +72,30 @@ function assertManifestEndpoint(ep, id) {
|
|
|
79
72
|
region: "array",
|
|
80
73
|
platform: (platform) => backend.AllFunctionsPlatforms.includes(platform),
|
|
81
74
|
entryPoint: "string",
|
|
82
|
-
availableMemoryMb: (mem) => backend.
|
|
83
|
-
maxInstances: "number",
|
|
84
|
-
minInstances: "number",
|
|
85
|
-
concurrency: "number",
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
75
|
+
availableMemoryMb: (mem) => mem === null || backend.isValidMemoryOption(mem),
|
|
76
|
+
maxInstances: "number?",
|
|
77
|
+
minInstances: "number?",
|
|
78
|
+
concurrency: "number?",
|
|
79
|
+
serviceAccount: "string?",
|
|
80
|
+
serviceAccountEmail: "string?",
|
|
81
|
+
timeoutSeconds: "number?",
|
|
82
|
+
vpc: "object?",
|
|
83
|
+
labels: "object?",
|
|
84
|
+
ingressSettings: (setting) => setting === null || backend.AllIngressSettings.includes(setting),
|
|
85
|
+
environmentVariables: "object?",
|
|
86
|
+
secretEnvironmentVariables: "array?",
|
|
93
87
|
httpsTrigger: "object",
|
|
94
88
|
callableTrigger: "object",
|
|
95
89
|
eventTrigger: "object",
|
|
96
90
|
scheduleTrigger: "object",
|
|
97
91
|
taskQueueTrigger: "object",
|
|
98
92
|
blockingTrigger: "object",
|
|
99
|
-
cpu: (cpu) => typeof cpu === "number" || cpu === "gcf_gen1",
|
|
93
|
+
cpu: (cpu) => cpu === null || typeof cpu === "number" || cpu === "gcf_gen1",
|
|
100
94
|
});
|
|
101
95
|
if (ep.vpc) {
|
|
102
96
|
(0, parsing_1.assertKeyTypes)(prefix + ".vpc", ep.vpc, {
|
|
103
97
|
connector: "string",
|
|
104
|
-
egressSettings: (setting) => backend.AllVpcEgressSettings.includes(setting),
|
|
98
|
+
egressSettings: (setting) => setting === null || backend.AllVpcEgressSettings.includes(setting),
|
|
105
99
|
});
|
|
106
100
|
(0, parsing_1.requireKeys)(prefix + ".vpc", ep.vpc, "connector");
|
|
107
101
|
}
|
|
@@ -138,13 +132,14 @@ function assertManifestEndpoint(ep, id) {
|
|
|
138
132
|
eventType: "string",
|
|
139
133
|
retry: "boolean",
|
|
140
134
|
region: "string",
|
|
141
|
-
|
|
135
|
+
serviceAccount: "string?",
|
|
136
|
+
serviceAccountEmail: "string?",
|
|
142
137
|
channel: "string",
|
|
143
138
|
});
|
|
144
139
|
}
|
|
145
140
|
else if (backend.isHttpsTriggered(ep)) {
|
|
146
141
|
(0, parsing_1.assertKeyTypes)(prefix + ".httpsTrigger", ep.httpsTrigger, {
|
|
147
|
-
invoker: "array",
|
|
142
|
+
invoker: "array?",
|
|
148
143
|
});
|
|
149
144
|
}
|
|
150
145
|
else if (backend.isCallableTriggered(ep)) {
|
|
@@ -152,36 +147,39 @@ function assertManifestEndpoint(ep, id) {
|
|
|
152
147
|
else if (backend.isScheduleTriggered(ep)) {
|
|
153
148
|
(0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger", ep.scheduleTrigger, {
|
|
154
149
|
schedule: "string",
|
|
155
|
-
timeZone: "string",
|
|
156
|
-
retryConfig: "object",
|
|
150
|
+
timeZone: "string?",
|
|
151
|
+
retryConfig: "object?",
|
|
157
152
|
});
|
|
158
|
-
(0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger.retryConfig", ep.scheduleTrigger.retryConfig, {
|
|
159
|
-
retryCount: "number",
|
|
160
|
-
maxDoublings: "number",
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
153
|
+
(0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger.retryConfig", ep.scheduleTrigger.retryConfig || {}, {
|
|
154
|
+
retryCount: "number?",
|
|
155
|
+
maxDoublings: "number?",
|
|
156
|
+
minBackoffSeconds: "number?",
|
|
157
|
+
maxBackoffSeconds: "number?",
|
|
158
|
+
maxRetrySeconds: "number?",
|
|
159
|
+
minBackoffDuration: "string?",
|
|
160
|
+
maxBackoffDuration: "string?",
|
|
161
|
+
maxRetryDuration: "string?",
|
|
164
162
|
});
|
|
165
163
|
}
|
|
166
164
|
else if (backend.isTaskQueueTriggered(ep)) {
|
|
167
165
|
(0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger", ep.taskQueueTrigger, {
|
|
168
|
-
rateLimits: "object",
|
|
169
|
-
retryConfig: "object",
|
|
170
|
-
invoker: "array",
|
|
166
|
+
rateLimits: "object?",
|
|
167
|
+
retryConfig: "object?",
|
|
168
|
+
invoker: "array?",
|
|
171
169
|
});
|
|
172
170
|
if (ep.taskQueueTrigger.rateLimits) {
|
|
173
171
|
(0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger.rateLimits", ep.taskQueueTrigger.rateLimits, {
|
|
174
|
-
maxConcurrentDispatches: "number",
|
|
175
|
-
maxDispatchesPerSecond: "number",
|
|
172
|
+
maxConcurrentDispatches: "number?",
|
|
173
|
+
maxDispatchesPerSecond: "number?",
|
|
176
174
|
});
|
|
177
175
|
}
|
|
178
176
|
if (ep.taskQueueTrigger.retryConfig) {
|
|
179
177
|
(0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger.retryConfig", ep.taskQueueTrigger.retryConfig, {
|
|
180
|
-
maxAttempts: "number",
|
|
181
|
-
maxRetrySeconds: "number",
|
|
182
|
-
minBackoffSeconds: "number",
|
|
183
|
-
maxBackoffSeconds: "number",
|
|
184
|
-
maxDoublings: "number",
|
|
178
|
+
maxAttempts: "number?",
|
|
179
|
+
maxRetrySeconds: "number?",
|
|
180
|
+
minBackoffSeconds: "number?",
|
|
181
|
+
maxBackoffSeconds: "number?",
|
|
182
|
+
maxDoublings: "number?",
|
|
185
183
|
});
|
|
186
184
|
}
|
|
187
185
|
}
|
|
@@ -198,18 +196,24 @@ function assertManifestEndpoint(ep, id) {
|
|
|
198
196
|
}
|
|
199
197
|
}
|
|
200
198
|
function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
|
|
199
|
+
var _a;
|
|
201
200
|
let triggered;
|
|
202
201
|
if (backend.isEventTriggered(ep)) {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
(0, proto_1.renameIfPresent)(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
202
|
+
const eventTrigger = {
|
|
203
|
+
eventType: ep.eventTrigger.eventType,
|
|
204
|
+
retry: ep.eventTrigger.retry,
|
|
205
|
+
};
|
|
206
|
+
(0, proto_1.renameIfPresent)(eventTrigger, ep.eventTrigger, "serviceAccount", "serviceAccountEmail");
|
|
207
|
+
(0, proto_1.copyIfPresent)(eventTrigger, ep.eventTrigger, "serviceAccount", "eventFilterPathPatterns", "region");
|
|
208
|
+
(0, proto_1.convertIfPresent)(eventTrigger, ep.eventTrigger, "channel", (c) => resolveChannelName(project, c, defaultRegion));
|
|
209
|
+
(0, proto_1.convertIfPresent)(eventTrigger, ep.eventTrigger, "eventFilters", (filters) => {
|
|
210
|
+
const copy = Object.assign({}, filters);
|
|
211
|
+
if (copy["topic"] && !copy["topic"].startsWith("projects/")) {
|
|
212
|
+
copy["topic"] = `projects/${project}/topics/${copy["topic"]}`;
|
|
211
213
|
}
|
|
212
|
-
|
|
214
|
+
return copy;
|
|
215
|
+
});
|
|
216
|
+
triggered = { eventTrigger };
|
|
213
217
|
}
|
|
214
218
|
else if (backend.isHttpsTriggered(ep)) {
|
|
215
219
|
triggered = { httpsTrigger: {} };
|
|
@@ -221,39 +225,39 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
|
|
|
221
225
|
else if (backend.isScheduleTriggered(ep)) {
|
|
222
226
|
const st = {
|
|
223
227
|
schedule: ep.scheduleTrigger.schedule || "",
|
|
224
|
-
timeZone: ep.scheduleTrigger.timeZone
|
|
225
|
-
retryConfig: {},
|
|
228
|
+
timeZone: (_a = ep.scheduleTrigger.timeZone) !== null && _a !== void 0 ? _a : null,
|
|
226
229
|
};
|
|
227
230
|
if (ep.scheduleTrigger.retryConfig) {
|
|
228
|
-
st.retryConfig = {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
st.retryConfig.maxBackoffSeconds = (0, proto_1.secondsFromDuration)(ep.scheduleTrigger.retryConfig.maxBackoffDuration);
|
|
237
|
-
}
|
|
238
|
-
if (ep.scheduleTrigger.retryConfig.minBackoffDuration) {
|
|
239
|
-
st.retryConfig.minBackoffSeconds = (0, proto_1.secondsFromDuration)(ep.scheduleTrigger.retryConfig.minBackoffDuration);
|
|
240
|
-
}
|
|
231
|
+
st.retryConfig = {};
|
|
232
|
+
(0, proto_1.copyIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "retryCount", "minBackoffSeconds", "maxBackoffSeconds", "maxRetrySeconds", "maxDoublings");
|
|
233
|
+
(0, proto_1.convertIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "minBackoffSeconds", "minBackoffDuration", (0, functional_1.nullsafeVisitor)(proto_1.secondsFromDuration));
|
|
234
|
+
(0, proto_1.convertIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "maxBackoffSeconds", "maxBackoffDuration", (0, functional_1.nullsafeVisitor)(proto_1.secondsFromDuration));
|
|
235
|
+
(0, proto_1.convertIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "maxRetrySeconds", "maxRetryDuration", (0, functional_1.nullsafeVisitor)(proto_1.secondsFromDuration));
|
|
236
|
+
}
|
|
237
|
+
else if (ep.scheduleTrigger.retryConfig === null) {
|
|
238
|
+
st.retryConfig = null;
|
|
241
239
|
}
|
|
242
240
|
triggered = { scheduleTrigger: st };
|
|
243
241
|
}
|
|
244
242
|
else if (backend.isTaskQueueTriggered(ep)) {
|
|
245
|
-
const tq = {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
243
|
+
const tq = {};
|
|
244
|
+
if (ep.taskQueueTrigger.invoker) {
|
|
245
|
+
tq.invoker = ep.taskQueueTrigger.invoker;
|
|
246
|
+
}
|
|
247
|
+
else if (ep.taskQueueTrigger.invoker === null) {
|
|
248
|
+
tq.invoker = null;
|
|
249
|
+
}
|
|
249
250
|
if (ep.taskQueueTrigger.retryConfig) {
|
|
250
|
-
tq.retryConfig = {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
};
|
|
251
|
+
tq.retryConfig = Object.assign({}, ep.taskQueueTrigger.retryConfig);
|
|
252
|
+
}
|
|
253
|
+
else if (ep.taskQueueTrigger.retryConfig === null) {
|
|
254
|
+
tq.retryConfig = null;
|
|
255
|
+
}
|
|
256
|
+
if (ep.taskQueueTrigger.rateLimits) {
|
|
257
|
+
tq.rateLimits = Object.assign({}, ep.taskQueueTrigger.rateLimits);
|
|
258
|
+
}
|
|
259
|
+
else if (ep.taskQueueTrigger.rateLimits === null) {
|
|
260
|
+
tq.rateLimits = null;
|
|
257
261
|
}
|
|
258
262
|
triggered = { taskQueueTrigger: tq };
|
|
259
263
|
}
|
|
@@ -265,18 +269,16 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
|
|
|
265
269
|
"firebase-tools with npm install -g firebase-tools@latest");
|
|
266
270
|
}
|
|
267
271
|
const parsed = Object.assign({ platform: ep.platform || "gcfv2", region: ep.region || [defaultRegion], project,
|
|
268
|
-
runtime, entryPoint: ep.entryPoint
|
|
269
|
-
(0, proto_1.
|
|
270
|
-
(0, proto_1.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
key,
|
|
275
|
-
secret: secret || key,
|
|
276
|
-
projectId: project,
|
|
277
|
-
});
|
|
272
|
+
runtime, entryPoint: ep.entryPoint }, triggered);
|
|
273
|
+
(0, proto_1.renameIfPresent)(parsed, ep, "serviceAccount", "serviceAccountEmail");
|
|
274
|
+
(0, proto_1.copyIfPresent)(parsed, ep, "availableMemoryMb", "cpu", "maxInstances", "minInstances", "concurrency", "timeoutSeconds", "vpc", "labels", "ingressSettings", "environmentVariables", "serviceAccount");
|
|
275
|
+
(0, proto_1.convertIfPresent)(parsed, ep, "secretEnvironmentVariables", (senvs) => {
|
|
276
|
+
if (!senvs) {
|
|
277
|
+
return null;
|
|
278
278
|
}
|
|
279
|
-
return
|
|
279
|
+
return senvs.map(({ key, secret }) => {
|
|
280
|
+
return { key, secret: secret || key, projectId: project };
|
|
281
|
+
});
|
|
280
282
|
});
|
|
281
283
|
return parsed;
|
|
282
284
|
}
|
|
@@ -284,17 +286,25 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
|
|
|
284
286
|
const allParsed = [];
|
|
285
287
|
const prefix = `endpoints[${id}]`;
|
|
286
288
|
const ep = manifest.endpoints[id];
|
|
287
|
-
assertManifestEndpoint(ep,
|
|
289
|
+
assertManifestEndpoint(ep, id);
|
|
288
290
|
for (const region of ep.region || [defaultRegion]) {
|
|
289
291
|
let triggered;
|
|
290
292
|
if (backend.isEventTriggered(ep)) {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
293
|
+
const eventTrigger = {
|
|
294
|
+
eventType: ep.eventTrigger.eventType,
|
|
295
|
+
retry: false,
|
|
296
|
+
};
|
|
297
|
+
(0, proto_1.renameIfPresent)(eventTrigger, ep.eventTrigger, "serviceAccount", "serviceAccountEmail");
|
|
298
|
+
(0, proto_1.copyIfPresent)(eventTrigger, ep.eventTrigger, "eventFilterPathPatterns", "retry", "serviceAccount", "region");
|
|
299
|
+
(0, proto_1.convertIfPresent)(eventTrigger, ep.eventTrigger, "channel", (c) => resolveChannelName(project, c, defaultRegion));
|
|
300
|
+
(0, proto_1.convertIfPresent)(eventTrigger, ep.eventTrigger, "eventFilters", (filters) => {
|
|
301
|
+
const copy = Object.assign({}, filters);
|
|
302
|
+
if (copy["topic"] && !copy["topic"].startsWith("projects/")) {
|
|
303
|
+
copy["topic"] = `projects/${project}/topics/${copy["topic"]}`;
|
|
296
304
|
}
|
|
297
|
-
|
|
305
|
+
return copy;
|
|
306
|
+
});
|
|
307
|
+
triggered = { eventTrigger };
|
|
298
308
|
}
|
|
299
309
|
else if (backend.isHttpsTriggered(ep)) {
|
|
300
310
|
triggered = { httpsTrigger: {} };
|
|
@@ -321,17 +331,15 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
|
|
|
321
331
|
region,
|
|
322
332
|
project,
|
|
323
333
|
runtime, entryPoint: ep.entryPoint }, triggered);
|
|
324
|
-
(0, proto_1.
|
|
325
|
-
(0, proto_1.
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
key,
|
|
330
|
-
secret: secret || key,
|
|
331
|
-
projectId: project,
|
|
332
|
-
});
|
|
334
|
+
(0, proto_1.renameIfPresent)(parsed, ep, "serviceAccount", "serviceAccountEmail");
|
|
335
|
+
(0, proto_1.copyIfPresent)(parsed, ep, "availableMemoryMb", "maxInstances", "minInstances", "concurrency", "serviceAccount", "timeoutSeconds", "vpc", "labels", "ingressSettings", "environmentVariables", "cpu");
|
|
336
|
+
(0, proto_1.convertIfPresent)(parsed, ep, "secretEnvironmentVariables", (senvs) => {
|
|
337
|
+
if (!senvs) {
|
|
338
|
+
return null;
|
|
333
339
|
}
|
|
334
|
-
return
|
|
340
|
+
return senvs.map(({ key, secret }) => {
|
|
341
|
+
return { key, secret: secret || key, projectId: project };
|
|
342
|
+
});
|
|
335
343
|
});
|
|
336
344
|
allParsed.push(parsed);
|
|
337
345
|
}
|
|
@@ -10,6 +10,7 @@ const backend = require("../../backend");
|
|
|
10
10
|
const api = require("../../../../api");
|
|
11
11
|
const proto = require("../../../../gcp/proto");
|
|
12
12
|
const events = require("../../../../functions/events");
|
|
13
|
+
const functional_1 = require("../../../../functional");
|
|
13
14
|
const TRIGGER_PARSER = path.resolve(__dirname, "./triggerParser.js");
|
|
14
15
|
function removeInspectOptions(options) {
|
|
15
16
|
return options.filter((opt) => !opt.startsWith("--inspect"));
|
|
@@ -88,8 +89,9 @@ function mergeRequiredAPIs(backend) {
|
|
|
88
89
|
}
|
|
89
90
|
exports.mergeRequiredAPIs = mergeRequiredAPIs;
|
|
90
91
|
function addResourcesToBuild(projectId, runtime, annotation, want) {
|
|
91
|
-
var _a;
|
|
92
|
+
var _a, _b;
|
|
92
93
|
Object.freeze(annotation);
|
|
94
|
+
const toSeconds = (0, functional_1.nullsafeVisitor)(proto.secondsFromDuration);
|
|
93
95
|
const regions = annotation.regions || [api.functionsDefaultRegion];
|
|
94
96
|
let triggered;
|
|
95
97
|
const triggerCount = +!!annotation.httpsTrigger +
|
|
@@ -110,9 +112,11 @@ function addResourcesToBuild(projectId, runtime, annotation, want) {
|
|
|
110
112
|
proto.copyIfPresent(triggered.taskQueueTrigger, annotation.taskQueueTrigger, "invoker");
|
|
111
113
|
proto.copyIfPresent(triggered.taskQueueTrigger, annotation.taskQueueTrigger, "rateLimits");
|
|
112
114
|
if (annotation.taskQueueTrigger.retryConfig) {
|
|
113
|
-
triggered.taskQueueTrigger.retryConfig =
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
triggered.taskQueueTrigger.retryConfig = {};
|
|
116
|
+
proto.copyIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxAttempts", "maxDoublings");
|
|
117
|
+
proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "minBackoffSeconds", "minBackoff", toSeconds);
|
|
118
|
+
proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxBackoffSeconds", "maxBackoff", toSeconds);
|
|
119
|
+
proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxRetryDurationSeconds", "maxRetryDuration", toSeconds);
|
|
116
120
|
}
|
|
117
121
|
}
|
|
118
122
|
else if (annotation.httpsTrigger) {
|
|
@@ -139,21 +143,16 @@ function addResourcesToBuild(projectId, runtime, annotation, want) {
|
|
|
139
143
|
triggered = {
|
|
140
144
|
scheduleTrigger: {
|
|
141
145
|
schedule: annotation.schedule.schedule,
|
|
142
|
-
timeZone: annotation.schedule.timeZone
|
|
146
|
+
timeZone: (_b = annotation.schedule.timeZone) !== null && _b !== void 0 ? _b : null,
|
|
143
147
|
retryConfig: {},
|
|
144
148
|
},
|
|
145
149
|
};
|
|
146
150
|
if (annotation.schedule.retryConfig) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
if (annotation.schedule.retryConfig.maxRetryDuration) {
|
|
154
|
-
triggered.scheduleTrigger.retryConfig.maxRetrySeconds = proto.secondsFromDuration(annotation.schedule.retryConfig.maxRetryDuration);
|
|
155
|
-
}
|
|
156
|
-
proto.copyIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "maxDoublings", "retryCount");
|
|
151
|
+
triggered.scheduleTrigger.retryConfig = {};
|
|
152
|
+
proto.copyIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "retryCount", "maxDoublings");
|
|
153
|
+
proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "maxRetrySeconds", "maxRetryDuration", toSeconds);
|
|
154
|
+
proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "minBackoffSeconds", "minBackoffDuration", toSeconds);
|
|
155
|
+
proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "maxBackoffSeconds", "maxBackoffDuration", toSeconds);
|
|
157
156
|
}
|
|
158
157
|
}
|
|
159
158
|
else if (annotation.blockingTrigger) {
|
|
@@ -169,7 +168,7 @@ function addResourcesToBuild(projectId, runtime, annotation, want) {
|
|
|
169
168
|
},
|
|
170
169
|
};
|
|
171
170
|
}
|
|
172
|
-
else {
|
|
171
|
+
else if (annotation.eventTrigger) {
|
|
173
172
|
triggered = {
|
|
174
173
|
eventTrigger: {
|
|
175
174
|
eventType: annotation.eventTrigger.eventType,
|
|
@@ -178,8 +177,13 @@ function addResourcesToBuild(projectId, runtime, annotation, want) {
|
|
|
178
177
|
},
|
|
179
178
|
};
|
|
180
179
|
}
|
|
180
|
+
else {
|
|
181
|
+
throw new error_1.FirebaseError("Do not understand Cloud Function annotation without a trigger" +
|
|
182
|
+
JSON.stringify(annotation, null, 2));
|
|
183
|
+
}
|
|
181
184
|
const endpointId = annotation.name;
|
|
182
|
-
const endpoint = Object.assign({ platform: annotation.platform || "gcfv1", region: regions, project: projectId, entryPoint: annotation.entryPoint, runtime: runtime
|
|
185
|
+
const endpoint = Object.assign({ platform: annotation.platform || "gcfv1", region: regions, project: projectId, entryPoint: annotation.entryPoint, runtime: runtime }, triggered);
|
|
186
|
+
proto.renameIfPresent(endpoint, annotation, "serviceAccount", "serviceAccountEmail");
|
|
183
187
|
if (annotation.vpcConnector != null) {
|
|
184
188
|
let maybeId = annotation.vpcConnector;
|
|
185
189
|
if (maybeId && !maybeId.includes("/")) {
|
|
@@ -188,8 +192,17 @@ function addResourcesToBuild(projectId, runtime, annotation, want) {
|
|
|
188
192
|
endpoint.vpc = { connector: maybeId };
|
|
189
193
|
proto.renameIfPresent(endpoint.vpc, annotation, "egressSettings", "vpcConnectorEgressSettings");
|
|
190
194
|
}
|
|
191
|
-
proto.copyIfPresent(endpoint, annotation, "concurrency", "labels", "
|
|
192
|
-
proto.
|
|
195
|
+
proto.copyIfPresent(endpoint, annotation, "concurrency", "labels", "maxInstances", "minInstances", "availableMemoryMb");
|
|
196
|
+
proto.convertIfPresent(endpoint, annotation, "ingressSettings", (str) => {
|
|
197
|
+
if (str === null) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
if (!backend.AllIngressSettings.includes(str)) {
|
|
201
|
+
throw new Error(`Invalid ingress setting ${str}`);
|
|
202
|
+
}
|
|
203
|
+
return str;
|
|
204
|
+
});
|
|
205
|
+
proto.convertIfPresent(endpoint, annotation, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
193
206
|
want.endpoints[endpointId] = endpoint;
|
|
194
207
|
}
|
|
195
208
|
exports.addResourcesToBuild = addResourcesToBuild;
|
|
@@ -285,8 +298,27 @@ function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
|
285
298
|
}
|
|
286
299
|
endpoint.secretEnvironmentVariables = secretEnvs;
|
|
287
300
|
}
|
|
288
|
-
proto.copyIfPresent(endpoint, annotation, "concurrency", "
|
|
289
|
-
proto.renameIfPresent(endpoint, annotation, "
|
|
301
|
+
proto.copyIfPresent(endpoint, annotation, "concurrency", "labels", "maxInstances", "minInstances");
|
|
302
|
+
proto.renameIfPresent(endpoint, annotation, "serviceAccount", "serviceAccountEmail");
|
|
303
|
+
proto.convertIfPresent(endpoint, annotation, "ingressSettings", (ingress) => {
|
|
304
|
+
if (ingress == null) {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
if (!backend.AllIngressSettings.includes(ingress)) {
|
|
308
|
+
throw new error_1.FirebaseError(`Invalid ingress setting ${ingress}`);
|
|
309
|
+
}
|
|
310
|
+
return ingress;
|
|
311
|
+
});
|
|
312
|
+
proto.convertIfPresent(endpoint, annotation, "availableMemoryMb", (mem) => {
|
|
313
|
+
if (mem === null) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
if (!backend.isValidMemoryOption(mem)) {
|
|
317
|
+
throw new error_1.FirebaseError(`This version of firebase-tools does not know about the memory option ${mem}. Is an upgrade necessary?`);
|
|
318
|
+
}
|
|
319
|
+
return mem;
|
|
320
|
+
});
|
|
321
|
+
proto.convertIfPresent(endpoint, annotation, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
290
322
|
want.endpoints[region] = want.endpoints[region] || {};
|
|
291
323
|
want.endpoints[region][endpoint.id] = endpoint;
|
|
292
324
|
mergeRequiredAPIs(want);
|
|
@@ -17,9 +17,15 @@ async function obtainStorageBindings(projectNumber) {
|
|
|
17
17
|
}
|
|
18
18
|
exports.obtainStorageBindings = obtainStorageBindings;
|
|
19
19
|
async function ensureStorageTriggerRegion(endpoint) {
|
|
20
|
+
var _a;
|
|
20
21
|
const { eventTrigger } = endpoint;
|
|
21
22
|
if (!eventTrigger.region) {
|
|
22
23
|
logger_1.logger.debug("Looking up bucket region for the storage event trigger");
|
|
24
|
+
if (!((_a = eventTrigger.eventFilters) === null || _a === void 0 ? void 0 : _a.bucket)) {
|
|
25
|
+
throw new error_1.FirebaseError("Error: storage event trigger is missing bucket filter: " +
|
|
26
|
+
JSON.stringify(eventTrigger, null, 2));
|
|
27
|
+
}
|
|
28
|
+
logger_1.logger.debug(`Looking up bucket region for the storage event trigger on bucket ${eventTrigger.eventFilters.bucket}`);
|
|
23
29
|
try {
|
|
24
30
|
const bucket = await storage.getBucket(eventTrigger.eventFilters.bucket);
|
|
25
31
|
eventTrigger.region = bucket.location.toLowerCase();
|