"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.promptForMinInstances = exports.promptForFunctionDeletion = exports.promptForFailurePolicies = void 0; const clc = require("colorette"); const functionsDeployHelper_1 = require("./functionsDeployHelper"); const error_1 = require("../../error"); const prompt_1 = require("../../prompt"); const logger_1 = require("../../logger"); const backend = require("./backend"); const pricing = require("./pricing"); const utils = require("../../utils"); async function promptForFailurePolicies(options, want, have) { const retryEndpoints = backend.allEndpoints(want).filter((e) => { return backend.isEventTriggered(e) && e.eventTrigger.retry; }); if (retryEndpoints.length === 0) { return; } const newRetryEndpoints = retryEndpoints.filter((endpoint) => { var _a; const existing = (_a = have.endpoints[endpoint.region]) === null || _a === void 0 ? void 0 : _a[endpoint.id]; return !(existing && backend.isEventTriggered(existing) && existing.eventTrigger.retry); }); if (newRetryEndpoints.length === 0) { return; } const warnMessage = "The following functions will newly be retried in case of failure: " + clc.bold(newRetryEndpoints.sort(backend.compareFunctions).map(functionsDeployHelper_1.getFunctionLabel).join(", ")) + ". " + "Retried executions are billed as any other execution, and functions are retried repeatedly until they either successfully execute or the maximum retry period has elapsed, which can be up to 7 days. " + "For safety, you might want to ensure that your functions are idempotent; see https://firebase.google.com/docs/functions/retries to learn more."; utils.logLabeledWarning("functions", warnMessage); if (options.force) { return; } if (options.nonInteractive) { throw new error_1.FirebaseError("Pass the --force option to deploy functions with a failure policy", { exit: 1, }); } const proceed = await (0, prompt_1.promptOnce)({ type: "confirm", name: "confirm", default: false, message: "Would you like to proceed with deployment?", }); if (!proceed) { throw new error_1.FirebaseError("Deployment canceled.", { exit: 1 }); } } exports.promptForFailurePolicies = promptForFailurePolicies; async function promptForFunctionDeletion(functionsToDelete, force, nonInteractive) { let shouldDeleteFns = true; if (functionsToDelete.length === 0 || force) { return true; } const deleteList = functionsToDelete .sort(backend.compareFunctions) .map((fn) => "\t" + (0, functionsDeployHelper_1.getFunctionLabel)(fn)) .join("\n"); if (nonInteractive) { const deleteCommands = functionsToDelete .map((func) => { return "\tfirebase functions:delete " + func.id + " --region " + func.region; }) .join("\n"); throw new error_1.FirebaseError("The following functions are found in your project but do not exist in your local source code:\n" + deleteList + "\n\nAborting because deletion cannot proceed in non-interactive mode. To fix, manually delete the functions by running:\n" + clc.bold(deleteCommands)); } else { logger_1.logger.info("\nThe following functions are found in your project but do not exist in your local source code:\n" + deleteList + "\n\nIf you are renaming a function or changing its region, it is recommended that you create the new " + "function first before deleting the old one to prevent event loss. For more info, visit " + clc.underline("https://firebase.google.com/docs/functions/manage-functions#modify" + "\n")); shouldDeleteFns = await (0, prompt_1.promptOnce)({ type: "confirm", name: "confirm", default: false, message: "Would you like to proceed with deletion? Selecting no will continue the rest of the deployments.", }); } return shouldDeleteFns; } exports.promptForFunctionDeletion = promptForFunctionDeletion; async function promptForMinInstances(options, want, have) { if (options.force) { return; } const increasesCost = backend.someEndpoint(want, (wantE) => { var _a; if (!pricing.canCalculateMinInstanceCost(wantE)) { return true; } const wantCost = pricing.monthlyMinInstanceCost([wantE]); const haveE = (_a = have.endpoints[wantE.region]) === null || _a === void 0 ? void 0 : _a[wantE.id]; let haveCost; if (!haveE) { haveCost = 0; } else if (!pricing.canCalculateMinInstanceCost(wantE)) { return true; } else { haveCost = pricing.monthlyMinInstanceCost([haveE]); } return wantCost > haveCost; }); if (!increasesCost) { return; } if (options.nonInteractive) { throw new error_1.FirebaseError("Pass the --force option to deploy functions that increase the minimum bill", { exit: 1, }); } const functionLines = backend .allEndpoints(want) .filter((fn) => fn.minInstances) .sort(backend.compareFunctions) .map((fn) => { return (`\t${(0, functionsDeployHelper_1.getFunctionLabel)(fn)}: ${fn.minInstances} instances, ` + backend.memoryOptionDisplayName(fn.availableMemoryMb || backend.DEFAULT_MEMORY) + " of memory each"); }) .join("\n"); let costLine; if (backend.someEndpoint(want, (fn) => !pricing.canCalculateMinInstanceCost(fn))) { costLine = "Cannot calculate the minimum monthly bill for this configuration. Consider running " + clc.bold("npm install -g firebase-tools"); } else { const cost = pricing.monthlyMinInstanceCost(backend.allEndpoints(want)).toFixed(2); costLine = `With these options, your minimum bill will be $${cost} in a 30-day month`; } const warnMessage = "The following functions have reserved minimum instances. This will " + "reduce the frequency of cold starts but increases the minimum cost. " + "You will be charged for the memory allocation and a fraction of the " + "CPU allocation of instances while they are idle.\n\n" + functionLines + "\n\n" + costLine; utils.logLabeledWarning("functions", warnMessage); const proceed = await (0, prompt_1.promptOnce)({ type: "confirm", name: "confirm", default: false, message: "Would you like to proceed with deployment?", }); if (!proceed) { throw new error_1.FirebaseError("Deployment canceled.", { exit: 1 }); } } exports.promptForMinInstances = promptForMinInstances;