firebase-tools 14.15.1 → 14.16.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/commands/dataconnect-sdk-generate.js +28 -24
  2. package/lib/commands/firestore-bulkdelete.js +73 -0
  3. package/lib/commands/firestore-operations-cancel.js +44 -0
  4. package/lib/commands/firestore-operations-describe.js +29 -0
  5. package/lib/commands/firestore-operations-list.js +29 -0
  6. package/lib/commands/firestore-utils.js +15 -0
  7. package/lib/commands/functions-config-export.js +5 -2
  8. package/lib/commands/index.js +5 -0
  9. package/lib/config.js +16 -4
  10. package/lib/dataconnect/ensureApis.js +3 -3
  11. package/lib/deploy/functions/build.js +2 -13
  12. package/lib/deploy/functions/deploy.js +4 -3
  13. package/lib/deploy/functions/prepare.js +10 -7
  14. package/lib/deploy/functions/runtimes/discovery/index.js +1 -1
  15. package/lib/emulator/auth/operations.js +10 -1
  16. package/lib/emulator/commandUtils.js +7 -1
  17. package/lib/emulator/controller.js +15 -31
  18. package/lib/emulator/dataconnectEmulator.js +27 -24
  19. package/lib/emulator/downloadableEmulatorInfo.json +18 -18
  20. package/lib/emulator/functionsEmulator.js +1 -1
  21. package/lib/emulator/hub.js +9 -5
  22. package/lib/extensions/runtimes/common.js +3 -2
  23. package/lib/firestore/api.js +45 -0
  24. package/lib/firestore/pretty-print.js +23 -0
  25. package/lib/functions/env.js +12 -1
  26. package/lib/functions/projectConfig.js +69 -9
  27. package/lib/gcp/cloudfunctions.js +1 -6
  28. package/lib/gcp/cloudfunctionsv2.js +1 -9
  29. package/lib/gcp/cloudsql/cloudsqladmin.js +2 -2
  30. package/lib/init/features/dataconnect/create_app.js +7 -2
  31. package/lib/init/features/dataconnect/index.js +72 -56
  32. package/lib/init/features/dataconnect/sdk.js +23 -11
  33. package/lib/mcp/errors.js +2 -10
  34. package/lib/mcp/index.js +1 -4
  35. package/lib/mcp/prompts/core/deploy.js +1 -1
  36. package/lib/mcp/prompts/crashlytics/connect.js +114 -0
  37. package/lib/mcp/prompts/crashlytics/index.js +2 -3
  38. package/lib/mcp/tools/auth/disable_user.js +1 -1
  39. package/lib/mcp/tools/auth/get_user.js +9 -2
  40. package/lib/mcp/tools/core/index.js +4 -0
  41. package/lib/mcp/tools/core/init.js +11 -2
  42. package/lib/mcp/tools/core/login.js +46 -0
  43. package/lib/mcp/tools/core/logout.js +62 -0
  44. package/lib/mcp/tools/dataconnect/execute.js +71 -0
  45. package/lib/mcp/tools/dataconnect/index.js +3 -13
  46. package/lib/mcp/tools/dataconnect/list_services.js +104 -7
  47. package/lib/mcp/util.js +1 -17
  48. package/lib/serve/functions.js +4 -3
  49. package/lib/track.js +16 -0
  50. package/lib/unzip.js +13 -0
  51. package/lib/utils.js +17 -1
  52. package/package.json +1 -1
  53. package/schema/firebase-config.json +160 -59
  54. package/lib/mcp/prompts/crashlytics/common.js +0 -10
  55. package/lib/mcp/prompts/crashlytics/fix_issue.js +0 -89
  56. package/lib/mcp/prompts/crashlytics/prioritize_issues.js +0 -79
  57. package/lib/mcp/tools/database/set_rules.js +0 -41
  58. package/lib/mcp/tools/dataconnect/execute_graphql.js +0 -48
  59. package/lib/mcp/tools/dataconnect/execute_graphql_read.js +0 -48
  60. package/lib/mcp/tools/dataconnect/execute_mutation.js +0 -62
  61. package/lib/mcp/tools/dataconnect/execute_query.js +0 -62
  62. package/lib/mcp/tools/dataconnect/get_connector.js +0 -31
  63. package/lib/mcp/tools/dataconnect/get_schema.js +0 -31
@@ -8,37 +8,41 @@ const projectUtils_1 = require("../projectUtils");
8
8
  const load_1 = require("../dataconnect/load");
