firebase-tools 10.2.1 → 10.2.2

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 (105) hide show
  1. package/lib/appdistribution/options-parser-util.js +1 -1
  2. package/lib/auth.js +3 -3
  3. package/lib/command.js +1 -1
  4. package/lib/commands/apps-android-sha-create.js +2 -2
  5. package/lib/commands/apps-sdkconfig.js +1 -1
  6. package/lib/commands/database-rules-list.js +2 -2
  7. package/lib/commands/emulators-start.js +1 -1
  8. package/lib/commands/ext-dev-init.js +49 -49
  9. package/lib/commands/ext-export.js +12 -2
  10. package/lib/commands/ext-install.js +104 -104
  11. package/lib/commands/ext-uninstall.js +8 -8
  12. package/lib/commands/ext-update.js +9 -9
  13. package/lib/commands/functions-config-export.js +1 -1
  14. package/lib/commands/hosting-clone.js +3 -3
  15. package/lib/commands/remoteconfig-get.js +1 -1
  16. package/lib/deploy/extensions/deploymentSummary.js +3 -3
  17. package/lib/deploy/extensions/params.js +3 -0
  18. package/lib/deploy/extensions/planner.js +2 -1
  19. package/lib/deploy/extensions/tasks.js +1 -1
  20. package/lib/deploy/functions/backend.js +12 -5
  21. package/lib/deploy/functions/checkIam.js +1 -1
  22. package/lib/deploy/functions/containerCleaner.js +3 -3
  23. package/lib/deploy/functions/ensure.js +3 -3
  24. package/lib/deploy/functions/functionsDeployHelper.js +2 -2
  25. package/lib/deploy/functions/prepare.js +3 -2
  26. package/lib/deploy/functions/pricing.js +1 -1
  27. package/lib/deploy/functions/prompts.js +2 -2
  28. package/lib/deploy/functions/release/fabricator.js +3 -3
  29. package/lib/deploy/functions/release/index.js +1 -1
  30. package/lib/deploy/functions/release/planner.js +11 -8
  31. package/lib/deploy/functions/release/reporter.js +3 -0
  32. package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
  33. package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
  34. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +16 -11
  35. package/lib/deploy/functions/runtimes/golang/index.js +2 -2
  36. package/lib/deploy/functions/runtimes/node/index.js +26 -0
  37. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
  38. package/lib/deploy/functions/runtimes/node/parseTriggers.js +28 -7
  39. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  40. package/lib/deploy/functions/validate.js +3 -3
  41. package/lib/deploy/hosting/deploy.js +2 -2
  42. package/lib/deploy/hosting/hashcache.js +21 -19
  43. package/lib/deploy/hosting/uploader.js +5 -5
  44. package/lib/deploy/remoteconfig/functions.js +2 -2
  45. package/lib/emulator/auth/cloudFunctions.js +1 -1
  46. package/lib/emulator/auth/operations.js +1 -1
  47. package/lib/emulator/constants.js +3 -0
  48. package/lib/emulator/controller.js +47 -19
  49. package/lib/emulator/download.js +18 -1
  50. package/lib/emulator/downloadableEmulators.js +1 -1
  51. package/lib/emulator/emulatorLogger.js +12 -1
  52. package/lib/emulator/extensions/validation.js +35 -0
  53. package/lib/emulator/extensionsEmulator.js +140 -0
  54. package/lib/emulator/functionsEmulator.js +86 -39
  55. package/lib/emulator/functionsEmulatorRuntime.js +44 -36
  56. package/lib/emulator/functionsEmulatorShell.js +1 -1
  57. package/lib/emulator/functionsEmulatorUtils.js +4 -4
  58. package/lib/emulator/functionsRuntimeWorker.js +2 -2
  59. package/lib/emulator/hub.js +4 -3
  60. package/lib/emulator/loggingEmulator.js +1 -1
  61. package/lib/emulator/pubsubEmulator.js +1 -1
  62. package/lib/emulator/registry.js +10 -2
  63. package/lib/emulator/storage/apis/firebase.js +31 -26
  64. package/lib/emulator/storage/apis/gcloud.js +7 -12
  65. package/lib/emulator/storage/files.js +36 -34
  66. package/lib/emulator/storage/index.js +2 -2
  67. package/lib/emulator/storage/metadata.js +2 -2
  68. package/lib/emulator/storage/rules/runtime.js +8 -7
  69. package/lib/emulator/types.js +3 -0
  70. package/lib/ensureApiEnabled.js +5 -1
  71. package/lib/error.js +1 -1
  72. package/lib/extensions/askUserForParam.js +1 -1
  73. package/lib/extensions/changelog.js +3 -1
  74. package/lib/extensions/checkProjectBilling.js +1 -1
  75. package/lib/extensions/displayExtensionInfo.js +1 -1
  76. package/lib/extensions/emulator/optionsHelper.js +24 -8
  77. package/lib/extensions/emulator/specHelper.js +10 -23
  78. package/lib/extensions/export.js +1 -51
  79. package/lib/extensions/extensionsApi.js +1 -1
  80. package/lib/extensions/extensionsHelper.js +13 -9
  81. package/lib/extensions/manifest.js +48 -0
  82. package/lib/extensions/metricsUtils.js +4 -4
  83. package/lib/extensions/paramHelper.js +4 -4
  84. package/lib/extensions/refs.js +1 -1
  85. package/lib/extensions/secretsUtils.js +3 -3
  86. package/lib/functional.js +1 -1
  87. package/lib/functions/env.js +2 -1
  88. package/lib/gcp/cloudfunctions.js +24 -5
  89. package/lib/gcp/cloudfunctionsv2.js +18 -5
  90. package/lib/gcp/cloudtasks.js +1 -1
  91. package/lib/gcp/docker.js +2 -2
  92. package/lib/gcp/run.js +2 -2
  93. package/lib/hosting/api.js +1 -1
  94. package/lib/hosting/proxy.js +2 -2
  95. package/lib/init/features/account.js +1 -1
  96. package/lib/management/database.js +1 -1
  97. package/lib/previews.js +1 -1
  98. package/lib/utils.js +1 -1
  99. package/npm-shrinkwrap.json +786 -393
  100. package/package.json +1 -1
  101. package/schema/firebase-config.json +5 -0
  102. package/templates/init/functions/javascript/package.lint.json +3 -3
  103. package/templates/init/functions/javascript/package.nolint.json +2 -2
  104. package/templates/init/functions/typescript/package.lint.json +7 -7
  105. package/templates/init/functions/typescript/package.nolint.json +3 -3
