@go-to-k/cdkd 0.296.28 → 0.296.30

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.
Files changed (26) hide show
  1. package/dist/{asg-provider-B3zcS87C.js → asg-provider-BaabA371.js} +3 -3
  2. package/dist/{asg-provider-B3zcS87C.js.map → asg-provider-BaabA371.js.map} +1 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/{deploy-engine-D4FdwPCi.js → deploy-engine-BuPc2Dfc.js} +1951 -60
  5. package/dist/deploy-engine-BuPc2Dfc.js.map +1 -0
  6. package/dist/{iam-policy-targets-B61e5_Sk.js → iam-policy-targets-Cz2tPxXk.js} +2 -2
  7. package/dist/{iam-policy-targets-B61e5_Sk.js.map → iam-policy-targets-Cz2tPxXk.js.map} +1 -1
  8. package/dist/{iam-role-provider-0U4kMuzh.js → iam-role-provider-CAiMUBcP.js} +3 -3
  9. package/dist/{iam-role-provider-0U4kMuzh.js.map → iam-role-provider-CAiMUBcP.js.map} +1 -1
  10. package/dist/index.d.ts +121 -55
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +3 -3
  13. package/dist/{neptune-provider-DF6Eh4Tl.js → neptune-provider-5yc_bOJ-.js} +3 -3
  14. package/dist/{neptune-provider-DF6Eh4Tl.js.map → neptune-provider-5yc_bOJ-.js.map} +1 -1
  15. package/dist/{program-v_QNBjtZ.js → program-CIxuz2zX.js} +557 -41
  16. package/dist/program-CIxuz2zX.js.map +1 -0
  17. package/dist/{provider-classes-wbKBBEol.js → provider-classes-DmZ0J68L.js} +216 -26
  18. package/dist/provider-classes-DmZ0J68L.js.map +1 -0
  19. package/dist/{rds-provider-BfQsw4hw.js → rds-provider-IBY6fDvN.js} +3 -3
  20. package/dist/{rds-provider-BfQsw4hw.js.map → rds-provider-IBY6fDvN.js.map} +1 -1
  21. package/dist/{version-B0JEGOLV.js → version-B__YmKBy.js} +2 -2
  22. package/dist/{version-B0JEGOLV.js.map → version-B__YmKBy.js.map} +1 -1
  23. package/package.json +1 -1
  24. package/dist/deploy-engine-D4FdwPCi.js.map +0 -1
  25. package/dist/program-v_QNBjtZ.js.map +0 -1
  26. package/dist/provider-classes-wbKBBEol.js.map +0 -1
@@ -1,9 +1,9 @@
1
1
  import { a as runWithStackAwsClients, i as resetAwsClients, o as setAwsClients, t as AwsClients } from "./aws-clients-CnmtbrxD.js";
2
2
  import { A as UNRENDERABLE, B as stringifyJsonPayload, D as SAFE_MSG_ALTERED_CHAR, F as displayStackName, I as isPasteableIdent, M as displayAwsMessage, N as displayIdent, O as SECRET_REF_MAX_CODE_POINTS, P as displaySafe, R as plainIdentOr, T as withStackName, V as truncateCodePoints, _ as derivesPatternBName, a as getLogger, f as getLiveRenderer, h as PATTERN_B_RESOURCE_TYPES, j as cutMarker, k as STACK_REF_MAX_CODE_POINTS, l as runStackBuffered, m as PATTERN_B_NAME_PROPERTIES, o as isStdoutReservedForPayload, p as PATTERN_B_NAME_OPTIONS, r as safeStringify, s as reserveStdoutForPayload, t as describeAwsFailure, v as explicitNamePropertyFor, w as withSkipPrefix, y as generateResourceName, z as safeMsg } from "./aws-failure-text-BaWeCWRz.js";
3
- import { $t as AccountIdUnavailableError, An as commandHole, Bn as setPasteableRunFlags, D as VALUE_NOT_SHOWN, E as assertRegionMatch, En as TIMEOUT_FLAG_RESOURCE_TYPE, Fn as plainOrDescribed, Ft as buildLockContentionMessage, G as runDeleteAttempt, Gt as producerCoordinateKey, Ht as DEFAULT_STATE_PREFIX, In as quotedOrDescribed, It as forceQuitRecoveryClause, Jt as withPasteableAwsProfile, Kt as producerRecordKey, Ln as shellBoundedDisplay, Lt as formatLockExpiry, Mn as isInertUnquoted, Nn as pasteableCommand, Nt as UNREPRODUCIBLE_LOCK_CLAUSE, On as SHELL_ACTIVE_WHY, P as remedyLogicalId, Pt as buildForceUnlockCommand, Qn as isAmbiguousOutcomeError, Qt as credentialFingerprint, Rn as shellQuote, Rt as formatLockOperation, T as RESOURCE_NOT_FOUND, Tn as withErrorHandling, Ut as injectiveKey, Vn as setPasteableVerbFlags, Vt as CUSTOM_RESOURCE_RESPONSE_PREFIX, Xt as ambientCredentialConfig, Yt as ambientClientDefaults, Z as isAwsCliLiteral, Zt as clientDefaultsFor, _n as ResourceUpdateNotSupportedError, an as DeployCancelledError, ar as isThrottlingError, cn as LocalInvokeBuildError$1, er as isRetryableTransientError, fn as MalformedProducerRecordRefusalError, ft as logicalIdShown, gn as ResourceTimeoutError, hn as ProvisioningError, ir as isMarkedNonRetryable, it as isInterruptedWaitError, ln as LocalStartServiceError, mn as PartialFailureError, mt as resourceTypeShown, n as RESOLVED_PREVIOUS_PRINCIPAL_KEYS, nr as retryClassificationText, nt as endCommandInterruptScope, on as DynamicReferenceRegionAmbiguousError, or as markNonRetryable, pn as NestedStackChildDirectDestroyError, qt as setPasteableAwsProfile, rn as CrossAccountSecretRefusalError, rt as interruptWatchListenerCount, s as readRecordedPrincipals, sn as IntrinsicResolutionRefusalError, t as IAM_PRINCIPAL_NAME, tn as CdkdError, tr as isTransientServerError, tt as beginCommandInterruptScope, vn as StackHasActiveImportsError, wn as normalizeAwsError, xn as SynthesisError, yn as StackTerminationProtectionError, zn as withheldTargetClause, zt as formatLockOwner } from "./iam-policy-targets-B61e5_Sk.js";
3
+ import { $n as isAmbiguousOutcomeError, $t as credentialFingerprint, Bn as withheldTargetClause, D as VALUE_NOT_SHOWN, Dn as TIMEOUT_FLAG_RESOURCE_TYPE, E as assertRegionMatch, En as withErrorHandling, Ft as buildLockContentionMessage, G as runDeleteAttempt, Hn as setPasteableVerbFlags, Ht as CUSTOM_RESOURCE_RESPONSE_PREFIX, In as plainOrDescribed, It as forceQuitRecoveryClause, Jt as setPasteableAwsProfile, Kt as producerCoordinateKey, Ln as quotedOrDescribed, Lt as formatLockExpiry, Nn as isInertUnquoted, Nt as UNREPRODUCIBLE_LOCK_CLAUSE, P as remedyLogicalId, Pn as pasteableCommand, Pt as buildForceUnlockCommand, Qt as clientDefaultsFor, Rn as shellBoundedDisplay, Rt as formatLockOperation, Sn as SynthesisError, T as RESOURCE_NOT_FOUND, Tn as normalizeAwsError, Ut as DEFAULT_STATE_PREFIX, Vn as setPasteableRunFlags, Wt as injectiveKey, Xt as ambientClientDefaults, Yt as withPasteableAwsProfile, Z as isAwsCliLiteral, Zt as ambientCredentialConfig, _n as ResourceTimeoutError, ar as isMarkedNonRetryable, bn as StackTerminationProtectionError, cn as IntrinsicResolutionRefusalError, en as AccountIdUnavailableError, ft as logicalIdShown, gn as ProvisioningError, hn as PartialFailureError, in as CrossAccountSecretRefusalError, it as isInterruptedWaitError, jn as commandHole, kn as SHELL_ACTIVE_WHY, ln as LocalInvokeBuildError$1, mn as NestedStackChildDirectDestroyError, mt as resourceTypeShown, n as RESOLVED_PREVIOUS_PRINCIPAL_KEYS, nn as CdkdError, nr as isTransientServerError, nt as endCommandInterruptScope, on as DeployCancelledError, or as isThrottlingError, pn as MalformedProducerRecordRefusalError, qt as producerRecordKey, rr as retryClassificationText, rt as interruptWatchListenerCount, s as readRecordedPrincipals, sn as DynamicReferenceRegionAmbiguousError, sr as markNonRetryable, t as IAM_PRINCIPAL_NAME, tr as isRetryableTransientError, tt as beginCommandInterruptScope, un as LocalStartServiceError, vn as ResourceUpdateNotSupportedError, yn as StackHasActiveImportsError, zn as shellQuote, zt as formatLockOwner } from "./iam-policy-targets-Cz2tPxXk.js";
4
4
  import { n as awsClientDefaults, r as getAssumedRoleCredentials, u as formatAuthority } from "./aws-client-defaults-D0q0z4dG.js";
