firebase-tools 14.2.2 → 14.3.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 (118) hide show
  1. package/lib/api.js +4 -2
  2. package/lib/apphosting/backend.js +12 -23
  3. package/lib/apphosting/config.js +9 -20
  4. package/lib/apphosting/githubConnections.js +52 -80
  5. package/lib/apphosting/repo.js +22 -36
  6. package/lib/apphosting/secrets/dialogs.js +2 -3
  7. package/lib/apphosting/utils.js +1 -3
  8. package/lib/auth.js +1 -4
  9. package/lib/commands/apphosting-backends-delete.js +5 -5
  10. package/lib/commands/apphosting-secrets-set.js +2 -6
  11. package/lib/commands/apps-create.js +2 -3
  12. package/lib/commands/apps-sdkconfig.js +2 -7
  13. package/lib/commands/database-import.js +4 -6
  14. package/lib/commands/database-remove.js +4 -6
  15. package/lib/commands/database-set.js +6 -6
  16. package/lib/commands/database-update.js +5 -5
  17. package/lib/commands/dataconnect-sql-shell.js +4 -6
  18. package/lib/commands/ext-dev-deprecate.js +1 -0
  19. package/lib/commands/ext-dev-init.js +3 -12
  20. package/lib/commands/ext-dev-register.js +2 -4
  21. package/lib/commands/ext-dev-undeprecate.js +1 -2
  22. package/lib/commands/ext-dev-usage.js +1 -3
  23. package/lib/commands/ext-export.js +1 -2
  24. package/lib/commands/ext-install.js +1 -0
  25. package/lib/commands/ext-sdk-install.js +1 -0
  26. package/lib/commands/ext-update.js +1 -0
  27. package/lib/commands/firestore-backups-delete.js +1 -2
  28. package/lib/commands/firestore-backups-schedules-delete.js +1 -2
  29. package/lib/commands/firestore-databases-delete.js +1 -5
  30. package/lib/commands/firestore-delete.js +6 -6
  31. package/lib/commands/functions-artifacts-setpolicy.js +12 -2
  32. package/lib/commands/functions-config-export.js +5 -9
  33. package/lib/commands/functions-delete.js +5 -5
  34. package/lib/commands/functions-deletegcfartifacts.js +4 -4
  35. package/lib/commands/functions-secrets-destroy.js +8 -10
  36. package/lib/commands/functions-secrets-prune.js +12 -13
  37. package/lib/commands/functions-secrets-set.js +11 -15
  38. package/lib/commands/hosting-channel-create.js +1 -2
  39. package/lib/commands/hosting-channel-delete.js +4 -4
  40. package/lib/commands/hosting-channel-open.js +2 -3
  41. package/lib/commands/hosting-disable.js +5 -5
  42. package/lib/commands/hosting-sites-delete.js +4 -4
  43. package/lib/commands/init.js +41 -58
  44. package/lib/commands/login.js +1 -5
  45. package/lib/commands/logout.js +2 -3
  46. package/lib/commands/open.js +1 -2
  47. package/lib/commands/projects-create.js +1 -2
  48. package/lib/commands/remoteconfig-rollback.js +5 -5
  49. package/lib/commands/use.js +110 -110
  50. package/lib/config.js +1 -2
  51. package/lib/dataconnect/build.js +2 -4
  52. package/lib/dataconnect/client.js +20 -1
  53. package/lib/dataconnect/schemaMigration.js +1 -6
  54. package/lib/deploy/functions/params.js +10 -17
  55. package/lib/deploy/functions/prompts.js +6 -28
  56. package/lib/emulator/commandUtils.js +4 -13
  57. package/lib/emulator/controller.js +1 -2
  58. package/lib/emulator/downloadableEmulators.js +12 -12
  59. package/lib/emulator/initEmulators.js +9 -20
  60. package/lib/extensions/askUserForEventsConfig.js +6 -15
  61. package/lib/extensions/askUserForParam.js +23 -52
  62. package/lib/extensions/checkProjectBilling.js +3 -9
  63. package/lib/extensions/diagnose.js +3 -6
  64. package/lib/extensions/extensionsHelper.js +17 -27
  65. package/lib/extensions/manifest.js +1 -2
  66. package/lib/extensions/tos.js +10 -2
  67. package/lib/extensions/utils.js +1 -10
  68. package/lib/frameworks/index.js +1 -2
  69. package/lib/frameworks/next/index.js +7 -4
  70. package/lib/frameworks/vite/index.js +1 -2
  71. package/lib/functions/secrets.js +14 -15
  72. package/lib/gcp/auth.js +29 -1
  73. package/lib/gif/fdcExperience.js +45 -0
  74. package/lib/hosting/interactive.js +2 -3
  75. package/lib/init/features/account.js +2 -4
  76. package/lib/init/features/database.js +11 -20
  77. package/lib/init/features/dataconnect/index.js +7 -14
  78. package/lib/init/features/dataconnect/sdk.js +15 -22
  79. package/lib/init/features/emulators.js +19 -41
  80. package/lib/init/features/firestore/index.js +2 -6
  81. package/lib/init/features/firestore/indexes.js +17 -31
  82. package/lib/init/features/firestore/rules.js +17 -31
  83. package/lib/init/features/functions/index.js +9 -16
  84. package/lib/init/features/functions/javascript.js +16 -30
  85. package/lib/init/features/functions/npm-dependencies.js +4 -8
  86. package/lib/init/features/functions/python.js +1 -3
  87. package/lib/init/features/functions/typescript.js +24 -43
  88. package/lib/init/features/genkit/index.js +23 -38
  89. package/lib/init/features/hosting/github.js +20 -51
  90. package/lib/init/features/hosting/index.js +36 -57
  91. package/lib/init/features/project.js +6 -16
  92. package/lib/init/features/remoteconfig.js +2 -8
  93. package/lib/init/features/storage.js +1 -3
  94. package/lib/management/apps.js +19 -44
  95. package/lib/management/projects.js +17 -28
  96. package/lib/mcp/index.js +12 -1
  97. package/lib/mcp/tools/auth/index.js +7 -1
  98. package/lib/mcp/tools/auth/set_sms_region_policy.js +36 -0
  99. package/lib/mcp/tools/core/consult_firebase_assistant.js +27 -0
  100. package/lib/mcp/tools/core/index.js +6 -1
  101. package/lib/mcp/tools/dataconnect/converter.js +33 -0
  102. package/lib/mcp/tools/dataconnect/generate_dataconnect_operation.js +33 -0
  103. package/lib/mcp/tools/dataconnect/generate_dataconnect_schema.js +25 -0
  104. package/lib/mcp/tools/dataconnect/get_dataconnect_connector.js +31 -0
  105. package/lib/mcp/tools/dataconnect/get_dataconnect_schema.js +31 -0
  106. package/lib/mcp/tools/dataconnect/index.js +11 -1
  107. package/lib/mcp/tools/firestore/{get_documents.js → get_firestore_documents.js} +5 -5
  108. package/lib/mcp/tools/firestore/index.js +7 -3
  109. package/lib/mcp/tools/firestore/{list_collections.js → list_firestore_collections.js} +3 -3
  110. package/lib/mcp/tools/index.js +2 -1
  111. package/lib/mcp/tools/storage/get_storage_rules.js +26 -0
  112. package/lib/mcp/tools/storage/index.js +5 -0
  113. package/lib/prompt.js +78 -65
  114. package/lib/requireTosAcceptance.js +4 -0
  115. package/lib/rulesDeploy.js +10 -15
  116. package/lib/track.js +1 -34
  117. package/lib/utils.js +27 -5
  118. package/package.json +2 -3