@@ -16,7 +16,7 @@ function getTestersOrGroups(value, file) {
16
16
  }
17
17
  exports.getTestersOrGroups = getTestersOrGroups;
18
18
  function getEmails(emails, file) {
19
- if (emails.length == 0) {
19
+ if (emails.length === 0) {
20
20
  ensureFileExists(file);
21
21
  const readFile = fs.readFileSync(file, "utf8");
22
22
  return splitter(readFile);
package/lib/auth.js CHANGED
@@ -291,7 +291,7 @@ async function loginRemotely(userHint) {
291
291
  });
292
292
  try {
293
293
  const tokens = await getTokensFromAuthorizationCode(code, `${api.authProxyOrigin}/complete`, codeVerifier);
294
- (0, track_1.track)("login", "google_remote");
294
+ void (0, track_1.track)("login", "google_remote");
295
295
  return {
296
296
  user: jwt.decode(tokens.id_token),
297
297
  tokens: tokens,
@@ -307,7 +307,7 @@ async function loginWithLocalhostGoogle(port, userHint) {
307
307
  const authUrl = getLoginUrl(callbackUrl, userHint);
308
308
  const successTemplate = "../templates/loginSuccess.html";
309
309
  const tokens = await loginWithLocalhost(port, callbackUrl, authUrl, successTemplate, getTokensFromAuthorizationCode);
310
- (0, track_1.track)("login", "google_localhost");
310
+ void (0, track_1.track)("login", "google_localhost");
311
311
  return {
312
312
  user: jwt.decode(tokens.id_token),
313
313
  tokens: tokens,
@@ -319,7 +319,7 @@ async function loginWithLocalhostGitHub(port) {
319
319
  const authUrl = getGithubLoginUrl(callbackUrl);
320
320
  const successTemplate = "../templates/loginSuccessGithub.html";
321
321
  const tokens = await loginWithLocalhost(port, callbackUrl, authUrl, successTemplate, getGithubTokensFromAuthorizationCode);
322
- (0, track_1.track)("login", "google_localhost");
322
+ void (0, track_1.track)("login", "google_localhost");
323
323
  return tokens;
324
324
  }
325
325
  async function loginWithLocalhost(port, callbackUrl, authUrl, successTemplate, getTokens) {
package/lib/command.js CHANGED
@@ -85,7 +85,7 @@ class Command {
85
85
  }, null, 2));
86
86
  }
87
87
  const duration = new Date().getTime() - start;
88
- track(this.name, "success", duration).then(() => process.exit());
88
+ void track(this.name, "success", duration).then(() => process.exit());
89
89
  })
90
90
  .catch(async (err) => {
91
91
  if ((0, utils_1.getInheritedOption)(options, "json")) {
@@ -9,9 +9,9 @@ const utils_1 = require("../utils");
9
9
  function getCertHashType(shaHash) {
10
10
  shaHash = shaHash.replace(/:/g, "");
11
11
  const shaHashCount = shaHash.length;
12
- if (shaHashCount == 40)
12
+ if (shaHashCount === 40)
13
13
  return apps_1.ShaCertificateType.SHA_1.toString();
14
- if (shaHashCount == 64)
14
+ if (shaHashCount === 64)
15
15
  return apps_1.ShaCertificateType.SHA_256.toString();
16
16
  return apps_1.ShaCertificateType.SHA_CERTIFICATE_TYPE_UNSPECIFIED.toString();
17
17
  }
@@ -70,7 +70,7 @@ module.exports = new command_1.Command("apps:sdkconfig [platform] [appId]")
70
70
  }
71
71
  spinner.succeed();
72
72
  const fileInfo = (0, apps_1.getAppConfigFile)(configData, appPlatform);
73
- if (appPlatform == apps_1.AppPlatform.WEB) {
73
+ if (appPlatform === apps_1.AppPlatform.WEB) {
74
74
  fileInfo.sdkConfig = configData;
75
75
  }
76
76
  if (options.out === undefined) {
@@ -18,10 +18,10 @@ exports.default = new command_1.Command("database:rules:list")
18
18
  const rulesets = await metadata.listAllRulesets(options.instance);
19
19
  for (const ruleset of rulesets) {
20
20
  const labels = [];
21
- if (ruleset.id == labeled.stable) {
21
+ if (ruleset.id === labeled.stable) {
22
22
  labels.push("stable");
23
23
  }
24
- if (ruleset.id == labeled.canary) {
24
+ if (ruleset.id === labeled.canary) {
25
25
  labels.push("canary");
26
26
  }
27
27
  logger_1.logger.info(`${ruleset.id} ${ruleset.createdAt} ${labels.join(",")}`);
@@ -59,9 +59,9 @@ module.exports = new command_1.Command("emulators:start")
59
59
  emulatorsTable.push(...controller
60
60
  .filterEmulatorTargets(options)
61
61
  .map((emulator) => {
62
- const info = registry_1.EmulatorRegistry.getInfo(emulator);
63
62
  const emulatorName = constants_1.Constants.description(emulator).replace(/ emulator/i, "");
64
63
  const isSupportedByUi = types_1.EMULATORS_SUPPORTED_BY_UI.includes(emulator);
64
+ const info = registry_1.EmulatorRegistry.getInfo(emulator === types_1.Emulators.EXTENSIONS ? types_1.Emulators.FUNCTIONS : emulator);
65
65
  if (!info) {
66
66
  return [emulatorName, "Failed to initialize (see above)", "", ""];
67
67
  }
@@ -24,6 +24,55 @@ function readCommonTemplates() {
24
24
  changelogTemplate: fs.readFileSync(path.join(TEMPLATE_ROOT, "CHANGELOG.md"), "utf8"),
25
25
  };
26
26
  }
27
+ exports.default = new command_1.Command("ext:dev:init")
28
+ .description("initialize files for writing an extension in the current directory")
29
+ .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extDevMinVersion")
30
+ .action(async (options) => {
31
+ const cwd = options.cwd || process.cwd();
32
+ const config = new config_1.Config({}, { projectDir: cwd, cwd: cwd });
33
+ try {
34
+ const lang = await (0, prompt_1.promptOnce)({
35
+ type: "list",
36
+ name: "language",
37
+ message: "In which language do you want to write the Cloud Functions for your extension?",
38
+ default: "javascript",
39
+ choices: [
40
+ {
41
+ name: "JavaScript",
42
+ value: "javascript",
43
+ },
44
+ {
45
+ name: "TypeScript",
46
+ value: "typescript",
47
+ },
48
+ ],
49
+ });
50
+ switch (lang) {
51
+ case "javascript": {
52
+ await javascriptSelected(config);
53
+ break;
54
+ }
55
+ case "typescript": {
56
+ await typescriptSelected(config);
57
+ break;
58
+ }
59
+ default: {
60
+ throw new error_1.FirebaseError(`${lang} is not supported.`);
61
+ }
62
+ }
63
+ await npmDependencies.askInstallDependencies({}, config);
64
+ const welcome = fs.readFileSync(path.join(TEMPLATE_ROOT, lang, "WELCOME.md"), "utf8");
65
+ return logger_1.logger.info("\n" + marked(welcome));
66
+ }
67
+ catch (err) {
68
+ if (!(err instanceof error_1.FirebaseError)) {
69
+ throw new error_1.FirebaseError(`Error occurred when initializing files for new extension: ${err.message}`, {
70
+ original: err,
71
+ });
72
+ }
73
+ throw err;
74
+ }
75
+ });
27
76
  async function typescriptSelected(config) {
28
77
  const packageLintingTemplate = fs.readFileSync(path.join(TEMPLATE_ROOT, "typescript", "package.lint.json"), "utf8");
29
78
  const packageNoLintingTemplate = fs.readFileSync(path.join(TEMPLATE_ROOT, "typescript", "package.nolint.json"), "utf8");
@@ -84,52 +133,3 @@ async function javascriptSelected(config) {
84
133
  }
85
134
  await config.askWriteProjectFile("functions/.gitignore", gitignoreTemplate);
86
135
  }
87
- exports.default = new command_1.Command("ext:dev:init")
88
- .description("initialize files for writing an extension in the current directory")
89
- .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extDevMinVersion")
90
- .action(async (options) => {
91
- const cwd = options.cwd || process.cwd();
92
- const config = new config_1.Config({}, { projectDir: cwd, cwd: cwd });
93
- try {
94
- const lang = await (0, prompt_1.promptOnce)({
95
- type: "list",
96
- name: "language",
97
- message: "In which language do you want to write the Cloud Functions for your extension?",
98
- default: "javascript",
99
- choices: [
100
- {
101
- name: "JavaScript",
102
- value: "javascript",
103
- },
104
- {
105
- name: "TypeScript",
106
- value: "typescript",
107
- },
108
- ],
109
- });
110
- switch (lang) {
111
- case "javascript": {
112
- await javascriptSelected(config);
113
- break;
114
- }
115
- case "typescript": {
116
- await typescriptSelected(config);
117
- break;
118
- }
119
- default: {
120
- throw new error_1.FirebaseError(`${lang} is not supported.`);
121
- }
122
- }
123
- await npmDependencies.askInstallDependencies({}, config);
124
- const welcome = fs.readFileSync(path.join(TEMPLATE_ROOT, lang, "WELCOME.md"), "utf8");
125
- return logger_1.logger.info("\n" + marked(welcome));
126
- }
127
- catch (err) {
128
- if (!(err instanceof error_1.FirebaseError)) {
129
- throw new error_1.FirebaseError(`Error occurred when initializing files for new extension: ${err.message}`, {
130
- original: err,
131
- });
132
- }
133
- throw err;
134
- }
135
- });
@@ -2,9 +2,12 @@
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");
5
6
  const planner = require("../deploy/extensions/planner");
7
+ const error_1 = require("../error");
6
8
  const export_1 = require("../extensions/export");
7
9
  const extensionsHelper_1 = require("../extensions/extensionsHelper");
10
+ const manifest_1 = require("../extensions/manifest");
8
11
  const functional_1 = require("../functional");
9
12
  const getProjectNumber_1 = require("../getProjectNumber");
10
13
  const logger_1 = require("../logger");
@@ -24,7 +27,7 @@ module.exports = new command_1.Command("ext:export")
24
27
  const subbed = await (0, export_1.setSecretParamsToLatest)(i);
25
28
  return (0, export_1.parameterizeProject)(projectId, projectNumber, subbed);
26
29
  }));
27
- if (have.length == 0) {
30
+ if (have.length === 0) {
28
31
  logger_1.logger.info(`No extension instances installed on ${projectId}, so there is nothing to export.`);
29
32
  return;
30
33
  }
@@ -40,5 +43,12 @@ module.exports = new command_1.Command("ext:export")
40
43
  logger_1.logger.info("Exiting. No changes made.");
41
44
  return;
42
45
  }
43
- await (0, export_1.writeFiles)(withRef, options);
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, {
51
+ nonInteractive: options.nonInteractive,
52
+ force: options.force,
53
+ });
44
54
  });
@@ -30,6 +30,110 @@ const previews_1 = require("../previews");
30
30
  marked.setOptions({
31
31
  renderer: new TerminalRenderer(),
32
32
  });
33
+ exports.default = new command_1.Command("ext:install [extensionName]")
34
+ .description("install an official extension if [extensionName] or [extensionName@version] is provided; " +
35
+ (previews_1.previews.extdev
36
+ ? "install a local extension if [localPathOrUrl] or [url#root] is provided; install a published extension (not authored by Firebase) if [publisherId/extensionId] is provided "
37
+ : "") +
38
+ "or run with `-i` to see all available extensions.")
39
+ .withForce()
40
+ .option("--params <paramsFile>", "name of params variables file with .env format.")
41
+ .before(requirePermissions_1.requirePermissions, ["firebaseextensions.instances.create"])
42
+ .before(extensionsHelper_1.ensureExtensionsApiEnabled)
43
+ .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
44
+ .before(extensionsHelper_1.diagnoseAndFixProject)
45
+ .action(async (extensionName, options) => {
46
+ const projectId = (0, projectUtils_1.needProjectId)(options);
47
+ const paramsEnvPath = options.params;
48
+ let learnMore = false;
49
+ if (!extensionName) {
50
+ if (options.interactive) {
51
+ learnMore = true;
52
+ extensionName = await (0, extensionsHelper_1.promptForOfficialExtension)("Which official extension do you wish to install?\n" +
53
+ " Select an extension, then press Enter to learn more.");
54
+ }
55
+ else {
56
+ throw new error_1.FirebaseError(`Unable to find published extension '${clc.bold(extensionName)}'. ` +
57
+ `Run ${clc.bold("firebase ext:install -i")} to select from the list of all available published extensions.`);
58
+ }
59
+ }
60
+ let source;
61
+ let extVersion;
62
+ if ((0, extensionsHelper_1.isLocalOrURLPath)(extensionName)) {
63
+ (0, track_1.track)("Extension Install", "Install by Source", options.interactive ? 1 : 0);
64
+ source = await infoInstallBySource(projectId, extensionName);
65
+ }
66
+ else {
67
+ (0, track_1.track)("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0);
68
+ extVersion = await infoInstallByReference(extensionName, options.interactive);
69
+ }
70
+ if (!(await (0, extensionsHelper_1.confirm)({
71
+ nonInteractive: options.nonInteractive,
72
+ force: options.force,
73
+ default: true,
74
+ }))) {
75
+ return;
76
+ }
77
+ if (!source && !extVersion) {
78
+ throw new error_1.FirebaseError("Could not find a source. Please specify a valid source to continue.");
79
+ }
80
+ const spec = (source === null || source === void 0 ? void 0 : source.spec) || (extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec);
81
+ if (!spec) {
82
+ throw new error_1.FirebaseError(`Could not find the extension.yaml for extension '${clc.bold(extensionName)}'. Please make sure this is a valid extension and try again.`);
83
+ }
84
+ if (learnMore) {
85
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, `You selected: ${clc.bold(spec.displayName)}.\n` +
86
+ `${spec.description}\n` +
87
+ `View details: https://firebase.google.com/products/extensions/${spec.name}\n`);
88
+ }
89
+ try {
90
+ return installExtension({
91
+ paramsEnvPath,
92
+ projectId,
93
+ extensionName,
94
+ source,
95
+ extVersion,
96
+ nonInteractive: options.nonInteractive,
97
+ force: options.force,
98
+ });
99
+ }
100
+ catch (err) {
101
+ if (!(err instanceof error_1.FirebaseError)) {
102
+ throw new error_1.FirebaseError(`Error occurred installing the extension: ${err.message}`, {
103
+ original: err,
104
+ });
105
+ }
106
+ throw err;
107
+ }
108
+ });
109
+ async function infoInstallBySource(projectId, extensionName) {
110
+ let source;
111
+ try {
112
+ source = await (0, extensionsHelper_1.createSourceFromLocation)(projectId, extensionName);
113
+ }
114
+ catch (err) {
115
+ throw new error_1.FirebaseError(`Unable to find published extension '${clc.bold(extensionName)}', ` +
116
+ `and encountered the following error when trying to create an instance of extension '${clc.bold(extensionName)}':\n ${err.message}`);
117
+ }
118
+ (0, displayExtensionInfo_1.displayExtInfo)(extensionName, "", source.spec);
119
+ return source;
120
+ }
121
+ async function infoInstallByReference(extensionName, interactive) {
122
+ if (extensionName.split("/").length < 2) {
123
+ const [extensionID, version] = extensionName.split("@");
124
+ extensionName = `firebase/${extensionID}@${version || "latest"}`;
125
+ }
126
+ const ref = refs.parse(extensionName);
127
+ const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
128
+ if (!ref.version) {
129
+ (0, track_1.track)("Extension Install", "Install by Extension Version Ref", interactive ? 1 : 0);
130
+ extensionName = `${extensionName}@latest`;
131
+ }
132
+ const extVersion = await extensionsApi.getExtensionVersion(extensionName);
133
+ (0, displayExtensionInfo_1.displayExtInfo)(extensionName, ref.publisherId, extVersion.spec, true);
134
+ await (0, warnings_1.displayWarningPrompts)(ref.publisherId, extension.registryLaunchStage, extVersion);
135
+ return extVersion;
136
+ }
33
137
  async function installExtension(options) {
34
138
  const { projectId, extensionName, source, extVersion, paramsEnvPath, nonInteractive, force } = options;
35
139
  const spec = (source === null || source === void 0 ? void 0 : source.spec) || (extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec);
@@ -162,107 +266,3 @@ async function installExtension(options) {
162
266
  });
163
267
  }
164
268
  }
165
- async function infoInstallBySource(projectId, extensionName) {
166
- let source;
167
- try {
168
- source = await (0, extensionsHelper_1.createSourceFromLocation)(projectId, extensionName);
169
- }
170
- catch (err) {
171
- throw new error_1.FirebaseError(`Unable to find published extension '${clc.bold(extensionName)}', ` +
172
- `and encountered the following error when trying to create an instance of extension '${clc.bold(extensionName)}':\n ${err.message}`);
173
- }
174
- (0, displayExtensionInfo_1.displayExtInfo)(extensionName, "", source.spec);
175
- return source;
176
- }
177
- async function infoInstallByReference(extensionName, interactive) {
178
- if (extensionName.split("/").length < 2) {
179
- const [extensionID, version] = extensionName.split("@");
180
- extensionName = `firebase/${extensionID}@${version || "latest"}`;
181
- }
182
- const ref = refs.parse(extensionName);
183
- const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
184
- if (!ref.version) {
185
- (0, track_1.track)("Extension Install", "Install by Extension Version Ref", interactive ? 1 : 0);
186
- extensionName = `${extensionName}@latest`;
187
- }
188
- const extVersion = await extensionsApi.getExtensionVersion(extensionName);
189
- (0, displayExtensionInfo_1.displayExtInfo)(extensionName, ref.publisherId, extVersion.spec, true);
190
- await (0, warnings_1.displayWarningPrompts)(ref.publisherId, extension.registryLaunchStage, extVersion);
191
- return extVersion;
192
- }
193
- exports.default = new command_1.Command("ext:install [extensionName]")
194
- .description("install an official extension if [extensionName] or [extensionName@version] is provided; " +
195
- (previews_1.previews.extdev
196
- ? "install a local extension if [localPathOrUrl] or [url#root] is provided; install a published extension (not authored by Firebase) if [publisherId/extensionId] is provided "
197
- : "") +
198
- "or run with `-i` to see all available extensions.")
199
- .withForce()
200
- .option("--params <paramsFile>", "name of params variables file with .env format.")
201
- .before(requirePermissions_1.requirePermissions, ["firebaseextensions.instances.create"])
202
- .before(extensionsHelper_1.ensureExtensionsApiEnabled)
203
- .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
204
- .before(extensionsHelper_1.diagnoseAndFixProject)
205
- .action(async (extensionName, options) => {
206
- const projectId = (0, projectUtils_1.needProjectId)(options);
207
- const paramsEnvPath = options.params;
208
- let learnMore = false;
209
- if (!extensionName) {
210
- if (options.interactive) {
211
- learnMore = true;
212
- extensionName = await (0, extensionsHelper_1.promptForOfficialExtension)("Which official extension do you wish to install?\n" +
213
- " Select an extension, then press Enter to learn more.");
214
- }
215
- else {
216
- throw new error_1.FirebaseError(`Unable to find published extension '${clc.bold(extensionName)}'. ` +
217
- `Run ${clc.bold("firebase ext:install -i")} to select from the list of all available published extensions.`);
218
- }
219
- }
220
- let source;
221
- let extVersion;
222
- if ((0, extensionsHelper_1.isLocalOrURLPath)(extensionName)) {
223
- (0, track_1.track)("Extension Install", "Install by Source", options.interactive ? 1 : 0);
224
- source = await infoInstallBySource(projectId, extensionName);
225
- }
226
- else {
227
- (0, track_1.track)("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0);
228
- extVersion = await infoInstallByReference(extensionName, options.interactive);
229
- }
230
- if (!(await (0, extensionsHelper_1.confirm)({
231
- nonInteractive: options.nonInteractive,
232
- force: options.force,
233
- default: true,
234
- }))) {
235
- return;
236
- }
237
- if (!source && !extVersion) {
238
- throw new error_1.FirebaseError("Could not find a source. Please specify a valid source to continue.");
239
- }
240
- const spec = (source === null || source === void 0 ? void 0 : source.spec) || (extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec);
241
- if (!spec) {
242
- throw new error_1.FirebaseError(`Could not find the extension.yaml for extension '${clc.bold(extensionName)}'. Please make sure this is a valid extension and try again.`);
243
- }
244
- if (learnMore) {
245
- utils.logLabeledBullet(extensionsHelper_1.logPrefix, `You selected: ${clc.bold(spec.displayName)}.\n` +
246
- `${spec.description}\n` +
247
- `View details: https://firebase.google.com/products/extensions/${spec.name}\n`);
248
- }
249
- try {
250
- return installExtension({
251
- paramsEnvPath,
252
- projectId,
253
- extensionName,
254
- source,
255
- extVersion,
256
- nonInteractive: options.nonInteractive,
257
- force: options.force,
258
- });
259
- }
260
- catch (err) {
261
- if (!(err instanceof error_1.FirebaseError)) {
262
- throw new error_1.FirebaseError(`Error occurred installing the extension: ${err.message}`, {
263
- original: err,
264
- });
265
- }
266
- throw err;
267
- }
268
- });
@@ -19,14 +19,6 @@ const logger_1 = require("../logger");
19
19
  marked.setOptions({
20
20
  renderer: new TerminalRenderer(),
21
21
  });
22
- function consoleUninstallOnly(projectId, instanceId) {
23
- const instanceURL = `https://console.firebase.google.com/project/${projectId}/extensions/instances/${instanceId}`;
24
- const consoleUninstall = "This extension has additional uninstall checks that are not currently supported by the CLI, and can only be uninstalled through the Firebase Console. " +
25
- `Please visit **[${instanceURL}](${instanceURL})** to uninstall this extension.`;
26
- logger_1.logger.info("\n");
27
- utils.logLabeledWarning(extensionsHelper_1.logPrefix, marked(consoleUninstall));
28
- return Promise.resolve();
29
- }
30
22
  exports.default = new command_1.Command("ext:uninstall <extensionInstanceId>")
31
23
  .description("uninstall an extension that is installed in your Firebase project by instance ID")
32
24
  .withForce()
@@ -102,3 +94,11 @@ exports.default = new command_1.Command("ext:uninstall <extensionInstanceId>")
102
94
  }
103
95
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `uninstalled ${clc.bold(instanceId)}`);
104
96
  });