5
- import { $ as gray, $a as prefetchCreateOnlyPropertyPaths, $i as refuseMalformedOutputs, $o as wholeStringLeavesOf, $r as getAccountInfo, $s as partitionSensitiveEnv, A as perType, Aa as NO_CC_HANDLERS_REASON, Ac as decodeListingKey, Ai as malformedLocalResourceEntriesWarning, An as buildFinalSnapshotIdentifier, Ao as shareLogOnlyValues, Ar as poisonRenderedSpellingsCollidingIn, As as rewriteTemplateAssetReferences, Bc as hasPlainPrototype, Bi as malformedResourceEntriesWarning, Bn as formatDestructiveChange, Bo as isUncertifiedBaselineMaskPosition, Br as AWS_CREDENTIAL_ENV_KEYS, Bs as validateContainerRepoName, Bt as planRollback, C as noEchoComparisonForTemplate, Ca as unreadableOrphanRecords, Cc as ssmResolvedValueType, Ci as hasReadableResources, Cn as maskEventTextWithBoundBags, Co as createUnionSecretMasker, Cs as AssetPublisher, Ct as isHandledOrphan, D as recordedProtectionNote, Dc as findLargeInlineResources, Di as malformedExportNamesWarning, Dn as extractDeploymentEventError, Do as printingCorpusOf, Dr as DiffCalculator, Ds as buildAssetRedirectMap, Dt as sameJournaledOrphans, E as recordedProtectionEvidence, Ea as findActionableSilentDrops, Ec as MIGRATE_TMP_PREFIX, Ei as malformedDriftResourcePropertiesWarning, En as stateSecretNameNeedles, Eo as logOnlyValueCount, Es as WorkGraph, Et as makeForeignHolderScan, Fa as isStatefulRecreateTargetForReplace, Fc as AssemblyReader, Fi as malformedOrphansRefusalMessage, Fn as refusesFinalSnapshot, Fo as markSameGenerationBag, Fr as assertFlagRoleArn, Fs as getBootstrapMarkerKey, Ft as recordAfterRollbackUpdate, Gc as displayAssemblyPath, Gi as previewableOrphanRecords, Gn as withCreateTokenLedger, Gs as describeDockerExecFailure, Gt as seedsDeleteFirstGuard, Hc as ownValue, Hi as malformedResourcesWarning, Ho as identityKeyFor, Hr as callerEnvCredentials, Hs as buildDockerImage, Ht as recordUnderIdIsNotOwn, Ia as isStatefulRecreateTargetSync, Ic as StageLoadError, Ii as malformedOrphansWarning, In as unsupportedFinalSnapshotError, Io as redactSecretsForState, Ir as assertSendableRoleArn, Is as isCrossRegionRedirect, It as demoteSupersededOrphans, Ji as refuseMalformedOrphanRecords, Jo as recordMaskOnlyValue, Js as finchSecretArgvRefusal, Kc as renderAssemblyPathEscape, Ki as refuseDivergentRecordRegionForDestroy, Ko as carriesSecretMask, Ks as describeDockerFailure, Kt as orphanDeleteNeedsIdentity, La as renderStatefulReason, Lc as processStackMessages, Li as malformedOutputsRefusalMessage, Ln as maskingRetryLogger, Lo as scrubResourceRecord, Lr as explicitRoleArnOrThrow, Ls as parseBootstrapMarker, Lt as isJournaledOrphan, Ma as findReplacedReadersOfRecreateTargets, Mc as PARTITION_TABLE, Mi as malformedOrphanRecordsRefusalMessage, Mn as createPreDeleteFinalSnapshot, Mo as errorCauseChain, Mr as producerRegionsFromState, Ms as BOOTSTRAP_MARKER_PREFIX, Na as shownType, Nc as canonicalizeRegion, Ni as malformedOrphanRecordsWarning, Nn as effectiveDeletionPolicy, No as maskSecretsInError, Nr as regionLessSecretName, Ns as assertAssetBucketRegion, Nt as withStackRecords, O as PROTECTION_PROPERTY_BY_TYPE, Oa as unwrittenCreateOnlyReplacement, Oc as uploadCfnTemplate, Oi as malformedExportSourceWarning, On as ATOMIC_FINAL_SNAPSHOT_TYPES, Oo as recordLogOnlyParameterValue, Or as INTRINSIC_KEYS, Os as createAssetRedirectResolver, Ot as replayFailedOperations, Pa as MULTI_REGION_RECREATE_BLOCKED_TYPES, Pc as derivePartitionAndUrlSuffix, Pi as malformedOrphanRowsKeptWarning, Pn as isFinalSnapshotError, Po as maskSecretsInText, Pr as applyRoleArnIfSet, Ps as ensureAssetStorage, Pt as removeProtectionTypeList, Q as cyan, Qi as refuseMalformedOrphansForOrphan, Qo as recordProvenPublicExpression, Qr as parameterTypeMayLoseSecretIdentity, Qs as isMalformedEnvKey, Rc as defineOwnKey, Ri as malformedOutputsWarning, Rn as constructPathOf, Ro as DYNAMIC_REFERENCE_TOKEN_SCAN, Rr as isIamRoleArn, Rs as readBootstrapMarkerBody, Rt as isReplacementOrphan, S as noEchoAttributeNamesOf, Sa as unpreviewableOrphanRecords, Sc as warnDeprecatedNoPrefixCliFlag, Si as hasReadableOutputs, Sn as journaledOrphanPrintingBag, So as carryLogOnlyValues, Ss as shouldRetainResource, St as dropFailedHint, T as noEchoParameterNamesOf, Ta as withheldAccountClause, Tc as CFN_TEMPLATE_URL_LIMIT, Ti as isReadableResourceEntry, Tn as secretNamePrintingBag, To as literalSplitDelimitersOf, Ts as stringifyValue, Tt as loadJournaledOrphans, Uc as absoluteAssemblyPathEscape, Ui as malformedScrubResourceEntriesRefusalMessage, Un as ledgerForStack, Uo as inheritNestedStackParameterAssociations, Ur as envCredentialsAreAssumedRole, Us as resolveDockerContextDirectory, Ut as replacementNeverSwapped, Vc as nullPrototypeRecord, Vi as malformedResourcePropertiesWarning, Vn as RollbackInlinePolicyWriters, Vo as pathCrossesDottedKey, Vr as applyCallerIdentityCredentials, Vs as buildDenyExternalAccessPolicy, Vt as recheckFailedPlan, Wc as describeFileReadFailure, Wi as malformedStateRefusalMessage, Wo as recordNestedStackParameterExpressions, Ws as describeDockerCapturedOutput, Wt as resolveReplacementOldType, X as createReadOnlyAttributeHealerFactory, Xi as refuseMalformedOrphans, Xo as recordNoEchoAttributeValues, Xr as coerceParameterTypedValue, Xs as getDockerCmd, Y as formatResourceLine, Yc as resolveBucketRegion, Yi as refuseMalformedOrphanRecordsForDestroy, Yo as recordMaskOnlyValuesIn, Ys as formatDockerLoginError, Yt as inheritProducerRegions, Z as bold, Zi as refuseMalformedOrphansForDestroy, Zo as recordNoEchoParameterFreshValue, Zr as isUnboundTemplateParameter, Zs as isDockerClientEnvKey, _ as makeCanonicalizePropertiesFn, _a as repairMalformedOrphansForReadOnly, _c as resolveSkipPrefix, _i as UNREADABLE_RESOURCES_MAP_ROW, _n as isExportAliasCollision, _r as deleteSkipReason, _s as importableOutputKeys, _t as revertedNestedRowIds, a as findNestedTemplateTreeDefect, aa as refuseMalformedResourceEntriesForImport, ac as escapeRegExp, ai as AWS_NO_VALUE, an as displayTextOrWithheld, ar as isCustomResource, as as isSingleDynamicReferenceToken, at as reachableDivergentParameters, b as serviceTokenBlockingReason, ba as repairMalformedResourcePropertiesForReadOnly, bc as resolveUseCdkBootstrapAssets, bi as displayLogicalId, bn as DEFAULT_RESOURCE_WARN_AFTER_MS, bo as valueAtCoordinate, bs as orphansAfterRollback, bt as withNestedStackContext, c as renderNestedTemplateTreeDefect, ca as refuseMalformedResourcePropertiesForDestroy, cc as getDockerImageBySourceHash, ci as refStateLookupFromResource, cn as secretBearingStateKeyWarning, co as canonicalCoordinates, cr as readsNoEchoDeleteValues, cs as S3StateBackend, ct as planOrphanAdoption, d as conditionInputsFrom, da as refuseMalformedResourcePropertiesForOrphan, dc as getDefaultStateBucketName, di as parameterInputsFor, dn as exportNameNoEchoParameters, do as maskReadbackAtCoordinates, dr as withPrintingSecrets, ds as acceptedCreateOnlyDropsOf, dt as displacedPhysicalIdShown, ea as refuseMalformedOutputsForDestroy, ec as redactDockerArgvValues, ei as isImpossibleEmptyStoredAttribute, en as updatePartialMessage, eo as templateResourceTypes, es as STATE_SOURCED_BASELINE_RULES, et as green, f as parentSuppliedValues, fa as refuseMalformedResourcesForDeploy, fc as getLegacyStateBucketName, fn as exportNameSecretExposure, fo as maskWholeValue, fr as CloudControlProvider, fs as describeRegionValueKind, ft as dropSettledNestedJournals, g as mergeNoChangeOutputs, ga as repairMalformedOrphanRecordsForReadOnly, gc as resolveCaptureObservedState, gi as UNREADABLE_ORPHANS_CONTAINER_ROW, gn as collectPublishedOutputNames, go as noEchoOutputsComparison, gr as deleteIndeterminateGuards, gs as hasUnverifiableParameterRefusal, h as keptWholeReasonText, ha as refuseMalformedState, hc as resolveAutoAssetStorage, hi as STATE_RESOURCES_MALFORMED, hn as collectDeclaredOutputNames, ho as noEchoLeavesOf, hr as UNSPECIFIED_SKIP_REASON, hs as hasReasonlessBaselineRefusal, ht as recordDisplacedSkips, i as childTemplateLoader, ia as refuseMalformedResourceEntriesForDestroy, ic as warnFinchArgvExposure, ii as keepsSecretReferenceToken, in as WITHHELD_NAME_DISPLAY, ir as ccBrokenReason, is as WHOLE_DYNAMIC_REFERENCE_PATTERN, it as namesAnyDeclaredParameter, j as readProtection, ja as hasNoCloudControlHandlers, jc as expectedOwnerParam, ji as malformedLocalResourcesWarning, jn as ccRoutedFinalSnapshotError, jo as createSecretMasker, jr as classifyReplaySecretRegion, js as AssetModeResolver, jt as destroyStackRecordsView, k as isProtectionValueActive, kc as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, ki as malformedLocalOutputsWarning, kn as PRE_DELETE_SNAPSHOT_TYPES, ko as recordLogOnlyValue, kr as IntrinsicFunctionResolver, ks as loadPublishableAssetManifest, kt as replayRollback, l as templateIdentity, la as refuseMalformedResourcePropertiesForDrift, lc as Synthesizer, ln as secretSafeKeyDisplay, lo as isMarkedCoordinate, lr as isCustomResourceType$1, ls as rebuildClientForBucketRegion, lt as NESTED_PENDING_PARENT_REASON, m as isSecretBearingReferenceString, ma as refuseMalformedResourcesForExport, mc as resolveApp, mi as STATE_REGION_DIVERGED, mn as noEchoParameterValueSeed, mo as noEchoCoordinatesOf, ms as hasReadableExportSet, mt as nestedChildStackName$1, n as IMPLICIT_DELETE_DEPENDENCIES, na as refuseMalformedResourceEntries, nc as runDockerForeground, ni as carriesFetchableDynamicReference, nn as DeploymentEventsReader, no as withRetry, nr as CC_BROKEN_REASON, ns as STATE_SOURCED_READBACK_RULES, nt as yellow, o as isAbsoluteAssetPath, oa as refuseMalformedResourceEntriesForImportSave, oc as stripControlChars, oi as cfnRefValueFromPhysicalId, on as exportAliasCollisionScrubWarning, oo as DagBuilder, or as wouldReturnToSdkProvider, os as LockManager, ot as resourcesNamingDeclaredParameter, p as readRecordedConditionVerdicts, pa as refuseMalformedResourcesForDestroy, pc as loadCdkJson, pi as JSON_LISTING_HOLE_VALUE, pn as isWholeDynamicReferenceValue, po as maskedLeafCoordinatesOf, pr as slowCcOperationTimeoutMs, ps as exportNamesCarriedFrom, qc as resolveAssemblyPath, qo as provenPublicValue, qs as dockerSpawnEnvWithSensitive, qt as findNestedStackTypeChanges, r as computeImplicitDeleteEdges, ra as refuseMalformedResourceEntriesForDeploy, rc as runDockerStreaming, ri as isNamelessDynamicReferenceError, rn as DeploymentEventsStore, rr as ProviderRegistry, rs as TEMPLATE_SOURCED_RULES, rt as computeParameterTaint, s as listNestedTemplateRows, sa as refuseMalformedResourceEntriesForOrphan, sc as AssetManifestLoader, si as isStalePlaceholderArnAttribute, sn as secretBearing, so as TemplateParser, sr as TemplateNoEchoReresolver, ss as isLockInfoExpired, st as makeSiblingClaimReader, t as DeployEngine, ta as refuseMalformedResourceAttributesForOrphan, tc as redactedDockerCause, ti as carriesDynamicReference, tn as updatePartialReason, to as describeTypeWithThrottleRetry, ts as STATE_SOURCED_CROSS_GENERATION_RULES, tt as red, u as conditionFingerprint, ua as refuseMalformedResourcePropertiesForExport, uc as synthesisStatusMessage, ui as withSharedDrainBudget, un as carriedExportAliasExposure, uo as maskAtCoordinates, us as splitImportedOps, ut as displacedOpClause, v as deferredServiceTokenWarning, va as repairMalformedOutputsForReadOnly, vc as resolveStateBucketWithDefault, vi as accountArgs, vn as bindingSkippedOutputs, vo as readbackPathFor, vs as importableOutputs, vt as withNestedRevertRun, w as noEchoExactEchoLeavesOf, wa as unreadableResourceEntries, wc as CFN_TEMPLATE_BODY_LIMIT, wi as isReadableOrphanRecord, wn as orphanRecordsPrintingBag, wo as hasMaskableValues, ws as isSensitiveAttributeName, wt as journaledOrphanLines, x as withResourceDeadline, xa as repairMalformedResourcesForReadOnly, xc as stateBucketExistenceConfirmed, xi as hasReadableOrphans, xn as completedReplayEntries, xo as liveMatchesUnresolvedTokenFrame, xs as orphansCarriedFrom, xt as deleteJournaledOrphans, y as findServiceTokenRefusals, ya as repairMalformedResourceEntriesForReadOnly, yc as resolveStateBucketWithDefaultAndSource, yi as deployRefusesOrphanRowsReason, yn as DEFAULT_RESOURCE_TIMEOUT_MS, yo as readsNoEchoSource, yr as isWaitAbandonedError, ys as isReadableBag, zc as hasOwnKey, zi as malformedRenderedContainersWarning, zn as findDestructiveChanges, zo as dynamicReferenceTokens, zr as sendableAssumeRoleCommand, zs as validateAssetBucketName, zt as planFailedOps } from "./deploy-engine-D4FdwPCi.js";
6
- import { t as getCdkdVersion } from "./version-B0JEGOLV.js";
5
+ import { $c as hasOwnKey, $i as previewableOrphanRecords, $s as validateAssetBucketName, $t as orphanDeleteNeedsIdentity, A as noEchoExactEchoLeavesOf, Aa as unpreviewableOrphanRecords, Ac as resolveCaptureObservedState, Ai as hasReadableOutputs, An as maskEventTextWithBoundBags, Ao as carryLogOnlyValues, As as hasUnverifiableParameterRefusal, At as isHandledOrphan, Ba as findReplacedReadersOfRecreateTargets, Bc as MIGRATE_TMP_PREFIX, Bi as malformedOrphanRecordsRefusalMessage, Bn as effectiveDeletionPolicy, Bo as errorCauseChain, Br as producerRegionsFromState, Bs as WorkGraph, Bt as withStackRecords, C as recordRetainedForReadoption, Ca as refuseMalformedState, Cc as Synthesizer, Ci as STATE_RESOURCES_MALFORMED, Cn as collectPublishedOutputNames, Co as noEchoLeavesOf, Cr as deleteIndeterminateGuards, Cs as isNotImplemented, Ct as revertedNestedRowIds, D as withResourceDeadline, Da as repairMalformedResourceEntriesForReadOnly, Dc as loadCdkJson, Di as deployRefusesOrphanRowsReason, Dn as DEFAULT_RESOURCE_WARN_AFTER_MS, Do as readsNoEchoSource, Dr as isWaitAbandonedError, Ds as exportNamesCarriedFrom, Dt as withNestedStackContext, E as serviceTokenBlockingReason, Ea as repairMalformedOutputsForReadOnly, Ec as getLegacyStateBucketName, Ei as accountArgs, En as DEFAULT_RESOURCE_TIMEOUT_MS, Eo as readbackPathFor, Es as describeRegionValueKind, F as isProtectionValueActive, Fc as stateBucketExistenceConfirmed, Fi as malformedExportNamesWarning, Fn as ATOMIC_FINAL_SNAPSHOT_TYPES, Fo as printingCorpusOf, Fr as DiffCalculator, Fs as orphansCarriedFrom, Ft as replayFailedOperations, Ga as renderStatefulReason, Gc as expectedOwnerParam, Gi as malformedOutputsRefusalMessage, Gn as constructPathOf, Go as scrubResourceRecord, Gr as explicitRoleArnOrThrow, Gs as AssetModeResolver, Gt as isReplacementOrphan, Ha as MULTI_REGION_RECREATE_BLOCKED_TYPES, Hc as uploadCfnTemplate, Hi as malformedOrphanRowsKeptWarning, Hn as refusesFinalSnapshot, Ho as maskSecretsInText, Hr as applyRoleArnIfSet, Hs as createAssetRedirectResolver, Ht as recordAfterRollbackUpdate, I as perType, Ia as unwrittenCreateOnlyReplacement, Ic as warnDeprecatedNoPrefixCliFlag, Ii as malformedExportSourceWarning, In as PRE_DELETE_SNAPSHOT_TYPES, Io as recordLogOnlyParameterValue, Ir as INTRINSIC_KEYS, Is as shouldRetainResource, It as replayRollback, Jc as derivePartitionAndUrlSuffix, Ji as malformedResourceEntriesWarning, Jn as RollbackInlinePolicyWriters, Jo as isUncertifiedBaselineMaskPosition, Jr as AWS_CREDENTIAL_ENV_KEYS, Js as ensureAssetStorage, Jt as recheckFailedPlan, Kc as PARTITION_TABLE, Ki as malformedOutputsWarning, Kn as findDestructiveChanges, Ko as DYNAMIC_REFERENCE_TOKEN_SCAN, Kr as isIamRoleArn, Ks as BOOTSTRAP_MARKER_PREFIX, Kt as planFailedOps, L as readProtection, Lc as ssmResolvedValueType, Li as malformedLocalOutputsWarning, Ln as buildFinalSnapshotIdentifier, Lo as recordLogOnlyValue, Lr as IntrinsicFunctionResolver, Ls as AssetPublisher, M as recordedProtectionEvidence, Ma as unreadableResourceEntries, Mc as resolveStateBucketWithDefault, Mi as isReadableOrphanRecord, Mn as secretNamePrintingBag, Mo as hasMaskableValues, Ms as importableOutputs, Mt as loadJournaledOrphans, N as recordedProtectionNote, Na as withheldAccountClause, Nc as resolveStateBucketWithDefaultAndSource, Ni as isReadableResourceEntry, Nn as stateSecretNameNeedles, No as literalSplitDelimitersOf, Ns as isReadableBag, Nt as makeForeignHolderScan, O as noEchoAttributeNamesOf, Oa as repairMalformedResourcePropertiesForReadOnly, Oc as resolveApp, Oi as displayLogicalId, On as completedReplayEntries, Oo as valueAtCoordinate, Os as hasReadableExportSet, Ot as deleteJournaledOrphans, P as PROTECTION_PROPERTY_BY_TYPE, Pa as findActionableSilentDrops, Pc as resolveUseCdkBootstrapAssets, Pi as malformedDriftResourcePropertiesWarning, Pn as extractDeploymentEventError, Po as logOnlyValueCount, Ps as orphansAfterRollback, Pt as sameJournaledOrphans, Qc as defineOwnKey, Qi as malformedStateRefusalMessage, Qn as withCreateTokenLedger, Qo as recordNestedStackParameterExpressions, Qs as readBootstrapMarkerBody, Qt as seedsDeleteFirstGuard, Ra as NO_CC_HANDLERS_REASON, Rc as CFN_TEMPLATE_BODY_LIMIT, Ri as malformedLocalResourceEntriesWarning, Rn as ccRoutedFinalSnapshotError, Ro as shareLogOnlyValues, Rr as poisonRenderedSpellingsCollidingIn, Rs as isSensitiveAttributeName, Rt as destroyStackRecordsView, S as keptForReadoption, Sa as refuseMalformedResourcesForExport, Sc as getDockerImageBySourceHash, Si as STATE_REGION_DIVERGED, Sn as collectDeclaredOutputNames, So as noEchoCoordinatesOf, Sr as UNSPECIFIED_SKIP_REASON, Ss as isAccessDenied, T as findServiceTokenRefusals, Ta as repairMalformedOrphansForReadOnly, Tc as getDefaultStateBucketName, Ti as UNREADABLE_RESOURCES_MAP_ROW, Tn as bindingSkippedOutputs, Tr as deleteSkipReason, Ts as acceptedCreateOnlyDropsOf, Tt as collectNestedChildUnaddressed, Ua as isStatefulRecreateTargetForReplace, Uc as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, Ui as malformedOrphansRefusalMessage, Un as unsupportedFinalSnapshotError, Uo as markSameGenerationBag, Ur as assertFlagRoleArn, Us as loadPublishableAssetManifest, Ut as demoteSupersededOrphans, Va as shownType, Vc as findLargeInlineResources, Vi as malformedOrphanRecordsWarning, Vn as isFinalSnapshotError, Vo as maskSecretsInError, Vr as regionLessSecretName, Vs as buildAssetRedirectMap, Vt as removeProtectionTypeList, Wa as isStatefulRecreateTargetSync, Wc as decodeListingKey, Wi as malformedOrphansWarning, Wn as maskingRetryLogger, Wo as redactSecretsForState, Wr as assertSendableRoleArn, Ws as rewriteTemplateAssetReferences, Wt as isJournaledOrphan, Xc as StageLoadError, Xi as malformedResourcesWarning, Xn as ledgerForStack, Xo as identityKeyFor, Xr as callerEnvCredentials, Xs as isCrossRegionRedirect, Xt as replacementNeverSwapped, Yc as AssemblyReader, Yi as malformedResourcePropertiesWarning, Yo as pathCrossesDottedKey, Yr as applyCallerIdentityCredentials, Ys as getBootstrapMarkerKey, Yt as recordUnderIdIsNotOwn, Zc as processStackMessages, Zi as malformedScrubResourceEntriesRefusalMessage, Zo as inheritNestedStackParameterAssociations, Zr as envCredentialsAreAssumedRole, Zs as parseBootstrapMarker, Zt as resolveReplacementOldType, _ as makeCanonicalizePropertiesFn, _a as refuseMalformedResourcePropertiesForDrift, _c as runDockerStreaming, _n as carriedExportAliasExposure, _o as isMarkedCoordinate, _s as rebuildClientForBucketRegion, _t as displacedPhysicalIdShown, a as findNestedTemplateTreeDefect, aa as refuseMalformedOrphansForDestroy, ac as describeDockerExecFailure, ai as isUnboundTemplateParameter, al as displayAssemblyPath, as as recordNoEchoParameterFreshValue, at as gray, ba as refuseMalformedResourcesForDeploy, bc as stripControlChars, bn as isWholeDynamicReferenceValue, bo as maskWholeValue, br as slowCcOperationTimeoutMs, bs as applyCrossPrefixScan, bt as nestedChildStackName$1, c as renderNestedTemplateTreeDefect, ca as refuseMalformedOutputsForDestroy, cc as finchSecretArgvRefusal, ci as isImpossibleEmptyStoredAttribute, cn as updatePartialReason, co as templateResourceTypes, cs as STATE_SOURCED_BASELINE_RULES, ct as yellow, d as conditionInputsFrom, da as refuseMalformedResourceEntriesForDeploy, dc as isDockerClientEnvKey, di as isNamelessDynamicReferenceError, dn as WITHHELD_NAME_DISPLAY, dr as ccBrokenReason, ds as TEMPLATE_SOURCED_RULES, dt as reachableDivergentParameters, ea as refuseDivergentRecordRegionForDestroy, ec as validateContainerRepoName, el as hasPlainPrototype, en as findNestedStackTypeChanges, es as carriesSecretMask, f as parentSuppliedValues, fa as refuseMalformedResourceEntriesForDestroy, fc as isMalformedEnvKey, fi as keepsSecretReferenceToken, fn as displayTextOrWithheld, fr as isCustomResource, fs as WHOLE_DYNAMIC_REFERENCE_PATTERN, ft as resourcesNamingDeclaredParameter, g as mergeNoChangeOutputs, ga as refuseMalformedResourcePropertiesForDestroy, gc as runDockerForeground, gi as refStateLookupFromResource, gn as secretSafeKeyDisplay, go as canonicalCoordinates, gr as isCustomResourceType$1, gs as S3StateBackend, gt as displacedOpClause, h as keptWholeReasonText, ha as refuseMalformedResourceEntriesForOrphan, hc as redactedDockerCause, hi as isStalePlaceholderArnAttribute, hn as secretBearingStateKeyWarning, ho as TemplateParser, hr as readsNoEchoDeleteValues, hs as isLockInfoExpired, ht as NESTED_PENDING_PARENT_REASON, i as childTemplateLoader, ia as refuseMalformedOrphans, ic as describeDockerCapturedOutput, ii as coerceParameterTypedValue, il as describeFileReadFailure, is as recordNoEchoAttributeValues, it as cyan, j as noEchoParameterNamesOf, ja as unreadableOrphanRecords, jc as resolveSkipPrefix, ji as hasReadableResources, jn as orphanRecordsPrintingBag, jo as createUnionSecretMasker, js as importableOutputKeys, jt as journaledOrphanLines, k as noEchoComparisonForTemplate, ka as repairMalformedResourcesForReadOnly, kc as resolveAutoAssetStorage, ki as hasReadableOrphans, kn as journaledOrphanPrintingBag, ko as liveMatchesUnresolvedTokenFrame, ks as hasReasonlessBaselineRefusal, kt as dropFailedHint, l as templateIdentity, la as refuseMalformedResourceAttributesForOrphan, lc as formatDockerLoginError, li as carriesDynamicReference, ll as resolveBucketRegion, ln as DeploymentEventsReader, lo as describeTypeWithThrottleRetry, lr as CC_BROKEN_REASON, ls as STATE_SOURCED_CROSS_GENERATION_RULES, lt as computeParameterTaint, m as isSecretBearingReferenceString, ma as refuseMalformedResourceEntriesForImportSave, mc as redactDockerArgvValues, mi as cfnRefValueFromPhysicalId, mn as secretBearing, mo as DagBuilder, mr as TemplateNoEchoReresolver, ms as LockManager, mt as planOrphanAdoption, n as IMPLICIT_DELETE_DEPENDENCIES, na as refuseMalformedOrphanRecords, nc as buildDockerImage, nl as ownValue, nn as inheritProducerRegions, ns as recordMaskOnlyValue, nt as createReadOnlyAttributeHealerFactory, o as isAbsoluteAssetPath, oa as refuseMalformedOrphansForOrphan, oc as describeDockerFailure, oi as parameterTypeMayLoseSecretIdentity, ol as renderAssemblyPathEscape, os as recordProvenPublicExpression, ot as green, p as readRecordedConditionVerdicts, pa as refuseMalformedResourceEntriesForImport, pc as partitionSensitiveEnv, pi as AWS_NO_VALUE, pn as exportAliasCollisionScrubWarning, pr as wouldReturnToSdkProvider, ps as isSingleDynamicReferenceToken, pt as makeSiblingClaimReader, qc as canonicalizeRegion, qi as malformedRenderedContainersWarning, qn as formatDestructiveChange, qo as dynamicReferenceTokens, qr as sendableAssumeRoleCommand, qs as assertAssetBucketRegion, qt as planRollback, r as computeImplicitDeleteEdges, ra as refuseMalformedOrphanRecordsForDestroy, rc as resolveDockerContextDirectory, rl as absoluteAssemblyPathEscape, rs as recordMaskOnlyValuesIn, rt as bold, s as listNestedTemplateRows, sa as refuseMalformedOutputs, sc as dockerSpawnEnvWithSensitive, si as getAccountInfo, sl as resolveAssemblyPath, sn as updatePartialMessage, so as prefetchCreateOnlyPropertyPaths, ss as wholeStringLeavesOf, st as red, t as DeployEngine, tc as buildDenyExternalAccessPolicy, tl as nullPrototypeRecord, ts as provenPublicValue, tt as formatResourceLine, u as conditionFingerprint, ua as refuseMalformedResourceEntries, uc as getDockerCmd, ui as carriesFetchableDynamicReference, un as DeploymentEventsStore, uo as withRetry, ur as ProviderRegistry, us as STATE_SOURCED_READBACK_RULES, ut as namesAnyDeclaredParameter, va as refuseMalformedResourcePropertiesForExport, vc as warnFinchArgvExposure, vi as withSharedDrainBudget, vn as exportNameNoEchoParameters, vo as maskAtCoordinates, vr as withPrintingSecrets, vs as CrossPrefixReadError, vt as dropSettledNestedJournals, w as deferredServiceTokenWarning, wa as repairMalformedOrphanRecordsForReadOnly, wc as synthesisStatusMessage, wi as UNREADABLE_ORPHANS_CONTAINER_ROW, wn as isExportAliasCollision, wo as noEchoOutputsComparison, wr as deleteLeftInPlace, ws as splitImportedOps, wt as withNestedRevertRun, xa as refuseMalformedResourcesForDestroy, xc as AssetManifestLoader, xi as JSON_LISTING_HOLE_VALUE, xn as noEchoParameterValueSeed, xo as maskedLeafCoordinatesOf, xs as crossPrefixDeniedWarning, xt as recordDisplacedSkips, ya as refuseMalformedResourcePropertiesForOrphan, yc as escapeRegExp, yi as parameterInputsFor, yn as exportNameSecretExposure, yo as maskReadbackAtCoordinates, yr as CloudControlProvider, ys as CrossPrefixScanCache, za as hasNoCloudControlHandlers, zc as CFN_TEMPLATE_URL_LIMIT, zi as malformedLocalResourcesWarning, zn as createPreDeleteFinalSnapshot, zo as createSecretMasker, zr as classifyReplaySecretRegion, zs as stringifyValue } from "./deploy-engine-BuPc2Dfc.js";
6
+ import { t as getCdkdVersion } from "./version-B__YmKBy.js";
7
7
  import { randomBytes, randomUUID } from "node:crypto";
