firebase-tools 11.6.0 → 11.7.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.
@@ -24,6 +24,7 @@ const utils = require("../../../utils");
24
24
  const services = require("../services");
25
25
  const v1_1 = require("../../../functions/events/v1");
26
26
  const throttler_1 = require("../../../throttler/throttler");
27
+ const checkIam_1 = require("../checkIam");
27
28
  const gcfV1PollerOptions = {
28
29
  apiOrigin: api_1.functionsOrigin,
29
30
  apiVersion: gcf.API_VERSION,
@@ -46,6 +47,7 @@ class Fabricator {
46
47
  this.functionExecutor = args.functionExecutor;
47
48
  this.sources = args.sources;
48
49
  this.appEngineLocation = args.appEngineLocation;
50
+ this.projectNumber = args.projectNumber;
49
51
  }
50
52
  async applyPlan(plan) {
51
53
  const timer = new timer_1.Timer();
@@ -270,6 +272,12 @@ class Fabricator {
270
272
  .run(() => run.setInvokerCreate(endpoint.project, serviceName, ["public"]))
271
273
  .catch(rethrowAs(endpoint, "set invoker"));
272
274
  }
275
+ else if (backend.isScheduleTriggered(endpoint)) {
276
+ const invoker = [(0, checkIam_1.getDefaultComputeServiceAgent)(this.projectNumber)];
277
+ await this.executor
278
+ .run(() => run.setInvokerCreate(endpoint.project, serviceName, invoker))
279
+ .catch(rethrowAs(endpoint, "set invoker"));
280
+ }
273
281
  const mem = endpoint.availableMemoryMb || backend.DEFAULT_MEMORY;
274
282
  const hasCustomCPU = endpoint.cpu !== backend.memoryToGen1Cpu(mem);
275
283
  if (!endpoint.concurrency) {
@@ -346,6 +354,9 @@ class Fabricator {
346
354
  v1_1.AUTH_BLOCKING_EVENTS.includes(endpoint.blockingTrigger.eventType)) {
347
355
  invoker = ["public"];
348
356
  }
357
+ else if (backend.isScheduleTriggered(endpoint)) {
358
+ invoker = [(0, checkIam_1.getDefaultComputeServiceAgent)(this.projectNumber)];
359
+ }
349
360
  if (invoker) {
350
361
  await this.executor
351
362
  .run(() => run.setInvokerUpdate(endpoint.project, serviceName, invoker))
@@ -452,13 +463,16 @@ class Fabricator {
452
463
  }
453
464
  }
454
465
  async upsertScheduleV1(endpoint) {
455
- const job = scheduler.jobFromEndpoint(endpoint, this.appEngineLocation);
466
+ const job = scheduler.jobFromEndpoint(endpoint, this.appEngineLocation, this.projectNumber);
456
467
  await this.executor
457
468
  .run(() => scheduler.createOrReplaceJob(job))
458
469
  .catch(rethrowAs(endpoint, "upsert schedule"));
459
470
  }
460
- upsertScheduleV2(endpoint) {
461
- return Promise.reject(new reporter.DeploymentError(endpoint, "upsert schedule", new Error("Not implemented")));
471
+ async upsertScheduleV2(endpoint) {
472
+ const job = scheduler.jobFromEndpoint(endpoint, endpoint.region, this.projectNumber);
473
+ await this.executor
474
+ .run(() => scheduler.createOrReplaceJob(job))
475
+ .catch(rethrowAs(endpoint, "upsert schedule"));
462
476
  }
463
477
  async upsertTaskQueue(endpoint) {
464
478
  const queue = cloudtasks.queueFromEndpoint(endpoint);
@@ -486,8 +500,11 @@ class Fabricator {
486
500
  .run(() => pubsub.deleteTopic(topicName))
487
501
  .catch(rethrowAs(endpoint, "delete topic"));
488
502
  }
489
- deleteScheduleV2(endpoint) {
490
- return Promise.reject(new reporter.DeploymentError(endpoint, "delete schedule", new Error("Not implemented")));
503
+ async deleteScheduleV2(endpoint) {
504
+ const jobName = scheduler.jobNameForEndpoint(endpoint, endpoint.region);
505
+ await this.executor
506
+ .run(() => scheduler.deleteJob(jobName))
507
+ .catch(rethrowAs(endpoint, "delete schedule"));
491
508
  }
492
509
  async disableTaskQueue(endpoint) {
493
510
  const update = {
@@ -14,6 +14,7 @@ const prompts = require("../prompts");
14
14
  const functionsConfig_1 = require("../../../functionsConfig");
15
15
  const functionsDeployHelper_1 = require("../functionsDeployHelper");
16
16
  const error_1 = require("../../../error");
17
+ const getProjectNumber_1 = require("../../../getProjectNumber");
17
18
  async function release(context, options, payload) {
18
19
  if (!context.config) {
19
20
  return;
@@ -53,6 +54,7 @@ async function release(context, options, payload) {
53
54
  executor: new executor.QueueExecutor({}),
54
55
  sources: context.sources,
55
56
  appEngineLocation: (0, functionsConfig_1.getAppEngineLocation)(context.firebaseConfig),
57
+ projectNumber: options.projectNumber || (await (0, getProjectNumber_1.getProjectNumber)(context.projectId)),
56
58
  });
57
59
  const summary = await fab.applyPlan(plan);
58
60
  await reporter.logAndTrackDeployStats(summary);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.detectFromPort = exports.detectFromYaml = exports.yamlToBuild = exports.yamlToBackend = exports.readFileAsync = void 0;
3
+ exports.detectFromPort = exports.detectFromYaml = exports.yamlToBuild = exports.readFileAsync = void 0;
4
4
  const node_fetch_1 = require("node-fetch");
5
5
  const fs = require("fs");
6
6
  const path = require("path");
@@ -11,21 +11,6 @@ const api = require("../../.../../../../api");
11
11
  const v1alpha1 = require("./v1alpha1");
12
12
  const error_1 = require("../../../../error");
13
13
  exports.readFileAsync = (0, util_1.promisify)(fs.readFile);
14
- function yamlToBackend(yaml, project, region, runtime) {
15
- try {
16
- if (!yaml.specVersion) {
17
- throw new error_1.FirebaseError("Expect backend yaml to specify a version number");
18
- }
19
- if (yaml.specVersion === "v1alpha1") {
20
- return v1alpha1.backendFromV1Alpha1(yaml, project, region, runtime);
21
- }
22
- throw new error_1.FirebaseError("It seems you are using a newer SDK than this version of the CLI can handle. Please update your CLI with `npm install -g firebase-tools`");
23
- }
24
- catch (err) {
25
- throw new error_1.FirebaseError("Failed to parse backend specification", { children: [err] });
26
- }
27
- }
28
- exports.yamlToBackend = yamlToBackend;
29
14
  function yamlToBuild(yaml, project, region, runtime) {
30
15
  try {
31
16
  if (!yaml.specVersion) {
@@ -31,6 +31,22 @@ function assertKeyTypes(prefix, yaml, schema) {
31
31
  }
32
32
  continue;
33
33
  }
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.includes("Field")) {
44
+ const match = /^Field<(\w+)>$/.exec(schemaType);
45
+ if (match && typeof value !== "string" && typeof value !== match[1]) {
46
+ throw new error_1.FirebaseError(`Expected ${fullKey} to be Field<${match[1]}>; was ${typeof value}`);
47
+ }
48
+ continue;
49
+ }
34
50
  if (value === null) {
35
51
  if (schemaType.endsWith("?")) {
36
52
  continue;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.backendFromV1Alpha1 = exports.buildFromV1Alpha1 = void 0;
4
- const backend = require("../../backend");
3
+ exports.buildFromV1Alpha1 = void 0;
5
4
  const build = require("../../build");
6
5
  const proto_1 = require("../../../../gcp/proto");
7
6
  const parsing_1 = require("./parsing");
@@ -27,33 +26,13 @@ function buildFromV1Alpha1(yaml, project, region, runtime) {
27
26
  bd.requiredAPIs = parseRequiredAPIs(manifest);
28
27
  for (const id of Object.keys(manifest.endpoints)) {
29
28
  const me = manifest.endpoints[id];
30
- assertManifestEndpoint(me, id);
29
+ assertBuildEndpoint(me, id);
31
30
  const be = parseEndpointForBuild(id, me, project, region, runtime);
32
31
  bd.endpoints[id] = be;
33
32
  }
34
33
  return bd;
35
34
  }
36
35
  exports.buildFromV1Alpha1 = buildFromV1Alpha1;
37
- function backendFromV1Alpha1(yaml, project, region, runtime) {
38
- const manifest = JSON.parse(JSON.stringify(yaml));
39
- const bkend = backend.empty();
40
- bkend.requiredAPIs = parseRequiredAPIs(manifest);
41
- (0, parsing_1.requireKeys)("", manifest, "endpoints");
42
- (0, parsing_1.assertKeyTypes)("", manifest, {
43
- specVersion: "string",
44
- params: "array",
45
- requiredAPIs: "array",
46
- endpoints: "object",
47
- });
48
- for (const id of Object.keys(manifest.endpoints)) {
49
- for (const parsed of parseEndpoints(manifest, id, project, region, runtime)) {
50
- bkend.endpoints[parsed.region] = bkend.endpoints[parsed.region] || {};
51
- bkend.endpoints[parsed.region][parsed.id] = parsed;
52
- }
53
- }
54
- return bkend;
55
- }
56
- exports.backendFromV1Alpha1 = backendFromV1Alpha1;
57
36
  function parseRequiredAPIs(manifest) {
58
37
  const requiredAPIs = manifest.requiredAPIs || [];
59
38
  for (const { api, reason } of requiredAPIs) {
@@ -66,22 +45,22 @@ function parseRequiredAPIs(manifest) {
66
45
  }
67
46
  return requiredAPIs;
68
47
  }
69
- function assertManifestEndpoint(ep, id) {
48
+ function assertBuildEndpoint(ep, id) {
70
49
  const prefix = `endpoints[${id}]`;
71
50
  (0, parsing_1.assertKeyTypes)(prefix, ep, {
72
51
  region: "array",
73
- platform: (platform) => backend.AllFunctionsPlatforms.includes(platform),
52
+ platform: (platform) => build.AllFunctionsPlatforms.includes(platform),
74
53
  entryPoint: "string",
75
- availableMemoryMb: (mem) => mem === null || backend.isValidMemoryOption(mem),
76
- maxInstances: "number?",
77
- minInstances: "number?",
78
- concurrency: "number?",
54
+ availableMemoryMb: (mem) => mem === null || isCEL(mem) || build.isValidMemoryOption(mem),
55
+ maxInstances: "Field<number>?",
56
+ minInstances: "Field<number>?",
57
+ concurrency: "Field<number>?",
79
58
  serviceAccount: "string?",
80
59
  serviceAccountEmail: "string?",
81
- timeoutSeconds: "number?",
60
+ timeoutSeconds: "Field<number>?",
82
61
  vpc: "object?",
83
62
  labels: "object?",
84
- ingressSettings: (setting) => setting === null || backend.AllIngressSettings.includes(setting),
63
+ ingressSettings: (setting) => setting === null || build.AllIngressSettings.includes(setting),
85
64
  environmentVariables: "object?",
86
65
  secretEnvironmentVariables: "array?",
87
66
  httpsTrigger: "object",
@@ -90,12 +69,12 @@ function assertManifestEndpoint(ep, id) {
90
69
  scheduleTrigger: "object",
91
70
  taskQueueTrigger: "object",
92
71
  blockingTrigger: "object",
93
- cpu: (cpu) => cpu === null || typeof cpu === "number" || cpu === "gcf_gen1",
72
+ cpu: (cpu) => cpu === null || isCEL(cpu) || cpu === "gcf_gen1" || typeof cpu === "number",
94
73
  });
95
74
  if (ep.vpc) {
96
75
  (0, parsing_1.assertKeyTypes)(prefix + ".vpc", ep.vpc, {
97
76
  connector: "string",
98
- egressSettings: (setting) => setting === null || backend.AllVpcEgressSettings.includes(setting),
77
+ egressSettings: (setting) => setting === null || build.AllVpcEgressSettings.includes(setting),
99
78
  });
100
79
  (0, parsing_1.requireKeys)(prefix + ".vpc", ep.vpc, "connector");
101
80
  }
@@ -124,44 +103,46 @@ function assertManifestEndpoint(ep, id) {
124
103
  if (triggerCount > 1) {
125
104
  throw new error_1.FirebaseError("Multiple triggers defined for endpoint" + id);
126
105
  }
127
- if (backend.isEventTriggered(ep)) {
106
+ if (build.isEventTriggered(ep)) {
128
107
  (0, parsing_1.requireKeys)(prefix + ".eventTrigger", ep.eventTrigger, "eventType", "eventFilters");
129
108
  (0, parsing_1.assertKeyTypes)(prefix + ".eventTrigger", ep.eventTrigger, {
130
109
  eventFilters: "object",
131
110
  eventFilterPathPatterns: "object",
132
111
  eventType: "string",
133
- retry: "boolean",
134
- region: "string",
112
+ retry: "Field<boolean>",
113
+ region: "Field<string>",
135
114
  serviceAccount: "string?",
136
115
  serviceAccountEmail: "string?",
137
116
  channel: "string",
138
117
  });
139
118
  }
140
- else if (backend.isHttpsTriggered(ep)) {
119
+ else if (build.isHttpsTriggered(ep)) {
141
120
  (0, parsing_1.assertKeyTypes)(prefix + ".httpsTrigger", ep.httpsTrigger, {
142
121
  invoker: "array?",
143
122
  });
144
123
  }
145
- else if (backend.isCallableTriggered(ep)) {
124
+ else if (build.isCallableTriggered(ep)) {
146
125
  }
147
- else if (backend.isScheduleTriggered(ep)) {
126
+ else if (build.isScheduleTriggered(ep)) {
148
127
  (0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger", ep.scheduleTrigger, {
149
- schedule: "string",
150
- timeZone: "string?",
128
+ schedule: "Field<string>",
129
+ timeZone: "Field<string>?",
151
130
  retryConfig: "object?",
152
131
  });
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?",
162
- });
132
+ if (ep.scheduleTrigger.retryConfig) {
133
+ (0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger.retryConfig", ep.scheduleTrigger.retryConfig, {
134
+ retryCount: "Field<number>?",
135
+ maxDoublings: "Field<number>?",
136
+ minBackoffSeconds: "Field<number>?",
137
+ maxBackoffSeconds: "Field<number>?",
138
+ maxRetrySeconds: "Field<number>?",
139
+ maxRetryDuration: "string?",
140
+ minBackoffDuration: "string?",
141
+ maxBackoffDuration: "string?",
142
+ });
143
+ }
163
144
  }
164
- else if (backend.isTaskQueueTriggered(ep)) {
145
+ else if (build.isTaskQueueTriggered(ep)) {
165
146
  (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger", ep.taskQueueTrigger, {
166
147
  rateLimits: "object?",
167
148
  retryConfig: "object?",
@@ -169,21 +150,21 @@ function assertManifestEndpoint(ep, id) {
169
150
  });
170
151
  if (ep.taskQueueTrigger.rateLimits) {
171
152
  (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger.rateLimits", ep.taskQueueTrigger.rateLimits, {
172
- maxConcurrentDispatches: "number?",
173
- maxDispatchesPerSecond: "number?",
153
+ maxConcurrentDispatches: "Field<number>?",
154
+ maxDispatchesPerSecond: "Field<number>?",
174
155
  });
175
156
  }
176
157
  if (ep.taskQueueTrigger.retryConfig) {
177
158
  (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger.retryConfig", ep.taskQueueTrigger.retryConfig, {
178
- maxAttempts: "number?",
179
- maxRetrySeconds: "number?",
180
- minBackoffSeconds: "number?",
181
- maxBackoffSeconds: "number?",
182
- maxDoublings: "number?",
159
+ maxAttempts: "Field<number>?",
160
+ maxRetrySeconds: "Field<number>?",
161
+ minBackoffSeconds: "Field<number>?",
162
+ maxBackoffSeconds: "Field<number>?",
163
+ maxDoublings: "Field<number>?",
183
164
  });
184
165
  }
185
166
  }
186
- else if (backend.isBlockingTriggered(ep)) {
167
+ else if (build.isBlockingTriggered(ep)) {
187
168
  (0, parsing_1.requireKeys)(prefix + ".blockingTrigger", ep.blockingTrigger, "eventType");
188
169
  (0, parsing_1.assertKeyTypes)(prefix + ".blockingTrigger", ep.blockingTrigger, {
189
170
  eventType: "string",
@@ -198,12 +179,14 @@ function assertManifestEndpoint(ep, id) {
198
179
  function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
199
180
  var _a;
200
181
  let triggered;
201
- if (backend.isEventTriggered(ep)) {
182
+ if (build.isEventTriggered(ep)) {
202
183
  const eventTrigger = {
203
184
  eventType: ep.eventTrigger.eventType,
204
185
  retry: ep.eventTrigger.retry,
205
186
  };
206
- (0, proto_1.renameIfPresent)(eventTrigger, ep.eventTrigger, "serviceAccount", "serviceAccountEmail");
187
+ if ("serviceAccountEmail" in ep.eventTrigger) {
188
+ eventTrigger.serviceAccount = ep.eventTrigger.serviceAccountEmail;
189
+ }
207
190
  (0, proto_1.copyIfPresent)(eventTrigger, ep.eventTrigger, "serviceAccount", "eventFilterPathPatterns", "region");
208
191
  (0, proto_1.convertIfPresent)(eventTrigger, ep.eventTrigger, "channel", (c) => resolveChannelName(project, c, defaultRegion));
209
192
  (0, proto_1.convertIfPresent)(eventTrigger, ep.eventTrigger, "eventFilters", (filters) => {
@@ -215,20 +198,23 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
215
198
  });
216
199
  triggered = { eventTrigger };
217
200
  }
218
- else if (backend.isHttpsTriggered(ep)) {
201
+ else if (build.isHttpsTriggered(ep)) {
219
202
  triggered = { httpsTrigger: {} };
220
203
  (0, proto_1.copyIfPresent)(triggered.httpsTrigger, ep.httpsTrigger, "invoker");
221
204
  }
222
- else if (backend.isCallableTriggered(ep)) {
205
+ else if (build.isCallableTriggered(ep)) {
223
206
  triggered = { callableTrigger: {} };
224
207
  }
225
- else if (backend.isScheduleTriggered(ep)) {
208
+ else if (build.isScheduleTriggered(ep)) {
226
209
  const st = {
227
210
  schedule: ep.scheduleTrigger.schedule || "",
228
211
  timeZone: (_a = ep.scheduleTrigger.timeZone) !== null && _a !== void 0 ? _a : null,
229
212
  };
230
213
  if (ep.scheduleTrigger.retryConfig) {
231
214
  st.retryConfig = {};
215
+ (0, proto_1.convertIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "maxBackoffSeconds", "maxBackoffDuration", (duration) => (duration === null ? null : (0, proto_1.secondsFromDuration)(duration)));
216
+ (0, proto_1.convertIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "minBackoffSeconds", "minBackoffDuration", (duration) => (duration === null ? null : (0, proto_1.secondsFromDuration)(duration)));
217
+ (0, proto_1.convertIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "maxRetrySeconds", "maxRetryDuration", (duration) => (duration === null ? null : (0, proto_1.secondsFromDuration)(duration)));
232
218
  (0, proto_1.copyIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "retryCount", "minBackoffSeconds", "maxBackoffSeconds", "maxRetrySeconds", "maxDoublings");
233
219
  (0, proto_1.convertIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "minBackoffSeconds", "minBackoffDuration", (0, functional_1.nullsafeVisitor)(proto_1.secondsFromDuration));
234
220
  (0, proto_1.convertIfPresent)(st.retryConfig, ep.scheduleTrigger.retryConfig, "maxBackoffSeconds", "maxBackoffDuration", (0, functional_1.nullsafeVisitor)(proto_1.secondsFromDuration));
@@ -239,7 +225,7 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
239
225
  }
240
226
  triggered = { scheduleTrigger: st };
241
227
  }
242
- else if (backend.isTaskQueueTriggered(ep)) {
228
+ else if (build.isTaskQueueTriggered(ep)) {
243
229
  const tq = {};
244
230
  if (ep.taskQueueTrigger.invoker) {
245
231
  tq.invoker = ep.taskQueueTrigger.invoker;
@@ -261,7 +247,7 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
261
247
  }
262
248
  triggered = { taskQueueTrigger: tq };
263
249
  }
264
- else if (backend.isBlockingTriggered(ep)) {
250
+ else if (ep.blockingTrigger) {
265
251
  triggered = { blockingTrigger: ep.blockingTrigger };
266
252
  }
267
253
  else {
@@ -270,7 +256,9 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
270
256
  }
271
257
  const parsed = Object.assign({ platform: ep.platform || "gcfv2", region: ep.region || [defaultRegion], project,
272
258
  runtime, entryPoint: ep.entryPoint }, triggered);
273
- (0, proto_1.renameIfPresent)(parsed, ep, "serviceAccount", "serviceAccountEmail");
259
+ if ("serviceAccountEmail" in ep) {
260
+ parsed.serviceAccount = ep.serviceAccountEmail;
261
+ }
274
262
  (0, proto_1.copyIfPresent)(parsed, ep, "availableMemoryMb", "cpu", "maxInstances", "minInstances", "concurrency", "timeoutSeconds", "vpc", "labels", "ingressSettings", "environmentVariables", "serviceAccount");
275
263
  (0, proto_1.convertIfPresent)(parsed, ep, "secretEnvironmentVariables", (senvs) => {
276
264
  if (!senvs) {
@@ -282,69 +270,6 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
282
270
  });
283
271
  return parsed;
284
272
  }
285
- function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
286
- const allParsed = [];
287
- const prefix = `endpoints[${id}]`;
288
- const ep = manifest.endpoints[id];
289
- assertManifestEndpoint(ep, id);
290
- for (const region of ep.region || [defaultRegion]) {
291
- let triggered;
292
- if (backend.isEventTriggered(ep)) {
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"]}`;
304
- }
305
- return copy;
306
- });
307
- triggered = { eventTrigger };
308
- }
309
- else if (backend.isHttpsTriggered(ep)) {
310
- triggered = { httpsTrigger: {} };
311
- (0, proto_1.copyIfPresent)(triggered.httpsTrigger, ep.httpsTrigger, "invoker");
312
- }
313
- else if (backend.isCallableTriggered(ep)) {
314
- triggered = { callableTrigger: {} };
315
- }
316
- else if (backend.isScheduleTriggered(ep)) {
317
- triggered = { scheduleTrigger: ep.scheduleTrigger };
318
- }
319
- else if (backend.isTaskQueueTriggered(ep)) {
320
- triggered = { taskQueueTrigger: ep.taskQueueTrigger };
321
- }
322
- else if (backend.isBlockingTriggered(ep)) {
323
- triggered = { blockingTrigger: ep.blockingTrigger };
324
- }
325
- else {
326
- throw new error_1.FirebaseError(`Do not recognize trigger type for endpoint ${id}. Try upgrading ` +
327
- "firebase-tools with npm install -g firebase-tools@latest");
328
- }
329
- (0, parsing_1.requireKeys)(prefix, ep, "entryPoint");
330
- const parsed = Object.assign({ platform: ep.platform || "gcfv2", id,
331
- region,
332
- project,
333
- runtime, entryPoint: ep.entryPoint }, triggered);
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;
339
- }
340
- return senvs.map(({ key, secret }) => {
341
- return { key, secret: secret || key, projectId: project };
342
- });
343
- });
344
- allParsed.push(parsed);
345
- }
346
- return allParsed;
347
- }
348
273
  function resolveChannelName(projectId, channel, defaultRegion) {
349
274
  if (!channel.includes("/")) {
350
275
  const location = defaultRegion;
@@ -365,3 +290,6 @@ function resolveChannelName(projectId, channel, defaultRegion) {
365
290
  return "projects/" + projectId + "/locations/" + location + "/channels/" + channelId;
366
291
  }
367
292
  }
293
+ function isCEL(expr) {
294
+ return typeof expr === "string" && expr.includes("{{") && expr.includes("}}");
295
+ }
@@ -116,7 +116,7 @@ function addResourcesToBuild(projectId, runtime, annotation, want) {
116
116
  proto.copyIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxAttempts", "maxDoublings");
117
117
  proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "minBackoffSeconds", "minBackoff", toSeconds);
118
118
  proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxBackoffSeconds", "maxBackoff", toSeconds);
119
- proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxRetryDurationSeconds", "maxRetryDuration", toSeconds);
119
+ proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxRetrySeconds", "maxRetryDuration", toSeconds);
120
120
  }
121
121
  }
122
122
  else if (annotation.httpsTrigger) {
@@ -28,7 +28,7 @@ exports.FIND_AVAILBLE_PORT_BY_DEFAULT = {
28
28
  auth: false,
29
29
  storage: false,
30
30
  extensions: false,
31
- eventarc: false,
31
+ eventarc: true,
32
32
  };
33
33
  exports.EMULATOR_DESCRIPTION = {
34
34
  ui: "Emulator UI",
@@ -338,18 +338,13 @@ async function startAll(options, showUI = true) {
338
338
  projectAlias: options.projectAlias,
339
339
  });
340
340
  await startEmulator(functionsEmulator);
341
+ const eventarcAddr = await getAndCheckAddress(types_1.Emulators.EVENTARC, options);
342
+ const eventarcEmulator = new eventarcEmulator_1.EventarcEmulator({
343
+ host: eventarcAddr.host,
344
+ port: eventarcAddr.port,
345
+ });
346
+ await startEmulator(eventarcEmulator);
341
347
  }
342
- if (!shouldStart(options, types_1.Emulators.EVENTARC)) {
343
- if (options.config.src.emulators) {
344
- options.config.src.emulators.eventarc = { host: constants_1.DEFAULT_HOST, port: constants_1.DEFAULT_PORTS.eventarc };
345
- }
346
- }
347
- const eventarcAddr = await getAndCheckAddress(types_1.Emulators.EVENTARC, options);
348
- const eventarcEmulator = new eventarcEmulator_1.EventarcEmulator({
349
- host: eventarcAddr.host,
350
- port: eventarcAddr.port,
351
- });
352
- await startEmulator(eventarcEmulator);
353
348
  if (shouldStart(options, types_1.Emulators.FIRESTORE)) {
354
349
  const firestoreLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FIRESTORE);
355
350
  const firestoreAddr = await getAndCheckAddress(types_1.Emulators.FIRESTORE, options);
@@ -675,24 +675,19 @@ async function initializeRuntime() {
675
675
  await initializeFirebaseFunctionsStubs();
676
676
  await initializeFirebaseAdminStubs();
677
677
  }
678
- async function loadTriggers(serializedFunctionTrigger) {
678
+ async function loadTriggers() {
679
679
  let triggerModule;
680
- if (serializedFunctionTrigger) {
681
- triggerModule = eval(serializedFunctionTrigger)();
680
+ try {
681
+ triggerModule = require(process.cwd());
682
682
  }
683
- else {
684
- try {
685
- triggerModule = require(process.cwd());
686
- }
687
- catch (err) {
688
- if (err.code !== "ERR_REQUIRE_ESM") {
689
- await moduleResolutionDetective(err);
690
- throw err;
691
- }
692
- const modulePath = require.resolve(process.cwd());
693
- const moduleURL = (0, url_1.pathToFileURL)(modulePath).href;
694
- triggerModule = await dynamicImport(moduleURL);
683
+ catch (err) {
684
+ if (err.code !== "ERR_REQUIRE_ESM") {
685
+ await moduleResolutionDetective(err);
686
+ throw err;
695
687
  }
688
+ const modulePath = require.resolve(process.cwd());
689
+ const moduleURL = (0, url_1.pathToFileURL)(modulePath).href;
690
+ triggerModule = await dynamicImport(moduleURL);
696
691
  }
697
692
  return triggerModule;
698
693
  }
@@ -716,8 +711,7 @@ async function handleMessage(message) {
716
711
  }
717
712
  if (!functionModule) {
718
713
  try {
719
- const serializedTriggers = runtimeArgs.opts ? runtimeArgs.opts.serializedTriggers : undefined;
720
- functionModule = await loadTriggers(serializedTriggers);
714
+ functionModule = await loadTriggers();
721
715
  }
722
716
  catch (e) {
723
717
  logDebug(e);
@@ -739,12 +733,7 @@ async function handleMessage(message) {
739
733
  logDebug(`Beginning invocation function ${FUNCTION_TARGET_NAME}!`);
740
734
  try {
741
735
  await invokeTrigger(trigger, runtimeArgs.frb);
742
- if (runtimeArgs.opts && runtimeArgs.opts.serializedTriggers) {
743
- await flushAndExit(0);
744
- }
745
- else {
746
- await goIdle();
747
- }
736
+ await goIdle();
748
737
  }
749
738
  catch (err) {
750
739
  new types_1.EmulatorLog("FATAL", "runtime-error", err.stack ? err.stack : err).log();
@@ -165,14 +165,17 @@ function createFirebaseEndpoints(emulator) {
165
165
  });
166
166
  });
167
167
  const handleUpload = async (req, res) => {
168
- if (!req.query.name) {
169
- res.sendStatus(400);
170
- return;
171
- }
168
+ var _a;
172
169
  const bucketId = req.params.bucketId;
173
- const objectId = req.query.name.toString();
170
+ const objectId = req.params.objectId
171
+ ? decodeURIComponent(req.params.objectId)
172
+ : ((_a = req.query.name) === null || _a === void 0 ? void 0 : _a.toString()) || null;
174
173
  const uploadType = req.header("x-goog-upload-protocol");
175
174
  if (uploadType === "multipart") {
175
+ if (!objectId) {
176
+ res.sendStatus(400);
177
+ return;
178
+ }
176
179
  const contentTypeHeader = req.header("content-type");
177
180
  if (!contentTypeHeader) {
178
181
  return res.sendStatus(400);
@@ -184,12 +187,7 @@ function createFirebaseEndpoints(emulator) {
184
187
  }
185
188
  catch (err) {
186
189
  if (err instanceof Error) {
187
- return res.status(400).json({
188
- error: {
189
- code: 400,
190
- message: err.message,
191
- },
192
- });
190
+ return res.status(400).send(err.message);
193
191
  }
194
192
  throw err;
195
193
  }
@@ -224,6 +222,10 @@ function createFirebaseEndpoints(emulator) {
224
222
  return;
225
223
  }
226
224
  if (uploadCommand === "start") {
225
+ if (!objectId) {
226
+ res.sendStatus(400);
227
+ return;
228
+ }
227
229
  const upload = uploadService.startResumableUpload({
228
230
  bucketId,
229
231
  objectId,
@@ -45,11 +45,11 @@ function parseMultipartRequestBodyPart(bodyPart) {
45
45
  }
46
46
  function parseObjectUploadMultipartRequest(contentTypeHeader, body) {
47
47
  if (!contentTypeHeader.startsWith("multipart/related")) {
48
- throw new Error(`Invalid Content-Type: ${contentTypeHeader}`);
48
+ throw new Error(`Bad content type. ${contentTypeHeader}`);
49
49
  }
50
50
  const boundaryId = contentTypeHeader.split("boundary=")[1];
51
51
  if (!boundaryId) {
52
- throw new Error(`Invalid Content-Type header: ${contentTypeHeader}`);
52
+ throw new Error(`Bad content type. ${contentTypeHeader}`);
53
53
  }
54
54
  const parsedBody = parseMultipartRequestBody(boundaryId, body);
55
55
  if (parsedBody.length !== 2) {