firebase-tools 13.35.1 → 14.0.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 (107) hide show
  1. package/lib/appdistribution/client.js +4 -2
  2. package/lib/apphosting/backend.js +65 -11
  3. package/lib/apphosting/config.js +130 -101
  4. package/lib/apphosting/githubConnections.js +0 -2
  5. package/lib/apphosting/rollout.js +3 -9
  6. package/lib/apphosting/secrets/dialogs.js +5 -2
  7. package/lib/apphosting/secrets/index.js +45 -3
  8. package/lib/apphosting/yaml.js +19 -8
  9. package/lib/commands/appdistribution-groups-create.js +1 -1
  10. package/lib/commands/appdistribution-groups-delete.js +1 -1
  11. package/lib/commands/appdistribution-groups-list.js +1 -1
  12. package/lib/commands/appdistribution-testers-add.js +1 -1
  13. package/lib/commands/appdistribution-testers-remove.js +1 -1
  14. package/lib/commands/apphosting-backends-create.js +1 -8
  15. package/lib/commands/apphosting-backends-delete.js +16 -26
  16. package/lib/commands/apphosting-backends-get.js +10 -16
  17. package/lib/commands/apphosting-backends-list.js +4 -10
  18. package/lib/commands/apphosting-rollouts-create.js +1 -8
  19. package/lib/commands/apphosting-secrets-access.js +1 -1
  20. package/lib/commands/apphosting-secrets-describe.js +1 -1
  21. package/lib/commands/apphosting-secrets-grantaccess.js +19 -9
  22. package/lib/commands/apphosting-secrets-set.js +31 -1
  23. package/lib/commands/apps-android-sha-create.js +1 -1
  24. package/lib/commands/apps-android-sha-delete.js +1 -1
  25. package/lib/commands/apps-android-sha-list.js +1 -1
  26. package/lib/commands/apps-create.js +1 -1
  27. package/lib/commands/apps-init.js +1 -1
  28. package/lib/commands/auth-export.js +1 -1
  29. package/lib/commands/auth-import.js +1 -1
  30. package/lib/commands/database-instances-create.js +1 -1
  31. package/lib/commands/database-profile.js +1 -2
  32. package/lib/commands/database-settings-set.js +1 -1
  33. package/lib/commands/database-update.js +1 -1
  34. package/lib/commands/dataconnect-sdk-generate.js +1 -1
  35. package/lib/commands/dataconnect-services-list.js +1 -1
  36. package/lib/commands/dataconnect-sql-diff.js +1 -1
  37. package/lib/commands/dataconnect-sql-grant.js +1 -1
  38. package/lib/commands/dataconnect-sql-migrate.js +2 -2
  39. package/lib/commands/dataconnect-sql-setup.js +1 -1
  40. package/lib/commands/dataconnect-sql-shell.js +1 -1
  41. package/lib/commands/deploy.js +3 -3
  42. package/lib/commands/emulators-exec.js +1 -1
  43. package/lib/commands/ext-dev-register.js +1 -1
  44. package/lib/commands/ext-dev-usage.js +2 -2
  45. package/lib/commands/ext-install.js +2 -3
  46. package/lib/commands/firestore-backups-delete.js +2 -2
  47. package/lib/commands/firestore-backups-get.js +1 -1
  48. package/lib/commands/firestore-backups-list.js +2 -2
  49. package/lib/commands/firestore-backups-schedules-create.js +4 -4
  50. package/lib/commands/firestore-backups-schedules-delete.js +2 -2
  51. package/lib/commands/firestore-backups-schedules-list.js +2 -2
  52. package/lib/commands/firestore-backups-schedules-update.js +1 -1
  53. package/lib/commands/firestore-databases-create.js +6 -6
  54. package/lib/commands/firestore-databases-delete.js +2 -2
  55. package/lib/commands/firestore-databases-get.js +1 -1
  56. package/lib/commands/firestore-databases-list.js +1 -1
  57. package/lib/commands/firestore-databases-restore.js +5 -5
  58. package/lib/commands/firestore-databases-update.js +4 -4
  59. package/lib/commands/firestore-delete.js +7 -8
  60. package/lib/commands/firestore-indexes-list.js +4 -4
  61. package/lib/commands/firestore-locations.js +1 -1
  62. package/lib/commands/functions-artifacts-setpolicy.js +7 -7
  63. package/lib/commands/functions-config-export.js +1 -1
  64. package/lib/commands/functions-deletegcfartifacts.js +1 -1
  65. package/lib/commands/functions-secrets-access.js +1 -1
  66. package/lib/commands/functions-secrets-describe.js +1 -1
  67. package/lib/commands/functions-secrets-destroy.js +2 -2
  68. package/lib/commands/functions-secrets-get.js +1 -1
  69. package/lib/commands/functions-secrets-prune.js +2 -2
  70. package/lib/commands/functions-secrets-set.js +3 -3
  71. package/lib/commands/index.js +0 -4
  72. package/lib/commands/init.js +3 -2
  73. package/lib/commands/internaltesting-frameworks-compose.js +1 -1
  74. package/lib/commands/remoteconfig-versions-list.js +1 -1
  75. package/lib/commands/setup-emulators-database.js +1 -1
  76. package/lib/commands/setup-emulators-dataconnect.js +1 -1
  77. package/lib/commands/setup-emulators-firestore.js +1 -1
  78. package/lib/commands/setup-emulators-pubsub.js +1 -1
  79. package/lib/commands/setup-emulators-storage.js +1 -1
  80. package/lib/commands/setup-emulators-ui.js +1 -1
  81. package/lib/config.js +16 -18
  82. package/lib/dataconnect/dataplaneClient.js +3 -1
  83. package/lib/deploy/functions/build.js +1 -0
  84. package/lib/deploy/functions/prompts.js +30 -1
  85. package/lib/deploy/functions/release/index.js +27 -9
  86. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +4 -4
  87. package/lib/emulator/apphosting/config.js +15 -14
  88. package/lib/emulator/auth/operations.js +2 -1
  89. package/lib/emulator/constants.js +2 -1
  90. package/lib/emulator/dataconnect/pgliteServer.js +2 -1
  91. package/lib/emulator/dataconnectEmulator.js +2 -0
  92. package/lib/emulator/downloadableEmulators.js +9 -9
  93. package/lib/emulator/env.js +3 -1
  94. package/lib/emulator/initEmulators.js +29 -4
  95. package/lib/experiments.js +1 -13
  96. package/lib/functions/artifacts.js +88 -1
  97. package/lib/gcp/cloudfunctions.js +1 -1
  98. package/lib/gcp/cloudfunctionsv2.js +5 -3
  99. package/lib/gcp/cloudsql/permissions.js +2 -1
  100. package/lib/gcp/cloudsql/permissions_setup.js +8 -5
  101. package/lib/gcp/proto.js +4 -3
  102. package/lib/init/features/dataconnect/sdk.js +4 -5
  103. package/package.json +2 -2
  104. package/standalone/package.json +1 -1
  105. package/templates/init/dataconnect/dataconnect.yaml +1 -1
  106. package/lib/commands/apphosting-config-export.js +0 -29
  107. package/lib/commands/experimental-functions-shell.js +0 -13
