firebase-tools 11.5.0 → 11.8.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.
Files changed (63) hide show
  1. package/lib/command.js +33 -7
  2. package/lib/commands/crashlytics-mappingfile-generateid.js +26 -0
  3. package/lib/commands/crashlytics-mappingfile-upload.js +46 -0
  4. package/lib/commands/crashlytics-symbols-upload.js +18 -87
  5. package/lib/commands/emulators-exec.js +4 -1
  6. package/lib/commands/emulators-export.js +5 -2
  7. package/lib/commands/emulators-start.js +23 -17
  8. package/lib/commands/ext-dev-publish.js +3 -0
  9. package/lib/commands/functions-delete.js +2 -0
  10. package/lib/commands/functions-secrets-get.js +2 -0
  11. package/lib/commands/index.js +3 -0
  12. package/lib/commands/login.js +2 -2
  13. package/lib/crashlytics/buildToolsJarHelper.js +51 -0
  14. package/lib/deploy/functions/backend.js +4 -4
  15. package/lib/deploy/functions/build.js +76 -9
  16. package/lib/deploy/functions/checkIam.js +6 -5
  17. package/lib/deploy/functions/params.js +22 -16
  18. package/lib/deploy/functions/prepare.js +1 -1
  19. package/lib/deploy/functions/release/fabricator.js +22 -5
  20. package/lib/deploy/functions/release/index.js +2 -0
  21. package/lib/deploy/functions/runtimes/discovery/index.js +1 -16
  22. package/lib/deploy/functions/runtimes/discovery/parsing.js +16 -0
  23. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +59 -131
  24. package/lib/deploy/functions/runtimes/node/parseTriggers.js +1 -1
  25. package/lib/emulator/auth/index.js +7 -2
  26. package/lib/emulator/auth/operations.js +10 -10
  27. package/lib/emulator/commandUtils.js +32 -15
  28. package/lib/emulator/constants.js +14 -6
  29. package/lib/emulator/controller.js +49 -17
  30. package/lib/emulator/downloadableEmulators.js +7 -7
  31. package/lib/emulator/eventarcEmulator.js +148 -0
  32. package/lib/emulator/extensionsEmulator.js +3 -1
  33. package/lib/emulator/functionsEmulator.js +44 -4
  34. package/lib/emulator/functionsEmulatorRuntime.js +12 -23
  35. package/lib/emulator/functionsEmulatorShared.js +6 -1
  36. package/lib/emulator/hub.js +7 -3
  37. package/lib/emulator/hubClient.js +2 -2
  38. package/lib/emulator/hubExport.js +22 -2
  39. package/lib/emulator/registry.js +1 -0
  40. package/lib/emulator/storage/apis/firebase.js +145 -129
  41. package/lib/emulator/storage/apis/gcloud.js +102 -42
  42. package/lib/emulator/storage/files.js +39 -17
  43. package/lib/emulator/storage/metadata.js +76 -55
  44. package/lib/emulator/storage/multipart.js +2 -2
  45. package/lib/emulator/storage/rules/runtime.js +12 -4
  46. package/lib/emulator/storage/server.js +2 -1
  47. package/lib/emulator/storage/upload.js +46 -9
  48. package/lib/emulator/types.js +3 -0
  49. package/lib/emulator/ui.js +7 -2
  50. package/lib/extensions/extensionsApi.js +2 -1
  51. package/lib/extensions/extensionsHelper.js +29 -1
  52. package/lib/functions/constants.js +14 -0
  53. package/lib/functions/env.js +9 -9
  54. package/lib/gcp/cloudfunctions.js +15 -18
  55. package/lib/gcp/cloudfunctionsv2.js +15 -18
  56. package/lib/gcp/cloudscheduler.js +32 -14
  57. package/lib/serve/index.js +15 -0
  58. package/lib/track.js +122 -3
  59. package/lib/utils.js +14 -1
  60. package/npm-shrinkwrap.json +542 -9
  61. package/package.json +5 -4
  62. package/schema/firebase-config.json +12 -0
  63. package/templates/extensions/CHANGELOG.md +1 -7
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toBackend = exports.resolveBackend = exports.of = exports.empty = void 0;
3
+ exports.toBackend = exports.resolveBackend = exports.AllIngressSettings = exports.AllVpcEgressSettings = exports.AllFunctionsPlatforms = exports.isValidMemoryOption = exports.isBlockingTriggered = exports.isTaskQueueTriggered = exports.isScheduleTriggered = exports.isEventTriggered = exports.isCallableTriggered = exports.isHttpsTriggered = exports.of = exports.empty = void 0;
4
4
  const backend = require("./backend");