@@ -15,6 +15,7 @@ const fsutils = require("../fsutils");
15
15
  const utils = require("../utils");
16
16
  const experiments_1 = require("../experiments");
17
17
  const templates_1 = require("../templates");
18
+ const error_1 = require("../error");
18
19
  const homeDir = os.homedir();
19
20
  const BANNER_TEXT = (0, templates_1.readTemplateSync)("banner.txt");
20
21
  const GITIGNORE_TEMPLATE = (0, templates_1.readTemplateSync)("_gitignore");
@@ -112,7 +113,8 @@ exports.command = new command_1.Command("init [feature]")
112
113
  .help(HELP)
113
114
  .before(requireAuth_1.requireAuth)
114
115
  .action(initAction);
115
- function initAction(feature, options) {
116
+ async function initAction(feature, options) {
117
+ var _a;
116
118
  if (feature && !featureNames.includes(feature)) {
117
119
  return utils.reject(clc.bold(feature) +
118
120
  " is not a supported feature; must be one of " +
@@ -152,66 +154,47 @@ function initAction(feature, options) {
152
154
  fallback: {},
153
155
  }),
154
156
  };
155
- let next;
156
157
  if (process.platform === "win32") {
157
- next = (0, prompt_1.promptOnce)({
158
- type: "confirm",
159
- message: "Are you ready to proceed?",
160
- });
158
+ if (!(await (0, prompt_1.confirm)("Are you ready to proceed?"))) {
159
+ throw new error_1.FirebaseError("Aborted by user.", { exit: 1 });
160
+ }
161
+ }
162
+ if (feature) {
163
+ setup.featureArg = true;
164
+ setup.features = [feature];
161
165
  }
162
166
  else {
163
- next = Promise.resolve(true);
167
+ setup.features = await (0, prompt_1.checkbox)({
168
+ message: "Which Firebase features do you want to set up for this directory? " +
169
+ "Press Space to select features, then Enter to confirm your choices.",
170
+ choices: choices.filter((c) => !c.hidden),
171
+ });
164
172
  }
165
- return next
166
- .then((proceed) => {
167
- if (!proceed) {
168
- return utils.reject("Aborted by user.", { exit: 1 });
169
- }
170
- if (feature) {
171
- setup.featureArg = true;
172
- setup.features = [feature];
173
- return undefined;
174
- }
175
- return (0, prompt_1.prompt)(setup, [
176
- {
177
- type: "checkbox",
178
- name: "features",
179
- message: "Which Firebase features do you want to set up for this directory? " +
180
- "Press Space to select features, then Enter to confirm your choices.",
181
- choices: choices.filter((c) => !c.hidden),
182
- },
183
- ]);
184
- })
185
- .then(() => {
186
- var _a;
187
- if (!setup.features || ((_a = setup.features) === null || _a === void 0 ? void 0 : _a.length) === 0) {
188
- return utils.reject("Must select at least one feature. Use " +
189
- clc.bold(clc.underline("SPACEBAR")) +
190
- " to select features, or specify a feature by running " +
191
- clc.bold("firebase init [feature_name]"));
192
- }
193
- setup.features.unshift("project");
194
- const allAccounts = (0, auth_1.getAllAccounts)();
195
- if (allAccounts.length > 1) {
196
- setup.features.unshift("account");
197
- }
198
- if (setup.features.includes("hosting") && setup.features.includes("hosting:github")) {
199
- setup.features = setup.features.filter((f) => f !== "hosting:github");
200
- }
201
- return (0, init_1.init)(setup, config, options);
202
- })
203
- .then(() => {
204
- logger_1.logger.info();
205
- utils.logBullet("Writing configuration info to " + clc.bold("firebase.json") + "...");
206
- config.writeProjectFile("firebase.json", setup.config);
207
- utils.logBullet("Writing project information to " + clc.bold(".firebaserc") + "...");
208
- config.writeProjectFile(".firebaserc", setup.rcfile);
209
- if (!fsutils.fileExistsSync(config.path(".gitignore"))) {
210
- utils.logBullet("Writing gitignore file to " + clc.bold(".gitignore") + "...");
211
- config.writeProjectFile(".gitignore", GITIGNORE_TEMPLATE);
212
- }
213
- logger_1.logger.info();
214
- utils.logSuccess("Firebase initialization complete!");
215
- });
173
+ if (!setup.features || ((_a = setup.features) === null || _a === void 0 ? void 0 : _a.length) === 0) {
174
+ throw new error_1.FirebaseError("Must select at least one feature. Use " +
175
+ clc.bold(clc.underline("SPACEBAR")) +
176
+ " to select features, or specify a feature by running " +
177
+ clc.bold("firebase init [feature_name]"));
178
+ }
179
+ setup.features.unshift("project");
180
+ const allAccounts = (0, auth_1.getAllAccounts)();
181
+ if (allAccounts.length > 1) {
182
+ setup.features.unshift("account");
183
+ }
184
+ if (setup.features.includes("hosting") && setup.features.includes("hosting:github")) {
185
+ setup.features = setup.features.filter((f) => f !== "hosting:github");
186
+ }
187
+ await (0, init_1.init)(setup, config, options);
188
+ logger_1.logger.info();
189
+ utils.logBullet("Writing configuration info to " + clc.bold("firebase.json") + "...");
190
+ config.writeProjectFile("firebase.json", setup.config);
191
+ utils.logBullet("Writing project information to " + clc.bold(".firebaserc") + "...");
192
+ config.writeProjectFile(".firebaserc", setup.rcfile);
193
+ if (!fsutils.fileExistsSync(config.path(".gitignore"))) {
194
+ utils.logBullet("Writing gitignore file to " + clc.bold(".gitignore") + "...");
195
+ config.writeProjectFile(".gitignore", GITIGNORE_TEMPLATE);
196
+ }
197
+ logger_1.logger.info();
198
+ utils.logSuccess("Firebase initialization complete!");
216
199
  }
217
200
  exports.initAction = initAction;
@@ -28,11 +28,7 @@ exports.command = new command_1.Command("login")
28
28
  }
