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
@@ -38,8 +38,7 @@ async function doSetup(setup, config, options) {
38
38
  value: "overwrite",
39
39
  },
40
40
  ];
41
- const initOpt = await (0, prompt_1.promptOnce)({
42
- type: "list",
41
+ const initOpt = await (0, prompt_1.select)({
43
42
  message: "Would you like to initialize a new codebase, or overwrite an existing one?",
44
43
  default: "new",
45
44
  choices,
@@ -66,10 +65,7 @@ async function initNewCodebase(setup, config) {
66
65
  if (attempts++ >= MAX_ATTEMPTS) {
67
66
  throw new error_1.FirebaseError("Exceeded max number of attempts to input valid codebase name. Please restart.");
68
67
  }
69
- codebase = await (0, prompt_1.promptOnce)({
70
- type: "input",
71
- message: "What should be the name of this codebase?",
72
- });
68
+ codebase = await (0, prompt_1.input)("What should be the name of this codebase?");
73
69
  try {
74
70
  (0, projectConfig_1.validateCodebase)(codebase);
75
71
  (0, projectConfig_1.assertUnique)(setup.config.functions, "codebase", codebase);
@@ -85,8 +81,7 @@ async function initNewCodebase(setup, config) {
85
81
  throw new error_1.FirebaseError("Exceeded max number of attempts to input valid source. Please restart.");
86
82
  }
87
83
  attempts++;
88
- source = await (0, prompt_1.promptOnce)({
89
- type: "input",
84
+ source = await (0, prompt_1.input)({
90
85
  message: `In what sub-directory would you like to initialize your functions for codebase ${clc.bold(codebase)}?`,
91
86
  default: codebase,
92
87
  });
@@ -114,8 +109,7 @@ async function overwriteCodebase(setup, config) {
114
109
  name: cfg["codebase"],
115
110
  value: cfg["codebase"],
116
111
  }));
117
- codebase = await (0, prompt_1.promptOnce)({
118
- type: "list",
112
+ codebase = await (0, prompt_1.select)({
119
113
  message: "Which codebase would you like to overwrite?",
120
114
  choices,
121
115
  });
@@ -142,13 +136,12 @@ async function languageSetup(setup, config) {
142
136
  name: "TypeScript",
143
137
  value: "typescript",
144
138
  },
139
+ {
140
+ name: "Python",
141
+ value: "python",
142
+ },
145
143
  ];
146
- choices.push({
147
- name: "Python",
148
- value: "python",
149
- });
150
- const language = await (0, prompt_1.promptOnce)({
151
- type: "list",
144
+ const language = await (0, prompt_1.select)({
152
145
  message: "What language would you like to use to write Cloud Functions?",
153
146
  default: "javascript",
154
147
  choices,
@@ -10,35 +10,21 @@ const PACKAGE_LINTING_TEMPLATE = (0, templates_1.readTemplateSync)("init/functio
10
10
  const PACKAGE_NO_LINTING_TEMPLATE = (0, templates_1.readTemplateSync)("init/functions/javascript/package.nolint.json");
11
11
  const ESLINT_TEMPLATE = (0, templates_1.readTemplateSync)("init/functions/javascript/_eslintrc");
12
12
  const GITIGNORE_TEMPLATE = (0, templates_1.readTemplateSync)("init/functions/javascript/_gitignore");
13
- function setup(setup, config) {
14
- return (0, prompt_1.prompt)(setup.functions, [
15
- {
16
- name: "lint",
17
- type: "confirm",
18
- message: "Do you want to use ESLint to catch probable bugs and enforce style?",
19
- default: false,
20
- },
21
- ])
22
- .then(() => {
23
- if (setup.functions.lint) {
24
- const cbconfig = (0, projectConfig_1.configForCodebase)(setup.config.functions, setup.functions.codebase);
25
- cbconfig.predeploy = ['npm --prefix "$RESOURCE_DIR" run lint'];
26
- return config
27
- .askWriteProjectFile(`${setup.functions.source}/package.json`, PACKAGE_LINTING_TEMPLATE)
28
- .then(() => {
29
- config.askWriteProjectFile(`${setup.functions.source}/.eslintrc.js`, ESLINT_TEMPLATE);
30
- });
31
- }
32
- return config.askWriteProjectFile(`${setup.functions.source}/package.json`, PACKAGE_NO_LINTING_TEMPLATE);
33
- })
34
- .then(() => {
35
- return config.askWriteProjectFile(`${setup.functions.source}/index.js`, INDEX_TEMPLATE);
36
- })
37
- .then(() => {
38
- return config.askWriteProjectFile(`${setup.functions.source}/.gitignore`, GITIGNORE_TEMPLATE);
39
- })
40
- .then(() => {
41
- return (0, npm_dependencies_1.askInstallDependencies)(setup.functions, config);
42
- });
13
+ async function setup(setup, config) {
14
+ setup.functions.lint =
15
+ setup.functions.lint ||
16
+ (await (0, prompt_1.confirm)("Do you want to use ESLint to catch probable bugs and enforce style?"));
17
+ if (setup.functions.lint) {
18
+ const cbconfig = (0, projectConfig_1.configForCodebase)(setup.config.functions, setup.functions.codebase);
19
+ cbconfig.predeploy = ['npm --prefix "$RESOURCE_DIR" run lint'];
20
+ await config.askWriteProjectFile(`${setup.functions.source}/package.json`, PACKAGE_LINTING_TEMPLATE);
21
+ await config.askWriteProjectFile(`${setup.functions.source}/.eslintrc.js`, ESLINT_TEMPLATE);
22
+ }
23
+ else {
24
+ await config.askWriteProjectFile(`${setup.functions.source}/package.json`, PACKAGE_NO_LINTING_TEMPLATE);
25
+ }
26
+ await config.askWriteProjectFile(`${setup.functions.source}/index.js`, INDEX_TEMPLATE);
27
+ await config.askWriteProjectFile(`${setup.functions.source}/.gitignore`, GITIGNORE_TEMPLATE);
28
+ await (0, npm_dependencies_1.askInstallDependencies)(setup.functions, config);
43
29
  }
44
30
  exports.setup = setup;
@@ -5,14 +5,10 @@ const logger_1 = require("../../../logger");
5
5
  const prompt_1 = require("../../../prompt");
6
6
  const spawn_1 = require("../../spawn");
7
7
  async function askInstallDependencies(setup, config) {
8
- await (0, prompt_1.prompt)(setup, [
9
- {
10
- name: "npm",
11
- type: "confirm",
12
- message: "Do you want to install dependencies with npm now?",
13
- default: true,
14
- },
15
- ]);
8
+ setup.npm = await (0, prompt_1.confirm)({
9
+ message: "Do you want to install dependencies with npm now?",
10
+ default: true,
11
+ });
16
12
  if (setup.npm) {
17
13
  try {
18
14
  await (0, spawn_1.wrapSpawn)("npm", ["install"], config.projectDir + `/${setup.source}`);
@@ -25,9 +25,7 @@ async function setup(setup, config) {
25
25
  venvProcess.on("exit", resolve);
26
26
  venvProcess.on("error", reject);
27
27
  });
28
- const install = await (0, prompt_1.promptOnce)({
29
- name: "install",
30
- type: "confirm",
28
+ const install = await (0, prompt_1.confirm)({
31
29
  message: "Do you want to install dependencies now?",
32
30
  default: true,
33
31
  });
@@ -12,48 +12,29 @@ const TSCONFIG_TEMPLATE = (0, templates_1.readTemplateSync)("init/functions/type
12
12
  const TSCONFIG_DEV_TEMPLATE = (0, templates_1.readTemplateSync)("init/functions/typescript/tsconfig.dev.json");
13
13
  const INDEX_TEMPLATE = (0, templates_1.readTemplateSync)("init/functions/typescript/index.ts");
14
14
  const GITIGNORE_TEMPLATE = (0, templates_1.readTemplateSync)("init/functions/typescript/_gitignore");
15
- function setup(setup, config) {
16
- return (0, prompt_1.prompt)(setup.functions, [
17
- {
18
- name: "lint",
19
- type: "confirm",
20
- message: "Do you want to use ESLint to catch probable bugs and enforce style?",
21
- default: true,
22
- },
23
- ])
24
- .then(() => {
25
- const cbconfig = (0, projectConfig_1.configForCodebase)(setup.config.functions, setup.functions.codebase);
26
- cbconfig.predeploy = [];
27
- if (setup.functions.lint) {
28
- cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run lint');
29
- cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run build');
30
- return config
31
- .askWriteProjectFile(`${setup.functions.source}/package.json`, PACKAGE_LINTING_TEMPLATE)
32
- .then(() => {
33
- return config.askWriteProjectFile(`${setup.functions.source}/.eslintrc.js`, ESLINT_TEMPLATE);
34
- });
35
- }
36
- else {
37
- cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run build');
38
- }
39
- return config.askWriteProjectFile(`${setup.functions.source}/package.json`, PACKAGE_NO_LINTING_TEMPLATE);
40
- })
41
- .then(() => {
42
- return config.askWriteProjectFile(`${setup.functions.source}/tsconfig.json`, TSCONFIG_TEMPLATE);
43
- })
44
- .then(() => {
45
- if (setup.functions.lint) {
46
- return config.askWriteProjectFile(`${setup.functions.source}/tsconfig.dev.json`, TSCONFIG_DEV_TEMPLATE);
47
- }
48
- })
49
- .then(() => {
50
- return config.askWriteProjectFile(`${setup.functions.source}/src/index.ts`, INDEX_TEMPLATE);
51
- })
52
- .then(() => {
53
- return config.askWriteProjectFile(`${setup.functions.source}/.gitignore`, GITIGNORE_TEMPLATE);
54
- })
55
- .then(() => {
56
- return (0, npm_dependencies_1.askInstallDependencies)(setup.functions, config);
57
- });
15
+ async function setup(setup, config) {
16
+ setup.functions.lint =
17
+ setup.functions.lint ||
18
+ (await (0, prompt_1.confirm)({
19
+ message: "Do you want to use ESLint to catch probable bugs and enforce style?",
20
+ default: true,
21
+ }));
22
+ const cbconfig = (0, projectConfig_1.configForCodebase)(setup.config.functions, setup.functions.codebase);
23
+ cbconfig.predeploy = [];
24
+ if (setup.functions.lint) {
25
+ cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run lint');
26
+ cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run build');
27
+ await config.askWriteProjectFile(`${setup.functions.source}/package.json`, PACKAGE_LINTING_TEMPLATE);
28
+ await config.askWriteProjectFile(`${setup.functions.source}/.eslintrc.js`, ESLINT_TEMPLATE);
29
+ await config.askWriteProjectFile(`${setup.functions.source}/tsconfig.dev.json`, TSCONFIG_DEV_TEMPLATE);
30
+ }
31
+ else {
32
+ cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run build');
33
+ await config.askWriteProjectFile(`${setup.functions.source}/package.json`, PACKAGE_NO_LINTING_TEMPLATE);
34
+ }
35
+ await config.askWriteProjectFile(`${setup.functions.source}/tsconfig.json`, TSCONFIG_TEMPLATE);
36
+ await config.askWriteProjectFile(`${setup.functions.source}/src/index.ts`, INDEX_TEMPLATE);
37
+ await config.askWriteProjectFile(`${setup.functions.source}/.gitignore`, GITIGNORE_TEMPLATE);
38
+ await (0, npm_dependencies_1.askInstallDependencies)(setup.functions, config);
58
39
  }
59
40
  exports.setup = setup;
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.promptWriteMode = exports.isPackageJson = exports.isTsConfig = exports.genkitSetup = exports.ensureVertexApiEnabled = exports.doSetup = void 0;
4
4
  const fs = require("fs");
5
- const inquirer = require("inquirer");
6
5
  const path = require("path");
7
6
  const semver = require("semver");
8
7
  const clc = require("colorette");
@@ -115,17 +114,13 @@ async function doSetup(setup, config, options) {
115
114
  throw new error_1.FirebaseError("Failed to initialize Genkit prerequisite: Firebase functions");
116
115
  }
117
116
  const projectDir = `${config.projectDir}/${setup.functions.source}`;
118
- const installType = (await inquirer.prompt([
119
- {
120
- name: "choice",
121
- type: "list",
122
- message: "Install the Genkit CLI globally or locally in this project?",
123
- choices: [
124
- { name: "Globally", value: "globally" },
125
- { name: "Just this project", value: "project" },
126
- ],
127
- },
128
- ])).choice;
117
+ const installType = await (0, prompt_1.select)({
118
+ message: "Install the Genkit CLI globally or locally in this project?",
119
+ choices: [
120
+ { name: "Globally", value: "globally" },
121
+ { name: "Just this project", value: "project" },
122
+ ],
123
+ });
129
124
  try {
130
125
  (0, utils_1.logLabeledBullet)("genkit", `Installing Genkit CLI version ${genkitInfo.cliVersion}`);
131
126
  if (installType === "globally") {
@@ -214,18 +209,13 @@ async function genkitSetup(options, genkitInfo, projectDir) {
214
209
  var _a, _b;
215
210
  const modelOptions = getModelOptions(genkitInfo);
216
211
  const supportedModels = Object.keys(modelOptions);
217
- const answer = await inquirer.prompt([
218
- {
219
- type: "list",
220
- name: "model",
221
- message: "Select a model provider:",
222
- choices: supportedModels.map((model) => ({
223
- name: modelOptions[model].label,
224
- value: model,
225
- })),
226
- },
227
- ]);
228
- const model = answer.model;
212
+ const model = await (0, prompt_1.select)({
213
+ message: "Select a model provider:",
214
+ choices: supportedModels.map((model) => ({
215
+ name: modelOptions[model].label,
216
+ value: model,
217
+ })),
218
+ });
229
219
  if (model === "vertexai") {
230
220
  await ensureVertexApiEnabled(options);
231
221
  }
@@ -419,19 +409,14 @@ function generateImportStatement(imports, name) {
419
409
  return `import {${imports}} from "${name}";`;
420
410
  }
421
411
  async function promptWriteMode(message, defaultOption = "merge") {
422
- const answer = await inquirer.prompt([
423
- {
424
- type: "list",
425
- name: "option",
426
- message,
427
- choices: [
428
- { name: "Set if unset", value: "merge" },
429
- { name: "Overwrite", value: "overwrite" },
430
- { name: "Keep unchanged", value: "keep" },
431
- ],
432
- default: defaultOption,
433
- },
434
- ]);
435
- return answer.option;
412
+ return (0, prompt_1.select)({
413
+ message,
414
+ choices: [
415
+ { name: "Set if unset", value: "merge" },
416
+ { name: "Overwrite", value: "overwrite" },
417
+ { name: "Keep unchanged", value: "keep" },
418
+ ],
419
+ default: defaultOption,
420
+ });
436
421
  }
437
422
  exports.promptWriteMode = promptWriteMode;
@@ -75,7 +75,7 @@ async function initGitHub(setup) {
75
75
  let shouldWriteYMLHostingFile = true;
76
76
  let shouldWriteYMLDeployFile = false;
77
77
  if (fs.existsSync(YML_FULL_PATH_PULL_REQUEST)) {
78
- const { overwrite } = await promptForWriteYMLFile({
78
+ const overwrite = await (0, prompt_1.confirm)({
79
79
  message: `GitHub workflow file for PR previews exists. Overwrite? ${YML_PULL_REQUEST_FILENAME}`,
80
80
  });
81
81
  shouldWriteYMLHostingFile = overwrite;
@@ -92,10 +92,9 @@ async function initGitHub(setup) {
92
92
  shouldWriteYMLDeployFile = true;
93
93
  }
94
94
  else {
95
- const { overwrite } = await promptForWriteYMLFile({
95
+ shouldWriteYMLDeployFile = await (0, prompt_1.confirm)({
96
96
  message: `The GitHub workflow file for deploying to the live channel already exists. Overwrite? ${YML_MERGE_FILENAME}`,
97
97
  });
98
- shouldWriteYMLDeployFile = overwrite;
99
98
  }
100
99
  }
101
100
  else {
@@ -260,10 +259,8 @@ async function uploadSecretToGitHub(repo, ghAccessToken, encryptedServiceAccount
260
259
  async function promptForRepo(options, ghAccessToken) {
261
260
  let key = "";
262
261
  let keyId = "";
263
- const { repo } = await (0, prompt_1.prompt)(options, [
264
- {
265
- type: "input",
266
- name: "repo",
262
+ const { repo } = options.repo ||
263
+ (await (0, prompt_1.input)({
267
264
  default: defaultGithubRepo(),
268
265
  message: "For which GitHub repository would you like to set up a GitHub workflow? (format: user/repository)",
269
266
  validate: async (repo) => {
@@ -289,64 +286,36 @@ async function promptForRepo(options, ghAccessToken) {
289
286
  }
290
287
  return true;
291
288
  },
292
- },
293
- ]);
289
+ }));
294
290
  return { repo, key, keyId };
295
291
  }
296
292
  async function promptForBuildScript(useWebFrameworks) {
297
- const { shouldSetupScript } = await (0, prompt_1.prompt)({}, [
298
- {
299
- type: "confirm",
300
- name: "shouldSetupScript",
301
- default: false,
302
- message: "Set up the workflow to run a build script before every deploy?",
303
- },
304
- ]);
293
+ const shouldSetupScript = await (0, prompt_1.confirm)({
294
+ message: "Set up the workflow to run a build script before every deploy?",
295
+ });
305
296
  if (!shouldSetupScript) {
306
297
  return { script: undefined };
307
298
  }
308
- const { script } = await (0, prompt_1.prompt)({}, [
309
- {
310
- type: "input",
311
- name: "script",
312
- default: useWebFrameworks ? undefined : "npm ci && npm run build",
313
- message: "What script should be run before every deploy?",
314
- },
315
- ]);
299
+ const script = await (0, prompt_1.input)({
300
+ default: useWebFrameworks ? undefined : "npm ci && npm run build",
301
+ message: "What script should be run before every deploy?",
302
+ });
316
303
  return { script };
317
304
  }
318
305
  async function promptToSetupDeploys(defaultBranch) {
319
- const { setupDeploys } = await (0, prompt_1.prompt)({}, [
320
- {
321
- type: "confirm",
322
- name: "setupDeploys",
323
- default: true,
324
- message: "Set up automatic deployment to your site's live channel when a PR is merged?",
325
- },
326
- ]);
306
+ const setupDeploys = await (0, prompt_1.confirm)({
307
+ default: true,
308
+ message: "Set up automatic deployment to your site's live channel when a PR is merged?",
309
+ });
327
310
  if (!setupDeploys) {
328
311
  return { setupDeploys };
329
312
  }
330
- const { branch } = await (0, prompt_1.prompt)({}, [
331
- {
332
- type: "input",
333
- name: "branch",
334
- default: defaultBranch,
335
- message: "What is the name of the GitHub branch associated with your site's live channel?",
336
- },
337
- ]);
313
+ const branch = await (0, prompt_1.input)({
314
+ default: defaultBranch,
315
+ message: "What is the name of the GitHub branch associated with your site's live channel?",
316
+ });
338
317
  return { branch, setupDeploys };
339
318
  }
340
- async function promptForWriteYMLFile({ message }) {
341
- return await (0, prompt_1.prompt)({}, [
342
- {
343
- type: "confirm",
344
- name: "overwrite",
345
- default: false,
346
- message,
347
- },
348
- ]);
349
- }
350
319
  async function getGitHubUserDetails(ghAccessToken) {
351
320
  const { body: ghUserDetails } = await githubApiClient.get("/user", {
352
321
  headers: { Authorization: `token ${ghAccessToken}`, "User-Agent": "Firebase CLI" },
@@ -33,8 +33,7 @@ async function doSetup(setup, config, options) {
33
33
  hasHostingSite = false;
34
34
  }
35
35
  if (!hasHostingSite) {
36
- const confirmCreate = await (0, prompt_1.promptOnce)({
37
- type: "confirm",
36
+ const confirmCreate = await (0, prompt_1.confirm)({
38
37
  message: "A Firebase Hosting site is required to deploy. Would you like to create one now?",
39
38
  default: true,
40
39
  });
@@ -56,44 +55,33 @@ async function doSetup(setup, config, options) {
56
55
  if (experiments.isEnabled("webframeworks")) {
57
56
  if (discoveredFramework) {
58
57
  const name = frameworks_1.WebFrameworks[discoveredFramework.framework].name;
59
- await (0, prompt_1.promptOnce)({
60
- name: "useDiscoveredFramework",
61
- type: "confirm",
62
- default: true,
58
+ setup.hosting.useDiscoveredFramework = await (0, prompt_1.confirm)({
63
59
  message: `Detected an existing ${name} codebase in the current directory, should we use this?`,
64
- }, setup.hosting);
60
+ default: true,
61
+ });
65
62
  }
66
63
  if (setup.hosting.useDiscoveredFramework) {
67
64
  setup.hosting.source = ".";
68
65
  setup.hosting.useWebFrameworks = true;
69
66
  }
70
67
  else {
71
- await (0, prompt_1.promptOnce)({
72
- name: "useWebFrameworks",
73
- type: "confirm",
74
- default: false,
75
- message: `Do you want to use a web framework? (${clc.bold("experimental")})`,
76
- }, setup.hosting);
68
+ setup.hosting.useWebFrameworks = await (0, prompt_1.confirm)(`Do you want to use a web framework? (${clc.bold("experimental")})`);
77
69
  }
78
70
  }
79
71
  if (setup.hosting.useWebFrameworks) {
80
- await (0, prompt_1.promptOnce)({
81
- name: "source",
82
- type: "input",
83
- default: "hosting",
72
+ setup.hosting.source = await (0, prompt_1.input)({
84
73
  message: "What folder would you like to use for your web application's root directory?",
85
- }, setup.hosting);
74
+ default: "hosting",
75
+ });
86
76
  if (setup.hosting.source !== ".")
87
77
  delete setup.hosting.useDiscoveredFramework;
88
78
  discoveredFramework = await (0, frameworks_1.discover)((0, path_1.join)(config.projectDir, setup.hosting.source));
89
79
  if (discoveredFramework) {
90
80
  const name = frameworks_1.WebFrameworks[discoveredFramework.framework].name;
91
- await (0, prompt_1.promptOnce)({
92
- name: "useDiscoveredFramework",
93
- type: "confirm",
94
- default: true,
81
+ setup.hosting.useDiscoveredFramework = await (0, prompt_1.confirm)({
95
82
  message: `Detected an existing ${name} codebase in ${setup.hosting.source}, should we use this?`,
96
- }, setup.hosting);
83
+ default: true,
84
+ });
97
85
  }
98
86
  if (setup.hosting.useDiscoveredFramework && discoveredFramework) {
99
87
  setup.hosting.webFramework = discoveredFramework.framework;
@@ -108,24 +96,24 @@ async function doSetup(setup, config, options) {
108
96
  }
109
97
  }
110
98
  const defaultChoice = (_a = choices.find(({ value }) => value === (discoveredFramework === null || discoveredFramework === void 0 ? void 0 : discoveredFramework.framework))) === null || _a === void 0 ? void 0 : _a.value;
111
- await (0, prompt_1.promptOnce)({
112
- name: "whichFramework",
113
- type: "list",
114
- message: "Please choose the framework:",
115
- default: defaultChoice,
116
- choices,
117
- }, setup.hosting);
99
+ setup.hosting.whichFramework =
100
+ setup.hosting.whichFramework ||
101
+ (await (0, prompt_1.select)({
102
+ message: "Please choose the framework:",
103
+ default: defaultChoice,
104
+ choices,
105
+ }));
118
106
  if (discoveredFramework)
119
107
  (0, node_fs_1.rmSync)(setup.hosting.source, { recursive: true });
120
108
  await frameworks_1.WebFrameworks[setup.hosting.whichFramework].init(setup, config);
121
109
  }
122
- await (0, prompt_1.promptOnce)({
123
- name: "region",
124
- type: "list",
125
- message: "In which region would you like to host server-side content, if applicable?",
126
- default: constants_1.DEFAULT_REGION,
127
- choices: constants_1.ALLOWED_SSR_REGIONS.filter((region) => region.recommended),
128
- }, setup.hosting);
110
+ setup.hosting.region =
111
+ setup.hosting.region ||
112
+ (await (0, prompt_1.select)({
113
+ message: "In which region would you like to host server-side content, if applicable?",
114
+ default: constants_1.DEFAULT_REGION,
115
+ choices: constants_1.ALLOWED_SSR_REGIONS.filter((region) => region.recommended),
116
+ }));
129
117
  setup.config.hosting = {
130
118
  source: setup.hosting.source,
131
119
  ignore: DEFAULT_IGNORES,
@@ -140,31 +128,22 @@ async function doSetup(setup, config, options) {
140
128
  logger_1.logger.info(`will contain Hosting assets to be uploaded with ${clc.bold("firebase deploy")}. If you`);
141
129
  logger_1.logger.info("have a build process for your assets, use your build's output directory.");
142
130
  logger_1.logger.info();
143
- await (0, prompt_1.prompt)(setup.hosting, [
144
- {
145
- name: "public",
146
- type: "input",
147
- default: "public",
148
- message: "What do you want to use as your public directory?",
149
- },
150
- {
151
- name: "spa",
152
- type: "confirm",
153
- default: false,
154
- message: "Configure as a single-page app (rewrite all urls to /index.html)?",
155
- },
156
- ]);
131
+ setup.hosting.public =
132
+ setup.hosting.public ||
133
+ (await (0, prompt_1.input)({
134
+ message: "What do you want to use as your public directory?",
135
+ default: "public",
136
+ }));
137
+ setup.hosting.spa =
138
+ setup.hosting.spa ||
139
+ (await (0, prompt_1.confirm)("Configure as a single-page app (rewrite all urls to /index.html)?"));
157
140
  setup.config.hosting = {
158
141
  public: setup.hosting.public,
159
142
  ignore: DEFAULT_IGNORES,
160
143
  };
161
144
  }
162
- await (0, prompt_1.promptOnce)({
163
- name: "github",
164
- type: "confirm",
165
- default: false,
166
- message: "Set up automatic builds and deploys with GitHub?",
167
- }, setup.hosting);
145
+ setup.hosting.github =
146
+ setup.hosting.github || (await (0, prompt_1.confirm)("Set up automatic builds and deploys with GitHub?"));
168
147
  if (!setup.hosting.useWebFrameworks) {
169
148
  if (setup.hosting.spa) {
170
149
  setup.config.hosting.rewrites = [{ source: "**", destination: "/index.html" }];
@@ -6,8 +6,8 @@ const _ = require("lodash");
6
6
  const error_1 = require("../../error");
7
7
  const projects_1 = require("../../management/projects");
8
8
  const logger_1 = require("../../logger");
9
- const prompt_1 = require("../../prompt");
10
9
  const utils = require("../../utils");
10
+ const prompt = require("../../prompt");
11
11
  const OPTION_NO_PROJECT = "Don't set up a default project";
12
12
  const OPTION_USE_PROJECT = "Use an existing project";
13
13
  const OPTION_NEW_PROJECT = "Create a new project";
@@ -24,14 +24,11 @@ function toInitProjectInfo(projectMetaData) {
24
24
  async function promptAndCreateNewProject() {
25
25
  utils.logBullet("If you want to create a project in a Google Cloud organization or folder, please use " +
26
26
  `"firebase projects:create" instead, and return to this command when you've created the project.`);
27
- const promptAnswer = {};
28
- await (0, prompt_1.prompt)(promptAnswer, projects_1.PROJECTS_CREATE_QUESTIONS);
29
- if (!promptAnswer.projectId) {
27
+ const { projectId, displayName } = await (0, projects_1.promptProjectCreation)();
28
+ if (!projectId) {
30
29
  throw new error_1.FirebaseError("Project ID cannot be empty");
31
30
  }
32
- return await (0, projects_1.createFirebaseProjectAndLog)(promptAnswer.projectId, {
33
- displayName: promptAnswer.displayName,
34
- });
31
+ return await (0, projects_1.createFirebaseProjectAndLog)(projectId, { displayName });
35
32
  }
36
33
  async function promptAndAddFirebaseToCloudProject() {
37
34
  const projectId = await (0, projects_1.promptAvailableProjectId)();
@@ -41,15 +38,8 @@ async function promptAndAddFirebaseToCloudProject() {
41
38
  return await (0, projects_1.addFirebaseToCloudProjectAndLog)(projectId);
42
39
  }
43
40
  async function projectChoicePrompt(options) {
44
- const choices = [
45
- { name: OPTION_USE_PROJECT, value: OPTION_USE_PROJECT },
46
- { name: OPTION_NEW_PROJECT, value: OPTION_NEW_PROJECT },
47
- { name: OPTION_ADD_FIREBASE, value: OPTION_ADD_FIREBASE },
48
- { name: OPTION_NO_PROJECT, value: OPTION_NO_PROJECT },
49
- ];
50
- const projectSetupOption = await (0, prompt_1.promptOnce)({
51
- type: "list",
52
- name: "id",
41
+ const choices = [OPTION_USE_PROJECT, OPTION_NEW_PROJECT, OPTION_ADD_FIREBASE, OPTION_NO_PROJECT];
42
+ const projectSetupOption = await prompt.select({
53
43
  message: "Please select an option:",
54
44
  choices,
55
45
  });
@@ -6,9 +6,7 @@ const fsutils = require("../../fsutils");
6
6
  const clc = require("colorette");
7
7
  async function doSetup(setup, config) {
8
8
  setup.config.remoteconfig = {};
9
- const jsonFilePath = await (0, prompt_1.promptOnce)({
10
- type: "input",
11
- name: "template",
9
+ const jsonFilePath = await (0, prompt_1.input)({
12
10
  message: "What file should be used for your Remote Config template?",
13
11
  default: "remoteconfig.template.json",
14
12
  });
@@ -17,11 +15,7 @@ async function doSetup(setup, config) {
17
15
  clc.bold(jsonFilePath) +
18
16
  " already exists." +
19
17
  " Do you want to overwrite the existing Remote Config template?";
20
- const overwrite = await (0, prompt_1.promptOnce)({
21
- type: "confirm",
22
- message: msg,
23
- default: false,
24
- });
18
+ const overwrite = await (0, prompt_1.confirm)(msg);
25
19
  if (!overwrite) {
26
20
  return;
27
21
  }