8
8
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutBucketVersioningCommand, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
9
9
  import { GetRoleCommand, GetUserCommand } from "@aws-sdk/client-iam";
@@ -1306,6 +1306,14 @@ function createListCommand() {
1306
1306
 
1307
1307
  //#endregion
1308
1308
  //#region src/utils/interrupt-signals.ts
1309
+ const postCleanupListeners = /* @__PURE__ */ new WeakSet();
1310
+ function prependPostCleanupSigintListener(listener) {
1311
+ postCleanupListeners.add(listener);
1312
+ process.prependListener("SIGINT", listener);
1313
+ return () => {
1314
+ process.removeListener("SIGINT", listener);
1315
+ };
1316
+ }
1309
1317
  function forwardSigtermToSigint() {
1310
1318
  beginCommandInterruptScope();
1311
1319
  try {
@@ -1333,7 +1341,7 @@ function watchCommandInterrupt(opts) {
1333
1341
  }
1334
1342
  let stacksInFlight = 0;
1335
1343
  function gracefulOwnerArmed() {
1336
- return process.listeners("SIGINT").filter((l) => l !== handler).length - interruptWatchListenerCount() > 0;
1344
+ return process.listeners("SIGINT").filter((l) => l !== handler && !postCleanupListeners.has(l)).length - interruptWatchListenerCount() > 0;
1337
1345
  }
1338
1346
  const handler = () => {
1339
1347
  if (stacksInFlight > 0 && gracefulOwnerArmed()) {
@@ -1923,8 +1931,8 @@ function resolveRequireApproval(cliValue, logger, cdkJson = loadCdkJson()) {
1923
1931
  throw new CdkdError(`cdk.json "requireApproval" must be one of ${REQUIRE_APPROVAL_VALUES.join(", ")}, got: ${displayIdent(typeof configured === "string" ? configured : JSON.stringify(configured))}`, "INVALID_REQUIRE_APPROVAL");
1924
1932
  }
1925
1933
  function createApprovalPrompter(options) {
1934
+ if (options.yes) return Object.assign(() => Promise.resolve(true), { autoApproves: true });
1926
1935
  return (request) => {
1927
- if (options.yes) return Promise.resolve(true);
1928
1936
  return serializePrompt(() => getLiveRenderer().suspendWhile(async () => {
1929
1937
  process.stdout.write(renderApprovalRequest(request));
1930
1938
  return confirmOrRefuse("Do you wish to deploy these changes?", {
@@ -2396,7 +2404,7 @@ function collectCrossStackRefs(node, onRef) {
2396
2404
  //#region src/provisioning/register-providers.ts
2397
2405
  let providerClasses;
2398
2406
  function loadProviderClasses() {
2399
- providerClasses ??= import("./provider-classes-wbKBBEol.js");
2407
+ providerClasses ??= import("./provider-classes-DmZ0J68L.js");
2400
2408
  return providerClasses;
2401
2409
  }
2402
2410
  function registerAllProviders(registry, classes) {
@@ -2637,6 +2645,262 @@ function createPrefixMigrationGate(opts) {
2637
2645
  };
2638
2646
  }
2639
2647
 
2648
+ //#endregion
2649
+ //#region src/cli/commands/registry-release.ts
2650
+ async function releaseRegistryMarkerQuietly(backend, stackName, region, logger, known) {
2651
+ if (stackName.includes("~")) return;
2652
+ try {
2653
+ const released = known === void 0 ? await backend.releaseRegistryMarker(stackName, region) : await backend.releaseRegistryMarker(stackName, region, known);
2654
+ logger.debug(safeMsg`Stack registry marker: ${released}`);
2655
+ } catch (error) {
2656
+ logger.warn(safeMsg`Could not delete the stack registry marker of ${displayStackName(stackName)} ` + safeMsg`(${describeAwsFailure(error).summary}). It names this state prefix, which no longer ` + `records the stack, so a deploy under another prefix treats it as stale.`);
2657
+ }
2658
+ }
2659
+
2660
+ //#endregion
2661
+ //#region src/cli/commands/cross-prefix-gate.ts
2662
+ function deployStackRegion(stack, baseRegion) {
2663
+ return stack.region || baseRegion;
2664
+ }
2665
+ function createCrossPrefixDeployGate(opts) {
2666
+ return async (gateStackName, state) => {
2667
+ if (gateStackName !== opts.stackName) return;
2668
+ if (state !== void 0) return;
2669
+ const result = await opts.guard.firstDeploy(opts.stackName, opts.region);
2670
+ applyCrossPrefixScan(result, {
2671
+ stackName: opts.stackName,
2672
+ region: opts.region,
2673
+ bucket: opts.bucket,
2674
+ recovery: opts.recovery
2675
+ }, "deploy", ...reportOnce(result));
2676
+ };
2677
+ }
2678
+ const reported = /* @__PURE__ */ new WeakSet();
2679
+ function reportOnce(result) {
2680
+ const first = !reported.has(result);
2681
+ reported.add(result);
2682
+ return first ? [(message) => getLogger().warn(message), (message) => getLogger().info(message)] : [() => void 0, () => void 0];
2683
+ }
2684
+ function createCrossPrefixDestructiveGate(opts) {
2685
+ return async (stackName, _destructive, stage) => {
2686
+ const result = await opts.cache.full(stackName, opts.region);
2687
+ applyCrossPrefixScan(result, {
2688
+ stackName,
2689
+ region: opts.region,
2690
+ bucket: opts.bucket,
2691
+ recovery: opts.recovery
2692
+ }, stage === "late" ? "deploy-late-replace" : "deploy-destructive", ...reportOnce(result));
2693
+ };
2694
+ }
2695
+ function createCrossPrefixHolder(opts) {
2696
+ return async (stackName) => {
2697
+ const result = await opts.cache.full(stackName, opts.region);
2698
+ switch (result.kind) {
2699
+ case "found": return {
2700
+ kind: "unreadable",
2701
+ what: safeMsg`bucket ${opts.bucket} also records this stack under another state prefix (${displayIdent(result.prefixes[0])}), whose record may hold it`
2702
+ };
2703
+ case "in-progress": return {
2704
+ kind: "unreadable",
2705
+ what: safeMsg`bucket ${opts.bucket} assigns this stack to another state prefix (${displayIdent(result.prefix)}), where a deploy may be in progress`
2706
+ };
2707
+ case "failed": return {
2708
+ kind: "unreadable",
2709
+ what: safeMsg`the other state prefixes of bucket ${opts.bucket} could not be checked`,
2710
+ retryable: true
2711
+ };
2712
+ case "denied":
2713
+ reportOnce(result)[0](crossPrefixDeniedWarning({
2714
+ stackName,
2715
+ region: opts.region,
2716
+ bucket: opts.bucket
2717
+ }, result.error, result.stage));
2718
+ return;
2719
+ default: return;
2720
+ }
2721
+ };
2722
+ }
2723
+ function crossPrefixEngineOptions(opts) {
2724
+ const backend = opts.backend;
2725
+ return {
2726
+ ...backend !== void 0 && { onFirstDeployLeftNoRecord: async (stackName) => {
2727
+ if (stackName !== opts.stackName) return;
2728
+ const known = await opts.guard.knownMarker?.(stackName, opts.region);
2729
+ await releaseRegistryMarkerQuietly(backend, stackName, opts.region, getLogger(), known);
2730
+ } },
2731
+ firstDeployGate: createCrossPrefixDeployGate({
2732
+ stackName: opts.stackName,
2733
+ region: opts.region,
2734
+ bucket: opts.bucket,
2735
+ recovery: opts.recovery,
2736
+ guard: opts.guard
2737
+ }),
2738
+ onDestructivePlan: createCrossPrefixDestructiveGate({
2739
+ region: opts.region,
2740
+ bucket: opts.bucket,
2741
+ recovery: opts.recovery,
2742
+ cache: opts.guard
2743
+ }),
2744
+ crossPrefixHolder: createCrossPrefixHolder({
2745
+ region: opts.region,
2746
+ bucket: opts.bucket,
2747
+ cache: opts.guard
2748
+ })
2749
+ };
2750
+ }
2751
+ function composeStateLoadedGates(crossPrefix, migration) {
2752
+ return async (stackName, state) => {
2753
+ await crossPrefix(stackName, state);
2754
+ if (migration) await migration(stackName, state);
2755
+ };
2756
+ }
2757
+
2758
+ //#endregion
2759
+ //#region src/state/stack-registry.ts
2760
+ function unwrapReadError(error) {
2761
+ return error instanceof CrossPrefixReadError ? error.cause : error;
2762
+ }
2763
+ function topLevelStackName(stackName) {
2764
+ return stackName.split("~")[0];
2765
+ }
2766
+ var CrossPrefixGuard = class {
2767
+ scan;
2768
+ backend;
2769
+ readOnly;
2770
+ markers = /* @__PURE__ */ new Map();
2771
+ answers = /* @__PURE__ */ new Map();
2772
+ constructor(backend, opts = {}) {
2773
+ this.backend = backend;
2774
+ this.readOnly = opts.readOnly === true;
2775
+ this.scan = opts.scan ?? new CrossPrefixScanCache(backend);
2776
+ }
2777
+ get target() {
2778
+ return this.scan.target;
2779
+ }
2780
+ full(stackName, region, when = "now") {
2781
+ const key = JSON.stringify([stackName, region]);
2782
+ let answer = this.answers.get(key);
2783
+ if (answer === void 0) {
2784
+ answer = this.evaluate(stackName, region, false, when);
2785
+ this.answers.set(key, answer);
2786
+ } else if (when === "now") this.scan.target.rank(stackName, region, "now");
2787
+ return answer;
2788
+ }
2789
+ firstDeploy(stackName, region) {
2790
+ const key = JSON.stringify([stackName, region]);
2791
+ const answer = this.evaluate(stackName, region, true, "now");
2792
+ this.answers.set(key, answer);
2793
+ return answer;
2794
+ }
2795
+ async knownMarker(stackName, region) {
2796
+ const read = this.markers.get(JSON.stringify([topLevelStackName(stackName), region]));
2797
+ if (read === void 0) return void 0;
2798
+ return read.catch(() => void 0);
2799
+ }
2800
+ marker(top, region, fresh = false) {
2801
+ const key = JSON.stringify([top, region]);
2802
+ let read = fresh ? void 0 : this.markers.get(key);
2803
+ if (read === void 0) {
2804
+ read = this.backend.getRegistryMarker(top, region);
2805
+ this.markers.set(key, read);
2806
+ }
2807
+ return read;
2808
+ }
2809
+ async evaluate(stackName, region, firstDeploy, when) {
2810
+ const top = topLevelStackName(stackName);
2811
+ const claimable = top === stackName && !this.readOnly;
2812
+ if (firstDeploy && claimable && !this.markers.has(JSON.stringify([top, region]))) {
2813
+ if (await this.claim(top, region) === "claimed") return { kind: "clear" };
2814
+ }
2815
+ for (let attempt = 0; attempt < 2; attempt++) {
2816
+ let marker;
2817
+ try {
2818
+ marker = await this.marker(top, region, attempt > 0);
2819
+ } catch (error) {
2820
+ return this.fallback(stackName, region, when, error);
2821
+ }
2822
+ if (marker === null) {
2823
+ if (firstDeploy) {
2824
+ if (!claimable) return { kind: "clear" };
2825
+ const claimed = await this.claim(top, region);
2826
+ if (claimed === "conflict") continue;
2827
+ if (claimed !== "claimed") return this.fallback(stackName, region, when, claimed.error);
2828
+ return { kind: "clear" };
2829
+ }
2830
+ const scanned = await this.scan.full(stackName, region, when);
2831
+ if (scanned.kind === "clear" && claimable) {
2832
+ if (await this.claim(top, region) === "conflict") continue;
2833
+ }
2834
+ return scanned;
2835
+ }
2836
+ if (marker.prefix === this.backend.prefix) return { kind: "clear" };
2837
+ let held;
2838
+ let locked;
2839
+ try {
2840
+ held = await this.backend.recordUnderPrefix(marker.prefix, stackName, region);
2841
+ locked = held === "holder" ? false : await this.backend.lockUnderPrefix(marker.prefix, top, region);
2842
+ } catch (error) {
2843
+ return isAccessDenied(error) ? {
2844
+ kind: "denied",
2845
+ error,
2846
+ stage: "probe"
2847
+ } : {
2848
+ kind: "failed",
2849
+ error
2850
+ };
2851
+ }
2852
+ if (held === "holder") return {
2853
+ kind: "found",
2854
+ prefixes: [marker.prefix]
2855
+ };
2856
+ if (locked) return {
2857
+ kind: "in-progress",
2858
+ prefix: marker.prefix
2859
+ };
2860
+ const stale = held === "empty" ? [marker.prefix] : [];
2861
+ const scanned = await this.scan.full(stackName, region, when);
2862
+ if (scanned.kind !== "clear") return scanned;
2863
+ const allStale = [.../* @__PURE__ */ new Set([...stale, ...scanned.stale ?? []])];
2864
+ const answer = {
2865
+ kind: "clear",
2866
+ ...allStale.length > 0 && { stale: allStale }
2867
+ };
2868
+ if (!claimable) return answer;
2869
+ if (await this.claim(top, region, marker.etag) === "conflict") continue;
2870
+ return answer;
2871
+ }
2872
+ return {
2873
+ kind: "failed",
2874
+ error: new CrossPrefixReadError(`_cdkd-registry/${region}/${top}.json`, Object.assign(/* @__PURE__ */ new Error("the marker changed twice while cdkd was claiming it"), { name: "ConcurrentClaim" }))
2875
+ };
2876
+ }
2877
+ async claim(top, region, ifMatch) {
2878
+ try {
2879
+ const result = await this.backend.claimRegistryMarker(top, region, ifMatch);
2880
+ if (result === "claimed") this.markers.set(JSON.stringify([top, region]), Promise.resolve({
2881
+ prefix: this.backend.prefix,
2882
+ etag: ""
2883
+ }));
2884
+ return result;
2885
+ } catch (error) {
2886
+ return { error };
2887
+ }
2888
+ }
2889
+ async fallback(stackName, region, when, error) {
2890
+ if (!isAccessDenied(error) && !isNotImplemented(unwrapReadError(error))) return {
2891
+ kind: "failed",
2892
+ error
2893
+ };
2894
+ const scanned = await this.scan.full(stackName, region, when);
2895
+ return scanned.kind === "clear" ? {
2896
+ kind: "denied",
2897
+ error,
2898
+ stage: "registry",
2899
+ ...scanned.stale && { stale: scanned.stale }
2900
+ } : scanned;
2901
+ }
2902
+ };
2903
+
2640
2904
  //#endregion
2641
2905
  //#region src/cli/commands/deploy.ts
2642
2906
  async function deployCommand(stacks, options) {
@@ -2706,6 +2970,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
2706
2970
  };
2707
2971
  process.on("SIGINT", topLevelSigintHandler);
2708
2972
  const unforwardSigterm = forwardSigtermToSigint();
2973
+ let preflightBackendForCleanup;
2709
2974
  try {
2710
2975
  logger.info(cyan(synthesisStatusMessage(app, "Synthesizing CDK app...")));
2711
2976
  const synthesizer = new Synthesizer();
@@ -2721,6 +2986,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
2721
2986
  };
2722
2987
  const [result, statePrep] = await Promise.all([synthesizer.synthesize(synthOptions), statePrepPromise]);
2723
2988
  const { stateBucket, preflightStateBackend, exportIndexStore } = statePrep;
2989
+ preflightBackendForCleanup = preflightStateBackend;
2724
2990
  synthOptions.stateBucket = stateBucket;
2725
2991
  const refusalRecovery = {
2726
2992
  profile: options.profile,
@@ -2787,6 +3053,8 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
2787
3053
  ignoreErrors: options.ignoreErrors === true
2788
3054
  });
2789
3055
  refuseMalformedNestedTemplateTrees(targetStacks);
3056
+ const baseRegion = namedCliRegion(options.region) ?? "us-east-1";
3057
+ const crossPrefixGuard = new CrossPrefixGuard(preflightStateBackend, { readOnly: options.dryRun === true });
2790
3058
  await synthesizer.expandMacrosForStacks(targetStacks, synthOptions);
2791
3059
  const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
2792
3060
  const stsClient = new STSClient({
@@ -2816,7 +3084,6 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
2816
3084
  };
2817
3085
  const dagBuilder = new DagBuilder({ relaxCdkVpcDefensiveDeps: !!options.aggressiveVpcParallel });
2818
3086
  const diffCalculator = new DiffCalculator();
2819
- const baseRegion = namedCliRegion(options.region) ?? "us-east-1";
2820
3087
  const workGraph = new WorkGraph();
2821
3088
  const stackMap = new Map(targetStacks.map((s) => [s.stackName, s]));
2822
3089
  const stackRedirects = /* @__PURE__ */ new Map();
@@ -2864,13 +3131,14 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
2864
3131
  logger.debug(`Work graph: ${summary["asset-publish"]} asset(s), ${summary["stack"]} stack(s)`);
2865
3132
  const bufferStackOutput = targetStacks.length > 1;
2866
3133
  let totalUnaddressed = 0;
3134
+ let totalCrossPrefixKept = 0;
2867
3135
  let cancelledStacks = 0;
2868
3136
  const runStack = async (stackInfo) => {
2869
3137
  return withSkipPrefix(skipPrefix, () => runStackInner(stackInfo));
2870
3138
  };
2871
3139
  const runStackInner = async (stackInfo) => {
2872
3140
  if (deployInterrupted) throw new DeployCancelledError(`Deploy interrupted before stack '${stackInfo.stackName}' started — not starting it.`);
2873
- const stackRegion = stackInfo.region || baseRegion;
3141
+ const stackRegion = deployStackRegion(stackInfo, baseRegion);
2874
3142
  logger.info(`\n${cyan("Deploying stack:")} ${bold(cyan(stackInfo.stackName))}${stackRegion !== baseRegion ? gray(` (region: ${stackRegion})`) : ""}`);
2875
3143
  const stackAwsClients = new AwsClients({
2876
3144
  region: stackRegion,
@@ -2908,6 +3176,14 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
2908
3176
  skipPrefix,
2909
3177
  yes: options.yes
2910
3178
  });
3179
+ const crossPrefix = crossPrefixEngineOptions({
3180
+ stackName: stackInfo.stackName,
3181
+ region: stackRegion,
3182
+ bucket: stateBucket,
3183
+ recovery: refusalRecovery,
3184
+ guard: crossPrefixGuard,
3185
+ backend: preflightStateBackend
3186
+ });
2911
3187
  let recreateTargets;
2912
3188
  if (options.recreateViaCcApi?.length || options.recreateViaSdkProvider?.length) {
2913
3189
  const stateForRecreateCheck = await stackStateBackend.getState(stackInfo.stackName, stackRegion);
@@ -2987,7 +3263,10 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
2987
3263
  refusalRecovery,
2988
3264
  ...assetRedirect && { assetRedirect },
2989
3265
  ...eventRecorder && { eventRecorder },
2990
- ...migrationGate && { onCurrentStateLoaded: migrationGate },
3266
+ onCurrentStateLoaded: composeStateLoadedGates(crossPrefix.firstDeployGate, migrationGate),
3267
+ ...crossPrefix.onFirstDeployLeftNoRecord && { onFirstDeployLeftNoRecord: crossPrefix.onFirstDeployLeftNoRecord },
3268
+ onDestructivePlan: crossPrefix.onDestructivePlan,
3269
+ crossPrefixHolder: crossPrefix.crossPrefixHolder,
2991
3270
  ...options.pinCcApi?.length && { pinCcApi: {
2992
3271
  stackName: stackInfo.stackName,
2993
3272
  logicalIds: new Set(options.pinCcApi)
@@ -3038,10 +3317,15 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3038
3317
  logger.info(` Updated: ${updatedTotal > 0 ? yellow(updatedTotal) : gray(updatedTotal)}`);
3039
3318
  logger.info(` Deleted: ${deployResult.deleted > 0 ? red(deployResult.deleted) : gray(deployResult.deleted)}`);
3040
3319
  if (deployResult.deleteSkipped > 0) logger.info(` Skipped (not deleted): ${yellow(deployResult.deleteSkipped)}`);
3320
+ const crossPrefixKept = deployResult.crossPrefixKept ?? 0;
3321
+ if (crossPrefixKept > 0) logger.info(` Kept (replacement refused: another state prefix records the stack, or the check could not run): ${yellow(crossPrefixKept)}`);
3041
3322
  if (ownUpdatePartial > 0) logger.info(safeMsg` of which left an orphaned predecessor: ${yellow(ownUpdatePartial)}`);
3042
3323
  if (nestedUpdatePartial > 0) logger.info(safeMsg` Left an orphaned predecessor in a nested stack: ${yellow(nestedUpdatePartial)}`);
3043
- const stackUnaddressed = deployResult.deleteSkipped + deployResult.updatePartial;
3044
- if (!options.dryRun) totalUnaddressed += stackUnaddressed;
3324
+ const stackUnaddressed = deployResult.deleteSkipped + deployResult.updatePartial + crossPrefixKept;
3325
+ if (!options.dryRun) {
3326
+ totalUnaddressed += stackUnaddressed;
3327
+ totalCrossPrefixKept += crossPrefixKept;
3328
+ }
3045
3329
  logger.info(` Unchanged: ${gray(deployResult.unchanged)}`);
3046
3330
  logger.info(` Duration: ${cyan((deployResult.durationMs / 1e3).toFixed(2) + "s")}`);
3047
3331
  if (deployResult.attributeFallbackCount > 0) logger.warn(`${deployResult.attributeFallbackCount} attribute resolution(s) fell back to the physical ID (potentially wrong values); re-run with --strict-getatt to fail on these`);
@@ -3057,7 +3341,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3057
3341
  created: deployResult.created,
3058
3342
  updated: updatedTotal,
3059
3343
  deleted: deployResult.deleted,
3060
- ...deployResult.deleteSkipped + deployResult.updatePartial > 0 && { skipped: deployResult.deleteSkipped + deployResult.updatePartial }
3344
+ ...stackUnaddressed > 0 && { skipped: stackUnaddressed }
3061
3345
  }, deployResult.durationMs);
3062
3346
  } catch (deployError) {
3063
3347
  if (deployError instanceof DeployCancelledError) {
@@ -3102,11 +3386,12 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3102
3386
  if (!outcome.ok) throw outcome.error;
3103
3387
  }
3104
3388
  });
3105
- if (totalUnaddressed > 0 && !options.allowUnaddressed) throw new PartialFailureError(`Deploy left ${totalUnaddressed} resource(s) unaddressed, so they may still exist in AWS. The two cases differ in what happens next: a DELETE the provider could not issue KEEPS its state record, so the next 'cdkd deploy' re-attempts it, while a replacement's surviving predecessor is NOT tracked and will never be retried — delete it by hand. The per-stack summaries above give the breakdown, and each resource's own warning names its cause and remedy. ` + (cancelledStacks > 0 ? `Note ${cancelledStacks} stack(s) were also cancelled and never deployed, so the template is not fully applied beyond the resources named above. ` : "") + `Pass --allow-unaddressed to exit 0 instead.`);
3389
+ if (totalUnaddressed > 0 && !options.allowUnaddressed) throw new PartialFailureError(`Deploy left ${totalUnaddressed} resource(s) unaddressed, so they may still exist in AWS. The two cases differ in what happens next: a DELETE the provider could not issue KEEPS its state record, so the next 'cdkd deploy' re-attempts it, while a replacement's surviving predecessor is NOT tracked and will never be retried — delete it by hand. ` + (totalCrossPrefixKept > 0 ? "A replacement kept because another state prefix records the stack, or the check could not run, keeps its old resource and applies no new value — resolve the pair, or let the check run, and re-deploy. " : "") + "The per-stack summaries above give the breakdown, and each resource's own warning names its cause and remedy. " + (cancelledStacks > 0 ? `Note ${cancelledStacks} stack(s) were also cancelled and never deployed, so the template is not fully applied beyond the resources named above. ` : "") + `Pass --allow-unaddressed to exit 0 instead.`);
3106
3390
  } finally {
3107
3391
  unforwardSigterm();
3108
3392
  process.removeListener("SIGINT", topLevelSigintHandler);
3109
3393
  awsClients.destroy();
3394
+ preflightBackendForCleanup?.destroyClient();
3110
3395
  }
3111
3396
  }
3112
3397
  function createDeployCommand() {
@@ -10744,19 +11029,40 @@ async function acquireStackLock(opts) {
10744
11029
  get interrupted() {
10745
11030
  return interrupted;
10746
11031
  },
10747
- async release({ failureMessage, beforeRelease }) {
11032
+ async release({ failureMessage, beforeRelease, holdUntil }) {
10748
11033
  if (released) return;
10749
11034
  released = true;
10750
- try {
10751
- await beforeRelease?.();
11035
+ const releaseNow = async () => {
10752
11036
  try {
10753
11037
  await lockManager.releaseLock(stackName, region);
10754
11038
  lockHeld = false;
10755
11039
  } catch (releaseErr) {
10756
11040
  getLogger().warn(safeMsg`${failureMessage}: ${describeAwsFailure(releaseErr).detail}`);
10757
11041
  }
11042
+ };
11043
+ let deferred = false;
11044
+ try {
11045
+ await beforeRelease?.();
11046
+ if (holdUntil !== void 0) {
11047
+ process.removeListener("SIGINT", sigintHandler);
11048
+ let forced = false;
11049
+ const removeDeferred = prependPostCleanupSigintListener(() => {
11050
+ if (!interrupted) {
11051
+ interrupted = true;
11052
+ return;
11053
+ }
11054
+ if (forced || !lockHeld) return;
11055
+ forced = true;
11056
+ lockManager.releaseLock(stackName, region).catch(() => {});
11057
+ process.stderr.write(`\nForce-quit (post-destroy cleanup): stack lock may not be released.${forceQuitRecoveryClause(stackName, region, recovery)}\n`);
11058
+ });
11059
+ holdUntil.defer(holdUntil.work.then(() => void 0, () => void 0).then(releaseNow).finally(removeDeferred));
11060
+ deferred = true;
11061
+ return;
11062
+ }
11063
+ await releaseNow();
10758
11064
  } finally {
10759
- process.removeListener("SIGINT", sigintHandler);
11065
+ if (!deferred) process.removeListener("SIGINT", sigintHandler);
10760
11066
  }
10761
11067
  }
10762
11068
  };
@@ -10864,6 +11170,16 @@ function countProtectedJournaledOrphans(orphans, region) {
10864
11170
  }
10865
11171
  return count;
10866
11172
  }
11173
+ async function releaseRegistryMarkerAfterDestroy(ctx, stackName, region, logger) {
11174
+ if (ctx.crossPrefixCheck === void 0) return;
11175
+ try {
11176
+ const known = await ctx.crossPrefixCheck.cache.knownMarker?.(stackName, region);
11177
+ const released = await ctx.stateBackend.releaseRegistryMarker(stackName, region, known);
11178
+ logger.debug(safeMsg`Stack registry marker: ${released}`);
11179
+ } catch (error) {
11180
+ logger.warn(safeMsg`Could not delete the stack registry marker of ${displayStackName(stackName)} ` + safeMsg`(${describeAwsFailure(error).summary}). It names this state prefix, which no longer ` + `records the stack, so a deploy under another prefix treats it as stale.`);
11181
+ }
11182
+ }
10867
11183
  async function runDestroyForStack(stackName, state, ctx) {
10868
11184
  const providerClasses = await loadProviderClasses();
10869
11185
  const logger = getLogger();
@@ -10875,11 +11191,16 @@ async function runDestroyForStack(stackName, state, ctx) {
10875
11191
  retainedCount: 0,
10876
11192
  skippedCount: 0,
10877
11193
  guardIndeterminateCount: 0,
11194
+ journaledOrphanSkips: 0,
11195
+ stateDeleted: false,
10878
11196
  errorCount: 0,
10879
11197
  interrupted: false
10880
11198
  };
11199
+ const retainedForReadoption = [];
11200
+ let retainedEarlier;
10881
11201
  const guardIndeterminateTargets = /* @__PURE__ */ new Set();
10882
11202
  const regionForState = state.region ?? ctx.baseRegion;
11203
+ const crossPrefixScan = ctx.crossPrefixCheck?.cache.full(stackName, regionForState);
10883
11204
  const refusalRecovery = {
10884
11205
  profile: ctx.profile,
10885
11206
  stateBucket: ctx.stateBucket,
@@ -10902,6 +11223,15 @@ async function runDestroyForStack(stackName, state, ctx) {
10902
11223
  const resourceCount = Object.keys(state.resources).length;
10903
11224
  const orphanCount = (state.orphans ?? []).length;
10904
11225
  refuseMalformedOutputsForDestroy(state, stackName, regionForState, refusalRecovery);
11226
+ if (crossPrefixScan) applyCrossPrefixScan(await crossPrefixScan, {
11227
+ stackName,
11228
+ region: regionForState,
11229
+ bucket: ctx.stateBucket,
11230
+ recovery: {
11231
+ profile: ctx.profile,
11232
+ stateBucket: ctx.stateBucket
11233
+ }
11234
+ }, "destroy", (message) => logger.warn(message), (message) => logger.info(message));
10905
11235
  if (resourceCount === 0 && orphanCount === 0 && journaledOrphans.count === 0) {
10906
11236
  logger.info(`Stack ${displayStackName(stackName)} has no resources, cleaning up state...`);
10907
11237
  const emptyLock = await acquireStackLock({
@@ -10924,7 +11254,9 @@ async function runDestroyForStack(stackName, state, ctx) {
10924
11254
  if (recheckJournaled > 0) throw new Error(`Stack ${displayStackName(stackName)} (${displaySafe(regionForState, { asciiOnly: true })}) was empty when this run started but its rollback journal now records ${recheckJournaled} resource(s) a failed deploy created — another cdkd process wrote to it. Re-run the destroy to act on the current state.`);
10925
11255
  if (!(!recheck || recheckResources === 0 && recheckOrphans === 0)) throw new Error(`Stack ${displayStackName(stackName)} (${displaySafe(regionForState, { asciiOnly: true })}) was empty when this run started but now has ${recheckResources} resource(s) and ${recheckOrphans} rollback-orphaned resource(s) — another cdkd process wrote to it. Re-run the destroy to act on the current state.`);
10926
11256
  await ctx.stateBackend.deleteState(stackName, regionForState);
11257
+ result.stateDeleted = true;
10927
11258
  logger.info(`${green("✓")} State deleted`);
11259
+ await Promise.all([recordRetainedForReadoption(ctx.stateBackend, stackName, regionForState, [], logger), releaseRegistryMarkerAfterDestroy(ctx, stackName, regionForState, logger)]);
10928
11260
  } finally {
10929
11261
  await emptyLock.release({ failureMessage: "Failed to release lock after empty-state cleanup" });
10930
11262
  }
@@ -11012,11 +11344,13 @@ async function runDestroyForStack(stackName, state, ctx) {
11012
11344
  }
11013
11345
  const renderer = getLiveRenderer();
11014
11346
  let statePreserved = false;
11347
+ let heldTail;
11348
+ let stackFinished = false;
11015
11349
  let journaledOrphanFailures = 0;
11016
- let journaledOrphanSkips = 0;
11017
11350
  const lock = await acquireStackLock({
11018
11351
  ...stackLockBase,
11019
11352
  onFirstSignal: () => {
11353
+ if (stackFinished) return;
11020
11354
  renderer.printAbove(() => {
11021
11355
  process.stderr.write("\nInterrupted — finishing in-flight deletes, then flushing state and releasing the lock (press Ctrl-C again to force-quit)...\n");
11022
11356
  });
@@ -11114,7 +11448,7 @@ async function runDestroyForStack(stackName, state, ctx) {
11114
11448
  result.errorCount += orphanOutcome.failures;
11115
11449
  journaledOrphanFailures = orphanOutcome.failures;
11116
11450
  result.skippedCount += orphanOutcome.skipped;
11117
- journaledOrphanSkips = orphanOutcome.skipped;
11451
+ result.journaledOrphanSkips += orphanOutcome.skipped;
11118
11452
  if (orphanOutcome.handled.length > 0) try {
11119
11453
  await ctx.stateBackend.dropRollbackJournalFailedOperations(stackName, regionForState, (op, segment) => isHandledOrphan(orphanOutcome.handled, segment, op));
11120
11454
  } catch (stripError) {
@@ -11190,6 +11524,17 @@ async function runDestroyForStack(stackName, state, ctx) {
11190
11524
  if (shouldRetainResource(resource.deletionPolicy)) {
11191
11525
  logger.info(` ⊘ ${displaySafe(logicalId)} (${displaySafe(resource.resourceType)}) retained — DeletionPolicy: ${displaySafe(resource.deletionPolicy)}`);
11192
11526
  result.retainedCount++;
11527
+ if (keptForReadoption(resource)) {
11528
+ retainedForReadoption.push({
11529
+ logicalId,
11530
+ resourceType: resource.resourceType,
11531
+ physicalId: resource.physicalId
11532
+ });
11533
+ if (retainedEarlier === void 0) {
11534
+ retainedEarlier = Promise.resolve().then(() => ctx.stateBackend.loadRetainedRecord(stackName, regionForState));
11535
+ retainedEarlier.catch(() => void 0);
11536
+ }
11537
+ }
11193
11538
  recordDestroyEvent(ctx.eventRecorder, {
11194
11539
  eventType: "RESOURCE_RETAINED",
11195
11540
  stackName,
@@ -11247,6 +11592,7 @@ async function runDestroyForStack(stackName, state, ctx) {
11247
11592
  const slowTypeMinTimeoutMs = slowCcOperationTimeoutMs(resource.resourceType, "DELETE");
11248
11593
  const timeoutMs = ctx.resourceTimeoutByType?.[resource.resourceType] ?? Math.max(providerMinTimeoutMs, slowTypeMinTimeoutMs, globalTimeoutMs);
11249
11594
  let deleteResult;
11595
+ let childLeftInAws = 0;
11250
11596
  const secretPrincipalOptIn = secretPrincipalRegions !== void 0 ? {
11251
11597
  importedProducerRegions: secretPrincipalRegions,
11252
11598
  retryMemo: { detached: /* @__PURE__ */ new Set() }
@@ -11256,7 +11602,7 @@ async function runDestroyForStack(stackName, state, ctx) {
11256
11602
  const noEchoDeleteValues = readsNoEchoDeleteValues(resource.resourceType) ? await ctx.noEchoReresolver?.valuesFor(logicalId, resource) : void 0;
11257
11603
  let lastDeleteError;
11258
11604
  for (let attempt = 0; attempt <= maxAttempts; attempt++) try {
11259
- deleteResult = await runDeleteAttempt(attempt >= maxAttempts, () => withStackRecords(destroyStackRecordsView(state.resources), () => provider.delete(logicalId, resource.physicalId, resource.resourceType, resource.properties, {
11605
+ const { value: outcome, unaddressed } = await runDeleteAttempt(attempt >= maxAttempts, () => collectNestedChildUnaddressed(() => withStackRecords(destroyStackRecordsView(state.resources), () => provider.delete(logicalId, resource.physicalId, resource.resourceType, resource.properties, {
11260
11606
  ...state.region !== void 0 && { expectedRegion: state.region },
11261
11607
  ...ctx.removeProtection === true && { removeProtection: true },
11262
11608
  ...finalSnapshotIdentifier !== void 0 && { finalSnapshotIdentifier },
@@ -11268,7 +11614,9 @@ async function runDestroyForStack(stackName, state, ctx) {
11268
11614
  ...noEchoDeleteValues !== void 0 && { noEchoDeleteValues },
11269
11615
  ...ctx.noEchoReresolver !== void 0 && { noEchoReresolver: ctx.noEchoReresolver },
11270
11616
  ...ctx.stackDestroy === true && { stackDestroy: true }
11271
- }))) ?? void 0;
11617
+ }))));
11618
+ deleteResult = outcome ?? void 0;
11619
+ childLeftInAws = unaddressed?.deleteSkipped ?? 0;
11272
11620
  lastDeleteError = null;
11273
11621
  break;
11274
11622
  } catch (retryError) {
@@ -11326,7 +11674,11 @@ async function runDestroyForStack(stackName, state, ctx) {
11326
11674
  });
11327
11675
  return;
11328
11676
  }
11329
- logger.info(` ${formatResourceLine("deleted", logicalId, resource.resourceType)}`);
11677
+ const leftInAws = childLeftInAws > 0 ? deleteLeftInPlace(deleteResult) ?? `${childLeftInAws} resource(s) a failed deploy created were left in AWS` : void 0;
11678
+ const deletedLine = leftInAws !== void 0 ? formatResourceLine("skipped", logicalId, resource.resourceType, `deleted (${leftInAws})`) : formatResourceLine("deleted", logicalId, resource.resourceType);
11679
+ logger.info(` ${deletedLine}`);
11680
+ result.skippedCount += childLeftInAws;
11681
+ result.journaledOrphanSkips += childLeftInAws;
11330
11682
  result.deletedCount++;
11331
11683
  recordDestroyEvent(ctx.eventRecorder, {
11332
11684
  eventType: "RESOURCE_SUCCEEDED",
@@ -11338,6 +11690,16 @@ async function runDestroyForStack(stackName, state, ctx) {
11338
11690
  ...resource.physicalId && { physicalId: resource.physicalId },
11339
11691
  durationMs: Date.now() - resourceStartedAt
11340
11692
  });
11693
+ if (leftInAws !== void 0) recordDestroyEvent(ctx.eventRecorder, {
11694
+ eventType: "RESOURCE_SKIPPED",
11695
+ stackName,
11696
+ operation: "DELETE",
11697
+ logicalId,
11698
+ resourceType: resource.resourceType,
11699
+ ...resource.provisionedBy && { provisionedBy: resource.provisionedBy },
11700
+ reason: leftInAws,
11701
+ durationMs: Date.now() - resourceStartedAt
11702
+ });
11341
11703
  delete remainingResources[logicalId];
11342
11704
  persistStateAfterDelete(logicalId);
11343
11705
  } catch (error) {
@@ -11396,12 +11758,22 @@ async function runDestroyForStack(stackName, state, ctx) {
11396
11758
  }
11397
11759
  result.interrupted = lock.interrupted;
11398
11760
  await saveChain;
11399
- const preserveState = result.errorCount > 0 || result.interrupted || result.skippedCount > journaledOrphanSkips;
11761
+ const preserveState = result.errorCount > 0 || result.interrupted || result.skippedCount > result.journaledOrphanSkips;
11400
11762
  statePreserved = preserveState;
11401
11763
  if (!preserveState) {
11402
11764
  await ctx.stateBackend.deleteState(stackName, regionForState);
11765
+ result.stateDeleted = true;
11403
11766
  logger.debug("State deleted");
11404
- if (ctx.exportIndexStore) await ctx.exportIndexStore.removeStack(stackName, regionForState);
11767
+ const writeKept = () => recordRetainedForReadoption(ctx.stateBackend, stackName, regionForState, retainedForReadoption, logger, retainedEarlier);
11768
+ const releaseMarker = () => releaseRegistryMarkerAfterDestroy(ctx, stackName, regionForState, logger);
11769
+ if (ctx.deferRegistryTail !== void 0) {
11770
+ heldTail = writeKept().then(releaseMarker);
11771
+ await ctx.exportIndexStore?.removeStack(stackName, regionForState);
11772
+ } else await Promise.all([
11773
+ writeKept(),
11774
+ releaseMarker(),
11775
+ ctx.exportIndexStore?.removeStack(stackName, regionForState)
11776
+ ]);
11405
11777
  } else {
11406
11778
  try {
11407
11779
  await ctx.stateBackend.saveState(stackName, regionForState, buildDestroySnapshot());
@@ -11410,7 +11782,7 @@ async function runDestroyForStack(stackName, state, ctx) {
11410
11782
  }
11411
11783
  if (result.interrupted) logger.warn(`Destroy interrupted — ${Object.keys(remainingResources).length} resource(s) not deleted. State preserved.`);
11412
11784
  else if (result.errorCount > 0) logger.warn(`${result.errorCount} resource(s) failed to delete` + (journaledOrphanFailures > 0 ? ` (${journaledOrphanFailures} of them recorded only in the rollback journal)` : "") + `. State preserved.`);
11413
- else logger.warn(`${result.skippedCount} resource(s) skipped — cdkd did not confirm they were deleted, so they may still exist in AWS. State preserved (the records are kept so the resources stay traceable).`);
11785
+ else logger.warn(`${result.skippedCount - result.journaledOrphanSkips} resource(s) skipped — cdkd did not confirm they were deleted, so they may still exist in AWS. State preserved (the records are kept so the resources stay traceable).`);
11414
11786
  }
11415
11787
  const retainedSuffix = result.retainedCount > 0 ? `, ${result.retainedCount} retained` : "";
11416
11788
  const skippedSuffix = result.skippedCount > 0 ? `, ${yellow(result.skippedCount)} skipped` : "";
@@ -11424,9 +11796,9 @@ async function runDestroyForStack(stackName, state, ctx) {
11424
11796
  const durablePointer = ctx.eventRecorder === void 0 ? "This summary is the only record: this run wrote no deployment events, because it destroyed a nested-stack child, which threads no event recorder." : "The RESOURCE_GUARD_INDETERMINATE entries name the check and the reason and survive the run." + withheldTargetClause(eventsCommand, "stack", "cdkd events", "This stack's name") + `\nRead them with: ${eventsCommand.command}`;
11425
11797
  logger.warn(`\n${yellow("⚠")} ${result.guardIndeterminateCount} pre-flight safety check(s) could NOT be completed during this destroy and cdkd proceeded anyway: ${[...guardIndeterminateTargets].map((t) => plainOrDescribed(t, "logical id")).join(", ")}. A check can be suppressed by DENYING the permission it needs, so treat this as unconfirmed rather than benign. ${durablePointer}`);
11426
11798
  }
11427
- if (journaledOrphanSkips > 0) logger.warn(safeMsg`${journaledOrphanSkips} resource(s) a failed deploy created were left in AWS (each named in a ` + "warning above, which says what to do with it). This stack no longer records them.");
11799
+ if (result.journaledOrphanSkips > 0) logger.warn(safeMsg`${result.journaledOrphanSkips} resource(s) a failed deploy created were left in AWS (each named in a ` + "warning above, which says what to do with it). This stack no longer records them.");
11428
11800
  if (!preserveState) {
11429
- const leftInAws = journaledOrphanSkips > 0;
11801
+ const leftInAws = result.journaledOrphanSkips > 0;
11430
11802
  logger.info(`\n${leftInAws ? yellow("⚠") : green("✓")} ${bold(`Stack ${plainOrDescribed(stackName, "stack name")} ${leftInAws ? "destroyed, with resources left in AWS" : "destroyed"}`)} (${green(result.deletedCount)} deleted${retainedSuffix}${leftInAws ? skippedSuffix : ""}${guardSuffix}, ${result.errorCount} errors)`);
11431
11803
  } else if (result.interrupted && result.errorCount === 0) logger.warn(`\n${yellow("⚠")} ${bold(`Stack ${plainOrDescribed(stackName, "stack name")} destroy interrupted`)} (${green(result.deletedCount)} deleted${retainedSuffix}${skippedSuffix}${guardSuffix}, ${result.errorCount} errors). State preserved — re-run 'cdkd destroy' / 'cdkd state destroy' to finish.`);
11432
11804
  else if (result.errorCount === 0) {
@@ -11448,6 +11820,10 @@ async function runDestroyForStack(stackName, state, ctx) {
11448
11820
  try {
11449
11821
  await lock.release({
11450
11822
  failureMessage: `Failed to release lock for stack ${displayStackName(stackName)}`,
11823
+ ...heldTail !== void 0 && ctx.deferRegistryTail !== void 0 && { holdUntil: {
11824
+ work: heldTail,
11825
+ defer: ctx.deferRegistryTail
11826
+ } },
11451
11827
  beforeRelease: async () => {
11452
11828
  try {
11453
11829
  renderer.stop();
@@ -11458,6 +11834,7 @@ async function runDestroyForStack(stackName, state, ctx) {
11458
11834
  logger.debug("Releasing lock...");
11459
11835
  }
11460
11836
  });
11837
+ stackFinished = true;
11461
11838
  } finally {
11462
11839
  restoreBaseRegionAndClients();
11463
11840
  }
@@ -11486,6 +11863,15 @@ async function scanActiveConsumers(producerStack, producerRegion, ctx) {
11486
11863
  }))).filter((r) => r !== null).flat();
11487
11864
  }
11488
11865
 
11866
+ //#endregion
11867
+ //#region src/cli/commands/destroy-skip-message.ts
11868
+ function skippedDestroyMessage(totalSkipped, totalOrphanSkips, rerunCommand) {
11869
+ const recordSkips = totalSkipped - totalOrphanSkips;
11870
+ const orphanSentence = `${totalOrphanSkips} resource(s) a failed deploy created were left in AWS, and no state records them any more. The warning naming each says what to do with it.`;
11871
+ if (recordSkips <= 0) return `Destroy finished, but ${orphanSentence}`;
11872
+ return `Destroy skipped ${recordSkips} entr${recordSkips === 1 ? "y" : "ies"} whose delete cdkd did not confirm, 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). The per-resource 'skipped (...)' lines and their warnings name each cause and whether repairing the record in state.json helps: where it does, repair it and re-run '${rerunCommand}'; otherwise (for example a custom-resource Delete handler that reported FAILED), delete the resources by hand and drop the records with 'cdkd state orphan <stack> --stack-region <region>'.` + (totalOrphanSkips > 0 ? ` Separately, ${orphanSentence}` : "");
11873
+ }
11874
+
11489
11875
  //#endregion
11490
11876
  //#region src/cli/commands/destroy.ts
11491
11877
  function orderConsumersBeforeProducers(stackNames, consumerToProducers) {
@@ -11508,6 +11894,10 @@ function orderConsumersBeforeProducers(stackNames, consumerToProducers) {
11508
11894
  }
11509
11895
  return ordered;
11510
11896
  }
11897
+ function plannedDestroyRegion(refs, synthRegion, cliRegion) {
11898
+ if (refs.length === 1) return refs[0]?.region || cliRegion;
11899
+ if (refs.length > 1 && synthRegion && refs.some((r) => r.region === synthRegion)) return synthRegion;
11900
+ }
11511
11901
  async function purgeEventsAfterDestroy(reader, stackName, region, opts, logger) {
11512
11902
  if (opts.purgeEvents !== true || opts.runResult !== "SUCCEEDED" || opts.interrupted) return null;
11513
11903
  try {
@@ -11565,6 +11955,9 @@ async function destroyCommand(stackArgs, options) {
11565
11955
  interruptWatch.dispose();
11566
11956
  throw error;
11567
11957
  }
11958
+ let stateBackendForCleanup;
11959
+ const deferredTails = [];
11960
+ let deferRegistryTail;
11568
11961
  try {
11569
11962
  const stateConfig = {
11570
11963
  bucket: stateBucket,
@@ -11574,6 +11967,7 @@ async function destroyCommand(stackArgs, options) {
11574
11967
  ...options.region && { region: options.region },
11575
11968
  ...options.profile && { profile: options.profile }
11576
11969
  });
11970
+ stateBackendForCleanup = stateBackend;
11577
11971
  await stateBackend.verifyBucketExists();
11578
11972
  const lockManager = new LockManager(awsClients.s3, stateConfig);
11579
11973
  const exportIndexStore = new ExportIndexStore(awsClients.s3, stateBucket, options.statePrefix, region, stateBackend, { profile: options.profile });
@@ -11650,6 +12044,7 @@ async function destroyCommand(stackArgs, options) {
11650
12044
  } else throw new CdkdError("Could not determine which stacks belong to this app. Specify stack names explicitly, or ensure --app / cdk.json is configured.", "DESTROY_NO_STACK_SELECTED", synthError);
11651
12045
  let totalErrors = 0;
11652
12046
  let totalSkipped = 0;
12047
+ let totalOrphanSkips = 0;
11653
12048
  let interrupted = false;
11654
12049
  const runInterrupted = () => interrupted || interruptWatch.interrupted();
11655
12050
  let stoppedEarly = false;
@@ -11716,6 +12111,14 @@ async function destroyCommand(stackArgs, options) {
11716
12111
  arr.push(ref);
11717
12112
  stateRefsByName.set(ref.stackName, arr);
11718
12113
  }
12114
+ const crossPrefixCheck = { cache: new CrossPrefixGuard(stateBackend) };
12115
+ if (stackNames.length > 1) deferRegistryTail = (released) => deferredTails.push(released);
12116
+ for (const name of stackNames) {
12117
+ const synth = appStacks.find((s) => s.stackName === name);
12118
+ if (synth?.terminationProtection === true && !options.removeProtection) continue;
12119
+ const planned = plannedDestroyRegion(stateRefsByName.get(name) ?? [], synth?.region, region);
12120
+ if (planned !== void 0) crossPrefixCheck.cache.full(name, planned, "prestart");
12121
+ }
11719
12122
  for (const [stackIndex, stackName] of stackNames.entries()) {
11720
12123
  logger.info(`\nPreparing to destroy stack: ${displaySafe(stackName)}`);
11721
12124
  const refs = stateRefsByName.get(stackName) ?? [];
@@ -11733,15 +12136,12 @@ async function destroyCommand(stackArgs, options) {
11733
12136
  continue;
11734
12137
  }
11735
12138
  }
12139
+ const plannedRegion = plannedDestroyRegion(refs, synthRegion, region);
11736
12140
  let stackTargetRegion;
11737
12141
  if (refs.length === 0) {
11738
12142
  logger.warn(`No state found for stack ${displaySafe(stackName)}, skipping`);
11739
12143
  continue;
11740
- } else if (refs.length === 1) {
11741
- const onlyRegion = refs[0]?.region;
11742
- if (!onlyRegion) stackTargetRegion = region;
11743
- else stackTargetRegion = onlyRegion;
11744
- } else if (synthRegion && refs.some((r) => r.region === synthRegion)) stackTargetRegion = synthRegion;
12144
+ } else if (plannedRegion !== void 0) stackTargetRegion = plannedRegion;
11745
12145
  else {
11746
12146
  const regions = refs.map((r) => r.region === void 0 ? "(legacy)" : plainOrDescribed(r.region, "region")).join(", ");
11747
12147
  const orphanOneClause = withheldAccountClause(accountRecovery, "the command below prints").trimEnd();
@@ -11819,6 +12219,8 @@ async function destroyCommand(stackArgs, options) {
11819
12219
  skipFinalSnapshot: options.skipFinalSnapshot === true,
11820
12220
  resolveSecretDerivedPrincipals: {},
11821
12221
  stackDestroy: true,
12222
+ crossPrefixCheck,
12223
+ ...deferRegistryTail !== void 0 && { deferRegistryTail },
11822
12224
  exportIndexStore,
11823
12225
  ...TemplateNoEchoReresolver.usable(synthStack?.template) && (synthStack.region === void 0 || synthStack.region === stackTargetRegion) && { noEchoReresolver: new TemplateNoEchoReresolver({
11824
12226
  template: synthStack.template,
@@ -11835,6 +12237,7 @@ async function destroyCommand(stackArgs, options) {
11835
12237
  })));
11836
12238
  totalErrors += result.errorCount;
11837
12239
  totalSkipped += result.skippedCount;
12240
+ totalOrphanSkips += result.journaledOrphanSkips;
11838
12241
  stackInterrupted = result.interrupted;
11839
12242
  stackCancelled = result.cancelled === true;
11840
12243
  if (result.interrupted) interrupted = true;
@@ -11870,11 +12273,13 @@ async function destroyCommand(stackArgs, options) {
11870
12273
  }
11871
12274
  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> --stack-region <region>' removes the stack's state in that region (every resource's record) without deleting AWS resources.`);
11872
12275
  if (interrupted || interruptWatch.interrupted() && stoppedEarly) throw new PartialFailureError(`Destroy interrupted by Ctrl-C. State preserved — re-run 'cdkd destroy' to finish.`);
11873
- if (totalSkipped > 0) throw new PartialFailureError(`Destroy skipped ${totalSkipped} entr${totalSkipped === 1 ? "y" : "ies"} whose delete cdkd did not confirm, 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). The per-resource 'skipped (...)' lines and their warnings name each cause and whether repairing the record in state.json helps: where it does, repair it and re-run 'cdkd destroy'; otherwise (for example a custom-resource Delete handler that reported FAILED), delete the resources by hand and drop the records with 'cdkd state orphan <stack> --stack-region <region>'.`);
12276
+ if (totalSkipped > 0) throw new PartialFailureError(skippedDestroyMessage(totalSkipped, totalOrphanSkips, "cdkd destroy"));
11874
12277
  } finally {
12278
+ await Promise.allSettled(deferredTails);
11875
12279
  unforwardSigterm();
11876
12280
  interruptWatch.dispose();
11877
12281
  awsClients.destroy();
12282
+ stateBackendForCleanup?.destroyClient();
11878
12283
  }
11879
12284
  }
11880
12285
  function createDestroyCommand() {
@@ -14022,7 +14427,7 @@ async function exportCommand(stackArg, options) {
14022
14427
  2. Re-run the phase 2 UPDATE manually with the full synth template:
14023
14428
  ${phase2RetryCommand(cfnStackName)}\n 3. Once phase 2 succeeds, clean up cdkd's stale state record.${orphan.note}\n Run: ${orphan.command}`);
14024
14429
  }
14025
- await stateBackend.deleteState(resolvedStackName, targetRegion);
14430
+ await removeExportedStackRecord(stateBackend, resolvedStackName, targetRegion, logger);
14026
14431
  logger.info(`cdkd state for ${quotedOrNotShown(resolvedStackName)} (${quotedRegion(targetRegion)}) removed. Manage the stack with 'cdk deploy' or 'aws cloudformation' from here on.`);
14027
14432
  printNextSteps({
14028
14433
  cfnStackName,
@@ -15626,6 +16031,11 @@ async function buildResolvedParametersPerStack(args) {
15626
16031
  intrinsicSkippedByCdkdName
15627
16032
  };
15628
16033
  }
16034
+ async function removeExportedStackRecord(stateBackend, stackName, region, logger) {
16035
+ await stateBackend.deleteState(stackName, region);
16036
+ await recordRetainedForReadoption(stateBackend, stackName, region, [], logger);
16037
+ await releaseRegistryMarkerQuietly(stateBackend, stackName, region, logger);
16038
+ }
15629
16039
  async function runPerStackImportLoop(args) {
15630
16040
  const logger = getLogger();
15631
16041
  const { rootStackName, rootRegion, rootStackInfoNestedTemplates, rootTemplateFormat, tree, rootTemplate, cfnStackNameOverrides, rootParameters, deps, options } = args;
@@ -15903,7 +16313,7 @@ async function runPerStackImportLoop(args) {
15903
16313
  }
15904
16314
  const stateDeletionFailures = [];
15905
16315
  for (const node of leafFirst) try {
15906
- await deps.stateBackend.deleteState(node.stackName, node.region);
16316
+ await removeExportedStackRecord(deps.stateBackend, node.stackName, node.region, logger);
15907
16317
  logger.info(`cdkd state for ${quotedOrNotShown(node.stackName)} (${quotedRegion(node.region)}) removed.`);
15908
16318
  } catch (err) {
15909
16319
  stateDeletionFailures.push({
@@ -16129,6 +16539,10 @@ const STATE_READ_REASONS = {
16129
16539
  "read-failed": STATE_READ_FAILED_REASON,
16130
16540
  "resources-malformed": "resources is not a JSON object; run `cdkd state show --json` to see the record"
16131
16541
  };
16542
+ function stateDestroyTargets(refs, stackRegion) {
16543
+ if (stackRegion) return refs.filter((r) => r.region === stackRegion || !r.region);
16544
+ return refs.length === 1 ? [...refs] : void 0;
16545
+ }
16132
16546
  function resourceCountOrNull(resources) {
16133
16547
  if (resources === void 0 || resources === null) return 0;
16134
16548
  if (typeof resources !== "object" || Array.isArray(resources)) return null;
@@ -16249,7 +16663,10 @@ async function setupStateBackend(options) {
16249
16663
  bucket,
16250
16664
  prefix,
16251
16665
  exportIndexStore: new ExportIndexStore(awsClients.s3, bucket, prefix, region, stateBackend, { profile: options.profile }),
16252
- dispose: () => awsClients.destroy()
16666
+ dispose: () => {
16667
+ awsClients.destroy();
16668
+ stateBackend.destroyClient();
16669
+ }
16253
16670
  };
16254
16671
  }
16255
16672
  function renderRecovery(options, setup) {
@@ -16690,6 +17107,43 @@ function createStateShowCommand() {
16690
17107
  cmd.addOption(deprecatedRegionOption);
16691
17108
  return cmd;
16692
17109
  }
17110
+ async function clearRetainedQuietly(backend, stackName, region, logger) {
17111
+ try {
17112
+ await backend.saveRetainedResources(stackName, region, []);
17113
+ return true;
17114
+ } catch (error) {
17115
+ logger.warn(safeMsg`Could not empty the kept-resource record of ${displayStackName(stackName)} ` + safeMsg`(${describeAwsFailure(error).summary}): a later deploy here may still take a kept ` + `resource back. Re-run 'cdkd state orphan' once it can write.`);
17116
+ return false;
17117
+ }
17118
+ }
17119
+ async function clearRetainedWithoutRecord(backend, stackName, stackRegion, logger) {
17120
+ if (stackName.includes("/")) return {
17121
+ cleared: [],
17122
+ attempted: 0
17123
+ };
17124
+ const base = `${backend.prefix}/${stackName}/`;
17125
+ let regions;
17126
+ try {
17127
+ const keys = (await backend.listRawKeys(base)).map((key) => key.slice(base.length).split("/")).filter((parts) => parts.length >= 2 && parts[0] !== "");
17128
+ const recorded = new Set(keys.filter((parts) => parts.length === 2 && parts[1] === "state.json").map((parts) => parts[0]));
17129
+ regions = [...new Set(keys.map((parts) => parts[0]).filter((region) => stackRegion === void 0 || region === stackRegion).filter((region) => !recorded.has(region)))];
17130
+ } catch (error) {
17131
+ logger.warn(safeMsg`Could not look for a kept-resource record of ${displayStackName(stackName)} ` + safeMsg`(${describeAwsFailure(error).summary}).`);
17132
+ return {
17133
+ cleared: [],
17134
+ attempted: 0
17135
+ };
17136
+ }
17137
+ const cleared = [];
17138
+ for (const region of regions) {
17139
+ if (await clearRetainedQuietly(backend, stackName, region, logger)) cleared.push(region);
17140
+ await releaseRegistryMarkerQuietly(backend, stackName, region, logger);
17141
+ }
17142
+ return {
17143
+ cleared,
17144
+ attempted: regions.length
17145
+ };
17146
+ }
16693
17147
  async function stateOrphanCommand(stackArgs, options) {
16694
17148
  const logger = getLogger();
16695
17149
  if (options.verbose) logger.setLevel("debug");
@@ -16705,6 +17159,12 @@ async function stateOrphanCommand(stackArgs, options) {
16705
17159
  for (const stackName of stackArgs) {
16706
17160
  const stackRefs = refs.filter((r) => r.stackName === stackName);
16707
17161
  if (stackRefs.length === 0) {
17162
+ const { cleared, attempted } = await clearRetainedWithoutRecord(setup.stateBackend, stackName, options.stackRegion, logger);
17163
+ if (attempted > 0 && cleared.length === 0) continue;
17164
+ if (cleared.length > 0) {
17165
+ logger.info(safeMsg`Cleared the kept-resource record of ${plainOrDescribed(stackName, "stack name")} ` + safeMsg`(${cleared.map((r) => displaySafe(r, { asciiOnly: true })).join(", ")}): ` + `a later deploy here no longer takes a kept resource back.`);
17166
+ continue;
17167
+ }
16708
17168
  logger.info(safeMsg`No state found for stack: ${plainOrDescribed(stackName, "stack name")}, skipping` + (isPasteableIdent(stackName) ? "" : safeMsg`. ${STATE_LIST_POINTER}`));
16709
17169
  continue;
16710
17170
  }
@@ -16748,10 +17208,13 @@ async function stateOrphanCommand(stackArgs, options) {
16748
17208
  await warnOnLiveForeignLock(setup.lockManager, stackName, target.region, logger);
16749
17209
  await setup.stateBackend.deleteState(stackName, target.region);
16750
17210
  await setup.lockManager.forceReleaseLock(stackName, target.region);
17211
+ await clearRetainedQuietly(setup.stateBackend, stackName, target.region, logger);
17212
+ await releaseRegistryMarkerQuietly(setup.stateBackend, stackName, target.region, logger);
16751
17213
  } else {
16752
17214
  await warnOnLiveForeignLock(setup.lockManager, stackName, void 0, logger);
16753
17215
  await setup.stateBackend.deleteLegacyState(stackName);
16754
17216
  await setup.lockManager.forceReleaseLock(stackName, void 0);
17217
+ await clearRetainedWithoutRecord(setup.stateBackend, stackName, void 0, logger);
16755
17218
  }
16756
17219
  logger.info(safeMsg`✓ Removed state for stack: ${describedStackRef(target)}` + ((options.yes || options.force) && refIsDescribed(target) ? safeMsg`. ${STATE_LIST_POINTER}` : ""));
16757
17220
  }
@@ -16899,6 +17362,8 @@ async function stateDestroyCommand(stackArgs, options) {
16899
17362
  interruptWatch.dispose();
16900
17363
  throw error;
16901
17364
  }
17365
+ const deferredTails = [];
17366
+ let deferRegistryTail;
16902
17367
  try {
16903
17368
  const stateRefs = await setup.stateBackend.listStacks();
16904
17369
  const knownStackNames = new Set(stateRefs.map((r) => r.stackName));
@@ -16908,6 +17373,7 @@ async function stateDestroyCommand(stackArgs, options) {
16908
17373
  logger.info(safeMsg`Found ${stackNames.length} stack(s) to destroy: ${stackNames.map(listedStackName).join(", ")}`);
16909
17374
  let totalErrors = 0;
16910
17375
  let totalSkipped = 0;
17376
+ let totalOrphanSkips = 0;
16911
17377
  let interrupted = false;
16912
17378
  const runInterrupted = () => interrupted || interruptWatch.interrupted();
16913
17379
  let stoppedEarly = false;
@@ -16916,16 +17382,23 @@ async function stateDestroyCommand(stackArgs, options) {
16916
17382
  if (!options.stackRegion) return laterRefs.length > 0;
16917
17383
  return laterRefs.some((r) => r.region === options.stackRegion || !r.region);
16918
17384
  });
17385
+ const crossPrefixCheck = { cache: new CrossPrefixGuard(setup.stateBackend) };
17386
+ if (stackNames.length > 1) deferRegistryTail = (released) => deferredTails.push(released);
17387
+ for (const name of stackNames) {
17388
+ const refs = stateRefs.filter((r) => r.stackName === name);
17389
+ for (const ref of stateDestroyTargets(refs, options.stackRegion) ?? []) crossPrefixCheck.cache.full(name, ref.region ?? setup.region, "prestart");
17390
+ }
16919
17391
  for (const [stackIndex, stackName] of stackNames.entries()) {
16920
17392
  const refs = stateRefs.filter((r) => r.stackName === stackName);
16921
17393
  let targets;
17394
+ const planned = stateDestroyTargets(refs, options.stackRegion);
16922
17395
  if (options.stackRegion) {
16923
- targets = refs.filter((r) => r.region === options.stackRegion || !r.region);
17396
+ targets = planned ?? [];
16924
17397
  if (targets.length === 0) {
16925
17398
  logger.warn(safeMsg`Skipping ${plainOrDescribed(stackName, "stack name")} (no state record matches ` + safeMsg`--stack-region ${displayIdent(options.stackRegion)})`);
16926
17399
  continue;
16927
17400
  }
16928
- } else if (refs.length === 1) targets = refs;
17401
+ } else if (planned !== void 0) targets = planned;
16929
17402
  else throw multipleRegionsError(stackName, refs, `Use --stack-region ${commandHole("region")} to pick one.`);
16930
17403
  for (const [refIndex, ref] of targets.entries()) {
16931
17404
  logger.info(safeMsg`\nPreparing to destroy stack: ${formatStackRefSafe(ref)}`);
@@ -16982,6 +17455,8 @@ async function stateDestroyCommand(stackArgs, options) {
16982
17455
  skipFinalSnapshot: options.skipFinalSnapshot === true,
16983
17456
  resolveSecretDerivedPrincipals: {},
16984
17457
  stackDestroy: true,
17458
+ crossPrefixCheck,
17459
+ ...deferRegistryTail !== void 0 && { deferRegistryTail },
16985
17460
  exportIndexStore: setup.exportIndexStore,
16986
17461
  ...options.allowUnsupportedTypes?.length && { allowUnsupportedTypes: options.allowUnsupportedTypes },
16987
17462
  ...options.resourceWarnAfter?.globalMs !== void 0 && { resourceWarnAfterMs: options.resourceWarnAfter.globalMs },
@@ -17007,6 +17482,7 @@ async function stateDestroyCommand(stackArgs, options) {
17007
17482
  }
17008
17483
  totalErrors += result.errorCount;
17009
17484
  totalSkipped += result.skippedCount;
17485
+ totalOrphanSkips += result.journaledOrphanSkips;
17010
17486
  if (result.interrupted) interrupted = true;
17011
17487
  if (runInterrupted()) {
17012
17488
  if (refIndex < targets.length - 1) stoppedEarly = true;
@@ -17020,8 +17496,9 @@ async function stateDestroyCommand(stackArgs, options) {
17020
17496
  }
17021
17497
  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> --stack-region <region>' removes the stack's state in that region (every resource's record) without deleting AWS resources.`);
17022
17498
  if (interrupted || interruptWatch.interrupted() && stoppedEarly) throw new PartialFailureError(`Destroy interrupted by Ctrl-C. State preserved — re-run 'cdkd state destroy' to finish.`);
17023
- if (totalSkipped > 0) throw new PartialFailureError(`Destroy skipped ${totalSkipped} entr${totalSkipped === 1 ? "y" : "ies"} whose delete cdkd did not confirm, 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). The per-resource 'skipped (...)' lines and their warnings name each cause and whether repairing the record in state.json helps: where it does, repair it and re-run 'cdkd state destroy'; otherwise (for example a custom-resource Delete handler that reported FAILED), delete the resources by hand and drop the records with 'cdkd state orphan <stack> --stack-region <region>'.`);
17499
+ if (totalSkipped > 0) throw new PartialFailureError(skippedDestroyMessage(totalSkipped, totalOrphanSkips, "cdkd state destroy"));
17024
17500
  } finally {
17501
+ await Promise.allSettled(deferredTails);
17025
17502
  unforwardSigterm();
17026
17503
  interruptWatch.dispose();
17027
17504
  setup.dispose();
@@ -17684,6 +18161,7 @@ async function rollbackCommand(stackArg, options) {
17684
18161
  });
17685
18162
  return;
17686
18163
  }
18164
+ const crossPrefixScan = new CrossPrefixGuard(setup.stateBackend).full(stackName, region);
17687
18165
  stackAwsClients = new AwsClients({
17688
18166
  region,
17689
18167
  ...options.profile && { profile: options.profile }
@@ -17718,6 +18196,15 @@ async function rollbackCommand(stackArg, options) {
17718
18196
  segments: journal.segments.filter((s) => s.reason !== NESTED_PENDING_PARENT_REASON)
17719
18197
  };
17720
18198
  if (!journal || journal.segments.length === 0 && orphanedPending === 0) throw new Error(`Nothing to roll back for ${plainOrDescribed(stackName, "stack name")} (${plainOrDescribed(region, "region")}). Run 'cdkd deploy' to (re)deploy, or 'cdkd destroy' to clean up.`);
18199
+ applyCrossPrefixScan(await crossPrefixScan, {
18200
+ stackName,
18201
+ region,
18202
+ bucket: setup.bucket,
18203
+ recovery: {
18204
+ profile: options.profile,
18205
+ stateBucket: setup.bucket
18206
+ }
18207
+ }, "rollback", (message) => logger.warn(message), (message) => logger.info(message));
17721
18208
  if (!stateData) throw new Error(`Rollback journal exists for ${safeStack(stackName)} (${safe(region)}) but its state.json is missing (keys: ${safe(setup.prefix)}/${safeStack(stackName)}/${safe(region)}/state.json and .../rollback-journal.json). State appears corrupted — inspect the bucket manually.`);
17722
18209
  demoteSupersededOrphans(journal.segments, Array.isArray(stateData.state.orphans) ? stateData.state.orphans : []);
17723
18210
  if (!options.revertFailed) for (const segment of journal.segments) {
@@ -17961,6 +18448,8 @@ async function rollbackCommand(stackArg, options) {
17961
18448
  const survivingOrphans = orphansAfterRollback(baseState, mintedOrphans).orphans ?? [];
17962
18449
  if (journal.segments.length === 0 && oldestInitialDeploy && Object.keys(stateResources).length === 0 && survivingOrphans.length === 0) {
17963
18450
  await setup.stateBackend.deleteState(stackName, region);
18451
+ await recordRetainedForReadoption(setup.stateBackend, stackName, region, [], logger);
18452
+ await releaseRegistryMarkerQuietly(setup.stateBackend, stackName, region, logger);
17964
18453
  logger.info(`State for ${stackRegionShown(stackName, region)} removed (stack fully rolled back).`);
17965
18454
  }
17966
18455
  if (declinedDivergentRewrite) throw new PartialFailureError(`Rollback stopped: ${declinedDivergentReason}.` + (totalFailures > 0 ? ` ${totalFailures} operation(s) also failed.` : "") + " Journal preserved (this segment, any older ones, and their failed operations) — re-run the rollback once the record's region field matches its key.");
@@ -19108,8 +19597,20 @@ async function forceUnlockCommand(stackArgs, options) {
19108
19597
  const where = r ? `${displayStackName(stackName)} (${displayIdent(r)})` : `${displayStackName(stackName)} (legacy lock key)`;
19109
19598
  logger.info(`Force-unlocking stack: ${where}`);
19110
19599
  try {
19111
- await lockManager.forceReleaseLock(stackName, r);
19600
+ let ledgerError;
19601
+ let recorded = false;
19602
+ await lockManager.forceReleaseLock(stackName, r, async (horizon) => {
19603
+ if (r === void 0) return;
19604
+ const ledger = ledgerForStack(stateBackend, stackName, r);
19605
+ for (let attempt = 0; attempt < 2 && !recorded; attempt++) try {
19606
+ await ledger.noteAbandoned(horizon);
19607
+ recorded = true;
19608
+ } catch (error) {
19609
+ ledgerError = error;
19610
+ }
19611
+ });
19112
19612
  logger.info(`✓ Lock released for stack: ${where}`);
19613
+ if (!recorded && ledgerError !== void 0) logger.warn(safeMsg`Lock released, but the create-token ledger of ${where} could not record when the ` + safeMsg`abandoned run stopped: ${describeAwsFailure(ledgerError).summary}. ` + "A later deploy may take back a resource of those names that another deployment creates.");
19113
19614
  } catch (error) {
19114
19615
  const message = describeAwsFailure(error).detail;
19115
19616
  if (message.includes("No lock found") || message.includes("NoSuchKey")) logger.info(`No lock found for stack: ${where}`);
@@ -19219,6 +19720,20 @@ var ObservedBaselineRefusals = class extends Set {
19219
19720
  unverifiableParameter = /* @__PURE__ */ new Set();
19220
19721
  hadDeployedParameterSource = false;
19221
19722
  };
19723
+ async function claimRegistryMarkerAfterImport(backend, stackName, region, logger) {
19724
+ const answer = await new CrossPrefixGuard(backend).full(stackName, region);
19725
+ const regionShown = displaySafe(region, { asciiOnly: true });
19726
+ switch (answer.kind) {
19727
+ case "clear": return;
19728
+ case "found":
19729
+ logger.warn(safeMsg`The state bucket also records ${displayStackName(stackName)} (${regionShown}) under another state prefix ` + safeMsg`(${answer.prefixes.map((p) => displayIdent(p)).join(", ")}). One stack name per ` + "account and region is supported: drop one of the records with 'cdkd state orphan' before deploying or destroying either.");
19730
+ return;
19731
+ case "in-progress":
19732
+ logger.warn(safeMsg`A deploy of ${displayStackName(stackName)} (${regionShown}) holds a lock under another state prefix ` + safeMsg`(${displayIdent(answer.prefix)}). One stack name per account and region is ` + `supported: keep one of the two before deploying or destroying either.`);
19733
+ return;
19734
+ default: logger.warn(safeMsg`Could not record ${displayStackName(stackName)} (${regionShown}) in the state bucket's stack registry` + (answer.kind === "denied" || answer.kind === "failed" ? safeMsg` (${describeAwsFailure(answer.error).summary})` : "") + `. Its next guarded command records it.`);
19735
+ }
19736
+ }
19222
19737
  async function importCommand(stackArg, options) {
19223
19738
  const providerClasses = await loadProviderClasses();
19224
19739
  const logger = getLogger();
@@ -19439,6 +19954,7 @@ async function importCommand(stackArg, options) {
19439
19954
  await recordImportOnRollbackJournal(stateBackend, stackInfo.stackName, targetRegion, importedRows.map((r) => r.logicalId), stackState.resources, logger);
19440
19955
  await stateBackend.saveState(stackInfo.stackName, targetRegion, stackState, saveOptions);
19441
19956
  logger.info(`✓ State written: ${stackInfo.stackName} (${targetRegion})`);
19957
+ await claimRegistryMarkerAfterImport(stateBackend, stackInfo.stackName, targetRegion, logger);
19442
19958
  logger.info(` ${importedRows.length} resource(s) imported. Run 'cdkd diff' to see how the imported state lines up with the template.`);
19443
19959
  if (migrationCfnStackName && migrationTree && accountIdForNestedSynth) await importNestedStackChildrenRecursive({
19444
19960
  lockRecovery,
@@ -27766,4 +28282,4 @@ function collectVerbFlags(program) {
27766
28282
 
27767
28283
  //#endregion
27768
28284
  export { canonicalizeIpProtocolValue as a, buildProgram, resolveSecretDerivedPrincipals as i, runDestroyForStack as n, resolvedResourceTimeoutMs as o, isResolvableSecretPrincipalList as r, canonicalizeIpv4Cidr as t };
27769
- //# sourceMappingURL=program-v_QNBjtZ.js.map
28285
+ //# sourceMappingURL=program-CIxuz2zX.js.map