97
+ function consoleUninstallOnly(projectId, instanceId) {
98
+ const instanceURL = `https://console.firebase.google.com/project/${projectId}/extensions/instances/${instanceId}`;
99
+ const consoleUninstall = "This extension has additional uninstall checks that are not currently supported by the CLI, and can only be uninstalled through the Firebase Console. " +
100
+ `Please visit **[${instanceURL}](${instanceURL})** to uninstall this extension.`;
101
+ logger_1.logger.info("\n");
102
+ utils.logLabeledWarning(extensionsHelper_1.logPrefix, marked(consoleUninstall));
103
+ return Promise.resolve();
104
+ }
@@ -25,15 +25,6 @@ const previews_1 = require("../previews");
25
25
  marked.setOptions({
26
26
  renderer: new TerminalRenderer(),
27
27
  });
28
- function isValidUpdate(existingSourceOrigin, newSourceOrigin) {
29
- if (existingSourceOrigin === extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION) {
30
- return [extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION, extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION_VERSION].includes(newSourceOrigin);
31
- }
32
- else if (existingSourceOrigin === extensionsHelper_1.SourceOrigin.LOCAL) {
33
- return [extensionsHelper_1.SourceOrigin.LOCAL, extensionsHelper_1.SourceOrigin.URL].includes(newSourceOrigin);
34
- }
35
- return false;
36
- }
37
28
  exports.default = new command_1.Command("ext:update <extensionInstanceId> [updateSource]")
