firebase-tools 12.3.1 → 12.4.1

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 (62) hide show
  1. package/lib/api/frameworks.js +21 -0
  2. package/lib/api.js +4 -3
  3. package/lib/appdistribution/client.js +52 -0
  4. package/lib/auth.js +3 -3
  5. package/lib/command.js +15 -4
  6. package/lib/commands/appdistribution-group-create.js +19 -0
  7. package/lib/commands/appdistribution-group-delete.js +24 -0
  8. package/lib/commands/appdistribution-testers-add.js +6 -1
  9. package/lib/commands/appdistribution-testers-remove.js +20 -13
  10. package/lib/commands/experiments-describe.js +1 -1
  11. package/lib/commands/ext-install.js +10 -4
  12. package/lib/commands/index.js +5 -0
  13. package/lib/commands/init.js +8 -0
  14. package/lib/commands/internaltesting-frameworks-init.js +14 -0
  15. package/lib/config.js +1 -0
  16. package/lib/deploy/extensions/prepare.js +1 -0
  17. package/lib/deploy/extensions/release.js +11 -1
  18. package/lib/deploy/functions/checkIam.js +4 -1
  19. package/lib/deploy/functions/prepare.js +2 -1
  20. package/lib/deploy/functions/runtimes/discovery/index.js +6 -0
  21. package/lib/deploy/functions/runtimes/node/index.js +12 -4
  22. package/lib/deploy/functions/runtimes/python/index.js +19 -25
  23. package/lib/deploy/hosting/deploy.js +0 -6
  24. package/lib/deploy/hosting/prepare.js +7 -1
  25. package/lib/deploy/index.js +11 -4
  26. package/lib/deploy/lifecycleHooks.js +3 -0
  27. package/lib/deploy/storage/prepare.js +1 -1
  28. package/lib/detectProjectRoot.js +4 -1
  29. package/lib/dynamicImport.js +11 -1
  30. package/lib/emulator/commandUtils.js +4 -4
  31. package/lib/emulator/controller.js +9 -7
  32. package/lib/emulator/downloadableEmulators.js +3 -3
  33. package/lib/emulator/functionsEmulator.js +1 -2
  34. package/lib/emulator/storage/index.js +6 -0
  35. package/lib/emulator/storage/rules/manager.js +0 -4
  36. package/lib/emulator/storage/server.js +52 -0
  37. package/lib/ensureApiEnabled.js +3 -1
  38. package/lib/experiments.js +5 -0
  39. package/lib/extensions/paramHelper.js +0 -5
  40. package/lib/frameworks/compose/discover/filesystem.js +52 -0
  41. package/lib/frameworks/compose/discover/frameworkMatcher.js +76 -0
  42. package/lib/frameworks/compose/discover/frameworkSpec.js +39 -0
  43. package/lib/frameworks/compose/discover/types.js +2 -0
  44. package/lib/frameworks/constants.js +2 -15
  45. package/lib/frameworks/index.js +13 -8
  46. package/lib/frameworks/utils.js +50 -20
  47. package/lib/functionsConfig.js +2 -2
  48. package/lib/gcp/cloudbuild.js +50 -0
  49. package/lib/gcp/storage.js +6 -5
  50. package/lib/init/features/composer/repo.js +121 -0
  51. package/lib/init/features/frameworks/constants.js +7 -0
  52. package/lib/init/features/frameworks/index.js +36 -0
  53. package/lib/init/features/index.js +3 -1
  54. package/lib/init/index.js +4 -0
  55. package/lib/management/projects.js +5 -1
  56. package/lib/monospace/index.js +82 -0
  57. package/lib/monospace/interfaces.js +2 -0
  58. package/lib/requireAuth.js +8 -0
  59. package/lib/track.js +91 -52
  60. package/lib/utils.js +6 -1
  61. package/package.json +1 -1
  62. package/schema/extension-yaml.json +432 -0
@@ -11,6 +11,7 @@ const track_1 = require("../../track");
11
11
  const utils = require("../../utils");
12
12
  const backend = require("../functions/backend");
13
13
  const ensureTargeted_1 = require("../../functions/ensureTargeted");
