firebase-tools 15.19.1 → 15.21.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 (61) hide show
  1. package/lib/appdistribution/client.js +6 -5
  2. package/lib/appdistribution/options-parser-util.js +21 -0
  3. package/lib/apphosting/constants.js +2 -1
  4. package/lib/apphosting/localbuilds.js +4 -2
  5. package/lib/archiveDirectory.js +2 -2
  6. package/lib/auth.js +2 -3
  7. package/lib/bin/cli.js +26 -18
  8. package/lib/commands/appdistribution-distribute.js +13 -4
  9. package/lib/commands/apptesting.js +18 -3
  10. package/lib/commands/crashlytics-symbols-upload.js +2 -2
  11. package/lib/crashlytics/sourcemap.js +3 -4
  12. package/lib/database/import.js +2 -2
  13. package/lib/dataconnect/build.js +6 -6
  14. package/lib/deploy/apphosting/util.js +9 -1
  15. package/lib/deploy/dataconnect/context.js +0 -2
  16. package/lib/deploy/dataconnect/deploy.js +0 -19
  17. package/lib/deploy/functions/prepare.js +47 -107
  18. package/lib/deploy/functions/prepareFunctionsUpload.js +1 -2
  19. package/lib/deploy/functions/release/index.js +0 -5
  20. package/lib/deploy/functions/services/ailogic.js +17 -10
  21. package/lib/deploy/functions/services/auth.js +3 -0
  22. package/lib/deploy/functions/services/database.js +18 -0
  23. package/lib/deploy/functions/services/dataconnect.js +20 -0
  24. package/lib/deploy/functions/services/firestore.js +12 -0
  25. package/lib/deploy/functions/services/index.js +18 -7
  26. package/lib/deploy/functions/services/storage.js +14 -0
  27. package/lib/deploy/functions/triggerRegionHelper.js +2 -4
  28. package/lib/emulator/auth/apiSpec.js +307 -33
  29. package/lib/emulator/auth/cloudFunctions.js +2 -2
  30. package/lib/emulator/auth/operations.js +99 -9
  31. package/lib/emulator/auth/state.js +27 -0
  32. package/lib/emulator/downloadableEmulatorInfo.json +24 -24
  33. package/lib/emulator/functionsEmulatorShell.js +4 -4
  34. package/lib/emulator/functionsRuntimeWorker.js +2 -2
  35. package/lib/emulator/pubsubEmulator.js +3 -3
  36. package/lib/emulator/storage/apis/firebase.js +2 -2
  37. package/lib/emulator/storage/cloudFunctions.js +2 -2
  38. package/lib/emulator/storage/metadata.js +1 -2
  39. package/lib/emulator/storage/persistence.js +2 -2
  40. package/lib/emulator/storage/upload.js +3 -3
  41. package/lib/env.js +20 -4
  42. package/lib/experiments.js +1 -2
  43. package/lib/frameworks/angular/index.js +3 -2
  44. package/lib/frameworks/angular/utils.js +100 -2
  45. package/lib/frameworks/astro/index.js +1 -1
  46. package/lib/frameworks/astro/utils.js +1 -1
  47. package/lib/functions/python.js +4 -4
  48. package/lib/gcp/location.js +16 -1
  49. package/lib/hosting/cloudRunProxy.js +8 -0
  50. package/lib/index.js +2 -2
  51. package/lib/init/features/apphosting.js +8 -1
  52. package/lib/init/features/dataconnect/create_app.js +3 -4
  53. package/lib/init/features/dataconnect/sdk.js +2 -2
  54. package/lib/init/features/functions/python.js +32 -20
  55. package/lib/localFunction.js +4 -2
  56. package/lib/mcp/tools/apptesting/tests.js +3 -1
  57. package/lib/track.js +2 -2
  58. package/lib/tsconfig.compile.tsbuildinfo +1 -1
  59. package/lib/tsconfig.publish.tsbuildinfo +1 -1
  60. package/lib/utils.js +70 -0
  61. package/package.json +1 -6
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_FUNCTION_REGION = exports.EVENTARC_SOURCE_ENV = void 0;
3
+ exports.EVENTARC_SOURCE_ENV = void 0;
4
4
  exports.prepare = prepare;
