firebase-tools 11.24.1 → 11.25.1

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 (37) hide show
  1. package/lib/commands/database-import.js +74 -0
  2. package/lib/commands/firestore-delete.js +12 -7
  3. package/lib/commands/firestore-indexes-list.js +5 -2
  4. package/lib/commands/index.js +1 -0
  5. package/lib/commands/init.js +5 -3
  6. package/lib/commands/logout.js +15 -15
  7. package/lib/database/import.js +125 -0
  8. package/lib/deploy/extensions/prepare.js +0 -14
  9. package/lib/deploy/firestore/deploy.js +22 -16
  10. package/lib/deploy/firestore/prepare.js +34 -24
  11. package/lib/deploy/firestore/release.js +13 -9
  12. package/lib/deploy/functions/prepare.js +1 -1
  13. package/lib/deploy/functions/release/fabricator.js +2 -24
  14. package/lib/deploy/functions/release/index.js +5 -5
  15. package/lib/deploy/functions/services/firestore.js +17 -0
  16. package/lib/deploy/functions/services/index.js +14 -0
  17. package/lib/emulator/controller.js +14 -3
  18. package/lib/extensions/emulator/optionsHelper.js +1 -1
  19. package/lib/extensions/emulator/triggerHelper.js +19 -1
  20. package/lib/extensions/paramHelper.js +7 -49
  21. package/lib/extensions/warnings.js +1 -7
  22. package/lib/firestore/delete.js +6 -1
  23. package/lib/firestore/fsConfig.js +67 -0
  24. package/lib/firestore/indexes.js +13 -13
  25. package/lib/firestore/options.js +2 -0
  26. package/lib/firestore/util.js +9 -7
  27. package/lib/functions/events/v2.js +7 -1
  28. package/lib/gcp/cloudfunctions.js +4 -1
  29. package/lib/gcp/cloudfunctionsv2.js +6 -1
  30. package/lib/gcp/firestore.js +14 -1
  31. package/lib/gcp/run.js +6 -0
  32. package/lib/init/features/hosting/github.js +1 -1
  33. package/lib/rulesDeploy.js +1 -3
  34. package/npm-shrinkwrap.json +41 -2
  35. package/package.json +2 -1
  36. package/schema/firebase-config.json +137 -29
  37. package/templates/init/functions/typescript/_eslintrc +1 -1
@@ -43,15 +43,15 @@ async function release(context, options, payload) {
43
43
  change.endpointsToDelete = [];
44
44
  }
45
45
  }
