firebase-tools 10.2.2 → 10.4.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 (76) hide show
  1. package/lib/commands/deploy.js +1 -1
  2. package/lib/commands/experimental-functions-shell.js +1 -1
  3. package/lib/commands/ext-configure.js +68 -7
  4. package/lib/commands/ext-export.js +10 -9
  5. package/lib/commands/ext-install.js +73 -9
  6. package/lib/commands/ext-uninstall.js +9 -0
  7. package/lib/commands/ext-update.js +58 -3
  8. package/lib/commands/functions-config-export.js +2 -2
  9. package/lib/commands/functions-shell.js +1 -1
  10. package/lib/commands/hosting-channel-create.js +2 -2
  11. package/lib/commands/hosting-channel-delete.js +2 -2
  12. package/lib/commands/hosting-channel-deploy.js +2 -2
  13. package/lib/commands/hosting-channel-list.js +2 -2
  14. package/lib/commands/hosting-channel-open.js +2 -2
  15. package/lib/commands/hosting-sites-delete.js +2 -2
  16. package/lib/commands/serve.js +1 -1
  17. package/lib/commands/target-apply.js +2 -2
  18. package/lib/commands/target-clear.js +2 -2
  19. package/lib/commands/target-remove.js +2 -2
  20. package/lib/commands/target.js +2 -2
  21. package/lib/config.js +9 -3
  22. package/lib/deploy/extensions/planner.js +15 -9
  23. package/lib/deploy/functions/backend.js +10 -1
  24. package/lib/deploy/functions/checkIam.js +4 -4
  25. package/lib/deploy/functions/prepare.js +2 -1
  26. package/lib/deploy/functions/release/fabricator.js +4 -4
  27. package/lib/deploy/functions/release/planner.js +34 -20
  28. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +6 -1
  29. package/lib/deploy/functions/runtimes/node/index.js +27 -0
  30. package/lib/deploy/functions/runtimes/node/parseTriggers.js +36 -13
  31. package/lib/deploy/functions/services/firebaseAlerts.js +30 -0
  32. package/lib/deploy/functions/services/index.js +9 -1
  33. package/lib/deploy/functions/services/storage.js +10 -4
  34. package/lib/deploy/functions/triggerRegionHelper.js +1 -1
  35. package/lib/emulator/auth/apiSpec.js +37 -0
  36. package/lib/emulator/commandUtils.js +2 -2
  37. package/lib/emulator/constants.js +1 -0
  38. package/lib/emulator/controller.js +9 -7
  39. package/lib/emulator/extensions/validation.js +37 -2
  40. package/lib/emulator/extensionsEmulator.js +47 -9
  41. package/lib/emulator/functionsEmulator.js +17 -12
  42. package/lib/emulator/functionsEmulatorShared.js +34 -11
  43. package/lib/emulator/storage/apis/firebase.js +316 -341
  44. package/lib/emulator/storage/apis/gcloud.js +238 -113
  45. package/lib/emulator/storage/crc.js +5 -1
  46. package/lib/emulator/storage/errors.js +9 -0
  47. package/lib/emulator/storage/files.js +161 -304
  48. package/lib/emulator/storage/index.js +25 -74
  49. package/lib/emulator/storage/metadata.js +63 -49
  50. package/lib/emulator/storage/multipart.js +62 -0
  51. package/lib/emulator/storage/persistence.js +78 -0
  52. package/lib/emulator/storage/rules/config.js +34 -0
  53. package/lib/emulator/storage/rules/manager.js +98 -0
  54. package/lib/emulator/storage/rules/runtime.js +4 -0
  55. package/lib/emulator/storage/rules/utils.js +48 -0
  56. package/lib/emulator/storage/server.js +2 -2
  57. package/lib/emulator/storage/upload.js +106 -0
  58. package/lib/extensions/askUserForParam.js +77 -28
  59. package/lib/extensions/emulator/optionsHelper.js +35 -3
  60. package/lib/extensions/extensionsHelper.js +19 -10
  61. package/lib/extensions/manifest.js +142 -14
  62. package/lib/extensions/paramHelper.js +32 -9
  63. package/lib/fsutils.js +14 -1
  64. package/lib/functions/env.js +4 -6
  65. package/lib/functions/events/v2.js +11 -0
  66. package/lib/gcp/cloudfunctions.js +20 -7
  67. package/lib/gcp/cloudfunctionsv2.js +30 -12
  68. package/lib/gcp/resourceManager.js +4 -4
  69. package/lib/requireConfig.js +11 -9
  70. package/lib/serve/functions.js +2 -1
  71. package/lib/utils.js +14 -1
  72. package/npm-shrinkwrap.json +2 -2
  73. package/package.json +1 -1
  74. package/lib/deploy/extensions/params.js +0 -42
  75. package/lib/deploy/functions/eventTypes.js +0 -10
  76. package/lib/prepareUpload.js +0 -44
