aws-cdk
Version:
AWS CDK CLI, the command line tool for CDK apps
829 lines • 119 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CliIoHost = void 0;
exports.matchAny = matchAny;
const util = __importStar(require("node:util"));
const cloud_assembly_schema_1 = require("@aws-cdk/cloud-assembly-schema");
const toolkit_lib_1 = require("@aws-cdk/toolkit-lib");
const chalk_1 = __importDefault(require("chalk"));
const promptly = __importStar(require("promptly"));
const api_private_1 = require("../../../lib/api-private");
const deploy_1 = require("../../commands/deploy");
const collect_telemetry_1 = require("../telemetry/collect-telemetry");
const error_1 = require("../telemetry/error");
const messages_1 = require("../telemetry/messages");
const session_1 = require("../telemetry/session");
const endpoint_sink_1 = require("../telemetry/sink/endpoint-sink");
const file_sink_1 = require("../telemetry/sink/file-sink");
const funnel_1 = require("../telemetry/sink/funnel");
const ci_1 = require("../util/ci");
/**
* A simple IO host for the CLI that writes messages to the console.
*/
class CliIoHost {
/**
* Returns the singleton instance
*/
static instance(props = {}, forceNew = false) {
if (forceNew || !CliIoHost._instance) {
CliIoHost._instance = new CliIoHost(props);
}
return CliIoHost._instance;
}
/**
* Returns the singleton instance if it exists
*/
static get() {
return CliIoHost._instance;
}
/**
* Singleton instance of the CliIoHost
*/
static _instance;
/**
* The current action being performed by the CLI.
*/
currentAction;
/**
* Whether the CliIoHost is running in CI mode.
*
* In CI mode, all non-error output goes to stdout instead of stderr.
*/
isCI;
/**
* Whether the host can use interactions and message styling.
*/
isTTY;
/**
* The current threshold.
*
* Messages with a lower priority level will be ignored.
*/
logLevel;
/**
* The conditions for requiring approval in this CliIoHost.
*/
requireDeployApproval;
/**
* Configure the target stream for notices
*
* (Not a setter because there's no need for additional logic when this value
* is changed yet)
*/
noticesDestination = 'stderr';
_progress = deploy_1.StackActivityProgress.BAR;
// Stack Activity Printer
activityPrinter;
// Corked Logging
corkedCounter = 0;
corkedLoggingBuffer = [];
// Message listeners in registration order. Each carries a matcher (by code,
// or a custom predicate). See `on`/`once`/`rewrite`/`respond`.
messageListeners = [];
// Observers of how messages are handled (see ObservableIoHost / observeMessages).
messageObservers = new Set();
// True while replaying corked messages, so observers aren't notified twice.
corkReplaying = false;
autoRespond;
/**
* The telemetry session object
*
* Will remain `undefined` if the user has disabled telemetry.
*/
telemetry;
constructor(props = {}) {
this.currentAction = props.currentAction ?? 'none';
this.isTTY = props.isTTY ?? process.stdout.isTTY ?? false;
this.logLevel = props.logLevel ?? 'info';
this.isCI = props.isCI ?? (0, ci_1.isCI)();
this.requireDeployApproval = props.requireDeployApproval ?? cloud_assembly_schema_1.RequireApproval.BROADENING;
this.stackProgress = props.stackProgress ?? deploy_1.StackActivityProgress.BAR;
this.autoRespond = props.autoRespond ?? false;
// Stack-activity messages are handled by the activity printer rather than
// written to a stream. This is wired up as message listeners.
this.routeStackActivityToPrinter();
}
async startTelemetry(args, context, proxyAgent) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const config = require('../cli-type-registry.json');
const validCommands = Object.keys(config.commands);
const cmd = args._[0];
if (!validCommands.includes(cmd)) {
// the user typed in an invalid command - no need for telemetry since the invocation is going to fail
// imminently anyway.
await this.asIoHelper().defaults.trace(`Session instantiated with an invalid command (${cmd}). Not starting telemetry.`);
return;
}
let sinks = [];
const telemetryFilePath = args['telemetry-file'];
if (telemetryFilePath) {
try {
sinks.push(new file_sink_1.FileTelemetrySink({
ioHost: this,
logFilePath: telemetryFilePath,
}));
await this.asIoHelper().defaults.trace('File Telemetry connected');
}
catch (e) {
await this.asIoHelper().defaults.trace(`File Telemetry instantiation failed: ${e.message}`);
}
}
const telemetryEndpoint = process.env.TELEMETRY_ENDPOINT ?? 'https://cdk-cli-telemetry.us-east-1.api.aws/metrics';
if ((0, collect_telemetry_1.canCollectTelemetry)(args, context) && telemetryEndpoint) {
try {
sinks.push(new endpoint_sink_1.EndpointTelemetrySink({
ioHost: this,
agent: proxyAgent,
endpoint: telemetryEndpoint,
}));
await this.asIoHelper().defaults.trace('Endpoint Telemetry connected');
}
catch (e) {
await this.asIoHelper().defaults.trace(`Endpoint Telemetry instantiation failed: ${e.message}`);
}
}
else {
await this.asIoHelper().defaults.trace('Endpoint Telemetry NOT connected');
}
if (sinks.length > 0) {
this.telemetry = new session_1.TelemetrySession({
ioHost: this,
client: new funnel_1.Funnel({ sinks }),
arguments: args,
context: context,
});
}
await this.telemetry?.begin();
}
/**
* Update the stackProgress preference.
*/
set stackProgress(type) {
this._progress = type;
}
/**
* Gets the stackProgress value.
*
* This takes into account other state of the ioHost,
* like if isTTY and isCI.
*/
get stackProgress() {
// We can always use EVENTS
if (this._progress === deploy_1.StackActivityProgress.EVENTS) {
return this._progress;
}
// if a debug message (and thus any more verbose messages) are relevant to the current log level, we have verbose logging
const verboseLogging = (0, api_private_1.isMessageRelevantForLevel)({ level: 'debug' }, this.logLevel);
if (verboseLogging) {
return deploy_1.StackActivityProgress.EVENTS;
}
// On Windows we cannot use fancy output
const isWindows = process.platform === 'win32';
if (isWindows) {
return deploy_1.StackActivityProgress.EVENTS;
}
// On some CI systems (such as CircleCI) output still reports as a TTY so we also
// need an individual check for whether we're running on CI.
// see: https://discuss.circleci.com/t/circleci-terminal-is-a-tty-but-term-is-not-set/9965
const fancyOutputAvailable = this.isTTY && !this.isCI;
if (!fancyOutputAvailable) {
return deploy_1.StackActivityProgress.EVENTS;
}
// Use the user preference
return this._progress;
}
get defaults() {
return this.asIoHelper().defaults;
}
asIoHelper() {
return (0, api_private_1.asIoHelper)(this, this.currentAction);
}
/**
* Executes a block of code with corked logging. All log messages during execution
* are buffered and only written when all nested cork blocks complete (when CORK_COUNTER reaches 0).
* The corking is bound to the specific instance of the CliIoHost.
*
* @param block - Async function to execute with corked logging
* @returns Promise that resolves with the block's return value
*/
async withCorkedLogging(block) {
this.corkedCounter++;
try {
return await block();
}
finally {
this.corkedCounter--;
if (this.corkedCounter === 0) {
// Process each buffered message through notify
this.corkReplaying = true;
try {
for (const ioMessage of this.corkedLoggingBuffer) {
await this.notify(ioMessage);
}
}
finally {
this.corkReplaying = false;
}
// remove all buffered messages in-place
this.corkedLoggingBuffer.splice(0);
}
}
}
on(selector, listener) {
return this.addMessageListener({ once: false, fn: listener, matches: messageMatcher(selector) });
}
/**
* Register an observer that is invoked for every message the host handles —
* both notifications and requests — with the disposition the host computed
* for it (its effective form after listeners and whether it was dropped). For
* a request, the resolved answer is the effective message's `defaultResponse`.
* Returns a function that removes the observer.
*
* @see ObservableIoHost
*/
observeMessages(observer) {
this.messageObservers.add(observer);
return () => {
this.messageObservers.delete(observer);
};
}
once(selector, listener) {
return this.addMessageListener({ once: true, fn: listener, matches: messageMatcher(selector) });
}
/**
* Remove every message listener registered via `on`/`once`/`rewrite`/`respond`.
*
* The host's own internal listeners (such as stack-activity routing) are kept,
* so the host keeps working afterwards. Message observers registered via
* `observeMessages` are a separate mechanism and are not affected.
*
* This is mainly useful for tests that share the singleton host and need to
* reset listener state between cases (a leftover listener would otherwise
* leak into the next test).
*/
removeAllListeners() {
// Drop user listeners in place (preserving array identity for any
// outstanding dispose closures); keep the host's internal listeners.
for (let i = this.messageListeners.length - 1; i >= 0; i--) {
if (!this.messageListeners[i].internal) {
this.messageListeners.splice(i, 1);
}
}
}
/**
* Answer a request (by its code) on the user's behalf with a fixed value, so
* the host does not prompt. Syntactic sugar for an `on` listener returning
* `{ respond: value, preventDefault: suppressQuestion }`; for conditional
* answers or to also reword the question, use `on`/`once` directly. Returns a
* function that removes the responder again.
*
* @param suppressQuestion - whether to also suppress writing the question text.
* Defaults to `true` (answer silently). Pass `false` to still surface the
* question while answering it.
*
* @example
* // Under --force, auto-confirm the destroy prompt without prompting.
* const dispose = ioHost.respond(IO.CDK_TOOLKIT_I7010, true);
*/
respond(code, value, suppressQuestion = true) {
return this.addMessageListener({ once: false, fn: () => ({ respond: value, preventDefault: suppressQuestion }), matches: messageMatcher(code) });
}
/**
* Like `respond`, but the answer is given only once and then removed.
*/
respondOnce(code, value, suppressQuestion = true) {
return this.addMessageListener({ once: true, fn: () => ({ respond: value, preventDefault: suppressQuestion }), matches: messageMatcher(code) });
}
/**
* Register a formatter that replaces the printed text of messages with the
* given code. This lets a caller define _how_ a toolkit message is presented
* without the IoHost needing to know about it.
*
* Optionally pass a `level` to also override the message's level (which moves
* it between stdout/stderr and changes verbosity filtering). For the rarer
* case of overriding only the level, use `on`/`once` returning `{ level }`.
*
* Syntactic sugar for an `on` listener that returns `{ message, level? }`.
* Returns a function that removes the formatter again.
*
* @example
* const dispose = ioHost.rewrite(IO.CDK_TOOLKIT_I2901, (msg) =>
* serializeStructure(msg.data.stacks, true));
*/
rewrite(code, formatter, level) {
return this.on(code, (msg) => ({ message: formatter(msg), ...(level !== undefined ? { level } : {}) }));
}
/**
* Like `rewrite`, but the formatter is automatically removed after it has
* been applied once.
*/
rewriteOnce(code, formatter, level) {
return this.once(code, (msg) => ({ message: formatter(msg), ...(level !== undefined ? { level } : {}) }));
}
/**
* Add a listener to the registry and return a function that removes it.
*/
addMessageListener(listener) {
this.messageListeners.push(listener);
return () => {
const index = this.messageListeners.indexOf(listener);
if (index >= 0) {
this.messageListeners.splice(index, 1);
}
};
}
/**
* Run every registered listener that matches the message, in registration
* order. A listener matches by its code (maker) or its custom predicate.
*
* A listener may update the message text/level (passed on to subsequent
* listeners and the rest of the pipeline), prevent the default processing, or
* (for requests) answer it. `once` listeners are removed after they have run.
* Matching is decided against the message as emitted, so a rewrite by an
* earlier listener does not change which later listeners apply.
*
* Returns the (possibly updated) message, whether the default processing was
* prevented, and whether a listener answered the request (and with what).
*/
async applyMessageListeners(msg) {
let current = msg;
let preventDefault = false;
let responded = false;
// Iterate over a copy so that `once` listeners can remove themselves safely.
for (const listener of [...this.messageListeners]) {
// Match against the emitted message; a listener receives the cumulatively
// transformed `current` message.
if (!listener.matches(msg)) {
continue;
}
// Listeners may be async; await each one before running the next so the
// cumulative effect on the message stays order-deterministic.
const result = await listener.fn(current);
if (listener.once) {
const index = this.messageListeners.indexOf(listener);
if (index >= 0) {
this.messageListeners.splice(index, 1);
}
}
if (result) {
if (result.message !== undefined) {
current = { ...current, message: result.message };
}
if (result.level !== undefined) {
current = { ...current, level: result.level };
}
if (result.preventDefault) {
preventDefault = true;
}
if ('respond' in result && 'defaultResponse' in msg) {
// Fold the answer into the request's default response and mark it
// answered, so we skip prompting and resolve with this value.
current = { ...current, defaultResponse: result.respond };
responded = true;
}
}
}
return { message: current, preventDefault, responded };
}
/**
* Notifies the host of a message.
* The caller waits until the notification completes.
*/
async notify(msg) {
await this.maybeEmitTelemetry(msg);
// Run any registered listeners. A listener may update the message text
// and/or prevent the default processing (e.g. stack-activity messages are
// routed to the activity printer and not written to a stream).
const { message, preventDefault } = await this.applyMessageListeners(msg);
// Tell observers how this message was handled (its effective form and
// whether it was dropped). Skipped while replaying corked messages so each
// message is observed exactly once.
if (!this.corkReplaying) {
this.notifyObservers({ type: 'notify', emitted: msg, effective: message, dropped: preventDefault });
}
if (preventDefault) {
return;
}
this.writeMessage(message);
}
/**
* Notify every registered message observer of how a message or request was
* handled. A no-op when nothing is observing (i.e. outside of tests), so the
* surrounding hot paths pay nothing in production.
*/
notifyObservers(observation) {
if (this.messageObservers.size === 0) {
return;
}
for (const observer of this.messageObservers) {
observer(observation);
}
}
/**
* Write a (already listener-processed) message to its target stream, honoring
* the log level and corked-logging buffer. Shared by `notify` and the
* non-prompting `requestResponse` path.
*/
writeMessage(message) {
if (!(0, api_private_1.isMessageRelevantForLevel)(message, this.logLevel)) {
return;
}
if (this.corkedCounter > 0) {
this.corkedLoggingBuffer.push(message);
return;
}
const output = this.formatMessage(message);
const stream = this.selectStream(message);
stream?.write(output);
}
async maybeEmitTelemetry(msg) {
try {
const telemetryEvent = eventFromMessage(msg);
if (telemetryEvent) {
await this.telemetry?.emit(telemetryEvent);
}
}
catch (e) {
await this.defaults.trace(`Emit Telemetry Failed ${e.message}`);
}
}
/**
* Route stack-activity messages to the activity printer (progress bar or
* event list) rather than writing them to a stream.
*
* Implemented as listeners that handle the message via the printer and
* prevent the default processing, so the rest of the pipeline does not also
* emit them. The printer is created lazily on the first stack-activity message.
*/
routeStackActivityToPrinter() {
const route = (msg) => {
if (!this.activityPrinter) {
this.activityPrinter = this.makeActivityPrinter();
}
this.activityPrinter.notify(msg);
return { preventDefault: true }; // handled by the printer; don't also write to a stream
};
// A single internal listener (so it survives `removeAllListeners()` and the
// host keeps routing stack activity) matching any of the activity codes.
this.addMessageListener({
once: false,
internal: true,
fn: route,
matches: matchAny(api_private_1.IO.CDK_TOOLKIT_I5501, api_private_1.IO.CDK_TOOLKIT_I5502, api_private_1.IO.CDK_TOOLKIT_I5503),
});
}
/**
* Detect special messages encode information about whether or not
* they require approval
*/
skipApprovalStep(msg) {
const approvalToolkitCodes = ['CDK_TOOLKIT_I5060'];
if (!(msg.code && approvalToolkitCodes.includes(msg.code))) {
return false;
}
switch (this.requireDeployApproval) {
// Never require approval
case cloud_assembly_schema_1.RequireApproval.NEVER:
return true;
// Always require approval
case cloud_assembly_schema_1.RequireApproval.ANYCHANGE:
return false;
// Require approval if changes include broadening permissions
case cloud_assembly_schema_1.RequireApproval.BROADENING:
return ['none', 'non-broadening'].includes(msg.data?.permissionChangeType);
}
}
/**
* Determines the output stream, based on message and configuration.
*/
selectStream(msg) {
if (isNoticesMessage(msg)) {
return targetStreamObject(this.noticesDestination);
}
return this.selectStreamFromLevel(msg.level);
}
/**
* Determines the output stream, based on message level and configuration.
*/
selectStreamFromLevel(level) {
// The stream selection policy for the CLI is the following:
//
// (1) Messages of level `result` always go to `stdout`
// (2) Messages of level `error` always go to `stderr`.
// (3a) All remaining messages go to `stderr`.
// (3b) If we are in CI mode, all remaining messages go to `stdout`.
//
switch (level) {
case 'error':
return process.stderr;
case 'result':
return process.stdout;
default:
return this.isCI ? process.stdout : process.stderr;
}
}
/**
* Notifies the host of a message that requires a response.
*
* Registered listeners run first: a listener may reword the question (its text
* or level) or answer it outright via `respond` (e.g. `--force` auto-confirms
* a destroy). If no listener answers and the host cannot prompt, the suggested
* default response is used.
*/
async requestResponse(msg) {
// Listeners run exactly once here (so we don't go back through `notify`):
// they may answer the request, or reword/relevel the question shown below.
const { message, ...listenerResult } = await this.applyMessageListeners(msg);
const response = await this.resolveRequest(message, listenerResult);
// Tell observers how this request was handled: the effective (possibly reworded) question
// and the resolved response. When a listener answered the request with the question suppressed
// (`preventDefault`, e.g. `--force` auto-confirm), it is reported as `dropped` since the user never saw it.
this.notifyObservers({ type: 'request', emitted: msg, effective: message, dropped: listenerResult.preventDefault });
return response;
}
/**
* Resolve a request to its response: a listener's answer if one was given,
* otherwise the answer prompted from the user, otherwise the suggested
* default when the host cannot prompt.
*
* Kept separate from `requestResponse` so the response can be observed in a
* single place regardless of which of these paths produced it.
*/
async resolveRequest(msg, listenerResult) {
// stop processing, a listener has taken care of it
if (listenerResult.preventDefault) {
return msg.defaultResponse;
}
// if a listener provided a response, we skip interaction
if (!isPromptableRequest(msg) || listenerResult.responded) {
this.writeMessage(msg);
return msg.defaultResponse;
}
const response = await this.withCorkedLogging(async () => {
// prepare prompt data
// @todo this format is not defined anywhere, probably should be
const data = msg.data ?? {};
const motivation = data.motivation ?? 'User input is needed';
const concurrency = data.concurrency ?? 0;
const responseDescription = data.responseDescription;
// Special approval prompt
// Determine if the message needs approval. If it does, continue (it is a basic confirmation prompt)
// If it does not, return success (true). We only check messages with codes that we are aware
// are requires approval codes.
if (this.skipApprovalStep(msg)) {
return true;
}
// In --yes mode, respond for the user if we can
if (this.autoRespond) {
// respond with yes to all confirmations
if (isConfirmationPrompt(msg)) {
await this.writeMessage({
...msg,
message: `${chalk_1.default.cyan(msg.message)} (auto-confirmed)`,
});
return true;
}
// respond with the default for all other messages
if (msg.defaultResponse) {
await this.writeMessage({
...msg,
message: `${chalk_1.default.cyan(msg.message)} (auto-responded with default: ${util.format(msg.defaultResponse)})`,
});
return msg.defaultResponse;
}
}
// only talk to user if STDIN is a terminal (otherwise, fail)
if (!this.isTTY) {
throw new toolkit_lib_1.ToolkitError('TtyNotAttached', `${motivation}, but terminal (TTY) is not attached so we are unable to get a confirmation from the user`);
}
// only talk to user if concurrency is 1 (otherwise, fail)
if (concurrency > 1) {
throw new toolkit_lib_1.ToolkitError('ConcurrencyConflict', `${motivation}, but concurrency is greater than 1 so we are unable to get a confirmation from the user`);
}
// Basic confirmation prompt
// We treat all requests with a boolean response as confirmation prompts
// The IoHost never aborts on a "no": it returns the answer and lets the
// calling action decide what to do (so abort handling is consistent
// across actions).
if (isConfirmationPrompt(msg)) {
return promptly.confirm(`${chalk_1.default.cyan(msg.message)} (y/n)`);
}
// Asking for a specific value
const prompt = extractPromptInfo(msg);
const desc = responseDescription ?? prompt.default;
const answer = await promptly.prompt(`${chalk_1.default.cyan(msg.message)}${desc ? ` (${desc})` : ''}`, {
default: prompt.default,
trim: true,
});
return prompt.convertAnswer(answer);
});
// We need to cast this because it is impossible to narrow the generic type
// isPromptableRequest ensures that the response type is one we can prompt for
// the remaining code ensure we are indeed returning the correct type
return response;
}
/**
* Formats a message for console output with optional color support
*/
formatMessage(msg) {
// apply provided style or a default style if we're in TTY mode
let message_text = this.isTTY
? styleMap[msg.level](msg.message)
: msg.message;
// prepend timestamp if IoMessageLevel is DEBUG or TRACE. Postpend a newline.
return ((msg.level === 'debug' || msg.level === 'trace')
? `[${this.formatTime(msg.time)}] ${message_text}`
: message_text) + '\n';
}
/**
* Formats date to HH:MM:SS
*/
formatTime(d) {
const pad = (n) => n.toString().padStart(2, '0');
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
/**
* Get an instance of the ActivityPrinter
*/
makeActivityPrinter() {
const props = {
stream: this.selectStreamFromLevel('info'),
};
switch (this.stackProgress) {
case deploy_1.StackActivityProgress.EVENTS:
return new api_private_1.HistoryActivityPrinter(props);
case deploy_1.StackActivityProgress.BAR:
return new api_private_1.CurrentActivityPrinter(props);
}
}
}
exports.CliIoHost = CliIoHost;
/**
* Convert a `MessageSelector` into a predicate that decides whether a listener
* applies to a message. A maker matches messages carrying its `code`; a
* predicate (e.g. a maker's `.is`, or any `(msg) => boolean`) is used as-is.
*/
function messageMatcher(selector) {
if (typeof selector === 'function') {
return selector;
}
const { code } = selector;
return (msg) => msg.code === code;
}
/**
* Combine several selectors into a single predicate that matches a message when
* *any* of them matches. Each selector may be a maker (matched by its `code`)
* or a predicate.
*
* Useful for one listener that spans multiple codes, e.g.
* `ioHost.on(matchAny(IO.CDK_TOOLKIT_I5501, IO.CDK_TOOLKIT_I5502), listener)`.
*/
function matchAny(...selectors) {
const matchers = selectors.map(messageMatcher);
return (msg) => matchers.some((matches) => matches(msg));
}
/**
* This IoHost implementation considers a request promptable, if:
* - it's a yes/no confirmation
* - asking for a string or number value
*/
function isPromptableRequest(msg) {
return isConfirmationPrompt(msg)
|| typeof msg.defaultResponse === 'string'
|| typeof msg.defaultResponse === 'number';
}
/**
* Check if the request is a confirmation prompt
* We treat all requests with a boolean response as confirmation prompts
*/
function isConfirmationPrompt(msg) {
return typeof msg.defaultResponse === 'boolean';
}
/**
* Helper to extract information for promptly from the request
*/
function extractPromptInfo(msg) {
const isNumber = (typeof msg.defaultResponse === 'number');
const defaultResponse = util.format(msg.defaultResponse);
return {
default: defaultResponse,
defaultDesc: 'defaultDescription' in msg && msg.defaultDescription ? util.format(msg.defaultDescription) : defaultResponse,
convertAnswer: isNumber ? (v) => Number(v) : (v) => String(v),
};
}
const styleMap = {
error: chalk_1.default.red,
warn: chalk_1.default.yellow,
result: chalk_1.default.reset,
info: chalk_1.default.reset,
debug: chalk_1.default.gray,
trace: chalk_1.default.gray,
};
function targetStreamObject(x) {
switch (x) {
case 'stderr':
return process.stderr;
case 'stdout':
return process.stdout;
case 'drop':
return undefined;
}
}
function isNoticesMessage(msg) {
return api_private_1.IO.CDK_TOOLKIT_I0100.is(msg) || api_private_1.IO.CDK_TOOLKIT_W0101.is(msg) || api_private_1.IO.CDK_TOOLKIT_E0101.is(msg) || api_private_1.IO.CDK_TOOLKIT_I0101.is(msg);
}
function eventFromMessage(msg) {
if (messages_1.CLI_PRIVATE_IO.CDK_CLI_I1001.is(msg)) {
return eventResult('SYNTH', msg);
}
if (messages_1.CLI_PRIVATE_IO.CDK_CLI_I2001.is(msg)) {
return eventResult('INVOKE', msg);
}
if (messages_1.CLI_PRIVATE_IO.CDK_CLI_I3001.is(msg)) {
return eventResult('DEPLOY', msg);
}
if (messages_1.CLI_PRIVATE_IO.CDK_CLI_I3003.is(msg)) {
return eventResult('ASSET', msg);
}
// Hotswap lives in the cdk-toolkit so it cannot be a CDK_CLI error code.
// Instead we reuse the existing Hotswap span.
if (api_private_1.IO.CDK_TOOLKIT_I5410.is(msg)) {
// Create a telemetry-compatible result
return hotswapToEventResult(msg.data);
}
return undefined;
function eventResult(eventType, m) {
return {
eventType,
duration: m.data.duration,
error: m.data.error,
counters: m.data.counters,
};
}
}
function hotswapToEventResult(result) {
const nonHotswappableResources = {};
for (const { subject } of result.nonHotswappableChanges) {
if ('resourceType' in subject) {
const keys = 'rejectedProperties' in subject && subject.rejectedProperties
? subject.rejectedProperties.map(p => `hotswapFallback:${subject.resourceType}#${p}`)
: [`hotswapFallback:${subject.resourceType}`];
for (const key of keys) {
nonHotswappableResources[key] = (nonHotswappableResources[key] ?? 0) + 1;
}
}
}
return {
eventType: 'HOTSWAP',
duration: result.duration,
...(result.error ? {
error: {
name: (0, error_1.cdkCliErrorName)(result.error),
},
} : {}),
counters: {
hotswapped: result.hotswapped ? 1 : 0,
hotswapFallback: result.hotswapFallback ? 1 : 0,
hotswappableChanges: result.hotswappableChanges.length,
nonHotswappableChanges: result.nonHotswappableChanges.length,
...nonHotswappableResources,
},
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWlvLWhvc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjbGktaW8taG9zdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFtaUNBLDRCQUdDO0FBcmlDRCxnREFBa0M7QUFDbEMsMEVBQWlFO0FBQ2pFLHNEQUFvRDtBQUVwRCxrREFBMEI7QUFDMUIsbURBQXFDO0FBRXJDLDBEQUFxSTtBQUVySSxrREFBOEQ7QUFDOUQsc0VBQXFFO0FBQ3JFLDhDQUFxRDtBQUVyRCxvREFBdUQ7QUFFdkQsa0RBQXdEO0FBQ3hELG1FQUF3RTtBQUN4RSwyREFBZ0U7QUFDaEUscURBQWtEO0FBRWxELG1DQUFrQztBQStPbEM7O0dBRUc7QUFDSCxNQUFhLFNBQVM7SUFDcEI7O09BRUc7SUFDSCxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQXdCLEVBQUUsRUFBRSxRQUFRLEdBQUcsS0FBSztRQUMxRCxJQUFJLFFBQVEsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNyQyxTQUFTLENBQUMsU0FBUyxHQUFHLElBQUksU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFDRCxPQUFPLFNBQVMsQ0FBQyxTQUFTLENBQUM7SUFDN0IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLEdBQUc7UUFDUixPQUFPLFNBQVMsQ0FBQyxTQUFTLENBQUM7SUFDN0IsQ0FBQztJQUVEOztPQUVHO0lBQ0ssTUFBTSxDQUFDLFNBQVMsQ0FBd0I7SUFFaEQ7O09BRUc7SUFDSSxhQUFhLENBQVk7SUFFaEM7Ozs7T0FJRztJQUNJLElBQUksQ0FBVTtJQUVyQjs7T0FFRztJQUNJLEtBQUssQ0FBVTtJQUV0Qjs7OztPQUlHO0lBQ0ksUUFBUSxDQUFpQjtJQUVoQzs7T0FFRztJQUNJLHFCQUFxQixDQUFrQjtJQUU5Qzs7Ozs7T0FLRztJQUNJLGtCQUFrQixHQUFpQixRQUFRLENB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