@@ -11,7 +11,7 @@ const requireAuth_1 = require("../requireAuth");
11
11
  const utils = require("../utils");
12
12
  const Table = require("cli-table3");
13
13
  exports.command = new command_1.Command("appdistribution:groups:list")
14
- .description("list groups in project")
14
+ .description("list App Distribution groups")
15
15
  .alias("appdistribution:group:list")
16
16
  .before(requireAuth_1.requireAuth)
17
17
  .action(async (options) => {
@@ -7,7 +7,7 @@ const requireAuth_1 = require("../requireAuth");
7
7
  const client_1 = require("../appdistribution/client");
8
8
  const options_parser_util_1 = require("../appdistribution/options-parser-util");
9
9
  exports.command = new command_1.Command("appdistribution:testers:add [emails...]")
10
- .description("add testers to project (and possibly group)")
10
+ .description("add testers to project (and App Distribution group, if specified via flag)")
11
11
  .option("--file <file>", "a path to a file containing a list of tester emails to be added")
12
12
  .option("--group-alias <group-alias>", "if specified, the testers are also added to the group identified by this alias")
13
13
  .before(requireAuth_1.requireAuth)
@@ -9,7 +9,7 @@ const client_1 = require("../appdistribution/client");
9
9
  const options_parser_util_1 = require("../appdistribution/options-parser-util");
10
10
  const logger_1 = require("../logger");
11
11
  exports.command = new command_1.Command("appdistribution:testers:remove [emails...]")
12
- .description("remove testers from a project (or group)")
12
+ .description("remove testers from a project (or App Distribution group, if specified via flag)")
13
13
  .option("--file <file>", "a path to a file containing a list of tester emails to be removed")
14
14
  .option("--group-alias <group-alias>", "if specified, the testers are only removed from the group identified by this alias, but not the project")
15
15
  .before(requireAuth_1.requireAuth)
@@ -8,23 +8,16 @@ const backend_1 = require("../apphosting/backend");
8
8
  const apphosting_1 = require("../gcp/apphosting");
9
9
  const firedata_1 = require("../gcp/firedata");
10
10
  const requireTosAcceptance_1 = require("../requireTosAcceptance");
11
- const utils_1 = require("../utils");
12
11
  exports.command = new command_1.Command("apphosting:backends:create")
13
12
  .description("create a Firebase App Hosting backend")
14
13
  .option("-a, --app <webAppId>", "specify an existing Firebase web app's ID to associate your App Hosting backend with")
15
- .option("-l, --location <location>", "specify the location of the backend")
16
14
  .option("-s, --service-account <serviceAccount>", "specify the service account used to run the server", "")
17
15
  .before(apphosting_1.ensureApiEnabled)
18
16
  .before(requireInteractive_1.default)
19
17
  .before((0, requireTosAcceptance_1.requireTosAcceptance)(firedata_1.APPHOSTING_TOS_ID))
20
18
  .action(async (options) => {
21
- if (options.location !== undefined) {
22
- (0, utils_1.logWarning)("--location is being removed in the next major release. " +
23
- "The CLI will prompt for a Primary Region where appropriate.");
24
- }
25
19
  const projectId = (0, projectUtils_1.needProjectId)(options);
26
20
  const webAppId = options.app;
27
- const location = options.location;
28
21
  const serviceAccount = options.serviceAccount;
29
- await (0, backend_1.doSetup)(projectId, webAppId, location, serviceAccount);
22
+ await (0, backend_1.doSetup)(projectId, webAppId, serviceAccount);
30
23
  });
@@ -12,26 +12,13 @@ const backend_1 = require("../apphosting/backend");
12
12
  const ora = require("ora");
13
13
  exports.command = new command_1.Command("apphosting:backends:delete <backend>")
14
14
  .description("delete a Firebase App Hosting backend")
15
- .option("-l, --location <location>", "specify the location of the backend")
16
15
  .withForce()
17
16
  .before(apphosting.ensureApiEnabled)
18
17
  .action(async (backendId, options) => {
19
- var _a;
20
18
  const projectId = (0, projectUtils_1.needProjectId)(options);
21
- if (options.location !== undefined) {
22
- utils.logWarning("--location is being removed in the next major release.");
23
- }
24
- let location = (_a = options.location) !== null && _a !== void 0 ? _a : "-";
25
- let backend;
26
- if (location === "-" || location === "") {
27
- backend = await (0, backend_1.getBackendForAmbiguousLocation)(projectId, backendId, "Please select the location of the backend you'd like to delete:");
28
- location = apphosting.parseBackendName(backend.name).location;
29
- }
30
- else {
31
- backend = await (0, backend_1.getBackendForLocation)(projectId, location, backendId);
32
- }
33
- utils.logWarning("You are about to permanently delete this backend:");
34
- (0, apphosting_backends_list_1.printBackendsTable)([backend]);
19
+ const backends = await (0, backend_1.chooseBackends)(projectId, backendId, "Please select the backends you'd like to delete:", options.force);
20
+ utils.logWarning("You are about to permanently delete these backend(s):");
21
+ (0, apphosting_backends_list_1.printBackendsTable)(backends);
35
22
  const confirmDeletion = await (0, prompt_1.promptOnce)({
36
23
  type: "confirm",
37
24
  name: "force",
@@ -41,15 +28,18 @@ exports.command = new command_1.Command("apphosting:backends:delete <backend>")
41
28
  if (!confirmDeletion) {
42
29
  return;
43
30
  }
44
- const spinner = ora("Deleting backend...").start();
45
- try {
46
- await (0, backend_1.deleteBackendAndPoll)(projectId, location, backendId);
47
- spinner.succeed(`Successfully deleted the backend: ${backendId}`);
48
- }
49
- catch (err) {
50
- spinner.stop();
51
- throw new error_1.FirebaseError(`Failed to delete backend: ${backendId}.`, {
52
- original: (0, error_1.getError)(err),
53
- });
31
+ for (const b of backends) {
32
+ const { location, id } = apphosting.parseBackendName(b.name);
33
+ const spinner = ora(`Deleting backend ${id}(${location})...`).start();
34
+ try {
35
+ await (0, backend_1.deleteBackendAndPoll)(projectId, location, id);
36
+ spinner.succeed(`Successfully deleted the backend: ${id}(${location})`);
37
+ }
38
+ catch (err) {
39
+ spinner.stop();
40
+ throw new error_1.FirebaseError(`Failed to delete backend: ${id}(${location}). Please retry.`, {
41
+ original: (0, error_1.getError)(err),
42
+ });
43
+ }
54
44
  }
55
45
  });
@@ -9,26 +9,14 @@ const apphosting = require("../gcp/apphosting");
9
9
  const apphosting_backends_list_1 = require("./apphosting-backends-list");
10
10
  exports.command = new command_1.Command("apphosting:backends:get <backend>")
11
11
  .description("print info about a Firebase App Hosting backend")
12
- .option("-l, --location <location>", "backend location")
13
12
  .before(apphosting.ensureApiEnabled)
14
13
  .action(async (backend, options) => {
15
- var _a;
16
14
  const projectId = (0, projectUtils_1.needProjectId)(options);
17
- if (options.location !== undefined) {
18
- (0, utils_1.logWarning)("--location is being removed in the next major release.");
19
- }
20
- const location = (_a = options.location) !== null && _a !== void 0 ? _a : "-";
21
15
  let backendsList = [];
22
16
  try {
23
- if (location !== "-") {
24
- const backendInRegion = await apphosting.getBackend(projectId, location, backend);
25
- backendsList.push(backendInRegion);
26
- }
27
- else {
28
- const resp = await apphosting.listBackends(projectId, "-");
29
- const allBackends = resp.backends || [];
30
- backendsList = allBackends.filter((bkd) => bkd.name.split("/").pop() === backend);
31
- }
17
+ const resp = await apphosting.listBackends(projectId, "-");
18
+ const allBackends = resp.backends || [];
19
+ backendsList = allBackends.filter((bkd) => bkd.name.split("/").pop() === backend);
32
20
  }
33
21
  catch (err) {
34
22
  throw new error_1.FirebaseError(`Failed to get backend: ${backend}. Please check the parameters you have provided.`, { original: (0, error_1.getError)(err) });
@@ -37,6 +25,12 @@ exports.command = new command_1.Command("apphosting:backends:get <backend>")
37
25
  (0, utils_1.logWarning)(`Backend "${backend}" not found`);
38
26
  return;
39
27
  }
40
- (0, apphosting_backends_list_1.printBackendsTable)(backendsList);
28
+ if (backendsList.length > 1) {
29
+ const regions = backendsList.map((b) => apphosting.parseBackendName(b.name).location);
30
+ (0, utils_1.logWarning)(`Detected multiple backends with the same ${backend} ID in regions: ${regions.join(", ")}}. This is not allowed until we can support more locations.\n` +
31
+ `Please delete and recreate any backends that share an ID with another backend. ` +
32
+ `Use apphosting:backends:list to see all backends.\n Returning the following backend:`);
33
+ }
34
+ (0, apphosting_backends_list_1.printBackendsTable)(backendsList.slice(0, 1));
41
35
  return backendsList[0];
42
36
  });
@@ -8,27 +8,21 @@ const logger_1 = require("../logger");
8
8
  const projectUtils_1 = require("../projectUtils");
9
9
  const apphosting = require("../gcp/apphosting");
10
10
  const Table = require("cli-table3");
11
- const utils_2 = require("../utils");
12
- const TABLE_HEAD = ["Backend", "Repository", "URL", "Location", "Updated Date"];
11
+ const TABLE_HEAD = ["Backend", "Repository", "URL", "Primary Region", "Updated Date"];
13
12
  exports.command = new command_1.Command("apphosting:backends:list")
14
13
  .description("list Firebase App Hosting backends")
15
- .option("-l, --location <location>", "list backends in the specified location")
16
14
  .before(apphosting.ensureApiEnabled)
17
15
  .action(async (options) => {
18
- var _a, _b;
19
- if (options.location !== undefined) {
20
- (0, utils_2.logWarning)("--location is being removed in the next major release.");
21
- }
16
+ var _a;
22
17
  const projectId = (0, projectUtils_1.needProjectId)(options);
23
- const location = (_a = options.location) !== null && _a !== void 0 ? _a : "-";
24
18
  let backendRes;
25
19
  try {
26
- backendRes = await apphosting.listBackends(projectId, location);
20
+ backendRes = await apphosting.listBackends(projectId, "-");
27
21
  }
28
22
  catch (err) {
29
23
  throw new error_1.FirebaseError(`Unable to list backends present for project: ${projectId}. Please check the parameters you have provided.`, { original: err });
30
24
  }
31
- const backends = (_b = backendRes.backends) !== null && _b !== void 0 ? _b : [];
25
+ const backends = (_a = backendRes.backends) !== null && _a !== void 0 ? _a : [];
32
26
  printBackendsTable(backends);
33
27
  return backends;
34
28
  });
@@ -6,25 +6,18 @@ const command_1 = require("../command");
6
6
  const projectUtils_1 = require("../projectUtils");
7
7
  const error_1 = require("../error");
8
8
  const rollout_1 = require("../apphosting/rollout");
9
- const utils_1 = require("../utils");
10
9
  exports.command = new command_1.Command("apphosting:rollouts:create <backendId>")
11
10
  .description("create a rollout using a build for an App Hosting backend")
12
- .option("-l, --location <location>", "specify the region of the backend")
13
11
  .option("-b, --git-branch <gitBranch>", "repository branch to deploy (mutually exclusive with -g)")
14
12
  .option("-g, --git-commit <gitCommit>", "git commit to deploy (mutually exclusive with -b)")
15
13
  .withForce("Skip confirmation before creating rollout")
16
14
  .before(apphosting.ensureApiEnabled)
17
15
  .action(async (backendId, options) => {
18
- var _a;
19
16
  const projectId = (0, projectUtils_1.needProjectId)(options);
20
- if (options.location !== undefined) {
21
- (0, utils_1.logWarning)("--location is being removed in the next major release.");
22
- }
23
- const location = (_a = options.location) !== null && _a !== void 0 ? _a : "-";
24
17
  const branch = options.gitBranch;
25
18
  const commit = options.gitCommit;
26
19
  if (branch && commit) {
27
20
  throw new error_1.FirebaseError("Cannot specify both a branch and commit to deploy. Please specify either --git-branch or --git-commit.");
28
21
  }
29
- await (0, rollout_1.createRollout)(backendId, projectId, location, branch, commit, options.force);
22
+ await (0, rollout_1.createRollout)(backendId, projectId, branch, commit, options.force);
30
23
  });
@@ -9,7 +9,7 @@ const requireAuth_1 = require("../requireAuth");
9
9
  const secretManager = require("../gcp/secretManager");
10
10
  const requirePermissions_1 = require("../requirePermissions");
11
11
  exports.command = new command_1.Command("apphosting:secrets:access <secretName[@version]>")
12
- .description("Access secret value given secret and its version. Defaults to accessing the latest version.")
12
+ .description("access secret value given secret and its version. Defaults to accessing the latest version")
13
13
  .before(requireAuth_1.requireAuth)
14
14
  .before(secretManager.ensureApi)
15
15
  .before(requirePermissions_1.requirePermissions, ["secretmanager.versions.access"])
@@ -10,7 +10,7 @@ const secretManager = require("../gcp/secretManager");
10
10
  const requirePermissions_1 = require("../requirePermissions");
11
11
  const Table = require("cli-table3");
12
12
  exports.command = new command_1.Command("apphosting:secrets:describe <secretName>")
13
- .description("Get metadata for secret and its versions.")
13
+ .description("get metadata for secret and its versions")
14
14
  .before(requireAuth_1.requireAuth)
15
15
  .before(secretManager.ensureApi)
16
16
  .before(requirePermissions_1.requirePermissions, ["secretmanager.secrets.get"])
@@ -10,10 +10,11 @@ const requirePermissions_1 = require("../requirePermissions");
10
10
  const apphosting = require("../gcp/apphosting");
11
11
  const secrets = require("../apphosting/secrets");
12
12
  const backend_1 = require("../apphosting/backend");
13
- exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretName>")
14
- .description("grant service accounts permissions to the provided secret")
13
+ exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretNames>")
14
+ .description("Grant service accounts, users, or groups permissions to the provided secret(s). Can pass one or more secrets, separated by a comma")
15
15
  .option("-l, --location <location>", "backend location", "-")
16
16
  .option("-b, --backend <backend>", "backend name")
17
+ .option("-e, --emails <emails>", "comma delimited list of user or group emails")
17
18
  .before(requireAuth_1.requireAuth)
18
19
  .before(secretManager.ensureApi)
19
20
  .before(apphosting.ensureApiEnabled)
@@ -25,15 +26,24 @@ exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretN
25
26
  "secretmanager.secrets.getIamPolicy",
26
27
  "secretmanager.secrets.setIamPolicy",
27
28
  ])
28
- .action(async (secretName, options) => {
29
+ .action(async (secretNames, options) => {
29
30
  const projectId = (0, projectUtils_1.needProjectId)(options);
30
31
  const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
31
- if (!options.backend) {
32
- throw new error_1.FirebaseError("Missing required flag --backend. See firebase apphosting:secrets:grantaccess --help for more info");
32
+ if (!options.backend && !options.emails) {
33
+ throw new error_1.FirebaseError("Missing required flag --backend or --emails. See firebase apphosting:secrets:grantaccess --help for more info");
33
34
  }
34
- const exists = await secretManager.secretExists(projectId, secretName);
35
- if (!exists) {
36
- throw new error_1.FirebaseError(`Cannot find secret ${secretName}`);
35
+ if (options.backend && options.emails) {
36
+ throw new error_1.FirebaseError("Cannot specify both --backend and --emails. See firebase apphosting:secrets:grantaccess --help for more info");
37
+ }
38
+ const secretList = secretNames.split(",");
39
+ for (const secretName of secretList) {
40
+ const exists = await secretManager.secretExists(projectId, secretName);
41
+ if (!exists) {
42
+ throw new error_1.FirebaseError(`Cannot find secret ${secretName}`);
43
+ }
44
+ }
45
+ if (options.emails) {
46
+ return await secrets.grantEmailsSecretAccess(projectId, secretList, String(options.emails).split(","));
37
47
  }
38
48
  const backendId = options.backend;
39
49
  const location = options.location;
@@ -45,5 +55,5 @@ exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretN
45
55
  backend = await apphosting.getBackend(projectId, location, backendId);
46
56
  }
47
57
  const accounts = secrets.toMulti(secrets.serviceAccountsForBackend(projectNumber, backend));
48
- await secrets.grantSecretAccess(projectId, projectNumber, secretName, accounts);
58
+ await Promise.allSettled(secretList.map((secretName) => secrets.grantSecretAccess(projectId, projectNumber, secretName, accounts)));
49
59
  });
@@ -12,6 +12,7 @@ const secrets = require("../apphosting/secrets");
12
12
  const dialogs = require("../apphosting/secrets/dialogs");
13
13
  const config = require("../apphosting/config");
14
14
  const utils = require("../utils");
15
+ const prompt = require("../prompt");
15
16
  exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
16
17
  .description("create or update a secret for use in Firebase App Hosting")
17
18
  .option("-l, --location <location>", "optional location to retrict secret replication")
@@ -45,6 +46,31 @@ exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
45
46
  if (!created) {
46
47
  return;
47
48
  }
49
+ const type = await prompt.promptOnce({
50
+ type: "list",
51
+ name: "type",
52
+ message: "Is this secret for production or only local testing?",
53
+ choices: [
54
+ { name: "Production", value: "production" },
55
+ { name: "Local testing only", value: "local" },
56
+ ],
57
+ });
58
+ if (type === "local") {
59
+ const emailList = await prompt.promptOnce({
60
+ type: "input",
61
+ name: "emails",
62
+ message: "Please enter a comma separated list of user or groups who should have access to this secret:",
63
+ });
64
+ if (emailList.length) {
65
+ await secrets.grantEmailsSecretAccess(projectId, [secretName], emailList.split(","));
66
+ }
67
+ else {
68
+ utils.logBullet("To grant access in the future run " +
69
+ clc.bold(`firebase apphosting:secrets:grantaccess ${secretName} --emails [email list]`));
70
+ }
71
+ await config.maybeAddSecretToYaml(secretName, config.APPHOSTING_EMULATORS_YAML_FILE);
72
+ return;
73
+ }
48
74
  const accounts = await dialogs.selectBackendServiceAccounts(projectNumber, projectId, options);
49
75
  if (!accounts.buildServiceAccounts.length && !accounts.runServiceAccounts.length) {
50
76
  utils.logWarning(`To use this secret in your backend, you must grant access. You can do so in the future with ${clc.bold("firebase apphosting:secrets:grantaccess")}`);
@@ -52,5 +78,9 @@ exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
52
78
  else {
53
79
  await secrets.grantSecretAccess(projectId, projectNumber, secretName, accounts);
54
80
  }
55
- await config.maybeAddSecretToYaml(secretName);
81
+ await config.maybeAddSecretToYaml(secretName, config.APPHOSTING_BASE_YAML_FILE);
82
+ utils.logBullet("To grant additional users access to this secret run " +
83
+ clc.bold(`firebase apphosting:secrets:grantaccess ${secretName} --email [email list]`) +
84
+ ".\nTo grant additional backends access to this secret run " +
85
+ clc.bold(`firebase apphosting:secrets:grantaccess ${secretName} --backend [backend ID]`));
56
86
  });
@@ -17,7 +17,7 @@ function getCertHashType(shaHash) {
17
17
  return apps_1.ShaCertificateType.SHA_CERTIFICATE_TYPE_UNSPECIFIED.toString();
18
18
  }
19
19
  exports.command = new command_1.Command("apps:android:sha:create <appId> <shaHash>")
20
- .description("add a SHA certificate hash for a given app id.")
20
+ .description("add a SHA certificate hash for a given app id")
21
21
  .before(requireAuth_1.requireAuth)
22
22
  .action(async (appId = "", shaHash = "", options) => {
23
23
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -8,7 +8,7 @@ const apps_1 = require("../management/apps");
8
8
  const requireAuth_1 = require("../requireAuth");
9
9
  const utils_1 = require("../utils");
10
10
  exports.command = new command_1.Command("apps:android:sha:delete <appId> <shaId>")
11
- .description("delete a SHA certificate hash for a given app id.")
11
+ .description("delete a SHA certificate hash for a given app id")
12
12
  .before(requireAuth_1.requireAuth)
13
13
  .action(async (appId = "", shaId = "", options) => {
14
14
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -31,7 +31,7 @@ function logCertificatesCount(count = 0) {
31
31
  logger_1.logger.info(`${count} SHA hash(es) total.`);
32
32
  }
33
33
  exports.command = new command_1.Command("apps:android:sha:list <appId>")
34
- .description("list the SHA certificate hashes for a given app id. ")
34
+ .description("list the SHA certificate hashes for a given app id")
35
35
  .before(requireAuth_1.requireAuth)
36
36
  .action(async (appId = "", options) => {
37
37
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -33,7 +33,7 @@ function logPostAppCreationInformation(appMetadata, appPlatform) {
33
33
  logger_1.logger.info(` firebase apps:sdkconfig ${appPlatform} ${appMetadata.appId}`);
34
34
  }
35
35
  exports.command = new command_1.Command("apps:create [platform] [displayName]")
36
- .description("create a new Firebase app. [platform] can be IOS, ANDROID or WEB (case insensitive).")
36
+ .description("create a new Firebase app. [platform] can be IOS, ANDROID or WEB (case insensitive)")
37
37
  .option("-a, --package-name <packageName>", "required package name for the Android app")
38
38
  .option("-b, --bundle-id <bundleId>", "required bundle id for the iOS app")
39
39
  .option("-s, --app-store-id <appStoreId>", "(optional) app store id for the iOS app")
@@ -52,7 +52,7 @@ function toAppPlatform(str) {
52
52
  throw new Error(`Platform ${str} is not compatible with apps:configure`);
53
53
  }
54
54
  exports.command = new command_1.Command("apps:init [platform] [appId]")
55
- .description("Automatically download and create config of a Firebase app. ")
55
+ .description("automatically download and create config of a Firebase app")
56
56
  .before(requireAuth_1.requireAuth)
57
57
  .option("-o, --out [file]", "(optional) write config output to a file")
58
58
  .action(async (platform = "", appId = "", options) => {
@@ -11,7 +11,7 @@ const requirePermissions_1 = require("../requirePermissions");
11
11
  const accountExporter_1 = require("../accountExporter");
12
12
  const MAX_BATCH_SIZE = 1000;
13
13
  exports.command = new command_1.Command("auth:export [dataFile]")
14
- .description("Export accounts from your Firebase project into a data file")
14
+ .description("export accounts from your Firebase project into a data file")
15
15
  .option("--format <format>", "Format of exported data (csv, json). Ignored if <dataFile> has format extension.")
16
16
  .before(requirePermissions_1.requirePermissions, ["firebaseauth.users.get"])
17
17
  .action((dataFile, options) => {
@@ -15,7 +15,7 @@ const requirePermissions_1 = require("../requirePermissions");
15
15
  const accountImporter_1 = require("../accountImporter");
16
16
  const MAX_BATCH_SIZE = 1000;
17
17
  exports.command = new command_1.Command("auth:import [dataFile]")
18
- .description("import users into your Firebase project from a data file(.csv or .json)")
18
+ .description("import users into your Firebase project from a data file (.csv or .json)")
19
19
  .option("--hash-algo <hashAlgo>", "specify the hash algorithm used in password for these accounts")
20
20
  .option("--hash-key <hashKey>", "specify the key used in hash algorithm")
21
21
  .option("--salt-separator <saltSeparator>", "specify the salt separator which will be appended to salt when verifying password. only used by SCRYPT now.")
@@ -12,7 +12,7 @@ const getDefaultDatabaseInstance_1 = require("../getDefaultDatabaseInstance");
12
12
  const error_1 = require("../error");
13
13
  const requireDatabaseInstance_1 = require("../requireDatabaseInstance");
14
14
  exports.command = new command_1.Command("database:instances:create <instanceName>")
15
- .description("create a realtime database instance")
15
+ .description("create a Realtime Database instance")
16
16
  .option("-l, --location <location>", "(optional) location for the database instance, defaults to us-central1")
17
17
  .before(requirePermissions_1.requirePermissions, ["firebasedatabase.instances.create"])
18
18
  .before(commandUtils_1.warnEmulatorNotSupported, types_1.Emulators.DATABASE)
@@ -9,9 +9,8 @@ const utils = require("../utils");
9
9
  const profiler_1 = require("../profiler");
10
10
  const types_1 = require("../emulator/types");
11
11
  const commandUtils_1 = require("../emulator/commandUtils");
12
- const description = "profile the Realtime Database and generate a usage report";
13
12
  exports.command = new command_1.Command("database:profile")
14
- .description(description)
13
+ .description("profile the Realtime Database and generate a usage report")
15
14
  .option("-o, --output <filename>", "save the output to the specified file")
16
15
  .option("-d, --duration <seconds>", "collect database usage information for the specified number of seconds")
17
16
  .option("--raw", "output the raw stats collected as newline delimited json")
@@ -14,7 +14,7 @@ const commandUtils_1 = require("../emulator/commandUtils");
14
14
  const requireDatabaseInstance_1 = require("../requireDatabaseInstance");
15
15
  const utils = require("../utils");
16
16
  exports.command = new command_1.Command("database:settings:set <path> <value>")
17
- .description("set the realtime database setting at path.")
17
+ .description("set the Realtime Database setting at path")
18
18
  .option("--instance <instance>", "use the database <instance>.firebaseio.com (if omitted, use default database instance)")
19
19
  .help(settings_1.HELP_TEXT)
20
20
  .before(requirePermissions_1.requirePermissions, ["firebasedatabase.instances.update"])
@@ -17,7 +17,7 @@ const logger_1 = require("../logger");
17
17
  const requireDatabaseInstance_1 = require("../requireDatabaseInstance");
18
18
  const utils = require("../utils");
19
19
  exports.command = new command_1.Command("database:update <path> [infile]")
20
- .description("update some of the keys for the defined path in your Firebase")
20
+ .description("update some of the keys for the defined path in your Realtime Database")
21
21
  .option("-d, --data <data>", "specify escaped JSON directly")
22
22
  .option("-f, --force", "pass this option to bypass confirmation prompt")
23
23
  .option("--instance <instance>", "use the database <instance>.firebaseio.com (if omitted, use default database instance)")
@@ -10,7 +10,7 @@ const fileUtils_1 = require("../dataconnect/fileUtils");
10
10
  const logger_1 = require("../logger");
11
11
  const auth_1 = require("../auth");
12
12
  exports.command = new command_1.Command("dataconnect:sdk:generate")
13
- .description("generates typed SDKs for your Data Connect connectors")
13
+ .description("generate typed SDKs for your Data Connect connectors")
14
14
  .option("--watch", "watch for changes to your connector GQL files and regenerate your SDKs when updates occur")
15
15
  .action(async (options) => {
16
16
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -10,7 +10,7 @@ const requirePermissions_1 = require("../requirePermissions");
10
10
  const ensureApis_1 = require("../dataconnect/ensureApis");
11
11
  const Table = require("cli-table3");
12
12
  exports.command = new command_1.Command("dataconnect:services:list")
13
- .description("list all deployed services in your Firebase project")
13
+ .description("list all deployed Data Connect services")
14
14
  .before(requirePermissions_1.requirePermissions, [
15
15
  "dataconnect.services.list",
16
16
  "dataconnect.schemas.list",
@@ -9,7 +9,7 @@ const fileUtils_1 = require("../dataconnect/fileUtils");
9
9
  const schemaMigration_1 = require("../dataconnect/schemaMigration");
10
10
  const requireAuth_1 = require("../requireAuth");
11
11
  exports.command = new command_1.Command("dataconnect:sql:diff [serviceId]")
12
- .description("displays the differences between a local DataConnect schema and your CloudSQL database's current schema")
12
+ .description("display the differences between a local Data Connect schema and your CloudSQL database's current schema")
13
13
  .before(requirePermissions_1.requirePermissions, [
14
14
  "firebasedataconnect.services.list",
15
15
  "firebasedataconnect.schemas.list",
@@ -12,7 +12,7 @@ const error_1 = require("../error");
12
12
  const permissions_setup_1 = require("../gcp/cloudsql/permissions_setup");
13
13
  const allowedRoles = Object.keys(permissions_setup_1.fdcSqlRoleMap);
14
14
  exports.command = new command_1.Command("dataconnect:sql:grant [serviceId]")
15
- .description("Grants the SQL role <role> to the provided user or service account <email>.")
15
+ .description("grants the SQL role <role> to the provided user or service account <email>")
16
16
  .option("-R, --role <role>", "The SQL role to grant. One of: owner, writer, or reader.")
17
17
  .option("-E, --email <email>", "The email of the user or service account we would like to grant the role to.")
18
18
  .before(requirePermissions_1.requirePermissions, ["firebasedataconnect.services.list"])
@@ -11,7 +11,7 @@ const requirePermissions_1 = require("../requirePermissions");
11
11
  const ensureApis_1 = require("../dataconnect/ensureApis");
12
12
  const utils_1 = require("../utils");
13
13
  exports.command = new command_1.Command("dataconnect:sql:migrate [serviceId]")
14
- .description("migrates your CloudSQL database's schema to match your local DataConnect schema")
14
+ .description("migrate your CloudSQL database's schema to match your local Data Connect schema")
15
15
  .before(requirePermissions_1.requirePermissions, [
16
16
  "firebasedataconnect.services.list",
17
17
  "firebasedataconnect.schemas.list",
@@ -19,7 +19,7 @@ exports.command = new command_1.Command("dataconnect:sql:migrate [serviceId]")
19
19
  "cloudsql.instances.connect",
20
20
  ])
21
21
  .before(requireAuth_1.requireAuth)
22
- .withForce("Execute any required database changes without prompting")
22
+ .withForce("execute any required database changes without prompting")
23
23
  .action(async (serviceId, options) => {
24
24
  var _a, _b;
25
25
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -14,7 +14,7 @@ const schemaMigration_1 = require("../dataconnect/schemaMigration");
14
14
  const connect_1 = require("../gcp/cloudsql/connect");
15
15
  const cloudSqlAdminClient = require("../gcp/cloudsql/cloudsqladmin");
16
16
  exports.command = new command_1.Command("dataconnect:sql:setup [serviceId]")
17
- .description("Setup your CloudSQL database")
17
+ .description("set up your CloudSQL database")
18
18
  .before(requirePermissions_1.requirePermissions, [
19
19
  "firebasedataconnect.services.list",
20
20
  "firebasedataconnect.schemas.list",
@@ -75,7 +75,7 @@ async function mainShellLoop(conn) {
75
75
  }
76
76
  }
77
77
  exports.command = new command_1.Command("dataconnect:sql:shell [serviceId]")
78
- .description("Starts a shell connected directly to your dataconnect cloudsql instance.")
78
+ .description("start a shell connected directly to your Data Connect service's linked CloudSQL instance")
79
79
  .before(requirePermissions_1.requirePermissions, ["firebasedataconnect.services.list", "cloudsql.instances.connect"])
80
80
  .before(requireAuth_1.requireAuth)
81
81
  .action(async (serviceId, options) => {
@@ -84,10 +84,10 @@ exports.command = new command_1.Command("deploy")
84
84
  "When filtering based on codebases, use colons to specify codebase names " +
85
85
  '(e.g. "--only functions:codebase1:func1,functions:codebase2:group1.subgroup1"). ' +
86
86
  "For data connect, can specify filters with colons to deploy only a service, connector, or schema" +
87
- '(e.g. "--only dataconnect:serviceId,dataconnect:serviceId:connectorId,dataconnect:serviceId:schema"). ')
87
+ '(e.g. "--only dataconnect:serviceId,dataconnect:serviceId:connectorId,dataconnect:serviceId:schema")')
88
88
  .option("--except <targets>", 'deploy to all targets except specified (e.g. "database")')
89
- .option("--dry-run", "Perform a dry run of your deployment. Validates your changes and builds your code without deploying any changes to your project. " +
90
- "In order to provide better validation, this may still enable APIs on the target project.")
89
+ .option("--dry-run", "perform a dry run of your deployment. Validates your changes and builds your code without deploying any changes to your project. " +
90
+ "In order to provide better validation, this may still enable APIs on the target project")
91
91
  .before(requireConfig_1.requireConfig)
92
92
  .before((options) => {
93
93
  options.filteredTargets = (0, filterTargets_1.filterTargets)(options, exports.VALID_DEPLOY_TARGETS);
@@ -7,7 +7,7 @@ const commandUtils_1 = require("../emulator/commandUtils");
7
7
  exports.command = new command_1.Command("emulators:exec <script>")
8
8
  .before(commandUtils.setExportOnExitOptions)
9
9
  .before(commandUtils.beforeEmulatorCommand)
10
- .description("start the local Firebase emulators, " + "run a test script, then shut down the emulators")
10
+ .description("start the local Firebase emulators, run a test script, then shut down the emulators")
11
11
  .option(commandUtils.FLAG_ONLY, commandUtils.DESC_ONLY)
12
12
  .option(commandUtils.FLAG_INSPECT_FUNCTIONS, commandUtils.DESC_INSPECT_FUNCTIONS)
13
13
  .option(commandUtils.FLAG_IMPORT, commandUtils.DESC_IMPORT)
@@ -13,7 +13,7 @@ const requirePermissions_1 = require("../requirePermissions");
13
13
  const error_1 = require("../error");
14
14
  const utils = require("../utils");
15
15
  exports.command = new command_1.Command("ext:dev:register")
16
- .description("register a publisher ID; run this before publishing your first extension.")
16
+ .description("register a publisher ID; run this before publishing your first extension")
17
17
  .before(requirePermissions_1.requirePermissions, ["firebaseextensions.sources.create"])
18
18
  .before(extensionsHelper_1.ensureExtensionsPublisherApiEnabled)
19
19
  .before(extensionsHelper_1.ensureExtensionsApiEnabled)
@@ -16,10 +16,10 @@ const logger_1 = require("../logger");
16
16
  const prompt_1 = require("../prompt");
17
17
  const shortenUrl_1 = require("../shortenUrl");
18
18
  exports.command = new command_1.Command("ext:dev:usage <publisherId>")
19
- .description("get usage for an extension")
19
+ .description("get usage statistics for an extension")
20
20
  .help("use this command to get the usage of extensions you published. " +
21
21
  "Specify the publisher ID you used to publish your extensions, " +
22
- "or the extension ref of your published extension.")
22
+ "or the extension ref of your published extension")
23
23
  .before(requireAuth_1.requireAuth)
24
24
  .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extDevMinVersion")
25
25
  .action(async (input) => {
@@ -23,9 +23,8 @@ const track_1 = require("../track");
23
23
  const prompt_1 = require("../prompt");
24
24
  const manifest = require("../extensions/manifest");
25
25
  const tos_1 = require("../extensions/tos");
26
- exports.command = new command_1.Command("ext:install [extensionRef]")
27
- .description("add an uploaded extension to firebase.json if [publisherId/extensionId] is provided;" +
28
- "or, add a local extension if [localPath] is provided")
26
+ exports.command = new command_1.Command("ext:install [extensionRefOrLocalPath]")
27
+ .description("add an extension to firebase.json")
29
28
  .option("--local", "deprecated")
30
29
  .withForce()
31
30
  .before(requirePermissions_1.requirePermissions, ["firebaseextensions.instances.create"])