5
5
  const proto = require("../../gcp/proto");
6
6
  const api = require("../../.../../api");
@@ -8,6 +8,7 @@ const params = require("./params");
8
8
  const previews_1 = require("../../previews");
9
9
  const error_1 = require("../../error");
10
10
  const functional_1 = require("../../functional");
11
+ const env_1 = require("../../functions/env");
11
12
  const logger_1 = require("../../logger");
12
13
  function empty() {
13
14
  return {
@@ -23,15 +24,79 @@ function of(endpoints) {
23
24
  return build;
24
25
  }
25
26
  exports.of = of;
26
- async function resolveBackend(build, userEnvOpt, userEnvs) {
27
+ function isHttpsTriggered(triggered) {
28
+ return {}.hasOwnProperty.call(triggered, "httpsTrigger");
29
+ }
30
+ exports.isHttpsTriggered = isHttpsTriggered;
31
+ function isCallableTriggered(triggered) {
32
+ return {}.hasOwnProperty.call(triggered, "callableTrigger");
33
+ }
34
+ exports.isCallableTriggered = isCallableTriggered;
35
+ function isEventTriggered(triggered) {
36
+ return {}.hasOwnProperty.call(triggered, "eventTrigger");
37
+ }
38
+ exports.isEventTriggered = isEventTriggered;
39
+ function isScheduleTriggered(triggered) {
40
+ return {}.hasOwnProperty.call(triggered, "scheduleTrigger");
41
+ }
42
+ exports.isScheduleTriggered = isScheduleTriggered;
43
+ function isTaskQueueTriggered(triggered) {
44
+ return {}.hasOwnProperty.call(triggered, "taskQueueTrigger");
45
+ }
46
+ exports.isTaskQueueTriggered = isTaskQueueTriggered;
47
+ function isBlockingTriggered(triggered) {
48
+ return {}.hasOwnProperty.call(triggered, "blockingTrigger");
49
+ }
50
+ exports.isBlockingTriggered = isBlockingTriggered;
51
+ const allMemoryOptions = [128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768];
52
+ function isValidMemoryOption(mem) {
53
+ return allMemoryOptions.includes(mem);
54
+ }
55
+ exports.isValidMemoryOption = isValidMemoryOption;
56
+ exports.AllFunctionsPlatforms = ["gcfv1", "gcfv2"];
57
+ exports.AllVpcEgressSettings = ["PRIVATE_RANGES_ONLY", "ALL_TRAFFIC"];
58
+ exports.AllIngressSettings = [
59
+ "ALLOW_ALL",
60
+ "ALLOW_INTERNAL_ONLY",
61
+ "ALLOW_INTERNAL_AND_GCLB",
62
+ ];
63
+ async function resolveBackend(build, userEnvOpt, userEnvs, nonInteractive) {
64
+ var _a;
27
65
  const projectId = userEnvOpt.projectId;
28
66
  let paramValues = {};
29
67
  if (previews_1.previews.functionsparams) {
30
- paramValues = await params.resolveParams(build.params, projectId, userEnvs);
68
+ paramValues = await params.resolveParams(build.params, projectId, envWithTypes(userEnvs), nonInteractive);
69
+ const toWrite = {};
70
+ for (const paramName of Object.keys(paramValues)) {
71
+ if (userEnvs.hasOwnProperty(paramName)) {
72
+ continue;
73
+ }
74
+ toWrite[paramName] = ((_a = paramValues[paramName]) === null || _a === void 0 ? void 0 : _a.toString()) || "";
75
+ }
76
+ (0, env_1.writeUserEnvs)(toWrite, userEnvOpt);
31
77
  }
32
78
  return toBackend(build, paramValues);
33
79
  }
34
80
  exports.resolveBackend = resolveBackend;
81
+ function envWithTypes(rawEnvs) {
82
+ const out = {};
83
+ for (const envName of Object.keys(rawEnvs)) {
84
+ const value = rawEnvs[envName];
85
+ if (!isNaN(+value) && isFinite(+value) && !value.includes("e")) {
86
+ out[envName] = +value;
87
+ }
88
+ else if (value === "true") {
89
+ out[envName] = true;
90
+ }
91
+ else if (value === "false") {
92
+ out[envName] = false;
93
+ }
94
+ else {
95
+ out[envName] = value;
96
+ }
97
+ }
98
+ return out;
99
+ }
35
100
  class Resolver {
36
101
  constructor(paramValues) {
37
102
  this.paramValues = paramValues;
@@ -127,7 +192,7 @@ function toBackend(build, paramValues) {
127
192
  }
128
193
  exports.toBackend = toBackend;
129
194
  function discoverTrigger(endpoint, region, r) {
130
- if ("httpsTrigger" in endpoint) {
195
+ if (isHttpsTriggered(endpoint)) {
131
196
  const httpsTrigger = {};
132
197
  if (endpoint.httpsTrigger.invoker === null) {
133
198
  httpsTrigger.invoker = null;
@@ -137,13 +202,13 @@ function discoverTrigger(endpoint, region, r) {
137
202
  }
138
203
  return { httpsTrigger };
139
204
  }
140
- else if ("callableTrigger" in endpoint) {
205
+ else if (isCallableTriggered(endpoint)) {
141
206
  return { callableTrigger: {} };
142
207
  }
143
- else if ("blockingTrigger" in endpoint) {
208
+ else if (isBlockingTriggered(endpoint)) {
144
209
  return { blockingTrigger: endpoint.blockingTrigger };
145
210
  }
146
- else if ("eventTrigger" in endpoint) {
211
+ else if (isEventTriggered(endpoint)) {
147
212
  const eventTrigger = {
148
213
  eventType: endpoint.eventTrigger.eventType,
149
214
  retry: r.resolveBoolean(endpoint.eventTrigger.retry) || false,
@@ -157,11 +222,13 @@ function discoverTrigger(endpoint, region, r) {
157
222
  r.resolveStrings(eventTrigger, endpoint.eventTrigger, "serviceAccount", "region", "channel");
158
223
  return { eventTrigger };
159
224
  }
160
- else if ("scheduleTrigger" in endpoint) {
225
+ else if (isScheduleTriggered(endpoint)) {
161
226
  const bkSchedule = {
162
227
  schedule: r.resolveString(endpoint.scheduleTrigger.schedule),
163
- timeZone: r.resolveString(endpoint.scheduleTrigger.timeZone),
164
228
  };
229
+ if (endpoint.scheduleTrigger.timeZone !== undefined) {
230
+ bkSchedule.timeZone = r.resolveString(endpoint.scheduleTrigger.timeZone);
231
+ }
165
232
  if (endpoint.scheduleTrigger.retryConfig) {
166
233
  const bkRetry = {};
167
234
  r.resolveInts(bkRetry, endpoint.scheduleTrigger.retryConfig, "maxBackoffSeconds", "minBackoffSeconds", "maxRetrySeconds", "retryCount", "maxDoublings");
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ensureServiceAgentRoles = exports.mergeBindings = exports.obtainDefaultComputeServiceAgentBindings = exports.obtainPubSubServiceAgentBindings = exports.checkHttpIam = exports.checkServiceAccountIam = exports.EVENTARC_EVENT_RECEIVER_ROLE = exports.RUN_INVOKER_ROLE = exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE = void 0;
3
+ exports.ensureServiceAgentRoles = exports.mergeBindings = exports.obtainDefaultComputeServiceAgentBindings = exports.obtainPubSubServiceAgentBindings = exports.getDefaultComputeServiceAgent = exports.checkHttpIam = exports.checkServiceAccountIam = exports.EVENTARC_EVENT_RECEIVER_ROLE = exports.RUN_INVOKER_ROLE = exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE = void 0;
4
4
  const colorette_1 = require("colorette");
5
5
  const logger_1 = require("../../logger");
6
6
  const functionsDeployHelper_1 = require("./functionsDeployHelper");
@@ -68,11 +68,12 @@ async function checkHttpIam(context, options, payload) {
68
68
  }
69
69
  exports.checkHttpIam = checkHttpIam;
70
70
  function getPubsubServiceAgent(projectNumber) {
71
- return `serviceAccount:service-${projectNumber}@gcp-sa-pubsub.iam.gserviceaccount.com`;
71
+ return `service-${projectNumber}@gcp-sa-pubsub.iam.gserviceaccount.com`;
72
72
  }
73
73
  function getDefaultComputeServiceAgent(projectNumber) {
74
- return `serviceAccount:${projectNumber}-compute@developer.gserviceaccount.com`;
74
+ return `${projectNumber}-compute@developer.gserviceaccount.com`;
75
75
  }
76
+ exports.getDefaultComputeServiceAgent = getDefaultComputeServiceAgent;
76
77
  function reduceEventsToServices(services, endpoint) {
77
78
  const service = (0, services_1.serviceForEndpoint)(endpoint);
78
79
  if (service.requiredProjectBindings && !services.find((s) => s.name === service.name)) {
@@ -83,13 +84,13 @@ function reduceEventsToServices(services, endpoint) {
83
84
  function obtainPubSubServiceAgentBindings(projectNumber) {
84
85
  const serviceAccountTokenCreatorBinding = {
85
86
  role: exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE,
86
- members: [getPubsubServiceAgent(projectNumber)],
87
+ members: [`serviceAccount:${getPubsubServiceAgent(projectNumber)}`],
87
88
  };
88
89
  return [serviceAccountTokenCreatorBinding];
89
90
  }
90
91
  exports.obtainPubSubServiceAgentBindings = obtainPubSubServiceAgentBindings;
91
92
  function obtainDefaultComputeServiceAgentBindings(projectNumber) {
92
- const defaultComputeServiceAgent = getDefaultComputeServiceAgent(projectNumber);
93
+ const defaultComputeServiceAgent = `serviceAccount:${getDefaultComputeServiceAgent(projectNumber)}`;
93
94
  const runInvokerBinding = {
94
95
  role: exports.RUN_INVOKER_ROLE,
95
96
  members: [defaultComputeServiceAgent],
@@ -21,7 +21,7 @@ function resolveInt(from, paramValues) {
21
21
  if (typeof from === "number") {
22
22
  return from;
23
23
  }
24
- const match = /\A{{ params\.(\w+) }}\z/.exec(from);
24
+ const match = /{{ params\.(\w+) }}/.exec(from);
25
25
  if (!match) {
26
26
  throw new error_1.FirebaseError("CEL evaluation of expression '" + from + "' not yet supported");
27
27
  }
@@ -102,20 +102,26 @@ function canSatisfyParam(param, value) {
102
102
  }
103
103
  (0, functional_1.assertExhaustive)(param);
104
104
  }
105
- async function resolveParams(params, projectId, userEnvs) {
105
+ async function resolveParams(params, projectId, userEnvs, nonInteractive) {
106
106
  const paramValues = {};
107
107
  const [provided, outstanding] = (0, functional_1.partition)(params, (param) => {
108
- return {}.hasOwnProperty.call(userEnvs, param.param);
108
+ return {}.hasOwnProperty.call(userEnvs, param.name);
109
109
  });
110
110
  for (const param of provided) {
111
- if (!canSatisfyParam(param, userEnvs[param.param])) {
111
+ if (!canSatisfyParam(param, userEnvs[param.name])) {
112
112
  throw new error_1.FirebaseError("Parameter " +
113
- param.param +
113
+ param.name +
114
114
  " resolved to value from dotenv files " +
115
- userEnvs[param.param] +
115
+ userEnvs[param.name] +
116
116
  " of wrong type");
117
117
  }
118
- paramValues[param.param] = userEnvs[param.param];
118
+ paramValues[param.name] = userEnvs[param.name];
119
+ }
120
+ if (nonInteractive && outstanding.length > 0) {
121
+ const envNames = outstanding.map((p) => p.name).join(", ");
122
+ throw new error_1.FirebaseError(`In non-interactive mode but have no value for the following environment variables: ${envNames}\n` +
123
+ "To continue, either run `firebase deploy` with an interactive terminal, or add values to a dotenv file. " +
124
+ "For information regarding how to use dotenv files, see https://firebase.google.com/docs/functions/config-env");
119
125
  }
120
126
  for (const param of outstanding) {
121
127
  let paramDefault = param.default;
@@ -123,9 +129,9 @@ async function resolveParams(params, projectId, userEnvs) {
123
129
  paramDefault = resolveDefaultCEL(param.type, paramDefault, paramValues);
124
130
  }
125
131
  if (paramDefault && !canSatisfyParam(param, paramDefault)) {
126
- throw new error_1.FirebaseError("Parameter " + param.param + " has default value " + paramDefault + " of wrong type");
132
+ throw new error_1.FirebaseError("Parameter " + param.name + " has default value " + paramDefault + " of wrong type");
127
133
  }
128
- paramValues[param.param] = await promptParam(param, paramDefault);
134
+ paramValues[param.name] = await promptParam(param, paramDefault);
129
135
  }
130
136
  return paramValues;
131
137
  }
@@ -146,15 +152,15 @@ async function promptStringParam(param, resolvedDefault) {
146
152
  }
147
153
  switch (param.input.type) {
148
154
  case "select":
149
- throw new error_1.FirebaseError("Build specified string parameter " + param.param + " with unsupported input type 'select'");
155
+ throw new error_1.FirebaseError("Build specified string parameter " + param.name + " with unsupported input type 'select'");
150
156
  case "text":
151
157
  default:
152
- let prompt = `Enter a value for ${param.label || param.param}`;
158
+ let prompt = `Enter a value for ${param.label || param.name}:`;
153
159
  if (param.description) {
154
160
  prompt += ` \n(${param.description})`;
155
161
  }
156
162
  return await (0, prompt_1.promptOnce)({
157
- name: param.param,
163
+ name: param.name,
158
164
  type: "input",
159
165
  default: resolvedDefault,
160
166
  message: prompt,
@@ -168,17 +174,17 @@ async function promptIntParam(param, resolvedDefault) {
168
174
  }
169
175
  switch (param.input.type) {
170
176
  case "select":
171
- throw new error_1.FirebaseError("Build specified int parameter " + param.param + " with unsupported input type 'select'");
177
+ throw new error_1.FirebaseError("Build specified int parameter " + param.name + " with unsupported input type 'select'");
172
178
  case "text":
173
179
  default:
174
- let prompt = `Enter a value for ${param.label || param.param}`;
180
+ let prompt = `Enter a value for ${param.label || param.name}:`;
175
181
  if (param.description) {
176
182
  prompt += ` \n(${param.description})`;
177
183
  }
178
184
  let res;
179
185
  while (true) {
180
186
  res = await (0, prompt_1.promptOnce)({
181
- name: param.param,
187
+ name: param.name,
182
188
  type: "number",
183
189
  default: resolvedDefault,
184
190
  message: prompt,
@@ -186,7 +192,7 @@ async function promptIntParam(param, resolvedDefault) {
186
192
  if (Number.isInteger(res)) {
187
193
  return res;
188
194
  }
189
- logger_1.logger.error(`${param.label || param.param} must be an integer; retrying...`);
195
+ logger_1.logger.error(`${param.label || param.name} must be an integer; retrying...`);
190
196
  }
191
197
  }
192
198
  }
@@ -78,7 +78,7 @@ async function prepare(context, options, payload) {
78
78
  const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
79
79
  const envs = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
80
80
  const wantBuild = await runtimeDelegate.discoverBuild(runtimeConfig, firebaseEnvs);
81
- const wantBackend = await build.resolveBackend(wantBuild, userEnvOpt, userEnvs);
81
+ const wantBackend = await build.resolveBackend(wantBuild, userEnvOpt, userEnvs, options.nonInteractive);
82
82
  wantBackend.environmentVariables = envs;
83
83
  for (const endpoint of backend.allEndpoints(wantBackend)) {
84
84
  endpoint.environmentVariables = wantBackend.environmentVariables;
@@ -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;