@@ -6,7 +6,7 @@ const { checkServiceAccountIam } = require("../deploy/functions/checkIam");
6
6
  const checkValidTargetFilters = require("../checkValidTargetFilters");
7
7
  const { Command } = require("../command");
8
8
  const deploy = require("../deploy");
9
- const requireConfig = require("../requireConfig");
9
+ const { requireConfig } = require("../requireConfig");
10
10
  const { filterTargets } = require("../filterTargets");
11
11
  const { requireHostingSite } = require("../requireHostingSite");
12
12
  const VALID_TARGETS = [
@@ -2,7 +2,7 @@
2
2
  var { Command } = require("../command");
3
3
  var { requirePermissions } = require("../requirePermissions");
4
4
  var { actionFunction } = require("../functionsShellCommandAction");
5
- var requireConfig = require("../requireConfig");
5
+ var { requireConfig } = require("../requireConfig");
6
6
  module.exports = new Command("experimental:functions:shell")
7
7
  .description("launch full Node shell with emulated functions. (Alias for `firebase functions:shell.)")
8
8
  .option("-p, --port <port>", "the port on which to emulate functions (default: 5000)", 5000)
@@ -15,6 +15,10 @@ const paramHelper = require("../extensions/paramHelper");
15
15
  const requirePermissions_1 = require("../requirePermissions");
16
16
  const utils = require("../utils");
17
17
  const logger_1 = require("../logger");
18
+ const refs = require("../extensions/refs");
19
+ const manifest = require("../extensions/manifest");
20
+ const functional_1 = require("../functional");
21
+ const paramHelper_1 = require("../extensions/paramHelper");
18
22
  marked.setOptions({
19
23
  renderer: new TerminalRenderer(),
20
24
  });
@@ -22,6 +26,7 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
22
26
  .description("configure an existing extension instance")
23
27
  .withForce()
24
28
  .option("--params <paramsFile>", "path of params file with .env format.")
29
+ .option("--local", "save to firebase.json rather than directly install to a Firebase project")
25
30
  .before(requirePermissions_1.requirePermissions, [
26
31
  "firebaseextensions.instances.update",
27
32
  "firebaseextensions.instances.get",
@@ -29,9 +34,47 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
29
34
  .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
30
35
  .before(extensionsHelper_1.diagnoseAndFixProject)
31
36
  .action(async (instanceId, options) => {
37
+ var _a;
38
+ const projectId = (0, projectUtils_1.needProjectId)(options);
39
+ if (options.local) {
40
+ if (options.nonInteractive) {
41
+ throw new error_1.FirebaseError(`Command not supported in non-interactive mode, edit ./extensions/${instanceId}.env directly instead`);
42
+ }
43
+ const config = manifest.loadConfig(options);
44
+ const targetRef = manifest.getInstanceRef(instanceId, config);
45
+ const extensionVersion = await extensionsApi.getExtensionVersion(refs.toExtensionVersionRef(targetRef));
46
+ const oldParamValues = manifest.readInstanceParam({
47
+ instanceId,
48
+ projectDir: config.projectDir,
49
+ });
50
+ const [immutableParams, tbdParams] = (0, functional_1.partition)(extensionVersion.spec.params, (param) => { var _a; return (_a = param.immutable) !== null && _a !== void 0 ? _a : false; });
51
+ infoImmutableParams(immutableParams, oldParamValues);
52
+ paramHelper.setNewDefaults(tbdParams, oldParamValues);
53
+ const mutableParamsBindingOptions = await paramHelper.getParams({
54
+ projectId,
55
+ paramSpecs: tbdParams,
56
+ nonInteractive: false,
57
+ paramsEnvPath: ((_a = options.params) !== null && _a !== void 0 ? _a : ""),
58
+ instanceId,
59
+ reconfiguring: true,
60
+ });
61
+ const newParamOptions = Object.assign(Object.assign({}, (0, paramHelper_1.buildBindingOptionsWithBaseValue)(oldParamValues)), mutableParamsBindingOptions);
62
+ await manifest.writeToManifest([
63
+ {
64
+ instanceId,
65
+ ref: targetRef,
66
+ params: newParamOptions,
67
+ paramSpecs: extensionVersion.spec.params,
68
+ },
69
+ ], config, {
70
+ nonInteractive: false,
71
+ force: true,
72
+ });
73
+ manifest.showPreviewWarning();
74
+ return;
75
+ }
32
76
  const spinner = ora(`Configuring ${clc.bold(instanceId)}. This usually takes 3 to 5 minutes...`);
33
77
  try {
34
- const projectId = (0, projectUtils_1.needProjectId)(options);
35
78
  let existingInstance;
36
79
  try {
37
80
  existingInstance = await extensionsApi.getInstance(projectId, instanceId);
@@ -45,10 +88,8 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
45
88
  throw err;
46
89
  }
47
90
  const paramSpecWithNewDefaults = paramHelper.getParamsWithCurrentValuesAsDefaults(existingInstance);
48
- const immutableParams = _.remove(paramSpecWithNewDefaults, (param) => {
49
- return param.immutable || param.param === "LOCATION";
50
- });
51
- const params = await paramHelper.getParams({
91
+ const immutableParams = _.remove(paramSpecWithNewDefaults, (param) => param.immutable);
92
+ const paramBindingOptions = await paramHelper.getParams({
52
93
  projectId,
53
94
  paramSpecs: paramSpecWithNewDefaults,
54
95
  nonInteractive: options.nonInteractive,
@@ -56,13 +97,14 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
56
97
  instanceId,
57
98
  reconfiguring: true,
58
99
  });
100
+ const paramBindings = (0, paramHelper_1.getBaseParamBindings)(paramBindingOptions);
59
101
  if (immutableParams.length) {
60
102
  const plural = immutableParams.length > 1;
61
103
  logger_1.logger.info(`The following param${plural ? "s are" : " is"} immutable:`);
62
104
  for (const { param } of immutableParams) {
63
105
  const value = _.get(existingInstance, `config.params.${param}`);
64
106
  logger_1.logger.info(`param: ${param}, value: ${value}`);
65
- params[param] = value;
107
+ paramBindings[param] = value;
66
108
  }
67
109
  logger_1.logger.info((plural
68
110
  ? "To set different values for these params"
@@ -70,10 +112,15 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
70
112
  ", uninstall the extension, then install a new instance of this extension.");
71
113
  }
72
114
  spinner.start();
73
- const res = await extensionsApi.configureInstance({ projectId, instanceId, params });
115
+ const res = await extensionsApi.configureInstance({
116
+ projectId,
117
+ instanceId,
118
+ params: paramBindings,
119
+ });
74
120
  spinner.stop();
75
121
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `successfully configured ${clc.bold(instanceId)}.`);
76
122
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`You can view your reconfigured instance in the Firebase console: ${utils.consoleUrl(projectId, `/extensions/instances/${instanceId}?tab=config`)}`));
123
+ manifest.showDeprecationWarning();
77
124
  return res;
78
125
  }
79
126
  catch (err) {
@@ -88,3 +135,17 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
88
135
  throw err;
89
136
  }
90
137
  });
138
+ function infoImmutableParams(immutableParams, paramValues) {
139
+ if (!immutableParams.length) {
140
+ return;
141
+ }
142
+ const plural = immutableParams.length > 1;
143
+ utils.logLabeledWarning(extensionsHelper_1.logPrefix, marked(`The following param${plural ? "s are" : " is"} immutable and won't be changed:`));
144
+ for (const { param } of immutableParams) {
145
+ logger_1.logger.info(`param: ${param}, value: ${paramValues[param]}`);
146
+ }
147
+ logger_1.logger.info((plural
148
+ ? "To set different values for these params"
149
+ : "To set a different value for this param") +
150
+ ", uninstall the extension, then install a new instance of this extension.");
151
+ }
@@ -2,12 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const checkMinRequiredVersion_1 = require("../checkMinRequiredVersion");
4
4
  const command_1 = require("../command");
5
- const config_1 = require("../config");
6
5
  const planner = require("../deploy/extensions/planner");
7
- const error_1 = require("../error");
8
6
  const export_1 = require("../extensions/export");
9
7
  const extensionsHelper_1 = require("../extensions/extensionsHelper");
10
- const manifest_1 = require("../extensions/manifest");
8
+ const manifest = require("../extensions/manifest");
9
+ const paramHelper_1 = require("../extensions/paramHelper");
11
10
  const functional_1 = require("../functional");
12
11
  const getProjectNumber_1 = require("../getProjectNumber");
13
12
  const logger_1 = require("../logger");
@@ -43,12 +42,14 @@ module.exports = new command_1.Command("ext:export")
43
42
  logger_1.logger.info("Exiting. No changes made.");
44
43
  return;
45
44
  }
46
- const existingConfig = config_1.Config.load(options, true);
47
- if (!existingConfig) {
48
- throw new error_1.FirebaseError("Not currently in a Firebase directory. Please run `firebase init` to create a Firebase directory.");
49
- }
50
- await (0, manifest_1.writeToManifest)(withRef, existingConfig, {
45
+ const manifestSpecs = withRef.map((spec) => ({
46
+ instanceId: spec.instanceId,
47
+ ref: spec.ref,
48
+ params: (0, paramHelper_1.buildBindingOptionsWithBaseValue)(spec.params),
49
+ }));
50
+ const existingConfig = manifest.loadConfig(options);
51
+ await manifest.writeToManifest(manifestSpecs, existingConfig, {
51
52
  nonInteractive: options.nonInteractive,
52
53
  force: options.force,
53
- });
54
+ }, true);
54
55
  });
