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.

hosting-channel-deploy.js 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.command = void 0;
  4. const colorette_1 = require("colorette");
  5. const command_1 = require("../command");
  6. const error_1 = require("../error");
  7. const api_1 = require("../hosting/api");
  8. const requirePermissions_1 = require("../requirePermissions");
  9. const deploy_1 = require("../deploy");
  10. const projectUtils_1 = require("../projectUtils");
  11. const logger_1 = require("../logger");
  12. const requireConfig_1 = require("../requireConfig");
  13. const expireUtils_1 = require("../hosting/expireUtils");
  14. const utils_1 = require("../utils");
  15. const config_1 = require("../hosting/config");
  16. const { marked } = require("marked");
  17. const requireHostingSite_1 = require("../requireHostingSite");
  18. const LOG_TAG = "hosting:channel";
  19. exports.command = new command_1.Command("hosting:channel:deploy [channelId]")
  20. .description("deploy to a specific Firebase Hosting channel")
  21. .option("-e, --expires <duration>", "duration string (e.g. 12h, 30d) for channel expiration, max 30d; defaults to 7d")
  22. .option("--only <target1,target2...>", "only create previews for specified targets")
  23. .option("--open", "open a browser to the channel after deploying")
  24. .option("--no-authorized-domains", "do not sync channel domains with Firebase Auth")
  25. .before(requireConfig_1.requireConfig)
  26. .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
  27. .before(requireHostingSite_1.requireHostingSite)
  28. .action(async (channelId, options) => {
  29. const projectId = (0, projectUtils_1.needProjectId)(options);
  30. if (options.open) {
  31. throw new error_1.FirebaseError("open is not yet implemented");
  32. }
  33. let expireTTL = expireUtils_1.DEFAULT_DURATION;
  34. if (options.expires) {
  35. expireTTL = (0, expireUtils_1.calculateChannelExpireTTL)(options.expires);
  36. logger_1.logger.debug(`Expires TTL: ${expireTTL}`);
  37. }
  38. if (!channelId) {
  39. throw new error_1.FirebaseError("channelID is currently required");
  40. }
  41. channelId = (0, api_1.normalizeName)(channelId);
  42. if (channelId.toLowerCase().trim() === "live") {
  43. throw new error_1.FirebaseError(`Cannot deploy to the ${(0, colorette_1.bold)("live")} channel using this command. Please use ${(0, colorette_1.bold)((0, colorette_1.yellow)("firebase deploy"))} instead.`);
  44. }
  45. if (options.only) {
  46. options.only = options.only
  47. .split(",")
  48. .map((o) => `hosting:${o}`)
  49. .join(",");
  50. }
  51. const sites = (0, config_1.hostingConfig)(options).map((config) => {
  52. return {
  53. target: config.target,
  54. site: config.site,
  55. url: "",
  56. version: "",
  57. expireTime: "",
  58. };
  59. });
  60. await Promise.all(sites.map(async (siteInfo) => {
  61. const site = siteInfo.site;
  62. let chan = await (0, api_1.getChannel)(projectId, site, channelId);
  63. if (chan) {
  64. logger_1.logger.debug("[hosting] found existing channel for site", site, chan);
  65. const channelExpires = Boolean(chan.expireTime);
  66. if (!channelExpires && options.expires) {
  67. chan = await (0, api_1.updateChannelTtl)(projectId, site, channelId, expireTTL);
  68. }
  69. else if (channelExpires) {
  70. const channelTimeRemaining = new Date(chan.expireTime).getTime() - Date.now();
  71. if (options.expires || channelTimeRemaining < expireTTL) {
  72. chan = await (0, api_1.updateChannelTtl)(projectId, site, channelId, expireTTL);
  73. logger_1.logger.debug("[hosting] updated TTL for existing channel for site", site, chan);
  74. }
  75. }
  76. }
  77. else {
  78. chan = await (0, api_1.createChannel)(projectId, site, channelId, expireTTL);
  79. logger_1.logger.debug("[hosting] created new channnel for site", site, chan);
  80. (0, utils_1.logLabeledSuccess)(LOG_TAG, `Channel ${(0, colorette_1.bold)(channelId)} has been created on site ${(0, colorette_1.bold)(site)}.`);
  81. }
  82. siteInfo.url = chan.url;
  83. siteInfo.expireTime = chan.expireTime;
  84. return;
  85. }));
  86. const { hosting } = await (0, deploy_1.deploy)(["hosting"], options, { hostingChannel: channelId });
  87. const versionNames = [];
  88. if (typeof hosting === "string") {
  89. versionNames.push(hosting);
  90. }
  91. else if (Array.isArray(hosting)) {
  92. hosting.forEach((version) => {
  93. versionNames.push(version);
  94. });
  95. }
  96. if (options.authorizedDomains) {
  97. await syncAuthState(projectId, sites);
  98. }
  99. else {
  100. logger_1.logger.debug(`skipping syncAuthState since authorizedDomains is ${options.authorizedDomains}`);
  101. }
  102. logger_1.logger.info();
  103. const deploys = {};
  104. sites.forEach((d) => {
  105. deploys[d.target || d.site] = d;
  106. let expires = "";
  107. if (d.expireTime) {
  108. expires = `[expires ${(0, colorette_1.bold)((0, utils_1.datetimeString)(new Date(d.expireTime)))}]`;
  109. }
  110. const versionPrefix = `sites/${d.site}/versions/`;
  111. const versionName = versionNames.find((v) => {
  112. return v.startsWith(versionPrefix);
  113. });
  114. let version = "";
  115. if (versionName) {
  116. d.version = versionName.replace(versionPrefix, "");
  117. version = ` [version ${(0, colorette_1.bold)(d.version)}]`;
  118. }
  119. (0, utils_1.logLabeledSuccess)(LOG_TAG, `Channel URL (${(0, colorette_1.bold)(d.site || d.target || "")}): ${d.url} ${expires}${version}`);
  120. });
  121. return deploys;
  122. });
  123. async function syncAuthState(projectId, sites) {
  124. const siteNames = sites.map((d) => d.site);
  125. const urlNames = sites.map((d) => d.url);
  126. try {
  127. await (0, api_1.addAuthDomains)(projectId, urlNames);
  128. logger_1.logger.debug("[hosting] added auth domain for urls", urlNames);
  129. }
  130. catch (e) {
  131. (0, utils_1.logLabeledWarning)(LOG_TAG, marked(`Unable to add channel domain to Firebase Auth. Visit the Firebase Console at ${(0, utils_1.consoleUrl)(projectId, "/authentication/providers")}`));
  132. logger_1.logger.debug("[hosting] unable to add auth domain", e);
  133. }
  134. try {
  135. await (0, api_1.cleanAuthState)(projectId, siteNames);
  136. }
  137. catch (e) {
  138. (0, utils_1.logLabeledWarning)(LOG_TAG, "Unable to sync Firebase Auth state.");
  139. logger_1.logger.debug("[hosting] unable to sync auth domain", e);
  140. }
  141. }