5
5
  exports.resolveDefaultRegionsForBuild = resolveDefaultRegionsForBuild;
6
6
  exports.inferDetailsFromExisting = inferDetailsFromExisting;
@@ -23,12 +23,7 @@ const runtimes = require("./runtimes");
23
23
  const supported = require("./runtimes/supported");
24
24
  const validate = require("./validate");
25
25
  const ensure = require("./ensure");
26
- const events = require("../../functions/events/v1");
27
- const firestore_1 = require("./services/firestore");
28
- const storage_1 = require("./services/storage");
29
- const database_1 = require("./services/database");
30
- const ailogic_1 = require("./services/ailogic");
31
- const names_1 = require("../../dataconnect/names");
26
+ const services_1 = require("./services");
32
27
  const api_1 = require("../../api");
33
28
  const functionsDeployHelper_1 = require("./functionsDeployHelper");
34
29
  const utils_1 = require("../../utils");
@@ -49,7 +44,6 @@ const functional_1 = require("../../functional");
49
44
  const prepare_1 = require("../extensions/prepare");
50
45
  const prompt = require("../../prompt");
51
46
  exports.EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE";
52
- exports.DEFAULT_FUNCTION_REGION = "us-central1";
53
47
  async function prepare(context, options, payload) {
54
48
  const projectId = (0, projectUtils_1.needProjectId)(options);
55
49
  const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
@@ -214,7 +208,7 @@ async function prepare(context, options, payload) {
214
208
  }
215
209
  const wantBackend = backend.merge(...Object.values(wantBackends));
216
210
  const haveBackend = backend.merge(...Object.values(haveBackends));
217
- await ensureAllRequiredAPIsEnabled(projectNumber, wantBackend);
211
+ await ensureAllRequiredAPIsEnabled(projectNumber, wantBackend, options);
218
212
  await warnIfNewGenkitFunctionIsMissingSecrets(wantBackend, haveBackend, options);
219
213
  warnIfDartBackendHasUnsupportedTriggers(wantBackend);
220
214
  const matchingBackend = backend.matchingBackend(wantBackend, (endpoint) => {
@@ -234,7 +228,7 @@ async function prepare(context, options, payload) {
234
228
  async function resolveDefaultRegionsForBuild(buildObj, have) {
235
229
  for (const [id, endpoint] of Object.entries(buildObj.endpoints)) {
236
230
  if (!endpoint.region?.length || endpoint.region.includes(build.REGION_TBD)) {
237
- let resolvedRegion = exports.DEFAULT_FUNCTION_REGION;
231
+ let resolvedRegion = services_1.FALLBACK_DEPLOYMENT_REGION;
238
232
  let matching;
239
233
  for (const region of Object.keys(have.endpoints)) {
240
234
  if (have.endpoints[region][id]) {
@@ -249,109 +243,19 @@ async function resolveDefaultRegionsForBuild(buildObj, have) {
249
243
  }
250
244
  else {
251
245
  try {
252
- if (build.isBlockingTriggered(endpoint)) {
253
- resolvedRegion = resolveRegionForBlockingTrigger(endpoint.blockingTrigger);
254
- }
255
- else if (build.isEventTriggered(endpoint)) {
256
- resolvedRegion = await resolveRegionForEventTrigger(endpoint.project, endpoint.eventTrigger);
257
- }
246
+ resolvedRegion = await resolveRegionForTrigger(endpoint);
258
247
  }
259
248
  catch (err) {
260
- logger_1.logger.debug(`Failed to resolve region for endpoint ${id}. Defaulting to ${exports.DEFAULT_FUNCTION_REGION}.`, (0, error_1.getErrStack)(err));
249
+ logger_1.logger.debug(`Failed to resolve region for endpoint ${id}. Defaulting to ${services_1.FALLBACK_DEPLOYMENT_REGION}.`, (0, error_1.getErrStack)(err));
261
250
  }
262
251
  }
263
252
  endpoint.region = [resolvedRegion];
264
253
  }
265
254
  }
266
255
  }
267
- function resolveRegionForBlockingTrigger(blockingTrigger) {
268
- const eventType = blockingTrigger.eventType;
269
- if (events.AUTH_BLOCKING_EVENTS.includes(eventType)) {
270
- return "us-east1";
271
- }
272
- if ((0, ailogic_1.isGlobalAILogicTrigger)(blockingTrigger)) {
273
- return "us-east1";
274
- }
275
- return exports.DEFAULT_FUNCTION_REGION;
276
- }
277
- async function resolveRegionForEventTrigger(project, eventTrigger) {
278
- const eventType = eventTrigger.eventType;
279
- if (eventType.startsWith("google.cloud.pubsub.") ||
280
- eventType.startsWith("providers/cloud.auth/eventTypes/") ||
281
- eventType.startsWith("providers/firebase.auth/eventTypes/") ||
282
- eventType.startsWith("google.firebase.testlab.") ||
283
- eventType.startsWith("google.firebase.remoteconfig.") ||
284
- eventType.startsWith("google.firebase.firebasealerts.")) {
285
- return "us-east1";
286
- }
287
- if (eventType.startsWith("google.cloud.firestore.")) {
288
- try {
289
- const databaseId = eventTrigger.eventFilters?.database || "(default)";
290
- const db = await (0, firestore_1.getDatabase)(project, databaseId);
291
- const locationId = db.locationId.toLowerCase();
292
- if (locationId === "nam5" || locationId === "nam7")
293
- return "us-central1";
294
- if (locationId === "eur3")
295
- return "europe-west1";
296
- return locationId;
297
- }
298
- catch (err) {
299
- logger_1.logger.debug("Failed to resolve Firestore database location", (0, error_1.getErrStack)(err));
300
- }
301
- }
302
- if (eventType.startsWith("google.cloud.storage.")) {
303
- try {
304
- const bucketName = eventTrigger.eventFilters?.bucket;
305
- if (bucketName) {
306
- const bucket = await (0, storage_1.getBucket)(bucketName);
307
- const locationId = bucket.location.toLowerCase();
308
- if (locationId === "us")
309
- return "us-east1";
310
- if (locationId === "eu")
311
- return "europe-west1";
312
- if (locationId === "asia")
313
- return "asia-east1";
314
- return locationId;
315
- }
316
- }
317
- catch (err) {
318
- logger_1.logger.debug("Failed to resolve Cloud Storage bucket location", (0, error_1.getErrStack)(err));
319
- }
320
- }
321
- if (eventType.startsWith("google.firebase.database.")) {
322
- if (eventTrigger.region)
323
- return eventTrigger.region;
324
- try {
325
- const instanceName = eventTrigger.eventFilters?.instance;
326
- if (instanceName) {
327
- const details = await (0, database_1.getDatabaseInstanceDetails)(project, instanceName);
328
- if (details.location && details.location !== "-") {
329
- return details.location.toLowerCase();
330
- }
331
- }
332
- }
333
- catch (err) {
334
- logger_1.logger.debug("Failed to resolve Realtime Database instance location", (0, error_1.getErrStack)(err));
335
- }
336
- }
337
- if (eventType.startsWith("google.firebase.dataconnect.")) {
338
- if (eventTrigger.region)
339
- return eventTrigger.region;
340
- try {
341
- const service = eventTrigger.eventFilters?.service;
342
- if (service) {
343
- return (0, names_1.parseServiceName)(service).location;
344
- }
345
- const connector = eventTrigger.eventFilters?.connector;
346
- if (connector) {
347
- return (0, names_1.parseConnectorName)(connector).location;
348
- }
349
- }
350
- catch (err) {
351
- logger_1.logger.debug("Failed to resolve DataConnect location", (0, error_1.getErrStack)(err));
352
- }
353
- }
354
- return exports.DEFAULT_FUNCTION_REGION;
256
+ async function resolveRegionForTrigger(endpoint) {
257
+ const service = (0, services_1.serviceForEndpoint)(endpoint);
258
+ return await service.getDefaultRegion(endpoint);
355
259
  }
356
260
  function inferDetailsFromExisting(want, have, usedDotenv) {
357
261
  for (const wantE of backend.allEndpoints(want)) {
@@ -531,8 +435,44 @@ async function warnIfNewGenkitFunctionIsMissingSecrets(have, want, options) {
531
435
  }
532
436
  }
533
437
  }
534
- async function ensureAllRequiredAPIsEnabled(projectNumber, wantBackend) {
535
- await Promise.all(Object.values(wantBackend.requiredAPIs).map(({ api }) => {
438
+ const STANDARD_APIS = [
439
+ "cloudfunctions.googleapis.com",
440
+ "runtimeconfig.googleapis.com",
441
+ "cloudbuild.googleapis.com",
442
+ "artifactregistry.googleapis.com",
443
+ "run.googleapis.com",
444
+ "eventarc.googleapis.com",
445
+ "pubsub.googleapis.com",
446
+ "storage.googleapis.com",
447
+ "secretmanager.googleapis.com",
448
+ "cloudscheduler.googleapis.com",
449
+ "cloudtasks.googleapis.com",
450
+ ];
451
+ async function ensureAllRequiredAPIsEnabled(projectNumber, wantBackend = backend.empty(), options = {}) {
452
+ const requiredApis = Object.values(wantBackend?.requiredAPIs ?? {});
453
+ const [standardApis, additionalApis] = (0, functional_1.partition)(requiredApis, ({ api }) => STANDARD_APIS.includes(api));
454
+ if (additionalApis.length > 0) {
455
+ const checks = await Promise.all(additionalApis.map(({ api }) => ensureApiEnabled.check(projectNumber, api, "functions", true)));
456
+ const missingApis = additionalApis.filter((_, i) => !checks[i]);
457
+ if (missingApis.length > 0) {
458
+ const apiList = missingApis
459
+ .map(({ api, reason }) => ` - ${api}${reason ? `: ${reason}` : ""}`)
460
+ .join("\n");
461
+ const confirm = await prompt.confirm({
462
+ message: `This codebase depends on the following additional API(s) which are currently disabled:\n${apiList}\nWould you like to enable them?`,
463
+ default: false,
464
+ force: options.force,
465
+ nonInteractive: options.nonInteractive,
466
+ });
467
+ if (!confirm) {
468
+ throw new error_1.FirebaseError("Must enable required APIs to deploy.");
469
+ }
470
+ await Promise.all(missingApis.map(({ api }) => {
471
+ return ensureApiEnabled.ensure(projectNumber, api, "functions", false);
472
+ }));
473
+ }
474
+ }
475
+ await Promise.all(standardApis.map(({ api }) => {
536
476
  return ensureApiEnabled.ensure(projectNumber, api, "functions", false);
537
477
  }));
538
478
  if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
@@ -6,7 +6,6 @@ exports.prepareFunctionsUpload = prepareFunctionsUpload;
6
6
  exports.convertToSortedKeyValueArray = convertToSortedKeyValueArray;
7
7
  const archiver = require("archiver");
8
8
  const clc = require("colorette");
9
- const filesize = require("filesize");
10
9
  const fs = require("fs");
11
10
  const path = require("path");
12
11
  const tmp = require("tmp");
@@ -120,7 +119,7 @@ async function packageSource(projectDir, sourceDir, config, additionalSources, r
120
119
  " packaged " +
121
120
  clc.bold(sourceDir) +
122
121
  " (" +
123
- filesize(archive.pointer()) +
122
+ utils.formatFilesize(archive.pointer()) +
124
123
  ") for uploading");
125
124
  const sourceHash = crypto.createHash("sha1").update(hashes.sort().join("")).digest("hex");
126
125
  const hash = configHash ? `${sourceHash}.${configHash}` : sourceHash;
@@ -18,7 +18,6 @@ const error_1 = require("../../../error");
18
18
  const getProjectNumber_1 = require("../../../getProjectNumber");
19
19
  const extensions_1 = require("../../extensions");
20
20
  const artifacts = require("../../../functions/artifacts");
21
- const supported_1 = require("../runtimes/supported");
22
21
  async function release(context, options, payload) {
23
22
  if (context.extensions && payload.extensions) {
24
23
  await (0, extensions_1.release)(context.extensions, options, payload.extensions);
@@ -89,10 +88,6 @@ async function release(context, options, payload) {
89
88
  reporter.printErrors(summary);
90
89
  const wantBackend = backend.merge(...Object.values(payload.functions).map((p) => p.wantBackend));
91
90
  printTriggerUrls(wantBackend, projectNumber);
92
- if (backend.someEndpoint(wantBackend, (endpoint) => (0, supported_1.runtimeIsLanguage)(endpoint.runtime, "dart"))) {
93
- utils.logLabeledBullet("functions", "Dart functions may not yet be visible in the Firebase Console. " +
94
- `View them in the Cloud Console at https://console.cloud.google.com/run/services?project=${context.projectId}`);
95
- }
96
91
  await setupArtifactCleanupPolicies(options, options.projectId, Object.keys(wantBackend.endpoints));
97
92
  const allErrors = summary.results.filter((r) => r.error).map((r) => r.error);
98
93
  if (allErrors.length) {
@@ -4,6 +4,7 @@ exports.AILogicService = exports.AI_LOGIC_EVENTS = exports.AI_LOGIC_AFTER_GENERA
4
4
  exports.isAILogicEvent = isAILogicEvent;
5
5
  exports.isGlobalAILogicTrigger = isGlobalAILogicTrigger;
6
6
  const backend = require("../backend");
7
+ const build = require("../build");
7
8
  const error_1 = require("../../../error");
8
9
  const ailogicApi = require("../../../gcp/ailogic");
9
10
  const ailogic_1 = require("../../../gcp/ailogic");
@@ -27,19 +28,19 @@ function isGlobalAILogicTrigger(blockingTrigger) {
27
28
  class AILogicService {
28
29
  constructor() {
29
30
  this.ensureTriggerRegion = () => Promise.resolve();
31
+ this.requiredProjectBindings = async (projectNumber) => {
32
+ return [
33
+ {
34
+ role: "roles/run.invoker",
35
+ members: [
36
+ `serviceAccount:service-${projectNumber}@gcp-sa-firebasevertexai.iam.gserviceaccount.com`,
37
+ ],
38
+ },
39
+ ];
40
+ };
30
41
  this.name = "ailogic";
31
42
  this.api = "firebasevertexai.googleapis.com";
32
43
  }
33
- async requiredProjectBindings(projectNumber) {
34
- return [
35
- {
36
- role: "roles/run.invoker",
37
- members: [
38
- `serviceAccount:service-${projectNumber}@gcp-sa-firebasevertexai.iam.gserviceaccount.com`,
39
- ],
40
- },
41
- ];
42
- }
43
44
  validateTrigger(endpoint, wantBackend) {
44
45
  if (!isAILogicEvent(endpoint)) {
45
46
  return;
@@ -91,5 +92,11 @@ class AILogicService {
91
92
  }
92
93
  }
93
94
  }
95
+ async getDefaultRegion(endpoint) {
96
+ if (build.isBlockingTriggered(endpoint) && isGlobalAILogicTrigger(endpoint.blockingTrigger)) {
97
+ return "us-east1";
98
+ }
99
+ return "us-central1";
100
+ }
94
101
  }
95
102
  exports.AILogicService = AILogicService;
@@ -129,5 +129,8 @@ class AuthBlockingService {
129
129
  this.triggerQueue = this.triggerQueue.then(() => this.unregisterTriggerLocked(ep));
130
130
  return this.triggerQueue;
131
131
  }
132
+ async getDefaultRegion() {
133
+ return "us-east1";
134
+ }
132
135
  }
133
136
  exports.AuthBlockingService = AuthBlockingService;
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.clearCache = clearCache;
4
4
  exports.getDatabaseInstanceDetails = getDatabaseInstanceDetails;
5
5
  exports.ensureDatabaseTriggerRegion = ensureDatabaseTriggerRegion;
6
+ exports.getDefaultRegion = getDefaultRegion;
6
7
  const error_1 = require("../../../error");
8
+ const build = require("../build");
7
9
  const database_1 = require("../../../management/database");
8
10
  const instanceCache = new Map();
9
11
  function clearCache() {
@@ -27,3 +29,19 @@ function ensureDatabaseTriggerRegion(endpoint) {
27
29
  }
28
30
  return Promise.resolve();
29
31
  }
32
+ async function getDefaultRegion(endpoint) {
33
+ if (!build.isEventTriggered(endpoint)) {
34
+ throw new error_1.FirebaseError("Database getDefaultRegion requires an event-triggered endpoint");
35
+ }
36
+ if (endpoint.eventTrigger.region) {
37
+ return endpoint.eventTrigger.region;
38
+ }
39
+ const instanceName = endpoint.eventTrigger.eventFilters?.instance;
40
+ if (instanceName) {
41
+ const details = await getDatabaseInstanceDetails(endpoint.project, instanceName);
42
+ if (details.location && details.location !== "-") {
43
+ return details.location.toLowerCase();
44
+ }
45
+ }
46
+ throw new error_1.FirebaseError("Could not resolve database instance location");
47
+ }
@@ -2,8 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ensureDataConnectTriggerRegion = ensureDataConnectTriggerRegion;
4
4
  exports.getDataConnectP4SA = getDataConnectP4SA;
5
+ exports.getDefaultRegion = getDefaultRegion;
5
6
  const api_1 = require("../../../api");
6
7
  const error_1 = require("../../../error");
8
+ const build = require("../build");
9
+ const names_1 = require("../../../dataconnect/names");
7
10
  const AUTOPUSH_DATACONNECT_SA_DOMAIN = "gcp-sa-autopush-dataconnect.iam.gserviceaccount.com";
8
11
  const STAGING_DATACONNECT_SA_DOMAIN = "gcp-sa-staging-dataconnect.iam.gserviceaccount.com";
9
12
  const PROD_DATACONNECT_SA_DOMAIN = "gcp-sa-firebasedataconnect.iam.gserviceaccount.com";
@@ -26,3 +29,20 @@ function getDataConnectP4SA(projectNumber) {
26
29
  }
27
30
  return `service-${projectNumber}@${PROD_DATACONNECT_SA_DOMAIN}`;
28
31
  }
32
+ async function getDefaultRegion(endpoint) {
33
+ if (!build.isEventTriggered(endpoint)) {
34
+ throw new error_1.FirebaseError("DataConnect getDefaultRegion requires an event-triggered endpoint");
35
+ }
36
+ if (endpoint.eventTrigger.region) {
37
+ return endpoint.eventTrigger.region;
38
+ }
39
+ const service = endpoint.eventTrigger.eventFilters?.service;
40
+ if (service) {
41
+ return (0, names_1.parseServiceName)(service).location;
42
+ }
43
+ const connector = endpoint.eventTrigger.eventFilters?.connector;
44
+ if (connector) {
45
+ return (0, names_1.parseConnectorName)(connector).location;
46
+ }
47
+ throw new error_1.FirebaseError("Could not resolve DataConnect location");
48
+ }
@@ -3,8 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.clearCache = clearCache;
4
4
  exports.getDatabase = getDatabase;
5
5
  exports.ensureFirestoreTriggerRegion = ensureFirestoreTriggerRegion;
6
+ exports.getDefaultRegion = getDefaultRegion;
6
7
  const firestore = require("../../../gcp/firestore");
7
8
  const error_1 = require("../../../error");
9
+ const build = require("../build");
10
+ const location_1 = require("../../../gcp/location");
8
11
  const dbCache = new Map();
9
12
  const dbPromiseCache = new Map();
10
13
  function clearCache() {
@@ -43,3 +46,12 @@ async function ensureFirestoreTriggerRegion(endpoint) {
43
46
  throw new error_1.FirebaseError("A firestore trigger location must match the firestore database region.");
44
47
  }
45
48
  }
49
+ async function getDefaultRegion(endpoint) {
50
+ if (!build.isEventTriggered(endpoint)) {
51
+ throw new error_1.FirebaseError("Firestore getDefaultRegion requires an event-triggered endpoint");
52
+ }
53
+ const databaseId = endpoint.eventTrigger.eventFilters?.database || "(default)";
54
+ const db = await getDatabase(endpoint.project, databaseId);
55
+ const locationId = db.locationId.toLowerCase();
56
+ return location_1.FIRESTORE_DUAL_REGION_TO_REGION_MAPPING[locationId] || locationId;
57
+ }
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.noopProjectBindings = exports.noop = void 0;
3
+ exports.FALLBACK_DEPLOYMENT_REGION = exports.DEFAULT_GLOBAL_TRIGGER_REGION = exports.noopProjectBindings = exports.noop = void 0;
4
4
  exports.serviceForEndpoint = serviceForEndpoint;
5
- const backend = require("../backend");
6
5
  const auth_1 = require("./auth");
7
6
  const storage_1 = require("./storage");
8
7
  const firebaseAlerts_1 = require("./firebaseAlerts");
@@ -16,6 +15,8 @@ const noop = () => Promise.resolve();
16
15
  exports.noop = noop;
17
16
  const noopProjectBindings = () => Promise.resolve([]);
18
17
  exports.noopProjectBindings = noopProjectBindings;
18
+ exports.DEFAULT_GLOBAL_TRIGGER_REGION = "us-east1";
19
+ exports.FALLBACK_DEPLOYMENT_REGION = "us-central1";
19
20
  const noOpService = {
20
21
  name: "noop",
21
22
  api: "",
@@ -23,6 +24,7 @@ const noOpService = {
23
24
  validateTrigger: exports.noop,
24
25
  registerTrigger: exports.noop,
25
26
  unregisterTrigger: exports.noop,
27
+ getDefaultRegion: () => Promise.resolve(exports.FALLBACK_DEPLOYMENT_REGION),
26
28
  };
27
29
  const pubSubService = {
28
30
  name: "pubsub",
@@ -32,6 +34,7 @@ const pubSubService = {
32
34
  validateTrigger: exports.noop,
33
35
  registerTrigger: exports.noop,
34
36
  unregisterTrigger: exports.noop,
37
+ getDefaultRegion: () => Promise.resolve(exports.DEFAULT_GLOBAL_TRIGGER_REGION),
35
38
  };
36
39
  const storageService = {
37
40
  name: "storage",
@@ -41,6 +44,7 @@ const storageService = {
41
44
  validateTrigger: exports.noop,
42
45
  registerTrigger: exports.noop,
43
46
  unregisterTrigger: exports.noop,
47
+ getDefaultRegion: storage_1.getDefaultRegion,
44
48
  };
45
49
  const firebaseAlertsService = {
46
50
  name: "firebasealerts",
@@ -50,6 +54,7 @@ const firebaseAlertsService = {
50
54
  validateTrigger: exports.noop,
51
55
  registerTrigger: exports.noop,
52
56
  unregisterTrigger: exports.noop,
57
+ getDefaultRegion: () => Promise.resolve(exports.DEFAULT_GLOBAL_TRIGGER_REGION),
53
58
  };
54
59
  const authBlockingService = new auth_1.AuthBlockingService();
55
60
  const aiLogicService = new ailogic_1.AILogicService();
@@ -61,6 +66,7 @@ const databaseService = {
61
66
  validateTrigger: exports.noop,
62
67
  registerTrigger: exports.noop,
63
68
  unregisterTrigger: exports.noop,
69
+ getDefaultRegion: database_1.getDefaultRegion,
64
70
  };
65
71
  const remoteConfigService = {
66
72
  name: "remoteconfig",
@@ -70,6 +76,7 @@ const remoteConfigService = {
70
76
  validateTrigger: exports.noop,
71
77
  registerTrigger: exports.noop,
72
78
  unregisterTrigger: exports.noop,
79
+ getDefaultRegion: () => Promise.resolve(exports.DEFAULT_GLOBAL_TRIGGER_REGION),
73
80
  };
74
81
  const testLabService = {
75
82
  name: "testlab",
@@ -79,6 +86,7 @@ const testLabService = {
79
86
  validateTrigger: exports.noop,
80
87
  registerTrigger: exports.noop,
81
88
  unregisterTrigger: exports.noop,
89
+ getDefaultRegion: () => Promise.resolve(exports.DEFAULT_GLOBAL_TRIGGER_REGION),
82
90
  };
83
91
  const firestoreService = {
84
92
  name: "firestore",
@@ -88,6 +96,7 @@ const firestoreService = {
88
96
  validateTrigger: exports.noop,
89
97
  registerTrigger: exports.noop,
90
98
  unregisterTrigger: exports.noop,
99
+ getDefaultRegion: firestore_1.getDefaultRegion,
91
100
  };
92
101
  const dataconnectService = {
93
102
  name: "dataconnect",
@@ -97,6 +106,7 @@ const dataconnectService = {
97
106
  validateTrigger: exports.noop,
98
107
  registerTrigger: exports.noop,
99
108
  unregisterTrigger: exports.noop,
109
+ getDefaultRegion: dataconnect_1.getDefaultRegion,
100
110
  };
101
111
  const EVENT_SERVICE_MAPPING = {
102
112
  "google.cloud.pubsub.topic.v1.messagePublished": pubSubService,
@@ -128,11 +138,12 @@ const EVENT_SERVICE_MAPPING = {
128
138
  "google.firebase.ailogic.v1.afterGenerate": aiLogicService,
129
139
  };
130
140
  function serviceForEndpoint(endpoint) {
131
- if (backend.isEventTriggered(endpoint)) {
132
- return EVENT_SERVICE_MAPPING[endpoint.eventTrigger.eventType] || noOpService;
141
+ let eventType;
142
+ if ("eventTrigger" in endpoint && endpoint.eventTrigger?.eventType) {
143
+ eventType = endpoint.eventTrigger.eventType;
133
144
  }
134
- if (backend.isBlockingTriggered(endpoint)) {
135
- return EVENT_SERVICE_MAPPING[endpoint.blockingTrigger.eventType] || noOpService;
145
+ else if ("blockingTrigger" in endpoint && endpoint.blockingTrigger?.eventType) {
146
+ eventType = endpoint.blockingTrigger.eventType;
136
147
  }
137
- return noOpService;
148
+ return eventType ? EVENT_SERVICE_MAPPING[eventType] || noOpService : noOpService;
138
149
  }
@@ -4,10 +4,12 @@ exports.clearCache = clearCache;
4
4
  exports.getBucket = getBucket;
5
5
  exports.obtainStorageBindings = obtainStorageBindings;
6
6
  exports.ensureStorageTriggerRegion = ensureStorageTriggerRegion;
7
+ exports.getDefaultRegion = getDefaultRegion;
7
8
  const storage = require("../../../gcp/storage");
8
9
  const logger_1 = require("../../../logger");
9
10
  const error_1 = require("../../../error");
10
11
  const location_1 = require("../../../gcp/location");
12
+ const build = require("../build");
11
13
  const PUBSUB_PUBLISHER_ROLE = "roles/pubsub.publisher";
12
14
  const bucketCache = new Map();
13
15
  function clearCache() {
@@ -54,3 +56,15 @@ async function ensureStorageTriggerRegion(endpoint) {
54
56
  throw new error_1.FirebaseError(`A function in region ${endpoint.region} cannot listen to a bucket in region ${eventTrigger.region}`);
55
57
  }
56
58
  }
59
+ async function getDefaultRegion(endpoint) {
60
+ if (!build.isEventTriggered(endpoint)) {
61
+ throw new error_1.FirebaseError("Storage getDefaultRegion requires an event-triggered endpoint");
62
+ }
63
+ const bucketName = endpoint.eventTrigger.eventFilters?.bucket;
64
+ if (!bucketName) {
65
+ throw new error_1.FirebaseError("Could not find bucket name in event trigger filters");
66
+ }
67
+ const bucket = await getBucket(bucketName);
68
+ const locationId = bucket.location.toLowerCase();
69
+ return location_1.STORAGE_MULTI_REGION_TO_REGION_MAPPING[locationId] || locationId;
70
+ }
@@ -8,6 +8,7 @@ const utils = require("../../utils");
8
8
  const storage_1 = require("./services/storage");
9
9
  const firestore_1 = require("./services/firestore");
10
10
  const database_1 = require("./services/database");
11
+ const location_1 = require("../../gcp/location");
11
12
  async function ensureTriggerRegions(want) {
12
13
  const regionLookups = [];
13
14
  const triggerRegionMap = new Map();
@@ -78,7 +79,7 @@ async function ensureTriggerRegions(want) {
78
79
  if (ep.region !== "us-central1" || !triggerRegion || triggerRegion === "global") {
79
80
  continue;
80
81
  }
81
- if (!isUSRegion(triggerRegion)) {
82
+ if (!(0, location_1.isUSRegion)(triggerRegion)) {
82
83
  offendingFunctions.push(`- ${ep.id} (us-central1, Trigger: ${triggerRegion})`);
83
84
  }
84
85
  }
@@ -119,6 +120,3 @@ function extractInstanceName(resource) {
119
120
  return resource;
120
121
  return null;
121
122
  }
122
- function isUSRegion(region) {
123
- return region === "us" || region.startsWith("nam") || region.startsWith("us-");
124
- }