14
+ const frameworks_1 = require("../../frameworks");
14
15
  function handlePublicDirectoryFlag(options) {
15
16
  if (options.public) {
16
17
  if (Array.isArray(options.config.get("hosting"))) {
@@ -48,6 +49,9 @@ async function addPinnedFunctionsToOnlyString(context, options) {
48
49
  if (endpoint) {
49
50
  options.only = (0, ensureTargeted_1.ensureTargeted)(options.only, endpoint.codebase || "default", endpoint.id);
50
51
  }
52
+ else if (c.webFramework) {
53
+ options.only = (0, ensureTargeted_1.ensureTargeted)(options.only, (0, frameworks_1.generateSSRCodebaseId)(c.site), r.function.functionId);
54
+ }
51
55
  else {
52
56
  options.only = (0, ensureTargeted_1.ensureTargeted)(options.only, r.function.functionId);
53
57
  }
@@ -94,7 +98,9 @@ async function prepare(context, options) {
94
98
  labels,
95
99
  };
96
100
  const [, versionName] = await Promise.all([
97
- (0, track_1.track)("hosting_deploy", config.webFramework || "classic"),
101
+ (0, track_1.trackGA4)("hosting_version", {
102
+ framework: config.webFramework || "classic",
103
+ }),
98
104
  api.createVersion(config.site, version),
99
105
  ]);
100
106
  return versionName;
@@ -96,11 +96,18 @@ const deploy = async function (targetNames, options, customContext = {}) {
96
96
  await chain(deploys, context, options, payload);
97
97
  await chain(releases, context, options, payload);
98
98
  await chain(postdeploys, context, options, payload);
99
- if ((0, lodash_1.has)(options, "config.notes.databaseRules")) {
100
- await (0, track_1.track)("Rules Deploy", options.config.notes.databaseRules);
101
- }
102
99
  const duration = Date.now() - startTime;
103
- await (0, track_1.track)("Product Deploy", [...targetNames].sort().join(","), duration);
100
+ const analyticsParams = {
101
+ interactive: options.nonInteractive ? "false" : "true",
102
+ };
103
+ Object.keys(TARGETS).reduce((accum, t) => {
104
+ accum[t] = "false";
105
+ return accum;
106
+ }, analyticsParams);
107
+ for (const t of targetNames) {
108
+ analyticsParams[t] = "true";
109
+ }
110
+ await (0, track_1.trackGA4)("product_deploy", analyticsParams, duration);
104
111
  logger_1.logger.info();
105
112
  (0, utils_1.logSuccess)((0, colorette_1.bold)((0, colorette_1.underline)("Deploy complete!")));
106
113
  logger_1.logger.info();
@@ -115,6 +115,9 @@ function getReleventConfigs(target, options) {
115
115
  return individualOnly.replace(`${target}:`, "");
116
116
  });
117
117
  return targetConfigs.filter((config) => {
118
+ if (target === "functions") {
119
+ return onlyTargets.includes(config.codebase);
120
+ }
118
121
  return !config.target || onlyTargets.includes(config.target);
119
122
  });
120
123
  }
@@ -26,7 +26,7 @@ async function default_1(context, options) {
26
26
  }
27
27
  const rulesDeploy = new rulesDeploy_1.RulesDeploy(options, rulesDeploy_1.RulesetServiceType.FIREBASE_STORAGE);
28
28
  const rulesConfigsToDeploy = [];
29
- if (!Array.isArray(rulesConfig)) {
29
+ if (!Array.isArray(rulesConfig) && options.project) {
30
30
  const defaultBucket = await gcp.storage.getDefaultBucket(options.project);
31
31
  rulesConfig = [Object.assign(rulesConfig, { bucket: defaultBucket })];
32
32
  }
@@ -9,7 +9,10 @@ function detectProjectRoot(options) {
9
9
  if (options.configPath) {
10
10
  const fullPath = (0, path_1.resolve)(projectRootDir, options.configPath);
11
11
  if (!(0, fsutils_1.fileExistsSync)(fullPath)) {
12
- throw new error_1.FirebaseError(`Could not load config file ${options.configPath}.`, { exit: 1 });
12
+ throw new error_1.FirebaseError(`Could not load config file ${options.configPath}.`, {
13
+ exit: 1,
14
+ status: 404,
15
+ });
13
16
  }
14
17
  return (0, path_1.dirname)(fullPath);
15
18
  }
@@ -1,10 +1,20 @@
1
1
  const { pathToFileURL } = require("url");
2
2
 
3
+ // If being compiled with webpack, use non webpack require for these calls.
4
+ // (VSCode plugin uses webpack which by default replaces require calls
5
+ // with its own require, which doesn't work on files)
6
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
7
+ const requireFunc =
8
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
9
+ // @ts-ignore prevent VSCE webpack from erroring on non_webpack_require
10
+ // eslint-disable-next-line camelcase
11
+ typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
12
+
3
13
  exports.dynamicImport = function(mod) {
4
14
  if (mod.startsWith("file://")) return import(mod);
5
15
  if (mod.startsWith("/")) return import(pathToFileURL(mod).toString());
6
16
  try {
7
- const path = require.resolve(mod);
17
+ const path = requireFunc.resolve(mod);
8
18
  return import(pathToFileURL(path).toString());
9
19
  } catch(e) {
10
20
  return Promise.reject(e);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JAVA_DEPRECATION_WARNING = exports.MIN_SUPPORTED_JAVA_MAJOR_VERSION = exports.checkJavaMajorVersion = exports.emulatorExec = exports.getListenOverview = exports.shutdownWhenKilled = exports.setExportOnExitOptions = exports.parseInspectionPort = exports.beforeEmulatorCommand = exports.warnEmulatorNotSupported = exports.printNoticeIfEmulated = exports.DESC_TEST_PARAMS = exports.FLAG_TEST_PARAMS = exports.DESC_TEST_CONFIG = exports.FLAG_TEST_CONFIG = exports.DESC_UI = exports.FLAG_UI = exports.EXPORT_ON_EXIT_CWD_DANGER = exports.EXPORT_ON_EXIT_USAGE_ERROR = exports.DESC_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT_NAME = exports.DESC_IMPORT = exports.FLAG_IMPORT = exports.DESC_INSPECT_FUNCTIONS = exports.FLAG_INSPECT_FUNCTIONS = exports.DESC_ONLY = exports.FLAG_ONLY = void 0;
3
+ exports.JAVA_DEPRECATION_WARNING = exports.MIN_SUPPORTED_JAVA_MAJOR_VERSION = exports.checkJavaMajorVersion = exports.emulatorExec = exports.getListenOverview = exports.shutdownWhenKilled = exports.setExportOnExitOptions = exports.parseInspectionPort = exports.beforeEmulatorCommand = exports.warnEmulatorNotSupported = exports.printNoticeIfEmulated = exports.DEFAULT_CONFIG = exports.DESC_TEST_PARAMS = exports.FLAG_TEST_PARAMS = exports.DESC_TEST_CONFIG = exports.FLAG_TEST_CONFIG = exports.DESC_UI = exports.FLAG_UI = exports.EXPORT_ON_EXIT_CWD_DANGER = exports.EXPORT_ON_EXIT_USAGE_ERROR = exports.DESC_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT_NAME = exports.DESC_IMPORT = exports.FLAG_IMPORT = exports.DESC_INSPECT_FUNCTIONS = exports.FLAG_INSPECT_FUNCTIONS = exports.DESC_ONLY = exports.FLAG_ONLY = void 0;
4
4
  const clc = require("colorette");
5
5
  const childProcess = require("child_process");
6
6
  const controller = require("../emulator/controller");
@@ -43,7 +43,7 @@ exports.FLAG_TEST_CONFIG = "--test-config <firebase.json file>";
43
43
  exports.DESC_TEST_CONFIG = "A firebase.json style file. Used to configure the Firestore and Realtime Database emulators.";
44
44
  exports.FLAG_TEST_PARAMS = "--test-params <params.env file>";
45
45
  exports.DESC_TEST_PARAMS = "A .env file containing test param values for your emulated extension.";
46
- const DEFAULT_CONFIG = new config_1.Config({
46
+ exports.DEFAULT_CONFIG = new config_1.Config({
47
47
  eventarc: {},
48
48
  database: {},
49
49
  firestore: {},
@@ -92,7 +92,7 @@ function warnEmulatorNotSupported(options, emulator) {
92
92
  }
93
93
  exports.warnEmulatorNotSupported = warnEmulatorNotSupported;
94
94
  async function beforeEmulatorCommand(options) {
95
- const optionsWithDefaultConfig = Object.assign(Object.assign({}, options), { config: DEFAULT_CONFIG });
95
+ const optionsWithDefaultConfig = Object.assign(Object.assign({}, options), { config: exports.DEFAULT_CONFIG });
96
96
  const optionsWithConfig = options.config ? options : optionsWithDefaultConfig;
97
97
  const canStartWithoutConfig = options.only &&
98
98
  !controller.shouldStart(optionsWithConfig, types_1.Emulators.FUNCTIONS) &&
@@ -106,7 +106,7 @@ async function beforeEmulatorCommand(options) {
106
106
  }
107
107
  if (canStartWithoutConfig && !options.config) {
108
108
  utils.logWarning("Could not find config (firebase.json) so using defaults.");
109
- options.config = DEFAULT_CONFIG;
109
+ options.config = exports.DEFAULT_CONFIG;
110
110
  }
111
111
  else {
112
112
  await (0, requireConfig_1.requireConfig)(options);
@@ -209,6 +209,10 @@ async function startAll(options, showUI = true, runningTestScript = false) {
209
209
  const extensionsBackends = await extensionEmulator.getExtensionBackends();
210
210
  const filteredExtensionsBackends = extensionEmulator.filterUnemulatedTriggers(options, extensionsBackends);
211
211
  emulatableBackends.push(...filteredExtensionsBackends);
212
+ (0, track_1.trackGA4)("extensions_emulated", {
213
+ number_of_extensions_emulated: filteredExtensionsBackends.length,
214
+ number_of_extensions_ignored: extensionsBackends.length - filteredExtensionsBackends.length,
215
+ });
212
216
  }
213
217
  const listenConfig = {};
214
218
  if (emulatableBackends.length) {
@@ -248,7 +252,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
248
252
  }
249
253
  function startEmulator(instance) {
250
254
  const name = instance.getName();
251
- void (0, track_1.track)("Emulator Run", name);
252
255
  void (0, track_1.trackEmulator)("emulator_run", {
253
256
  emulator_name: name,
254
257
  is_demo_project: String(isDemoProject),
@@ -261,7 +264,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
261
264
  listen: listenForEmulator[types_1.Emulators.HUB],
262
265
  listenForEmulator,
263
266
  });
264
- void (0, track_1.track)("emulators:start", "hub");
265
267
  await startEmulator(hub);
266
268
  }
267
269
  let exportMetadata = {
@@ -531,11 +533,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
531
533
  });
532
534
  await startEmulator(hostingEmulator);
533
535
  }
534
- if (showUI && !shouldStart(options, types_1.Emulators.UI)) {
535
- hubLogger.logLabeled("WARN", "emulators", "The Emulator UI is not starting, either because none of the emulated " +
536
- "products have an interaction layer in Emulator UI or it cannot " +
537
- "determine the Project ID. Pass the --project flag to specify a project.");
538
- }
539
536
  if (listenForEmulator.logging) {
540
537
  const loggingAddr = legacyGetFirstAddr(types_1.Emulators.LOGGING);
541
538
  const loggingEmulator = new loggingEmulator_1.LoggingEmulator({
@@ -544,6 +541,11 @@ async function startAll(options, showUI = true, runningTestScript = false) {
544
541
  });
545
542
  await startEmulator(loggingEmulator);
546
543
  }
544
+ if (showUI && !shouldStart(options, types_1.Emulators.UI)) {
545
+ hubLogger.logLabeled("WARN", "emulators", "The Emulator UI is not starting, either because none of the running " +
546
+ "emulators have a UI component or the Emulator UI cannot " +
547
+ "determine the Project ID. Pass the --project flag to specify a project.");
548
+ }
547
549
  if (listenForEmulator.ui) {
548
550
  const ui = new ui_1.EmulatorUI({
549
551
  projectId: projectId,
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
23
23
  expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63",
24
24
  },
25
25
  firestore: {
26
- version: "1.17.4",
27
- expectedSize: 64969580,
28
- expectedChecksum: "9d580b58e55e57b0cdc3ca8888098d43",
26
+ version: "1.18.1",
27
+ expectedSize: 64866257,
28
+ expectedChecksum: "743211a3e33217fe71dc20aff1fa26a5",
29
29
  },
30
30
  storage: {
31
31
  version: "1.1.3",
@@ -36,7 +36,6 @@ const v1_1 = require("../functions/events/v1");
36
36
  const build_1 = require("../deploy/functions/build");
37
37
  const env_1 = require("./env");
38
38
  const python_1 = require("../functions/python");
39
- const EVENT_INVOKE = "functions:invoke";
40
39
  const EVENT_INVOKE_GA4 = "functions_invoke";
41
40
  const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
42
41
  class IPCConn {
@@ -754,6 +753,7 @@ class FunctionsEmulator {
754
753
  envs.GCLOUD_PROJECT = this.args.projectId;
755
754
  envs.K_REVISION = "1";
756
755
  envs.PORT = "80";
756
+ envs.GOOGLE_CLOUD_QUOTA_PROJECT = this.args.projectId;
757
757
  if (trigger) {
758
758
  const target = trigger.entryPoint;
759
759
  envs.FUNCTION_TARGET = target;
@@ -1003,7 +1003,6 @@ class FunctionsEmulator {
1003
1003
  req.headers[functionsEmulatorShared_1.HttpConstants.CALLABLE_AUTH_HEADER] = encodeURIComponent(JSON.stringify(contextAuth));
1004
1004
  }
1005
1005
  }
1006
- void (0, track_1.track)(EVENT_INVOKE, (0, functionsEmulatorShared_1.getFunctionService)(trigger));
1007
1006
  void (0, track_1.trackEmulator)(EVENT_INVOKE_GA4, {
1008
1007
  function_service: (0, functionsEmulatorShared_1.getFunctionService)(trigger),
1009
1008
  });
@@ -64,6 +64,7 @@ class StorageEmulator {
64
64
  }
65
65
  async stop() {
66
66
  await this._persistence.deleteAll();
67
+ await this._rulesRuntime.stop();
67
68
  await this._rulesManager.stop();
68
69
  return this.destroyServer ? this.destroyServer() : Promise.resolve();
69
70
  }
@@ -85,6 +86,11 @@ class StorageEmulator {
85
86
  createRulesManager(rules) {
86
87
  return (0, manager_1.createStorageRulesManager)(rules, this._rulesRuntime);
87
88
  }
89
+ async replaceRules(rules) {
90
+ await this._rulesManager.stop();
91
+ this._rulesManager = this.createRulesManager(rules);
92
+ return this._rulesManager.start();
93
+ }
88
94
  getPersistenceTmpDir() {
89
95
  return `${(0, os_1.tmpdir)()}/firebase/storage/blobs`;
90
96
  }
@@ -20,7 +20,6 @@ class DefaultStorageRulesManager {
20
20
  this._rules = _rules;
21
21
  }
22
22
  async start() {
23
- this._runtime.start();
24
23
  const issues = await this.loadRuleset();
25
24
  this.updateWatcher(this._rules.name);
26
25
  return issues;
@@ -30,9 +29,6 @@ class DefaultStorageRulesManager {
30
29
  }
31
30
  async stop() {
32
31
  await this._watcher.close();
33
- if (this._runtime.alive) {
34
- await this._runtime.stop();
35
- }
36
32
  }
37
33
  updateWatcher(rulesFile) {
38
34
  this._watcher = chokidar
@@ -8,6 +8,7 @@ const types_1 = require("../types");
8
8
  const bodyParser = require("body-parser");
9
9
  const gcloud_1 = require("./apis/gcloud");
10
10
  const firebase_1 = require("./apis/firebase");
11
+ const errors_1 = require("../auth/errors");
11
12
  function createApp(defaultProjectId, emulator) {
12
13
  const { storageLayer } = emulator;
13
14
  const app = express();
@@ -50,6 +51,54 @@ function createApp(defaultProjectId, emulator) {
50
51
  await storageLayer.export(path, { initiatedBy });
51
52
  res.sendStatus(200);
52
53
  });
54
+ app.put("/internal/setRules", async (req, res) => {
55
+ const rulesRaw = req.body.rules;
56
+ if (!(rulesRaw && Array.isArray(rulesRaw.files) && rulesRaw.files.length > 0)) {
57
+ res.status(400).json({
58
+ message: "Request body must include 'rules.files' array",
59
+ });
60
+ return;
61
+ }
62
+ const { files } = rulesRaw;
63
+ function parseRulesFromFiles(files) {
64
+ if (files.length === 1) {
65
+ const file = files[0];
66
+ if (!isRulesFile(file)) {
67
+ throw new errors_1.InvalidArgumentError("Each member of 'rules.files' array must contain 'name' and 'content'");
68
+ }
69
+ return { name: file.name, content: file.content };
70
+ }
71
+ const rules = [];
72
+ for (const file of files) {
73
+ if (!isRulesFile(file) || !file.resource) {
74
+ throw new errors_1.InvalidArgumentError("Each member of 'rules.files' array must contain 'name', 'content', and 'resource'");
75
+ }
76
+ rules.push({ resource: file.resource, rules: { name: file.name, content: file.content } });
77
+ }
78
+ return rules;
79
+ }
80
+ let rules;
81
+ try {
82
+ rules = parseRulesFromFiles(files);
83
+ }
84
+ catch (err) {
85
+ if (err instanceof errors_1.InvalidArgumentError) {
86
+ res.status(400).json({ message: err.message });
87
+ return;
88
+ }
89
+ throw err;
90
+ }
91
+ const issues = await emulator.replaceRules(rules);
92
+ if (issues.errors.length > 0) {
93
+ res.status(400).json({
94
+ message: "There was an error updating rules, see logs for more details",
95
+ });
96
+ return;
97
+ }
98
+ res.status(200).json({
99
+ message: "Rules updated successfully",
100
+ });
101
+ });
53
102
  app.post("/internal/reset", (req, res) => {
54
103
  emulator.reset();
55
104
  res.sendStatus(200);
@@ -59,3 +108,6 @@ function createApp(defaultProjectId, emulator) {
59
108
  return Promise.resolve(app);
60
109
  }
61
110
  exports.createApp = createApp;
111
+ function isRulesFile(file) {
112
+ return (typeof file.name === "string" && typeof file.content === "string");
113
+ }
@@ -52,7 +52,9 @@ async function pollCheckEnabled(projectId, apiName, prefix, silent, enablementRe
52
52
  });
53
53
  const isEnabled = await check(projectId, apiName, prefix, silent);
54
54
  if (isEnabled) {
55
- void (0, track_1.track)("api_enabled", apiName);
55
+ void (0, track_1.trackGA4)("api_enabled", {
56
+ api_name: apiName,
57
+ });
56
58
  return;
57
59
  }
58
60
  if (!silent) {
@@ -72,6 +72,11 @@ exports.ALL_EXPERIMENTS = experiments({
72
72
  "These commands are not meant for public consumption and may break or disappear " +
73
73
  "without a notice.",
74
74
  },
75
+ frameworks: {
76
+ shortDescription: "Allow CLI option for Frameworks",
77
+ default: true,
78
+ public: false,
79
+ },
75
80
  });
76
81
  function isValidExperiment(name) {
77
82
  return Object.keys(exports.ALL_EXPERIMENTS).includes(name);
@@ -8,7 +8,6 @@ const error_1 = require("../error");
8
8
  const logger_1 = require("../logger");
9
9
  const extensionsHelper_1 = require("./extensionsHelper");
10
10
  const askUserForParam = require("./askUserForParam");
11
- const track_1 = require("../track");
12
11
  const env = require("../functions/env");
13
12
  const utils_1 = require("../utils");
14
13
  const NONINTERACTIVE_ERROR_MESSAGE = "As of firebase-tools@11, `ext:install`, `ext:update` and `ext:configure` are interactive only commands. " +
@@ -61,8 +60,6 @@ async function getParams(args) {
61
60
  reconfiguring: !!args.reconfiguring,
62
61
  });
63
62
  }
64
- const paramNames = Object.keys(params);
65
- void (0, track_1.track)("Extension Params", paramNames.length ? "Not Present" : "Present", paramNames.length);
66
63
  return params;
67
64
  }
68
65
  exports.getParams = getParams;
@@ -80,8 +77,6 @@ async function getParamsForUpdate(args) {
80
77
  instanceId: args.instanceId,
81
78
  });
82
79
  }
83
- const paramNames = Object.keys(params);
84
- void (0, track_1.track)("Extension Params", paramNames.length ? "Not Present" : "Present", paramNames.length);
85
80
  return params;
86
81
  }
87
82
  exports.getParamsForUpdate = getParamsForUpdate;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readOrNull = exports.LocalFileSystem = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path = require("path");
6
+ const error_1 = require("../../../error");
7
+ const logger_1 = require("../../../../src/logger");
8
+ class LocalFileSystem {
9
+ constructor(cwd) {
10
+ this.cwd = cwd;
11
+ this.existsCache = {};
12
+ this.contentCache = {};
13
+ }
14
+ async exists(file) {
15
+ try {
16
+ if (!(file in this.contentCache)) {
17
+ this.existsCache[file] = await (0, fs_extra_1.pathExists)(path.resolve(this.cwd, file));
18
+ }
19
+ return this.existsCache[file];
20
+ }
21
+ catch (error) {
22
+ throw new error_1.FirebaseError(`Error occured while searching for file: ${error}`);
23
+ }
24
+ }
25
+ async read(file) {
26
+ try {
27
+ if (!(file in this.contentCache)) {
28
+ const fileContents = await (0, fs_extra_1.readFile)(path.resolve(this.cwd, file), "utf-8");
29
+ this.contentCache[file] = fileContents;
30
+ }
31
+ return this.contentCache[file];
32
+ }
33
+ catch (error) {
34
+ logger_1.logger.error("Error occured while reading file contents.");
35
+ throw error;
36
+ }
37
+ }
38
+ }
39
+ exports.LocalFileSystem = LocalFileSystem;
40
+ async function readOrNull(fs, path) {
41
+ try {
42
+ return fs.read(path);
43
+ }
44
+ catch (err) {
45
+ if (err && typeof err === "object" && (err === null || err === void 0 ? void 0 : err.code) === "ENOENT") {
46
+ logger_1.logger.debug("ENOENT error occured while reading file.");
47
+ return null;
48
+ }
49
+ throw new Error(`Unknown error occured while reading file: ${err}`);
50
+ }
51
+ }
52
+ exports.readOrNull = readOrNull;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.frameworkMatcher = exports.removeEmbededFrameworks = exports.filterFrameworksWithFiles = exports.filterFrameworksWithDependencies = void 0;
4
+ const error_1 = require("../../../error");
5
+ const logger_1 = require("../../../logger");
6
+ function filterFrameworksWithDependencies(allFrameworkSpecs, dependencies) {
7
+ return allFrameworkSpecs.filter((framework) => {
8
+ return framework.requiredDependencies.every((dependency) => {
9
+ return dependency.name in dependencies;
10
+ });
11
+ });
12
+ }
13
+ exports.filterFrameworksWithDependencies = filterFrameworksWithDependencies;
14
+ async function filterFrameworksWithFiles(allFrameworkSpecs, fs) {
15
+ try {
16
+ const filteredFrameworks = [];
17
+ for (const framework of allFrameworkSpecs) {
18
+ if (!framework.requiredFiles) {
19
+ filteredFrameworks.push(framework);
20
+ continue;
21
+ }
22
+ let isRequired = true;
23
+ for (let files of framework.requiredFiles) {
24
+ files = Array.isArray(files) ? files : [files];
25
+ for (const file of files) {
26
+ isRequired = isRequired && (await fs.exists(file));
27
+ if (!isRequired) {
28
+ break;
29
+ }
30
+ }
31
+ }
32
+ if (isRequired) {
33
+ filteredFrameworks.push(framework);
34
+ }
35
+ }
36
+ return filteredFrameworks;
37
+ }
38
+ catch (error) {
39
+ logger_1.logger.error("Error: Unable to filter frameworks based on required files", error);
40
+ throw error;
41
+ }
42
+ }
43
+ exports.filterFrameworksWithFiles = filterFrameworksWithFiles;
44
+ function removeEmbededFrameworks(allFrameworkSpecs) {
45
+ const embededFrameworkSet = new Set();
46
+ for (const framework of allFrameworkSpecs) {
47
+ if (!framework.embedsFrameworks) {
48
+ continue;
49
+ }
50
+ for (const item of framework.embedsFrameworks) {
51
+ embededFrameworkSet.add(item);
52
+ }
53
+ }
54
+ return allFrameworkSpecs.filter((item) => !embededFrameworkSet.has(item.id));
55
+ }
56
+ exports.removeEmbededFrameworks = removeEmbededFrameworks;
57
+ async function frameworkMatcher(runtime, fs, frameworks, dependencies) {
58
+ try {
59
+ const filterRuntimeFramework = frameworks.filter((framework) => framework.runtime === runtime);
60
+ const frameworksWithDependencies = filterFrameworksWithDependencies(filterRuntimeFramework, dependencies);
61
+ const frameworkWithFiles = await filterFrameworksWithFiles(frameworksWithDependencies, fs);
62
+ const allMatches = removeEmbededFrameworks(frameworkWithFiles);
63
+ if (allMatches.length === 0) {
64
+ return null;
65
+ }
66
+ if (allMatches.length > 1) {
67
+ const frameworkNames = allMatches.map((framework) => framework.id);
68
+ throw new error_1.FirebaseError(`Multiple Frameworks are matched: ${frameworkNames.join(", ")} Manually set up override commands in firebase.json`);
69
+ }
70
+ return allMatches[0];
71
+ }
72
+ catch (error) {
73
+ throw new error_1.FirebaseError(`Failed to match the correct framework: ${error}`);
74
+ }
75
+ }
76
+ exports.frameworkMatcher = frameworkMatcher;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.frameworkSpecs = void 0;
4
+ exports.frameworkSpecs = [
5
+ {
6
+ id: "express",
7
+ runtime: "nodejs",
8
+ webFrameworkId: "Express.js",
9
+ requiredDependencies: [
10
+ {
11
+ name: "express",
12
+ },
13
+ ],
14
+ },
15
+ {
16
+ id: "nextjs",
17
+ runtime: "nodejs",
18
+ webFrameworkId: "Next.js",
19
+ requiredFiles: ["next.config.js", "next.config.ts"],
20
+ requiredDependencies: [
21
+ {
22
+ name: "next",
23
+ },
24
+ ],
25
+ commands: {
26
+ build: {
27
+ cmd: "next build",
28
+ },
29
+ dev: {
30
+ cmd: "next dev",
31
+ env: { NODE_ENV: "dev" },
32
+ },
33
+ run: {
34
+ cmd: "next run",
35
+ env: { NODE_ENV: "production" },
36
+ },
37
+ },
38
+ },
39
+ ];
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE = exports.GET_DEFAULT_BUILD_TARGETS = exports.WebFrameworks = exports.I18N_ROOT = exports.ALLOWED_SSR_REGIONS = exports.DEFAULT_REGION = exports.VALID_LOCALE_FORMATS = exports.VALID_ENGINES = exports.NODE_VERSION = exports.SHARP_VERSION = exports.FIREBASE_ADMIN_VERSION = exports.FIREBASE_FUNCTIONS_VERSION = exports.FIREBASE_FRAMEWORKS_VERSION = exports.MAILING_LIST_URL = exports.FEATURE_REQUEST_URL = exports.FILE_BUG_URL = exports.DEFAULT_DOCS_URL = exports.SupportLevelWarnings = exports.NPM_COMMAND_TIMEOUT_MILLIES = void 0;
4
- const fs_1 = require("fs");
5
- const path_1 = require("path");
3
+ exports.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE = exports.GET_DEFAULT_BUILD_TARGETS = exports.I18N_ROOT = exports.ALLOWED_SSR_REGIONS = exports.DEFAULT_REGION = exports.VALID_LOCALE_FORMATS = exports.VALID_ENGINES = exports.NODE_VERSION = exports.SHARP_VERSION = exports.FIREBASE_ADMIN_VERSION = exports.FIREBASE_FUNCTIONS_VERSION = exports.FIREBASE_FRAMEWORKS_VERSION = exports.MAILING_LIST_URL = exports.FEATURE_REQUEST_URL = exports.FILE_BUG_URL = exports.DEFAULT_DOCS_URL = exports.SupportLevelWarnings = exports.NPM_COMMAND_TIMEOUT_MILLIES = void 0;
6
4
  const clc = require("colorette");
7
5
  exports.NPM_COMMAND_TIMEOUT_MILLIES = 10000;
8
6
  exports.SupportLevelWarnings = {
@@ -16,7 +14,7 @@ exports.DEFAULT_DOCS_URL = "https://firebase.google.com/docs/hosting/frameworks/
16
14
  exports.FILE_BUG_URL = "https://github.com/firebase/firebase-tools/issues/new?template=bug_report.md";
17
15
  exports.FEATURE_REQUEST_URL = "https://github.com/firebase/firebase-tools/issues/new?template=feature_request.md";
18
16
  exports.MAILING_LIST_URL = "https://goo.gle/41enW5X";
19
- exports.FIREBASE_FRAMEWORKS_VERSION = "^0.10.1";
17
+ exports.FIREBASE_FRAMEWORKS_VERSION = "^0.10.4";
20
18
  exports.FIREBASE_FUNCTIONS_VERSION = "^4.3.0";
21
19
  exports.FIREBASE_ADMIN_VERSION = "^11.0.1";
22
20
  exports.SHARP_VERSION = "^0.32.1";
@@ -32,17 +30,6 @@ exports.ALLOWED_SSR_REGIONS = [
32
30
  { name: "asia-east1 (Taiwan)", value: "asia-east1" },
33
31
  ];
34
32
  exports.I18N_ROOT = "/";
35
- exports.WebFrameworks = Object.fromEntries((0, fs_1.readdirSync)(__dirname)
36
- .filter((path) => (0, fs_1.statSync)((0, path_1.join)(__dirname, path)).isDirectory())
37
- .map((path) => {
38
- try {
39
- return [path, require((0, path_1.join)(__dirname, path))];
40
- }
41
- catch (e) {
42
- return [];
43
- }
44
- })
45
- .filter(([, obj]) => obj && obj.name && obj.discover && obj.build && obj.type !== undefined && obj.support));
46
33
  function GET_DEFAULT_BUILD_TARGETS() {
47
34
  return Promise.resolve(["production", "development"]);
48
35
  }