29
29
  if (!options.reauth) {
30
30
  utils.logBullet("Firebase optionally collects CLI and Emulator Suite usage and error reporting information to help improve our products. Data is collected in accordance with Google's privacy policy (https://policies.google.com/privacy) and is not used to identify you.\n");
31
- const collectUsage = await (0, prompt_1.promptOnce)({
32
- type: "confirm",
33
- name: "collectUsage",
34
- message: "Allow Firebase to collect CLI and Emulator Suite usage and error reporting information?",
35
- });
31
+ const collectUsage = await (0, prompt_1.confirm)("Allow Firebase to collect CLI and Emulator Suite usage and error reporting information?");
36
32
  configstore_1.configstore.set("usage", collectUsage);
37
33
  if (collectUsage) {
38
34
  utils.logBullet("To change your data collection preference at any time, run `firebase logout` and log in again.");
@@ -5,8 +5,8 @@ const command_1 = require("../command");
5
5
  const logger_1 = require("../logger");
6
6
  const clc = require("colorette");
7
7
  const utils = require("../utils");
8
- const prompt_1 = require("../prompt");
9
8
  const auth_1 = require("../auth");
9
+ const prompt_1 = require("../prompt");
10
10
  exports.command = new command_1.Command("logout [email]")
11
11
  .description("log the CLI out of Firebase")
12
12
  .action(logoutAction);
@@ -38,8 +38,7 @@ async function logoutAction(email, options) {
38
38
  value: a,
39
39
  };
40
40
  });