46
- const functionExecutor = new executor.QueueExecutor({
46
+ const throttlerOptions = {
47
47
  retries: 30,
48
48
  backoff: 20000,
49
49
  concurrency: 40,
50
- maxBackoff: 40000,
51
- });
50
+ maxBackoff: 100000,
51
+ };
52
52
  const fab = new fabricator.Fabricator({
53
- functionExecutor,
54
- executor: new executor.QueueExecutor({}),
53
+ functionExecutor: new executor.QueueExecutor(throttlerOptions),
54
+ executor: new executor.QueueExecutor(throttlerOptions),
55
55
  sources: context.sources,
56
56
  appEngineLocation: (0, functionsConfig_1.getAppEngineLocation)(context.firebaseConfig),
57
57
  projectNumber: options.projectNumber || (await (0, getProjectNumber_1.getProjectNumber)(context.projectId)),
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureFirestoreTriggerRegion = void 0;
4
+ const firestore = require("../../../gcp/firestore");
5
+ const error_1 = require("../../../error");
6
+ async function ensureFirestoreTriggerRegion(endpoint) {
7
+ var _a;
8
+ const db = await firestore.getDatabase(endpoint.project, ((_a = endpoint.eventTrigger.eventFilters) === null || _a === void 0 ? void 0 : _a.database) || "(default)");
9
+ const dbRegion = db.locationId;
10
+ if (!endpoint.eventTrigger.region) {
11
+ endpoint.eventTrigger.region = dbRegion;
12
+ }
13
+ if (endpoint.eventTrigger.region !== dbRegion) {
14
+ throw new error_1.FirebaseError("A firestore trigger location must match the firestore database region.");
15
+ }
16
+ }
17
+ exports.ensureFirestoreTriggerRegion = ensureFirestoreTriggerRegion;
@@ -8,6 +8,7 @@ const firebaseAlerts_1 = require("./firebaseAlerts");
8
8
  const database_1 = require("./database");
9
9
  const remoteConfig_1 = require("./remoteConfig");
10
10
  const testLab_1 = require("./testLab");
11
+ const firestore_1 = require("./firestore");
11
12
  const noop = () => Promise.resolve();
12
13
  exports.noop = noop;
13
14
  const noopProjectBindings = () => Promise.resolve([]);
@@ -75,6 +76,15 @@ const testLabService = {
75
76
  registerTrigger: exports.noop,
76
77
  unregisterTrigger: exports.noop,
77
78
  };
79
+ const firestoreService = {
80
+ name: "firestore",
81
+ api: "firestore.googleapis.com",
82
+ requiredProjectBindings: exports.noopProjectBindings,
83
+ ensureTriggerRegion: firestore_1.ensureFirestoreTriggerRegion,
84
+ validateTrigger: exports.noop,
85
+ registerTrigger: exports.noop,
86
+ unregisterTrigger: exports.noop,
87
+ };
78
88
  const EVENT_SERVICE_MAPPING = {
79
89
  "google.cloud.pubsub.topic.v1.messagePublished": pubSubService,
80
90
  "google.cloud.storage.object.v1.finalized": storageService,
@@ -90,6 +100,10 @@ const EVENT_SERVICE_MAPPING = {
90
100
  "google.firebase.database.ref.v1.deleted": databaseService,
91
101
  "google.firebase.remoteconfig.remoteConfig.v1.updated": remoteConfigService,
92
102
  "google.firebase.testlab.testMatrix.v1.completed": testLabService,
103
+ "google.cloud.firestore.document.v1.written": firestoreService,
104
+ "google.cloud.firestore.document.v1.created": firestoreService,
105
+ "google.cloud.firestore.document.v1.updated": firestoreService,
106
+ "google.cloud.firestore.document.v1.deleted": firestoreService,
93
107
  };
94
108
  function serviceForEndpoint(endpoint) {
95
109
  if (backend.isEventTriggered(endpoint)) {
@@ -4,6 +4,7 @@ exports.exportEmulatorData = exports.startAll = exports.shouldStart = exports.fi
4
4
  const clc = require("colorette");
5
5
  const fs = require("fs");
6
6
  const path = require("path");
7
+ const fsConfig = require("../firestore/fsConfig");
7
8
  const logger_1 = require("../logger");
8
9
  const track_1 = require("../track");
9
10
  const utils = require("../utils");
@@ -151,7 +152,7 @@ function findExportMetadata(importPath) {
151
152
  }
152
153
  }
153
154
  async function startAll(options, showUI = true) {
154
- var _a, _b, _c, _d, _e, _f, _g, _h;
155
+ var _a, _b, _c, _d, _e, _f, _g;
155
156
  const targets = filterEmulatorTargets(options);
156
157
  options.targets = targets;
157
158
  const singleProjectModeEnabled = ((_a = options.config.src.emulators) === null || _a === void 0 ? void 0 : _a.singleProjectMode) === undefined ||
@@ -377,8 +378,18 @@ async function startAll(options, showUI = true) {
377
378
  });
378
379
  }
379
380
  const config = options.config;
380
- const rulesLocalPath = (_h = config.src.firestore) === null || _h === void 0 ? void 0 : _h.rules;
381
- let rulesFileFound = false;
381
+ let rulesLocalPath;
382
+ let rulesFileFound;
383
+ const firestoreConfigs = fsConfig.getFirestoreConfig(projectId, options);
384
+ if (!firestoreConfigs) {
385
+ firestoreLogger.logLabeled("WARN", "firestore", `Cloud Firestore config does not exist in firebase.json.`);
386
+ }
387
+ else if (firestoreConfigs.length !== 1) {
388
+ firestoreLogger.logLabeled("WARN", "firestore", `Cloud Firestore Emulator does not support multiple databases yet.`);
389
+ }
390
+ else if (firestoreConfigs[0].rules) {
391
+ rulesLocalPath = firestoreConfigs[0].rules;
392
+ }
382
393
  if (rulesLocalPath) {
383
394
  const rules = config.path(rulesLocalPath);
384
395
  rulesFileFound = fs.existsSync(rules);
@@ -40,7 +40,7 @@ async function getExtensionFunctionInfo(instance, paramValues) {
40
40
  const spec = await planner.getExtensionSpec(instance);
41
41
  const functionResources = specHelper.getFunctionResourcesWithParamSubstitution(spec, paramValues);
42
42
  const extensionTriggers = functionResources
43
- .map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r))
43
+ .map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r, instance.systemParams))
44
44
  .map((trigger) => {
45
45
  trigger.name = `ext-${instance.instanceId}-${trigger.name}`;
46
46
  return trigger;
@@ -7,7 +7,15 @@ const types_1 = require("../../emulator/types");
7
7
  const error_1 = require("../../error");
8
8
  const types_2 = require("../../extensions/types");
9
9
  const proto = require("../../gcp/proto");
10
- function functionResourceToEmulatedTriggerDefintion(resource) {
10
+ const SUPPORTED_SYSTEM_PARAMS = {
11
+ "firebaseextensions.v1beta.function": {
12
+ regions: "firebaseextensions.v1beta.function/location",
13
+ timeoutSeconds: "firebaseextensions.v1beta.function/timeoutSeconds",
14
+ availableMemoryMb: "firebaseextensions.v1beta.function/memory",
15
+ labels: "firebaseextensions.v1beta.function/labels",
16
+ },
17
+ };
18
+ function functionResourceToEmulatedTriggerDefintion(resource, systemParams = {}) {
11
19
  const resourceType = resource.type;
12
20
  if (resource.type === types_2.FUNCTIONS_RESOURCE_TYPE) {
13
21
  const etd = {
@@ -15,6 +23,16 @@ function functionResourceToEmulatedTriggerDefintion(resource) {
15
23
  entryPoint: resource.name,
16
24
  platform: "gcfv1",
17
25
  };
26
+ proto.convertIfPresent(etd, systemParams, "regions", SUPPORTED_SYSTEM_PARAMS[types_2.FUNCTIONS_RESOURCE_TYPE].regions, (str) => [str]);
27
+ proto.convertIfPresent(etd, systemParams, "timeoutSeconds", SUPPORTED_SYSTEM_PARAMS[types_2.FUNCTIONS_RESOURCE_TYPE].timeoutSeconds, (d) => +d);
28
+ proto.convertIfPresent(etd, systemParams, "availableMemoryMb", SUPPORTED_SYSTEM_PARAMS[types_2.FUNCTIONS_RESOURCE_TYPE].availableMemoryMb, (d) => +d);
29
+ proto.convertIfPresent(etd, systemParams, "labels", SUPPORTED_SYSTEM_PARAMS[types_2.FUNCTIONS_RESOURCE_TYPE].labels, (str) => {
30
+ const ret = {};
31
+ for (const [key, value] of str.split(",").map((label) => label.split(":"))) {
32
+ ret[key] = value;
33
+ }
34
+ return ret;
35
+ });
18
36
  const properties = resource.properties || {};
19
37
  proto.convertIfPresent(etd, properties, "timeoutSeconds", "timeout", proto.secondsFromDuration);
20
38
  proto.convertIfPresent(etd, properties, "regions", "location", (str) => [str]);
@@ -11,7 +11,9 @@ const askUserForParam = require("./askUserForParam");
11
11
  const track_1 = require("../track");
12
12
  const env = require("../functions/env");
13
13
  const utils_1 = require("../utils");
14
- const warnings_1 = require("./warnings");
14
+ const NONINTERACTIVE_ERROR_MESSAGE = "As of firebase-tools@11, `ext:install`, `ext:update` and `ext:configure` are interactive only commands. " +
15
+ "To deploy an extension noninteractively, use an extensions manifest and `firebase deploy --only extensions`. " +
16
+ "See https://firebase.google.com/docs/extensions/manifest for more details";
15
17
  function getBaseParamBindings(params) {
16
18
  let ret = {};
17
19
  for (const [k, v] of Object.entries(params)) {
@@ -46,23 +48,8 @@ function getParamsWithCurrentValuesAsDefaults(extensionInstance) {
46
48
  exports.getParamsWithCurrentValuesAsDefaults = getParamsWithCurrentValuesAsDefaults;
47
49
  async function getParams(args) {
48
50
  let params;
49
- if (args.nonInteractive && !args.paramsEnvPath) {
50
- const paramsMessage = args.paramSpecs
51
- .map((p) => {
52
- return `\t${p.param}${p.required ? "" : " (Optional)"}`;
53
- })
54
- .join("\n");
55
- throw new error_1.FirebaseError("In non-interactive mode but no `--params` flag found. " +
56
- "To install this extension in non-interactive mode, set `--params` to a path to an .env file" +
57
- " containing values for this extension's params:\n" +
58
- paramsMessage);
59
- }
60
- else if (args.paramsEnvPath) {
61
- (0, warnings_1.paramsFlagDeprecationWarning)();
62
- params = getParamsFromFile({
63
- paramSpecs: args.paramSpecs,
64
- paramsEnvPath: args.paramsEnvPath,
65
- });
51
+ if (args.nonInteractive) {
52
+ throw new error_1.FirebaseError(NONINTERACTIVE_ERROR_MESSAGE);
66
53
  }
67
54
  else {
68
55
  const firebaseProjectParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
@@ -81,22 +68,8 @@ async function getParams(args) {
81
68
  exports.getParams = getParams;
82
69
  async function getParamsForUpdate(args) {
83
70
  let params;
84
- if (args.nonInteractive && !args.paramsEnvPath) {
85
- const paramsMessage = args.newSpec.params
86
- .map((p) => {
87
- return `\t${p.param}${p.required ? "" : " (Optional)"}`;
88
- })
89
- .join("\n");
90
- throw new error_1.FirebaseError("In non-interactive mode but no `--params` flag found. " +
91
- "To update this extension in non-interactive mode, set `--params` to a path to an .env file" +
92
- " containing values for this extension's params:\n" +
93
- paramsMessage);
94
- }
95
- else if (args.paramsEnvPath) {
96
- params = getParamsFromFile({
97
- paramSpecs: args.newSpec.params,
98
- paramsEnvPath: args.paramsEnvPath,
99
- });
71
+ if (args.nonInteractive) {
72
+ throw new error_1.FirebaseError(NONINTERACTIVE_ERROR_MESSAGE);
100
73
  }
101
74
  else {
102
75
  params = await promptForNewParams({
@@ -148,21 +121,6 @@ async function promptForNewParams(args) {
148
121
  return newParamBindingOptions;
149
122
  }
150
123
  exports.promptForNewParams = promptForNewParams;
151
- function getParamsFromFile(args) {
152
- let envParams;
153
- try {
154
- envParams = readEnvFile(args.paramsEnvPath);
155
- void (0, track_1.track)("Extension Env File", "Present");
156
- }
157
- catch (err) {
158
- void (0, track_1.track)("Extension Env File", "Invalid");
159
- throw new error_1.FirebaseError(`Error reading env file: ${err.message}\n`, { original: err });
160
- }
161
- const params = (0, extensionsHelper_1.populateDefaultParams)(envParams, args.paramSpecs);
162
- (0, extensionsHelper_1.validateCommandLineParams)(params, args.paramSpecs);
163
- logger_1.logger.info(`Using param values from ${args.paramsEnvPath}`);
164
- return buildBindingOptionsWithBaseValue(params);
165
- }
166
124
  function readEnvFile(envPath) {
167
125
  const buf = fs.readFileSync(path.resolve(envPath), "utf8");
168
126
  const result = env.parse(buf.toString().trim());
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.outOfBandChangesWarning = exports.paramsFlagDeprecationWarning = exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
3
+ exports.outOfBandChangesWarning = exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
4
4
  const marked_1 = require("marked");
5
5
  const clc = require("colorette");
6
6
  const types_1 = require("./types");
@@ -69,12 +69,6 @@ async function displayWarningsForDeploy(instancesToCreate) {
69
69
  return experimental.length > 0 || eapExtensions.length > 0;
70
70
  }
71
71
  exports.displayWarningsForDeploy = displayWarningsForDeploy;
72
- function paramsFlagDeprecationWarning() {
73
- logger_1.logger.warn("The --params flag is deprecated and will be removed in firebase-tools@11. " +
74
- "Instead, use an extensions manifest and `firebase deploy --only extensions` to deploy extensions noninteractively. " +
75
- "See https://firebase.google.com/docs/extensions/manifest for more details");
76
- }
77
- exports.paramsFlagDeprecationWarning = paramsFlagDeprecationWarning;
78
72
  function outOfBandChangesWarning(instanceIds) {
79
73
  logger_1.logger.warn("The following instances may have been changed in the Firebase console or by another machine since the last deploy from this machine.\n\t" +
80
74
  clc.bold(instanceIds.join("\n\t")) +
@@ -17,13 +17,14 @@ class FirestoreDelete {
17
17
  this.recursive = Boolean(options.recursive);
18
18
  this.shallow = Boolean(options.shallow);
19
19
  this.allCollections = Boolean(options.allCollections);
20
+ this.databaseId = options.databaseId;
20
21
  this.readBatchSize = 7500;
21
22
  this.maxPendingDeletes = 15;
22
23
  this.deleteBatchSize = 250;
23
24
  this.maxQueueSize = this.deleteBatchSize * this.maxPendingDeletes * 2;
24
25
  this.path = this.path.replace(/(^\/+|\/+$)/g, "");
25
26
  this.allDescendants = this.recursive;
26
- this.root = "projects/" + project + "/databases/(default)/documents";
27
+ this.root = `projects/${project}/databases/${this.databaseId}/documents`;
27
28
  const segments = this.path.split("/");
28
29
  this.isDocumentPath = segments.length % 2 === 0;
29
30
  this.isCollectionPath = !this.isDocumentPath;
@@ -308,6 +309,7 @@ class FirestoreDelete {
308
309
  const collectionId = collectionIds[i];
309
310
  const deleteOp = new FirestoreDelete(this.project, collectionId, {
310
311
  recursive: true,
312
+ databaseId: this.databaseId,
311
313
  });
312
314
  promises.push(deleteOp.execute());
313
315
  }
@@ -335,6 +337,9 @@ class FirestoreDelete {
335
337
  return this.deletePath();
336
338
  });
337
339
  }
340
+ getRoot() {
341
+ return this.root;
342
+ }
338
343
  }
339
344
  exports.FirestoreDelete = FirestoreDelete;
340
345
  FirestoreDelete.progressBar = new ProgressBar("Deleted :current docs (:rate docs/s)\n", {
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFirestoreConfig = void 0;
4
+ const error_1 = require("../error");
5
+ const logger_1 = require("../logger");
6
+ function getFirestoreConfig(projectId, options) {
7
+ const fsConfig = options.config.src.firestore;
8
+ if (fsConfig === undefined) {
9
+ return [];
10
+ }
11
+ const rc = options.rc;
12
+ let allDatabases = !options.only;
13
+ const onlyDatabases = new Set();
14
+ if (options.only) {
15
+ const split = options.only.split(",");
16
+ if (split.includes("firestore")) {
17
+ allDatabases = true;
18
+ }
19
+ else {
20
+ for (const value of split) {
21
+ if (value.startsWith("firestore:")) {
22
+ const target = value.split(":")[1];
23
+ onlyDatabases.add(target);
24
+ }
25
+ }
26
+ }
27
+ }
28
+ if (!Array.isArray(fsConfig)) {
29
+ if (fsConfig) {
30
+ const databaseId = fsConfig.database || `(default)`;
31
+ return [{ rules: fsConfig.rules, indexes: fsConfig.indexes, database: databaseId }];
32
+ }
33
+ else {
34
+ logger_1.logger.debug("Possibly invalid database config: ", JSON.stringify(fsConfig));
35
+ return [];
36
+ }
37
+ }
38
+ const results = [];
39
+ for (const c of fsConfig) {
40
+ const { database, target } = c;
41
+ if (target) {
42
+ if (allDatabases || onlyDatabases.has(target)) {
43
+ rc.requireTarget(projectId, "firestore", target);
44
+ const databases = rc.target(projectId, "firestore", target);
45
+ for (const database of databases) {
46
+ results.push({ database, rules: c.rules, indexes: c.indexes });
47
+ }
48
+ onlyDatabases.delete(target);
49
+ }
50
+ }
51
+ else if (database) {
52
+ if (allDatabases) {
53
+ results.push(c);
54
+ }
55
+ }
56
+ else {
57
+ throw new error_1.FirebaseError('Must supply either "target" or "databaseId" in firestore config');
58
+ }
59
+ }
60
+ if (!allDatabases && onlyDatabases.size !== 0) {
61
+ throw new error_1.FirebaseError(`Could not find configurations in firebase.json for the following database targets: ${[
62
+ ...onlyDatabases,
63
+ ].join(", ")}`);
64
+ }
65
+ return results;
66
+ }
67
+ exports.getFirestoreConfig = getFirestoreConfig;
@@ -15,7 +15,7 @@ class FirestoreIndexes {
15
15
  constructor() {
16
16
  this.apiClient = new apiv2_1.Client({ urlPrefix: api_1.firestoreOrigin, apiVersion: "v1" });
17
17
  }
18
- async deploy(options, indexes, fieldOverrides) {
18
+ async deploy(options, indexes, fieldOverrides, databaseId = "(default)") {
19
19
  const spec = this.upgradeOldSpec({
20
20
  indexes,
21
21
  fieldOverrides,
@@ -23,8 +23,8 @@ class FirestoreIndexes {
23
23
  this.validateSpec(spec);
24
24
  const indexesToDeploy = spec.indexes;
25
25
  const fieldOverridesToDeploy = spec.fieldOverrides;
26
- const existingIndexes = await this.listIndexes(options.project);
27
- const existingFieldOverrides = await this.listFieldOverrides(options.project);
26
+ const existingIndexes = await this.listIndexes(options.project, databaseId);
27
+ const existingFieldOverrides = await this.listFieldOverrides(options.project, databaseId);
28
28
  const indexesToDelete = existingIndexes.filter((index) => {
29
29
  return !indexesToDeploy.some((spec) => this.indexMatchesSpec(index, spec));
30
30
  });
@@ -68,7 +68,7 @@ class FirestoreIndexes {
68
68
  }
69
69
  else {
70
70
  logger_1.logger.debug(`Creating new index: ${JSON.stringify(index)}`);
71
- await this.createIndex(options.project, index);
71
+ await this.createIndex(options.project, index, databaseId);
72
72
  }
73
73
  }
74
74
  if (shouldDeleteIndexes && indexesToDelete.length > 0) {
@@ -106,7 +106,7 @@ class FirestoreIndexes {
106
106
  }
107
107
  else {
108
108
  logger_1.logger.debug(`Updating field override: ${JSON.stringify(field)}`);
109
- await this.patchField(options.project, field);
109
+ await this.patchField(options.project, field, databaseId);
110
110
  }
111
111
  }
112
112
  if (shouldDeleteFields && fieldOverridesToDelete.length > 0) {
@@ -116,8 +116,8 @@ class FirestoreIndexes {
116
116
  }
117
117
  }
118
118
  }
119
- async listIndexes(project) {
120
- const url = `/projects/${project}/databases/(default)/collectionGroups/-/indexes`;
119
+ async listIndexes(project, databaseId = "(default)") {
120
+ const url = `/projects/${project}/databases/${databaseId}/collectionGroups/-/indexes`;
121
121
  const res = await this.apiClient.get(url);
122
122
  const indexes = res.body.indexes;
123
123
  if (!indexes) {
@@ -135,8 +135,8 @@ class FirestoreIndexes {
135
135
  };
136
136
  });
137
137
  }
138
- async listFieldOverrides(project) {
139
- const parent = `projects/${project}/databases/(default)/collectionGroups/-`;
138
+ async listFieldOverrides(project, databaseId = "(default)") {
139
+ const parent = `projects/${project}/databases/${databaseId}/collectionGroups/-`;
140
140
  const url = `/${parent}/fields?filter=indexConfig.usesAncestorConfig=false OR ttlConfig:*`;
141
141
  const res = await this.apiClient.get(url);
142
142
  const fields = res.body.fields;
@@ -250,8 +250,8 @@ class FirestoreIndexes {
250
250
  }
251
251
  });
252
252
  }
253
- async patchField(project, spec) {
254
- const url = `/projects/${project}/databases/(default)/collectionGroups/${spec.collectionGroup}/fields/${spec.fieldPath}`;
253
+ async patchField(project, spec, databaseId = "(default)") {
254
+ const url = `/projects/${project}/databases/${databaseId}/collectionGroups/${spec.collectionGroup}/fields/${spec.fieldPath}`;
255
255
  const indexes = spec.indexes.map((index) => {
256
256
  return {
257
257
  queryScope: index.queryScope,
@@ -286,8 +286,8 @@ class FirestoreIndexes {
286
286
  const data = {};
287
287
  return this.apiClient.patch(`/${url}`, data);
288
288
  }
289
- createIndex(project, index) {
290
- const url = `/projects/${project}/databases/(default)/collectionGroups/${index.collectionGroup}/indexes`;
289
+ createIndex(project, index, databaseId = "(default)") {
290
+ const url = `/projects/${project}/databases/${databaseId}/collectionGroups/${index.collectionGroup}/indexes`;
291
291
  return this.apiClient.post(url, {
292
292
  fields: index.fields,
293
293
  queryScope: index.queryScope,
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -2,20 +2,21 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.booleanXOR = exports.parseFieldName = exports.parseIndexName = void 0;
4
4
  const error_1 = require("../error");
5
- const INDEX_NAME_REGEX = /projects\/([^\/]+?)\/databases\/\(default\)\/collectionGroups\/([^\/]+?)\/indexes\/([^\/]*)/;
6
- const FIELD_NAME_REGEX = /projects\/([^\/]+?)\/databases\/\(default\)\/collectionGroups\/([^\/]+?)\/fields\/([^\/]*)/;
5
+ const INDEX_NAME_REGEX = /projects\/([^\/]+?)\/databases\/([^\/]+?)\/collectionGroups\/([^\/]+?)\/indexes\/([^\/]*)/;
6
+ const FIELD_NAME_REGEX = /projects\/([^\/]+?)\/databases\/([^\/]+?)\/collectionGroups\/([^\/]+?)\/fields\/([^\/]*)/;
7
7
  function parseIndexName(name) {
8
8
  if (!name) {
9
9
  throw new error_1.FirebaseError(`Cannot parse undefined index name.`);
10
10
  }
11
11
  const m = name.match(INDEX_NAME_REGEX);
12
- if (!m || m.length < 4) {
12
+ if (!m || m.length < 5) {
13
13
  throw new error_1.FirebaseError(`Error parsing index name: ${name}`);
14
14
  }
15
15
  return {
16
16
  projectId: m[1],
17
- collectionGroupId: m[2],
18
- indexId: m[3],
17
+ databaseId: m[2],
18
+ collectionGroupId: m[3],
19
+ indexId: m[4],
19
20
  };
20
21
  }
21
22
  exports.parseIndexName = parseIndexName;
@@ -26,8 +27,9 @@ function parseFieldName(name) {
26
27
  }
27
28
  return {
28
29
  projectId: m[1],
29
- collectionGroupId: m[2],
30
- fieldPath: m[3],
30
+ databaseId: m[2],
31
+ collectionGroupId: m[3],
32
+ fieldPath: m[4],
31
33
  };
32
34
  }
33
35
  exports.parseFieldName = parseFieldName;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TEST_LAB_EVENT = exports.REMOTE_CONFIG_EVENT = exports.DATABASE_EVENTS = exports.FIREBASE_ALERTS_PUBLISH_EVENT = exports.STORAGE_EVENTS = exports.PUBSUB_PUBLISH_EVENT = void 0;
3
+ exports.FIRESTORE_EVENTS = exports.TEST_LAB_EVENT = exports.REMOTE_CONFIG_EVENT = exports.DATABASE_EVENTS = exports.FIREBASE_ALERTS_PUBLISH_EVENT = exports.STORAGE_EVENTS = exports.PUBSUB_PUBLISH_EVENT = void 0;
4
4
  exports.PUBSUB_PUBLISH_EVENT = "google.cloud.pubsub.topic.v1.messagePublished";
5
5
  exports.STORAGE_EVENTS = [
6
6
  "google.cloud.storage.object.v1.finalized",
@@ -17,3 +17,9 @@ exports.DATABASE_EVENTS = [
17
17
  ];
18
18
  exports.REMOTE_CONFIG_EVENT = "google.firebase.remoteconfig.remoteConfig.v1.updated";
19
19
  exports.TEST_LAB_EVENT = "google.firebase.testlab.testMatrix.v1.completed";
20
+ exports.FIRESTORE_EVENTS = [
21
+ "google.cloud.firestore.document.v1.written",
22
+ "google.cloud.firestore.document.v1.created",
23
+ "google.cloud.firestore.document.v1.updated",
24
+ "google.cloud.firestore.document.v1.deleted",
25
+ ];
@@ -15,7 +15,7 @@ const constants_1 = require("../functions/constants");
15
15
  exports.API_VERSION = "v1";
16
16
  const client = new apiv2_1.Client({ urlPrefix: api_1.functionsOrigin, apiVersion: exports.API_VERSION });
17
17
  function functionsOpLogReject(funcName, type, err) {
18
- var _a, _b;
18
+ var _a, _b, _c, _d;
19
19
  if (((_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) === 429) {
20
20
  utils.logWarning(`${clc.bold(clc.yellow("functions:"))} got "Quota Exceeded" error while trying to ${type} ${funcName}. Waiting to retry...`);
21
21
  }
@@ -24,6 +24,7 @@ function functionsOpLogReject(funcName, type, err) {
24
24
  }
25
25
  throw new error_1.FirebaseError(`Failed to ${type} function ${funcName}`, {
26
26
  original: err,
27
+ status: (_d = (_c = err === null || err === void 0 ? void 0 : err.context) === null || _c === void 0 ? void 0 : _c.response) === null || _d === void 0 ? void 0 : _d.statusCode,
27
28
  context: { function: funcName },
28
29
  });
29
30
  }
@@ -57,6 +58,7 @@ async function createFunction(cloudFunction) {
57
58
  }
58
59
  exports.createFunction = createFunction;
59
60
  async function setIamPolicy(options) {
61
+ var _a, _b;
60
62
  const endpoint = `/${options.name}:setIamPolicy`;
61
63
  try {
62
64
  await client.post(endpoint, {
@@ -67,6 +69,7 @@ async function setIamPolicy(options) {
67
69
  catch (err) {
68
70
  throw new error_1.FirebaseError(`Failed to set the IAM Policy on the function ${options.name}`, {
69
71
  original: err,
72
+ status: (_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode,
70
73
  });
71
74
  }
72
75
  }
@@ -49,7 +49,7 @@ function mebibytes(memory) {
49
49
  }
50
50
  exports.mebibytes = mebibytes;
51
51
  function functionsOpLogReject(funcName, type, err) {
52
- var _a, _b;
52
+ var _a, _b, _c, _d;
53
53
  utils.logWarning(clc.bold(clc.yellow("functions:")) + ` ${err === null || err === void 0 ? void 0 : err.message}`);
54
54
  if (((_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) === 429) {
55
55
  utils.logWarning(`${clc.bold(clc.yellow("functions:"))} got "Quota Exceeded" error while trying to ${type} ${funcName}. Waiting to retry...`);
@@ -62,6 +62,7 @@ function functionsOpLogReject(funcName, type, err) {
62
62
  }
63
63
  throw new error_1.FirebaseError(`Failed to ${type} function ${funcName}`, {
64
64
  original: err,
65
+ status: (_d = (_c = err === null || err === void 0 ? void 0 : err.context) === null || _c === void 0 ? void 0 : _c.response) === null || _d === void 0 ? void 0 : _d.statusCode,
65
66
  context: { function: funcName },
66
67
  });
67
68
  }
@@ -182,6 +183,10 @@ function functionFromEndpoint(endpoint, source) {
182
183
  gcfFunction.serviceConfig.availableMemory = mem > 1024 ? `${mem / 1024}Gi` : `${mem}Mi`;
183
184
  proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "minInstanceCount", "minInstances");
184
185
  proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "maxInstanceCount", "maxInstances");
186
+ proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "maxInstanceRequestConcurrency", "concurrency");
187
+ proto.convertIfPresent(gcfFunction.serviceConfig, endpoint, "availableCpu", "cpu", (cpu) => {
188
+ return String(cpu);
189
+ });
185
190
  if (endpoint.vpc) {
186
191
  proto.renameIfPresent(gcfFunction.serviceConfig, endpoint.vpc, "vpcConnector", "connector");
187
192
  proto.renameIfPresent(gcfFunction.serviceConfig, endpoint.vpc, "vpcConnectorEgressSettings", "egressSettings");
@@ -1,13 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteDocuments = exports.deleteDocument = exports.listCollectionIds = void 0;
3
+ exports.deleteDocuments = exports.deleteDocument = exports.listCollectionIds = exports.getDatabase = void 0;
4
4
  const api_1 = require("../api");
5
5
  const apiv2_1 = require("../apiv2");
6
+ const logger_1 = require("../logger");
6
7
  const apiClient = new apiv2_1.Client({
7
8
  auth: true,
8
9
  apiVersion: "v1",
9
10
  urlPrefix: api_1.firestoreOriginOrEmulator,
10
11
  });
12
+ async function getDatabase(project, database) {
13
+ const url = `projects/${project}/databases/${database}`;
14
+ try {
15
+ const resp = await apiClient.get(url);
16
+ return resp.body;
17
+ }
18
+ catch (err) {
19
+ logger_1.logger.info(`There was an error retrieving the Firestore database. Currently, the database id is set to ${database}, make sure it exists.`);
20
+ throw err;
21
+ }
22
+ }
23
+ exports.getDatabase = getDatabase;
11
24
  function listCollectionIds(project) {
12
25
  const url = "projects/" + project + "/databases/(default)/documents:listCollectionIds";
13
26
  const data = {
package/lib/gcp/run.js CHANGED
@@ -24,6 +24,7 @@ function gcpIds(service) {
24
24
  }
25
25
  exports.gcpIds = gcpIds;
26
26
  async function getService(name) {
27
+ var _a, _b;
27
28
  try {
28
29
  const response = await client.get(name);
29
30
  return response.body;
@@ -31,6 +32,7 @@ async function getService(name) {
31
32
  catch (err) {
32
33
  throw new error_1.FirebaseError(`Failed to fetch Run service ${name}`, {
33
34
  original: err,
35
+ status: (_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode,
34
36
  });
35
37
  }
36
38
  }
@@ -71,6 +73,7 @@ function serviceIsResolved(service) {
71
73
  }
72
74
  exports.serviceIsResolved = serviceIsResolved;
73
75
  async function replaceService(name, service) {
76
+ var _a, _b;
74
77
  try {
75
78
  const response = await client.put(name, service);
76
79
  return response.body;
@@ -78,11 +81,13 @@ async function replaceService(name, service) {
78
81
  catch (err) {
79
82
  throw new error_1.FirebaseError(`Failed to replace Run service ${name}`, {
80
83
  original: err,
84
+ status: (_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode,
81
85
  });
82
86
  }
83
87
  }
84
88
  exports.replaceService = replaceService;
85
89
  async function setIamPolicy(name, policy, httpClient = client) {
90
+ var _a, _b;
86
91
  try {
87
92
  await httpClient.post(`${name}:setIamPolicy`, {
88
93
  policy,
@@ -92,6 +97,7 @@ async function setIamPolicy(name, policy, httpClient = client) {
92
97
  catch (err) {
93
98
  throw new error_1.FirebaseError(`Failed to set the IAM Policy on the Service ${name}`, {
94
99
  original: err,
100
+ status: (_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode,
95
101
  });
96
102
  }
97
103
  }
@@ -24,7 +24,7 @@ let YML_FULL_PATH_PULL_REQUEST;
24
24
  let YML_FULL_PATH_MERGE;
25
25
  const YML_PULL_REQUEST_FILENAME = "firebase-hosting-pull-request.yml";
26
26
  const YML_MERGE_FILENAME = "firebase-hosting-merge.yml";
27
- const CHECKOUT_GITHUB_ACTION_NAME = "actions/checkout@v2";
27
+ const CHECKOUT_GITHUB_ACTION_NAME = "actions/checkout@v3";
28
28
  const HOSTING_GITHUB_ACTION_NAME = "FirebaseExtended/action-hosting-deploy@v0";
29
29
  const githubApiClient = new apiv2_1.Client({ urlPrefix: api_1.githubApiOrigin, auth: false });
30
30
  async function initGitHub(setup) {