firebase-tools 13.29.1 → 13.29.2

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.
@@ -51,7 +51,7 @@ exports.command = new command_1.Command("appdistribution:distribute <release-bin
51
51
  const testCases = (0, options_parser_util_1.parseIntoStringArray)(options.testCaseIds, options.testCaseIdsFile);
52
52
  const testDevices = (0, options_parser_util_1.parseTestDevices)(options.testDevices, options.testDevicesFile);
53
53
  if (testCases.length && (options.testUsernameResource || options.testPasswordResource)) {
54
- throw new error_1.FirebaseError("Password and username resource names are not supported for the AI testing agent.");
54
+ throw new error_1.FirebaseError("Password and username resource names are not supported for the testing agent.");
55
55
  }
56
56
  const loginCredential = (0, options_parser_util_1.getLoginCredential)({
57
57
  username: options.testUsername,
@@ -1,15 +1,74 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.build = void 0;
3
+ exports.handleBuildErrors = exports.build = void 0;
4
4
  const dataconnectEmulator_1 = require("../emulator/dataconnectEmulator");
5
5
  const error_1 = require("../error");
6
+ const experiments = require("../experiments");
7
+ const prompt_1 = require("../prompt");
8
+ const utils = require("../utils");
6
9
  const graphqlError_1 = require("./graphqlError");
7
- async function build(options, configDir) {
10
+ async function build(options, configDir, dryRun) {
8
11
  var _a, _b;
9
- const buildResult = await dataconnectEmulator_1.DataConnectEmulator.build({ configDir });
12
+ const args = { configDir };
13
+ if (experiments.isEnabled("fdcconnectorevolution") && options.projectId) {
14
+ const flags = process.env["DATA_CONNECT_PREVIEW"];
15
+ if (flags) {
16
+ process.env["DATA_CONNECT_PREVIEW"] = flags + ",conn_evolution";
17
+ }
18
+ else {
19
+ process.env["DATA_CONNECT_PREVIEW"] = "conn_evolution";
20
+ }
21
+ args.projectId = options.projectId;
22
+ }
23
+ const buildResult = await dataconnectEmulator_1.DataConnectEmulator.build(args);
10
24
  if ((_a = buildResult === null || buildResult === void 0 ? void 0 : buildResult.errors) === null || _a === void 0 ? void 0 : _a.length) {
11
- throw new error_1.FirebaseError(`There are errors in your schema and connector files:\n${buildResult.errors.map(graphqlError_1.prettify).join("\n")}`);
25
+ await handleBuildErrors(buildResult.errors, options.nonInteractive, options.force, dryRun);
12
26
  }
13
27
  return (_b = buildResult === null || buildResult === void 0 ? void 0 : buildResult.metadata) !== null && _b !== void 0 ? _b : {};
14
28
  }
15
29
  exports.build = build;
30
+ async function handleBuildErrors(errors, nonInteractive, force, dryRun) {
31
+ if (errors.filter((w) => { var _a; return !((_a = w.extensions) === null || _a === void 0 ? void 0 : _a.warningLevel); }).length) {
32
+ throw new error_1.FirebaseError(`There are errors in your schema and connector files:\n${errors.map(graphqlError_1.prettify).join("\n")}`);
33
+ }
34
+ const interactiveAcks = errors.filter((w) => { var _a; return ((_a = w.extensions) === null || _a === void 0 ? void 0 : _a.warningLevel) === "INTERACTIVE_ACK"; });
35
+ const requiredAcks = errors.filter((w) => { var _a; return ((_a = w.extensions) === null || _a === void 0 ? void 0 : _a.warningLevel) === "REQUIRE_ACK"; });
36
+ const choices = [
37
+ { name: "Acknowledge all changes and proceed", value: "proceed" },
38
+ { name: "Reject changes and abort", value: "abort" },
39
+ ];
40
+ if (requiredAcks.length) {
41
+ utils.logLabeledWarning("dataconnect", `There are changes in your schema or connectors that may break your existing applications. These changes require explicit acknowledgement to proceed. You may either reject the changes and update your sources with the suggested workaround(s), if any, or acknowledge these changes and proceed with the deployment:\n` +
42
+ (0, graphqlError_1.prettifyWithWorkaround)(requiredAcks));
43
+ if (nonInteractive && !force) {
44
+ throw new error_1.FirebaseError("Explicit acknowledgement required for breaking schema or connector changes. Rerun this command with --force to deploy these changes.");
45
+ }
46
+ else if (!nonInteractive && !force && !dryRun) {
47
+ const result = await (0, prompt_1.promptOnce)({
48
+ message: "Would you like to proceed with these breaking changes?",
49
+ type: "list",
50
+ choices,
51
+ default: "abort",
52
+ });
53
+ if (result === "abort") {
54
+ throw new error_1.FirebaseError(`Deployment aborted.`);
55
+ }
56
+ }
57
+ }
58
+ if (interactiveAcks.length) {
59
+ utils.logLabeledWarning("dataconnect", `There are changes in your schema or connectors that may cause unexpected behavior in your existing applications:\n` +
60
+ interactiveAcks.map(graphqlError_1.prettify).join("\n"));
61
+ if (!nonInteractive && !force && !dryRun) {
62
+ const result = await (0, prompt_1.promptOnce)({
63
+ message: "Would you like to proceed with these changes?",
64
+ type: "list",
65
+ choices,
66
+ default: "proceed",
67
+ });
68
+ if (result === "abort") {
69
+ throw new error_1.FirebaseError(`Deployment aborted.`);
70
+ }
71
+ }
72
+ }
73
+ }
74
+ exports.handleBuildErrors = handleBuildErrors;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.upgradeInstructions = exports.printFreeTrialUnavailable = exports.getFreeTrialInstanceId = exports.checkFreeTrialInstanceUsed = exports.freeTrialTermsLink = void 0;
3
+ exports.upgradeInstructions = exports.printFreeTrialUnavailable = exports.isFreeTrialError = exports.getFreeTrialInstanceId = exports.checkFreeTrialInstanceUsed = exports.freeTrialTermsLink = void 0;
4
4
  const cloudmonitoring_1 = require("../gcp/cloudmonitoring");
5
5
  const cloudsqladmin_1 = require("../gcp/cloudsql/cloudsqladmin");
6
6
  const utils = require("../utils");
@@ -36,17 +36,23 @@ async function getFreeTrialInstanceId(projectId) {
36
36
  return (_a = instances.find((i) => { var _a; return ((_a = i.settings.userLabels) === null || _a === void 0 ? void 0 : _a["firebase-data-connect"]) === "ft"; })) === null || _a === void 0 ? void 0 : _a.name;
37
37
  }
38
38
  exports.getFreeTrialInstanceId = getFreeTrialInstanceId;
39
+ async function isFreeTrialError(err, projectId) {
40
+ return err.message.includes("Quota Exhausted") && (await checkFreeTrialInstanceUsed(projectId))
41
+ ? true
42
+ : false;
43
+ }
44
+ exports.isFreeTrialError = isFreeTrialError;
39
45
  function printFreeTrialUnavailable(projectId, configYamlPath, instanceId) {
40
46
  if (!instanceId) {
41
- utils.logLabeledError("data connect", "The CloudSQL free trial has already been used on this project.");
42
- utils.logLabeledError("data connect", `You may create or use a paid CloudSQL instance by visiting https://console.cloud.google.com/sql/instances`);
47
+ utils.logLabeledError("dataconnect", "The CloudSQL free trial has already been used on this project.");
48
+ utils.logLabeledError("dataconnect", `You may create or use a paid CloudSQL instance by visiting https://console.cloud.google.com/sql/instances`);
43
49
  return;
44
50
  }
45
- utils.logLabeledError("data connect", `Project '${projectId} already has a CloudSQL instance '${instanceId}' on the Firebase Data Connect no-cost trial.`);
51
+ utils.logLabeledError("dataconnect", `Project '${projectId} already has a CloudSQL instance '${instanceId}' on the Firebase Data Connect no-cost trial.`);
46
52
  const reuseHint = `To use a different database in the same instance, ${clc.bold(`change the ${clc.blue("instanceId")} to "${instanceId}"`)} and update ${clc.blue("location")} in ` +
47
53
  `${clc.green(configYamlPath)}.`;
48
- utils.logLabeledError("data connect", reuseHint);
49
- utils.logLabeledError("data connect", `Alternatively, you may create a new (paid) CloudSQL instance at https://console.cloud.google.com/sql/instances`);
54
+ utils.logLabeledError("dataconnect", reuseHint);
55
+ utils.logLabeledError("dataconnect", `Alternatively, you may create a new (paid) CloudSQL instance at https://console.cloud.google.com/sql/instances`);
50
56
  }
51
57
  exports.printFreeTrialUnavailable = printFreeTrialUnavailable;
52
58
  function upgradeInstructions(projectId) {
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.prettify = void 0;
3
+ exports.prettifyWithWorkaround = exports.prettify = void 0;
4
+ const Table = require("cli-table");
4
5
  function prettify(err) {
5
6
  var _a, _b, _c, _d;
6
7
  const message = err.message;
@@ -14,3 +15,28 @@ function prettify(err) {
14
15
  return header.length ? `${header}: ${message}` : message;
15
16
  }
16
17
  exports.prettify = prettify;
18
+ function prettifyWithWorkaround(errs) {
19
+ var _a, _b;
20
+ const table = new Table({
21
+ head: ["Issue", "Workaround", "Reason"],
22
+ style: { head: ["yellow"] },
23
+ });
24
+ for (const e of errs) {
25
+ if (!((_b = (_a = e.extensions) === null || _a === void 0 ? void 0 : _a.workarounds) === null || _b === void 0 ? void 0 : _b.length)) {
26
+ table.push([prettify(e), "", ""]);
27
+ }
28
+ else {
29
+ const workarounds = e.extensions.workarounds;
30
+ for (let i = 0; i < workarounds.length; i++) {
31
+ if (i === 0) {
32
+ table.push([prettify(e), workarounds[i].Description, workarounds[i].Reason]);
33
+ }
34
+ else {
35
+ table.push(["", workarounds[i].Description, workarounds[i].Reason]);
36
+ }
37
+ }
38
+ }
39
+ }
40
+ return table.toString();
41
+ }
42
+ exports.prettifyWithWorkaround = prettifyWithWorkaround;
@@ -33,11 +33,6 @@ async function provisionCloudSql(args) {
33
33
  if (err.status !== 404) {
34
34
  throw err;
35
35
  }
36
- const freeTrialInstanceId = await (0, freeTrial_1.getFreeTrialInstanceId)(projectId);
37
- if (await (0, freeTrial_1.checkFreeTrialInstanceUsed)(projectId)) {
38
- (0, freeTrial_1.printFreeTrialUnavailable)(projectId, configYamlPath, freeTrialInstanceId);
39
- throw new error_1.FirebaseError("No-cost Cloud SQL trial has already been used on this project.");
40
- }
41
36
  const cta = dryRun ? "It will be created on your next deploy" : "Creating it now.";
42
37
  silent ||
43
38
  utils.logLabeledBullet("dataconnect", `CloudSQL instance '${instanceId}' not found.` +
@@ -45,15 +40,25 @@ async function provisionCloudSql(args) {
45
40
  `\nThis instance is provided under the terms of the Data Connect no-cost trial ${(0, freeTrial_1.freeTrialTermsLink)()}` +
46
41
  `\nMonitor the progress at ${cloudSqlAdminClient.instanceConsoleLink(projectId, instanceId)}`);
47
42
  if (!dryRun) {
48
- const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration, waitForCreation), "Creating your instance...");
49
- if (newInstance) {
50
- silent || utils.logLabeledBullet("dataconnect", "Instance created");
51
- connectionName = (newInstance === null || newInstance === void 0 ? void 0 : newInstance.connectionName) || "";
43
+ try {
44
+ const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration, waitForCreation), "Creating your instance...");
45
+ if (newInstance) {
46
+ silent || utils.logLabeledBullet("dataconnect", "Instance created");
47
+ connectionName = (newInstance === null || newInstance === void 0 ? void 0 : newInstance.connectionName) || "";
48
+ }
49
+ else {
50
+ silent ||
51
+ utils.logLabeledBullet("dataconnect", "Cloud SQL instance creation started - it should be ready shortly. Database and users will be created on your next deploy.");
52
+ return connectionName;
53
+ }
52
54
  }
53
- else {
54
- silent ||
55
- utils.logLabeledBullet("dataconnect", "Cloud SQL instance creation started - it should be ready shortly. Database and users will be created on your next deploy.");
56
- return connectionName;
55
+ catch (err) {
56
+ if (await (0, freeTrial_1.isFreeTrialError)(err, projectId)) {
57
+ const freeTrialInstanceId = await (0, freeTrial_1.getFreeTrialInstanceId)(projectId);
58
+ (0, freeTrial_1.printFreeTrialUnavailable)(projectId, configYamlPath, freeTrialInstanceId);
59
+ throw new error_1.FirebaseError("No-cost Cloud SQL trial has already been used on this project.");
60
+ }
61
+ throw err;
57
62
  }
58
63
  }
59
64
  }
@@ -32,7 +32,7 @@ async function default_1(context, options) {
32
32
  const filters = (0, filters_1.getResourceFilters)(options);
33
33
  const serviceInfos = await Promise.all(serviceCfgs.map((c) => (0, load_1.load)(projectId, options.config, c.source)));
34
34
  for (const si of serviceInfos) {
35
- si.deploymentMetadata = await (0, build_1.build)(options, si.sourceDirectory);
35
+ si.deploymentMetadata = await (0, build_1.build)(options, si.sourceDirectory, options.dryRun);
36
36
  }
37
37
  const unmatchedFilters = filters === null || filters === void 0 ? void 0 : filters.filter((f) => {
38
38
  const serviceMatched = serviceInfos.some((s) => s.dataConnectYaml.serviceId === f.serviceId);
@@ -10,6 +10,8 @@ const developmentServer_2 = require("./developmentServer");
10
10
  const types_1 = require("../types");
11
11
  const config_1 = require("./config");
12
12
  const projectPath_1 = require("../../projectPath");
13
+ const registry_1 = require("../registry");
14
+ const env_1 = require("../env");
13
15
  async function start(options) {
14
16
  var _a;
15
17
  const hostname = constants_1.DEFAULT_HOST;
@@ -29,7 +31,7 @@ async function serve(port, startCommand, backendRelativeDir) {
29
31
  for (const env of apphostingLocalConfig.environmentVariables) {
30
32
  environmentVariablesAsRecord[env.variable] = env.value;
31
33
  }
32
- const environmentVariablesToInject = Object.assign(Object.assign({}, environmentVariablesAsRecord), { PORT: port.toString() });
34
+ const environmentVariablesToInject = Object.assign(Object.assign(Object.assign({}, getEmulatorEnvs()), environmentVariablesAsRecord), { PORT: port.toString() });
33
35
  if (startCommand) {
34
36
  developmentServer_2.logger.logLabeled("BULLET", types_1.Emulators.APPHOSTING, `running custom start command: '${startCommand}'`);
35
37
  await (0, spawn_1.spawnWithCommandString)(startCommand, backendRoot, environmentVariablesToInject);
@@ -46,3 +48,9 @@ function availablePort(host, port) {
46
48
  family: (0, net_1.isIPv4)(host) ? "IPv4" : "IPv6",
47
49
  });
48
50
  }
51
+ function getEmulatorEnvs() {
52
+ const envs = {};
53
+ const emulatorInfos = registry_1.EmulatorRegistry.listRunningWithInfo();
54
+ (0, env_1.setEnvVarsForEmulators)(envs, emulatorInfos);
55
+ return envs;
56
+ }
@@ -589,7 +589,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
589
589
  default: false,
590
590
  }))) {
591
591
  await cleanShutdown();
592
- return { deprecationNotices: [] };
592
+ throw new error_1.FirebaseError("Command aborted");
593
593
  }
594
594
  }
595
595
  emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT).logLabeled("BULLET", "dataconnect", `Importing data from ${exportMetadataFilePath}`);
@@ -65,9 +65,12 @@ class DataConnectEmulator {
65
65
  this.logger.logLabeled("INFO", "dataconnect", `FIREBASE_DATACONNECT_POSTGRESQL_STRING is set to ${clc.bold(connStr)} - using that instead of starting a new database`);
66
66
  }
67
67
  else if (pgHost && pgPort) {
68
- const dataDirectory = this.args.config.get("emulators.dataconnect.dataDir");
68
+ let dataDirectory = this.args.config.get("emulators.dataconnect.dataDir");
69
+ if (dataDirectory) {
70
+ dataDirectory = this.args.config.path(dataDirectory);
71
+ }
69
72
  const postgresDumpPath = this.args.importPath
70
- ? path.join(this.args.importPath, "postgres.tar.gz")
73
+ ? path.join(this.args.config.path(this.args.importPath), "postgres.tar.gz")
71
74
  : undefined;
72
75
  this.postgresServer = new pgliteServer_1.PostgresServer({
73
76
  dataDirectory,
@@ -135,7 +138,7 @@ class DataConnectEmulator {
135
138
  }
136
139
  async exportData(exportPath) {
137
140
  if (this.postgresServer) {
138
- await this.postgresServer.exportData(path.join(exportPath, "postgres.tar.gz"));
141
+ await this.postgresServer.exportData(path.join(this.args.config.path(exportPath), "postgres.tar.gz"));
139
142
  }
140
143
  else {
141
144
  throw new error_1.FirebaseError("The Data Connect emulator is currently connected to a separate Postgres instance. Export is not supported.");
@@ -174,6 +177,9 @@ class DataConnectEmulator {
174
177
  var _a;
175
178
  const commandInfo = await (0, downloadableEmulators_1.downloadIfNecessary)(types_1.Emulators.DATACONNECT);
176
179
  const cmd = ["--logtostderr", "-v=2", "build", `--config_dir=${args.configDir}`];
180
+ if (args.projectId) {
181
+ cmd.push(`--project_id=${args.projectId}`);
182
+ }
177
183
  const res = childProcess.spawnSync(commandInfo.binary, cmd, { encoding: "utf-8" });
178
184
  if ((0, downloadableEmulators_1.isIncomaptibleArchError)(res.error)) {
179
185
  throw new error_1.FirebaseError(`Unkown system error when running the Data Connect toolkit. ` +
@@ -48,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
48
48
  },
49
49
  dataconnect: process.platform === "darwin"
50
50
  ? {
51
- version: "1.7.5",
52
- expectedSize: 25281280,
53
- expectedChecksum: "85d0de96b5c08b553fd8506a2bc381bb",
51
+ version: "1.7.6",
52
+ expectedSize: 25322240,
53
+ expectedChecksum: "2dda7394330fd1aba37605466941eef0",
54
54
  }
55
55
  : process.platform === "win32"
56
56
  ? {
57
- version: "1.7.5",
58
- expectedSize: 25711616,
59
- expectedChecksum: "c99d67fa8e74d41760b96122b055b8e2",
57
+ version: "1.7.6",
58
+ expectedSize: 25752064,
59
+ expectedChecksum: "283c11e28a0072b596531b79462a8e94",
60
60
  }
61
61
  : {
62
- version: "1.7.5",
63
- expectedSize: 25190552,
64
- expectedChecksum: "61d966b781e6f2887f8b38ec271b54e2",
62
+ version: "1.7.6",
63
+ expectedSize: 25235608,
64
+ expectedChecksum: "f66e24b3726df57cd1f1685a64a87904",
65
65
  },
66
66
  };
67
67
  exports.DownloadDetails = {
@@ -118,7 +118,7 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
118
118
  return;
119
119
  }
120
120
  await instance.clearData();
121
- res.status(200).send("Data cleared");
121
+ res.status(200).json({ success: true });
122
122
  });
123
123
  return app;
124
124
  }
@@ -38,6 +38,11 @@ class EmulatorHubClient {
38
38
  const res = await this.tryOrigins((client) => client.get(hub_1.EmulatorHub.PATH_EMULATORS));
39
39
  return res.body;
40
40
  }
41
+ async clearDataConnectData() {
42
+ const origin = await this.getStatus();
43
+ const apiClient = new apiv2_1.Client({ urlPrefix: origin, auth: false });
44
+ await apiClient.post(hub_1.EmulatorHub.PATH_CLEAR_DATA_CONNECT);
45
+ }
41
46
  async postExport(options) {
42
47
  const origin = await this.getStatus();
43
48
  const apiClient = new apiv2_1.Client({ urlPrefix: origin, auth: false });
@@ -106,6 +106,12 @@ exports.ALL_EXPERIMENTS = experiments({
106
106
  default: true,
107
107
  public: false,
108
108
  },
109
+ fdcconnectorevolution: {
110
+ shortDescription: "Enable Data Connect connector evolution warnings.",
111
+ fullDescription: "Enable Data Connect connector evolution warnings.",
112
+ default: false,
113
+ public: false,
114
+ },
109
115
  });
110
116
  function isValidExperiment(name) {
111
117
  return Object.keys(exports.ALL_EXPERIMENTS).includes(name);
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getErrorMessage = exports.getValidator = void 0;
4
4
  const fs = require("fs");
5
5
  const path = require("path");
6
- const Ajv = require("ajv");
7
- const ajv = new Ajv();
6
+ const ajv_1 = require("ajv");
7
+ const ajv_formats_1 = require("ajv-formats");
8
+ const ajv = new ajv_1.Ajv({ allowUnionTypes: true });
9
+ (0, ajv_formats_1.default)(ajv);
8
10
  let _VALIDATOR = undefined;
9
11
  function getValidator() {
10
12
  if (!_VALIDATOR) {
@@ -17,13 +19,13 @@ function getValidator() {
17
19
  exports.getValidator = getValidator;
18
20
  function getErrorMessage(e) {
19
21
  if (e.keyword === "additionalProperties") {
20
- return `Object "${e.dataPath}" in "firebase.json" has unknown property: ${JSON.stringify(e.params)}`;
22
+ return `Object "${e.instancePath}" in "firebase.json" has unknown property: ${JSON.stringify(e.params)}`;
21
23
  }
22
24
  else if (e.keyword === "required") {
23
- return `Object "${e.dataPath}" in "firebase.json" is missing required property: ${JSON.stringify(e.params)}`;
25
+ return `Object "${e.instancePath}" in "firebase.json" is missing required property: ${JSON.stringify(e.params)}`;
24
26
  }
25
27
  else {
26
- return `Field "${e.dataPath}" in "firebase.json" is possibly invalid: ${e.message}`;
28
+ return `Field "${e.instancePath}" in "firebase.json" is possibly invalid: ${e.message}`;
27
29
  }
28
30
  }
29
31
  exports.getErrorMessage = getErrorMessage;
@@ -259,9 +259,6 @@ function functionFromEndpoint(endpoint) {
259
259
  }
260
260
  else if (backend.isCallableTriggered(endpoint)) {
261
261
  gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-callable": "true" });
262
- if (endpoint.callableTrigger.genkitAction) {
263
- gcfFunction.labels["genkit-action"] = endpoint.callableTrigger.genkitAction;
264
- }
265
262
  }
266
263
  else if (backend.isBlockingTriggered(endpoint)) {
267
264
  gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { [constants_1.BLOCKING_LABEL]: constants_1.BLOCKING_EVENT_TO_LABEL_KEY[endpoint.blockingTrigger.eventType] });
@@ -297,9 +294,6 @@ function endpointFromFunction(gcfFunction) {
297
294
  trigger = {
298
295
  callableTrigger: {},
299
296
  };
300
- if (gcfFunction.labels["genkit-action"]) {
301
- trigger.callableTrigger.genkitAction = gcfFunction.labels["genkit-action"];
302
- }
303
297
  }
304
298
  else if ((_d = gcfFunction.labels) === null || _d === void 0 ? void 0 : _d[constants_1.BLOCKING_LABEL]) {
305
299
  trigger = {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.actuate = exports.doSetup = void 0;
3
+ exports.toDNSCompatibleId = exports.actuate = exports.doSetup = void 0;
4
4
  const path_1 = require("path");
5
5
  const clc = require("colorette");
6
6
  const fs = require("fs-extra");
@@ -100,7 +100,8 @@ async function askQuestions(setup, isBillingEnabled) {
100
100
  })));
101
101
  }
102
102
  else {
103
- info.serviceId = info.serviceId || (0, path_1.basename)(process.cwd());
103
+ const defaultServiceId = toDNSCompatibleId((0, path_1.basename)(process.cwd()));
104
+ info.serviceId = info.serviceId || defaultServiceId;
104
105
  info.cloudSqlInstanceId = info.cloudSqlInstanceId || `${info.serviceId || "app"}-fdc`;
105
106
  info.locationId = info.locationId || `us-central1`;
106
107
  info.cloudSqlDatabase = info.cloudSqlDatabase || `fdcdb`;
@@ -339,3 +340,17 @@ async function locationChoices(setup) {
339
340
  ];
340
341
  }
341
342
  }
343
+ function toDNSCompatibleId(id) {
344
+ let defaultServiceId = (0, path_1.basename)(id)
345
+ .toLowerCase()
346
+ .replaceAll(/[^a-z0-9-]/g, "")
347
+ .slice(0, 63);
348
+ while (defaultServiceId.endsWith("-") && defaultServiceId.length) {
349
+ defaultServiceId = defaultServiceId.slice(0, defaultServiceId.length - 1);
350
+ }
351
+ while (defaultServiceId.startsWith("-") && defaultServiceId.length) {
352
+ defaultServiceId = defaultServiceId.slice(1, defaultServiceId.length);
353
+ }
354
+ return defaultServiceId || "app";
355
+ }
356
+ exports.toDNSCompatibleId = toDNSCompatibleId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.29.1",
3
+ "version": "13.29.2",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -64,7 +64,8 @@
64
64
  "@google-cloud/cloud-sql-connector": "^1.3.3",
65
65
  "@google-cloud/pubsub": "^4.5.0",
66
66
  "abort-controller": "^3.0.0",
67
- "ajv": "^6.12.6",
67
+ "ajv": "^8.17.1",
68
+ "ajv-formats": "3.0.1",
68
69
  "archiver": "^7.0.0",
69
70
  "async-lock": "1.4.1",
70
71
  "body-parser": "^1.19.0",
@@ -75,8 +76,8 @@
75
76
  "commander": "^5.1.0",
76
77
  "configstore": "^5.0.1",
77
78
  "cors": "^2.8.5",
78
- "cross-env": "^5.1.3",
79
- "cross-spawn": "^7.0.3",
79
+ "cross-env": "^7.0.3",
80
+ "cross-spawn": "^7.0.5",
80
81
  "csv-parse": "^5.0.4",
81
82
  "deep-equal-in-any-order": "^2.0.6",
82
83
  "exegesis": "^4.2.0",