@go-to-k/cdkd 0.284.61 → 0.284.62

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.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Ar as isCdkdError, Dr as StateError, Jt as TemplateParser, Mn as Synthesizer, Or as SynthesisError, Sr as ProvisioningError, Ut as DiffCalculator, W as IAMRoleProvider, Yt as LockManager, Zt as S3StateBackend, ar as getAwsClients, cr as AssetError, er as AssemblyReader, fr as DependencyError, ir as AwsClients, jr as normalizeAwsError, kr as formatError, lr as CdkdError, nr as clearBucketRegionCache, or as resetAwsClients, q as ProviderRegistry, qt as DagBuilder, r as DeployEngine, rn as AssetPublisher, rr as resolveBucketRegion, rt as CloudControlProvider, sr as setAwsClients, ur as ConfigError, vr as LockError } from "./deploy-engine-0d-g0TT4.js";
1
+ import { Ar as isCdkdError, Dr as StateError, Jt as TemplateParser, Mn as Synthesizer, Or as SynthesisError, Sr as ProvisioningError, Ut as DiffCalculator, W as IAMRoleProvider, Yt as LockManager, Zt as S3StateBackend, ar as getAwsClients, cr as AssetError, er as AssemblyReader, fr as DependencyError, ir as AwsClients, jr as normalizeAwsError, kr as formatError, lr as CdkdError, nr as clearBucketRegionCache, or as resetAwsClients, q as ProviderRegistry, qt as DagBuilder, r as DeployEngine, rn as AssetPublisher, rr as resolveBucketRegion, rt as CloudControlProvider, sr as setAwsClients, ur as ConfigError, vr as LockError } from "./deploy-engine-D8AIgkwy.js";
2
2
  import { n as getLogger, r as setLogger, t as ConsoleLogger } from "./logger-zRrlbaQt.js";
3
3
 
4
4
  export { AssemblyReader, AssetError, AssetPublisher, AwsClients, CdkdError, CloudControlProvider, ConfigError, ConsoleLogger, DagBuilder, DependencyError, DeployEngine, DiffCalculator, IAMRoleProvider, LockError, LockManager, ProviderRegistry, ProvisioningError, S3StateBackend, StateError, SynthesisError, Synthesizer, TemplateParser, clearBucketRegionCache, formatError, getAwsClients, getLogger, isCdkdError, normalizeAwsError, resetAwsClients, resolveBucketRegion, setAwsClients, setLogger };