9
9
  const logger_1 = require("../logger");
10
10
  const auth_1 = require("../auth");
11
+ const utils_1 = require("../utils");
11
12
  exports.command = new command_1.Command("dataconnect:sdk:generate")
12
13
  .description("generate typed SDKs for your Data Connect connectors")
13
14
  .option("--watch", "watch for changes to your connector GQL files and regenerate your SDKs when updates occur")
14
15
  .action(async (options) => {
15
16
  const projectId = (0, projectUtils_1.needProjectId)(options);
16
17
  const serviceInfos = await (0, load_1.loadAll)(projectId, options.config);
17
- for (const serviceInfo of serviceInfos) {
18
- const configDir = serviceInfo.sourceDirectory;
19
- const hasGeneratables = serviceInfo.connectorInfo.some((c) => {
20
- var _a, _b, _c, _d;
21
- return (((_a = c.connectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk) ||
22
- ((_b = c.connectorYaml.generate) === null || _b === void 0 ? void 0 : _b.kotlinSdk) ||
23
- ((_c = c.connectorYaml.generate) === null || _c === void 0 ? void 0 : _c.swiftSdk) ||
24
- ((_d = c.connectorYaml.generate) === null || _d === void 0 ? void 0 : _d.dartSdk));
18
+ const serviceInfosWithSDKs = serviceInfos.filter((serviceInfo) => serviceInfo.connectorInfo.some((c) => {
19
+ var _a, _b, _c, _d;
20
+ return (((_a = c.connectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk) ||
21
+ ((_b = c.connectorYaml.generate) === null || _b === void 0 ? void 0 : _b.kotlinSdk) ||
22
+ ((_c = c.connectorYaml.generate) === null || _c === void 0 ? void 0 : _c.swiftSdk) ||
23
+ ((_d = c.connectorYaml.generate) === null || _d === void 0 ? void 0 : _d.dartSdk));
24
+ }));
25
+ if (!serviceInfosWithSDKs.length) {
26
+ logger_1.logger.warn("No generated SDKs have been declared in connector.yaml files.");
27
+ logger_1.logger.warn(`Run ${clc.bold("firebase init dataconnect:sdk")} to configure a generated SDK.`);
28
+ logger_1.logger.warn(`See https://firebase.google.com/docs/data-connect/web-sdk for more details of how to configure generated SDKs.`);
29
+ return;
30
+ }
31
+ async function generateSDK(serviceInfo) {
32
+ return dataconnectEmulator_1.DataConnectEmulator.generate({
33
+ configDir: serviceInfo.sourceDirectory,
34
+ watch: options.watch,
35
+ account: (0, auth_1.getProjectDefaultAccount)(options.projectRoot),
25
36
  });
26
- if (!hasGeneratables) {
27
- logger_1.logger.warn("No generated SDKs have been declared in connector.yaml files.");
28
- logger_1.logger.warn(`Run ${clc.bold("firebase init dataconnect:sdk")} to configure a generated SDK.`);
29
- logger_1.logger.warn(`See https://firebase.google.com/docs/data-connect/web-sdk for more details of how to configure generated SDKs.`);
30
- return;
31
- }
32
- for (const conn of serviceInfo.connectorInfo) {
33
- const account = (0, auth_1.getProjectDefaultAccount)(options.projectRoot);
34
- const output = await dataconnectEmulator_1.DataConnectEmulator.generate({
35
- configDir,
36
- connectorId: conn.connectorYaml.connectorId,
37
- watch: options.watch,
38
- account,
39
- });
40
- logger_1.logger.info(output);
41
- logger_1.logger.info(`Generated SDKs for ${conn.connectorYaml.connectorId}`);
37
+ }
38
+ if (options.watch) {
39
+ await Promise.race(serviceInfosWithSDKs.map(generateSDK));
40
+ }
41
+ else {
42
+ for (const s of serviceInfosWithSDKs) {
43
+ await generateSDK(s);
42
44
  }
45
+ const services = serviceInfosWithSDKs.map((s) => s.dataConnectYaml.serviceId).join(", ");
46
+ (0, utils_1.logLabeledSuccess)("dataconnect", `Successfully Generated SDKs for services: ${clc.bold(services)}`);
43
47
  }
44
48
  });
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const command_1 = require("../command");
5
+ const fsi = require("../firestore/api");
6
+ const logger_1 = require("../logger");
7
+ const requirePermissions_1 = require("../requirePermissions");
8
+ const types_1 = require("../emulator/types");
9
+ const commandUtils_1 = require("../emulator/commandUtils");
10
+ const prompt_1 = require("../prompt");
11
+ const utils = require("../utils");
12
+ const clc = require("colorette");
13
+ const utils_1 = require("../utils");
14
+ const error_1 = require("../error");
15
+ function confirmationMessage(options, databaseId, collectionIds) {
16
+ const root = `projects/${options.project}/databases/${databaseId}/documents`;
17
+ return ("You are about to delete all documents in the following collection groups: " +
18
+ clc.cyan(collectionIds.map((item) => `"${item}"`).join(", ")) +
19
+ " in " +
20
+ clc.cyan(`"${root}"`) +
21
+ ". Are you sure?");
22
+ }
23
+ exports.command = new command_1.Command("firestore:bulkdelete")
24
+ .description("managed bulk delete service to delete data from one or more collection groups")
25
+ .option("--database <databaseName>", 'Database ID for database to delete from. "(default)" if none is provided.')
26
+ .option("--collection-ids <collectionIds>", "A comma-separated list of collection group IDs to delete. Deletes all documents in the specified collection groups.")
27
+ .before(requirePermissions_1.requirePermissions, ["datastore.databases.bulkDeleteDocuments"])
28
+ .before(commandUtils_1.warnEmulatorNotSupported, types_1.Emulators.FIRESTORE)
29
+ .action(async (options) => {
30
+ if (!options.collectionIds) {
31
+ throw new error_1.FirebaseError("Missing required flag --collection-ids=[comma separated list of collection groups]");
32
+ }
33
+ let collectionIds = [];
34
+ try {
35
+ collectionIds = options.collectionIds
36
+ .split(",")
37
+ .filter((id) => id.trim() !== "");
38
+ }
39
+ catch (e) {
40
+ throw new error_1.FirebaseError("The value for --collection-ids must a list of comma separated collection group names");
41
+ }
42
+ if (collectionIds.length === 0) {
43
+ throw new error_1.FirebaseError("Must specify at least one collection ID in --collection-ids.");
44
+ }
45
+ const databaseId = options.database || "(default)";
46
+ const api = new fsi.FirestoreApi();
47
+ const confirmed = await (0, prompt_1.confirm)({
48
+ message: confirmationMessage(options, databaseId, collectionIds),
49
+ default: false,
50
+ force: options.force,
51
+ nonInteractive: options.nonInteractive,
52
+ });
53
+ if (!confirmed) {
54
+ return utils.reject("Command aborted.", { exit: 1 });
55
+ }
56
+ const op = await api.bulkDeleteDocuments(options.project, databaseId, collectionIds);
57
+ if (options.json) {
58
+ logger_1.logger.info(JSON.stringify(op, undefined, 2));
59
+ }
60
+ else {
61
+ if (op.name) {
62
+ (0, utils_1.logSuccess)(`Successfully started bulk delete operation.`);
63
+ (0, utils_1.logBullet)(`Operation name: ` + clc.cyan(op.name));
64
+ (0, utils_1.logBullet)("You can monitor the operation's progress using the " +
65
+ clc.cyan(`gcloud firestore operations describe`) +
66
+ ` command.`);
67
+ }
68
+ else {
69
+ (0, utils_1.logLabeledError)(`Bulk Delete:`, `Failed to start a bulk delete operation.`);
70
+ }
71
+ }
72
+ return op;
73
+ });
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const command_1 = require("../command");
5
+ const fsi = require("../firestore/api");
6
+ const types_1 = require("../emulator/types");
7
+ const commandUtils_1 = require("../emulator/commandUtils");
8
+ const firestore_utils_1 = require("./firestore-utils");
9
+ const prompt_1 = require("../prompt");
10
+ const clc = require("colorette");
11
+ const utils = require("../utils");
12
+ const logger_1 = require("../logger");
13
+ exports.command = new command_1.Command("firestore:operations:cancel <operationName>")
14
+ .description("cancels a long-running Cloud Firestore admin operation")
15
+ .option("--database <databaseName>", 'Database ID for which the operation is running. "(default)" if none is provided.')
16
+ .option("--force", "Forces the operation cancellation without asking for confirmation")
17
+ .before(commandUtils_1.errorMissingProject)
18
+ .before(commandUtils_1.warnEmulatorNotSupported, types_1.Emulators.FIRESTORE)
19
+ .action(async (operationName, options) => {
20
+ const databaseId = options.database || "(default)";
21
+ operationName = (0, firestore_utils_1.getShortOperationName)(operationName);
22
+ if (!options.force) {
23
+ const fullName = `/projects/${options.project}/databases/${databaseId}/operations/${operationName}`;
24
+ const confirmMessage = `You are about to cancel the operation: ${clc.bold(clc.yellow(clc.underline(fullName)))}. Do you wish to continue?`;
25
+ const consent = await (0, prompt_1.confirm)(confirmMessage);
26
+ if (!consent) {
27
+ return utils.reject("Command aborted.", { exit: 1 });
28
+ }
29
+ }
30
+ const api = new fsi.FirestoreApi();
31
+ const status = await api.cancelOperation(options.project, databaseId, operationName);
32
+ if (options.json) {
33
+ logger_1.logger.info(JSON.stringify(status, undefined, 2));
34
+ }
35
+ else {
36
+ if (status.success) {
37
+ utils.logSuccess("Operation cancelled successfully.");
38
+ }
39
+ else {
40
+ utils.logWarning("Canceling the operation failed.");
41
+ }
42
+ }
43
+ return status;
44
+ });
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const command_1 = require("../command");
5
+ const fsi = require("../firestore/api");
6
+ const logger_1 = require("../logger");
7
+ const types_1 = require("../emulator/types");
8
+ const commandUtils_1 = require("../emulator/commandUtils");
9
+ const pretty_print_1 = require("../firestore/pretty-print");
10
+ const firestore_utils_1 = require("./firestore-utils");
11
+ exports.command = new command_1.Command("firestore:operations:describe <operationName>")
12
+ .description("retrieves information about a Cloud Firestore admin operation")
13
+ .option("--database <databaseName>", 'Database ID for which the operation is running. "(default)" if none is provided.')
14
+ .before(commandUtils_1.errorMissingProject)
15
+ .before(commandUtils_1.warnEmulatorNotSupported, types_1.Emulators.FIRESTORE)
16
+ .action(async (operationName, options) => {
17
+ const databaseId = options.database || "(default)";
18
+ operationName = (0, firestore_utils_1.getShortOperationName)(operationName);
19
+ const api = new fsi.FirestoreApi();
20
+ const operation = await api.describeOperation(options.project, databaseId, operationName);
21
+ if (options.json) {
22
+ logger_1.logger.info(JSON.stringify(operation, undefined, 2));
23
+ }
24
+ else {
25
+ const printer = new pretty_print_1.PrettyPrint();
26
+ printer.prettyPrintOperation(operation);
27
+ }
28
+ return operation;
29
+ });
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const command_1 = require("../command");
5
+ const fsi = require("../firestore/api");
6
+ const logger_1 = require("../logger");
7
+ const types_1 = require("../emulator/types");
8
+ const commandUtils_1 = require("../emulator/commandUtils");
9
+ const pretty_print_1 = require("../firestore/pretty-print");
10
+ exports.command = new command_1.Command("firestore:operations:list")
11
+ .description("list pending Cloud Firestore admin operations and their status")
12
+ .option("--database <databaseName>", 'Database ID for database to list operations for. "(default)" if none is provided.')
13
+ .option("--limit <number>", "The maximum number of operations to list. Uses 100 by default.")
14
+ .before(commandUtils_1.errorMissingProject)
15
+ .before(commandUtils_1.warnEmulatorNotSupported, types_1.Emulators.FIRESTORE)
16
+ .action(async (options) => {
17
+ const databaseId = options.database || "(default)";
18
+ const limit = options.limit === undefined ? 100 : Number(options.limit);
19
+ const api = new fsi.FirestoreApi();
20
+ const { operations } = await api.listOperations(options.project, databaseId, limit);
21
+ if (options.json) {
22
+ logger_1.logger.info(JSON.stringify(operations, undefined, 2));
23
+ }
24
+ else {
25
+ const printer = new pretty_print_1.PrettyPrint();
26
+ printer.prettyPrintOperations(operations);
27
+ }
28
+ return operations;
29
+ });
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getShortOperationName = void 0;
4
+ const error_1 = require("../error");
5
+ function getShortOperationName(operationName) {
6
+ let opName = operationName;
7
+ if (operationName.includes("/operations/")) {
8
+ opName = operationName.split("/operations/")[1];
9
+ }
10
+ if (opName.length === 0 || opName.includes("/")) {
11
+ throw new error_1.FirebaseError(`"${operationName}" is not a valid operation name.`);
12
+ }
13
+ return opName;
14
+ }
15
+ exports.getShortOperationName = getShortOperationName;
@@ -78,7 +78,10 @@ exports.command = new command_1.Command("functions:config:export")
78
78
  .before(requireInteractive_1.default)
79
79
  .action(async (options) => {
80
80
  const config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)[0];
81
- const functionsDir = config.source;
81
+ const configDir = (0, projectConfig_1.resolveConfigDir)(config);
82
+ if (!configDir) {
83
+ throw new error_1.FirebaseError("functions:config:export requires a local env directory. Set functions[].configDir in firebase.json when using remoteSource.");
84
+ }
82
85
  let pInfos = configExport.getProjectInfos(options);
83
86
  checkReservedAliases(pInfos);
84
87
  (0, utils_1.logBullet)("Importing functions configs from projects [" +
@@ -111,6 +114,6 @@ exports.command = new command_1.Command("functions:config:export")
111
114
  filesToWrite[".env"] =
112
115
  `${header}# .env file contains environment variables that applies to all projects.\n`;
113
116
  for (const [filename, content] of Object.entries(filesToWrite)) {
114
- await options.config.askWriteProjectFile(path.join(functionsDir, filename), content);
117
+ await options.config.askWriteProjectFile(path.join(configDir, filename), content);
115
118
  }
116
119
  });
@@ -96,8 +96,13 @@ function load(client) {
96
96
  client.ext.dev.usage = loadCommand("ext-dev-usage");
97
97
  client.firestore = {};
98
98
  client.firestore.delete = loadCommand("firestore-delete");
99
+ client.firestore.bulkDelete = loadCommand("firestore-bulkdelete");
99
100
  client.firestore.indexes = loadCommand("firestore-indexes-list");
100
101
  client.firestore.locations = loadCommand("firestore-locations");
102
+ client.firestore.operations = {};
103
+ client.firestore.operations.cancel = loadCommand("firestore-operations-cancel");
104
+ client.firestore.operations.describe = loadCommand("firestore-operations-describe");
105
+ client.firestore.operations.list = loadCommand("firestore-operations-list");
101
106
  client.firestore.databases = {};
102
107
  client.firestore.databases.list = loadCommand("firestore-databases-list");
103
108
  client.firestore.databases.get = loadCommand("firestore-databases-get");
package/lib/config.js CHANGED
@@ -42,13 +42,25 @@ class Config {
42
42
  });
43
43
  if (this.get("functions")) {
44
44
  if (this.projectDir && fsutils.dirExistsSync(this.path(Config.DEFAULT_FUNCTIONS_SOURCE))) {
45
- if (Array.isArray(this.get("functions"))) {
46
- if (!this.get("functions.[0].source")) {
47
- this.set("functions.[0].source", Config.DEFAULT_FUNCTIONS_SOURCE);
45
+ const funcs = this.get("functions");
46
+ if (Array.isArray(funcs)) {
47
+ let emptyIdx;
48
+ for (let i = 0; i < funcs.length; i++) {
49
+ const hasSource = this.get(`functions.[${i}].source`);
50
+ const hasRemote = this.get(`functions.[${i}].remoteSource`);
51
+ if (!hasSource && !hasRemote) {
52
+ emptyIdx = i;
53
+ break;
54
+ }
55
+ }
56
+ if (emptyIdx !== undefined) {
57
+ this.set(`functions.[${emptyIdx}].source`, Config.DEFAULT_FUNCTIONS_SOURCE);
48
58
  }
49
59
  }
50
60
  else {
51
- if (!this.get("functions.source")) {
61
+ const hasSource = this.get("functions.source");
62
+ const hasRemote = this.get("functions.remoteSource");
63
+ if (!hasSource && !hasRemote) {
52
64
  this.set("functions.source", Config.DEFAULT_FUNCTIONS_SOURCE);
53
65
  }
54
66
  }
@@ -4,10 +4,10 @@ exports.ensureGIFApis = exports.ensureApis = void 0;
4
4
  const api = require("../api");
5
5
  const ensureApiEnabled_1 = require("../ensureApiEnabled");
6
6
  const prefix = "dataconnect";
7
- async function ensureApis(projectId) {
7
+ async function ensureApis(projectId, silent = false) {
8
8
  await Promise.all([
9
- (0, ensureApiEnabled_1.ensure)(projectId, api.dataconnectOrigin(), prefix),
10
- (0, ensureApiEnabled_1.ensure)(projectId, api.cloudSQLAdminOrigin(), prefix),
9
+ (0, ensureApiEnabled_1.ensure)(projectId, api.dataconnectOrigin(), prefix, silent),
10
+ (0, ensureApiEnabled_1.ensure)(projectId, api.cloudSQLAdminOrigin(), prefix, silent),
11
11
  ]);
12
12
  }
13
13
  exports.ensureApis = ensureApis;
@@ -3,11 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.applyPrefix = exports.toBackend = exports.envWithTypes = exports.resolveBackend = exports.AllIngressSettings = exports.AllVpcEgressSettings = exports.AllFunctionsPlatforms = 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
- const api = require("../../.../../api");
6
+ const api = require("../../api");
7
7
  const params = require("./params");
8
8
  const error_1 = require("../../error");
9
9
  const functional_1 = require("../../functional");
10
- const env_1 = require("../../functions/env");
11
10
  const cel_1 = require("./cel");
12
11
  function empty() {
13
12
  return {
@@ -56,17 +55,7 @@ exports.AllIngressSettings = [
56
55
  "ALLOW_INTERNAL_AND_GCLB",
57
56
  ];
58
57
  async function resolveBackend(opts) {
59
- let paramValues = {};
60
- paramValues = await params.resolveParams(opts.build.params, opts.firebaseConfig, envWithTypes(opts.build.params, opts.userEnvs), opts.nonInteractive, opts.isEmulator);
61
- const toWrite = {};
62
- for (const paramName of Object.keys(paramValues)) {
63
- const paramValue = paramValues[paramName];
64
- if (Object.prototype.hasOwnProperty.call(opts.userEnvs, paramName) || paramValue.internal) {
65
- continue;
66
- }
67
- toWrite[paramName] = paramValue.toString();
68
- }
69
- (0, env_1.writeUserEnvs)(toWrite, opts.userEnvOpt);
58
+ const paramValues = await params.resolveParams(opts.build.params, opts.firebaseConfig, envWithTypes(opts.build.params, opts.userEnvs), opts.nonInteractive, opts.isEmulator);
70
59
  return { backend: toBackend(opts.build, paramValues), envs: paramValues };
71
60
  }
72
61
  exports.resolveBackend = resolveBackend;
@@ -51,7 +51,7 @@ async function uploadSourceV2(projectId, source, wantBackend) {
51
51
  return res.storageSource;
52
52
  }
53
53
  async function uploadCodebase(context, codebase, wantBackend) {
54
- var _a;
54
+ var _a, _b, _c, _d;
55
55
  const source = (_a = context.sources) === null || _a === void 0 ? void 0 : _a[codebase];
56
56
  if (!source || (!source.functionsSourceV1 && !source.functionsSourceV2)) {
57
57
  return;
@@ -67,9 +67,10 @@ async function uploadCodebase(context, codebase, wantBackend) {
67
67
  if (storage) {
68
68
  source.storage = storage;
69
69
  }
70
- const sourceDir = (0, projectConfig_1.configForCodebase)(context.config, codebase).source;
70
+ const cfg = (0, projectConfig_1.configForCodebase)(context.config, codebase);
71
+ const label = (_d = (_b = cfg.source) !== null && _b !== void 0 ? _b : (_c = cfg.remoteSource) === null || _c === void 0 ? void 0 : _c.dir) !== null && _d !== void 0 ? _d : "remote";
71
72
  if (uploads.length) {
72
- (0, utils_1.logSuccess)(`${clc.green(clc.bold("functions:"))} ${clc.bold(sourceDir)} folder uploaded successfully`);
73
+ (0, utils_1.logLabeledSuccess)("functions", `${clc.bold(label)} source uploaded successfully`);
73
74
  }
74
75
  }
75
76
  catch (err) {
@@ -59,6 +59,7 @@ async function prepare(context, options, payload) {
59
59
  if (allowFunctionsConfig && checkAPIsEnabled[1]) {
60
60
  runtimeConfig = Object.assign(Object.assign({}, runtimeConfig), (await (0, prepareFunctionsUpload_1.getFunctionsConfig)(projectId)));
61
61
  }
62
+ context.hasRuntimeConfig = Object.keys(runtimeConfig).some((k) => k !== "firebase");
62
63
  const wantBuilds = await loadCodebases(context.config, options, firebaseConfig, runtimeConfig, context.filters);
63
64
  if (Object.values(wantBuilds).some((b) => b.extensions)) {
64
65
  const extContext = {};
@@ -72,22 +73,23 @@ async function prepare(context, options, payload) {
72
73
  for (const [codebase, wantBuild] of Object.entries(wantBuilds)) {
73
74
  const config = (0, projectConfig_1.configForCodebase)(context.config, codebase);
74
75
  const firebaseEnvs = functionsEnv.loadFirebaseEnvs(firebaseConfig, projectId);
76
+ const localCfg = (0, projectConfig_1.requireLocal)(config, "Remote sources are not supported.");
75
77
  const userEnvOpt = {
76
- functionsSource: options.config.path(config.source),
78
+ functionsSource: options.config.path(localCfg.source),
77
79
  projectId: projectId,
78
80
  projectAlias: options.projectAlias,
79
81
  };
80
- proto.convertIfPresent(userEnvOpt, config, "configDir", (cd) => options.config.path(cd));
82
+ proto.convertIfPresent(userEnvOpt, localCfg, "configDir", (cd) => options.config.path(cd));
81
83
  const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
82
84
  const envs = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
83
85
  const { backend: wantBackend, envs: resolvedEnvs } = await build.resolveBackend({
84
86
  build: wantBuild,
85
87
  firebaseConfig,
86
- userEnvOpt,
87
88
  userEnvs,
88
89
  nonInteractive: options.nonInteractive,
89
90
  isEmulator: false,
90
91
  });
92
+ functionsEnv.writeResolvedParams(resolvedEnvs, userEnvs, userEnvOpt);
91
93
  let hasEnvsFromParams = false;
92
94
  wantBackend.environmentVariables = envs;
93
95
  for (const envName of Object.keys(resolvedEnvs)) {
@@ -141,20 +143,21 @@ async function prepare(context, options, payload) {
141
143
  validate.endpointsAreUnique(wantBackends);
142
144
  context.sources = {};
143
145
  for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
144
- const config = (0, projectConfig_1.configForCodebase)(context.config, codebase);
145
- const sourceDirName = config.source;
146
+ const cfg = (0, projectConfig_1.configForCodebase)(context.config, codebase);
147
+ const localCfg = (0, projectConfig_1.requireLocal)(cfg, "Remote sources are not supported.");
148
+ const sourceDirName = localCfg.source;
146
149
  const sourceDir = options.config.path(sourceDirName);
147
150
  const source = {};
148
151
  if (backend.someEndpoint(wantBackend, () => true)) {
149
152
  (0, utils_1.logLabeledBullet)("functions", `preparing ${clc.bold(sourceDirName)} directory for uploading...`);
150
153
  }
151
154
  if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
152
- const packagedSource = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, config);
155
+ const packagedSource = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, localCfg);
153
156
  source.functionsSourceV2 = packagedSource === null || packagedSource === void 0 ? void 0 : packagedSource.pathToSource;
154
157
  source.functionsSourceV2Hash = packagedSource === null || packagedSource === void 0 ? void 0 : packagedSource.hash;
155
158
  }
156
159
  if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv1")) {
157
- const packagedSource = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, config, runtimeConfig);
160
+ const packagedSource = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, localCfg, runtimeConfig);
158
161
  source.functionsSourceV1 = packagedSource === null || packagedSource === void 0 ? void 0 : packagedSource.pathToSource;
159
162
  source.functionsSourceV1Hash = packagedSource === null || packagedSource === void 0 ? void 0 : packagedSource.hash;
160
163
  }
@@ -6,7 +6,7 @@ const fs = require("fs");
6
6
  const path = require("path");
7
7
  const yaml = require("yaml");
8
8
  const logger_1 = require("../../../../logger");
9
- const api = require("../../.../../../../api");
9
+ const api = require("../../../../api");
10
10
  const v1alpha1 = require("./v1alpha1");
11
11
  const error_1 = require("../../../../error");
12
12
  const TIMEOUT_OVERRIDE_ENV_VAR = "FUNCTIONS_DISCOVERY_TIMEOUT";
@@ -1512,7 +1512,16 @@ async function mfaSignInFinalize(state, reqBody) {
1512
1512
  (0, errors_1.assert)(sessionInfo, "MISSING_SESSION_INFO");
1513
1513
  const phoneNumber = verifyPhoneNumber(state, sessionInfo, code);
1514
1514
  let { user, signInProvider } = parsePendingCredential(state, reqBody.mfaPendingCredential);
1515
- const enrollment = (_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.find((enrollment) => enrollment.unobfuscatedPhoneInfo === phoneNumber);
1515
+ const enrollment = (_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.find((enrollment) => {
1516
+ if (enrollment.unobfuscatedPhoneInfo === phoneNumber) {
1517
+ return true;
1518
+ }
1519
+ if (!!enrollment.unobfuscatedPhoneInfo &&
1520
+ obfuscatePhoneNumber(enrollment.unobfuscatedPhoneInfo) === phoneNumber) {
1521
+ return true;
1522
+ }
1523
+ return false;
1524
+ });
1516
1525
  const { updates, extraClaims } = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, user, { signInMethod: signInProvider, signInSecondFactor: "phone" });
1517
1526
  user = state.updateUserByLocalId(user.localId, Object.assign(Object.assign({}, updates), { lastLoginAt: Date.now().toString() }));
1518
1527
  (0, errors_1.assert)(enrollment && enrollment.mfaEnrollmentId, "MFA_ENROLLMENT_NOT_FOUND");
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JAVA_DEPRECATION_WARNING = exports.MIN_SUPPORTED_JAVA_MAJOR_VERSION = exports.checkJavaMajorVersion = exports.emulatorExec = exports.getListenOverview = exports.shutdownWhenKilled = exports.setExportOnExitOptions = exports.parseInspectionPort = exports.beforeEmulatorCommand = exports.warnEmulatorNotSupported = exports.printNoticeIfEmulated = exports.DEFAULT_CONFIG = exports.DESC_TEST_PARAMS = exports.FLAG_TEST_PARAMS = exports.DESC_TEST_CONFIG = exports.FLAG_TEST_CONFIG = exports.DESC_UI = exports.FLAG_UI = exports.DESC_VERBOSITY = exports.FLAG_VERBOSITY = exports.FLAG_VERBOSITY_NAME = exports.EXPORT_ON_EXIT_CWD_DANGER = exports.EXPORT_ON_EXIT_USAGE_ERROR = exports.DESC_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT_NAME = exports.DESC_IMPORT = exports.FLAG_IMPORT = exports.DESC_INSPECT_FUNCTIONS = exports.FLAG_INSPECT_FUNCTIONS = exports.DESC_ONLY = exports.FLAG_ONLY = void 0;
3
+ exports.JAVA_DEPRECATION_WARNING = exports.MIN_SUPPORTED_JAVA_MAJOR_VERSION = exports.checkJavaMajorVersion = exports.emulatorExec = exports.getListenOverview = exports.shutdownWhenKilled = exports.setExportOnExitOptions = exports.parseInspectionPort = exports.beforeEmulatorCommand = exports.errorMissingProject = exports.warnEmulatorNotSupported = exports.printNoticeIfEmulated = exports.DEFAULT_CONFIG = exports.DESC_TEST_PARAMS = exports.FLAG_TEST_PARAMS = exports.DESC_TEST_CONFIG = exports.FLAG_TEST_CONFIG = exports.DESC_UI = exports.FLAG_UI = exports.DESC_VERBOSITY = exports.FLAG_VERBOSITY = exports.FLAG_VERBOSITY_NAME = exports.EXPORT_ON_EXIT_CWD_DANGER = exports.EXPORT_ON_EXIT_USAGE_ERROR = exports.DESC_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT_NAME = exports.DESC_IMPORT = exports.FLAG_IMPORT = exports.DESC_INSPECT_FUNCTIONS = exports.FLAG_INSPECT_FUNCTIONS = exports.DESC_ONLY = exports.FLAG_ONLY = void 0;
4
4
  const clc = require("colorette");
5
5
  const childProcess = require("child_process");
6
6
  const controller = require("../emulator/controller");
@@ -86,6 +86,12 @@ async function warnEmulatorNotSupported(options, emulator) {
86
86
  }
87
87
  }
88
88
  exports.warnEmulatorNotSupported = warnEmulatorNotSupported;
89
+ async function errorMissingProject(options) {
90
+ if (!options.project) {
91
+ throw new error_1.FirebaseError("Project is not defined. Either use `--project` or use `firebase use` to set your active project.");
92
+ }
93
+ }
94
+ exports.errorMissingProject = errorMissingProject;
89
95
  async function beforeEmulatorCommand(options) {
90
96
  const optionsWithDefaultConfig = Object.assign(Object.assign({}, options), { config: exports.DEFAULT_CONFIG });
91
97
  const optionsWithConfig = options.config ? options : optionsWithDefaultConfig;