No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

controller.js 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.exportEmulatorData = exports.startAll = exports.shouldStart = exports.filterEmulatorTargets = exports.cleanShutdown = exports.onExit = exports.exportOnExit = void 0;
  4. const clc = require("colorette");
  5. const fs = require("fs");
  6. const path = require("path");
  7. const logger_1 = require("../logger");
  8. const track_1 = require("../track");
  9. const utils = require("../utils");
  10. const registry_1 = require("./registry");
  11. const types_1 = require("./types");
  12. const constants_1 = require("./constants");
  13. const functionsEmulator_1 = require("./functionsEmulator");
  14. const functionsEmulatorUtils_1 = require("./functionsEmulatorUtils");
  15. const auth_1 = require("./auth");
  16. const databaseEmulator_1 = require("./databaseEmulator");
  17. const firestoreEmulator_1 = require("./firestoreEmulator");
  18. const hostingEmulator_1 = require("./hostingEmulator");
  19. const eventarcEmulator_1 = require("./eventarcEmulator");
  20. const error_1 = require("../error");
  21. const projectUtils_1 = require("../projectUtils");
  22. const pubsubEmulator_1 = require("./pubsubEmulator");
  23. const commandUtils = require("./commandUtils");
  24. const hub_1 = require("./hub");
  25. const hubExport_1 = require("./hubExport");
  26. const ui_1 = require("./ui");
  27. const loggingEmulator_1 = require("./loggingEmulator");
  28. const dbRulesConfig = require("../database/rulesConfig");
  29. const emulatorLogger_1 = require("./emulatorLogger");
  30. const hubClient_1 = require("./hubClient");
  31. const prompt_1 = require("../prompt");
  32. const commandUtils_1 = require("./commandUtils");
  33. const fsutils_1 = require("../fsutils");
  34. const storage_1 = require("./storage");
  35. const config_1 = require("./storage/rules/config");
  36. const getDefaultDatabaseInstance_1 = require("../getDefaultDatabaseInstance");
  37. const auth_2 = require("../auth");
  38. const extensionsEmulator_1 = require("./extensionsEmulator");
  39. const projectConfig_1 = require("../functions/projectConfig");
  40. const downloadableEmulators_1 = require("./downloadableEmulators");
  41. const frameworks_1 = require("../frameworks");
  42. const experiments = require("../experiments");
  43. const portUtils_1 = require("./portUtils");
  44. const START_LOGGING_EMULATOR = utils.envOverride("START_LOGGING_EMULATOR", "false", (val) => val === "true");
  45. async function exportOnExit(options) {
  46. const exportOnExitDir = options.exportOnExit;
  47. if (exportOnExitDir) {
  48. try {
  49. utils.logBullet(`Automatically exporting data using ${commandUtils_1.FLAG_EXPORT_ON_EXIT_NAME} "${exportOnExitDir}" ` +
  50. "please wait for the export to finish...");
  51. await exportEmulatorData(exportOnExitDir, options, "exit");
  52. }
  53. catch (e) {
  54. utils.logWarning(e);
  55. utils.logWarning(`Automatic export to "${exportOnExitDir}" failed, going to exit now...`);
  56. }
  57. }
  58. }
  59. exports.exportOnExit = exportOnExit;
  60. async function onExit(options) {
  61. await exportOnExit(options);
  62. }
  63. exports.onExit = onExit;
  64. async function cleanShutdown() {
  65. emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.HUB).logLabeled("BULLET", "emulators", "Shutting down emulators.");
  66. await registry_1.EmulatorRegistry.stopAll();
  67. }
  68. exports.cleanShutdown = cleanShutdown;
  69. function filterEmulatorTargets(options) {
  70. let targets = [...types_1.ALL_SERVICE_EMULATORS];
  71. targets.push(types_1.Emulators.EXTENSIONS);
  72. targets = targets.filter((e) => {
  73. return options.config.has(e) || options.config.has(`emulators.${e}`);
  74. });
  75. const onlyOptions = options.only;
  76. if (onlyOptions) {
  77. const only = onlyOptions.split(",").map((o) => {
  78. return o.split(":")[0];
  79. });
  80. targets = targets.filter((t) => only.includes(t));
  81. }
  82. return targets;
  83. }
  84. exports.filterEmulatorTargets = filterEmulatorTargets;
  85. function shouldStart(options, name) {
  86. var _a, _b;
  87. if (name === types_1.Emulators.HUB) {
  88. return !!options.project;
  89. }
  90. const targets = filterEmulatorTargets(options);
  91. const emulatorInTargets = targets.includes(name);
  92. if (name === types_1.Emulators.UI) {
  93. if (options.ui) {
  94. return true;
  95. }
  96. if (((_b = (_a = options.config.src.emulators) === null || _a === void 0 ? void 0 : _a.ui) === null || _b === void 0 ? void 0 : _b.enabled) === false) {
  97. return false;
  98. }
  99. return (!!options.project && targets.some((target) => types_1.EMULATORS_SUPPORTED_BY_UI.includes(target)));
  100. }
  101. if (name === types_1.Emulators.FUNCTIONS && emulatorInTargets) {
  102. try {
  103. (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
  104. return true;
  105. }
  106. catch (err) {
  107. emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("WARN", "functions", `The functions emulator is configured but there is no functions source directory. Have you run ${clc.bold("firebase init functions")}?`);
  108. return false;
  109. }
  110. }
  111. if (name === types_1.Emulators.HOSTING && emulatorInTargets && !options.config.get("hosting")) {
  112. emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.HOSTING).logLabeled("WARN", "hosting", `The hosting emulator is configured but there is no hosting configuration. Have you run ${clc.bold("firebase init hosting")}?`);
  113. return false;
  114. }
  115. return emulatorInTargets;
  116. }
  117. exports.shouldStart = shouldStart;
  118. function findExportMetadata(importPath) {
  119. const pathIsDirectory = fs.lstatSync(importPath).isDirectory();
  120. if (!pathIsDirectory) {
  121. return;
  122. }
  123. const importFilePath = path.join(importPath, hubExport_1.HubExport.METADATA_FILE_NAME);
  124. if ((0, fsutils_1.fileExistsSync)(importFilePath)) {
  125. return JSON.parse(fs.readFileSync(importFilePath, "utf8").toString());
  126. }
  127. const fileList = fs.readdirSync(importPath);
  128. const firestoreMetadataFile = fileList.find((f) => f.endsWith(".overall_export_metadata"));
  129. if (firestoreMetadataFile) {
  130. const metadata = {
  131. version: hub_1.EmulatorHub.CLI_VERSION,
  132. firestore: {
  133. version: "prod",
  134. path: importPath,
  135. metadata_file: `${importPath}/${firestoreMetadataFile}`,
  136. },
  137. };
  138. emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FIRESTORE).logLabeled("BULLET", "firestore", `Detected non-emulator Firestore export at ${importPath}`);
  139. return metadata;
  140. }
  141. const rtdbDataFile = fileList.find((f) => f.endsWith(".json"));
  142. if (rtdbDataFile) {
  143. const metadata = {
  144. version: hub_1.EmulatorHub.CLI_VERSION,
  145. database: {
  146. version: "prod",
  147. path: importPath,
  148. },
  149. };
  150. emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATABASE).logLabeled("BULLET", "firestore", `Detected non-emulator Database export at ${importPath}`);
  151. return metadata;
  152. }
  153. }
  154. async function startAll(options, showUI = true) {
  155. var _a, _b, _c, _d, _e, _f, _g;
  156. const targets = filterEmulatorTargets(options);
  157. options.targets = targets;
  158. const singleProjectModeEnabled = ((_a = options.config.src.emulators) === null || _a === void 0 ? void 0 : _a.singleProjectMode) === undefined ||
  159. ((_b = options.config.src.emulators) === null || _b === void 0 ? void 0 : _b.singleProjectMode);
  160. if (targets.length === 0) {
  161. throw new error_1.FirebaseError(`No emulators to start, run ${clc.bold("firebase init emulators")} to get started.`);
  162. }
  163. if (targets.some(downloadableEmulators_1.requiresJava)) {
  164. if ((await commandUtils.checkJavaMajorVersion()) < commandUtils_1.MIN_SUPPORTED_JAVA_MAJOR_VERSION) {
  165. utils.logLabeledError("emulators", commandUtils_1.JAVA_DEPRECATION_WARNING, "warn");
  166. throw new error_1.FirebaseError(commandUtils_1.JAVA_DEPRECATION_WARNING);
  167. }
  168. }
  169. const hubLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.HUB);
  170. hubLogger.logLabeled("BULLET", "emulators", `Starting emulators: ${targets.join(", ")}`);
  171. const projectId = (0, projectUtils_1.getProjectId)(options) || "";
  172. const isDemoProject = constants_1.Constants.isDemoProject(projectId);
  173. if (isDemoProject) {
  174. hubLogger.logLabeled("BULLET", "emulators", `Detected demo project ID "${projectId}", emulated services will use a demo configuration and attempts to access non-emulated services for this project will fail.`);
  175. }
  176. const onlyOptions = options.only;
  177. if (onlyOptions) {
  178. const requested = onlyOptions.split(",").map((o) => {
  179. return o.split(":")[0];
  180. });
  181. const ignored = requested.filter((k) => !targets.includes(k));
  182. for (const name of ignored) {
  183. if ((0, types_1.isEmulator)(name)) {
  184. emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("WARN", name, `Not starting the ${clc.bold(name)} emulator, make sure you have run ${clc.bold("firebase init")}.`);
  185. }
  186. else {
  187. throw new error_1.FirebaseError(`${name} is not a valid emulator name, valid options are: ${JSON.stringify(types_1.ALL_SERVICE_EMULATORS)}`, { exit: 1 });
  188. }
  189. }
  190. }
  191. const emulatableBackends = [];
  192. let extensionEmulator = undefined;
  193. if (shouldStart(options, types_1.Emulators.EXTENSIONS)) {
  194. const projectNumber = isDemoProject
  195. ? constants_1.Constants.FAKE_PROJECT_NUMBER
  196. : await (0, projectUtils_1.needProjectNumber)(options);
  197. const aliases = (0, projectUtils_1.getAliases)(options, projectId);
  198. extensionEmulator = new extensionsEmulator_1.ExtensionsEmulator({
  199. projectId,
  200. projectDir: options.config.projectDir,
  201. projectNumber,
  202. aliases,
  203. extensions: options.config.get("extensions"),
  204. });
  205. const extensionsBackends = await extensionEmulator.getExtensionBackends();
  206. const filteredExtensionsBackends = extensionEmulator.filterUnemulatedTriggers(options, extensionsBackends);
  207. emulatableBackends.push(...filteredExtensionsBackends);
  208. }
  209. const listenConfig = {};
  210. if (emulatableBackends.length) {
  211. listenConfig[types_1.Emulators.FUNCTIONS] = getListenConfig(options, types_1.Emulators.FUNCTIONS);
  212. listenConfig[types_1.Emulators.EVENTARC] = getListenConfig(options, types_1.Emulators.EVENTARC);
  213. }
  214. for (const emulator of types_1.ALL_EMULATORS) {
  215. if (emulator === types_1.Emulators.FUNCTIONS ||
  216. emulator === types_1.Emulators.EVENTARC ||
  217. emulator === types_1.Emulators.EXTENSIONS ||
  218. (emulator === types_1.Emulators.UI && !showUI)) {
  219. continue;
  220. }
  221. if (shouldStart(options, emulator) ||
  222. (emulator === types_1.Emulators.LOGGING &&
  223. ((showUI && shouldStart(options, types_1.Emulators.UI)) || START_LOGGING_EMULATOR))) {
  224. const config = getListenConfig(options, emulator);
  225. listenConfig[emulator] = config;
  226. if (emulator === types_1.Emulators.FIRESTORE) {
  227. const wsPortConfig = (_d = (_c = options.config.src.emulators) === null || _c === void 0 ? void 0 : _c.firestore) === null || _d === void 0 ? void 0 : _d.websocketPort;
  228. listenConfig["firestore.websocket"] = {
  229. host: config.host,
  230. port: wsPortConfig || 9150,
  231. portFixed: !!wsPortConfig,
  232. };
  233. }
  234. }
  235. }
  236. let listenForEmulator = await (0, portUtils_1.resolveHostAndAssignPorts)(listenConfig);
  237. hubLogger.log("DEBUG", "assigned listening specs for emulators", { user: listenForEmulator });
  238. function legacyGetFirstAddr(name) {
  239. const firstSpec = listenForEmulator[name][0];
  240. return {
  241. host: firstSpec.address,
  242. port: firstSpec.port,
  243. };
  244. }
  245. function startEmulator(instance) {
  246. const name = instance.getName();
  247. void (0, track_1.track)("Emulator Run", name);
  248. void (0, track_1.trackEmulator)("emulator_run", {
  249. emulator_name: name,
  250. is_demo_project: String(isDemoProject),
  251. });
  252. return registry_1.EmulatorRegistry.start(instance);
  253. }
  254. if (listenForEmulator.hub) {
  255. const hub = new hub_1.EmulatorHub({
  256. projectId,
  257. listen: listenForEmulator[types_1.Emulators.HUB],
  258. listenForEmulator,
  259. });
  260. void (0, track_1.track)("emulators:start", "hub");
  261. await startEmulator(hub);
  262. }
  263. let exportMetadata = {
  264. version: "unknown",
  265. };
  266. if (options.import) {
  267. utils.assertIsString(options.import);
  268. const importDir = path.resolve(options.import);
  269. const foundMetadata = findExportMetadata(importDir);
  270. if (foundMetadata) {
  271. exportMetadata = foundMetadata;
  272. void (0, track_1.trackEmulator)("emulator_import", {
  273. initiated_by: "start",
  274. emulator_name: types_1.Emulators.HUB,
  275. });
  276. }
  277. else {
  278. hubLogger.logLabeled("WARN", "emulators", `Could not find import/export metadata file, ${clc.bold("skipping data import!")}`);
  279. }
  280. }
  281. const hostingConfig = options.config.get("hosting");
  282. if (Array.isArray(hostingConfig) ? hostingConfig.some((it) => it.source) : hostingConfig === null || hostingConfig === void 0 ? void 0 : hostingConfig.source) {
  283. experiments.assertEnabled("webframeworks", "emulate a web framework");
  284. const emulators = [];
  285. if (experiments.isEnabled("webframeworks")) {
  286. for (const e of types_1.ALL_SERVICE_EMULATORS) {
  287. if (listenForEmulator[e]) {
  288. emulators.push({
  289. name: e,
  290. host: utils.connectableHostname(listenForEmulator[e][0].address),
  291. port: listenForEmulator[e][0].port,
  292. });
  293. }
  294. }
  295. }
  296. await (0, frameworks_1.prepareFrameworks)(targets, options, options, emulators);
  297. }
  298. const projectDir = (options.extDevDir || options.config.projectDir);
  299. if (shouldStart(options, types_1.Emulators.FUNCTIONS)) {
  300. const functionsCfg = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
  301. utils.assertIsStringOrUndefined(options.extDevDir);
  302. for (const cfg of functionsCfg) {
  303. const functionsDir = path.join(projectDir, cfg.source);
  304. emulatableBackends.push({
  305. functionsDir,
  306. codebase: cfg.codebase,
  307. env: Object.assign({}, options.extDevEnv),
  308. secretEnv: [],
  309. predefinedTriggers: options.extDevTriggers,
  310. nodeMajorVersion: (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.extDevNodeVersion || cfg.runtime),
  311. });
  312. }
  313. }
  314. if (extensionEmulator) {
  315. await startEmulator(extensionEmulator);
  316. }
  317. if (emulatableBackends.length) {
  318. if (!listenForEmulator.functions || !listenForEmulator.eventarc) {
  319. listenForEmulator = await (0, portUtils_1.resolveHostAndAssignPorts)(Object.assign(Object.assign({}, listenForEmulator), { functions: (_e = listenForEmulator.functions) !== null && _e !== void 0 ? _e : getListenConfig(options, types_1.Emulators.FUNCTIONS), eventarc: (_f = listenForEmulator.eventarc) !== null && _f !== void 0 ? _f : getListenConfig(options, types_1.Emulators.EVENTARC) }));
  320. hubLogger.log("DEBUG", "late-assigned ports for functions and eventarc emulators", {
  321. user: listenForEmulator,
  322. });
  323. }
  324. const functionsLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
  325. const functionsAddr = legacyGetFirstAddr(types_1.Emulators.FUNCTIONS);
  326. const projectId = (0, projectUtils_1.needProjectId)(options);
  327. let inspectFunctions;
  328. if (options.inspectFunctions) {
  329. inspectFunctions = commandUtils.parseInspectionPort(options);
  330. functionsLogger.logLabeled("WARN", "functions", `You are running the Functions emulator in debug mode (port=${inspectFunctions}). This means that functions will execute in sequence rather than in parallel.`);
  331. }
  332. const emulatorsNotRunning = types_1.ALL_SERVICE_EMULATORS.filter((e) => {
  333. return e !== types_1.Emulators.FUNCTIONS && !listenForEmulator[e];
  334. });
  335. if (emulatorsNotRunning.length > 0 && !constants_1.Constants.isDemoProject(projectId)) {
  336. functionsLogger.logLabeled("WARN", "functions", `The following emulators are not running, calls to these services from the Functions emulator will affect production: ${clc.bold(emulatorsNotRunning.join(", "))}`);
  337. }
  338. const account = (0, auth_2.getProjectDefaultAccount)(options.projectRoot);
  339. const functionsEmulator = new functionsEmulator_1.FunctionsEmulator({
  340. projectId,
  341. projectDir,
  342. emulatableBackends,
  343. account,
  344. host: functionsAddr.host,
  345. port: functionsAddr.port,
  346. debugPort: inspectFunctions,
  347. projectAlias: options.projectAlias,
  348. });
  349. await startEmulator(functionsEmulator);
  350. const eventarcAddr = legacyGetFirstAddr(types_1.Emulators.EVENTARC);
  351. const eventarcEmulator = new eventarcEmulator_1.EventarcEmulator({
  352. host: eventarcAddr.host,
  353. port: eventarcAddr.port,
  354. });
  355. await startEmulator(eventarcEmulator);
  356. }
  357. if (listenForEmulator.firestore) {
  358. const firestoreLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FIRESTORE);
  359. const firestoreAddr = legacyGetFirstAddr(types_1.Emulators.FIRESTORE);
  360. const websocketPort = legacyGetFirstAddr("firestore.websocket").port;
  361. const args = {
  362. host: firestoreAddr.host,
  363. port: firestoreAddr.port,
  364. websocket_port: websocketPort,
  365. project_id: projectId,
  366. auto_download: true,
  367. };
  368. if (exportMetadata.firestore) {
  369. utils.assertIsString(options.import);
  370. const importDirAbsPath = path.resolve(options.import);
  371. const exportMetadataFilePath = path.resolve(importDirAbsPath, exportMetadata.firestore.metadata_file);
  372. firestoreLogger.logLabeled("BULLET", "firestore", `Importing data from ${exportMetadataFilePath}`);
  373. args.seed_from_export = exportMetadataFilePath;
  374. void (0, track_1.trackEmulator)("emulator_import", {
  375. initiated_by: "start",
  376. emulator_name: types_1.Emulators.FIRESTORE,
  377. });
  378. }
  379. const config = options.config;
  380. const rulesLocalPath = (_g = config.src.firestore) === null || _g === void 0 ? void 0 : _g.rules;
  381. let rulesFileFound = false;
  382. if (rulesLocalPath) {
  383. const rules = config.path(rulesLocalPath);
  384. rulesFileFound = fs.existsSync(rules);
  385. if (rulesFileFound) {
  386. args.rules = rules;
  387. }
  388. else {
  389. firestoreLogger.logLabeled("WARN", "firestore", `Cloud Firestore rules file ${clc.bold(rules)} specified in firebase.json does not exist.`);
  390. }
  391. }
  392. else {
  393. firestoreLogger.logLabeled("WARN", "firestore", "Did not find a Cloud Firestore rules file specified in a firebase.json config file.");
  394. }
  395. if (!rulesFileFound) {
  396. firestoreLogger.logLabeled("WARN", "firestore", "The emulator will default to allowing all reads and writes. Learn more about this option: https://firebase.google.com/docs/emulator-suite/install_and_configure#security_rules_configuration.");
  397. }
  398. if (singleProjectModeEnabled) {
  399. if (projectId) {
  400. args.single_project_mode = true;
  401. args.single_project_mode_error = false;
  402. }
  403. else {
  404. firestoreLogger.logLabeled("DEBUG", "firestore", "Could not enable single_project_mode: missing projectId.");
  405. }
  406. }
  407. const firestoreEmulator = new firestoreEmulator_1.FirestoreEmulator(args);
  408. await startEmulator(firestoreEmulator);
  409. firestoreLogger.logLabeled("SUCCESS", types_1.Emulators.FIRESTORE, `Firestore Emulator UI websocket is running on ${websocketPort}.`);
  410. }
  411. if (listenForEmulator.database) {
  412. const databaseLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATABASE);
  413. const databaseAddr = legacyGetFirstAddr(types_1.Emulators.DATABASE);
  414. const args = {
  415. host: databaseAddr.host,
  416. port: databaseAddr.port,
  417. projectId,
  418. auto_download: true,
  419. single_project_mode: singleProjectModeEnabled ? "Warning" : undefined,
  420. };
  421. try {
  422. if (!options.instance) {
  423. options.instance = await (0, getDefaultDatabaseInstance_1.getDefaultDatabaseInstance)(options);
  424. }
  425. }
  426. catch (e) {
  427. databaseLogger.log("DEBUG", `Failed to retrieve default database instance: ${JSON.stringify(e)}`);
  428. }
  429. const rc = dbRulesConfig.normalizeRulesConfig(dbRulesConfig.getRulesConfig(projectId, options), options);
  430. logger_1.logger.debug("database rules config: ", JSON.stringify(rc));
  431. args.rules = rc;
  432. if (rc.length === 0) {
  433. databaseLogger.logLabeled("WARN", "database", "Did not find a Realtime Database rules file specified in a firebase.json config file. The emulator will default to allowing all reads and writes. Learn more about this option: https://firebase.google.com/docs/emulator-suite/install_and_configure#security_rules_configuration.");
  434. }
  435. else {
  436. for (const c of rc) {
  437. const rules = c.rules;
  438. if (!fs.existsSync(rules)) {
  439. databaseLogger.logLabeled("WARN", "database", `Realtime Database rules file ${clc.bold(rules)} specified in firebase.json does not exist.`);
  440. }
  441. }
  442. }
  443. const databaseEmulator = new databaseEmulator_1.DatabaseEmulator(args);
  444. await startEmulator(databaseEmulator);
  445. if (exportMetadata.database) {
  446. utils.assertIsString(options.import);
  447. const importDirAbsPath = path.resolve(options.import);
  448. const databaseExportDir = path.resolve(importDirAbsPath, exportMetadata.database.path);
  449. const files = fs.readdirSync(databaseExportDir).filter((f) => f.endsWith(".json"));
  450. void (0, track_1.trackEmulator)("emulator_import", {
  451. initiated_by: "start",
  452. emulator_name: types_1.Emulators.DATABASE,
  453. count: files.length,
  454. });
  455. for (const f of files) {
  456. const fPath = path.join(databaseExportDir, f);
  457. const ns = path.basename(f, ".json");
  458. await databaseEmulator.importData(ns, fPath);
  459. }
  460. }
  461. }
  462. if (listenForEmulator.auth) {
  463. if (!projectId) {
  464. throw new error_1.FirebaseError(`Cannot start the ${constants_1.Constants.description(types_1.Emulators.AUTH)} without a project: run 'firebase init' or provide the --project flag`);
  465. }
  466. const authAddr = legacyGetFirstAddr(types_1.Emulators.AUTH);
  467. const authEmulator = new auth_1.AuthEmulator({
  468. host: authAddr.host,
  469. port: authAddr.port,
  470. projectId,
  471. singleProjectMode: singleProjectModeEnabled
  472. ? auth_1.SingleProjectMode.WARNING
  473. : auth_1.SingleProjectMode.NO_WARNING,
  474. });
  475. await startEmulator(authEmulator);
  476. if (exportMetadata.auth) {
  477. utils.assertIsString(options.import);
  478. const importDirAbsPath = path.resolve(options.import);
  479. const authExportDir = path.resolve(importDirAbsPath, exportMetadata.auth.path);
  480. await authEmulator.importData(authExportDir, projectId, { initiatedBy: "start" });
  481. }
  482. }
  483. if (listenForEmulator.pubsub) {
  484. if (!projectId) {
  485. throw new error_1.FirebaseError("Cannot start the Pub/Sub emulator without a project: run 'firebase init' or provide the --project flag");
  486. }
  487. const pubsubAddr = legacyGetFirstAddr(types_1.Emulators.PUBSUB);
  488. const pubsubEmulator = new pubsubEmulator_1.PubsubEmulator({
  489. host: pubsubAddr.host,
  490. port: pubsubAddr.port,
  491. projectId,
  492. auto_download: true,
  493. });
  494. await startEmulator(pubsubEmulator);
  495. }
  496. if (listenForEmulator.storage) {
  497. const storageAddr = legacyGetFirstAddr(types_1.Emulators.STORAGE);
  498. const storageEmulator = new storage_1.StorageEmulator({
  499. host: storageAddr.host,
  500. port: storageAddr.port,
  501. projectId: projectId,
  502. rules: (0, config_1.getStorageRulesConfig)(projectId, options),
  503. });
  504. await startEmulator(storageEmulator);
  505. if (exportMetadata.storage) {
  506. utils.assertIsString(options.import);
  507. const importDirAbsPath = path.resolve(options.import);
  508. const storageExportDir = path.resolve(importDirAbsPath, exportMetadata.storage.path);
  509. storageEmulator.storageLayer.import(storageExportDir, { initiatedBy: "start" });
  510. }
  511. }
  512. if (listenForEmulator.hosting) {
  513. const hostingAddr = legacyGetFirstAddr(types_1.Emulators.HOSTING);
  514. const hostingEmulator = new hostingEmulator_1.HostingEmulator({
  515. host: hostingAddr.host,
  516. port: hostingAddr.port,
  517. options,
  518. });
  519. await startEmulator(hostingEmulator);
  520. }
  521. if (showUI && !shouldStart(options, types_1.Emulators.UI)) {
  522. hubLogger.logLabeled("WARN", "emulators", "The Emulator UI is not starting, either because none of the emulated " +
  523. "products have an interaction layer in Emulator UI or it cannot " +
  524. "determine the Project ID. Pass the --project flag to specify a project.");
  525. }
  526. if (listenForEmulator.logging) {
  527. const loggingAddr = legacyGetFirstAddr(types_1.Emulators.LOGGING);
  528. const loggingEmulator = new loggingEmulator_1.LoggingEmulator({
  529. host: loggingAddr.host,
  530. port: loggingAddr.port,
  531. });
  532. await startEmulator(loggingEmulator);
  533. }
  534. if (listenForEmulator.ui) {
  535. const ui = new ui_1.EmulatorUI({
  536. projectId: projectId,
  537. auto_download: true,
  538. listen: listenForEmulator[types_1.Emulators.UI],
  539. });
  540. await startEmulator(ui);
  541. }
  542. let serviceEmulatorCount = 0;
  543. const running = registry_1.EmulatorRegistry.listRunning();
  544. for (const name of running) {
  545. const instance = registry_1.EmulatorRegistry.get(name);
  546. if (instance) {
  547. await instance.connect();
  548. }
  549. if (types_1.ALL_SERVICE_EMULATORS.includes(name)) {
  550. serviceEmulatorCount++;
  551. }
  552. }
  553. void (0, track_1.trackEmulator)("emulators_started", {
  554. count: serviceEmulatorCount,
  555. count_all: running.length,
  556. is_demo_project: String(isDemoProject),
  557. });
  558. return { deprecationNotices: [] };
  559. }
  560. exports.startAll = startAll;
  561. function getListenConfig(options, emulator) {
  562. var _a, _b, _c, _d;
  563. let host = ((_b = (_a = options.config.src.emulators) === null || _a === void 0 ? void 0 : _a[emulator]) === null || _b === void 0 ? void 0 : _b.host) || constants_1.Constants.getDefaultHost();
  564. if (host === "localhost" && utils.isRunningInWSL()) {
  565. host = "127.0.0.1";
  566. }
  567. const portVal = (_d = (_c = options.config.src.emulators) === null || _c === void 0 ? void 0 : _c[emulator]) === null || _d === void 0 ? void 0 : _d.port;
  568. let port;
  569. let portFixed;
  570. if (portVal) {
  571. port = parseInt(`${portVal}`, 10);
  572. portFixed = true;
  573. }
  574. else {
  575. port = constants_1.Constants.getDefaultPort(emulator);
  576. portFixed = !constants_1.FIND_AVAILBLE_PORT_BY_DEFAULT[emulator];
  577. }
  578. return {
  579. host,
  580. port,
  581. portFixed,
  582. };
  583. }
  584. async function exportEmulatorData(exportPath, options, initiatedBy) {
  585. const projectId = options.project;
  586. if (!projectId) {
  587. throw new error_1.FirebaseError("Could not determine project ID, make sure you're running in a Firebase project directory or add the --project flag.", { exit: 1 });
  588. }
  589. const hubClient = new hubClient_1.EmulatorHubClient(projectId);
  590. if (!hubClient.foundHub()) {
  591. throw new error_1.FirebaseError(`Did not find any running emulators for project ${clc.bold(projectId)}.`, { exit: 1 });
  592. }
  593. let origin;
  594. try {
  595. origin = await hubClient.getStatus();
  596. }
  597. catch (e) {
  598. const filePath = hub_1.EmulatorHub.getLocatorFilePath(projectId);
  599. throw new error_1.FirebaseError(`The emulator hub for ${projectId} did not respond to a status check. If this error continues try shutting down all running emulators and deleting the file ${filePath}`, { exit: 1 });
  600. }
  601. utils.logBullet(`Found running emulator hub for project ${clc.bold(projectId)} at ${origin}`);
  602. const exportAbsPath = path.resolve(exportPath);
  603. if (!fs.existsSync(exportAbsPath)) {
  604. utils.logBullet(`Creating export directory ${exportAbsPath}`);
  605. fs.mkdirSync(exportAbsPath);
  606. }
  607. const existingMetadata = hubExport_1.HubExport.readMetadata(exportAbsPath);
  608. if (existingMetadata && !(options.force || options.exportOnExit)) {
  609. if (options.noninteractive) {
  610. throw new error_1.FirebaseError("Export already exists in the target directory, re-run with --force to overwrite.", { exit: 1 });
  611. }
  612. const prompt = await (0, prompt_1.promptOnce)({
  613. type: "confirm",
  614. message: `The directory ${exportAbsPath} already contains export data. Exporting again to the same directory will overwrite all data. Do you want to continue?`,
  615. default: false,
  616. });
  617. if (!prompt) {
  618. throw new error_1.FirebaseError("Command aborted", { exit: 1 });
  619. }
  620. }
  621. utils.logBullet(`Exporting data to: ${exportAbsPath}`);
  622. try {
  623. await hubClient.postExport({ path: exportAbsPath, initiatedBy });
  624. }
  625. catch (e) {
  626. throw new error_1.FirebaseError("Export request failed, see emulator logs for more information.", {
  627. exit: 1,
  628. original: e,
  629. });
  630. }
  631. utils.logSuccess("Export complete");
  632. }
  633. exports.exportEmulatorData = exportEmulatorData;