38
29
  .description(previews_1.previews.extdev
39
30
  ? "update an existing extension instance to the latest version or from a local or URL source"
@@ -192,3 +183,12 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
192
183
  throw err;
193
184
  }
194
185
  });
186
+ function isValidUpdate(existingSourceOrigin, newSourceOrigin) {
187
+ if (existingSourceOrigin === extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION) {
188
+ return [extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION, extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION_VERSION].includes(newSourceOrigin);
189
+ }
190
+ else if (existingSourceOrigin === extensionsHelper_1.SourceOrigin.LOCAL) {
191
+ return [extensionsHelper_1.SourceOrigin.LOCAL, extensionsHelper_1.SourceOrigin.URL].includes(newSourceOrigin);
192
+ }
193
+ return false;
194
+ }
@@ -96,7 +96,7 @@ exports.default = new command_1.Command("functions:config:export")
96
96
  throw new error_1.FirebaseError("Exceeded max attempts to fix invalid config keys.");
97
97
  }
98
98
  const errMsg = configExport.hydrateEnvs(pInfos, prefix);
99
- if (errMsg.length == 0) {
99
+ if (errMsg.length === 0) {
100
100
  break;
101
101
  }
102
102
  prefix = await promptForPrefix(errMsg);
@@ -32,8 +32,8 @@ exports.default = new command_1.Command("hosting:clone <source> <targetChannel>"
32
32
  if (sourceChannelId) {
33
33
  sourceChannelId = (0, api_1.normalizeName)(sourceChannelId);
34
34
  }
35
- const equalSiteIds = sourceSiteId == targetSiteId;
36
- const equalChannelIds = sourceChannelId == targetChannelId;
35
+ const equalSiteIds = sourceSiteId === targetSiteId;
36
+ const equalChannelIds = sourceChannelId === targetChannelId;
37
37
  if (equalSiteIds && equalChannelIds) {
38
38
  throw new error_1.FirebaseError(`Source and destination cannot be equal. Please pick a different source or desination.`);
39
39
  }
@@ -67,7 +67,7 @@ exports.default = new command_1.Command("hosting:clone <source> <targetChannel>"
67
67
  }
68
68
  }
69
69
  const currentTargetVersionName = (_d = (_c = tChannel.release) === null || _c === void 0 ? void 0 : _c.version) === null || _d === void 0 ? void 0 : _d.name;
70
- if (equalSiteIds && sourceVersionName == currentTargetVersionName) {
70
+ if (equalSiteIds && sourceVersionName === currentTargetVersionName) {
71
71
  utils.logSuccess(`Channels ${(0, cli_color_1.bold)(sourceChannelId)} and ${(0, cli_color_1.bold)(targetChannel)} are serving identical versions. No need to clone.`);
72
72
  return;
73
73
  }
@@ -15,7 +15,7 @@ const error_1 = require("../error");
15
15
  const tableHead = ["Entry Name", "Value"];
16
16
  const MAX_DISPLAY_ITEMS = 20;
17
17
  function checkValidOptionalNumber(versionNumber) {
18
- if (!versionNumber || typeof Number(versionNumber) == "number") {
18
+ if (!versionNumber || typeof Number(versionNumber) === "number") {
19
19
  return versionNumber;
20
20
  }
21
21
  throw new error_1.FirebaseError(`Could not interpret "${versionNumber}" as a valid number.`);
@@ -7,8 +7,8 @@ const humanReadable = (dep) => `${clc.bold(dep.instanceId)} (${dep.ref ? `${refs
7
7
  exports.humanReadable = humanReadable;
8
8
  const humanReadableUpdate = (from, to) => {
9
9
  var _a, _b, _c, _d, _e;
10
- if (((_a = from.ref) === null || _a === void 0 ? void 0 : _a.publisherId) == ((_b = to.ref) === null || _b === void 0 ? void 0 : _b.publisherId) &&
11
- ((_c = from.ref) === null || _c === void 0 ? void 0 : _c.extensionId) == ((_d = to.ref) === null || _d === void 0 ? void 0 : _d.extensionId)) {
10
+ if (((_a = from.ref) === null || _a === void 0 ? void 0 : _a.publisherId) === ((_b = to.ref) === null || _b === void 0 ? void 0 : _b.publisherId) &&
11
+ ((_c = from.ref) === null || _c === void 0 ? void 0 : _c.extensionId) === ((_d = to.ref) === null || _d === void 0 ? void 0 : _d.extensionId)) {
12
12
  return `\t${clc.bold(from.instanceId)} (${refs.toExtensionVersionRef(from.ref)} => ${(_e = to.ref) === null || _e === void 0 ? void 0 : _e.version})`;
13
13
  }
14
14
  else {
@@ -28,7 +28,7 @@ exports.createsSummary = createsSummary;
28
28
  function updatesSummary(toUpdate, have) {
29
29
  const instancesToUpdate = toUpdate
30
30
  .map((to) => {
31
- const from = have.find((exists) => exists.instanceId == to.instanceId);
31
+ const from = have.find((exists) => exists.instanceId === to.instanceId);
32
32
  return humanReadableUpdate(from, to);
33
33
  })
34
34
  .join("\n");
@@ -13,6 +13,9 @@ function readParams(args) {
13
13
  `${args.instanceId}.env.${args.projectNumber}`,
14
14
  `${args.instanceId}.env.${args.projectId}`,
15
15
  ];
16
+ if (args.checkLocal) {
17
+ filesToCheck.push(`${args.instanceId}.env.local`);
18
+ }
16
19
  let noFilesFound = true;
17
20
  const combinedParams = {};
18
21
  for (const fileToCheck of filesToCheck) {
@@ -58,6 +58,7 @@ async function want(args) {
58
58
  projectId: args.projectId,
59
59
  projectNumber: args.projectNumber,
60
60
  aliases: args.aliases,
61
+ checkLocal: args.checkLocal,
61
62
  });
62
63
  const autoPopulatedParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
63
64
  const subbedParams = (0, extensionsHelper_1.substituteParams)(params, autoPopulatedParams);
@@ -80,7 +81,7 @@ async function want(args) {
80
81
  }
81
82
  exports.want = want;
82
83
  async function resolveVersion(ref) {
83
- if (!ref.version || ref.version == "latest") {
84
+ if (!ref.version || ref.version === "latest") {
84
85
  return "latest";
85
86
  }
86
87
  const extensionRef = refs.toExtensionRef(ref);
@@ -5,7 +5,7 @@ const clc = require("cli-color");
5
5
  const extensionsApi = require("../../extensions/extensionsApi");
6
6
  const refs = require("../../extensions/refs");
7
7
  const utils = require("../../utils");
8
- const isRetryable = (err) => err.status == 429 || err.status == 409;
8
+ const isRetryable = (err) => err.status === 429 || err.status === 409;
9
9
  function extensionsDeploymentHandler(errorHandler) {
10
10
  return async (task) => {
11
11
  var _a, _b, _c, _d;