@@ -1,7 +1,7 @@
1
- import { $ as endCommandInterruptScope, $n as derivePartitionAndUrlSuffix, $t as exportNamesCarriedFrom, A as renderStatefulReason, An as AssetManifestLoader, At as isSingleDynamicReferenceToken, B as exportAliasCollisionScrubWarning, Bn as resolveStateBucketWithDefault, Bt as s3BucketRegionalDomainName, C as isFinalSnapshotError, Cn as buildDockerImage, Cr as ResourceTimeoutError, Ct as requireConfigString, D as extractDeploymentEventError, Dn as partitionSensitiveEnv, Dt as createSecretMasker, E as makeCanonicalizePropertiesFn, En as getDockerCmd, Er as StackTerminationProtectionError, Et as TEMPLATE_SOURCED_RULES, F as green, Fn as getLegacyStateBucketName, Fr as isThrottlingError, Ft as classifyReplaySecretRegion, G as collectInlinePolicyNamesManagedBySiblings, Gn as CFN_TEMPLATE_BODY_LIMIT, Gt as describeTypeWithThrottleRetry, H as secretBearingStateKeyWarning, Hn as resolveUseCdkBootstrapAssets, Ht as applyRoleArnIfSet, I as red, In as resolveApp, Ir as markNonRetryable, It as producerRegionsFromState, J as findActionableSilentDrops, Jn as findLargeInlineResources, Jt as TemplateParser, K as clearOnUpdateRemoval, Kn as CFN_TEMPLATE_URL_LIMIT, Kt as withRetry, L as yellow, Ln as resolveAutoAssetStorage, Lt as s3BucketArn, M as bold, Mn as Synthesizer, Mr as withErrorHandling, Mt as maskSecretsInText, N as cyan, Nn as synthesisStatusMessage, Nr as isMarkedNonRetryable, Nt as redactSecretsForState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as runDockerForeground, Ot as dynamicReferenceTokens, P as gray, Pn as getDefaultStateBucketName, Pr as isRetryableTransientError, Pt as scrubResourceRecord, Q as beginCommandInterruptScope, Qn as canonicalizeRegion, Qt as rebuildClientForBucketRegion, R as collectDeclaredOutputNames, Rn as resolveCaptureObservedState, Rt as s3BucketDomainName, S as createPreDeleteFinalSnapshot, Sn as buildDenyExternalAccessPolicy, Sr as ProvisioningError, St as requireConfigObject, T as unsupportedFinalSnapshotError, Tn as formatDockerLoginError, Tr as StackHasActiveImportsError, Tt as STATE_SOURCED_READBACK_RULES, U as stateKeySecretExposure, Un as stateBucketExistenceConfirmed, Ut as DiffCalculator, V as isExportAliasCollision, Vn as resolveStateBucketWithDefaultAndSource, Vt as s3BucketWebsiteUrl, W as IAMRoleProvider, Wn as warnDeprecatedNoPrefixCliFlag, Wt as INTRINSIC_KEYS, X as CUSTOM_RESOURCE_RESPONSE_PREFIX, Xn as expectedOwnerParam, Xt as displaySafe, Y as findSilentDropProperties, Yn as uploadCfnTemplate, Yt as LockManager, Z as DEFAULT_STATE_PREFIX, Zn as PARTITION_TABLE, Zt as S3StateBackend, _ as computeImplicitDeleteEdges, _n as isCrossRegionRedirect, _r as LocalStartServiceError, _t as configBooleanRefusal, a as DeploymentEventsStore, an as WorkGraph, ar as getAwsClients, at as disableInstanceApiTermination, b as buildFinalSnapshotIdentifier, bn as validateAssetBucketName, br as NestedStackChildDirectDestroyError, bt as replayWarn, c as replayFailedOperations, cn as loadPublishableAssetManifest, ct as carriesDynamicReference, d as updatePartialReason, dn as stripControlChars, dr as CrossAccountSecretRefusalError, dt as refStateLookupFromResource, en as importableOutputKeys, er as AssemblyReader, et as interruptWatchListenerCount, f as UNSPECIFIED_SKIP_REASON, fn as AssetModeResolver, ft as WAFv2WebACLProvider, g as IMPLICIT_DELETE_DEPENDENCIES, gn as getBootstrapMarkerKey, gr as LocalMigrateError, gt as coerceCfnBoolean, h as maskingRetryLogger, hn as ensureAssetStorage, hr as LocalInvokeBuildError$1, ht as assertRegionMatch, i as DeploymentEventsReader, in as stringifyValue, ir as AwsClients, it as slowCcOperationTimeoutMs, j as formatResourceLine, jn as getDockerImageBySourceHash, jr as normalizeAwsError, jt as maskSecretsInError, k as isStatefulRecreateTargetSync, kn as runDockerStreaming, kt as errorCauseChain, l as replayRollback, ln as rewriteTemplateAssetReferences, lr as CdkdError, lt as cfnRefValueFromPhysicalId, m as withResourceDeadline, mn as assertAssetBucketRegion, mr as DynamicReferenceRegionAmbiguousError, mt as resolveExplicitPhysicalId, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as shouldRetainResource, nt as startInterruptWatch, o as planFailedOps, on as buildAssetRedirectMap, or as resetAwsClients, ot as isTerminationProtectionPropagationError, p as deleteSkipReason, pn as BOOTSTRAP_MARKER_PREFIX, pr as DeployCancelledError, pt as normalizeAwsTagsToCfn, q as ProviderRegistry, qn as MIGRATE_TMP_PREFIX, qt as DagBuilder, r as DeployEngine, rn as AssetPublisher, rr as resolveBucketRegion, rt as CloudControlProvider, s as planRollback, sn as createAssetRedirectResolver, sr as setAwsClients, st as IntrinsicFunctionResolver, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as importableOutputs, tr as processStackMessages, tt as isInterruptedWaitError, u as updatePartialMessage, un as escapeRegExp, ut as getAccountInfo, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as parseBootstrapMarker, vt as configStringRefusal, w as refusesFinalSnapshot, wn as dockerSpawnEnvWithSensitive, wr as ResourceUpdateNotSupportedError, wt as STATE_SOURCED_CROSS_GENERATION_RULES, x as ccRoutedFinalSnapshotError, xn as validateContainerRepoName, xr as PartialFailureError, xt as requireConfigArray, y as PRE_DELETE_SNAPSHOT_TYPES, yn as readBootstrapMarkerBody, yr as MissingCdkCliError, yt as readConfigString, z as collectPublishedOutputNames, zn as resolveSkipPrefix, zt as s3BucketDualStackDomainName } from "./deploy-engine-0d-g0TT4.js";
1
+ import { $ as endCommandInterruptScope, $n as derivePartitionAndUrlSuffix, $t as exportNamesCarriedFrom, A as renderStatefulReason, An as AssetManifestLoader, At as isSingleDynamicReferenceToken, B as exportAliasCollisionScrubWarning, Bn as resolveStateBucketWithDefault, Bt as s3BucketRegionalDomainName, C as isFinalSnapshotError, Cn as buildDockerImage, Cr as ResourceTimeoutError, Ct as requireConfigString, D as extractDeploymentEventError, Dn as partitionSensitiveEnv, Dt as createSecretMasker, E as makeCanonicalizePropertiesFn, En as getDockerCmd, Er as StackTerminationProtectionError, Et as TEMPLATE_SOURCED_RULES, F as green, Fn as getLegacyStateBucketName, Fr as isThrottlingError, Ft as classifyReplaySecretRegion, G as collectInlinePolicyNamesManagedBySiblings, Gn as CFN_TEMPLATE_BODY_LIMIT, Gt as describeTypeWithThrottleRetry, H as secretBearingStateKeyWarning, Hn as resolveUseCdkBootstrapAssets, Ht as applyRoleArnIfSet, I as red, In as resolveApp, Ir as markNonRetryable, It as producerRegionsFromState, J as findActionableSilentDrops, Jn as findLargeInlineResources, Jt as TemplateParser, K as clearOnUpdateRemoval, Kn as CFN_TEMPLATE_URL_LIMIT, Kt as withRetry, L as yellow, Ln as resolveAutoAssetStorage, Lt as s3BucketArn, M as bold, Mn as Synthesizer, Mr as withErrorHandling, Mt as maskSecretsInText, N as cyan, Nn as synthesisStatusMessage, Nr as isMarkedNonRetryable, Nt as redactSecretsForState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as runDockerForeground, Ot as dynamicReferenceTokens, P as gray, Pn as getDefaultStateBucketName, Pr as isRetryableTransientError, Pt as scrubResourceRecord, Q as beginCommandInterruptScope, Qn as canonicalizeRegion, Qt as rebuildClientForBucketRegion, R as collectDeclaredOutputNames, Rn as resolveCaptureObservedState, Rt as s3BucketDomainName, S as createPreDeleteFinalSnapshot, Sn as buildDenyExternalAccessPolicy, Sr as ProvisioningError, St as requireConfigObject, T as unsupportedFinalSnapshotError, Tn as formatDockerLoginError, Tr as StackHasActiveImportsError, Tt as STATE_SOURCED_READBACK_RULES, U as stateKeySecretExposure, Un as stateBucketExistenceConfirmed, Ut as DiffCalculator, V as isExportAliasCollision, Vn as resolveStateBucketWithDefaultAndSource, Vt as s3BucketWebsiteUrl, W as IAMRoleProvider, Wn as warnDeprecatedNoPrefixCliFlag, Wt as INTRINSIC_KEYS, X as CUSTOM_RESOURCE_RESPONSE_PREFIX, Xn as expectedOwnerParam, Xt as displaySafe, Y as findSilentDropProperties, Yn as uploadCfnTemplate, Yt as LockManager, Z as DEFAULT_STATE_PREFIX, Zn as PARTITION_TABLE, Zt as S3StateBackend, _ as computeImplicitDeleteEdges, _n as isCrossRegionRedirect, _r as LocalStartServiceError, _t as configBooleanRefusal, a as DeploymentEventsStore, an as WorkGraph, ar as getAwsClients, at as disableInstanceApiTermination, b as buildFinalSnapshotIdentifier, bn as validateAssetBucketName, br as NestedStackChildDirectDestroyError, bt as replayWarn, c as replayFailedOperations, cn as loadPublishableAssetManifest, ct as carriesDynamicReference, d as updatePartialReason, dn as stripControlChars, dr as CrossAccountSecretRefusalError, dt as refStateLookupFromResource, en as importableOutputKeys, er as AssemblyReader, et as interruptWatchListenerCount, f as UNSPECIFIED_SKIP_REASON, fn as AssetModeResolver, ft as WAFv2WebACLProvider, g as IMPLICIT_DELETE_DEPENDENCIES, gn as getBootstrapMarkerKey, gr as LocalMigrateError, gt as coerceCfnBoolean, h as maskingRetryLogger, hn as ensureAssetStorage, hr as LocalInvokeBuildError$1, ht as assertRegionMatch, i as DeploymentEventsReader, in as stringifyValue, ir as AwsClients, it as slowCcOperationTimeoutMs, j as formatResourceLine, jn as getDockerImageBySourceHash, jr as normalizeAwsError, jt as maskSecretsInError, k as isStatefulRecreateTargetSync, kn as runDockerStreaming, kt as errorCauseChain, l as replayRollback, ln as rewriteTemplateAssetReferences, lr as CdkdError, lt as cfnRefValueFromPhysicalId, m as withResourceDeadline, mn as assertAssetBucketRegion, mr as DynamicReferenceRegionAmbiguousError, mt as resolveExplicitPhysicalId, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as shouldRetainResource, nt as startInterruptWatch, o as planFailedOps, on as buildAssetRedirectMap, or as resetAwsClients, ot as isTerminationProtectionPropagationError, p as deleteSkipReason, pn as BOOTSTRAP_MARKER_PREFIX, pr as DeployCancelledError, pt as normalizeAwsTagsToCfn, q as ProviderRegistry, qn as MIGRATE_TMP_PREFIX, qt as DagBuilder, r as DeployEngine, rn as AssetPublisher, rr as resolveBucketRegion, rt as CloudControlProvider, s as planRollback, sn as createAssetRedirectResolver, sr as setAwsClients, st as IntrinsicFunctionResolver, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as importableOutputs, tr as processStackMessages, tt as isInterruptedWaitError, u as updatePartialMessage, un as escapeRegExp, ut as getAccountInfo, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as parseBootstrapMarker, vt as configStringRefusal, w as refusesFinalSnapshot, wn as dockerSpawnEnvWithSensitive, wr as ResourceUpdateNotSupportedError, wt as STATE_SOURCED_CROSS_GENERATION_RULES, x as ccRoutedFinalSnapshotError, xn as validateContainerRepoName, xr as PartialFailureError, xt as requireConfigArray, y as PRE_DELETE_SNAPSHOT_TYPES, yn as readBootstrapMarkerBody, yr as MissingCdkCliError, yt as readConfigString, z as collectPublishedOutputNames, zn as resolveSkipPrefix, zt as s3BucketDualStackDomainName } from "./deploy-engine-D8AIgkwy.js";
2
2
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
3
- import { t as getCdkdVersion } from "./version-iXYxz3AH.js";
4
- import { t as ASGProvider } from "./asg-provider-DTolzTHQ.js";
3
+ import { t as getCdkdVersion } from "./version-DoW7XkO0.js";
4
+ import { t as ASGProvider } from "./asg-provider-BfX7AwFi.js";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import { createHash, randomBytes, randomUUID } from "node:crypto";
7
7
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -2032,7 +2032,9 @@ function createListCommand() {
2032
2032
  * cancellation, and GitLab CI / `docker stop` / Kubernetes send SIGTERM
2033
2033
  * directly. cdkd's graceful-interrupt handling (the top-level command
2034
2034
  * handlers, the deploy engine's partial-state save, and the per-provider
2035
- * poll-abort listeners in CustomResource / ACM / CloudFront / Route53) is
2035
+ * poll-abort listeners in CustomResource / CloudFront / ACM `grep -rn
2036
+ * "process.on('SIGINT'" src/provisioning/providers/` regenerates that closed
2037
+ * set, and Route53 is NOT in it) is
2036
2038
  * registered on SIGINT only, so an unhandled SIGTERM killed the process