@@ -27,6 +27,8 @@ const utils = require("../utils");
27
27
  const track_1 = require("../track");
28
28
  const logger_1 = require("../logger");
29
29
  const previews_1 = require("../previews");
30
+ const manifest = require("../extensions/manifest");
31
+ const paramHelper_1 = require("../extensions/paramHelper");
30
32
  marked.setOptions({
31
33
  renderer: new TerminalRenderer(),
32
34
  });
@@ -38,13 +40,15 @@ exports.default = new command_1.Command("ext:install [extensionName]")
38
40
  "or run with `-i` to see all available extensions.")
39
41
  .withForce()
40
42
  .option("--params <paramsFile>", "name of params variables file with .env format.")
43
+ .option("--local", "save to firebase.json rather than directly install to a Firebase project")
41
44
  .before(requirePermissions_1.requirePermissions, ["firebaseextensions.instances.create"])
42
45
  .before(extensionsHelper_1.ensureExtensionsApiEnabled)
43
46
  .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
44
47
  .before(extensionsHelper_1.diagnoseAndFixProject)
45
48
  .action(async (extensionName, options) => {
49
+ var _a;
46
50
  const projectId = (0, projectUtils_1.needProjectId)(options);
47
- const paramsEnvPath = options.params;
51
+ const paramsEnvPath = ((_a = options.params) !== null && _a !== void 0 ? _a : "");
48
52
  let learnMore = false;
49
53
  if (!extensionName) {
50
54
  if (options.interactive) {
@@ -59,12 +63,18 @@ exports.default = new command_1.Command("ext:install [extensionName]")
59
63
  }
60
64
  let source;
61
65
  let extVersion;
66
+ if ((0, extensionsHelper_1.isUrlPath)(extensionName)) {
67
+ void (0, track_1.track)("Extension Install", "Install by url path", options.interactive ? 1 : 0);
68
+ }
62
69
  if ((0, extensionsHelper_1.isLocalOrURLPath)(extensionName)) {
63
- (0, track_1.track)("Extension Install", "Install by Source", options.interactive ? 1 : 0);
70
+ void (0, track_1.track)("Extension Install", "Install by Source", options.interactive ? 1 : 0);
71
+ if (options.local) {
72
+ throw new error_1.FirebaseError("Installing a local source locally is not supported yet, please use ext:dev:emulator commands");
73
+ }
64
74
  source = await infoInstallBySource(projectId, extensionName);
65
75
  }
66
76
  else {
67
- (0, track_1.track)("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0);
77
+ void (0, track_1.track)("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0);
68
78
  extVersion = await infoInstallByReference(extensionName, options.interactive);
69
79
  }
70
80
  if (!(await (0, extensionsHelper_1.confirm)({
@@ -86,6 +96,27 @@ exports.default = new command_1.Command("ext:install [extensionName]")
86
96
  `${spec.description}\n` +
87
97
  `View details: https://firebase.google.com/products/extensions/${spec.name}\n`);
88
98
  }
99
+ if (options.local) {
100
+ try {
101
+ return installToManifest({
102
+ paramsEnvPath,
103
+ projectId,
104
+ extensionName,
105
+ source,
106
+ extVersion,
107
+ nonInteractive: options.nonInteractive,
108
+ force: options.force,
109
+ });
110
+ }
111
+ catch (err) {
112
+ if (!(err instanceof error_1.FirebaseError)) {
113
+ throw new error_1.FirebaseError(`Error occurred saving the extension to manifest: ${err.message}`, {
114
+ original: err,
115
+ });
116
+ }
117
+ throw err;
118
+ }
119
+ }
89
120
  try {
90
121
  return installExtension({
91
122
  paramsEnvPath,
@@ -126,7 +157,7 @@ async function infoInstallByReference(extensionName, interactive) {
126
157
  const ref = refs.parse(extensionName);
127
158
  const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
128
159
  if (!ref.version) {
129
- (0, track_1.track)("Extension Install", "Install by Extension Version Ref", interactive ? 1 : 0);
160
+ void (0, track_1.track)("Extension Install", "Install by Extension Version Ref", interactive ? 1 : 0);
130
161
  extensionName = `${extensionName}@latest`;
131
162
  }
132
163
  const extVersion = await extensionsApi.getExtensionVersion(extensionName);
@@ -134,6 +165,35 @@ async function infoInstallByReference(extensionName, interactive) {
134
165
  await (0, warnings_1.displayWarningPrompts)(ref.publisherId, extension.registryLaunchStage, extVersion);
135
166
  return extVersion;
136
167
  }
168
+ async function installToManifest(options) {
169
+ const { projectId, extensionName, extVersion, paramsEnvPath, nonInteractive, force } = options;
170
+ const spec = extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec;
171
+ if (!spec) {
172
+ throw new error_1.FirebaseError(`Could not find the extension.yaml for ${extensionName}. Please make sure this is a valid extension and try again.`);
173
+ }
174
+ const config = manifest.loadConfig(options);
175
+ let instanceId = spec.name;
176
+ while (manifest.instanceExists(instanceId, config)) {
177
+ instanceId = await (0, extensionsHelper_1.promptForValidInstanceId)(`${spec.name}-${(0, utils_1.getRandomString)(4)}`);
178
+ }
179
+ const paramBindingOptions = await paramHelper.getParams({
180
+ projectId,
181
+ paramSpecs: spec.params,
182
+ nonInteractive,
183
+ paramsEnvPath,
184
+ instanceId,
185
+ });
186
+ const ref = refs.parse(extVersion.ref);
187
+ await manifest.writeToManifest([
188
+ {
189
+ instanceId,
190
+ ref,
191
+ params: paramBindingOptions,
192
+ paramSpecs: spec.params,
193
+ },
194
+ ], config, { nonInteractive, force: force !== null && force !== void 0 ? force : false });
195
+ manifest.showPreviewWarning();
196
+ }
137
197
  async function installExtension(options) {
138
198
  const { projectId, extensionName, source, extVersion, paramsEnvPath, nonInteractive, force } = options;
139
199
  const spec = (source === null || source === void 0 ? void 0 : source.spec) || (extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec);
@@ -201,17 +261,19 @@ async function installExtension(options) {
201
261
  else {
202
262
  choice = "installNew";
203
263
  }
204
- let params;
264
+ let paramBindingOptions;
265
+ let paramBindings;
205
266
  switch (choice) {
206
267
  case "installNew":
207
268
  instanceId = await (0, extensionsHelper_1.promptForValidInstanceId)(`${instanceId}-${(0, utils_1.getRandomString)(4)}`);
208
- params = await paramHelper.getParams({
269
+ paramBindingOptions = await paramHelper.getParams({
209
270
  projectId,
210
271
  paramSpecs: spec.params,
211
272
  nonInteractive,
212
273
  paramsEnvPath,
213
274
  instanceId,
214
275
  });
276
+ paramBindings = (0, paramHelper_1.getBaseParamBindings)(paramBindingOptions);
215
277
  spinner.text = "Installing your extension instance. This usually takes 3 to 5 minutes...";
216
278
  spinner.start();
217
279
  await extensionsApi.createInstance({
@@ -219,20 +281,21 @@ async function installExtension(options) {
219
281
  instanceId,
220
282
  extensionSource: source,
221
283
  extensionVersionRef: extVersion === null || extVersion === void 0 ? void 0 : extVersion.ref,
222
- params,
284
+ params: paramBindings,
223
285
  });
224
286
  spinner.stop();
225
287
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `Successfully installed your instance of ${clc.bold(spec.displayName || spec.name)}! ` +
226
288
  `Its Instance ID is ${clc.bold(instanceId)}.`);
227
289
  break;
228
290
  case "updateExisting":
229
- params = await paramHelper.getParams({
291
+ paramBindingOptions = await paramHelper.getParams({
230
292
  projectId,
231
293
  paramSpecs: spec.params,
232
294
  nonInteractive,
233
295
  paramsEnvPath,
234
296
  instanceId,
235
297
  });
298
+ paramBindings = (0, paramHelper_1.getBaseParamBindings)(paramBindingOptions);
236
299
  spinner.text = "Updating your extension instance. This usually takes 3 to 5 minutes...";
237
300
  spinner.start();
238
301
  await (0, updateHelper_1.update)({
@@ -240,7 +303,7 @@ async function installExtension(options) {
240
303
  instanceId,
241
304
  source,
242
305
  extRef: extVersion === null || extVersion === void 0 ? void 0 : extVersion.ref,
243
- params,
306
+ params: paramBindings,
244
307
  });
245
308
  spinner.stop();
246
309
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `Successfully updated your instance of ${clc.bold(spec.displayName || spec.name)}! ` +
@@ -253,6 +316,7 @@ async function installExtension(options) {
253
316
  `which may include some required post-installation tasks: ${utils.consoleUrl(projectId, `/extensions/instances/${instanceId}?tab=usage`)}`));
254
317
  logger_1.logger.info(marked("You can run `firebase ext` to view available Firebase Extensions commands, " +
255
318
  "including those to update, reconfigure, or delete your installed extension."));
319
+ manifest.showDeprecationWarning();
256
320
  }
257
321
  catch (err) {
258
322
  if (spinner.isSpinning) {
@@ -16,17 +16,25 @@ const prompt_1 = require("../prompt");
16
16
  const requirePermissions_1 = require("../requirePermissions");
17
17
  const utils = require("../utils");
18
18
  const logger_1 = require("../logger");
19
+ const manifest = require("../extensions/manifest");
19
20
  marked.setOptions({
20
21
  renderer: new TerminalRenderer(),
21
22
  });
22
23
  exports.default = new command_1.Command("ext:uninstall <extensionInstanceId>")
23
24
  .description("uninstall an extension that is installed in your Firebase project by instance ID")
24
25
  .withForce()
26
+ .option("--local", "remove from firebase.json rather than directly uninstall from a Firebase project")
25
27
  .before(requirePermissions_1.requirePermissions, ["firebaseextensions.instances.delete"])
26
28
  .before(extensionsHelper_1.ensureExtensionsApiEnabled)
27
29
  .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
28
30
  .before(extensionsHelper_1.diagnoseAndFixProject)
29
31
  .action(async (instanceId, options) => {
32
+ if (options.local) {
33
+ const config = manifest.loadConfig(options);
34
+ manifest.removeFromManifest(instanceId, config);
35
+ manifest.showPreviewWarning();
36
+ return;
37
+ }
30
38
  const projectId = (0, projectUtils_1.needProjectId)(options);
31
39
  let instance;
32
40
  try {
@@ -93,6 +101,7 @@ exports.default = new command_1.Command("ext:uninstall <extensionInstanceId>")
93
101
  return utils.reject(`Error occurred uninstalling extension ${instanceId}`, { original: err });
94
102
  }
95
103
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `uninstalled ${clc.bold(instanceId)}`);
104
+ manifest.showDeprecationWarning();
96
105
  });
97
106
  function consoleUninstallOnly(projectId, instanceId) {
98
107
  const instanceURL = `https://console.firebase.google.com/project/${projectId}/extensions/instances/${instanceId}`;
@@ -22,6 +22,7 @@ const projectUtils_1 = require("../projectUtils");
22
22
  const requirePermissions_1 = require("../requirePermissions");
23
23
  const utils = require("../utils");
24
24
  const previews_1 = require("../previews");
25
+ const manifest = require("../extensions/manifest");
25
26
  marked.setOptions({
26
27
  renderer: new TerminalRenderer(),
27
28
  });
@@ -38,10 +39,62 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
38
39
  .before(extensionsHelper_1.diagnoseAndFixProject)
39
40
  .withForce()
40
41
  .option("--params <paramsFile>", "name of params variables file with .env format.")
42
+ .option("--local", "save the update to firebase.json rather than directly update an existing Extension instance on a Firebase project")
41
43
  .action(async (instanceId, updateSource, options) => {
44
+ var _a, _b;
45
+ const projectId = (0, projectUtils_1.needProjectId)(options);
46
+ if (options.local) {
47
+ const config = manifest.loadConfig(options);
48
+ const oldRef = manifest.getInstanceRef(instanceId, config);
49
+ const oldExtensionVersion = await extensionsApi.getExtensionVersion(refs.toExtensionVersionRef(oldRef));
50
+ updateSource = (0, updateHelper_1.inferUpdateSource)(updateSource, refs.toExtensionRef(oldRef));
51
+ const newSourceOrigin = (0, extensionsHelper_1.getSourceOrigin)(updateSource);
52
+ if (![extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION, extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION_VERSION].includes(newSourceOrigin)) {
53
+ throw new error_1.FirebaseError(`Only updating to a published extension version is allowed`);
54
+ }
55
+ const newExtensionVersion = await extensionsApi.getExtensionVersion(updateSource);
56
+ if (oldExtensionVersion.ref === newExtensionVersion.ref) {
57
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, `${clc.bold(instanceId)} is already up to date. Its version is ${clc.bold(newExtensionVersion.ref)}.`);
58
+ return;
59
+ }
60
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, `Updating ${clc.bold(instanceId)} from version ${clc.bold(oldExtensionVersion.ref)} to version ${clc.bold(newExtensionVersion.ref)}.`);
61
+ if (!(await (0, extensionsHelper_1.confirm)({
62
+ nonInteractive: options.nonInteractive,
63
+ force: options.force,
64
+ default: false,
65
+ }))) {
66
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, "Update aborted.");
67
+ return;
68
+ }
69
+ const oldParamValues = manifest.readInstanceParam({
70
+ instanceId,
71
+ projectDir: config.projectDir,
72
+ });
73
+ const newParamBindingOptions = await paramHelper.getParamsForUpdate({
74
+ spec: oldExtensionVersion.spec,
75
+ newSpec: newExtensionVersion.spec,
76
+ currentParams: oldParamValues,
77
+ projectId,
78
+ paramsEnvPath: ((_a = options.params) !== null && _a !== void 0 ? _a : ""),
79
+ nonInteractive: options.nonInteractive,
80
+ instanceId,
81
+ });
82
+ await manifest.writeToManifest([
83
+ {
84
+ instanceId,
85
+ ref: refs.parse(newExtensionVersion.ref),
86
+ params: newParamBindingOptions,
87
+ paramSpecs: newExtensionVersion.spec.params,
88
+ },
89
+ ], config, {
90
+ nonInteractive: options.nonInteractive,
91
+ force: true,
92
+ });
93
+ manifest.showPreviewWarning();
94
+ return;
95
+ }
42
96
  const spinner = ora(`Updating ${clc.bold(instanceId)}. This usually takes 3 to 5 minutes...`);
43
97
  try {
44
- const projectId = (0, projectUtils_1.needProjectId)(options);
45
98
  let existingInstance;
46
99
  try {
47
100
  existingInstance = await extensionsApi.getInstance(projectId, instanceId);
@@ -143,15 +196,16 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
143
196
  }
144
197
  }
145
198
  const oldParamValues = Object.assign({}, existingParams);
146
- const newParams = await paramHelper.getParamsForUpdate({
199
+ const newParamBindings = await paramHelper.getParamsForUpdate({
147
200
  spec: existingSpec,
148
201
  newSpec,
149
202
  currentParams: existingParams,
150
203
  projectId,
151
- paramsEnvPath: options.params,
204
+ paramsEnvPath: ((_b = options.params) !== null && _b !== void 0 ? _b : ""),
152
205
  nonInteractive: options.nonInteractive,
153
206
  instanceId,
154
207
  });
208
+ const newParams = paramHelper.getBaseParamBindings(newParamBindings);
155
209
  spinner.start();
156
210
  const updateOptions = {
157
211
  projectId,
@@ -170,6 +224,7 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
170
224
  spinner.stop();
171
225
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `successfully updated ${clc.bold(instanceId)}.`);
172
226
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`You can view your updated instance in the Firebase console: ${utils.consoleUrl(projectId, `/extensions/instances/${instanceId}?tab=usage`)}`));
227
+ manifest.showDeprecationWarning();
173
228
  }
174
229
  catch (err) {
175
230
  if (spinner.isSpinning) {
@@ -12,7 +12,7 @@ const requirePermissions_1 = require("../requirePermissions");
12
12
  const utils_1 = require("../utils");
13
13
  const functional_1 = require("../functional");
14
14
  const configExport = require("../functions/runtimeConfigExport");
15
- const requireConfig = require("../requireConfig");
15
+ const requireConfig_1 = require("../requireConfig");
16
16
  const REQUIRED_PERMISSIONS = [
17
17
  "runtimeconfig.configs.list",
18
18
  "runtimeconfig.configs.get",
@@ -76,7 +76,7 @@ exports.default = new command_1.Command("functions:config:export")
76
76
  "runtimeconfig.variables.list",
77
77
  "runtimeconfig.variables.get",
78
78
  ])
79
- .before(requireConfig)
79
+ .before(requireConfig_1.requireConfig)
80
80
  .before(requireInteractive_1.default)
81
81
  .action(async (options) => {
82
82
  let pInfos = configExport.getProjectInfos(options);
@@ -2,7 +2,7 @@
2
2
  var { Command } = require("../command");
3
3
  var { requirePermissions } = require("../requirePermissions");
4
4
  var { actionFunction } = require("../functionsShellCommandAction");
5
- var requireConfig = require("../requireConfig");
5
+ var { requireConfig } = require("../requireConfig");
6
6
  var commandUtils = require("../emulator/commandUtils");
7
7
  module.exports = new Command("functions:shell")
8
8
  .description("launch full Node shell with emulated functions")
@@ -10,7 +10,7 @@ const prompt_1 = require("../prompt");
10
10
  const requirePermissions_1 = require("../requirePermissions");
11
11
  const projectUtils_1 = require("../projectUtils");
12
12
  const logger_1 = require("../logger");
13
- const requireConfig = require("../requireConfig");
13
+ const requireConfig_1 = require("../requireConfig");
14
14
  const { marked } = require("marked");
15
15
  const requireHostingSite_1 = require("../requireHostingSite");
16
16
  const LOG_TAG = "hosting:channel";
@@ -18,7 +18,7 @@ exports.default = new command_1.Command("hosting:channel:create [channelId]")
18
18
  .description("create a Firebase Hosting channel")
19
19
  .option("-e, --expires <duration>", "duration string (e.g. 12h or 30d) for channel expiration, max 30d")
20
20
  .option("--site <siteId>", "site for which to create the channel")
21
- .before(requireConfig)
21
+ .before(requireConfig_1.requireConfig)
22
22
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
23
23
  .before(requireHostingSite_1.requireHostingSite)
24
24
  .action(async (channelId, options) => {
@@ -9,13 +9,13 @@ const prompt_1 = require("../prompt");
9
9
  const requireHostingSite_1 = require("../requireHostingSite");
10
10
  const requirePermissions_1 = require("../requirePermissions");
11
11
  const projectUtils_1 = require("../projectUtils");
12
- const requireConfig = require("../requireConfig");
12
+ const requireConfig_1 = require("../requireConfig");
13
13
  const logger_1 = require("../logger");
14
14
  exports.default = new command_1.Command("hosting:channel:delete <channelId>")
15
15
  .description("delete a Firebase Hosting channel")
16
16
  .withForce()
17
17
  .option("--site <siteId>", "site in which the channel exists")
18
- .before(requireConfig)
18
+ .before(requireConfig_1.requireConfig)
19
19
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
20
20
  .before(requireHostingSite_1.requireHostingSite)
21
21
  .action(async (channelId, options) => {
@@ -9,7 +9,7 @@ const requirePermissions_1 = require("../requirePermissions");
9
9
  const deploy = require("../deploy");
10
10
  const projectUtils_1 = require("../projectUtils");
11
11
  const logger_1 = require("../logger");
12
- const requireConfig = require("../requireConfig");
12
+ const requireConfig_1 = require("../requireConfig");
13
13
  const expireUtils_1 = require("../hosting/expireUtils");
14
14
  const utils_1 = require("../utils");
15
15
  const { marked } = require("marked");
@@ -21,7 +21,7 @@ exports.default = new command_1.Command("hosting:channel:deploy [channelId]")
21
21
  .option("--only <target1,target2...>", "only create previews for specified targets")
22
22
  .option("--open", "open a browser to the channel after deploying")
23
23
  .option("--no-authorized-domains", "do not sync channel domains with Firebase Auth")
24
- .before(requireConfig)
24
+ .before(requireConfig_1.requireConfig)
25
25
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
26
26
  .before(requireHostingSite_1.requireHostingSite)
27
27
  .action(async (channelId, options) => {
@@ -7,14 +7,14 @@ const command_1 = require("../command");
7
7
  const requirePermissions_1 = require("../requirePermissions");
8
8
  const projectUtils_1 = require("../projectUtils");
9
9
  const logger_1 = require("../logger");
10
- const requireConfig = require("../requireConfig");
10
+ const requireConfig_1 = require("../requireConfig");
11
11
  const utils_1 = require("../utils");
12
12
  const requireHostingSite_1 = require("../requireHostingSite");
13
13
  const TABLE_HEAD = ["Channel ID", "Last Release Time", "URL", "Expire Time"];
14
14
  exports.default = new command_1.Command("hosting:channel:list")
15
15
  .description("list all Firebase Hosting channels for your project")
16
16
  .option("--site <siteName>", "list channels for the specified site")
17
- .before(requireConfig)
17
+ .before(requireConfig_1.requireConfig)
18
18
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
19
19
  .before(requireHostingSite_1.requireHostingSite)
20
20
  .action(async (options) => {
@@ -8,7 +8,7 @@ const error_1 = require("../error");
8
8
  const api_1 = require("../hosting/api");
9
9
  const requirePermissions_1 = require("../requirePermissions");
10
10
  const projectUtils_1 = require("../projectUtils");
11
- const requireConfig = require("../requireConfig");
11
+ const requireConfig_1 = require("../requireConfig");
12
12
  const utils_1 = require("../utils");
13
13
  const prompt_1 = require("../prompt");
14
14
  const requireHostingSite_1 = require("../requireHostingSite");
@@ -16,7 +16,7 @@ exports.default = new command_1.Command("hosting:channel:open [channelId]")
16
16
  .description("opens the URL for a Firebase Hosting channel")
17
17
  .help("if unable to open the URL in a browser, it will be displayed in the output")
18
18
  .option("--site <siteId>", "the site to which the channel belongs")
19
- .before(requireConfig)
19
+ .before(requireConfig_1.requireConfig)
20
20
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.get"])
21
21
  .before(requireHostingSite_1.requireHostingSite)
22
22
  .action(async (channelId, options) => {
@@ -8,13 +8,13 @@ const prompt_1 = require("../prompt");
8
8
  const error_1 = require("../error");
9
9
  const requirePermissions_1 = require("../requirePermissions");
10
10
  const projectUtils_1 = require("../projectUtils");
11
- const requireConfig = require("../requireConfig");
11
+ const requireConfig_1 = require("../requireConfig");
12
12
  const logger_1 = require("../logger");
13
13
  const LOG_TAG = "hosting:sites";
14
14
  exports.default = new command_1.Command("hosting:sites:delete <siteId>")
15
15
  .description("delete a Firebase Hosting site")
16
16
  .withForce()
17
- .before(requireConfig)
17
+ .before(requireConfig_1.requireConfig)
18
18
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.delete"])
19
19
  .action(async (siteId, options) => {
20
20
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -5,7 +5,7 @@ var { Command } = require("../command");
5
5
  const { logger } = require("../logger");
6
6
  var utils = require("../utils");
7
7
  var { requirePermissions } = require("../requirePermissions");
8
- var requireConfig = require("../requireConfig");
8
+ var { requireConfig } = require("../requireConfig");
9
9
  var { serve } = require("../serve/index");
10
10
  var { filterTargets } = require("../filterTargets");
11
11
  var { needProjectNumber } = require("../projectUtils");