41
- newDefaultAccount = await (0, prompt_1.promptOnce)({
42
- type: "list",
41
+ newDefaultAccount = await (0, prompt_1.select)({
43
42
  message: "You are logging out of your default account, which account should become the new default?",
44
43
  choices,
45
44
  });
@@ -67,8 +67,7 @@ exports.command = new command_1.Command("open [link]")
67
67
  throw new error_1.FirebaseError("Unrecognized link name. Valid links are:\n\n" + LINKS.map((l) => l.arg).join("\n"));
68
68
  }
69
69
  if (!link) {
70
- const name = await (0, prompt_1.promptOnce)({
71
- type: "list",
70
+ const name = await (0, prompt_1.select)({
72
71
  message: "What link would you like to open?",
73
72
  choices: CHOICES,
74
73
  });
@@ -4,7 +4,6 @@ exports.command = void 0;
4
4
  const command_1 = require("../command");
5
5
  const error_1 = require("../error");
6
6
  const projects_1 = require("../management/projects");
7
- const prompt_1 = require("../prompt");
8
7
  const requireAuth_1 = require("../requireAuth");
9
8
  exports.command = new command_1.Command("projects:create [projectId]")
10
9
  .description("creates a new Google Cloud Platform project, then adds Firebase resources to the project")
@@ -18,7 +17,7 @@ exports.command = new command_1.Command("projects:create [projectId]")
18
17
  throw new error_1.FirebaseError("Invalid argument, please provide only one type of project parent (organization or folder)");
19
18
  }
20
19
  if (!options.nonInteractive) {
21
- await (0, prompt_1.prompt)(options, projects_1.PROJECTS_CREATE_QUESTIONS);
20
+ options = Object.assign(Object.assign({}, options), (await (0, projects_1.promptProjectCreation)()));
22
21
  }
23
22
  if (!options.projectId) {
24
23
  throw new error_1.FirebaseError("Project ID cannot be empty");
@@ -35,13 +35,13 @@ exports.command = new command_1.Command("remoteconfig:rollback")
35
35
  `. ` +
36
36
  `Invalid Version Number`);
37
37
  }
38
- const confirm = await (0, prompt_1.promptOnce)({
39
- type: "confirm",
40
- name: "force",
38
+ const proceed = await (0, prompt_1.confirm)({
41
39
  message: "Proceed to rollback template to version " + targetVersion + "?",
42
40
  default: false,
43
- }, options);
44
- if (!confirm) {
41
+ force: options.force,
42
+ nonInteractive: options.nonInteractive,
43
+ });
44
+ if (!proceed) {
45
45
  return;
46
46
  }
47
47
  return (0, rollback_1.rollbackTemplate)((0, projectUtils_1.needProjectId)(options), targetVersion);
@@ -9,6 +9,7 @@ const prompt_1 = require("../prompt");
9
9
  const requireAuth_1 = require("../requireAuth");
10
10
  const command_2 = require("../command");
11
11
  const utils = require("../utils");
12
+ const error_1 = require("../error");
12
13
  function listAliases(options) {
13
14
  if (options.rc.hasProjects) {
14
15
  logger_1.logger.info("Project aliases for", clc.bold(options.projectRoot || "") + ":");
@@ -29,6 +30,106 @@ function listAliases(options) {
29
30
  function verifyMessage(name) {
30
31
  return "please verify project " + clc.bold(name) + " exists and you have access.";
31
32
  }
33
+ async function setNewActive(projectOrAlias, aliasOpt, options) {
34
+ let project;
35
+ const hasAlias = options.rc.hasProjectAlias(projectOrAlias);
36
+ const resolvedProject = options.rc.resolveAlias(projectOrAlias);
37
+ (0, command_2.validateProjectId)(resolvedProject);
38
+ try {
39
+ project = await (0, projects_1.getProject)(resolvedProject);
40
+ }
41
+ catch (_a) {
42
+ throw new error_1.FirebaseError("Invalid project selection, " + verifyMessage(projectOrAlias));
43
+ }
44
+ if (aliasOpt) {
45
+ if (!project) {
46
+ throw new error_1.FirebaseError(`Cannot create alias ${clc.bold(aliasOpt)}, ${verifyMessage(projectOrAlias)}`);
47
+ }
48
+ options.rc.addProjectAlias(aliasOpt, projectOrAlias);
49
+ logger_1.logger.info("Created alias", clc.bold(aliasOpt), "for", resolvedProject + ".");
50
+ }
51
+ if (hasAlias) {
52
+ if (!project) {
53
+ throw new error_1.FirebaseError(`Unable to use alias ${clc.bold(projectOrAlias)}, ${verifyMessage(resolvedProject)}`);
54
+ }
55
+ utils.makeActiveProject(options.projectRoot, projectOrAlias);
56
+ logger_1.logger.info("Now using alias", clc.bold(projectOrAlias), "(" + resolvedProject + ")");
57
+ }
58
+ else if (project) {
59
+ utils.makeActiveProject(options.projectRoot, projectOrAlias);
60
+ logger_1.logger.info("Now using project", clc.bold(projectOrAlias));
61
+ }
62
+ else {
63
+ throw new error_1.FirebaseError(`Invalid project selection, ${verifyMessage(projectOrAlias)}`);
64
+ }
65
+ }
66
+ function unalias(alias, options) {
67
+ if (options.rc.hasProjectAlias(alias)) {
68
+ options.rc.removeProjectAlias(alias);
69
+ logger_1.logger.info("Removed alias", clc.bold(alias));
70
+ logger_1.logger.info();
71
+ listAliases(options);
72
+ }
73
+ }
74
+ async function addAlias(options) {
75
+ if (options.nonInteractive) {
76
+ return utils.reject("Cannot run " +
77
+ clc.bold("firebase use --add") +
78
+ " in non-interactive mode. Use " +
79
+ clc.bold("firebase use <project_id> --alias <alias>") +
80
+ " instead.");
81
+ }
82
+ const projects = await (0, projects_1.listFirebaseProjects)();
83
+ const results = {};
84
+ const project = await (0, prompt_1.select)({
85
+ message: "Which project do you want to add?",
86
+ choices: projects.map((p) => p.projectId).sort(),
87
+ });
88
+ const alias = await (0, prompt_1.input)({
89
+ message: "What alias do you want to use for this project? (e.g. staging)",
90
+ validate: (input) => {
91
+ return input && input.length > 0;
92
+ },
93
+ });
94
+ options.rc.addProjectAlias(alias, project);
95
+ utils.makeActiveProject(options.projectRoot, results.alias);
96
+ logger_1.logger.info();
97
+ logger_1.logger.info("Created alias", clc.bold(results.alias || ""), "for", results.project + ".");
98
+ logger_1.logger.info("Now using alias", clc.bold(results.alias || "") + " (" + results.project + ")");
99
+ }
100
+ function clearAlias(options) {
101
+ utils.makeActiveProject(options.projectRoot, undefined);
102
+ delete options.projectAlias;
103
+ delete options.project;
104
+ logger_1.logger.info("Cleared active project.");
105
+ logger_1.logger.info();
106
+ listAliases(options);
107
+ }
108
+ async function genericUse(options) {
109
+ if (options.nonInteractive || !process.stdout.isTTY) {
110
+ if (options.project) {
111
+ logger_1.logger.info(options.project);
112
+ return options.project;
113
+ }
114
+ return utils.reject("No active project");
115
+ }
116
+ if (options.projectAlias) {
117
+ logger_1.logger.info("Active Project:", clc.bold(clc.cyan(options.projectAlias + " (" + options.project + ")")));
118
+ }
119
+ else if (options.project) {
120
+ logger_1.logger.info("Active Project:", clc.bold(clc.cyan(options.project)));
121
+ }
122
+ else {
123
+ let msg = "No project is currently active";
124
+ if (options.rc.hasProjects) {
125
+ msg += ", and no aliases have been created.";
126
+ }
127
+ logger_1.logger.info(msg + ".");
128
+ }
129
+ logger_1.logger.info();
130
+ listAliases(options);
131
+ return options.project;
132
+ }
32
133
  exports.command = new command_1.Command("use [alias_or_project_id]")
33
134
  .description("set an active Firebase project for your working directory")
34
135
  .option("--add", "create a new project alias interactively")
@@ -49,117 +150,16 @@ exports.command = new command_1.Command("use [alias_or_project_id]")
49
150
  " to start a project directory in the current folder.");
50
151
  }
51
152
  if (newActive) {
52
- let project;
53
- const hasAlias = options.rc.hasProjectAlias(newActive);
54
- const resolvedProject = options.rc.resolveAlias(newActive);
55
- (0, command_2.validateProjectId)(resolvedProject);
56
- return (0, projects_1.getProject)(resolvedProject)
57
- .then((foundProject) => {
58
- project = foundProject;
59
- })
60
- .catch(() => {
61
- return utils.reject("Invalid project selection, " + verifyMessage(newActive));
62
- })
63
- .then(() => {
64
- if (aliasOpt) {
65
- if (!project) {
66
- return utils.reject("Cannot create alias " + clc.bold(aliasOpt) + ", " + verifyMessage(newActive));
67
- }
68
- options.rc.addProjectAlias(aliasOpt, newActive);
69
- logger_1.logger.info("Created alias", clc.bold(aliasOpt), "for", resolvedProject + ".");
70
- }
71
- if (hasAlias) {
72
- if (!project) {
73
- return utils.reject("Unable to use alias " +
74
- clc.bold(newActive) +
75
- ", " +
76
- verifyMessage(resolvedProject));
77
- }
78
- utils.makeActiveProject(options.projectRoot, newActive);
79
- logger_1.logger.info("Now using alias", clc.bold(newActive), "(" + resolvedProject + ")");
80
- }
81
- else if (project) {
82
- utils.makeActiveProject(options.projectRoot, newActive);
83
- logger_1.logger.info("Now using project", clc.bold(newActive));
84
- }
85
- else {
86
- return utils.reject("Invalid project selection, " + verifyMessage(newActive));
87
- }
88
- });
89
- }
90
- else if (options.unalias) {
91
- if (options.rc.hasProjectAlias(options.unalias)) {
92
- options.rc.removeProjectAlias(options.unalias);
93
- logger_1.logger.info("Removed alias", clc.bold(options.unalias));
94
- logger_1.logger.info();
95
- listAliases(options);
96
- }
153
+ return setNewActive(newActive, aliasOpt, options);
97
154
  }
98
- else if (options.add) {
99
- if (options.nonInteractive) {
100
- return utils.reject("Cannot run " +
101
- clc.bold("firebase use --add") +
102
- " in non-interactive mode. Use " +
103
- clc.bold("firebase use <project_id> --alias <alias>") +
104
- " instead.");
105
- }
106
- return (0, projects_1.listFirebaseProjects)().then((projects) => {
107
- const results = {};
108
- return (0, prompt_1.prompt)(results, [
109
- {
110
- type: "list",
111
- name: "project",
112
- message: "Which project do you want to add?",
113
- choices: projects.map((p) => p.projectId).sort(),
114
- },
115
- {
116
- type: "input",
117
- name: "alias",
118
- message: "What alias do you want to use for this project? (e.g. staging)",
119
- validate: (input) => {
120
- return input && input.length > 0;
121
- },
122
- },
123
- ]).then(() => {
124
- options.rc.addProjectAlias(results.alias, results.project);
125
- utils.makeActiveProject(options.projectRoot, results.alias);
126
- logger_1.logger.info();
127
- logger_1.logger.info("Created alias", clc.bold(results.alias || ""), "for", results.project + ".");
128
- logger_1.logger.info("Now using alias", clc.bold(results.alias || "") + " (" + results.project + ")");
129
- });
130
- });
131
- }
132
- else if (options.clear) {
133
- utils.makeActiveProject(options.projectRoot, undefined);
134
- options.projectAlias = null;
135
- options.project = null;
136
- logger_1.logger.info("Cleared active project.");
137
- logger_1.logger.info();
138
- listAliases(options);
155
+ if (options.unalias) {
156
+ return unalias(options.unalias, options);
139
157
  }
140
- else {
141
- if (options.nonInteractive || !process.stdout.isTTY) {
142
- if (options.project) {
143
- logger_1.logger.info(options.project);
144
- return options.project;
145
- }
146
- return utils.reject("No active project");
147
- }
148
- if (options.projectAlias) {
149
- logger_1.logger.info("Active Project:", clc.bold(clc.cyan(options.projectAlias + " (" + options.project + ")")));
150
- }
151
- else if (options.project) {
152
- logger_1.logger.info("Active Project:", clc.bold(clc.cyan(options.project)));
153
- }
154
- else {
155
- let msg = "No project is currently active";
156
- if (options.rc.hasProjects) {
157
- msg += ", and no aliases have been created.";
158
- }
159
- logger_1.logger.info(msg + ".");
160
- }
161
- logger_1.logger.info();
162
- listAliases(options);
163
- return options.project;
158
+ if (options.add) {
159
+ return addAlias(options);
160
+ }
161
+ if (options.clear) {
162
+ return clearAlias(options);
164
163
  }
164
+ return genericUse(options);
165
165
  });
package/lib/config.js CHANGED
@@ -179,8 +179,7 @@ class Config {
179
179
  existingContent = fsutils.readFile(writeTo);
180
180
  }
181
181
  if (existingContent && existingContent !== content && !force) {
182
- next = await (0, prompt_1.promptOnce)({
183
- type: "confirm",
182
+ next = await (0, prompt_1.confirm)({
184
183
  message: "File " + clc.underline(path) + " already exists. Overwrite?",
185
184
  default: !!confirmByDefault,
186
185
  });
@@ -44,9 +44,8 @@ async function handleBuildErrors(errors, nonInteractive, force, dryRun) {
44
44
  throw new error_1.FirebaseError("Explicit acknowledgement required for breaking schema or connector changes and new insecure operations. Rerun this command with --force to deploy these changes.");
45
45
  }
46
46
  else if (!nonInteractive && !force && !dryRun) {
47
- const result = await (0, prompt_1.promptOnce)({
47
+ const result = await (0, prompt_1.select)({
48
48
  message: "Would you like to proceed with these changes?",
49
- type: "list",
50
49
  choices,
51
50
  default: "abort",
52
51
  });
@@ -59,9 +58,8 @@ async function handleBuildErrors(errors, nonInteractive, force, dryRun) {
59
58
  utils.logLabeledWarning("dataconnect", `There are existing insecure operations or changes in your schema or connectors that may cause unexpected behavior in your existing applications:\n` +
60
59
  (0, graphqlError_1.prettifyTable)(interactiveAcks));
61
60
  if (!nonInteractive && !force && !dryRun) {
62
- const result = await (0, prompt_1.promptOnce)({
61
+ const result = await (0, prompt_1.select)({
63
62
  message: "Would you like to proceed with these changes?",
64
- type: "list",
65
63
  choices,
66
64
  default: "proceed",
67
65
  });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.upsertConnector = exports.listConnectors = exports.deleteConnector = exports.getConnector = exports.deleteSchema = exports.upsertSchema = exports.getSchema = exports.deleteService = exports.createService = exports.listAllServices = exports.getService = exports.listLocations = void 0;
3
+ exports.upsertConnector = exports.listConnectors = exports.deleteConnector = exports.getConnector = exports.deleteSchema = exports.upsertSchema = exports.listSchemas = exports.getSchema = exports.deleteService = exports.createService = exports.listAllServices = exports.getService = exports.listLocations = void 0;
4
4
  const api_1 = require("../api");
5
5
  const apiv2_1 = require("../apiv2");
6
6
  const operationPoller = require("../operation-poller");
@@ -70,6 +70,25 @@ async function getSchema(serviceName) {
70
70
  }
71
71
  }
72
72
  exports.getSchema = getSchema;
73
+ async function listSchemas(serviceName, fields = []) {
74
+ const schemas = [];
75
+ const getNextPage = async (pageToken = "") => {
76
+ const res = await dataconnectClient().get(`${serviceName}/schemas`, {
77
+ queryParams: {
78
+ pageSize: PAGE_SIZE_MAX,
79
+ pageToken,
80
+ fields: fields.join(","),
81
+ },
82
+ });
83
+ schemas.push(...(res.body.schemas || []));
84
+ if (res.body.nextPageToken) {
85
+ await getNextPage(res.body.nextPageToken);
86
+ }
87
+ };
88
+ await getNextPage();
89
+ return schemas;
90
+ }
91
+ exports.listSchemas = listSchemas;
73
92
  async function upsertSchema(schema, validateOnly = false) {
74
93
  const op = await dataconnectClient().patch(`${schema.name}`, schema, {
75
94
  queryParams: {
@@ -307,12 +307,7 @@ async function promptForSchemaMigration(options, instanceName, databaseId, err,
307
307
  { name: "Abort changes", value: "none" },
308
308
  ];
309
309
  const defaultValue = validationMode === "STRICT_AFTER_COMPATIBLE" ? "none" : "all";
310
- return await (0, prompt_1.promptOnce)({
311
- message: message,
312
- type: "list",
313
- choices,
314
- default: defaultValue,
315
- });
310
+ return await (0, prompt_1.select)({ message, choices, default: defaultValue });
316
311
  }
317
312
  if (!validateOnly) {
318
313
  throw new error_1.FirebaseError("Command aborted. Your database schema is incompatible with your Data Connect schema. Run `firebase dataconnect:sql:migrate` to migrate your database schema");
@@ -219,9 +219,7 @@ function populateDefaultParams(config) {
219
219
  async function handleSecret(secretParam, projectId) {
220
220
  const metadata = await secretManager.getSecretMetadata(projectId, secretParam.name, "latest");
221
221
  if (!metadata.secret) {
222
- const secretValue = await (0, prompt_1.promptOnce)({
223
- name: secretParam.name,
224
- type: "password",
222
+ const secretValue = await (0, prompt_1.password)({
225
223
  message: `This secret will be stored in Cloud Secret Manager (https://cloud.google.com/secret-manager/pricing) as ${secretParam.name}. Enter a value for ${secretParam.label || secretParam.name}:`,
226
224
  });
227
225
  await secretManager.createSecret(projectId, secretParam.name, (0, secretManager_1.labels)());
@@ -454,31 +452,28 @@ async function promptResourceStrings(prompt, input, projectId) {
454
452
  function shouldRetry(obj) {
455
453
  return typeof obj === "object" && obj.message !== undefined;
456
454
  }
457
- async function promptText(prompt, input, resolvedDefault, converter) {
458
- const res = await (0, prompt_1.promptOnce)({
459
- type: "input",
455
+ async function promptText(prompt, textInput, resolvedDefault, converter) {
456
+ const res = await (0, prompt_1.input)({
460
457
  default: resolvedDefault,
461
458
  message: prompt,
462
459
  });
463
- if (input.text.validationRegex) {
464
- const userRe = new RegExp(input.text.validationRegex);
460
+ if (textInput.text.validationRegex) {
461
+ const userRe = new RegExp(textInput.text.validationRegex);
465
462
  if (!userRe.test(res)) {
466
- logger_1.logger.error(input.text.validationErrorMessage ||
463
+ logger_1.logger.error(textInput.text.validationErrorMessage ||
467
464
  `Input did not match provided validator ${userRe.toString()}, retrying...`);
468
- return promptText(prompt, input, resolvedDefault, converter);
465
+ return promptText(prompt, textInput, resolvedDefault, converter);
469
466
  }
470
467
  }
471
468
  const converted = converter(res.toString());
472
469
  if (shouldRetry(converted)) {
473
470
  logger_1.logger.error(converted.message);
474
- return promptText(prompt, input, resolvedDefault, converter);
471
+ return promptText(prompt, textInput, resolvedDefault, converter);
475
472
  }
476
473
  return converted;
477
474
  }
478
475
  async function promptSelect(prompt, input, resolvedDefault, converter) {
479
- const response = await (0, prompt_1.promptOnce)({
480
- name: "input",
481
- type: "list",
476
+ const response = await (0, prompt_1.select)({
482
477
  default: resolvedDefault,
483
478
  message: prompt,
484
479
  choices: input.select.options.map((option) => {
@@ -497,9 +492,7 @@ async function promptSelect(prompt, input, resolvedDefault, converter) {
497
492
  return converted;
498
493
  }
499
494
  async function promptSelectMultiple(prompt, input, resolvedDefault, converter) {
500
- const response = await (0, prompt_1.promptOnce)({
501
- name: "input",
502
- type: "checkbox",
495
+ const response = await (0, prompt_1.checkbox)({
503
496
  default: resolvedDefault,
504
497
  message: prompt,
505
498
  choices: input.multiSelect.options.map((option) => {
@@ -39,12 +39,7 @@ async function promptForFailurePolicies(options, want, have) {
39
39
  exit: 1,
40
40
  });
41
41
  }
42
- const proceed = await (0, prompt_1.promptOnce)({
43
- type: "confirm",
44
- name: "confirm",
45
- default: false,
46
- message: "Would you like to proceed with deployment?",
47
- });
42
+ const proceed = await (0, prompt_1.confirm)("Would you like to proceed with deployment?");
48
43
  if (!proceed) {
49
44
  throw new error_1.FirebaseError("Deployment canceled.", { exit: 1 });
50
45
  }
@@ -105,10 +100,7 @@ async function promptForUnsafeMigration(fnsToUpdate, options) {
105
100
  return safeUpdates;
106
101
  }
107
102
  for (const eu of unsafeUpdates) {
108
- const shouldUpdate = await (0, prompt_1.promptOnce)({
109
- type: "confirm",
110
- name: "confirm",
111
- default: false,
103
+ const shouldUpdate = await (0, prompt_1.confirm)({
112
104
  message: `[${(0, functionsDeployHelper_1.getFunctionLabel)(eu.endpoint)}] Would you like to proceed with the unsafe migration?`,
113
105
  });
114
106
  if (shouldUpdate) {
@@ -177,12 +169,7 @@ async function promptForMinInstances(options, want, have) {
177
169
  "\n\n" +
178
170
  costLine;
179
171
  utils.logLabeledWarning("functions", warnMessage);
180
- const proceed = await (0, prompt_1.promptOnce)({
181
- type: "confirm",
182
- name: "confirm",
183
- default: false,
184
- message: "Would you like to proceed with deployment?",
185
- });
172
+ const proceed = await (0, prompt_1.confirm)("Would you like to proceed with deployment?");
186
173
  if (!proceed) {
187
174
  throw new error_1.FirebaseError("Deployment canceled.", { exit: 1 });
188
175
  }
@@ -200,19 +187,10 @@ async function promptForCleanupPolicyDays(options, locations) {
200
187
  `Pass the --force option to automatically set up a cleanup policy or ` +
201
188
  "run 'firebase functions:artifacts:setpolicy' to manually set up a cleanup policy.");
202
189
  }
203
- const result = await (0, prompt_1.promptOnce)({
204
- type: "input",
205
- name: "days",
206
- default: artifacts.DEFAULT_CLEANUP_DAYS.toString(),
190
+ return await (0, prompt_1.number)({
191
+ default: artifacts.DEFAULT_CLEANUP_DAYS,
207
192
  message: "How many days do you want to keep container images before they're deleted?",
208
- validate: (input) => {
209
- const days = parseInt(input);
210
- if (isNaN(days) || days < 0) {
211
- return "Please enter a non-negative number";
212
- }
213
- return true;
214
- },
193
+ validate: (days) => !days || isNaN(days) || days < 0 ? "Please enter a non-negative number" : true,
215
194
  });
216
- return parseInt(result);
217
195
  }
218
196
  exports.promptForCleanupPolicyDays = promptForCleanupPolicyDays;