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
@@ -69,7 +69,7 @@ function printNoticeIfEmulated(options, emulator) {
69
69
  }
70
70
  }
71
71
  exports.printNoticeIfEmulated = printNoticeIfEmulated;
72
- function warnEmulatorNotSupported(options, emulator) {
72
+ async function warnEmulatorNotSupported(options, emulator) {
73
73
  if (emulator !== types_1.Emulators.DATABASE && emulator !== types_1.Emulators.FIRESTORE) {
74
74
  return;
75
75
  }
@@ -80,18 +80,9 @@ function warnEmulatorNotSupported(options, emulator) {
80
80
  const envVal = process.env[envKey];
81
81
  if (envVal) {
82
82
  utils.logWarning(`You have set ${clc.bold(`${envKey}=${envVal}`)}, however this command does not support running against the ${emuName} so this action will affect production.`);
83
- const opts = {
84
- confirm: undefined,
85
- };
86
- return (0, prompt_1.promptOnce)({
87
- type: "confirm",
88
- default: false,
89
- message: "Do you want to continue?",
90
- }).then(() => {
91
- if (!opts.confirm) {
92
- return utils.reject("Command aborted.", { exit: 1 });
93
- }
94
- });
83
+ if (!(await (0, prompt_1.confirm)("Do you want to continue?"))) {
84
+ throw new error_1.FirebaseError("Command aborted.", { exit: 1 });
85
+ }
95
86
  }
96
87
  }
97
88
  exports.warnEmulatorNotSupported = warnEmulatorNotSupported;
@@ -583,8 +583,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
583
583
  emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT).logLabeled("WARN", "dataconnect", "'firebase.json#emulators.dataconnect.dataDir' is set and `--import` flag was passed. " +
584
584
  "This will overwrite any data saved from previous runs.");
585
585
  if (!options.nonInteractive &&
586
- !(await (0, prompt_1.promptOnce)({
587
- type: "confirm",
586
+ !(await (0, prompt_1.confirm)({
588
587
  message: `Do you wish to continue and overwrite data in ${dataDirectory}?`,
589
588
  default: false,
590
589
  }))) {
@@ -37,9 +37,9 @@ const EMULATOR_UPDATE_DETAILS = {
37
37
  ui: experiments.isEnabled("emulatoruisnapshot")
38
38
  ? { version: "SNAPSHOT", expectedSize: -1, expectedChecksum: "" }
39
39
  : {
40
- version: "1.14.0",
41
- expectedSize: 3615311,
42
- expectedChecksum: "30763ff4a8b81e2c482f05b56799b5c0",
40
+ version: "1.15.0",
41
+ expectedSize: 3538469,
42
+ expectedChecksum: "2f13d5aea9524564c8b7adaa9cfa2128",
43
43
  },
44
44
  pubsub: {
45
45
  version: "0.8.14",
@@ -48,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
48
48
  },
49
49
  dataconnect: process.platform === "darwin"
50
50
  ? {
51
- version: "2.4.0",
52
- expectedSize: 27316992,
53
- expectedChecksum: "615fb819b38dc61a36f18f0f8017379d",
51
+ version: "2.5.0",
52
+ expectedSize: 27378432,
53
+ expectedChecksum: "d18bc3a07be90886f6ec212f3393b66e",
54
54
  }
55
55
  : process.platform === "win32"
56
56
  ? {
57
- version: "2.4.0",
58
- expectedSize: 27774464,
59
- expectedChecksum: "1968300587f73fff246aa5c2cf9008fe",
57
+ version: "2.5.0",
58
+ expectedSize: 27836416,
59
+ expectedChecksum: "d335e9295b00381eb12682bc944ffef7",
60
60
  }
61
61
  : {
62
- version: "2.4.0",
63
- expectedSize: 27230360,
64
- expectedChecksum: "88407f13d5647aab496c3810666867a4",
62
+ version: "2.5.0",
63
+ expectedSize: 27295896,
64
+ expectedChecksum: "dc44dbfd972a9b3608794909df517077",
65
65
  },
66
66
  };
67
67
  exports.DownloadDetails = {
@@ -8,21 +8,18 @@ const developmentServer_1 = require("./apphosting/developmentServer");
8
8
  const emulatorLogger_1 = require("./emulatorLogger");
9
9
  const types_1 = require("./types");
10
10
  const config_1 = require("../apphosting/config");
11
- const detectProjectRoot_1 = require("../detectProjectRoot");
12
11
  const projectUtils_1 = require("../projectUtils");
13
12
  const secrets_1 = require("../apphosting/secrets");
14
13
  exports.AdditionalInitFns = {
15
14
  [types_1.Emulators.APPHOSTING]: async (config) => {
16
- var _a, _b;
15
+ var _a;
17
16
  const cwd = process.cwd();
18
17
  const additionalConfigs = new Map();
19
18
  const logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.APPHOSTING);
20
19
  logger.logLabeled("INFO", "Initializing Emulator");
21
- const backendRelativeDir = await (0, prompt_1.promptOnce)({
22
- name: "rootDir",
23
- type: "input",
24
- default: "./",
20
+ const backendRelativeDir = await (0, prompt_1.input)({
25
21
  message: "Specify your app's root directory relative to your repository",
22
+ default: "./",
26
23
  });
27
24
  additionalConfigs.set("rootDirectory", backendRelativeDir);
28
25
  const backendRoot = (0, path_1.join)(cwd, backendRelativeDir);
@@ -36,23 +33,19 @@ exports.AdditionalInitFns = {
36
33
  const projectId = (0, projectUtils_1.getProjectId)(config.options);
37
34
  let env = [];
38
35
  try {
39
- const projectRoot = (_a = (0, detectProjectRoot_1.detectProjectRoot)({ cwd: config.options.cwd })) !== null && _a !== void 0 ? _a : backendRoot;
40
- env = await (0, config_1.maybeGenerateEmulatorYaml)(projectId, projectRoot);
36
+ env = await (0, config_1.maybeGenerateEmulatorYaml)(projectId, backendRoot);
41
37
  }
42
38
  catch (e) {
43
39
  logger.log("WARN", "failed to export app hosting configs");
44
40
  }
45
- const secretIds = (_b = env === null || env === void 0 ? void 0 : env.filter((e) => "secret" in e)) === null || _b === void 0 ? void 0 : _b.map((e) => e.secret);
41
+ const secretIds = (_a = env === null || env === void 0 ? void 0 : env.filter((e) => "secret" in e)) === null || _a === void 0 ? void 0 : _a.map((e) => e.secret);
46
42
  if (secretIds === null || secretIds === void 0 ? void 0 : secretIds.length) {
47
43
  if (!projectId) {
48
44
  logger.log("WARN", "Cannot grant developers access to secrets for local development without knowing what project the secret is in. " +
49
45
  `Run ${clc.bold(`firebase apphosting:secrets:grantaccess ${secretIds.join(",")} --project [project] --emails [email list]`)}`);
50
46
  }
51
47
  else {
52
- const users = await (0, prompt_1.promptOnce)({
53
- type: "input",
54
- message: "Your config has secret values. Please provide a comma-separated list of users or groups who should have access to secrets for local development:",
55
- });
48
+ const users = await (0, prompt_1.input)("Your config has secret values. Please provide a comma-separated list of users or groups who should have access to secrets for local development: ");
56
49
  if (users.length) {
57
50
  await (0, secrets_1.grantEmailsSecretAccess)(projectId, secretIds, users.split(",").map((u) => u.trim()));
58
51
  }
@@ -68,13 +61,9 @@ exports.AdditionalInitFns = {
68
61
  const additionalConfig = {};
69
62
  const defaultDataConnectDir = config.get("dataconnect.source", "dataconnect");
70
63
  const defaultDataDir = config.get("emulators.dataconnect.dataDir", `${defaultDataConnectDir}/.dataconnect/pgliteData`);
71
- if (await (0, prompt_1.promptOnce)({
72
- name: "dataDir",
73
- type: "confirm",
74
- message: "Do you want to persist Postgres data from the Data Connect emulator between runs? " +
75
- `Data will be saved to ${defaultDataDir}. ` +
76
- `You can change this directory by editing 'firebase.json#emulators.dataconnect.dataDir'.`,
77
- })) {
64
+ if (await (0, prompt_1.confirm)("Do you want to persist Postgres data from the Data Connect emulator between runs? " +
65
+ `Data will be saved to ${defaultDataDir}. ` +
66
+ `You can change this directory by editing 'firebase.json#emulators.dataconnect.dataDir'.`)) {
78
67
  additionalConfig["dataDir"] = defaultDataDir;
79
68
  }
80
69
  return additionalConfig;
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.askForEventArcLocation = exports.EXTENSIONS_DEFAULT_EVENT_ARC_REGION = exports.ALLOWED_EVENT_ARC_REGIONS = exports.askShouldCollectEventsConfig = exports.askForAllowedEventTypes = exports.getEventArcChannel = exports.askForEventsConfig = exports.checkAllowedEventTypesResponse = void 0;
4
- const prompt_1 = require("../prompt");
5
4
  const extensionsApi = require("../extensions/extensionsApi");
6
5
  const utils = require("../utils");
7
6
  const clc = require("colorette");
8
7
  const logger_1 = require("../logger");
9
8
  const marked_1 = require("marked");
9
+ const prompt_1 = require("../prompt");
10
10
  function checkAllowedEventTypesResponse(response, validEvents) {
11
11
  const validEventTypes = validEvents.map((e) => e.type);
12
12
  if (response.length === 0) {
@@ -56,9 +56,7 @@ async function askForAllowedEventTypes(eventDescriptors, preselectedTypes) {
56
56
  value: e.type,
57
57
  }));
58
58
  while (!valid) {
59
- response = await (0, prompt_1.promptOnce)({
60
- name: "selectedEventTypesInput",
61
- type: "checkbox",
59
+ response = await (0, prompt_1.checkbox)({
62
60
  default: preselectedTypes !== null && preselectedTypes !== void 0 ? preselectedTypes : [],
63
61
  message: `Please select the events [${eventTypes.length} types total] that this extension is permitted to emit. ` +
64
62
  "You can implement your own handlers that trigger when these events are emitted to customize the extension's behavior. ",
@@ -70,13 +68,8 @@ async function askForAllowedEventTypes(eventDescriptors, preselectedTypes) {
70
68
  return response.filter((e) => e !== "");
71
69
  }
72
70
  exports.askForAllowedEventTypes = askForAllowedEventTypes;
73
- async function askShouldCollectEventsConfig() {
74
- return (0, prompt_1.promptOnce)({
75
- type: "confirm",
76
- name: "shouldCollectEvents",
77
- message: `Would you like to enable events?`,
78
- default: false,
79
- });
71
+ function askShouldCollectEventsConfig() {
72
+ return (0, prompt_1.confirm)("Would you like to enable events?");
80
73
  }
81
74
  exports.askShouldCollectEventsConfig = askShouldCollectEventsConfig;
82
75
  exports.ALLOWED_EVENT_ARC_REGIONS = [
@@ -90,12 +83,10 @@ async function askForEventArcLocation(preselectedLocation) {
90
83
  let valid = false;
91
84
  let location = "";
92
85
  while (!valid) {
93
- location = await (0, prompt_1.promptOnce)({
94
- name: "input",
95
- type: "list",
86
+ location = await (0, prompt_1.select)({
96
87
  default: preselectedLocation !== null && preselectedLocation !== void 0 ? preselectedLocation : exports.EXTENSIONS_DEFAULT_EVENT_ARC_REGION,
97
88
  message: "Which location would you like the Eventarc channel to live in? We recommend using the default option. A channel location that differs from the extension's Cloud Functions location can incur egress cost.",
98
- choices: exports.ALLOWED_EVENT_ARC_REGIONS.map((e) => ({ checked: false, value: e })),
89
+ choices: exports.ALLOWED_EVENT_ARC_REGIONS,
99
90
  });
100
91
  valid = exports.ALLOWED_EVENT_ARC_REGIONS.includes(location);
101
92
  if (!valid) {
@@ -82,11 +82,7 @@ async function ask(args) {
82
82
  });
83
83
  if (advancedParams.length) {
84
84
  promises.push(async () => {
85
- const shouldPrompt = await (0, prompt_1.promptOnce)({
86
- type: "confirm",
87
- message: "Do you want to configure any advanced parameters for this instance?",
88
- default: false,
89
- });
85
+ const shouldPrompt = await (0, prompt_1.confirm)("Do you want to configure any advanced parameters for this instance?");
90
86
  if (shouldPrompt) {
91
87
  const advancedPromises = advancedParams.map((paramSpec) => {
92
88
  return async () => {
@@ -126,14 +122,10 @@ async function askForParam(args) {
126
122
  while (!valid) {
127
123
  switch (paramSpec.type) {
128
124
  case types_1.ParamType.SELECT:
129
- response = await (0, prompt_1.promptOnce)({
130
- name: "input",
131
- type: "list",
132
- default: () => {
133
- if (paramSpec.default) {
134
- return getInquirerDefault(_.get(paramSpec, "options", []), paramSpec.default);
135
- }
136
- },
125
+ response = await (0, prompt_1.select)({
126
+ default: paramSpec.default
127
+ ? getInquirerDefault(_.get(paramSpec, "options", []), paramSpec.default)
128
+ : undefined,
137
129
  message: "Which option do you want enabled for this parameter? " +
138
130
  "Select an option with the arrow keys, and use Enter to confirm your choice. " +
139
131
  "You may only select one option.",
@@ -142,21 +134,16 @@ async function askForParam(args) {
142
134
  valid = checkResponse(response, paramSpec);
143
135
  break;
144
136
  case types_1.ParamType.MULTISELECT:
145
- response = await (0, utils_1.onceWithJoin)({
146
- name: "input",
147
- type: "checkbox",
148
- default: () => {
149
- if (paramSpec.default) {
150
- const defaults = paramSpec.default.split(",");
151
- return defaults.map((def) => {
152
- return getInquirerDefault(_.get(paramSpec, "options", []), def);
153
- });
154
- }
155
- },
137
+ response = (await (0, prompt_1.checkbox)({
138
+ default: paramSpec.default
139
+ ? paramSpec.default.split(",").map((def) => {
140
+ return getInquirerDefault(_.get(paramSpec, "options", []), def);
141
+ })
142
+ : undefined,
156
143
  message: "Which options do you want enabled for this parameter? " +
157
144
  "Press Space to select, then Enter to confirm your choices. ",
158
145
  choices: (0, utils_1.convertExtensionOptionToLabeledList)(paramSpec.options),
159
- });
146
+ })).join(",");
160
147
  valid = checkResponse(response, paramSpec);
161
148
  break;
162
149
  case types_1.ParamType.SECRET:
@@ -175,9 +162,7 @@ async function askForParam(args) {
175
162
  valid = true;
176
163
  break;
177
164
  default:
178
- response = await (0, prompt_1.promptOnce)({
179
- name: paramSpec.param,
180
- type: "input",
165
+ response = await (0, prompt_1.input)({
181
166
  default: paramSpec.default,
182
167
  message: `Enter a value for ${label}:`,
183
168
  });
@@ -195,9 +180,7 @@ function isValidSecretLocations(secretLocations, paramSpec) {
195
180
  }
196
181
  async function promptSecretLocations(paramSpec) {
197
182
  if (paramSpec.required) {
198
- return await (0, prompt_1.promptOnce)({
199
- name: "input",
200
- type: "checkbox",
183
+ return await (0, prompt_1.checkbox)({
201
184
  message: "Where would you like to store your secrets? You must select at least one value",
202
185
  choices: [
203
186
  {
@@ -213,9 +196,7 @@ async function promptSecretLocations(paramSpec) {
213
196
  ],
214
197
  });
215
198
  }
216
- return await (0, prompt_1.promptOnce)({
217
- name: "input",
218
- type: "checkbox",
199
+ return await (0, prompt_1.checkbox)({
219
200
  message: "Where would you like to store your secrets? " +
220
201
  "If you don't want to set this optional secret, leave both options unselected to skip it",
221
202
  choices: [
@@ -236,18 +217,13 @@ async function promptLocalSecret(instanceId, paramSpec) {
236
217
  let value;
237
218
  do {
238
219
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, "Configure a local secret value for Extensions Emulator");
239
- value = await (0, prompt_1.promptOnce)({
240
- name: paramSpec.param,
241
- type: "input",
242
- message: `This secret will be stored in ./extensions/${instanceId}.secret.local.\n` +
243
- `Enter value for "${paramSpec.label.trim()}" to be used by Extensions Emulator:`,
244
- });
220
+ value = await (0, prompt_1.input)(`This secret will be stored in ./extensions/${instanceId}.secret.local.\n` +
221
+ `Enter value for "${paramSpec.label.trim()}" to be used by Extensions Emulator:`);
245
222
  } while (!value);
246
223
  return value;
247
224
  }
248
225
  async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
249
- const action = await (0, prompt_1.promptOnce)({
250
- type: "list",
226
+ const action = await (0, prompt_1.select)({
251
227
  message: `Choose what you would like to do with this secret:`,
252
228
  choices: [
253
229
  { name: "Leave unchanged", value: SecretUpdateAction.LEAVE },
@@ -265,11 +241,7 @@ async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
265
241
  else {
266
242
  secretName = await generateSecretName(projectId, instanceId, paramSpec.param);
267
243
  }
268
- const secretValue = await (0, prompt_1.promptOnce)({
269
- name: paramSpec.param,
270
- type: "password",
271
- message: `This secret will be stored in Cloud Secret Manager as ${secretName}.\nEnter new value for ${paramSpec.label.trim()}:`,
272
- });
244
+ const secretValue = await (0, prompt_1.password)(`This secret will be stored in Cloud Secret Manager as ${secretName}.\nEnter new value for ${paramSpec.label.trim()}:`);
273
245
  if (secretValue === "" && paramSpec.required) {
274
246
  logger_1.logger.info(`Secret value cannot be empty for required param ${paramSpec.param}`);
275
247
  return promptReconfigureSecret(projectId, instanceId, paramSpec);
@@ -296,12 +268,11 @@ async function promptReconfigureSecret(projectId, instanceId, paramSpec) {
296
268
  }
297
269
  async function promptCreateSecret(projectId, instanceId, paramSpec, secretName) {
298
270
  const name = secretName !== null && secretName !== void 0 ? secretName : (await generateSecretName(projectId, instanceId, paramSpec.param));
299
- const secretValue = await (0, prompt_1.promptOnce)({
300
- name: paramSpec.param,
301
- type: "password",
302
- default: paramSpec.default,
271
+ const secretValue = (await (0, prompt_1.password)({
303
272
  message: `This secret will be stored in Cloud Secret Manager (https://cloud.google.com/secret-manager/pricing) as ${name} and managed by Firebase Extensions (Firebase Extensions Service Agent will be granted Secret Admin role on this secret).\nEnter a value for ${paramSpec.label.trim()}:`,
304
- });
273
+ })) ||
274
+ paramSpec.default ||
275
+ "";
305
276
  if (secretValue === "" && paramSpec.required) {
306
277
  logger_1.logger.info(`Secret value cannot be empty for required param ${paramSpec.param}`);
307
278
  return promptCreateSecret(projectId, instanceId, paramSpec, name);
@@ -25,9 +25,7 @@ async function openBillingAccount(projectId, url, open) {
25
25
  logger_1.logger.debug("Unable to open billing URL: " + err.stack);
26
26
  }
27
27
  }
28
- await prompt.promptOnce({
29
- name: "continue",
30
- type: "confirm",
28
+ await prompt.confirm({
31
29
  message: "Press enter when finished upgrading your project to continue setting up your extension.",
32
30
  default: true,
33
31
  });
@@ -36,9 +34,7 @@ async function openBillingAccount(projectId, url, open) {
36
34
  async function chooseBillingAccount(projectId, accounts) {
37
35
  const choices = accounts.map((m) => m.displayName);
38
36
  choices.push(ADD_BILLING_ACCOUNT);
39
- const answer = await prompt.promptOnce({
40
- name: "billing",
41
- type: "list",
37
+ const answer = await prompt.select({
42
38
  message: `Extensions require your project to be upgraded to the Blaze plan. You have access to the following billing accounts.
43
39
  Please select the one that you would like to associate with this project:`,
44
40
  choices: choices,
@@ -61,9 +57,7 @@ async function setUpBillingAccount(projectId) {
61
57
  logger_1.logger.info();
62
58
  logger_1.logger.info(clc.bold(clc.underline(billingURL)));
63
59
  logger_1.logger.info();
64
- const open = await prompt.promptOnce({
65
- name: "open-url",
66
- type: "confirm",
60
+ const open = await prompt.confirm({
67
61
  message: "Press enter to open the URL.",
68
62
  default: true,
69
63
  });
@@ -5,8 +5,8 @@ const extensionsHelper_1 = require("./extensionsHelper");
5
5
  const getProjectNumber_1 = require("../getProjectNumber");
6
6
  const utils = require("../utils");
7
7
  const resourceManager = require("../gcp/resourceManager");
8
- const extensionsApi_1 = require("./extensionsApi");
9
8
  const prompt_1 = require("../prompt");
9
+ const extensionsApi_1 = require("./extensionsApi");
10
10
  const logger_1 = require("../logger");
11
11
  const error_1 = require("../error");
12
12
  const SERVICE_AGENT_ROLE = "roles/firebasemods.serviceAgent";
@@ -36,11 +36,8 @@ async function diagnose(projectId) {
36
36
  else {
37
37
  utils.logWarning("Firebase Extensions Service Agent is missing a required IAM role " +
38
38
  "`Firebase Extensions API Service Agent`.");
39
- const fix = await (0, prompt_1.promptOnce)({
40
- type: "confirm",
41
- message: "Would you like to fix the issue by updating IAM policy to include Firebase " +
42
- "Extensions Service Agent with role `Firebase Extensions API Service Agent`",
43
- });
39
+ const fix = await (0, prompt_1.confirm)("Would you like to fix the issue by updating IAM policy to include Firebase " +
40
+ "Extensions Service Agent with role `Firebase Extensions API Service Agent`");
44
41
  if (fix) {
45
42
  policy.bindings.push({
46
43
  role: SERVICE_AGENT_ROLE,
@@ -33,9 +33,9 @@ const storage_1 = require("../gcp/storage");
33
33
  const projectUtils_1 = require("../projectUtils");
34
34
  const extensionsApi_1 = require("./extensionsApi");
35
35
  const publisherApi_1 = require("./publisherApi");
36
+ const prompt_1 = require("../prompt");
36
37
  const refs = require("./refs");
37
38
  const localHelper_1 = require("./localHelper");
38
- const prompt_1 = require("../prompt");
39
39
  const logger_1 = require("../logger");
40
40
  const utils_2 = require("../utils");
41
41
  const change_log_1 = require("./change-log");
@@ -309,8 +309,7 @@ async function promptForValidInstanceId(instanceId) {
309
309
  let newInstanceId = "";
310
310
  const instanceIdRegex = /^[a-z][a-z\d\-]*[a-z\d]$/;
311
311
  while (!instanceIdIsValid) {
312
- newInstanceId = await (0, prompt_1.promptOnce)({
313
- type: "input",
312
+ newInstanceId = await (0, prompt_1.input)({
314
313
  default: instanceId,
315
314
  message: `Please enter a new name for this instance:`,
316
315
  });
@@ -332,10 +331,7 @@ async function promptForValidRepoURI() {
332
331
  let repoIsValid = false;
333
332
  let extensionRoot = "";
334
333
  while (!repoIsValid) {
335
- extensionRoot = await (0, prompt_1.promptOnce)({
336
- type: "input",
337
- message: "Enter the GitHub repo URI where this extension's source code is located:",
338
- });
334
+ extensionRoot = await (0, prompt_1.input)("Enter the GitHub repo URI where this extension's source code is located:");
339
335
  if (!repoRegex.test(extensionRoot)) {
340
336
  logger_1.logger.info("Repo URI must follow this format: https://github.com/<user>/<repo>");
341
337
  }
@@ -347,8 +343,7 @@ async function promptForValidRepoURI() {
347
343
  }
348
344
  exports.promptForValidRepoURI = promptForValidRepoURI;
349
345
  async function promptForExtensionRoot(defaultRoot) {
350
- return await (0, prompt_1.promptOnce)({
351
- type: "input",
346
+ return await (0, prompt_1.input)({
352
347
  message: "Enter this extension's root directory in the repo (defaults to previous root if set):",
353
348
  default: defaultRoot,
354
349
  });
@@ -369,22 +364,20 @@ async function promptForReleaseStage(args) {
369
364
  };
370
365
  choices.push(stableChoice);
371
366
  }
372
- stage = await (0, prompt_1.promptOnce)({
373
- type: "list",
367
+ stage = await (0, prompt_1.select)({
374
368
  message: "Choose the release stage:",
375
369
  choices: choices,
376
370
  default: stage,
377
371
  });
378
372
  if (stage === "stable" && !args.hasVersions) {
379
- logger_1.logger.info(`${clc.bold(clc.yellow("Warning:"))} It's highly recommended to first upload a pre-release version before choosing stable.`);
380
373
  const confirmed = await (0, prompt_1.confirm)({
374
+ message: `${clc.bold(clc.yellow("Warning:"))} It's highly recommended to first upload a pre-release version before choosing stable.`,
381
375
  nonInteractive: args.nonInteractive,
382
376
  force: args.force,
383
377
  default: false,
384
378
  });
385
379
  if (!confirmed) {
386
- stage = await (0, prompt_1.promptOnce)({
387
- type: "list",
380
+ stage = await (0, prompt_1.select)({
388
381
  message: "Choose the release stage:",
389
382
  choices: choices,
390
383
  default: stage,
@@ -605,8 +598,7 @@ async function uploadExtensionVersionFromGitHubSource(args) {
605
598
  const defaultSourceRef = "HEAD";
606
599
  if (!sourceRef) {
607
600
  if (!args.nonInteractive) {
608
- sourceRef = await (0, prompt_1.promptOnce)({
609
- type: "input",
601
+ sourceRef = await (0, prompt_1.input)({
610
602
  message: "Enter the commit hash, branch, or tag name to build from in the repo:",
611
603
  default: defaultSourceRef,
612
604
  });
@@ -645,6 +637,7 @@ async function uploadExtensionVersionFromGitHubSource(args) {
645
637
  autoReview: stage === "stable" && autoReview,
646
638
  });
647
639
  const confirmed = await (0, prompt_1.confirm)({
640
+ message: "Continue?",
648
641
  nonInteractive: args.nonInteractive,
649
642
  force: args.force,
650
643
  default: false,
@@ -713,6 +706,7 @@ async function uploadExtensionVersionFromLocalSource(args) {
713
706
  const releaseNotes = validateReleaseNotes(args.rootDirectory, extensionSpec.version, extension);
714
707
  displayReleaseNotes({ extensionRef, newVersion, releaseNotes, autoReview: false });
715
708
  const confirmed = await (0, prompt_1.confirm)({
709
+ message: "Continue?",
716
710
  nonInteractive: args.nonInteractive,
717
711
  force: args.force,
718
712
  default: false,
@@ -818,9 +812,7 @@ function displayReleaseNotes(args) {
818
812
  exports.displayReleaseNotes = displayReleaseNotes;
819
813
  async function promptForOfficialExtension(message) {
820
814
  const officialExts = await (0, resolveSource_1.getExtensionRegistry)(true);
821
- return await (0, prompt_1.promptOnce)({
822
- name: "input",
823
- type: "list",
815
+ return await (0, prompt_1.select)({
824
816
  message,
825
817
  choices: (0, utils_1.convertOfficialExtensionsToList)(officialExts),
826
818
  pageSize: Object.keys(officialExts).length,
@@ -829,15 +821,13 @@ async function promptForOfficialExtension(message) {
829
821
  exports.promptForOfficialExtension = promptForOfficialExtension;
830
822
  async function promptForRepeatInstance(projectName, extensionName) {
831
823
  const message = `An extension with the ID '${clc.bold(extensionName)}' already exists in the project '${clc.bold(projectName)}'. What would you like to do?`;
832
- const choices = [
833
- { name: "Update or reconfigure the existing instance", value: "updateExisting" },
834
- { name: "Install a new instance with a different ID", value: "installNew" },
835
- { name: "Cancel extension installation", value: "cancel" },
836
- ];
837
- return await (0, prompt_1.promptOnce)({
838
- type: "list",
824
+ return await (0, prompt_1.select)({
839
825
  message,
840
- choices,
826
+ choices: [
827
+ { name: "Update or reconfigure the existing instance", value: "updateExisting" },
828
+ { name: "Install a new instance with a different ID", value: "installNew" },
829
+ { name: "Cancel extension installation", value: "cancel" },
830
+ ],
841
831
  });
842
832
  }
843
833
  exports.promptForRepeatInstance = promptForRepeatInstance;
@@ -24,8 +24,7 @@ async function writeToManifest(specs, config, options, allowOverwrite = false) {
24
24
  .map((i) => `${i[0]}: ${i[1]}`)
25
25
  .join("\n\t");
26
26
  if (allowOverwrite) {
27
- const overwrite = await (0, prompt_1.promptOnce)({
28
- type: "list",
27
+ const overwrite = await (0, prompt_1.select)({
29
28
  message: `firebase.json already contains extensions:\n${currentExtensions}\nWould you like to overwrite or merge?`,
30
29
  choices: [
31
30
  { name: "Overwrite", value: true },
@@ -49,7 +49,11 @@ async function acceptLatestPublisherTOS(options, projectId) {
49
49
  else {
50
50
  const tosLink = extensionsTosUrl("publisher");
51
51
  logger_1.logger.info(`To continue, you must accept the Firebase Extensions Publisher Terms of Service: ${tosLink}`);
52
- if (await (0, prompt_1.confirm)(Object.assign(Object.assign({}, options), { message: "Do you accept the Firebase Extensions Publisher Terms of Service?" }))) {
52
+ if (await (0, prompt_1.confirm)({
53
+ message: "Do you accept the Firebase Extensions Publisher Terms of Service?",
54
+ nonInteractive: options.nonInteractive,
55
+ force: options.force,
56
+ })) {
53
57
  return acceptPublisherTOS(projectId, currentAcceptance.latestTosVersion);
54
58
  }
55
59
  }
@@ -69,7 +73,11 @@ async function acceptLatestAppDeveloperTOS(options, projectId, instanceIds) {
69
73
  if (currentAcceptance.lastAcceptedVersion) {
70
74
  logger_1.logger.debug(`User Terms of Service aready accepted on project ${projectId}.`);
71
75
  }
72
- else if (!(await (0, prompt_1.confirm)(Object.assign(Object.assign({}, options), { message: "Do you accept the Firebase Extensions User Terms of Service?" })))) {
76
+ else if (!(await (0, prompt_1.confirm)({
77
+ message: "Do you accept the Firebase Extensions User Terms of Service?",
78
+ nonInteractive: options.nonInteractive,
79
+ force: options.force,
80
+ }))) {
73
81
  throw new error_1.FirebaseError("You must accept the terms of service to continue.");
74
82
  }
75
83
  const tosPromises = instanceIds.map((instanceId) => {
@@ -1,16 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getResourceRuntime = exports.formatTimestamp = exports.getRandomString = exports.convertOfficialExtensionsToList = exports.convertExtensionOptionToLabeledList = exports.onceWithJoin = void 0;
4
- const prompt_1 = require("../prompt");
3
+ exports.getResourceRuntime = exports.formatTimestamp = exports.getRandomString = exports.convertOfficialExtensionsToList = exports.convertExtensionOptionToLabeledList = void 0;
5
4
  const types_1 = require("./types");
6
- async function onceWithJoin(question) {
7
- const response = await (0, prompt_1.promptOnce)(question);
8
- if (Array.isArray(response)) {
9
- return response.join(",");
10
- }
11
- return response;
12
- }
13
- exports.onceWithJoin = onceWithJoin;
14
5
  function convertExtensionOptionToLabeledList(options) {
15
6
  return options.map((option) => {
16
7
  return {
@@ -177,8 +177,7 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
177
177
  console.warn(`No Firebase app associated with site ${site}, unable to provide authenticated server context.
178
178
  You can link a Web app to a Hosting site here https://console.firebase.google.com/project/${project}/settings/general/web`);
179
179
  if (!options.nonInteractive) {
180
- const continueDeploy = await (0, prompt_1.promptOnce)({
181
- type: "confirm",
180
+ const continueDeploy = await (0, prompt_1.confirm)({
182
181
  default: true,
183
182
  message: "Would you like to continue with the deploy?",
184
183
  });
@@ -205,13 +205,16 @@ async function build(dir, target, context) {
205
205
  }
206
206
  exports.build = build;
207
207
  async function init(setup, config) {
208
- const language = await (0, prompt_1.promptOnce)({
209
- type: "list",
208
+ const language = await (0, prompt_1.select)({
210
209
  default: "TypeScript",
211
210
  message: "What language would you like to use?",
212
- choices: ["JavaScript", "TypeScript"],
211
+ choices: [
212
+ { name: "JavaScript", value: "js" },
213
+ { name: "TypeScript", value: "ts" },
214
+ ],
213
215
  });
214
- (0, child_process_1.execSync)(`npx --yes create-next-app@"${exports.supportedRange}" -e hello-world ${setup.hosting.source} --use-npm ${language === "TypeScript" ? "--ts" : "--js"}`, { stdio: "inherit", cwd: config.projectDir });
216
+ (0, child_process_1.execSync)(`npx --yes create-next-app@"${exports.supportedRange}" -e hello-world ` +
217
+ `${setup.hosting.source} --use-npm --${language}`, { stdio: "inherit", cwd: config.projectDir });
215
218
  }
216
219
  exports.init = init;
217
220
  async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
@@ -17,8 +17,7 @@ exports.DEFAULT_BUILD_SCRIPT = ["vite build", "tsc && vite build"];
17
17
  const initViteTemplate = (template) => async (setup, config) => await init(setup, config, template);
18
18
  exports.initViteTemplate = initViteTemplate;
19
19
  async function init(setup, config, baseTemplate = "vanilla") {
20
- const template = await (0, prompt_1.promptOnce)({
21
- type: "list",
20
+ const template = await (0, prompt_1.select)({
22
21
  default: "JavaScript",
23
22
  message: "What language would you like to use?",
24
23
  choices: [