2037
2039
  * mid-run, skipped every `finally`, and stranded the stack lock for its
2038
2040
  * full TTL.
@@ -2082,7 +2084,7 @@ function installSigtermForwarder() {
2082
2084
  * `cdkd deploy` has had one of these since issue #1348 (`deploy.ts`'s
2083
2085
  * `topLevelSigintHandler`). The destroy side had none, so the ONLY channel
2084
2086
  * carrying "the user interrupted" from `runDestroyForStack` back to the
2085
- * `--all` loop was `DestroyRunResult.interrupted` — a boolean assigned ONCE,
2087
+ * `--all` loop was `DestroyRunnerResult.interrupted` — a boolean assigned ONCE,
2086
2088
  * inside the runner's `try`, after its level loop. Every instant where the
2087
2089
  * runner's `draining` flag flips AFTER that assignment is an instant where
2088
2090
  * `cdkd destroy --all` went on to delete the NEXT stack after the user asked
@@ -2106,10 +2108,38 @@ function installSigtermForwarder() {
2106
2108
  *
2107
2109
  * A handler that lives for the whole command closes both, because it is armed
2108
2110
  * in every window rather than in the ones the runner happens to span. The two
2109
- * flags answer different questions and both are kept: `result.interrupted` is
2110
- * the PER-STACK outcome (it decides that stack's state preservation, its
2111
- * summary line and its `--purge-events` skip), while this one is the
2112
- * COMMAND-level "stop" the loop wants.
2111
+ * flags answer different questions and both are kept, one owner each:
2112
+ *
2113
+ * - PER-STACK, "did THIS stack finish, or is there work left in it?" —
2114
+ * `DestroyRunnerResult.interrupted`, owned by `destroy-runner.ts`. It has FOUR
2115
+ * consumers: that stack's state preservation, its summary line,
2116
+ * `destroy.ts`'s `--purge-events` skip, and — the one earlier revisions of
2117
+ * this list omitted — `NestedStackProvider.delete`, which reads the CHILD's
2118
+ * result to decide whether the child row is `{ outcome: 'skipped' }` on the
2119
+ * parent and whether its failure is `markNonRetryable`.
2120
+ *
2121
+ * That fourth consumer is why the `&& statePreserved` gate below is a
2122
+ * behavior change beyond the exit code: a fully-destroyed child that takes
2123
+ * a tail signal no longer reports `interrupted`, so the parent no longer
2124
+ * marks its row skipped. That is the CORRECT reading — `skipped` means
2125
+ * "cdkd could not address this, the resources may still exist in AWS",
2126
+ * which is false of a child whose every resource was deleted and whose
2127
+ * state record is gone; it would preserve the parent's row for a child that
2128
+ * no longer exists and exit 2 over a completed teardown. Stopping the
2129
+ * surrounding `--all` run is a DIFFERENT question, still answered by this
2130
+ * watch, which the parent command holds for its whole run.
2131
+ * - PER-RUN, "has the user asked this COMMAND to stop?" — this watch. Its
2132
+ * consumers are the loops' `break`s and the terminal exit-code verdict
2133
+ * (which pairs it with `stoppedEarly`, so a signal in a completed run's
2134
+ * tail does not report unfinished work there is none of).
2135
+ *
2136
+ * `--purge-events` moved onto the per-stack answer when the runner's outer
2137
+ * re-sync was gated on `statePreserved`. Before that the per-stack flag could
2138
+ * be true over a stack whose state was already DELETED, so the purge had to
2139
+ * read the command-level one to stay conservative — at the cost of the
2140
+ * opposite error: a tail signal on the LAST stack skipped the purge while the
2141
+ * command exited 0, reporting full success with the events left behind. With
2142
+ * the per-stack flag accurate, one read serves both directions.
2113
2143
  *
2114
2144
  * Note on the counterpart contract: `deploy-engine.ts` removes its own SIGINT
2115
2145
  * handler before releasing its lock, which is safe only because `deploy.ts`'s
@@ -2123,6 +2153,11 @@ function installSigtermForwarder() {
2123
2153
  */
2124
2154
  function watchCommandInterrupt(opts) {
2125
2155
  let interrupted = false;
2156
+ const promptAbort = new AbortController();
2157
+ function markInterrupted() {
2158
+ interrupted = true;
2159
+ promptAbort.abort();
2160
+ }
2126
2161
  let stacksInFlight = 0;
2127
2162
  /**
2128
2163
  * Is some OTHER listener going to handle this signal gracefully?
@@ -2145,27 +2180,30 @@ function watchCommandInterrupt(opts) {
2145
2180
  * - `interrupt-watch.ts`'s shared handler, which is a LATCH rather than a
2146
2181
  * graceful owner — deferring to it is exactly the swallow above.
2147
2182
  *
2148
- * A provider's transient wait listener (CustomResource / ACM / CloudFront /
2149
- * Route53) does count, and that is correct rather than a false positive:
2150
- * those exist only DURING a provider wait, which is strictly inside the
2151
- * runner handler's own lifetime, so one cannot be present while the runner's
2152
- * is absent.
2183
+ * A provider's transient wait listener does count, and that is correct
2184
+ * rather than a false positive: three providers install one grep
2185
+ * `process.on('SIGINT'` under `src/provisioning/providers/**` for the
2186
+ * closed set, today `acm-certificate-provider.ts`,
2187
+ * `cloudfront-distribution-provider.ts` and `custom-resource-provider.ts`,
2188
+ * NOT Route53, whose provider registers none — and each exists only
2189
+ * DURING a provider wait, which is strictly inside the runner handler's own
2190
+ * lifetime, so one cannot be present while the runner's is absent.
2153
2191
  */
2154
2192
  function gracefulOwnerArmed() {
2155
2193
  return process.listeners("SIGINT").filter((l) => l !== handler).length - interruptWatchListenerCount() > 0;
2156
2194
  }
2157
2195
  const handler = () => {
2158
2196
  if (stacksInFlight > 0 && gracefulOwnerArmed()) {
2159
- interrupted = true;
2197
+ markInterrupted();
2160
2198
  return;
2161
2199
  }
2162
2200
  if (interrupted) {
2163
- process.stderr.write("\nForce-quit.\n");
2201
+ process.stderr.write("\nForce-quit.\nIf the next run reports a stack lock, release it with: cdkd force-unlock <stack-name>\n");
2164
2202
  process.exit(130);
2165
2203
  }
2166
- interrupted = true;
2204
+ markInterrupted();
2167
2205
  if (stacksInFlight > 0) {
2168
- process.stderr.write(`\nInterrupted before ${opts.command} armed its per-stack teardown — quitting now. Nothing was deleted and no stack lock is held.\n`);
2206
+ process.stderr.write(`\nInterrupted before ${opts.command} armed its per-stack teardown — quitting now. No delete was issued for this stack; on an --all run, stacks processed earlier are already destroyed.\nIf the next run reports a stack lock, release it with: cdkd force-unlock <stack-name>\n`);
2169
2207
  process.exit(130);
2170
2208
  }
2171
2209
  process.stderr.write(`\nInterrupted — ${opts.command} will stop before starting another stack (press Ctrl-C again to force-quit)...\n`);
@@ -2173,6 +2211,7 @@ function watchCommandInterrupt(opts) {
2173
2211
  process.on("SIGINT", handler);
2174
2212
  return {
2175
2213
  interrupted: () => interrupted,
2214
+ signal: promptAbort.signal,
2176
2215
  async runStack(fn) {
2177
2216
  stacksInFlight += 1;
2178
2217
  try {
@@ -2186,6 +2225,22 @@ function watchCommandInterrupt(opts) {
2186
2225
  }
2187
2226
  };
2188
2227
  }
2228
+ /**
2229
+ * Did this rejection come from a prompt aborted through
2230
+ * {@link CommandInterruptWatch.signal}?
2231
+ *
2232
+ * Deliberately duck-typed rather than `instanceof`: what `readline/promises`
2233
+ * rejects with is an internal Node error class in some versions and a
2234
+ * `DOMException` in others, and neither is importable. Both spellings carry
2235
+ * `name === 'AbortError'` / `code === 'ABORT_ERR'`, and the caller pairs this
2236
+ * with its own `watch.interrupted()` check, so a same-named error from an
2237
+ * unrelated abort cannot be mistaken for the user's Ctrl-C.
2238
+ */
2239
+ function isPromptAbortError(error) {
2240
+ if (typeof error !== "object" || error === null) return false;
2241
+ const { name, code } = error;
2242
+ return name === "AbortError" || code === "ABORT_ERR";
2243
+ }
2189
2244
 
2190
2245
  //#endregion
2191
2246
  //#region src/deployment/recreate-targets.ts
@@ -59254,7 +59309,6 @@ async function runDestroyForStack(stackName, state, ctx) {
59254
59309
  }
59255
59310
  }
59256
59311
  result.skippedEmpty = true;
59257
- result.interrupted ||= emptyInterrupted;
59258
59312
  return result;
59259
59313
  }
59260
59314
  const needsStrongRefCheck = !!(state.outputs && Object.keys(state.outputs).length > 0);
@@ -59327,6 +59381,7 @@ async function runDestroyForStack(stackName, state, ctx) {
59327
59381
  const renderer = getLiveRenderer();
59328
59382
  let draining = false;
59329
59383
  let lockHeld = false;
59384
+ let statePreserved = false;
59330
59385
  const sigintHandler = () => {
59331
59386
  if (draining) {
59332
59387
  if (lockHeld) {
@@ -59643,6 +59698,7 @@ async function runDestroyForStack(stackName, state, ctx) {
59643
59698
  result.interrupted = draining;
59644
59699
  await saveChain;
59645
59700
  const preserveState = result.errorCount > 0 || result.interrupted || result.skippedCount > 0;
59701
+ statePreserved = preserveState;
59646
59702
  if (!preserveState) {
59647
59703
  await ctx.stateBackend.deleteState(stackName, regionForState);
59648
59704
  logger.debug("State deleted");
@@ -59690,7 +59746,7 @@ async function runDestroyForStack(stackName, state, ctx) {
59690
59746
  process.removeListener("SIGINT", sigintHandler);
59691
59747
  restoreBaseRegionAndClients();
59692
59748
  }
59693
- result.interrupted ||= draining;
59749
+ result.interrupted ||= draining && statePreserved;
59694
59750
  }
59695
59751
  return result;
59696
59752
  }
@@ -68750,6 +68806,7 @@ async function destroyCommand(stackArgs, options) {
68750
68806
  let totalSkipped = 0;
68751
68807
  let interrupted = false;
68752
68808
  const runInterrupted = () => interrupted || interruptWatch.interrupted();
68809
+ let stoppedEarly = false;
68753
68810
  let stackNames;
68754
68811
  if (options.all) stackNames = candidateStacks.map((s) => s.stackName);
68755
68812
  else if (stackPatterns.length > 0) stackNames = matchStacks(candidateStacks, stackPatterns).map((s) => s.stackName);
@@ -68790,7 +68847,7 @@ async function destroyCommand(stackArgs, options) {
68790
68847
  arr.push(ref);
68791
68848
  stateRefsByName.set(ref.stackName, arr);
68792
68849
  }
68793
- for (const stackName of stackNames) {
68850
+ for (const [stackIndex, stackName] of stackNames.entries()) {
68794
68851
  logger.info(`\nPreparing to destroy stack: ${stackName}`);
68795
68852
  const refs = stateRefsByName.get(stackName) ?? [];
68796
68853
  const synthStack = appStacks.find((s) => s.stackName === stackName);
@@ -68826,7 +68883,10 @@ async function destroyCommand(stackArgs, options) {
68826
68883
  totalErrors++;
68827
68884
  continue;
68828
68885
  }
68829
- if (runInterrupted()) break;
68886
+ if (runInterrupted()) {
68887
+ stoppedEarly = true;
68888
+ break;
68889
+ }
68830
68890
  const eventRecorder = startRunRecorder({
68831
68891
  backend: stateBackend,
68832
68892
  stackName,
@@ -68834,6 +68894,8 @@ async function destroyCommand(stackArgs, options) {
68834
68894
  command: "destroy"
68835
68895
  });
68836
68896
  let destroyRunResult = "SUCCEEDED";
68897
+ let stackInterrupted = false;
68898
+ let stackCancelled = false;
68837
68899
  try {
68838
68900
  const result = await interruptWatch.runStack(() => withNestedStackContext({
68839
68901
  stateBackend,
@@ -68877,6 +68939,8 @@ async function destroyCommand(stackArgs, options) {
68877
68939
  })));
68878
68940
  totalErrors += result.errorCount;
68879
68941
  totalSkipped += result.skippedCount;
68942
+ stackInterrupted = result.interrupted;
68943
+ stackCancelled = result.cancelled === true;
68880
68944
  if (result.interrupted) interrupted = true;
68881
68945
  destroyRunResult = result.errorCount > 0 || result.skippedCount > 0 ? "FAILED" : "SUCCEEDED";
68882
68946
  eventRecorder.record({
@@ -68901,12 +68965,15 @@ async function destroyCommand(stackArgs, options) {
68901
68965
  await purgeEventsAfterDestroy(new DeploymentEventsReader(stateBackend), stackName, stackTargetRegion, {
68902
68966
  purgeEvents: options.purgeEvents,
68903
68967
  runResult: destroyRunResult,
68904
- interrupted: runInterrupted()
68968
+ interrupted: stackInterrupted || stackCancelled
68905
68969
  }, logger);
68906
- if (runInterrupted()) break;
68970
+ if (runInterrupted()) {
68971
+ if (stackIndex < stackNames.length - 1) stoppedEarly = true;
68972
+ break;
68973
+ }
68907
68974
  }
68908
68975
  if (totalErrors > 0) throw new PartialFailureError(`Destroy completed with ${totalErrors} resource error(s). State preserved — inspect 'cdkd state show <stack>' and re-run 'cdkd destroy' to retry. If the same resource keeps failing, 'cdkd state orphan <stack>' removes the state record without deleting AWS resources.`);
68909
- if (runInterrupted()) throw new PartialFailureError(`Destroy interrupted by Ctrl-C. State preserved — re-run 'cdkd destroy' to finish.`);
68976
+ if (interrupted || interruptWatch.interrupted() && stoppedEarly) throw new PartialFailureError(`Destroy interrupted by Ctrl-C. State preserved — re-run 'cdkd destroy' to finish.`);
68910
68977
  if (totalSkipped > 0) throw new PartialFailureError(`Destroy skipped ${totalSkipped} entr${totalSkipped === 1 ? "y" : "ies"} cdkd could not address, so the underlying resources may still exist in AWS. A skipped nested stack counts as ONE entry and may cover several of its own resources — the per-stack summaries above give the exact breakdown. State preserved (the records are kept). Repair the physicalId in state.json and re-run 'cdkd destroy', or delete the resources by hand and drop the records with 'cdkd state orphan <stack>'.`);
68911
68978
  } finally {
68912
68979
  unforwardSigterm();
@@ -73505,12 +73572,24 @@ async function stateDestroyCommand(stackArgs, options) {
73505
73572
  process.stdout.write(`\nWARNING: This destroys ${stackNames.length} stack(s) and removes their state records:\n`);
73506
73573
  for (const name of stackNames) process.stdout.write(` - ${name}\n`);
73507
73574
  process.stdout.write("\n");
73575
+ if (process.stdin.isTTY !== true) throw new CdkdError("The state destroy --all confirmation prompt cannot run in a non-interactive environment. Pass --yes / -y to confirm the batch, or run the command from a real terminal.", "NON_INTERACTIVE_CONFIRM");
73508
73576
  const rl = readline$1.createInterface({
73509
73577
  input: process.stdin,
73510
73578
  output: process.stdout
73511
73579
  });
73512
- const answer = await rl.question(`Destroy all ${stackNames.length} stack(s)? (y/N): `);
73513
- rl.close();
73580
+ let answer;
73581
+ try {
73582
+ answer = await rl.question(`Destroy all ${stackNames.length} stack(s)? (y/N): `, { signal: interruptWatch.signal });
73583
+ } catch (error) {
73584
+ if (interruptWatch.interrupted() && isPromptAbortError(error)) {
73585
+ process.stderr.write("\nDestroy cancelled — nothing was destroyed.\n");
73586
+ rl.close();
73587
+ process.exit(130);
73588
+ }
73589
+ throw error;
73590
+ } finally {
73591
+ rl.close();
73592
+ }
73514
73593
  const trimmed = answer.trim().toLowerCase();
73515
73594
  if (trimmed !== "y" && trimmed !== "yes") {
73516
73595
  logger.info("Destroy cancelled");
@@ -73522,7 +73601,31 @@ async function stateDestroyCommand(stackArgs, options) {
73522
73601
  let totalSkipped = 0;
73523
73602
  let interrupted = false;
73524
73603
  const runInterrupted = () => interrupted || interruptWatch.interrupted();
73525
- for (const stackName of stackNames) {
73604
+ let stoppedEarly = false;
73605
+ /**
73606
+ * Would any stack AFTER `stackIndex` actually have been destroyed?
73607
+ *
73608
+ * `stackIndex < stackNames.length - 1` answers "does an INDEX remain",
73609
+ * which is not the same question and over-claims: with
73610
+ * `--stack-region us-east-1`, a later name whose only state record lives in
73611
+ * eu-west-1 is warn-and-skipped by the `targets.length === 0` branch below
73612
+ * — it was never going to be destroyed, so a signal before it leaves
73613
+ * nothing undone and the run must still exit 0. Measured on
73614
+ * `state destroy --all --yes --stack-region us-east-1` with StackA in
73615
+ * us-east-1 and StackB only in eu-west-1: the index form exited 2 having
73616
+ * dispatched StackA, i.e. every target it had.
73617
+ *
73618
+ * The predicate mirrors that branch's own filter over `stateRefs`, the
73619
+ * same list the loop selects from. `destroy.ts` needs no counterpart: its
73620
+ * `candidateStacks` is already pre-filtered by the set of stack names that
73621
+ * have state, so an index there IS a target.
73622
+ */
73623
+ const targetRemainsAfter = (stackIndex) => stackNames.slice(stackIndex + 1).some((name) => {
73624
+ const laterRefs = stateRefs.filter((r) => r.stackName === name);
73625
+ if (!options.stackRegion) return laterRefs.length > 0;
73626
+ return laterRefs.some((r) => r.region === options.stackRegion || !r.region);
73627
+ });
73628
+ for (const [stackIndex, stackName] of stackNames.entries()) {
73526
73629
  const refs = stateRefs.filter((r) => r.stackName === stackName);
73527
73630
  let targets;
73528
73631
  if (options.stackRegion) {
@@ -73536,14 +73639,17 @@ async function stateDestroyCommand(stackArgs, options) {
73536
73639
  const regions = refs.map((r) => r.region ?? "(legacy)").join(", ");
73537
73640
  throw new Error(`Stack '${stackName}' has state in multiple regions: ${regions}. Use --stack-region <region> to pick one.`);
73538
73641
  }
73539
- for (const ref of targets) {
73642
+ for (const [refIndex, ref] of targets.entries()) {
73540
73643
  logger.info(`\nPreparing to destroy stack: ${stackName}${ref.region ? ` (${ref.region})` : ""}`);
73541
73644
  const stateResult = await setup.stateBackend.getState(stackName, ref.region ?? setup.region);
73542
73645
  if (!stateResult) {
73543
73646
  logger.warn(`No state found for stack ${stackName}${ref.region ? ` in ${ref.region}` : ""}, skipping`);
73544
73647
  continue;
73545
73648
  }
73546
- if (runInterrupted()) break;
73649
+ if (runInterrupted()) {
73650
+ stoppedEarly = true;
73651
+ break;
73652
+ }
73547
73653
  const result = await interruptWatch.runStack(() => withNestedStackContext({
73548
73654
  stateBackend: setup.stateBackend,
73549
73655
  lockManager: setup.lockManager,
@@ -73586,12 +73692,18 @@ async function stateDestroyCommand(stackArgs, options) {
73586
73692
  totalErrors += result.errorCount;
73587
73693
  totalSkipped += result.skippedCount;
73588
73694
  if (result.interrupted) interrupted = true;
73589
- if (runInterrupted()) break;
73695
+ if (runInterrupted()) {
73696
+ if (refIndex < targets.length - 1) stoppedEarly = true;
73697
+ break;
73698
+ }
73699
+ }
73700
+ if (runInterrupted()) {
73701
+ if (targetRemainsAfter(stackIndex)) stoppedEarly = true;
73702
+ break;
73590
73703
  }
73591
- if (runInterrupted()) break;
73592
73704
  }
73593
73705
  if (totalErrors > 0) throw new PartialFailureError(`Destroy completed with ${totalErrors} resource error(s). State preserved — inspect 'cdkd state show <stack>' and re-run 'cdkd state destroy' to retry. If the same resource keeps failing, 'cdkd state orphan <stack>' removes the state record without deleting AWS resources.`);
73594
- if (runInterrupted()) throw new PartialFailureError(`Destroy interrupted by Ctrl-C. State preserved — re-run 'cdkd state destroy' to finish.`);
73706
+ if (interrupted || interruptWatch.interrupted() && stoppedEarly) throw new PartialFailureError(`Destroy interrupted by Ctrl-C. State preserved — re-run 'cdkd state destroy' to finish.`);
73595
73707
  if (totalSkipped > 0) throw new PartialFailureError(`Destroy skipped ${totalSkipped} entr${totalSkipped === 1 ? "y" : "ies"} cdkd could not address, so the underlying resources may still exist in AWS. A skipped nested stack counts as ONE entry and may cover several of its own resources — the per-stack summaries above give the exact breakdown. State preserved (the records are kept). Repair the physicalId in state.json and re-run 'cdkd state destroy', or delete the resources by hand and drop the records with 'cdkd state orphan <stack>'.`);
73596
73708
  } finally {
73597
73709
  unforwardSigterm();
@@ -87873,4 +87985,4 @@ function buildProgram() {
87873
87985
 
87874
87986
  //#endregion
87875
87987
  export { buildProgram };
87876
- //# sourceMappingURL=program-CrJMVg4e.js.map
87988
+ //# sourceMappingURL=program-XLMSMzWe.js.map