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
@@ -42,13 +42,13 @@ async function ensureValidKey(key, options) {
42
42
  throw new error_1.FirebaseError("Secret key must be in UPPER_SNAKE_CASE.");
43
43
  }
44
44
  (0, utils_1.logWarning)(`By convention, secret key must be in UPPER_SNAKE_CASE.`);
45
- const confirm = await (0, prompt_1.promptOnce)({
46
- name: "updateKey",
47
- type: "confirm",
45
+ const useTransformed = await (0, prompt_1.confirm)({
48
46
  default: true,
49
47
  message: `Would you like to use ${transformedKey} as key instead?`,
50
- }, options);
51
- if (!confirm) {
48
+ nonInteractive: options.nonInteractive,
49
+ force: options.force,
50
+ });
51
+ if (!useTransformed) {
52
52
  throw new error_1.FirebaseError("Secret key must be in UPPER_SNAKE_CASE.");
53
53
  }
54
54
  }
@@ -66,12 +66,11 @@ async function ensureSecret(projectId, name, options) {
66
66
  const secret = await (0, secretManager_1.getSecret)(projectId, name);
67
67
  if ((0, secretManager_1.isAppHostingManaged)(secret)) {
68
68
  (0, utils_1.logWarning)("Your secret is managed by Firebase App Hosting. Continuing will disable automatic deletion of old versions.");
69
- const stopTracking = await (0, prompt_1.promptOnce)({
70
- name: "doNotTrack",
71
- type: "confirm",
72
- default: false,
69
+ const stopTracking = await (0, prompt_1.confirm)({
73
70
  message: "Do you wish to continue?",
74
- }, options);
71
+ nonInteractive: options.nonInteractive,
72
+ force: options.force,
73
+ });
75
74
  if (stopTracking) {
76
75
  delete secret.labels[secretManager_2.FIREBASE_MANAGED];
77
76
  await (0, secretManager_1.patchSecret)(secret.projectId, secret.name, secret.labels);
@@ -84,13 +83,13 @@ async function ensureSecret(projectId, name, options) {
84
83
  if (!options.force) {
85
84
  (0, utils_1.logWarning)("Your secret is not managed by Cloud Functions for Firebase. " +
86
85
  "Firebase managed secrets are automatically pruned to reduce your monthly cost for using Secret Manager. ");
87
- const confirm = await (0, prompt_1.promptOnce)({
88
- name: "updateLabels",
89
- type: "confirm",
86
+ const updateLabels = await (0, prompt_1.confirm)({
90
87
  default: true,
91
88
  message: `Would you like to have your secret ${secret.name} managed by Cloud Functions for Firebase?`,
92
- }, options);
93
- if (confirm) {
89
+ nonInteractive: options.nonInteractive,
90
+ force: options.force,
91
+ });
92
+ if (updateLabels) {
94
93
  return (0, secretManager_1.patchSecret)(projectId, secret.name, Object.assign(Object.assign({}, secret.labels), (0, secretManager_3.labels)()));
95
94
  }
96
95
  }
package/lib/gcp/auth.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setCustomClaim = exports.disableUser = exports.findUser = exports.updateAuthDomains = exports.getAuthDomains = void 0;
3
+ exports.setDenySmsRegionPolicy = exports.setAllowSmsRegionPolicy = exports.setCustomClaim = exports.disableUser = exports.findUser = exports.updateAuthDomains = exports.getAuthDomains = void 0;
4
4
  const apiv2_1 = require("../apiv2");
5
5
  const api_1 = require("../api");
6
6
  const apiClient = new apiv2_1.Client({ urlPrefix: (0, api_1.identityOrigin)(), auth: true });
@@ -72,3 +72,31 @@ async function setCustomClaim(project, uid, claim, options) {
72
72
  return user;
73
73
  }
74
74
  exports.setCustomClaim = setCustomClaim;
75
+ async function setAllowSmsRegionPolicy(project, countryCodes) {
76
+ const res = await apiClient.patch(`/admin/v2/projects/${project}/config?updateMask=sms_region_config`, {
77
+ sms_region_config: {
78
+ allowlist_only: {
79
+ allowed_regions: countryCodes,
80
+ },
81
+ },
82
+ });
83
+ if (res.status !== 200) {
84
+ throw new Error("SMS Region Policy failed to be configured");
85
+ }
86
+ return true;
87
+ }
88
+ exports.setAllowSmsRegionPolicy = setAllowSmsRegionPolicy;
89
+ async function setDenySmsRegionPolicy(project, countryCodes) {
90
+ const res = await apiClient.patch(`/admin/v2/projects/${project}/config?updateMask=sms_region_config`, {
91
+ sms_region_config: {
92
+ allow_by_default: {
93
+ disallowed_regions: countryCodes,
94
+ },
95
+ },
96
+ });
97
+ if (res.status !== 200) {
98
+ throw new Error("SMS Region Policy failed to be configured");
99
+ }
100
+ return true;
101
+ }
102
+ exports.setDenySmsRegionPolicy = setDenySmsRegionPolicy;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateOperation = exports.chatWithFirebase = exports.generateSchema = void 0;
4
+ const apiv2_1 = require("../apiv2");
5
+ const api_1 = require("../api");
6
+ const apiClient = new apiv2_1.Client({ urlPrefix: (0, api_1.cloudCompanionOrigin)(), auth: true });
7
+ const schemaGeneratorExperience = "/appeco/firebase/fdc-schema-generator";
8
+ const geminiInFirebaseChatExperience = "/appeco/firebase/firebase-chat/free";
9
+ const operationGeneratorExperience = "/appeco/firebase/fdc-query-generator";
10
+ async function generateSchema(prompt, project) {
11
+ const res = await apiClient.post(`/v1beta/projects/${project}/locations/global/instances/default:completeTask`, {
12
+ input: { messages: [{ content: prompt, author: "USER" }] },
13
+ experienceContext: {
14
+ experience: schemaGeneratorExperience,
15
+ },
16
+ });
17
+ return res.body.output.messages[0].content;
18
+ }
19
+ exports.generateSchema = generateSchema;
20
+ async function chatWithFirebase(prompt, project) {
21
+ const res = await apiClient.post(`/v1beta/projects/${project}/locations/global/instances/default:completeTask`, {
22
+ input: { messages: [{ content: prompt, author: "USER" }] },
23
+ experienceContext: {
24
+ experience: geminiInFirebaseChatExperience,
25
+ },
26
+ });
27
+ return res.body;
28
+ }
29
+ exports.chatWithFirebase = chatWithFirebase;
30
+ async function generateOperation(prompt, service, project) {
31
+ const res = await apiClient.post(`/v1beta/projects/${project}/locations/global/instances/default:completeTask`, {
32
+ input: { messages: [{ content: prompt, author: "USER" }] },
33
+ experienceContext: {
34
+ experience: operationGeneratorExperience,
35
+ },
36
+ clientContext: {
37
+ additionalContext: {
38
+ "@type": "type.googleapis.com/google.cloud.cloudaicompanion.v1main.FirebaseChatRequestContext",
39
+ fdcInfo: { fdcServiceName: service, requiresQuery: true },
40
+ },
41
+ },
42
+ });
43
+ return res.body.output.messages[0].content;
44
+ }
45
+ exports.generateOperation = generateOperation;
@@ -4,8 +4,8 @@ exports.interactiveCreateHostingSite = void 0;
4
4
  const error_1 = require("../error");
5
5
  const utils_1 = require("../utils");
6
6
  const projectUtils_1 = require("../projectUtils");
7
- const prompt_1 = require("../prompt");
8
7
  const api_1 = require("./api");
8
+ const prompt_1 = require("../prompt");
9
9
  const nameSuggestion = new RegExp("try something like `(.+)`");
10
10
  const prompt = "Please provide an unique, URL-friendly id for your site. Your site's URL will be <site-id>.web.app. " +
11
11
  'We recommend using letters, numbers, and hyphens (e.g. "{project-id}-{random-hash}"):';
@@ -26,8 +26,7 @@ async function interactiveCreateHostingSite(siteId, appId, options) {
26
26
  }
27
27
  while (!newSite) {
28
28
  if (!id || suggestion) {
29
- id = await (0, prompt_1.promptOnce)({
30
- type: "input",
29
+ id = await (0, prompt_1.input)({
31
30
  message: prompt,
32
31
  validate: (s) => s.length > 0,
33
32
  default: suggestion,
@@ -4,8 +4,8 @@ exports.doSetup = void 0;
4
4
  const logger_1 = require("../../logger");
5
5
  const utils = require("../../utils");
6
6
  const auth_1 = require("../../auth");
7
- const prompt_1 = require("../../prompt");
8
7
  const error_1 = require("../../error");
8
+ const prompt_1 = require("../../prompt");
9
9
  async function promptForAccount() {
10
10
  logger_1.logger.info();
11
11
  logger_1.logger.info(`Which account do you want to use for this project? Choose an account or add a new one now`);
@@ -21,9 +21,7 @@ async function promptForAccount() {
21
21
  name: "(add a new account)",
22
22
  value: "__add__",
23
23
  });
24
- const emailChoice = await (0, prompt_1.promptOnce)({
25
- type: "list",
26
- name: "email",
24
+ const emailChoice = await (0, prompt_1.select)({
27
25
  message: "Please select an option:",
28
26
  choices,
29
27
  });
@@ -37,8 +37,7 @@ function writeDBRules(rules, logMessagePrefix, filename, config) {
37
37
  logger_1.logger.info(clc.bold("firebase deploy") + ".");
38
38
  }
39
39
  async function createDefaultDatabaseInstance(project) {
40
- const selectedLocation = await (0, prompt_1.promptOnce)({
41
- type: "list",
40
+ const selectedLocation = await (0, prompt_1.select)({
42
41
  message: "Please choose the location for your default Realtime Database instance:",
43
42
  choices: [
44
43
  { name: "us-central1", value: database_1.DatabaseLocation.US_CENTRAL1 },
@@ -79,13 +78,11 @@ async function doSetup(setup, config) {
79
78
  instanceDetails = await (0, database_1.getDatabaseInstanceDetails)(setup.projectId, setup.instance);
80
79
  }
81
80
  else {
82
- const confirm = await (0, prompt_1.promptOnce)({
83
- type: "confirm",
84
- name: "confirm",
85
- default: true,
81
+ const createDefault = await (0, prompt_1.confirm)({
86
82
  message: "It seems like you haven’t initialized Realtime Database in your project yet. Do you want to set it up?",
83
+ default: true,
87
84
  });
88
- if (confirm) {
85
+ if (createDefault) {
89
86
  instanceDetails = await createDefaultDatabaseInstance(setup.projectId);
90
87
  }
91
88
  }
@@ -95,14 +92,12 @@ async function doSetup(setup, config) {
95
92
  logger_1.logger.info("Firebase Realtime Database Security Rules allow you to define how your data should be");
96
93
  logger_1.logger.info("structured and when your data can be read from and written to.");
97
94
  logger_1.logger.info();
98
- await (0, prompt_1.prompt)(setup.config.database, [
99
- {
100
- type: "input",
101
- name: "rules",
102
- message: "What file should be used for Realtime Database Security Rules?",
103
- default: "database.rules.json",
104
- },
105
- ]);
95
+ setup.config.database.rules =
96
+ setup.config.database.rules ||
97
+ (await (0, prompt_1.input)({
98
+ message: "What file should be used for Realtime Database Security Rules?",
99
+ default: "database.rules.json",
100
+ }));
106
101
  const filename = setup.config.database.rules;
107
102
  if (!filename) {
108
103
  throw new error_1.FirebaseError("Must specify location for Realtime Database rules file.");
@@ -113,11 +108,7 @@ async function doSetup(setup, config) {
113
108
  ? `the Realtime Database Security Rules for ${clc.bold(instanceDetails.name)} from the Firebase console`
114
109
  : "default rules";
115
110
  const msg = `File ${clc.bold(filename)} already exists. Do you want to overwrite it with ${rulesDescription}?`;
116
- writeRules = await (0, prompt_1.promptOnce)({
117
- type: "confirm",
118
- message: msg,
119
- default: false,
120
- });
111
+ writeRules = await (0, prompt_1.confirm)(msg);
121
112
  }
122
113
  if (writeRules) {
123
114
  if (instanceDetails) {
@@ -211,9 +211,8 @@ async function promptForExistingServices(setup, info, isBillingEnabled) {
211
211
  };
212
212
  });
213
213
  choices.push({ name: "Create a new service", value: undefined });
214
- choice = await (0, prompt_1.promptOnce)({
214
+ choice = await (0, prompt_1.select)({
215
215
  message: "Your project already has existing services. Which would you like to set up local files for?",
216
- type: "list",
217
216
  choices,
218
217
  });
219
218
  }
@@ -271,9 +270,8 @@ async function promptForCloudSQL(setup, info) {
271
270
  else {
272
271
  choices.push({ name: "Create a new CloudSQL instance", value: "", location: "" });
273
272
  }
274
- info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
273
+ info.cloudSqlInstanceId = await (0, prompt_1.select)({
275
274
  message: `Which CloudSQL instance would you like to use?`,
276
- type: "list",
277
275
  choices,
278
276
  });
279
277
  if (info.cloudSqlInstanceId !== "") {
@@ -283,17 +281,15 @@ async function promptForCloudSQL(setup, info) {
283
281
  }
284
282
  if (info.cloudSqlInstanceId === "") {
285
283
  info.isNewInstance = true;
286
- info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({
284
+ info.cloudSqlInstanceId = await (0, prompt_1.input)({
287
285
  message: `What ID would you like to use for your new CloudSQL instance?`,
288
- type: "input",
289
286
  default: `${info.serviceId.toLowerCase() || "app"}-fdc`,
290
287
  });
291
288
  }
292
289
  if (info.locationId === "") {
293
290
  const choices = await locationChoices(setup);
294
- info.locationId = await (0, prompt_1.promptOnce)({
291
+ info.locationId = await (0, prompt_1.select)({
295
292
  message: "What location would like to use?",
296
- type: "list",
297
293
  choices,
298
294
  });
299
295
  }
@@ -305,9 +301,8 @@ async function promptForCloudSQL(setup, info) {
305
301
  });
306
302
  choices.push({ name: "Create a new database", value: "" });
307
303
  if (dbs.length) {
308
- info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
304
+ info.cloudSqlDatabase = await (0, prompt_1.select)({
309
305
  message: `Which database in ${info.cloudSqlInstanceId} would you like to use?`,
310
- type: "list",
311
306
  choices,
312
307
  });
313
308
  }
@@ -318,9 +313,8 @@ async function promptForCloudSQL(setup, info) {
318
313
  }
319
314
  if (info.cloudSqlDatabase === "") {
320
315
  info.isNewDatabase = true;
321
- info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({
316
+ info.cloudSqlDatabase = await (0, prompt_1.input)({
322
317
  message: `What ID would you like to use for your new database in ${info.cloudSqlInstanceId}?`,
323
- type: "input",
324
318
  default: `fdcdb`,
325
319
  });
326
320
  }
@@ -328,9 +322,8 @@ async function promptForCloudSQL(setup, info) {
328
322
  }
329
323
  async function promptForService(info) {
330
324
  if (info.serviceId === "") {
331
- info.serviceId = await (0, prompt_1.promptOnce)({
325
+ info.serviceId = await (0, prompt_1.input)({
332
326
  message: "What ID would you like to use for this service?",
333
- type: "input",
334
327
  default: (0, path_1.basename)(process.cwd()),
335
328
  });
336
329
  }
@@ -41,7 +41,7 @@ async function askQuestions(setup, config) {
41
41
  let appDir = process.env[exports.FDC_APP_FOLDER] || process.cwd();
42
42
  let targetPlatform = await (0, fileUtils_1.getPlatformFromFolder)(appDir);
43
43
  if (targetPlatform === types_1.Platform.NONE && !((_a = process.env[exports.FDC_APP_FOLDER]) === null || _a === void 0 ? void 0 : _a.length)) {
44
- appDir = await (0, prompt_1.promptForDirectory)({
44
+ appDir = await (0, utils_1.promptForDirectory)({
45
45
  config,
46
46
  message: "Where is your app directory? Leave blank to set up a generated SDK in your current directory.",
47
47
  });
@@ -60,18 +60,16 @@ async function askQuestions(setup, config) {
60
60
  { name: "Android (Kotlin)", value: types_1.Platform.ANDROID },
61
61
  { name: "Flutter (Dart)", value: types_1.Platform.FLUTTER },
62
62
  ];
63
- targetPlatform = await (0, prompt_1.promptOnce)({
63
+ targetPlatform = await (0, prompt_1.select)({
64
64
  message: "Which platform do you want to set up a generated SDK for?",
65
- type: "list",
66
65
  choices: platforms,
67
66
  });
68
67
  }
69
68
  else {
70
69
  (0, utils_1.logSuccess)(`Detected ${targetPlatform} app in directory ${appDir}`);
71
70
  }
72
- const connectorInfo = await (0, prompt_1.promptOnce)({
71
+ const connectorInfo = await (0, prompt_1.select)({
73
72
  message: "Which connector do you want set up a generated SDK for?",
74
- type: "list",
75
73
  choices: connectorChoices,
76
74
  });
77
75
  const connectorYaml = JSON.parse(JSON.stringify(connectorInfo.connectorYaml));
@@ -79,23 +77,18 @@ async function askQuestions(setup, config) {
79
77
  if (targetPlatform === types_1.Platform.WEB) {
80
78
  const unusedFrameworks = fileUtils_1.SUPPORTED_FRAMEWORKS.filter((framework) => { var _a; return !((_a = newConnectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk[framework]); });
81
79
  if (unusedFrameworks.length > 0) {
82
- const additionalFrameworks = await (0, prompt_1.prompt)(setup, [
83
- {
84
- type: "checkbox",
85
- name: "fdcFrameworks",
86
- message: `Which frameworks would you like to generate SDKs for? ` +
87
- "Press Space to select features, then Enter to confirm your choices.",
88
- choices: fileUtils_1.SUPPORTED_FRAMEWORKS.map((frameworkStr) => {
89
- var _a, _b;
90
- return ({
91
- value: frameworkStr,
92
- name: frameworkStr,
93
- checked: (_b = (_a = newConnectorYaml === null || newConnectorYaml === void 0 ? void 0 : newConnectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk) === null || _b === void 0 ? void 0 : _b[frameworkStr],
94
- });
95
- }),
96
- },
97
- ]);
98
- for (const framework of additionalFrameworks.fdcFrameworks) {
80
+ const additionalFrameworks = await (0, prompt_1.checkbox)({
81
+ message: "Which frameworks would you like to generate SDKs for? " +
82
+ "Press Space to select features, then Enter to confirm your choices.",
83
+ choices: fileUtils_1.SUPPORTED_FRAMEWORKS.map((frameworkStr) => {
84
+ var _a, _b;
85
+ return ({
86
+ value: frameworkStr,
87
+ checked: (_b = (_a = newConnectorYaml === null || newConnectorYaml === void 0 ? void 0 : newConnectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk) === null || _b === void 0 ? void 0 : _b[frameworkStr],
88
+ });
89
+ }),
90
+ });
91
+ for (const framework of additionalFrameworks) {
99
92
  newConnectorYaml.generate.javascriptSdk[framework] = true;
100
93
  }
101
94
  }
@@ -14,19 +14,15 @@ async function doSetup(setup, config) {
14
14
  return {
15
15
  value: e,
16
16
  name: constants_1.Constants.description(e),
17
- checked: config && (config.has(e) || config.has(`emulators.${e}`)),
17
+ checked: (config === null || config === void 0 ? void 0 : config.has(e)) || (config === null || config === void 0 ? void 0 : config.has(`emulators.${e}`)),
18
18
  };
19
19
  });
20
20
  const selections = {};
21
- await (0, prompt_1.prompt)(selections, [
22
- {
23
- type: "checkbox",
24
- name: "emulators",
25
- message: "Which Firebase emulators do you want to set up? " +
26
- "Press Space to select emulators, then Enter to confirm your choices.",
27
- choices: choices,
28
- },
29
- ]);
21
+ selections.emulators = await (0, prompt_1.checkbox)({
22
+ message: "Which Firebase emulators do you want to set up? " +
23
+ "Press Space to select emulators, then Enter to confirm your choices.",
24
+ choices: choices,
25
+ });
30
26
  if (!selections.emulators) {
31
27
  return;
32
28
  }
@@ -38,14 +34,10 @@ async function doSetup(setup, config) {
38
34
  utils.logBullet(`Port for ${selected} already configured: ${clc.cyan(currentPort)}`);
39
35
  }
40
36
  else {
41
- await (0, prompt_1.prompt)(setup.config.emulators[selected], [
42
- {
43
- type: "number",
44
- name: "port",
45
- message: `Which port do you want to use for the ${clc.underline(selected)} emulator?`,
46
- default: constants_1.Constants.getDefaultPort(selected),
47
- },
48
- ]);
37
+ setup.config.emulators[selected].port = await (0, prompt_1.number)({
38
+ message: `Which port do you want to use for the ${clc.underline(selected)} emulator?`,
39
+ default: constants_1.Constants.getDefaultPort(selected),
40
+ });
49
41
  }
50
42
  const additionalInitFn = initEmulators_1.AdditionalInitFns[selected];
51
43
  if (additionalInitFn) {
@@ -64,34 +56,20 @@ async function doSetup(setup, config) {
64
56
  else {
65
57
  const ui = setup.config.emulators.ui || {};
66
58
  setup.config.emulators.ui = ui;
67
- await (0, prompt_1.prompt)(ui, [
68
- {
69
- name: "enabled",
70
- type: "confirm",
71
- message: `Would you like to enable the ${uiDesc}?`,
72
- default: true,
73
- },
74
- ]);
59
+ ui.enalbed = await (0, prompt_1.confirm)({
60
+ message: `Would you like to enable the ${uiDesc}?`,
61
+ default: true,
62
+ });
75
63
  if (ui.enabled) {
76
- await (0, prompt_1.prompt)(ui, [
77
- {
78
- type: "input",
79
- name: "port",
80
- message: `Which port do you want to use for the ${clc.underline(uiDesc)} (leave empty to use any available port)?`,
81
- },
82
- ]);
64
+ ui.port = await (0, prompt_1.number)(`Which port do you want to use for the ${clc.underline(uiDesc)} (leave empty to use any available port)?`);
83
65
  const portNum = Number.parseInt(ui.port);
84
66
  ui.port = isNaN(portNum) ? undefined : portNum;
85
67
  }
86
68
  }
87
- await (0, prompt_1.prompt)(selections, [
88
- {
89
- name: "download",
90
- type: "confirm",
91
- message: "Would you like to download the emulators now?",
92
- default: true,
93
- },
94
- ]);
69
+ selections.download = await (0, prompt_1.confirm)({
70
+ message: "Would you like to download the emulators now?",
71
+ default: true,
72
+ });
95
73
  }
96
74
  if (setup.config.emulators.singleProjectMode === undefined) {
97
75
  setup.config.emulators.singleProjectMode = true;
@@ -37,12 +37,8 @@ async function getDatabaseType(setup) {
37
37
  return dbType;
38
38
  }
39
39
  }
40
- async function selectDatabaseByPrompting() {
41
- const database = await (0, prompt_1.promptOnce)({
42
- type: "input",
43
- message: "Please input the name of the Native Firestore database you would like to use:",
44
- });
45
- return database;
40
+ function selectDatabaseByPrompting() {
41
+ return (0, prompt_1.input)("Please input the name of the Native Firestore database you would like to use:");
46
42
  }
47
43
  async function doSetup(setup, config, options) {
48
44
  if (setup.projectId) {
@@ -10,46 +10,32 @@ const logger_1 = require("../../../logger");
10
10
  const templates_1 = require("../../../templates");
11
11
  const indexes = new api.FirestoreApi();
12
12
  const INDEXES_TEMPLATE = (0, templates_1.readTemplateSync)("init/firestore/firestore.indexes.json");
13
- function initIndexes(setup, config) {
13
+ async function initIndexes(setup, config) {
14
14
  logger_1.logger.info();
15
15
  logger_1.logger.info("Firestore indexes allow you to perform complex queries while");
16
16
  logger_1.logger.info("maintaining performance that scales with the size of the result");
17
17
  logger_1.logger.info("set. You can keep index definitions in your project directory");
18
18
  logger_1.logger.info("and publish them with " + clc.bold("firebase deploy") + ".");
19
19
  logger_1.logger.info();
20
- return (0, prompt_1.prompt)(setup.config.firestore, [
21
- {
22
- type: "input",
23
- name: "indexes",
20
+ const filename = setup.config.firestore.indexes ||
21
+ (await (0, prompt_1.input)({
24
22
  message: "What file should be used for Firestore indexes?",
25
23
  default: "firestore.indexes.json",
26
- },
27
- ])
28
- .then(() => {
29
- const filename = setup.config.firestore.indexes;
30
- if (fsutils.fileExistsSync(filename)) {
31
- const msg = "File " +
32
- clc.bold(filename) +
33
- " already exists." +
34
- " Do you want to overwrite it with the Firestore Indexes from the Firebase Console?";
35
- return (0, prompt_1.promptOnce)({
36
- type: "confirm",
37
- message: msg,
38
- default: false,
39
- });
24
+ }));
25
+ if (fsutils.fileExistsSync(filename)) {
26
+ const msg = "File " +
27
+ clc.bold(filename) +
28
+ " already exists." +
29
+ " Do you want to overwrite it with the Firestore Indexes from the Firebase Console?";
30
+ if (!(await (0, prompt_1.confirm)(msg))) {
31
+ return;
40
32
  }
41
- return Promise.resolve(true);
42
- })
43
- .then((overwrite) => {
44
- if (!overwrite) {
45
- return Promise.resolve();
46
- }
47
- if (!setup.projectId) {
48
- return config.writeProjectFile(setup.config.firestore.indexes, INDEXES_TEMPLATE);
49
- }
50
- return getIndexesFromConsole(setup.projectId, setup.databaseId).then((contents) => {
51
- return config.writeProjectFile(setup.config.firestore.indexes, contents);
52
- });
33
+ }
34
+ if (!setup.projectId) {
35
+ return config.writeProjectFile(setup.config.firestore.indexes, INDEXES_TEMPLATE);
36
+ }
37
+ return getIndexesFromConsole(setup.projectId, setup.databaseId).then((contents) => {
38
+ return config.writeProjectFile(setup.config.firestore.indexes, contents);
53
39
  });
54
40
  }
55
41
  exports.initIndexes = initIndexes;
@@ -10,45 +10,31 @@ const utils = require("../../../utils");
10
10
  const templates_1 = require("../../../templates");
11
11
  const DEFAULT_RULES_FILE = "firestore.rules";
12
12
  const RULES_TEMPLATE = (0, templates_1.readTemplateSync)("init/firestore/firestore.rules");
13
- function initRules(setup, config) {
13
+ async function initRules(setup, config) {
14
14
  logger_1.logger.info();
15
15
  logger_1.logger.info("Firestore Security Rules allow you to define how and when to allow");
16
16
  logger_1.logger.info("requests. You can keep these rules in your project directory");
17
17
  logger_1.logger.info("and publish them with " + clc.bold("firebase deploy") + ".");
18
18
  logger_1.logger.info();
19
- return (0, prompt_1.prompt)(setup.config.firestore, [
20
- {
21
- type: "input",
22
- name: "rules",
19
+ const filename = setup.config.firestore.rules ||
20
+ (await (0, prompt_1.input)({
23
21
  message: "What file should be used for Firestore Rules?",
24
22
  default: DEFAULT_RULES_FILE,
25
- },
26
- ])
27
- .then(() => {
28
- const filename = setup.config.firestore.rules;
29
- if (fsutils.fileExistsSync(filename)) {
30
- const msg = "File " +
31
- clc.bold(filename) +
32
- " already exists." +
33
- " Do you want to overwrite it with the Firestore Rules from the Firebase Console?";
34
- return (0, prompt_1.promptOnce)({
35
- type: "confirm",
36
- message: msg,
37
- default: false,
38
- });
23
+ }));
24
+ if (fsutils.fileExistsSync(filename)) {
25
+ const msg = "File " +
26
+ clc.bold(filename) +
27
+ " already exists." +
28
+ " Do you want to overwrite it with the Firestore Rules from the Firebase Console?";
29
+ if (!(await (0, prompt_1.confirm)(msg))) {
30
+ return;
39
31
  }
40
- return Promise.resolve(true);
41
- })
42
- .then((overwrite) => {
43
- if (!overwrite) {
44
- return Promise.resolve();
45
- }
46
- if (!setup.projectId) {
47
- return config.writeProjectFile(setup.config.firestore.rules, getDefaultRules());
48
- }
49
- return getRulesFromConsole(setup.projectId).then((contents) => {
50
- return config.writeProjectFile(setup.config.firestore.rules, contents);
51
- });
32
+ }
33
+ if (!setup.projectId) {
34
+ return config.writeProjectFile(setup.config.firestore.rules, getDefaultRules());
35
+ }
36
+ return getRulesFromConsole(setup.projectId).then((contents) => {
37
+ return config.writeProjectFile(setup.config.firestore.rules, contents);
52
38
  });
53
39
  }
54
40
  exports.initRules = initRules;