@go-to-k/cdkd 0.302.4 → 0.303.0

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 (43) hide show
  1. package/dist/{asg-provider-CGqU-6sj.js → asg-provider-CJIPV0St.js} +11 -8
  2. package/dist/asg-provider-CJIPV0St.js.map +1 -0
  3. package/dist/{aws-client-defaults-DBXBcg0J.js → aws-client-defaults-BX9Y_fKp.js} +11 -2
  4. package/dist/{aws-client-defaults-DBXBcg0J.js.map → aws-client-defaults-BX9Y_fKp.js.map} +1 -1
  5. package/dist/{aws-clients-B_CEQGE1.js → aws-clients-BJ7dmM_T.js} +3 -8
  6. package/dist/aws-clients-BJ7dmM_T.js.map +1 -0
  7. package/dist/{aws-failure-text-e_ddrDDo.js → aws-failure-text-w5_iao51.js} +3 -2
  8. package/dist/{aws-failure-text-e_ddrDDo.js.map → aws-failure-text-w5_iao51.js.map} +1 -1
  9. package/dist/cli.js +3 -2
  10. package/dist/cli.js.map +1 -1
  11. package/dist/{db-instance-modify-retry-D0e5Ryd_.js → db-instance-modify-retry-f79-MmD9.js} +3 -3
  12. package/dist/{db-instance-modify-retry-D0e5Ryd_.js.map → db-instance-modify-retry-f79-MmD9.js.map} +1 -1
  13. package/dist/{deploy-engine-CN2w5GAK.js → deploy-engine-Bx98Q92J.js} +5433 -303
  14. package/dist/deploy-engine-Bx98Q92J.js.map +1 -0
  15. package/dist/{iam-policy-targets-DBAi38y_.js → iam-policy-targets-NZn9Idzv.js} +67 -11
  16. package/dist/iam-policy-targets-NZn9Idzv.js.map +1 -0
  17. package/dist/{iam-role-provider-Cv7YzUwO.js → iam-role-provider-C8WZMqgE.js} +13 -8
  18. package/dist/iam-role-provider-C8WZMqgE.js.map +1 -0
  19. package/dist/index.d.ts +33 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +5 -5
  22. package/dist/{neptune-provider-BcENx6g8.js → neptune-provider-NdOn7ncA.js} +39 -26
  23. package/dist/neptune-provider-NdOn7ncA.js.map +1 -0
  24. package/dist/{program-CAibYjpk.js → program-TEYrbsKm.js} +1938 -233
  25. package/dist/program-TEYrbsKm.js.map +1 -0
  26. package/dist/{provider-classes-B52ogqNj.js → provider-classes-g1s3vsUl.js} +1409 -527
  27. package/dist/provider-classes-g1s3vsUl.js.map +1 -0
  28. package/dist/{rds-provider-C6jYh60H.js → rds-provider-BlAiy5-P.js} +20 -13
  29. package/dist/rds-provider-BlAiy5-P.js.map +1 -0
  30. package/dist/{version-CNK8U3qj.js → version-BhQymxXT.js} +2 -2
  31. package/dist/{version-CNK8U3qj.js.map → version-BhQymxXT.js.map} +1 -1
  32. package/package.json +1 -1
  33. package/dist/asg-provider-CGqU-6sj.js.map +0 -1
  34. package/dist/aws-clients-B_CEQGE1.js.map +0 -1
  35. package/dist/deploy-engine-CN2w5GAK.js.map +0 -1
  36. package/dist/iam-policy-targets-DBAi38y_.js.map +0 -1
  37. package/dist/iam-role-provider-Cv7YzUwO.js.map +0 -1
  38. package/dist/neptune-provider-BcENx6g8.js.map +0 -1
  39. package/dist/program-CAibYjpk.js.map +0 -1
  40. package/dist/provider-classes-B52ogqNj.js.map +0 -1
  41. package/dist/rds-provider-C6jYh60H.js.map +0 -1
  42. package/dist/secret-redaction-BHWS-PZK.js +0 -3937
  43. package/dist/secret-redaction-BHWS-PZK.js.map +0 -1
@@ -1,10 +1,9 @@
1
- import { a as runWithStackAwsClients, i as resetAwsClients, o as setAwsClients, t as AwsClients } from "./aws-clients-B_CEQGE1.js";
2
- import { $ as stringifyJsonPayload, A as isNameGeneration, B as SECRET_REF_MAX_CODE_POINTS, C as generateResourceName, F as withSkipPrefix, G as displayAwsMessage, H as UNRENDERABLE, I as withStackScope, J as displayStackName, K as displayIdent, Q as safeMsg, V as STACK_REF_MAX_CODE_POINTS, W as cutMarker, Y as isPasteableIdent, Z as plainIdentOr, _ as PATTERN_B_RESOURCE_TYPES, a as safeStringify, b as derivesPatternBName, c as isStdoutReservedForPayload, d as runStackBuffered, et as terminalSafe, g as PATTERN_B_NAME_PROPERTIES, h as PATTERN_B_NAME_OPTIONS, l as reserveStdoutForPayload, m as getLiveRenderer, n as describeAwsFailure, q as displaySafe, s as getLogger, tt as truncateCodePoints, x as explicitNamePropertyFor, z as SAFE_MSG_ALTERED_CHAR } from "./aws-failure-text-e_ddrDDo.js";
3
- import { $t as producerRecordKey, Bt as buildForceUnlockCommand, Cn as ProvisioningError, D as VALUE_NOT_SHOWN, Dn as StackTerminationProtectionError, E as assertRegionMatch, En as StackHasActiveImportsError, Fn as TIMEOUT_FLAG_RESOURCE_TYPE, Gn as quotedOrDescribed, Gt as formatLockOwner, Hn as pasteableCommand, Ht as forceQuitRecoveryClause, Jn as withheldTargetClause, Jt as CUSTOM_RESOURCE_RESPONSE_PREFIX, Kn as shellBoundedDisplay, Ln as SHELL_ACTIVE_WHY, Nn as normalizeAwsError, On as StateError, P as remedyLogicalId, Pn as withErrorHandling, Qt as producerCoordinateKey, Sn as PartialFailureError, Sr as markNonRetryable, T as RESOURCE_NOT_FOUND, Tn as ResourceUpdateNotSupportedError, Ut as formatLockExpiry, Vn as isInertUnquoted, Vt as buildLockContentionMessage, Wn as plainOrDescribed, Wt as formatLockOperation, Xn as setPasteableVerbFlags, Xt as injectiveKey, Y as runDeleteAttempt, Yn as setPasteableRunFlags, Yt as DEFAULT_STATE_PREFIX, _n as LocalStartServiceError, _r as isTransientServerError, an as credentialFingerprint, at as beginCommandInterruptScope, bn as MalformedProducerRecordRefusalError, br as isMarkedNonRetryable, cn as CdkdError, cr as stripControlChars, ct as isInterruptedWaitError, en as setPasteableAwsProfile, fn as DeployCancelledError, gn as LocalInvokeBuildError$1, gr as isRetryableTransientError, gt as logicalIdShown, hn as IntrinsicResolutionRefusalError, in as clientDefaultsFor, kn as SynthesisError, lr as stripForDisplay, mn as DynamicReferenceRegionAmbiguousError, n as RESOLVED_PREVIOUS_PRINCIPAL_KEYS, nn as ambientClientDefaults, on as AccountIdUnavailableError, ot as endCommandInterruptScope, pr as isAmbiguousOutcomeError, qn as shellQuote, rn as ambientCredentialConfig, s as readRecordedPrincipals, sr as escapeRegExp, st as interruptWatchListenerCount, t as IAM_PRINCIPAL_NAME, tn as withPasteableAwsProfile, tt as isAwsCliLiteral, un as CrossAccountSecretRefusalError, vr as retryClassificationText, vt as resourceTypeShown, wn as ResourceTimeoutError, xn as NestedStackChildDirectDestroyError, xr as isThrottlingError, zn as commandHole, zt as UNREPRODUCIBLE_LOCK_CLAUSE } from "./iam-policy-targets-DBAi38y_.js";
4
- import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, l as runInStackAwsScope, n as awsClientDefaults, r as getAssumedRoleCredentials, u as formatAuthority } from "./aws-client-defaults-DBXBcg0J.js";
5
- import { $ as pendingRequestCount, $a as refuseMalformedOutputs, $c as absoluteAssemblyPathEscape, $i as isImpossibleEmptyStoredAttribute, $n as noEchoExactEchoLeavesOf, $o as prefetchCreateOnlyPropertyPaths, $r as applyCustomResourceResponseExpiration, $s as buildDockerImage, $t as nameGenerationCarriedFrom, A as inheritedProvenanceForChildDiff, Aa as malformedLocalResourceEntriesWarning, Ac as resolveUseCdkBootstrapAssets, Ai as refuseUnreadableCdkCrossAccountRefs, Ao as NO_CC_HANDLERS_REASON, As as orphansAfterRollback, At as replayRollback, B as conditionFingerprint, Ba as malformedResourceEntriesWarning, Bc as decodeListingKey, Bi as sendableAssumeRoleCommand, Bn as yellow, Bs as loadPublishableAssetManifest, Bt as replacementNeverSwapped, Ca as hasReadableResources, Cc as loadCdkJson, Cn as bindingSkippedOutputs, Co as unreadableOrphanRecords, Cr as ledgerForStack, Cs as exportNamesCarriedFrom, Ct as sameJournaledOrphans, D as IMPLICIT_DELETE_DEPENDENCIES, Da as malformedExportNamesWarning, Dc as resolveSkipPrefix, Dn as constructPathOf, Dr as DeploymentEventsReader, Ds as importableOutputKeys, Ea as malformedDriftResourcePropertiesWarning, Ec as resolveCaptureObservedState, En as maskingRetryLogger, Eo as findActionableSilentDrops, Es as hasUnverifiableParameterRefusal, F as findNestedTemplateTreeDefect, Fa as malformedOrphansRefusalMessage, Fc as CFN_TEMPLATE_URL_LIMIT, Fi as applyRoleArnIfSet, Fn as bold, Fo as isStatefulRecreateTargetForReplace, Fs as isSensitiveAttributeName, Ft as isReplacementOrphan, G as withResourceDeadline, Ga as previewableOrphanRecords, Gc as AssemblyReader, Gi as classifyRecordedSecretRegion, Gn as removeSuperseded, Gr as wouldReturnToSdkProvider, Gs as ensureAssetStorage, H as parentSuppliedValues, Ha as malformedResourcesWarning, Hc as PARTITION_TABLE, Hi as applyCallerIdentityCredentials, Hn as deleteSupersededEntry, Hr as ProviderRegistry, Hs as AssetModeResolver, Ht as seedsDeleteFirstGuard, I as isAbsoluteAssetPath, Ia as malformedOrphansWarning, Ic as MIGRATE_TMP_PREFIX, Ii as assertFlagRoleArn, In as cyan, Io as isStatefulRecreateTargetSync, Is as stringifyValue, It as planFailedOps, J as keptWholeReasonText, Ja as refuseMalformedOrphanRecords, Jc as defineOwnKey, Ji as regionLessSecretName, Jn as supersededHolderOf, Jr as readsNoEchoDeleteValues, Js as parseBootstrapMarker, K as diffSecurity, Ka as refuseDivergentRecordRegionForDestroy, Kc as StageLoadError, Ki as classifyReplaySecretRegion, Kn as supersededAfterRollback, Ks as getBootstrapMarkerKey, Kt as inheritProducerRegions, L as listNestedTemplateRows, La as malformedOutputsRefusalMessage, Lc as findLargeInlineResources, Li as assertSendableRoleArn, Ln as gray, Lo as renderStatefulReason, Ls as WorkGraph, Lt as planRollback, M as findServiceTokenRefusals, Ma as malformedOrphanRecordsRefusalMessage, Mc as warnDeprecatedNoPrefixCliFlag, Mo as findReplacedReadersOfRecreateTargets, Ms as shouldRetainResource, Mt as recordAfterRollbackUpdate, N as serviceTokenBlockingReason, Na as malformedOrphanRecordsWarning, Nc as ssmResolvedValueType, Ni as recordedOutputReferenceRegions, Nn as withStackRecords, No as shownType, Ns as stackInstanceIdCarriedFrom, Nt as demoteSupersededOrphans, O as computeImplicitDeleteEdges, Oa as malformedExportSourceWarning, Oc as resolveStateBucketWithDefault, Oi as resolveDynamicReferences, On as findDestructiveChanges, Oo as unwrittenCreateOnlyReplacement, Or as DeploymentEventsStore, Os as importableOutputs, P as childTemplateLoader, Pa as malformedOrphanRowsKeptWarning, Pc as CFN_TEMPLATE_BODY_LIMIT, Pi as recordedReferenceRegions, Po as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ps as AssetPublisher, Pt as isJournaledOrphan, Q as planOrphanAdoption, Qa as refuseMalformedOrphansForOrphan, Qc as ownValue, Qi as getAccountInfo, Qn as noEchoComparisonForTemplate, Qr as CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID, Qs as buildDenyExternalAccessPolicy, Qt as updatePartialReason, R as renderNestedTemplateTreeDefect, Ra as malformedOutputsWarning, Rc as uploadCfnTemplate, Ri as explicitRoleArnOrThrow, Rn as green, Rs as buildAssetRedirectMap, Rt as recheckFailedPlan, Sa as hasReadableOutputs, Sc as getLegacyStateBucketName, Sn as isExportAliasCollision, So as unpreviewableOrphanRecords, Ss as describeRegionValueKind, St as makeForeignHolderScan, Ta as isReadableResourceEntry, Tc as resolveAutoAssetStorage, Tn as DEFAULT_RESOURCE_WARN_AFTER_MS, To as withheldAccountClause, Tr as withCreateTokenLedger, Ts as hasReasonlessBaselineRefusal, U as readRecordedConditionVerdicts, Ua as malformedScrubResourceEntriesRefusalMessage, Uc as canonicalizeRegion, Ui as callerEnvCredentials, Un as holdsSupersededResources, Ur as ccBrokenReason, Us as BOOTSTRAP_MARKER_PREFIX, Ut as orphanNeedsIdentity, V as conditionInputsFrom, Va as malformedResourcePropertiesWarning, Vc as expectedOwnerParam, Vi as AWS_CREDENTIAL_ENV_KEYS, Vn as addSuperseded, Vr as CC_BROKEN_REASON, Vs as rewriteTemplateAssetReferences, Vt as resolveReplacementOldType, Wa as malformedStateRefusalMessage, Wc as derivePartitionAndUrlSuffix, Wi as envCredentialsAreAssumedRole, Wn as isSupersededResourceRecord, Wr as isCustomResource, Ws as assertAssetBucketRegion, Wt as findNestedStackTypeChanges, X as makeCanonicalizePropertiesFn, Xa as refuseMalformedOrphans, Xc as hasPlainPrototype, Xi as isUnboundTemplateParameter, Xn as withoutSuperseded, Xs as validateAssetBucketName, Y as mergeNoChangeOutputs, Ya as refuseMalformedOrphanRecordsForDestroy, Yc as hasOwnKey, Yi as coerceParameterTypedValue, Yn as supersededResourcesOf, Yr as isCustomResourceType$1, Ys as readBootstrapMarkerBody, Z as makeSiblingClaimReader, Za as refuseMalformedOrphansForDestroy, Zc as nullPrototypeRecord, Zi as parameterTypeMayLoseSecretIdentity, Zn as noEchoAttributeNamesOf, Zr as withPrintingSecrets, Zs as validateContainerRepoName, Zt as updatePartialMessage, _a as UNREADABLE_RESOURCES_MAP_ROW, _c as AssetManifestLoader, _n as exportNameSecretExposure, _o as repairMalformedOrphansForReadOnly, _r as createPreDeleteFinalSnapshot, _s as isNotImplemented, _t as dropFailedCommands, a as isProtectionValueActive, aa as cfnRefValueFromPhysicalId, ac as finchSecretArgvRefusal, ai as UNSPECIFIED_SKIP_REASON, al as injectedAwsRegionValue, an as computeParameterTaint, ao as refuseMalformedResourceEntriesForImport, ar as namingSecretsWithRecordedNoEcho, at as displacedPhysicalIdShown, ba as displayLogicalId, bc as synthesisStatusMessage, bi as IntrinsicFunctionResolver, bn as collectDeclaredOutputNames, bo as repairMalformedResourcePropertiesForReadOnly, br as refusesFinalSnapshot, bs as splitImportedOps, bt as journaledOrphanLines, cc as isDockerClientEnvKey, ci as deleteSkipReason, cn as resourcesNamingDeclaredParameter, co as refuseMalformedResourcePropertiesForDestroy, cr as secretNamePrintingBags, cs as LockManager, ct as nestedChildStackName$1, dc as redactDockerArgvValues, dn as exportAliasCollisionScrubWarning, do as refuseMalformedResourcePropertiesForOrphan, dr as stateSecretNameNeedles, ds as rebuildClientForBucketRegion, dt as revertedNestedRowIds, ea as carriesDynamicReference, ec as resolveDockerContextDirectory, ei as customResourceResponseExpirationWarning, el as describeFileReadFailure, en as nameGenerationHighWaterOf, eo as refuseMalformedOutputsForDestroy, er as noEchoParameterNamesOf, es as templateResourceTypes, et as resolvePendingCloudControlRequests, fa as declaresNoEcho, fc as redactedCause, fn as secretBearing, fo as refuseMalformedResourcesForDeploy, fr as storedSecretNameNeedles, fs as CrossPrefixReadError, ft as withNestedRevertRun, ga as UNREADABLE_ORPHANS_CONTAINER_ROW, gc as warnFinchArgvExposure, gn as exportNameNoEchoParameters, go as repairMalformedOrphanRecordsForReadOnly, gr as ccRoutedFinalSnapshotError, gs as isAccessDenied, gt as deleteJournaledOrphans, ha as STATE_RESOURCES_MALFORMED, hc as runDockerStreaming, hn as carriedExportAliasExposure, ho as refuseMalformedState, hr as buildFinalSnapshotIdentifier, hs as crossPrefixDeniedWarning, ht as withNestedStackContext, i as PROTECTION_PROPERTY_BY_TYPE, ia as AWS_NO_VALUE, ic as dockerSpawnEnvWithSensitive, ii as RollbackInlinePolicyWriters, il as injectAwsRegion, in as retiredNameGenerationsLeaving, io as refuseMalformedResourceEntriesForDestroy, ir as maskEventTextWithBoundBags, it as displacedOpClause, j as deferredServiceTokenWarning, ja as malformedLocalResourcesWarning, jc as stateBucketExistenceConfirmed, ji as keepHeldTokenProvenance, jn as destroyStackRecordsView, jo as hasNoCloudControlHandlers, js as orphansCarriedFrom, jt as removeProtectionTypeList, k as crossStackOutputProvenanceSource, ka as malformedLocalOutputsWarning, kc as resolveStateBucketWithDefaultAndSource, ki as producerLookupOver, kn as formatDestructiveChange, kr as extractDeploymentEventError, ks as isReadableBag, kt as replayFailedOperations, la as withSharedDrainBudget, lc as isMalformedEnvKey, ln as WITHHELD_NAME_DISPLAY, lo as refuseMalformedResourcePropertiesForDrift, ls as isLockInfoExpired, lt as recordDisplacedSkips, ma as STATE_REGION_DIVERGED, mc as runDockerForeground, mn as secretSafeKeyDisplay, mo as refuseMalformedResourcesForExport, mr as PRE_DELETE_SNAPSHOT_TYPES, ms as applyCrossPrefixScan, mt as getCurrentNestedStackContext, n as recordedProtectionEvidence, na as isNamelessDynamicReferenceError, nc as describeDockerExecFailure, ni as slowCcOperationTimeoutMs, nl as renderAssemblyPathEscape, nn as retiredAfterRollback, no as refuseMalformedResourceEntries, nr as completedReplayEntries, ns as withRetry, nt as recordRetainedForReadoption, o as perType, oa as isStalePlaceholderArnAttribute, oc as formatDockerLoginError, oi as deleteIndeterminateGuards, on as namesAnyDeclaredParameter, oo as refuseMalformedResourceEntriesForImportSave, or as orphanRecordsPrintingBag, os as DagBuilder, ot as dropSettledNestedJournals, pa as JSON_LISTING_HOLE_VALUE, pc as redactedDockerCause, pn as secretBearingStateKeyWarning, po as refuseMalformedResourcesForDestroy, pr as ATOMIC_FINAL_SNAPSHOT_TYPES, ps as CrossPrefixScanCache, pt as collectNestedChildUnaddressed, q as isSecretBearingReferenceString, qc as processStackMessages, qi as producerRegionsFromState, qn as supersededHeldByOtherTypeWarning, qr as TemplateNoEchoReresolver, qs as isCrossRegionRedirect, r as recordedProtectionNote, ra as keepsSecretReferenceToken, rc as describeDockerFailure, rl as resolveAssemblyPath, rn as retiredNameGenerationsAfter, ro as refuseMalformedResourceEntriesForDeploy, rr as journaledOrphanPrintingBag, rt as NESTED_PENDING_PARENT_REASON, s as readProtection, sa as refStateLookupFromResource, sc as getDockerCmd, si as deleteLeftInPlace, sl as resolveBucketRegion, sn as reachableDivergentParameters, so as refuseMalformedResourceEntriesForOrphan, sr as secretNamePrintingBag, ss as TemplateParser, t as DeployEngine, ta as carriesFetchableDynamicReference, tc as describeDockerCapturedOutput, ti as CloudControlProvider, tl as displayAssemblyPath, tn as nameScopeOf, to as refuseMalformedResourceAttributesForOrphan, tr as createReadOnlyAttributeHealerFactory, ts as describeTypeWithThrottleRetry, tt as keptForRetainedRecord, ua as parameterInputsFor, uc as partitionSensitiveEnv, ui as isWaitAbandonedError, un as displayTextOrWithheld, uo as refuseMalformedResourcePropertiesForExport, ur as secretNamedRecordNeedles, us as S3StateBackend, va as accountArgs, vc as getDockerImageBySourceHash, vi as DiffCalculator, vn as isWholeDynamicReferenceValue, vo as repairMalformedOutputsForReadOnly, vr as effectiveDeletionPolicy, vs as stackInstanceIdOf, vt as dropFailedHint, wa as isReadableOrphanRecord, wc as resolveApp, wn as DEFAULT_RESOURCE_TIMEOUT_MS, wo as unreadableResourceEntries, ws as hasReadableExportSet, wt as formatResourceLine, xa as hasReadableOrphans, xc as getDefaultStateBucketName, xi as poisonRenderedSpellingsCollidingIn, xn as collectPublishedOutputNames, xo as repairMalformedResourcesForReadOnly, xr as unsupportedFinalSnapshotError, xs as acceptedCreateOnlyDropsOf, xt as loadJournaledOrphans, ya as deployRefusesOrphanRowsReason, yc as Synthesizer, yi as INTRINSIC_KEYS, yn as noEchoParameterValueSeed, yo as repairMalformedResourceEntriesForReadOnly, yr as isFinalSnapshotError, ys as withStackInstanceIdWithheld, yt as isHandledOrphan, z as templateIdentity, za as malformedRenderedContainersWarning, zc as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, zi as isIamRoleArn, zn as red, zs as createAssetRedirectResolver, zt as recordUnderIdIsNotOwn } from "./deploy-engine-CN2w5GAK.js";
6
- import { $ as recordLogOnlyParameterValue, Cn as WHOLE_DYNAMIC_REFERENCE_PATTERN, Ct as DYNAMIC_REFERENCE_TOKEN_SCAN, Dt as pathCrossesDottedKey, Et as isUncertifiedBaselineMaskPosition, F as redactForState, G as carryLogOnlyValues, It as recordNestedStackParameterExpressions, Jt as physicalNameCopiesOf, Ot as identityKeyFor, Q as printingCorpusOf, S as liveMatchesUnresolvedTokenFrame, Tn as isSingleDynamicReferenceToken, Tt as dynamicReferenceTokens, X as literalSplitDelimitersOf, Xt as recordPhysicalNameCopy, Y as hasMaskableValues, Z as logOnlyValueCount, _n as recordMaskOnlyValuesIn, a as maskReadbackAtCoordinates, at as errorCauseChain, b as valueAtCoordinate, bn as recordProvenPublicExpression, bt as withPhysicalNameCopies, ct as maskSecretsInText, d as noEchoOutputsComparison, g as readsNoEchoSource, gn as recordMaskOnlyValue, h as readbackPathFor, i as maskAtCoordinates, it as createSecretMasker, kt as inheritNestedStackParameterAssociations, l as noEchoCoordinatesOf, nn as carriesSecretMask, nt as shareLogOnlyValues, o as maskWholeValue, pn as provenPublicValue, q as createUnionSecretMasker, r as isMarkedCoordinate, rt as unionOfSecretBags, s as maskedLeafCoordinatesOf, st as maskSecretsInError, t as canonicalCoordinates, tn as splitGetAttStringForm, tt as recordLogOnlyValue, u as noEchoLeavesOf, v as recordedNoEchoValuesOf, vn as recordNoEchoAttributeValues, vt as scrubResourceRecord, xn as wholeStringLeavesOf, yn as recordNoEchoParameterFreshValue } from "./secret-redaction-BHWS-PZK.js";
7
- import { t as getCdkdVersion } from "./version-CNK8U3qj.js";
1
+ import { a as runWithStackAwsClients, i as resetAwsClients, o as setAwsClients, t as AwsClients } from "./aws-clients-BJ7dmM_T.js";
2
+ import { $ as stringifyJsonPayload, A as isNameGeneration, B as SECRET_REF_MAX_CODE_POINTS, C as generateResourceName, F as withSkipPrefix, G as displayAwsMessage, H as UNRENDERABLE, I as withStackScope, J as displayStackName, K as displayIdent, Q as safeMsg, U as asIsMessage, V as STACK_REF_MAX_CODE_POINTS, W as cutMarker, Y as isPasteableIdent, Z as plainIdentOr, _ as PATTERN_B_RESOURCE_TYPES, a as safeStringify, b as derivesPatternBName, c as isStdoutReservedForPayload, d as runStackBuffered, et as terminalSafe, g as PATTERN_B_NAME_PROPERTIES, h as PATTERN_B_NAME_OPTIONS, l as reserveStdoutForPayload, m as getLiveRenderer, n as describeAwsFailure, q as displaySafe, s as getLogger, tt as truncateCodePoints, x as explicitNamePropertyFor, z as SAFE_MSG_ALTERED_CHAR } from "./aws-failure-text-w5_iao51.js";
3
+ import { An as StateError, Cn as NestedStackChildDirectDestroyError, Cr as markNonRetryable, Dn as ResourceUpdateNotSupportedError, E as isMarkedNotGone, En as ResourceTimeoutError, Fn as normalizeAwsError, Gt as formatLockExpiry, Ht as buildForceUnlockCommand, I as remedyLogicalId, In as withErrorHandling, Jn as shellBoundedDisplay, Kn as plainOrDescribed, Kt as formatLockOperation, Ln as TIMEOUT_FLAG_RESOURCE_TYPE, Mn as formatError, O as assertRegionMatch, On as StackHasActiveImportsError, Qn as setPasteableVerbFlags, Qt as injectiveKey, Sn as MalformedProducerRecordRefusalError, Sr as isThrottlingError, T as RESOURCE_NOT_FOUND, Tn as ProvisioningError, Un as isInertUnquoted, Ut as buildLockContentionMessage, Vn as commandHole, Vt as UNREPRODUCIBLE_LOCK_CLAUSE, Wn as pasteableCommand, Wt as forceQuitRecoveryClause, Xn as withheldTargetClause, Xt as CUSTOM_RESOURCE_RESPONSE_PREFIX, Yn as shellQuote, Z as runDeleteAttempt, Zn as setPasteableRunFlags, Zt as DEFAULT_STATE_PREFIX, _n as IntrinsicResolutionRefusalError, _r as isRetryableTransientError, an as ambientCredentialConfig, bt as resourceTypeShown, cn as AccountIdUnavailableError, cr as escapeRegExp, ct as endCommandInterruptScope, en as producerCoordinateKey, fn as CrossAccountSecretRefusalError, gn as DynamicReferenceRegionAmbiguousError, in as ambientClientDefaults, jn as SynthesisError, k as VALUE_NOT_SHOWN, kn as StackTerminationProtectionError, lr as stripControlChars, lt as interruptWatchListenerCount, mn as DeployCancelledError, mr as isAmbiguousOutcomeError, n as RESOLVED_PREVIOUS_PRINCIPAL_KEYS, nn as setPasteableAwsProfile, on as clientDefaultsFor, qn as quotedOrDescribed, qt as formatLockOwner, rn as withPasteableAwsProfile, rt as isAwsCliLiteral, s as readRecordedPrincipals, sn as credentialFingerprint, st as beginCommandInterruptScope, t as IAM_PRINCIPAL_NAME, tn as producerRecordKey, un as CdkdError, ur as stripForDisplay, ut as isInterruptedWaitError, vn as LocalInvokeBuildError$1, vr as isTransientServerError, vt as logicalIdShown, wn as PartialFailureError, xr as isMarkedNonRetryable, yn as LocalStartServiceError, yr as retryClassificationText, zn as SHELL_ACTIVE_WHY } from "./iam-policy-targets-NZn9Idzv.js";
4
+ import { a as setAssumedRoleCredentials, d as formatAuthority, i as getPreAssumeEnvCredentials, n as awsClientDefaults, r as getAssumedRoleCredentials, u as runInStackAwsScope } from "./aws-client-defaults-BX9Y_fKp.js";
5
+ import { $ as pendingRequestCount, $a as malformedLocalResourcesWarning, $c as importableOutputKeys, $i as keepHeldTokenProvenance, $l as resolveApp, $n as destroyStackRecordsView, $o as hasNoCloudControlHandlers, $s as logOnlyValueCount, $t as seedsDeleteFirstGuard, A as inheritedProvenanceForChildDiff, Ac as recordProvenPublicExpression, Ai as deleteSkipReason, Al as describeDockerCapturedOutput, An as isWholeDynamicReferenceValue, Ao as refuseMalformedResourcePropertiesForDestroy, Ar as secretNamePrintingBags, As as canonicalCoordinates, At as readRefactorMarkerOnce, Au as ownValue, B as conditionFingerprint, Ba as accountArgs, Bc as applyCrossPrefixScan, Bi as DiffCalculator, Bl as redactDockerArgvValues, Bn as findDestructiveChanges, Bo as repairMalformedOutputsForReadOnly, Br as effectiveDeletionPolicy, Bs as readbackPathFor, Bt as replayFailedOperations, Ca as carriesFetchableDynamicReference, Cc as splitGetAttStringForm, Ci as CloudControlProvider, Cl as parseBootstrapMarker, Cn as exportAliasCollisionScrubWarning, Co as refuseMalformedResourceAttributesForOrphan, Cr as createReadOnlyAttributeHealerFactory, Cs as describeTypeWithThrottleRetry, Ct as sameJournaledOrphans, Cu as describeJsonParseFailure, D as IMPLICIT_DELETE_DEPENDENCIES, Da as cfnRefValueFromPhysicalId, Dc as recordMaskOnlyValuesIn, Di as UNSPECIFIED_SKIP_REASON, Dl as buildDenyExternalAccessPolicy, Dn as carriedExportAliasExposure, Do as refuseMalformedResourceEntriesForImport, Dr as namingSecretsWithRecordedNoEcho, Du as hasOwnKey, Ea as AWS_NO_VALUE, Ec as recordMaskOnlyValue, Ei as RollbackInlinePolicyWriters, El as validateContainerRepoName, En as secretSafeKeyDisplay, Eo as refuseMalformedResourceEntriesForDestroy, Er as maskEventTextWithBoundBags, Eu as defineOwnKey, F as findNestedTemplateTreeDefect, Fa as JSON_LISTING_HOLE_VALUE, Fc as isLockInfoExpired, Fl as formatDockerLoginError, Fn as bindingSkippedOutputs, Fo as refuseMalformedResourcesForDestroy, Fr as ATOMIC_FINAL_SNAPSHOT_TYPES, Fs as maskedLeafCoordinatesOf, Ft as updateRefactorMarker, Fu as resolveAssemblyPath, G as withResourceDeadline, Ga as hasReadableResources, Gc as withStackInstanceIdWithheld, Gl as warnFinchArgvExposure, Gn as rollbackOrphanIds, Go as unreadableOrphanRecords, Gr as ledgerForStack, Gt as isJournaledOrphan, H as parentSuppliedValues, Ha as displayLogicalId, Hc as isAccessDenied, Hi as IntrinsicFunctionResolver, Hl as redactedDockerCause, Hn as findRefactorHints, Ho as repairMalformedResourcePropertiesForReadOnly, Hr as refusesFinalSnapshot, Hs as recordedNoEchoValuesOf, Ht as removeProtectionTypeList, I as isAbsoluteAssetPath, Ia as STATE_REGION_DIVERGED, Ic as S3StateBackend, Il as getDockerCmd, In as DEFAULT_RESOURCE_TIMEOUT_MS, Io as refuseMalformedResourcesForExport, Ir as PRE_DELETE_SNAPSHOT_TYPES, Is as noEchoCoordinatesOf, It as hasPendingMovesOut, Iu as injectAwsRegion, J as keptWholeReasonText, Ja as malformedDriftResourcePropertiesWarning, Jc as describeRegionValueKind, Jl as Synthesizer, Jn as looselyEqual, Jo as findActionableSilentDrops, Jt as planRollback, K as diffSecurity, Ka as isReadableOrphanRecord, Kc as splitImportedOps, Kl as AssetManifestLoader, Kn as withMovedTo, Ko as unreadableResourceEntries, Ks as redactForState, Kt as isReplacementOrphan, L as listNestedTemplateRows, La as STATE_RESOURCES_MALFORMED, Lc as rebuildClientForBucketRegion, Ll as isDockerClientEnvKey, Ln as DEFAULT_RESOURCE_WARN_AFTER_MS, Lo as refuseMalformedState, Lr as buildFinalSnapshotIdentifier, Ls as noEchoLeavesOf, Lt as pendingMovesOutOf, Lu as injectedAwsRegionValue, M as findServiceTokenRefusals, Ma as parameterInputsFor, Mc as WHOLE_DYNAMIC_REFERENCE_PATTERN, Mi as isWaitAbandonedError, Ml as describeDockerFailure, Mn as collectDeclaredOutputNames, Mo as refuseMalformedResourcePropertiesForExport, Mr as secretNamedRecordNeedles, Ms as maskAtCoordinates, Mt as refactorMarkerRefusalMessage, Mu as describeFileReadFailure, N as serviceTokenBlockingReason, Nc as isSingleDynamicReferenceToken, Nl as dockerSpawnEnvWithSensitive, Nn as collectPublishedOutputNames, No as refuseMalformedResourcePropertiesForOrphan, Nr as stateSecretNameNeedles, Ns as maskReadbackAtCoordinates, Nt as refuseRefactorMarker, Nu as displayAssemblyPath, O as computeImplicitDeleteEdges, Oa as isStalePlaceholderArnAttribute, Oc as recordNoEchoAttributeValues, Oi as deleteIndeterminateGuards, Ol as buildDockerImage, On as exportNameNoEchoParameters, Oo as refuseMalformedResourceEntriesForImportSave, Or as orphanRecordsPrintingBag, Os as DagBuilder, Ou as hasPlainPrototype, P as childTemplateLoader, Pa as declaresNoEcho, Pc as LockManager, Pl as finchSecretArgvRefusal, Pn as isExportAliasCollision, Po as refuseMalformedResourcesForDeploy, Pr as storedSecretNameNeedles, Ps as maskWholeValue, Pt as sameMove, Pu as renderAssemblyPathEscape, Q as planOrphanAdoption, Qa as malformedLocalResourceEntriesWarning, Qc as hasUnverifiableParameterRefusal, Qi as refuseUnreadableCdkCrossAccountRefs, Ql as loadCdkJson, Qo as NO_CC_HANDLERS_REASON, Qs as literalSplitDelimitersOf, Qt as resolveReplacementOldType, R as renderNestedTemplateTreeDefect, Ra as UNREADABLE_ORPHANS_CONTAINER_ROW, Rc as CrossPrefixReadError, Rl as isMalformedEnvKey, Rn as maskingRetryLogger, Ro as repairMalformedOrphanRecordsForReadOnly, Rr as ccRoutedFinalSnapshotError, Rs as noEchoOutputsComparison, Rt as pendingMovesRefusalMessage, Sa as carriesDynamicReference, Sc as recordPhysicalNameCopy, Si as customResourceResponseExpirationWarning, Sl as isCrossRegionRedirect, Sn as displayTextOrWithheld, So as refuseMalformedOutputsForDestroy, Sr as noEchoParameterNamesOf, Ss as templateResourceTypes, St as makeForeignHolderScan, Su as processStackMessages, Ta as keepsSecretReferenceToken, Tc as provenPublicValue, Tl as validateAssetBucketName, Tn as secretBearingStateKeyWarning, To as refuseMalformedResourceEntriesForDeploy, Tr as journaledOrphanPrintingBag, Tu as utf8ByteLength, U as readRecordedConditionVerdicts, Ua as hasReadableOrphans, Uc as isNotImplemented, Ui as poisonRenderedSpellingsCollidingIn, Ul as runDockerForeground, Un as hintSidesOf, Uo as repairMalformedResourcesForReadOnly, Ur as unsupportedFinalSnapshotError, Us as valueAtCoordinate, Ut as recordAfterRollbackUpdate, V as conditionInputsFrom, Va as deployRefusesOrphanRowsReason, Vc as crossPrefixDeniedWarning, Vi as INTRINSIC_KEYS, Vl as redactedCause, Vn as formatDestructiveChange, Vo as repairMalformedResourceEntriesForReadOnly, Vr as isFinalSnapshotError, Vs as readsNoEchoSource, Vt as replayRollback, Wa as hasReadableOutputs, Wc as stackInstanceIdOf, Wl as runDockerStreaming, Wn as movedToHint, Wo as unpreviewableOrphanRecords, Ws as liveMatchesUnresolvedTokenFrame, Wt as demoteSupersededOrphans, X as makeCanonicalizePropertiesFn, Xa as malformedExportSourceWarning, Xc as hasReadableExportSet, Xi as resolveDynamicReferences, Xl as getDefaultStateBucketName, Xn as parseMappingFile, Xo as unwrittenCreateOnlyReplacement, Xr as DeploymentEventsStore, Xs as createUnionSecretMasker, Xt as recordUnderIdIsNotOwn, Y as mergeNoChangeOutputs, Ya as malformedExportNamesWarning, Yc as exportNamesCarriedFrom, Yl as synthesisStatusMessage, Yn as mappingPairs, Yr as DeploymentEventsReader, Ys as carryLogOnlyValues, Yt as recheckFailedPlan, Z as makeSiblingClaimReader, Za as malformedLocalOutputsWarning, Zc as hasReasonlessBaselineRefusal, Zi as producerLookupOver, Zl as getLegacyStateBucketName, Zn as proposeRenames, Zr as extractDeploymentEventError, Zs as hasMaskableValues, Zt as replacementNeverSwapped, _a as coerceParameterTypedValue, _c as inheritNestedStackParameterAssociations, _i as isCustomResourceType$1, _l as AssetModeResolver, _n as computeParameterTaint, _o as refuseMalformedOrphanRecordsForDestroy, _r as supersededResourcesOf, _t as dropFailedCommands, _u as PARTITION_TABLE, a as isProtectionValueActive, aa as assertSendableRoleArn, ac as createSecretMasker, al as stackInstanceIdCarriedFrom, ao as malformedOutputsRefusalMessage, ar as gray, as as renderStatefulReason, at as displacedPhysicalIdShown, au as resolveUseCdkBootstrapAssets, ba as getAccountInfo, bc as physicalNameCopiesOf, bi as CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID, bl as ensureAssetStorage, bn as resourcesNamingDeclaredParameter, bo as refuseMalformedOrphansForOrphan, br as noEchoComparisonForTemplate, bt as journaledOrphanLines, bu as AssemblyReader, ca as sendableAssumeRoleCommand, cc as maskSecretsInText, cl as timePhase, cn as updatePartialMessage, co as malformedResourceEntriesWarning, cr as yellow, ct as nestedChildStackName$1, cu as ssmResolvedValueType, da as callerEnvCredentials, di as ccBrokenReason, dl as stringifyValue, dn as nameGenerationHighWaterOf, do as malformedScrubResourceEntriesRefusalMessage, dr as holdsSupersededResources, dt as revertedNestedRowIds, du as MIGRATE_TMP_PREFIX, ec as printingCorpusOf, el as importableOutputs, en as orphanNeedsIdentity, eo as malformedOrphanRecordsRefusalMessage, es as findReplacedReadersOfRecreateTargets, et as resolvePendingCloudControlRequests, eu as resolveAutoAssetStorage, fa as envCredentialsAreAssumedRole, fc as DYNAMIC_REFERENCE_TOKEN_SCAN, fi as isCustomResource, fl as WorkGraph, fn as nameScopeOf, fo as malformedStateRefusalMessage, fr as isSupersededResourceRecord, ft as withNestedRevertRun, fu as findLargeInlineResources, ga as regionLessSecretName, gc as identityKeyFor, gi as readsNoEchoDeleteValues, gl as rewriteTemplateAssetReferences, gn as withNameGenerationReached, go as refuseMalformedOrphanRecords, gr as supersededHolderOf, gt as deleteJournaledOrphans, gu as expectedOwnerParam, ha as producerRegionsFromState, hc as pathCrossesDottedKey, hi as TemplateNoEchoReresolver, hl as loadPublishableAssetManifest, hn as retiredNameGenerationsLeaving, hr as supersededHeldByOtherTypeWarning, ht as withNestedStackContext, hu as decodeListingKey, i as PROTECTION_PROPERTY_BY_TYPE, ia as assertFlagRoleArn, ic as unionOfSecretBags, il as shouldRetainResource, io as malformedOrphansWarning, ir as cyan, is as isStatefulRecreateTargetSync, it as displacedOpClause, iu as resolveStateBucketWithDefaultAndSource, j as deferredServiceTokenWarning, ja as withSharedDrainBudget, jc as wholeStringLeavesOf, jl as describeDockerExecFailure, jn as noEchoParameterValueSeed, jo as refuseMalformedResourcePropertiesForDrift, js as isMarkedCoordinate, jt as refactorMarkerMovesOf, ju as absoluteAssemblyPathEscape, k as crossStackOutputProvenanceSource, ka as refStateLookupFromResource, kc as recordNoEchoParameterFreshValue, ki as deleteLeftInPlace, kl as resolveDockerContextDirectory, kn as exportNameSecretExposure, ko as refuseMalformedResourceEntriesForOrphan, kr as secretNamePrintingBag, ks as TemplateParser, kt as readRefactorMarker, ku as nullPrototypeRecord, la as AWS_CREDENTIAL_ENV_KEYS, lc as scrubResourceRecord, li as CC_BROKEN_REASON, ll as AssetPublisher, ln as updatePartialReason, lo as malformedResourcePropertiesWarning, lr as addSuperseded, lt as recordDisplacedSkips, lu as CFN_TEMPLATE_BODY_LIMIT, ma as classifyReplaySecretRegion, mc as isUncertifiedBaselineMaskPosition, ml as createAssetRedirectResolver, mn as retiredNameGenerationsAfter, mo as refuseDivergentRecordRegionForDestroy, mr as supersededAfterRollback, mt as getCurrentNestedStackContext, mu as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, n as recordedProtectionEvidence, na as recordedReferenceRegions, nc as recordLogOnlyValue, nl as orphansAfterRollback, no as malformedOrphanRowsKeptWarning, ns as MULTI_REGION_RECREATE_BLOCKED_TYPES, nt as recordRetainedForReadoption, nu as resolveSkipPrefix, o as perType, oa as explicitRoleArnOrThrow, oc as errorCauseChain, ol as PhaseClock, oo as malformedOutputsWarning, or as green, ot as dropSettledNestedJournals, ou as stateBucketExistenceConfirmed, pa as classifyRecordedSecretRegion, pc as dynamicReferenceTokens, pi as wouldReturnToSdkProvider, pl as buildAssetRedirectMap, pn as retiredAfterRollback, po as previewableOrphanRecords, pr as removeSuperseded, pt as collectNestedChildUnaddressed, pu as uploadCfnTemplate, q as isSecretBearingReferenceString, qa as isReadableResourceEntry, qc as acceptedCreateOnlyDropsOf, ql as getDockerImageBySourceHash, qn as isPairableType, qo as withheldAccountClause, qr as withCreateTokenLedger, qt as planFailedOps, r as recordedProtectionNote, ra as applyRoleArnIfSet, rc as shareLogOnlyValues, rl as orphansCarriedFrom, rn as inheritProducerRegions, ro as malformedOrphansRefusalMessage, rr as bold, rs as isStatefulRecreateTargetForReplace, rt as NESTED_PENDING_PARENT_REASON, ru as resolveStateBucketWithDefault, s as readProtection, sa as isIamRoleArn, sc as maskSecretsInError, sl as renderPhaseTimings, so as malformedRenderedContainersWarning, sr as red, su as warnDeprecatedNoPrefixCliFlag, t as DeployEngine, ta as recordedOutputReferenceRegions, tc as recordLogOnlyParameterValue, tl as isReadableBag, tn as findNestedStackTypeChanges, to as malformedOrphanRecordsWarning, tr as withStackRecords, ts as shownType, tt as keptForRetainedRecord, tu as resolveCaptureObservedState, ua as applyCallerIdentityCredentials, uc as withPhysicalNameCopies, ui as ProviderRegistry, ul as isSensitiveAttributeName, un as nameGenerationCarriedFrom, uo as malformedResourcesWarning, ur as deleteSupersededEntry, uu as CFN_TEMPLATE_URL_LIMIT, va as isUnboundTemplateParameter, vc as recordNestedStackParameterExpressions, vl as BOOTSTRAP_MARKER_PREFIX, vn as namesAnyDeclaredParameter, vo as refuseMalformedOrphans, vr as withoutSuperseded, vt as dropFailedHint, vu as canonicalizeRegion, wa as isNamelessDynamicReferenceError, wc as carriesSecretMask, wi as slowCcOperationTimeoutMs, wl as readBootstrapMarkerBody, wn as secretBearing, wo as refuseMalformedResourceEntries, wr as completedReplayEntries, ws as withRetry, wt as formatResourceLine, wu as parseFailureDebugDetail, xa as isImpossibleEmptyStoredAttribute, xi as applyCustomResourceResponseExpiration, xl as getBootstrapMarkerKey, xn as WITHHELD_NAME_DISPLAY, xo as refuseMalformedOutputs, xr as noEchoExactEchoLeavesOf, xs as prefetchCreateOnlyPropertyPaths, xt as loadJournaledOrphans, xu as StageLoadError, ya as parameterTypeMayLoseSecretIdentity, yi as withPrintingSecrets, yl as assertAssetBucketRegion, yn as reachableDivergentParameters, yo as refuseMalformedOrphansForDestroy, yr as noEchoAttributeNamesOf, yt as isHandledOrphan, yu as derivePartitionAndUrlSuffix, z as templateIdentity, za as UNREADABLE_RESOURCES_MAP_ROW, zc as CrossPrefixScanCache, zl as partitionSensitiveEnv, zn as constructPathOf$1, zo as repairMalformedOrphansForReadOnly, zr as createPreDeleteFinalSnapshot, zt as refusePendingMovesOut, zu as resolveBucketRegion } from "./deploy-engine-Bx98Q92J.js";
6
+ import { t as getCdkdVersion } from "./version-BhQymxXT.js";
8
7
  import { randomBytes, randomUUID } from "node:crypto";
9
8
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutBucketVersioningCommand, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
10
9
  import { GetRoleCommand, GetUserCommand } from "@aws-sdk/client-iam";
@@ -21,12 +20,13 @@ import { basename, dirname, isAbsolute, join, resolve } from "node:path";
21
20
  import { execFile, spawn } from "node:child_process";
22
21
  import { tmpdir } from "node:os";
23
22
  import { BatchDeleteImageCommand, DeleteRepositoryCommand, DescribeImagesCommand as DescribeImagesCommand$1, ECRClient, GetAuthorizationTokenCommand } from "@aws-sdk/client-ecr";
24
- import { promisify } from "node:util";
23
+ import { isDeepStrictEqual, promisify } from "node:util";
25
24
  import graphlib from "graphlib";
26
25
  import { Command, InvalidArgumentError, Option } from "commander";
27
26
  import * as readline$1 from "node:readline/promises";
28
27
  import readline from "node:readline/promises";
29
- import { Document, Pair, Scalar, YAMLMap, YAMLSeq, isScalar, parse, stringify, visit } from "yaml";
28
+ import { Document, Pair, Scalar, YAMLError, YAMLMap, YAMLSeq, isScalar, parse, parseDocument, stringify, visit } from "yaml";
29
+ import { emitKeypressEvents } from "node:readline";
30
30
  import { A2A_CONTAINER_PORT, A2A_PATH, AGENTCORE_A2A_PROTOCOL, AGENTCORE_AGUI_PROTOCOL, AGENTCORE_MCP_PROTOCOL, ConnectionRegistry, DynamicReferenceResolver, EcsTaskResolutionError, HOST_GATEWAY_MIN_VERSION, LocalInvokeBuildError, MCP_CONTAINER_PORT, MCP_PATH, a2aInvokeOnce, addAlbSpecificOptions, addCommonEcsServiceOptions, addStartServiceSpecificOptions, albStrategy, architectureToPlatform, attachAuthorizers, attachStageContext, availableApiIdentifiers, bufferToBody, buildAgentCoreCodeImage, buildCognitoJwksUrl, buildConnectEvent, buildContainerImage, buildCorsConfigByApiId, buildCorsConfigFromCloudFrontChain, buildDisconnectEvent, buildJwksUrlFromIssuer, buildMessageEvent, buildMgmtEndpointEnvUrl, buildStageMap, classifySourceChange, containsDynamicReference, createAuthorizerCache, createFileWatcher, createFileWatcher as createFileWatcher$1, createJwksCache, createWatchPredicates, defaultCredentialsLoader, derivePseudoParametersFromRegion, describeAwsFailureForWarn, discoverRoutes, discoverWebSocketApis, downloadAndExtractS3Bundle, filterRoutesByApiIdentifier, firstUsableRegion, groupRoutesByServer, handleConnectionsRequest, invokeAgentCore, invokeAgentCoreWs, keysNotFromTemplate, keysOverriddenBy, materializeLayerFromArn, mcpInvokeOnce, parseConnectionsPath, parseSelectionExpressionPath, pickAgentCoreCandidateStack, pickAgentCoreCandidateStack as pickAgentCoreCandidateStack$1, probeHostGatewaySupport, readMtlsMaterialsFromDisk, recordAssumedRole, resolveAgentCoreTarget, resolveDynamicReferencesInEnv, resolveEnvVars, resolveHostGatewayExtraHosts, resolveRuntimeCodeMountPath, resolveRuntimeFileExtension, resolveRuntimeImage, resolveSingleTarget, resolveWatchConfig, runEcsServiceEmulator, signAgentCoreInvocation, startApiServer, substituteImagePlaceholders, tryResolveImageFnJoin, verifyJwtViaDiscovery, waitForAgentCorePing, withoutKeys } from "cdk-local/internal";
31
31
  import { createLocalStartAgentCoreCommand, createLocalStartCloudFrontCommand, createLocalStateProvider, getEmbedConfig, isCfnFlagPresent, listTargets, rejectExplicitCfnStackWithMultipleStacks, resolveCfnFallbackRegion, setEmbedConfig, substituteAgainstState, substituteAgainstStateAsync, substituteEnvVarsFromState, substituteEnvVarsFromStateAsync } from "cdk-local";
32
32
  import { createServer } from "node:net";
@@ -130,7 +130,7 @@ function parseResourceTimeoutToken(flagName) {
130
130
  try {
131
131
  ms = parseDuration(durationPart);
132
132
  } catch (err) {
133
- const inner = err instanceof Error ? err.message : String(err);
133
+ const inner = describeAwsFailure(err).detail;
134
134
  throw new Error(`Invalid ${flagName} value "${raw}": ${inner}`);
135
135
  }
136
136
  acc.perTypeMs[typePart] = ms;
@@ -249,7 +249,7 @@ const allowUnaddressedOption = new Option("--allow-unaddressed", "Exit 0 even wh
249
249
  const noCfnFallbackOption = new Option("--no-cfn-fallback", "Do not fall back to CloudFormation (ListExports / stack outputs) when an Fn::ImportValue / Fn::GetStackOutput reference is not found in cdkd state (default: fall back, so producers still managed by CloudFormation can be referenced)");
250
250
  const annotationMessageOptions = [new Option("--strict", "Do not proceed with stacks carrying warning annotations").default(false), new Option("--ignore-errors", "Ignore error annotations from stack synthesis, which will likely produce an invalid deployment").default(false)];
251
251
  const deployOptions = [
252
- new Option("--concurrency <number>", "Maximum concurrent resource operations").default(10).argParser((value) => parseInt(value, 10)),
252
+ new Option("--concurrency <number>", "Maximum concurrent resource operations").default(20).argParser((value) => parseInt(value, 10)),
253
253
  new Option("--stack-concurrency <number>", "Maximum concurrent stack deployments").default(4).argParser((value) => parseInt(value, 10)),
254
254
  new Option("--asset-publish-concurrency <number>", "Maximum concurrent asset publish operations (S3 uploads + ECR push)").default(8).argParser((value) => parseInt(value, 10)),
255
255
  new Option("--image-build-concurrency <number>", "Maximum concurrent Docker image builds").default(4).argParser((value) => parseInt(value, 10)),
@@ -2261,14 +2261,6 @@ function mapsEqual(a, b) {
2261
2261
  }
2262
2262
  return true;
2263
2263
  }
2264
- function describeParseFailure(err, bytes) {
2265
- const raw = err instanceof Error ? err.message : String(err);
2266
- const at = /at position (\d+)/.exec(raw);
2267
- return `invalid JSON${at ? ` at code-unit position ${at[1]}` : ""}; ${bytes} byte(s) read`;
2268
- }
2269
- function utf8ByteLength(body) {
2270
- return Buffer.byteLength(body, "utf8");
2271
- }
2272
2264
  function describeIndexVersion(value) {
2273
2265
  return typeof value === "number" ? String(value) : `a non-numeric value (${typeof value})`;
2274
2266
  }
@@ -2348,7 +2340,7 @@ var ExportIndexStore = class {
2348
2340
  if (this.loadState.kind === "loaded") return new Map(this.loadState.entries);
2349
2341
  const outcome = await this.loadPersisted();
2350
2342
  if (outcome.kind === "missing") return void 0;
2351
- if (outcome.kind === "corrupt") throw new Error(`Exports index at ${this.indexKey()} could not be parsed (${describeParseFailure(outcome.error, outcome.bytes)}). Its contents were NOT examined.`);
2343
+ if (outcome.kind === "corrupt") throw new Error(`Exports index at ${this.indexKey()} could not be parsed (${describeJsonParseFailure(outcome.error, outcome.bytes)}). Its contents were NOT examined.`);
2352
2344
  return new Map(outcome.entries);
2353
2345
  }
2354
2346
  async patchEntry(exportName, entry, opts = {}) {
@@ -2434,7 +2426,7 @@ var ExportIndexStore = class {
2434
2426
  return;
2435
2427
  }
2436
2428
  if (outcome.kind === "corrupt") {
2437
- this.logger.warn(`Exports index corrupt (${outcome.error instanceof Error ? outcome.error.message : String(outcome.error)}); rebuilding from state.json files`);
2429
+ this.logger.warn(`Exports index corrupt (${describeJsonParseFailure(outcome.error, outcome.bytes)}); rebuilding from state.json files`);
2438
2430
  await this.rebuild();
2439
2431
  return;
2440
2432
  }
@@ -2718,7 +2710,7 @@ function collectCrossStackRefs(node, onRef, unconditional) {
2718
2710
  //#region src/provisioning/register-providers.ts
2719
2711
  let providerClasses;
2720
2712
  function loadProviderClasses() {
2721
- providerClasses ??= import("./provider-classes-B52ogqNj.js");
2713
+ providerClasses ??= import("./provider-classes-g1s3vsUl.js");
2722
2714
  return providerClasses;
2723
2715
  }
2724
2716
  function registerAllProviders(registry, classes) {
@@ -3226,7 +3218,10 @@ var CrossPrefixGuard = class {
3226
3218
  //#endregion
3227
3219
  //#region src/cli/commands/deploy.ts
3228
3220
  async function deployCommand(stacks, options) {
3221
+ const runClock = new PhaseClock("run", { fromProcessStart: true });
3222
+ runClock.lap("node startup + module load");
3229
3223
  const providerClasses = await loadProviderClasses();
3224
+ runClock.lap("provider load");
3230
3225
  const logger = getLogger();
3231
3226
  if (options.verbose) {
3232
3227
  logger.setLevel("debug");
@@ -3296,6 +3291,19 @@ async function deployCommand(stacks, options) {
3296
3291
  })
3297
3292
  };
3298
3293
  })();
3294
+ const callerIdentityPromise = (async () => {
3295
+ const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
3296
+ const stsClient = new STSClient({
3297
+ ...awsClientDefaults(),
3298
+ region
3299
+ });
3300
+ try {
3301
+ return await stsClient.send(new GetCallerIdentityCommand({}));
3302
+ } finally {
3303
+ stsClient.destroy();
3304
+ }
3305
+ })();
3306
+ callerIdentityPromise.catch(() => void 0);
3299
3307
  let deployInterrupted = false;
3300
3308
  const topLevelSigintHandler = () => {
3301
3309
  if (deployInterrupted) {
@@ -3322,7 +3330,9 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3322
3330
  ...options.profile && { macroExpandS3ClientOpts: { profile: options.profile } },
3323
3331
  deferMacroExpansion: true
3324
3332
  };
3325
- const [result, statePrep] = await Promise.all([synthesizer.synthesize(synthOptions), statePrepPromise]);
3333
+ runClock.lap("config, region, credentials");
3334
+ const [result, statePrep] = await Promise.all([timePhase("run", "synth (beside the state bucket prep)", () => synthesizer.synthesize(synthOptions)), timePhase("run", "state bucket prep (beside synth)", () => statePrepPromise)]);
3335
+ runClock.lap("synth + state bucket prep");
3326
3336
  const { stateBucket, preflightStateBackend, exportIndexStore } = statePrep;
3327
3337
  preflightBackendForCleanup = preflightStateBackend;
3328
3338
  synthOptions.stateBucket = stateBucket;
@@ -3410,14 +3420,11 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3410
3420
  const stackRegions = new Map(await Promise.all(targetStacks.map(async (s) => [s, await regionForStack(s.stackName, s.region)])));
3411
3421
  refuseStackNameRegionCollisions(sameNamedAppStacks, (s) => stackRegions.get(s) ?? s.region, selectedSet);
3412
3422
  const crossPrefixGuard = new CrossPrefixGuard(preflightStateBackend, { readOnly: options.dryRun === true });
3423
+ runClock.lap("stack selection, stack regions");
3413
3424
  await synthesizer.expandMacrosForStacks(targetStacks, synthOptions);
3414
- const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
3415
- const stsClient = new STSClient({
3416
- ...awsClientDefaults(),
3417
- region
3418
- });
3419
- const accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
3420
- stsClient.destroy();
3425
+ runClock.lap("macro expansion");
3426
+ const accountId = (await callerIdentityPromise).Account;
3427
+ runClock.lap("caller identity");
3421
3428
  const assetPublisher = new AssetPublisher();
3422
3429
  const useCdkBootstrapAssets = resolveUseCdkBootstrapAssets(options.useCdkBootstrapAssets);
3423
3430
  const autoAssetStorage = resolveAutoAssetStorage(options.autoAssetStorage);
@@ -3644,7 +3651,8 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3644
3651
  ...approveDeployment && {
3645
3652
  requireApproval,
3646
3653
  approveDeployment
3647
- }
3654
+ },
3655
+ ...stackInfo.terminationProtection === true && { terminationProtection: true }
3648
3656
  };
3649
3657
  const stackDeployEngine = new DeployEngine(stackStateBackend, stackLockManager, dagBuilder, diffCalculator, stackProviderRegistry, deployEngineOptions, stackRegion, exportIndexStore);
3650
3658
  const deployResult = await withNestedStackContext({
@@ -3727,12 +3735,13 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3727
3735
  if (reach.unmatched.length > 0) throw new CdkdError(reach.errorMessage, "PIN_CC_API_INVALID");
3728
3736
  for (const partial of reach.partial) logger.info(`--pin-cc-api ${partial.logicalId}: applies to ${partial.appliesTo.join(", ")}; not declared by ${partial.absentFrom.join(", ")}`);
3729
3737
  }
3738
+ runClock.lap("work graph build, recreate checks");
3730
3739
  await workGraph.execute({
3731
3740
  "asset-build": options.imageBuildConcurrency,
3732
3741
  "asset-publish": options.assetPublishConcurrency,
3733
3742
  stack: options.stackConcurrency
3734
3743
  }, async (node) => {
3735
- if (node.type === "asset-build" || node.type === "asset-publish") await assetPublisher.executeNode(node);
3744
+ if (node.type === "asset-build" || node.type === "asset-publish") await timePhase("run", node.type, () => assetPublisher.executeNode(node), node.id);
3736
3745
  else {
3737
3746
  const { stack: stackInfo } = node.data;
3738
3747
  if (!bufferStackOutput) {
@@ -3746,10 +3755,12 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3746
3755
  });
3747
3756
  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.`);
3748
3757
  } finally {
3758
+ runClock.lap("assets + stacks, summary");
3749
3759
  unforwardSigterm();
3750
3760
  process.removeListener("SIGINT", topLevelSigintHandler);
3751
3761
  awsClients.destroy();
3752
3762
  preflightBackendForCleanup?.destroyClient();
3763
+ for (const line of renderPhaseTimings()) logger.info(line);
3753
3764
  }
3754
3765
  }
3755
3766
  function createDeployCommand() {
@@ -4255,7 +4266,7 @@ function buildCustomTags() {
4255
4266
  tag: "!GetAtt",
4256
4267
  resolve(value) {
4257
4268
  const dot = value.indexOf(".");
4258
- if (dot < 0) throw new Error(`!GetAtt requires '<LogicalId>.<Attribute>'; got '${value}'`);
4269
+ if (dot < 0) throw new Error(`${GETATT_SHAPE_REFUSAL}; got '${value}'`);
4259
4270
  return { "Fn::GetAtt": [value.slice(0, dot), value.slice(dot + 1)] };
4260
4271
  },
4261
4272
  identify: () => false
@@ -4298,6 +4309,28 @@ function buildCustomTags() {
4298
4309
  return tags;
4299
4310
  }
4300
4311
  const CUSTOM_TAGS = buildCustomTags();
4312
+ const GETATT_SHAPE_REFUSAL = "!GetAtt requires '<LogicalId>.<Attribute>'";
4313
+ const YAML_ALIAS_EXHAUSTION = "Excessive alias count indicates a resource exhaustion attack";
4314
+ function describeYamlFinding(err) {
4315
+ if (err instanceof YAMLError) {
4316
+ const at = err.linePos?.[0];
4317
+ const where = at ? ` at line ${at.line}, column ${at.col}` : "";
4318
+ if (err.code === "TAG_RESOLVE_FAILED" && err.message.startsWith(GETATT_SHAPE_REFUSAL)) return `${GETATT_SHAPE_REFUSAL}${where}`;
4319
+ return `${err.name} ${err.code}${where}`;
4320
+ }
4321
+ if (err instanceof Error) return err.message === YAML_ALIAS_EXHAUSTION ? `${err.name}: ${YAML_ALIAS_EXHAUSTION}` : err.name || "Error";
4322
+ return describeAwsFailure(err).detail;
4323
+ }
4324
+ function parseYamlTemplate(body) {
4325
+ const doc = parseDocument(body, { customTags: CUSTOM_TAGS });
4326
+ const logger = getLogger();
4327
+ for (const warning of doc.warnings) {
4328
+ logger.debug(safeMsg`Template YAML warning: ${parseFailureDebugDetail(warning)}`);
4329
+ logger.warn(safeMsg`Template YAML warning: ${describeYamlFinding(warning)}`);
4330
+ }
4331
+ if (doc.errors.length > 0) throw doc.errors[0];
4332
+ return doc.toJS();
4333
+ }
4301
4334
  function parseCfnTemplate(text) {
4302
4335
  const format = detectTemplateFormat(text);
4303
4336
  const body = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
@@ -4305,12 +4338,14 @@ function parseCfnTemplate(text) {
4305
4338
  if (format === "json") try {
4306
4339
  parsed = JSON.parse(body);
4307
4340
  } catch (err) {
4308
- throw new Error(`Template is not valid JSON. Cause: ${err instanceof Error ? err.message : String(err)}`);
4341
+ getLogger().debug(safeMsg`Template failed to parse as JSON: ${parseFailureDebugDetail(err)}`);
4342
+ throw new Error(`Template is not valid JSON. Cause: ${describeJsonParseFailure(err, utf8ByteLength(body))}`);
4309
4343
  }
4310
4344
  else try {
4311
- parsed = parse(body, { customTags: CUSTOM_TAGS });
4345
+ parsed = parseYamlTemplate(body);
4312
4346
  } catch (err) {
4313
- throw new Error(`Template is not valid YAML. Cause: ${err instanceof Error ? err.message : String(err)}`);
4347
+ getLogger().debug(safeMsg`Template failed to parse as YAML: ${parseFailureDebugDetail(err)}`);
4348
+ throw new Error(`Template is not valid YAML. Cause: ${describeYamlFinding(err)}`);
4314
4349
  }
4315
4350
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`Template root is not an object.`);
4316
4351
  return parsed;
@@ -4606,7 +4641,7 @@ function injectRetainPolicies(templateBody, cfnStackName) {
4606
4641
  try {
4607
4642
  parsed = parseCfnTemplate(templateBody);
4608
4643
  } catch (err) {
4609
- throw new Error(`Template for '${cfnStackName}' is not a valid CloudFormation template. cdkd's --migrate-from-cloudformation flow supports both JSON and YAML templates (YAML via a CFn-aware codec that preserves !Ref / !GetAtt / !Sub shorthand). Cause: ${err instanceof Error ? err.message : String(err)}`);
4644
+ throw new Error(`Template for '${cfnStackName}' is not a valid CloudFormation template. cdkd's --migrate-from-cloudformation flow supports both JSON and YAML templates (YAML via a CFn-aware codec that preserves !Ref / !GetAtt / !Sub shorthand). Cause: ${describeAwsFailure(err).detail}`);
4610
4645
  }
4611
4646
  if (!("Resources" in parsed) || typeof parsed["Resources"] !== "object" || parsed["Resources"] === null || Array.isArray(parsed["Resources"])) throw new Error(`Template for '${cfnStackName}' has no Resources section — refusing to retire.`);
4612
4647
  const modified = injectRetainPoliciesOnParsedResources(parsed["Resources"]);
@@ -4675,7 +4710,7 @@ async function injectRetainPoliciesRecursiveInternal(templateBody, cfnStackName,
4675
4710
  try {
4676
4711
  parsed = parseCfnTemplate(templateBody);
4677
4712
  } catch (err) {
4678
- throw new Error(`Template for '${cfnStackName}' is not a valid CloudFormation template. cdkd's --migrate-from-cloudformation flow supports both JSON and YAML templates (YAML via a CFn-aware codec that preserves !Ref / !GetAtt / !Sub shorthand). Cause: ${err instanceof Error ? err.message : String(err)}`);
4713
+ throw new Error(`Template for '${cfnStackName}' is not a valid CloudFormation template. cdkd's --migrate-from-cloudformation flow supports both JSON and YAML templates (YAML via a CFn-aware codec that preserves !Ref / !GetAtt / !Sub shorthand). Cause: ${describeAwsFailure(err).detail}`);
4679
4714
  }
4680
4715
  if (!("Resources" in parsed) || typeof parsed["Resources"] !== "object" || parsed["Resources"] === null || Array.isArray(parsed["Resources"])) throw new Error(`Template for '${cfnStackName}' has no Resources section — refusing to retire.`);
4681
4716
  const resources = parsed["Resources"];
@@ -4916,7 +4951,9 @@ function indexNestedChildTemplates(template, templatePath) {
4916
4951
  return result;
4917
4952
  }
4918
4953
  async function loadStateOrEmpty(stackName, region, stateBackend, refusalRecovery) {
4954
+ const refactorMarker = readRefactorMarkerOnce(stateBackend);
4919
4955
  const result = await stateBackend.getState(stackName, region);
4956
+ const markerRefusal = refactorMarkerRefusalMessage(await refactorMarker, stackName, region, "cdkd deploy");
4920
4957
  if (result) {
4921
4958
  const unreadable = [];
4922
4959
  const unreadableContainers = [];
@@ -4946,15 +4983,19 @@ async function loadStateOrEmpty(stackName, region, stateBackend, refusalRecovery
4946
4983
  unreadableContainers.push("orphans");
4947
4984
  deployRefusals.push(DEPLOY_REFUSES_ORPHANS_CONTAINER_REASON);
4948
4985
  }
4986
+ if (hasPendingMovesOut(result.state)) deployRefusals.push(pendingMovesRefusalMessage(result.state, stackName, region, "cdkd deploy"));
4987
+ if (markerRefusal !== void 0) deployRefusals.push(markerRefusal);
4949
4988
  if (isReadableBag(result.state.outputs) && !hasReadableExportSet(result.state)) logger.warn(malformedExportNamesWarning(stackName, region, refusalRecovery));
4950
4989
  return {
4951
4990
  state: result.state,
4952
4991
  unreadable,
4953
4992
  unreadableContainers,
4954
- deployRefusals
4993
+ deployRefusals,
4994
+ found: true
4955
4995
  };
4956
4996
  }
4957
4997
  return {
4998
+ found: false,
4958
4999
  state: {
4959
5000
  stackName,
4960
5001
  region,
@@ -4965,7 +5006,7 @@ async function loadStateOrEmpty(stackName, region, stateBackend, refusalRecovery
4965
5006
  },
4966
5007
  unreadable: [],
4967
5008
  unreadableContainers: [],
4968
- deployRefusals: []
5009
+ deployRefusals: markerRefusal === void 0 ? [] : [markerRefusal]
4969
5010
  };
4970
5011
  }
4971
5012
  function tokenValueForComparison(token, declaredType) {
@@ -5754,7 +5795,7 @@ function healerUnderRecordPrintingBag(healer, resources, namingSecrets) {
5754
5795
  async function buildDiffTree(args) {
5755
5796
  const { stackName, displayName, region, template, nestedTemplates, recursive, stateBackend, diffCalculator, parentHasSecretReference, parameters, parentUnresolvedParameters, canonicalizeProperties, assetRedirect, cfnFallback, producerLookup, consumerAccount, previewOrphanAdoption, attributeHealerFor, ancestorTemplatePaths, isNestedChild, inheritedSecrets, inheritedDerivedNames, inheritedNoEchoParameters, inheritedNoEchoParametersAnyVerdict, refusalRecovery, inheritedReferenceProvenance, inheritedSecretTokens } = args;
5756
5797
  const unboundHealer = attributeHealerFor?.(stackName, region);
5757
- const { state, unreadable, unreadableContainers, deployRefusals } = await loadStateOrEmpty(stackName, region, stateBackend, refusalRecovery);
5798
+ const { state, unreadable, unreadableContainers, deployRefusals, found } = await loadStateOrEmpty(stackName, region, stateBackend, refusalRecovery);
5758
5799
  const attributeHealer = unboundHealer;
5759
5800
  const createOnlyPrefetch = prefetchCreateOnlyPropertyPaths(templateResourceTypes(recordedTemplateResources(template, state)));
5760
5801
  const secretBearingAbove = parentHasSecretReference === true || templateHasSecretDynamicReference(template);
@@ -5811,6 +5852,7 @@ async function buildDiffTree(args) {
5811
5852
  destructiveChanges: findDestructiveChanges(stackName, changes.values(), stateAfterAdoption.resources, effectiveTemplate),
5812
5853
  children: []
5813
5854
  };
5855
+ if (found && !isNestedChild && node.blocking.length === 0) node.refactorSides = hintSidesOf(changes.values(), rollbackOrphanIds(state.orphans));
5814
5856
  if (!recursive) return node;
5815
5857
  const templateChildIds = /* @__PURE__ */ new Set();
5816
5858
  for (const [logicalId, resource] of Object.entries(effectiveTemplate.Resources ?? {})) {
@@ -6000,13 +6042,15 @@ function diffTreeToJson(node) {
6000
6042
  for (const change of node.changes.values()) {
6001
6043
  if (change.changeType === "NO_CHANGE") continue;
6002
6044
  const ccApi = node.ccApiRoutes.get(change.logicalId);
6045
+ const movedTo = change.changeType === "DELETE" ? node.refactorHints?.get(change.logicalId) : void 0;
6003
6046
  changes.push({
6004
6047
  logicalId: change.logicalId,
6005
6048
  changeType: change.changeType,
6006
6049
  resourceType: change.resourceType,
6007
6050
  ...change.propertyChanges && change.propertyChanges.length > 0 ? { propertyChanges: change.propertyChanges } : {},
6008
6051
  ...change.attributeChanges && change.attributeChanges.length > 0 ? { attributeChanges: change.attributeChanges } : {},
6009
- ...ccApi && ccApi.length > 0 ? { ccApi } : {}
6052
+ ...ccApi && ccApi.length > 0 ? { ccApi } : {},
6053
+ ...movedTo !== void 0 && { movedTo }
6010
6054
  });
6011
6055
  }
6012
6056
  return {
@@ -6026,11 +6070,12 @@ function diffTreeToJson(node) {
6026
6070
  unreadable: node.unreadable,
6027
6071
  unreadableContainers: node.unreadableContainers,
6028
6072
  unreadableOrphans: node.unreadableOrphans,
6029
- destructiveChanges: node.destructiveChanges.map(({ logicalId, resourceType, constructPath, impact }) => ({
6073
+ destructiveChanges: node.destructiveChanges.map(({ logicalId, resourceType, constructPath, impact, movedTo }) => ({
6030
6074
  logicalId,
6031
6075
  resourceType,
6032
6076
  ...constructPath !== void 0 && { constructPath },
6033
- impact
6077
+ impact,
6078
+ ...movedTo !== void 0 && { movedTo }
6034
6079
  })),
6035
6080
  children: node.children.map(diffTreeToJson)
6036
6081
  };
@@ -6079,7 +6124,7 @@ function renderDiffValue(own, filtered, indent, isNewSide) {
6079
6124
  }
6080
6125
  return (JSON.stringify(filtered, null, 2) ?? "undefined").replace(/\n/g, `\n${indent}`);
6081
6126
  }
6082
- function renderChangeLines(changes, logFn, ccApiRoutes, adoptedOrphans) {
6127
+ function renderChangeLines(changes, logFn, ccApiRoutes, adoptedOrphans, refactorHints) {
6083
6128
  let createCount = 0;
6084
6129
  let updateCount = 0;
6085
6130
  let deleteCount = 0;
@@ -6118,7 +6163,10 @@ function renderChangeLines(changes, logFn, ccApiRoutes, adoptedOrphans) {
6118
6163
  break;
6119
6164
  case "DELETE":
6120
6165
  deleteCount++;
6121
- logFn(` [-] ${logicalId} (${change.resourceType})`);
6166
+ {
6167
+ const movedTo = refactorHints?.get(logicalId);
6168
+ logFn(` [-] ${logicalId} (${change.resourceType})` + (movedTo !== void 0 ? movedToHint(movedTo) : ""));
6169
+ }
6122
6170
  }
6123
6171
  return {
6124
6172
  create: createCount,
@@ -6182,7 +6230,7 @@ function renderDiffTree(node, isRoot, logFn) {
6182
6230
  const hasChanges = nodeHasChanges(node);
6183
6231
  if (hasChanges || node.blocking.length > 0) logFn(isRoot ? `\nStack ${stripForDisplay(node.stackName)}:` : `\nNested stack: ${stripForDisplay(node.displayName)}`);
6184
6232
  if (hasChanges) {
6185
- const { create, update, delete: del } = renderChangeLines(node.changes, logFn, node.ccApiRoutes, node.adoptedOrphans);
6233
+ const { create, update, delete: del } = renderChangeLines(node.changes, logFn, node.ccApiRoutes, node.adoptedOrphans, node.refactorHints);
6186
6234
  const outputs = renderOutputChangeLines(node.outputChanges, logFn);
6187
6235
  logFn(`\n${create} to create, ${update} to update, ${del} to delete`);
6188
6236
  if (outputs.add + outputs.change + outputs.remove > 0) logFn(`${outputs.add} output(s) to add, ${outputs.change} to change, ${outputs.remove} to remove`);
@@ -6394,6 +6442,7 @@ async function diffCommand(stacks, options) {
6394
6442
  suppressLegacyNotice: true
6395
6443
  });
6396
6444
  const trees = [];
6445
+ const treeEnvs = [];
6397
6446
  const producerLookup = producerLookupOver(allStacks);
6398
6447
  const sharedNames = new Set(targetStacks.map((s) => s.stackName).filter((name, i, names) => names.indexOf(name) !== i));
6399
6448
  for (const stackInfo of targetStacks) {
@@ -6424,7 +6473,20 @@ async function diffCommand(stacks, options) {
6424
6473
  isNestedChild: false,
6425
6474
  refusalRecovery
6426
6475
  }));
6476
+ treeEnvs.push(`${stackInfo.account ?? ""}/${stackRegion}`);
6427
6477
  }
6478
+ const hints = findRefactorHints(trees.flatMap((tree, i) => tree.refactorSides === void 0 ? [] : [{
6479
+ id: String(i),
6480
+ stackName: tree.stackName,
6481
+ env: treeEnvs[i],
6482
+ ...tree.refactorSides
6483
+ }]));
6484
+ trees.forEach((tree, i) => {
6485
+ const forTree = hints.get(String(i));
6486
+ if (forTree === void 0) return;
6487
+ tree.refactorHints = forTree;
6488
+ tree.destructiveChanges = withMovedTo(tree.destructiveChanges, forTree);
6489
+ });
6428
6490
  let securityDifferences = 0;
6429
6491
  let securityBroadening = false;
6430
6492
  if (securityOnly) for (const tree of trees) {
@@ -11995,6 +12057,12 @@ async function purgeStateHistoryIfOptedIn(ctx, stackName, region) {
11995
12057
  if (ctx.purgeStateHistory === true) await ctx.stateBackend.purgeDeletedStateHistory(stackName, region);
11996
12058
  }
11997
12059
  const NESTED_STACK_TYPE = "AWS::CloudFormation::Stack";
12060
+ function maskedSnapshotLogger(logger, mask) {
12061
+ return {
12062
+ info: (message) => logger.info(mask(message)),
12063
+ debug: (message) => logger.debug(mask(message))
12064
+ };
12065
+ }
11998
12066
  function recordDestroyEvent(recorder, event) {
11999
12067
  recorder?.record(maskEventTextWithBoundBags(event));
12000
12068
  }
@@ -12032,6 +12100,9 @@ async function releaseRegistryMarkerAfterDestroy(ctx, stackName, region, logger)
12032
12100
  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.`);
12033
12101
  }
12034
12102
  }
12103
+ function holdsSameResourcesAs(snapshot, current) {
12104
+ return isDeepStrictEqual(snapshot.resources, current.resources) && isDeepStrictEqual(snapshot.supersededResources, current.supersededResources);
12105
+ }
12035
12106
  async function runDestroyForStack(stackName, state, ctx) {
12036
12107
  const stackRegion = state.region;
12037
12108
  if (!stackRegion || stackRegion === ctx.baseRegion) return destroyStackInRegion(stackName, state, ctx, void 0);
@@ -12103,6 +12174,7 @@ async function destroyStackInRegion(stackName, state, ctx, stackScope) {
12103
12174
  refuseMalformedResourcePropertiesForDestroy(state, stackName, regionForState, refusalRecovery);
12104
12175
  refuseMalformedOrphansForDestroy(state, stackName, regionForState, refusalRecovery);
12105
12176
  refuseMalformedOrphanRecordsForDestroy(state, stackName, regionForState, refusalRecovery);
12177
+ refusePendingMovesOut(state, stackName, regionForState, "cdkd destroy");
12106
12178
  let journalAtEntry;
12107
12179
  try {
12108
12180
  journalAtEntry = { journal: await ctx.stateBackend.loadRollbackJournal(stackName, regionForState) };
@@ -12169,7 +12241,9 @@ async function destroyStackInRegion(stackName, state, ctx, stackScope) {
12169
12241
  refuseMalformedResourceEntriesForDestroy(recheck.state, stackName, regionForState, refusalRecovery);
12170
12242
  refuseMalformedOrphansForDestroy(recheck.state, stackName, regionForState, refusalRecovery);
12171
12243
  refuseMalformedOrphanRecordsForDestroy(recheck.state, stackName, regionForState, refusalRecovery);
12244
+ refusePendingMovesOut(recheck.state, stackName, regionForState, "cdkd destroy");
12172
12245
  }
12246
+ refuseRefactorMarker(await readRefactorMarker(ctx.stateBackend), stackName, regionForState, "cdkd destroy");
12173
12247
  const recheckResources = recheck ? Object.keys(recheck.state.resources).length : 0;
12174
12248
  const recheckOrphans = recheck ? (recheck.state.orphans ?? []).length : 0;
12175
12249
  const recheckRead = await loadJournaledOrphans(ctx.stateBackend, stackName, regionForState, recheck?.state.orphans, journaledOrphans.unreadable === true ? { warn: () => void 0 } : logger);
@@ -12301,6 +12375,23 @@ async function destroyStackInRegion(stackName, state, ctx, stackScope) {
12301
12375
  },
12302
12376
  onAcquireFailure: restoreBaseRegionAndClients
12303
12377
  });
12378
+ try {
12379
+ const [current, marker] = await Promise.all([ctx.stateBackend.getState(stackName, regionForState), readRefactorMarker(ctx.stateBackend)]);
12380
+ if (current === null || !holdsSameResourcesAs(state, current.state)) throw new CdkdError(safeMsg`cdkd destroy refused stack ${stackName} (${regionForState}): its state ` + "changed after it was read (another command wrote it while this one waited for confirmation), so nothing was deleted. Re-run cdkd destroy.", "STATE_CHANGED");
12381
+ if (current.state.terminationProtection === true && ctx.removeProtection !== true) throw new StackTerminationProtectionError(stackName, void 0, {
12382
+ args: accountArgs(refusalRecovery),
12383
+ clause: withheldAccountClause(refusalRecovery, "the command below prints")
12384
+ }, {
12385
+ command: ctx.stateDestroy === true ? "cdkd state destroy" : "cdkd destroy",
12386
+ stackRegion: regionForState
12387
+ });
12388
+ refusePendingMovesOut(current.state, stackName, regionForState, "cdkd destroy");
12389
+ refuseRefactorMarker(marker, stackName, regionForState, "cdkd destroy");
12390
+ } catch (error) {
12391
+ await lock.release({ failureMessage: "Failed to release lock after a state re-check refusal" });
12392
+ restoreBaseRegionAndClients();
12393
+ throw error;
12394
+ }
12304
12395
  if (needsStrongRefCheck) {
12305
12396
  const releaseThenUnregister = async () => {
12306
12397
  await lock.release({ failureMessage: "Failed to release lock after strong-ref refusal/failure" });
@@ -12545,7 +12636,7 @@ async function destroyStackInRegion(stackName, state, ctx, stackScope) {
12545
12636
  if (policy === "Snapshot" && ctx.skipFinalSnapshot !== true) {
12546
12637
  if (ATOMIC_FINAL_SNAPSHOT_TYPES.has(resource.resourceType) && resource.provisionedBy !== "cc-api") finalSnapshotIdentifier = buildFinalSnapshotIdentifier(resource.physicalId, resource.resourceType);
12547
12638
  else if (ATOMIC_FINAL_SNAPSHOT_TYPES.has(resource.resourceType)) throw ccRoutedFinalSnapshotError(logicalId, resource.resourceType, "--skip-final-snapshot");
12548
- else if (PRE_DELETE_SNAPSHOT_TYPES.has(resource.resourceType)) await createPreDeleteFinalSnapshot(resource.resourceType, resource.physicalId, logicalId, destroyAwsClients ?? ctx.baseAwsClients, logger);
12639
+ else if (PRE_DELETE_SNAPSHOT_TYPES.has(resource.resourceType)) await createPreDeleteFinalSnapshot(resource.resourceType, resource.physicalId, logicalId, destroyAwsClients ?? ctx.baseAwsClients, maskedSnapshotLogger(logger, createUnionSecretMasker([printingBagOf(logicalId)])));
12549
12640
  else throw unsupportedFinalSnapshotError(logicalId, resource.resourceType, "--skip-final-snapshot");
12550
12641
  }
12551
12642
  const provider = destroyProviderRegistry.getProviderFor({
@@ -12675,7 +12766,7 @@ async function destroyStackInRegion(stackName, state, ctx, stackScope) {
12675
12766
  } catch (error) {
12676
12767
  renderer.removeTask(logicalId);
12677
12768
  const msg = describeAwsFailure(error).detail;
12678
- if (!isInterruptedWaitError(error) && !isFinalSnapshotError(error) && !isMarkedNonRetryable(error) && !isWaitAbandonedError(error) && (msg.includes("does not exist") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException"))) {
12769
+ if (!isInterruptedWaitError(error) && !isFinalSnapshotError(error) && !isMarkedNonRetryable(error) && !isWaitAbandonedError(error) && !isMarkedNotGone(error) && (msg.includes("does not exist") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException"))) {
12679
12770
  logger.debug(` ${displaySafe(logicalId)} already deleted, removing from state`);
12680
12771
  result.deletedCount++;
12681
12772
  recordDestroyEvent(ctx.eventRecorder, {
@@ -13270,6 +13361,18 @@ async function destroyCommand(stackArgs, options) {
13270
13361
  logger.warn(`No state found for stack ${displaySafe(stackName)}, skipping`);
13271
13362
  continue;
13272
13363
  }
13364
+ if (synthStack?.terminationProtection !== true && stateResult.state.terminationProtection === true) {
13365
+ if (options.removeProtection) logger.warn(safeMsg`Stack ${stackName} was deployed with terminationProtection: true — bypassing because --remove-protection set`);
13366
+ else {
13367
+ const err = new StackTerminationProtectionError(stackName, void 0, {
13368
+ args: stateCommandAccount.args,
13369
+ clause: withheldAccountClause(accountRecovery, "the command below prints")
13370
+ }, { command: "cdkd destroy" });
13371
+ logger.error(safeMsg` ✗ ${asIsMessage(err.message)}`);
13372
+ totalErrors++;
13373
+ continue;
13374
+ }
13375
+ }
13273
13376
  if (stateResult.state.parentStack) {
13274
13377
  const err = new NestedStackChildDirectDestroyError(stackName, stateResult.state.parentStack, stateResult.state.parentLogicalId, void 0, stateCommandAccount);
13275
13378
  logger.error(` ✗ ${err.message}`);
@@ -13539,6 +13642,160 @@ async function dropFailedJournalEntry(args) {
13539
13642
  }
13540
13643
  }
13541
13644
 
13645
+ //#endregion
13646
+ //#region src/cli/interactive-select.ts
13647
+ const ARM_DELAY_MS = 50;
13648
+ const FILTER_CHAR = /^[\p{L}\p{N}\p{P}\p{S} ]$/u;
13649
+ function isInteractiveTerminal(streams) {
13650
+ return streams.input.isTTY === true && typeof streams.input.setRawMode === "function" && streams.output.isTTY === true;
13651
+ }
13652
+ function filterItems(items, filter) {
13653
+ const needle = filter.toLowerCase();
13654
+ return needle === "" ? [...items] : items.filter((i) => i.label.toLowerCase().includes(needle));
13655
+ }
13656
+ function renderSelectFrame(title, visible, cursor, filter, pageSize) {
13657
+ const lines = [title];
13658
+ if (filter !== "") lines.push(` filter: ${filter}`);
13659
+ if (visible.length === 0) lines.push(" (no match)");
13660
+ else {
13661
+ const start = Math.min(Math.max(0, cursor - Math.floor(pageSize / 2)), Math.max(0, visible.length - pageSize));
13662
+ const end = Math.min(visible.length, start + pageSize);
13663
+ if (start > 0) lines.push(` ... ${start} more above`);
13664
+ for (let i = start; i < end; i++) lines.push(`${i === cursor ? "> " : " "}${visible[i].label}`);
13665
+ if (end < visible.length) lines.push(` ... ${visible.length - end} more below`);
13666
+ }
13667
+ lines.push(" (up/down move, type to filter, Enter select, Esc back, Ctrl+C quit)");
13668
+ return lines;
13669
+ }
13670
+ function fitToWidth(line, columns) {
13671
+ if (typeof columns !== "number" || columns < 2) return line;
13672
+ const chars = [...line];
13673
+ return chars.length < columns ? line : `${chars.slice(0, columns - 2).join("")}…`;
13674
+ }
13675
+ function selectFromList(title, items, streams) {
13676
+ const { input, output } = streams;
13677
+ const rows = typeof output.rows === "number" && output.rows > 0 ? output.rows : 24;
13678
+ const pageSize = Math.max(3, Math.min(15, rows - 5));
13679
+ let filter = "";
13680
+ let cursor = 0;
13681
+ let drawn = 0;
13682
+ const erase = () => {
13683
+ if (drawn > 0) output.write(`\x1b[${drawn}F\x1b[0J`);
13684
+ drawn = 0;
13685
+ };
13686
+ const draw = () => {
13687
+ erase();
13688
+ const lines = renderSelectFrame(title, filterItems(items, filter), cursor, filter, pageSize).map((line) => fitToWidth(line, output.columns));
13689
+ output.write(`${lines.join("\n")}\n`);
13690
+ drawn = lines.length;
13691
+ };
13692
+ return new Promise((resolve, reject) => {
13693
+ emitKeypressEvents(input);
13694
+ input.setRawMode?.(true);
13695
+ input.resume();
13696
+ let armed = false;
13697
+ const armTimer = setTimeout(() => {
13698
+ armed = true;
13699
+ }, streams.armDelayMs ?? ARM_DELAY_MS);
13700
+ const finish = (result) => {
13701
+ clearTimeout(armTimer);
13702
+ input.removeListener("keypress", onKey);
13703
+ input.setRawMode?.(false);
13704
+ input.pause();
13705
+ erase();
13706
+ resolve(result);
13707
+ };
13708
+ const onKey = (str, key) => {
13709
+ if (!armed) return;
13710
+ const visible = filterItems(items, filter);
13711
+ const name = key?.name;
13712
+ if (key?.ctrl === true && (name === "c" || name === "d")) return finish({ kind: "quit" });
13713
+ if (name === "escape") return finish({ kind: "back" });
13714
+ if (name === "return" || name === "enter") {
13715
+ const picked = visible[cursor];
13716
+ if (picked !== void 0) return finish({
13717
+ kind: "picked",
13718
+ value: picked.value
13719
+ });
13720
+ return;
13721
+ }
13722
+ if (name === "up" || key?.ctrl === true && name === "p") cursor = visible.length === 0 ? 0 : (cursor - 1 + visible.length) % visible.length;
13723
+ else if (name === "down" || key?.ctrl === true && name === "n") cursor = visible.length === 0 ? 0 : (cursor + 1) % visible.length;
13724
+ else if (name === "backspace") {
13725
+ filter = filter.slice(0, -1);
13726
+ cursor = 0;
13727
+ } else if (typeof str === "string" && key?.ctrl !== true && key?.meta !== true && FILTER_CHAR.test(str)) {
13728
+ filter += str;
13729
+ cursor = 0;
13730
+ } else return;
13731
+ draw();
13732
+ };
13733
+ input.on("keypress", onKey);
13734
+ try {
13735
+ draw();
13736
+ } catch (error) {
13737
+ clearTimeout(armTimer);
13738
+ input.removeListener("keypress", onKey);
13739
+ input.setRawMode?.(false);
13740
+ input.pause();
13741
+ reject(error);
13742
+ }
13743
+ });
13744
+ }
13745
+
13746
+ //#endregion
13747
+ //#region src/cli/commands/state-browse.ts
13748
+ const VIEW_ITEMS = [
13749
+ {
13750
+ label: "Resources (logical id, type, physical id)",
13751
+ value: "resources"
13752
+ },
13753
+ {
13754
+ label: "Resources with dependencies and attributes",
13755
+ value: "resources-long"
13756
+ },
13757
+ {
13758
+ label: "Full state record (cdkd state show)",
13759
+ value: "show"
13760
+ },
13761
+ {
13762
+ label: "Back to the stack list",
13763
+ value: "back"
13764
+ }
13765
+ ];
13766
+ function nonInteractiveBrowseRefusal() {
13767
+ return new CdkdError("cdkd state browse needs an interactive terminal. Without one, use cdkd state list, cdkd state resources <stack> and cdkd state show <stack>.", "NON_INTERACTIVE");
13768
+ }
13769
+ async function runStateBrowse(deps) {
13770
+ if (!isInteractiveTerminal(deps.streams)) throw nonInteractiveBrowseRefusal();
13771
+ const refs = await deps.listStacks();
13772
+ if (refs.length === 0) {
13773
+ deps.streams.output.write("No stacks in the state bucket.\n");
13774
+ return;
13775
+ }
13776
+ const stackItems = refs.map((ref) => ({
13777
+ label: deps.label(ref),
13778
+ value: ref
13779
+ }));
13780
+ for (;;) {
13781
+ const stack = await selectFromList("Select a stack:", stackItems, deps.streams);
13782
+ if (stack.kind !== "picked") return;
13783
+ for (;;) {
13784
+ const title = `${deps.label(stack.value)}:`;
13785
+ const view = await selectFromList(title, VIEW_ITEMS, deps.streams);
13786
+ if (view.kind === "quit") return;
13787
+ if (view.kind === "back" || view.value === "back") break;
13788
+ deps.streams.output.write(`\n${title}\n`);
13789
+ try {
13790
+ await deps.printView(view.value, stack.value);
13791
+ } catch (error) {
13792
+ deps.reportError(error);
13793
+ }
13794
+ deps.streams.output.write("\n");
13795
+ }
13796
+ }
13797
+ }
13798
+
13542
13799
  //#endregion
13543
13800
  //#region src/deployment/public-ssm-proof.ts
13544
13801
  var PublicSsmProver = class {
@@ -18173,59 +18430,63 @@ async function stateResourcesCommand(stackName, options) {
18173
18430
  if (options.json) reserveStdoutForPayload();
18174
18431
  const setup = await setupStateBackend(options);
18175
18432
  try {
18176
- const ref = resolveSingleRegion(stackName, await setup.stateBackend.listStacks(), options.stackRegion);
18177
- if (!ref.region) throw legacyRecordRefusal(stackName);
18178
- const stateResult = await setup.stateBackend.getState(stackName, ref.region);
18179
- if (!stateResult) throw new Error(`No state found for stack ${formatStackRefSafe(ref)} in s3://${setup.bucket}/${setup.prefix}/. Run 'cdkd state list' to see available stacks.`);
18180
- if (repairMalformedResourcesForReadOnly(stateResult.state)) logger.warn(malformedResourcesWarning(stackName, ref.region, renderRecovery(options, setup)));
18181
- if (options.long || options.json) repairRenderedContainers(stateResult.state, RESOURCES_RENDERED_CONTAINERS, stackName, ref.region, logger, renderRecovery(options, setup));
18182
- const resources = stateResult.state.resources;
18183
- const details = Object.entries(resources).map(([logicalId, entry]) => {
18184
- const resource = entry ?? {};
18185
- return {
18186
- logicalId,
18187
- resourceType: resource.resourceType,
18188
- physicalId: resource.physicalId,
18189
- dependencies: resource.dependencies ?? [],
18190
- attributes: resource.attributes ?? {}
18191
- };
18192
- }).sort((a, b) => a.logicalId.localeCompare(b.logicalId));
18193
- if (options.json) {
18194
- process.stdout.write(`${stringifyJsonPayload(details)}\n`);
18195
- return;
18196
- }
18197
- if (details.length === 0) return;
18198
- if (options.long) {
18199
- const lines = [];
18200
- for (const detail of details) {
18201
- lines.push(stripForDisplay(detail.logicalId));
18202
- lines.push(` Type: ${formatAttributeValue(detail.resourceType)}`);
18203
- lines.push(` PhysicalID: ${formatAttributeValue(detail.physicalId)}`);
18204
- lines.push(` Dependencies: ${formatDependencyList(detail.dependencies)}`);
18205
- const attrEntries = Object.entries(detail.attributes);
18206
- if (attrEntries.length === 0) lines.push(" Attributes: (none)");
18207
- else {
18208
- lines.push(" Attributes:");
18209
- for (const [k, v] of attrEntries) lines.push(` ${stripForDisplay(k)}: ${formatAttributeValue(v)}`);
18210
- }
18211
- lines.push("");
18212
- }
18213
- if (lines[lines.length - 1] === "") lines.pop();
18214
- process.stdout.write(`${lines.join("\n")}\n`);
18215
- return;
18216
- }
18217
- const rows = details.map((d) => ({
18218
- logicalId: stripForDisplay(d.logicalId),
18219
- resourceType: formatAttributeValue(d.resourceType),
18220
- physicalId: formatAttributeValue(d.physicalId)
18221
- }));
18222
- const idWidth = Math.max(...rows.map((r) => r.logicalId.length));
18223
- const typeWidth = Math.max(...rows.map((r) => r.resourceType.length));
18224
- for (const row of rows) process.stdout.write(`${row.logicalId.padEnd(idWidth)} ${row.resourceType.padEnd(typeWidth)} ${row.physicalId}\n`);
18433
+ await printStackResources(stackName, options, setup);
18225
18434
  } finally {
18226
18435
  setup.dispose();
18227
18436
  }
18228
18437
  }
18438
+ async function printStackResources(stackName, options, setup) {
18439
+ const logger = getLogger();
18440
+ const ref = resolveSingleRegion(stackName, await setup.stateBackend.listStacks(), options.stackRegion);
18441
+ if (!ref.region) throw legacyRecordRefusal(stackName);
18442
+ const stateResult = await setup.stateBackend.getState(stackName, ref.region);
18443
+ if (!stateResult) throw new Error(`No state found for stack ${formatStackRefSafe(ref)} in s3://${setup.bucket}/${setup.prefix}/. Run 'cdkd state list' to see available stacks.`);
18444
+ if (repairMalformedResourcesForReadOnly(stateResult.state)) logger.warn(malformedResourcesWarning(stackName, ref.region, renderRecovery(options, setup)));
18445
+ if (options.long || options.json) repairRenderedContainers(stateResult.state, RESOURCES_RENDERED_CONTAINERS, stackName, ref.region, logger, renderRecovery(options, setup));
18446
+ const resources = stateResult.state.resources;
18447
+ const details = Object.entries(resources).map(([logicalId, entry]) => {
18448
+ const resource = entry ?? {};
18449
+ return {
18450
+ logicalId,
18451
+ resourceType: resource.resourceType,
18452
+ physicalId: resource.physicalId,
18453
+ dependencies: resource.dependencies ?? [],
18454
+ attributes: resource.attributes ?? {}
18455
+ };
18456
+ }).sort((a, b) => a.logicalId.localeCompare(b.logicalId));
18457
+ if (options.json) {
18458
+ process.stdout.write(`${stringifyJsonPayload(details)}\n`);
18459
+ return;
18460
+ }
18461
+ if (details.length === 0) return;
18462
+ if (options.long) {
18463
+ const lines = [];
18464
+ for (const detail of details) {
18465
+ lines.push(stripForDisplay(detail.logicalId));
18466
+ lines.push(` Type: ${formatAttributeValue(detail.resourceType)}`);
18467
+ lines.push(` PhysicalID: ${formatAttributeValue(detail.physicalId)}`);
18468
+ lines.push(` Dependencies: ${formatDependencyList(detail.dependencies)}`);
18469
+ const attrEntries = Object.entries(detail.attributes);
18470
+ if (attrEntries.length === 0) lines.push(" Attributes: (none)");
18471
+ else {
18472
+ lines.push(" Attributes:");
18473
+ for (const [k, v] of attrEntries) lines.push(` ${stripForDisplay(k)}: ${formatAttributeValue(v)}`);
18474
+ }
18475
+ lines.push("");
18476
+ }
18477
+ if (lines[lines.length - 1] === "") lines.pop();
18478
+ process.stdout.write(`${lines.join("\n")}\n`);
18479
+ return;
18480
+ }
18481
+ const rows = details.map((d) => ({
18482
+ logicalId: stripForDisplay(d.logicalId),
18483
+ resourceType: formatAttributeValue(d.resourceType),
18484
+ physicalId: formatAttributeValue(d.physicalId)
18485
+ }));
18486
+ const idWidth = Math.max(...rows.map((r) => r.logicalId.length));
18487
+ const typeWidth = Math.max(...rows.map((r) => r.resourceType.length));
18488
+ for (const row of rows) process.stdout.write(`${row.logicalId.padEnd(idWidth)} ${row.resourceType.padEnd(typeWidth)} ${row.physicalId}\n`);
18489
+ }
18229
18490
  function formatAttributeValue(value) {
18230
18491
  if (value === null) return "null";
18231
18492
  if (value === void 0) return "undefined";
@@ -18270,34 +18531,38 @@ async function stateShowCommand(stackName, options) {
18270
18531
  if (options.json) reserveStdoutForPayload();
18271
18532
  const setup = await setupStateBackend(options);
18272
18533
  try {
18273
- const ref = resolveSingleRegion(stackName, await setup.stateBackend.listStacks(), options.stackRegion);
18274
- if (!ref.region) throw legacyRecordRefusal(stackName);
18275
- const [stateResult, lockInfo] = await Promise.all([setup.stateBackend.getState(stackName, ref.region), setup.lockManager.getLockInfo(stackName, ref.region)]);
18276
- if (!stateResult) throw new Error(`No state found for stack ${formatStackRefSafe(ref)} in s3://${setup.bucket}/${setup.prefix}/. Run 'cdkd state list' to see available stacks.`);
18277
- if (options.showNested) {
18278
- const treeWithLocks = await loadLocksForTree(await buildCdkdStateStackTree(stackName, ref.region, setup.stateBackend, stateResult.state, renderRecovery(options, setup)), setup.lockManager, lockInfo);
18279
- if (options.json) {
18280
- warnUnreadableTreeNodes(treeWithLocks, logger, renderRecovery(options, setup));
18281
- process.stdout.write(`${stringifyJsonPayload(treeToShowJson(treeWithLocks))}\n`);
18282
- return;
18283
- }
18284
- repairTreeForTextRender(treeWithLocks, logger, renderRecovery(options, setup));
18285
- const lines = renderTreeWithChildren(treeWithLocks);
18286
- process.stdout.write(`${lines.join("\n")}\n`);
18287
- return;
18288
- }
18534
+ await printStackShow(stackName, options, setup);
18535
+ } finally {
18536
+ setup.dispose();
18537
+ }
18538
+ }
18539
+ async function printStackShow(stackName, options, setup) {
18540
+ const logger = getLogger();
18541
+ const ref = resolveSingleRegion(stackName, await setup.stateBackend.listStacks(), options.stackRegion);
18542
+ if (!ref.region) throw legacyRecordRefusal(stackName);
18543
+ const [stateResult, lockInfo] = await Promise.all([setup.stateBackend.getState(stackName, ref.region), setup.lockManager.getLockInfo(stackName, ref.region)]);
18544
+ if (!stateResult) throw new Error(`No state found for stack ${formatStackRefSafe(ref)} in s3://${setup.bucket}/${setup.prefix}/. Run 'cdkd state list' to see available stacks.`);
18545
+ if (options.showNested) {
18546
+ const treeWithLocks = await loadLocksForTree(await buildCdkdStateStackTree(stackName, ref.region, setup.stateBackend, stateResult.state, renderRecovery(options, setup)), setup.lockManager, lockInfo);
18289
18547
  if (options.json) {
18290
- process.stdout.write(`${stringifyJsonPayload({
18291
- state: withStackInstanceIdWithheld(stateResult.state),
18292
- lock: lockInfo
18293
- })}\n`);
18548
+ warnUnreadableTreeNodes(treeWithLocks, logger, renderRecovery(options, setup));
18549
+ process.stdout.write(`${stringifyJsonPayload(treeToShowJson(treeWithLocks))}\n`);
18294
18550
  return;
18295
18551
  }
18296
- repairRecordForTextRender(stateResult.state, stackName, ref.region, logger, renderRecovery(options, setup));
18297
- process.stdout.write(`${renderStateBlock(stateResult.state, lockInfo, true).join("\n")}\n`);
18298
- } finally {
18299
- setup.dispose();
18552
+ repairTreeForTextRender(treeWithLocks, logger, renderRecovery(options, setup));
18553
+ const lines = renderTreeWithChildren(treeWithLocks);
18554
+ process.stdout.write(`${lines.join("\n")}\n`);
18555
+ return;
18556
+ }
18557
+ if (options.json) {
18558
+ process.stdout.write(`${stringifyJsonPayload({
18559
+ state: withStackInstanceIdWithheld(stateResult.state),
18560
+ lock: lockInfo
18561
+ })}\n`);
18562
+ return;
18300
18563
  }
18564
+ repairRecordForTextRender(stateResult.state, stackName, ref.region, logger, renderRecovery(options, setup));
18565
+ process.stdout.write(`${renderStateBlock(stateResult.state, lockInfo, true).join("\n")}\n`);
18301
18566
  }
18302
18567
  const SKIPPED_DIGEST_PREVIEW_LEN = 12;
18303
18568
  const UNSERIALIZABLE = "(unserializable)";
@@ -18715,6 +18980,20 @@ function createStateOrphanCommand() {
18715
18980
  cmd.addOption(deprecatedRegionOption);
18716
18981
  return cmd;
18717
18982
  }
18983
+ async function protectedRootOf(stackName, state, region, backend) {
18984
+ let name = stackName;
18985
+ let record = state;
18986
+ const seen = /* @__PURE__ */ new Set();
18987
+ for (let depth = 0; record !== void 0 && depth < 32; depth++) {
18988
+ if (record.terminationProtection === true) return name;
18989
+ const parent = record.parentStack;
18990
+ if (typeof parent !== "string" || parent === "" || seen.has(parent)) return void 0;
18991
+ seen.add(name);
18992
+ const parentRegion = typeof record.parentRegion === "string" ? record.parentRegion : region;
18993
+ name = parent;
18994
+ record = (await backend.getState(parent, parentRegion))?.state;
18995
+ }
18996
+ }
18718
18997
  async function stateDestroyCommand(stackArgs, options) {
18719
18998
  if (options.all) throw new CdkdError(`cdkd state destroy no longer accepts --all: it destroyed every stack in the state bucket, which every CDK app deployed to this account shares, so one command reached across apps. Name each stack to destroy: cdkd state destroy ${commandHole("stacks...")} (cdkd state list shows them), or run cdkd destroy --all from the CDK app, which destroys only that app's top-level stacks (cdkd destroy '**' destroys its CDK Stage stacks too).`, "STATE_DESTROY_ALL_REMOVED");
18720
18999
  const providerClasses = await loadProviderClasses();
@@ -18789,6 +19068,24 @@ async function stateDestroyCommand(stackArgs, options) {
18789
19068
  logger.warn(safeMsg`No state found for stack ${displayStackName(stackName)}` + (ref.region ? safeMsg` in ${displayIdent(ref.region)}` : "") + ", skipping");
18790
19069
  continue;
18791
19070
  }
19071
+ const protectedRoot = await protectedRootOf(stackName, stateResult.state, refRegion, setup.stateBackend);
19072
+ if (protectedRoot !== void 0) {
19073
+ if (options.removeProtection === true) logger.warn(safeMsg`Stack ${displayStackName(protectedRoot)} was deployed with terminationProtection: true — bypassing because --remove-protection set`);
19074
+ else {
19075
+ const recovery = renderRecovery(options, setup);
19076
+ const err = new StackTerminationProtectionError(stackName, void 0, {
19077
+ args: accountArgs(recovery),
19078
+ clause: withheldAccountClause(recovery, "the command below prints")
19079
+ }, {
19080
+ command: "cdkd state destroy",
19081
+ stackRegion: refRegion,
19082
+ ...protectedRoot !== stackName && { root: protectedRoot }
19083
+ });
19084
+ logger.error(safeMsg` ✗ ${asIsMessage(err.message)}`);
19085
+ totalErrors++;
19086
+ continue;
19087
+ }
19088
+ }
18792
19089
  if (runInterrupted()) {
18793
19090
  stoppedEarly = true;
18794
19091
  break;
@@ -18835,6 +19132,7 @@ async function stateDestroyCommand(stackArgs, options) {
18835
19132
  statePrefix: options.statePrefix,
18836
19133
  skipConfirmation: options.yes,
18837
19134
  removeProtection: options.removeProtection === true,
19135
+ stateDestroy: true,
18838
19136
  skipFinalSnapshot: options.skipFinalSnapshot === true,
18839
19137
  resolveSecretDerivedPrincipals: {},
18840
19138
  stackDestroy: true,
@@ -18889,7 +19187,7 @@ async function stateDestroyCommand(stackArgs, options) {
18889
19187
  }
18890
19188
  }
18891
19189
  function createStateDestroyCommand() {
18892
- const cmd = new Command("destroy").description("Destroy a stack's AWS resources and remove its state record without requiring the CDK app. For removing only the state record (keeping AWS resources intact), use 'cdkd state orphan'.").argument("[stacks...]", "Stack name(s) to destroy (physical CloudFormation names)").addOption(new Option("--all").hideHelp()).option("--remove-protection", `Bypass deletion protection on protected resources by flipping the per-resource protection flag off in-place before delete. Covers ${removeProtectionTypeList()}.`, false).addOption(stackRegionOption$1()).addHelpText("after", [
19190
+ const cmd = new Command("destroy").description("Destroy a stack's AWS resources and remove its state record without requiring the CDK app. For removing only the state record (keeping AWS resources intact), use 'cdkd state orphan'.").argument("[stacks...]", "Stack name(s) to destroy (physical CloudFormation names)").addOption(new Option("--all").hideHelp()).option("--remove-protection", `Destroy a stack deployed with terminationProtection: true, and bypass deletion protection on protected resources by flipping the per-resource protection flag off in-place before delete. Covers ${removeProtectionTypeList()}.`, false).addOption(stackRegionOption$1()).addHelpText("after", [
18893
19191
  "",
18894
19192
  "Examples:",
18895
19193
  " cdkd state destroy MyStack",
@@ -19366,7 +19664,9 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
19366
19664
  refreshed++;
19367
19665
  } catch (err) {
19368
19666
  failed++;
19369
- logger.warn(safeMsg` ✗ ${displayStackName(stackName)}/${displayIdent(logicalId)} ` + safeMsg`(${displayIdent(resource.resourceType)}): ` + safeMsg`readCurrentState failed — ${describeAwsFailure(err).detail}`);
19667
+ if (err instanceof SyntaxError) logger.debug(safeMsg`readCurrentState parse failure for ${displayIdent(logicalId)}: ${parseFailureDebugDetail(err)}`);
19668
+ const detail = err instanceof SyntaxError ? "SyntaxError (its text is withheld: a parse error quotes the body it read)" : describeAwsFailure(err).detail;
19669
+ logger.warn(safeMsg` ✗ ${displayStackName(stackName)}/${displayIdent(logicalId)} ` + safeMsg`(${displayIdent(resource.resourceType)}): ` + safeMsg`readCurrentState failed — ${detail}`);
19370
19670
  }
19371
19671
  }));
19372
19672
  await Promise.all(tasks);
@@ -19418,9 +19718,55 @@ function createStateRefreshObservedCommand() {
19418
19718
  cmd.addOption(deprecatedRegionOption);
19419
19719
  return cmd;
19420
19720
  }
19721
+ async function stateBrowseCommand(options) {
19722
+ const logger = getLogger();
19723
+ if (options.verbose) logger.setLevel("debug");
19724
+ const streams = {
19725
+ input: process.stdin,
19726
+ output: process.stdout
19727
+ };
19728
+ if (!isInteractiveTerminal(streams)) throw nonInteractiveBrowseRefusal();
19729
+ const setup = await setupStateBackend(options);
19730
+ try {
19731
+ await runStateBrowse(stateBrowseDeps(setup, options, streams));
19732
+ } finally {
19733
+ setup.dispose();
19734
+ }
19735
+ }
19736
+ function stateBrowseDeps(setup, options, streams) {
19737
+ return {
19738
+ streams,
19739
+ listStacks: async () => sortRefs(await setup.stateBackend.listStacks()),
19740
+ label: formatStackRefSafe,
19741
+ printView: async (view, ref) => {
19742
+ if (!ref.region) throw legacyRecordRefusal(ref.stackName);
19743
+ const base = {
19744
+ ...options,
19745
+ stackRegion: ref.region,
19746
+ json: false
19747
+ };
19748
+ if (view === "show") await printStackShow(ref.stackName, {
19749
+ ...base,
19750
+ showNested: false
19751
+ }, setup);
19752
+ else await printStackResources(ref.stackName, {
19753
+ ...base,
19754
+ long: view === "resources-long"
19755
+ }, setup);
19756
+ },
19757
+ reportError: (error) => getLogger().error(formatError(error))
19758
+ };
19759
+ }
19760
+ function createStateBrowseCommand() {
19761
+ const cmd = new Command("browse").description("Pick a stack with the keyboard and view its resources or state record (needs a terminal)").action(withErrorHandling(stateBrowseCommand));
19762
+ [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
19763
+ cmd.addOption(deprecatedRegionOption);
19764
+ return cmd;
19765
+ }
19421
19766
  function createStateCommand() {
19422
19767
  const cmd = new Command("state").description("Manage cdkd state stored in S3");
19423
19768
  cmd.addCommand(createStateInfoCommand());
19769
+ cmd.addCommand(createStateBrowseCommand());
19424
19770
  cmd.addCommand(createStateListCommand());
19425
19771
  cmd.addCommand(createStateResourcesCommand());
19426
19772
  cmd.addCommand(createStateShowCommand());
@@ -20265,7 +20611,8 @@ function printRunEvents(stackName, region, runId, events) {
20265
20611
  const headShown = safeText(head);
20266
20612
  const laterShows = rest.some((line) => safeText(line) !== "");
20267
20613
  const message = !e.error.message ? "" : headShown !== "" ? `: ${headShown}` : laterShows ? "" : `: ${UNRENDERABLE}`;
20268
- logger.info(` ${red(`${name}${code}${message}`)}${reqId}`);
20614
+ const line = rest.length === 0 && headShown.startsWith(`${name}. `) ? `${name}${e.error.awsErrorCode === e.error.name ? "" : code}${headShown.slice(name.length)}` : `${name}${code}${message}`;
20615
+ logger.info(` ${red(line)}${reqId}`);
20269
20616
  for (const line of rest) {
20270
20617
  const shown = safeText(line);
20271
20618
  if (shown !== "") logger.info(red(safeMsg` ${shown}`));
@@ -20518,7 +20865,8 @@ async function scanReferencedAssets(stateBackend, marker, logger, account) {
20518
20865
  statePrefix: void 0
20519
20866
  }, "the command below prints").trimEnd(), keyPrefixHoleSentence(recovery.statePrefix)].filter((part) => part !== "").join(" ");
20520
20867
  const inspect = inspectHint === void 0 ? "its stack name is not safe to paste into a command, so inspect the object at that key directly" : `see the command below`;
20521
- throw new CdkdError(`State file ${displayIdent(key, { maxCodePoints: STATE_KEY_MAX_CODE_POINTS })} is not valid JSON — aborting: gc must know every referenced asset before deleting anything, and this file's references are unreadable. Repair or remove the corrupt state file (${inspect}), then re-run.` + (accountClause === "" ? "" : ` ${accountClause}`) + (inspectHint === void 0 ? "" : `\nInspect it with: ${inspectHint}`), "GC_STATE_UNREADABLE", error);
20868
+ logger.debug(safeMsg`State file ${displayIdent(key, { maxCodePoints: STATE_KEY_MAX_CODE_POINTS })} failed to parse: ${displaySafe(describeAwsFailure(error).detail, { asciiOnly: true }) || "<unrenderable>"}`);
20869
+ throw new CdkdError(`State file ${displayIdent(key, { maxCodePoints: STATE_KEY_MAX_CODE_POINTS })} is not valid JSON — aborting: gc must know every referenced asset before deleting anything, and this file's references are unreadable. Repair or remove the corrupt state file (${inspect}), then re-run.` + (accountClause === "" ? "" : ` ${accountClause}`) + (inspectHint === void 0 ? "" : `\nInspect it with: ${inspectHint}`), "GC_STATE_UNREADABLE");
20522
20870
  }
20523
20871
  collectAssetReferences(parsed, marker, refs);
20524
20872
  }
@@ -20847,87 +21195,1435 @@ function keyPrefixHoleSentence(prefix) {
20847
21195
  }
20848
21196
 
20849
21197
  //#endregion
20850
- //#region src/cli/commands/publish-assets.ts
20851
- async function publishAssetsCommand(stacks, options) {
20852
- const logger = getLogger();
20853
- if (options.verbose) logger.setLevel("debug");
20854
- warnIfDeprecatedRegion(options);
20855
- const rawNamedRegion = rawCliRegion(options.region);
20856
- foldRegionOption(options);
20857
- await applyRoleArnIfSet({
20858
- roleArn: options.roleArn,
20859
- region: options.region
20860
- });
20861
- const app = resolveApp(options.app);
20862
- if (!app) throw new Error("No app command specified. Use --app, set CDKD_APP env var, or add \"app\" to cdk.json");
20863
- logger.info(synthesisStatusMessage(app, "Synthesizing CDK app..."));
20864
- const synthesizer = new Synthesizer();
20865
- const context = parseContextOptions(options.context);
20866
- const synthOptions = {
20867
- app,
20868
- output: options.output,
20869
- ...options.region && { region: options.region },
20870
- ...options.profile && { profile: options.profile },
20871
- ...Object.keys(context).length > 0 && { context }
20872
- };
20873
- const { stacks: allStacks } = await synthesizer.synthesize(synthOptions);
20874
- logger.debug(`Found ${allStacks.length} stack(s) in assembly`);
20875
- const stackPatterns = stacks.length > 0 ? stacks : options.stack ? [options.stack] : [];
20876
- let targetStacks;
20877
- if (allStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
20878
- if (options.all) targetStacks = allStacks;
20879
- else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
20880
- else if (allStacks.length === 1) targetStacks = allStacks;
20881
- else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all`);
20882
- if (targetStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
20883
- const effectiveRegion = await resolveEffectiveRegion(options);
20884
- exportInferredRegionForSdk(effectiveRegion);
20885
- const baseRegion = effectiveRegion.region;
20886
- const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
20887
- const stsClient = new STSClient({
20888
- ...ambientClientDefaults(),
20889
- region: baseRegion
20890
- });
20891
- const accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
20892
- stsClient.destroy();
20893
- const useCdkBootstrapAssets = resolveUseCdkBootstrapAssets(options.useCdkBootstrapAssets);
20894
- let markerAccess;
20895
- const getModeResolver = async () => {
20896
- if (markerAccess !== void 0) return markerAccess?.resolver ?? null;
20897
- let bucket;
20898
- try {
20899
- bucket = await resolveStateBucketWithDefault(options.stateBucket, baseRegion, legacyStateBucketFallbackRegion(effectiveRegion));
20900
- } catch {
20901
- logger.info("No cdkd state bucket found — publishing to the asset-manifest destinations (CDK bootstrap storage) verbatim. Run 'cdkd bootstrap' to opt into cdkd-owned asset storage that 'cdk gc' never touches.");
20902
- markerAccess = null;
20903
- return null;
21198
+ //#region src/state/logical-id-rename.ts
21199
+ function applyLogicalIdRenames(state, renames, template) {
21200
+ const byFrom = /* @__PURE__ */ new Map();
21201
+ const targets = /* @__PURE__ */ new Set();
21202
+ for (const { from, to } of renames) {
21203
+ if (!hasOwnKey(state.resources, from)) throw new Error(`Logical ID ${from} is not in the stack's state`);
21204
+ if (hasOwnKey(state.resources, to)) throw new Error(`Logical ID ${to} is already in the stack's state`);
21205
+ if (byFrom.has(from) || targets.has(to) || from === to) throw new Error(`Logical ID ${from} -> ${to} is named more than once`);
21206
+ byFrom.set(from, to);
21207
+ targets.add(to);
21208
+ }
21209
+ const retiredBefore = state.retiredNameGenerations ?? {};
21210
+ const resources = {};
21211
+ const leaving = [];
21212
+ for (const [logicalId, record] of Object.entries(state.resources)) {
21213
+ const to = byFrom.get(logicalId);
21214
+ if (to === void 0) {
21215
+ defineOwnKey(resources, logicalId, rewriteRecordReferences(record, byFrom));
21216
+ continue;
20904
21217
  }
20905
- const markerClients = new AwsClients({
20906
- region: baseRegion,
20907
- ...options.profile && { profile: options.profile }
20908
- });
20909
- const backend = new S3StateBackend(markerClients.s3, {
20910
- bucket,
20911
- prefix: options.statePrefix
20912
- }, {
20913
- region: baseRegion,
20914
- ...options.profile && { profile: options.profile }
21218
+ leaving.push({
21219
+ logicalId,
21220
+ record
20915
21221
  });
20916
- const resolver = new AssetModeResolver(backend, accountId, { ...options.profile && { profile: options.profile } });
20917
- markerAccess = {
20918
- resolver,
20919
- regionFor: stackRegionResolver({
20920
- effective: effectiveRegion,
20921
- probe: backend,
20922
- logger,
20923
- siblings: allStacks.filter((s) => !s.region).map((s) => s.stackName)
20924
- }),
20925
- dispose: () => markerClients.destroy()
20926
- };
20927
- return resolver;
21222
+ const constructPath = constructPathOf(template, to);
21223
+ const retiredTo = hasOwnKey(retiredBefore, to) ? retiredBefore[to] : void 0;
21224
+ const moved = withNameGenerationReached({
21225
+ ...rewriteRecordReferences(record, byFrom),
21226
+ ...constructPath !== void 0 && { constructPath }
21227
+ }, to, retiredTo);
21228
+ defineOwnKey(resources, to, moved);
21229
+ }
21230
+ const { skippedOutputs: _dropped, ...rest } = state;
21231
+ const retired = retiredNameGenerationsAfter(state, leaving);
21232
+ return {
21233
+ ...rest,
21234
+ ...stackInstanceIdCarriedFrom(state),
21235
+ resources,
21236
+ ...retired,
21237
+ ...Array.isArray(state.supersededResources) && { supersededResources: state.supersededResources.map((entry) => {
21238
+ if (entry === null || typeof entry !== "object") return entry;
21239
+ const to = byFrom.get(entry.logicalId);
21240
+ return {
21241
+ ...entry,
21242
+ ...to !== void 0 && { logicalId: to },
21243
+ state: rewriteRecordReferences(entry.state, byFrom)
21244
+ };
21245
+ }) },
21246
+ ...Array.isArray(state.orphans) && { orphans: state.orphans.map((entry) => entry === null || typeof entry !== "object" ? entry : {
21247
+ ...entry,
21248
+ state: rewriteRecordReferences(entry.state, byFrom)
21249
+ }) },
21250
+ lastModified: Date.now()
20928
21251
  };
20929
- const regionForStack = async (stack) => {
20930
- if (stack.region) return stack.region;
21252
+ }
21253
+ function constructPathOf(template, logicalId) {
21254
+ const resources = template.Resources ?? {};
21255
+ if (!hasOwnKey(resources, logicalId)) return void 0;
21256
+ const metadata = resources[logicalId].Metadata;
21257
+ if (metadata === null || typeof metadata !== "object") return void 0;
21258
+ const path = metadata["aws:cdk:path"];
21259
+ return typeof path === "string" ? path : void 0;
21260
+ }
21261
+ function rewriteRecordReferences(record, renames) {
21262
+ if (record === null || typeof record !== "object" || !hasPlainPrototype(record)) return record;
21263
+ const out = { ...record };
21264
+ if (Array.isArray(record.dependencies)) {
21265
+ const seen = /* @__PURE__ */ new Set();
21266
+ out.dependencies = [];
21267
+ for (const dependency of record.dependencies) {
21268
+ const renamed = typeof dependency === "string" ? renames.get(dependency) ?? dependency : dependency;
21269
+ if (typeof renamed === "string") {
21270
+ if (seen.has(renamed)) continue;
21271
+ seen.add(renamed);
21272
+ }
21273
+ out.dependencies.push(renamed);
21274
+ }
21275
+ }
21276
+ if (record.properties !== void 0) out.properties = renameReferencesInValue(record.properties, renames);
21277
+ if (record.attributes !== void 0) out.attributes = renameReferencesInValue(record.attributes, renames);
21278
+ return out;
21279
+ }
21280
+ function renameReferencesInValue(value, renames) {
21281
+ if (Array.isArray(value)) return value.map((item) => renameReferencesInValue(item, renames));
21282
+ if (value === null || typeof value !== "object" || !hasPlainPrototype(value)) return value;
21283
+ const entries = Object.entries(value);
21284
+ if (entries.length === 1) {
21285
+ const [key, arg] = entries[0];
21286
+ if (key === "Ref" && typeof arg === "string") return { Ref: renames.get(arg) ?? arg };
21287
+ if (key === "Fn::GetAtt") return { "Fn::GetAtt": renameGetAttArgument(arg, renames) };
21288
+ if (key === "Fn::Sub") return { "Fn::Sub": renameSubArgument(arg, renames) };
21289
+ }
21290
+ const out = {};
21291
+ for (const [key, item] of entries) defineOwnKey(out, key, renameReferencesInValue(item, renames));
21292
+ return out;
21293
+ }
21294
+ function renameGetAttArgument(arg, renames) {
21295
+ if (Array.isArray(arg) && arg.length >= 1 && typeof arg[0] === "string") {
21296
+ const [target, ...rest] = arg;
21297
+ return [renames.get(target) ?? target, ...rest.map((item) => renameReferencesInValue(item, renames))];
21298
+ }
21299
+ if (typeof arg === "string") {
21300
+ const dot = arg.indexOf(".");
21301
+ if (dot > 0) {
21302
+ const target = arg.slice(0, dot);
21303
+ const renamed = renames.get(target);
21304
+ if (renamed !== void 0) return `${renamed}${arg.slice(dot)}`;
21305
+ }
21306
+ return arg;
21307
+ }
21308
+ return renameReferencesInValue(arg, renames);
21309
+ }
21310
+ function renameSubArgument(arg, renames) {
21311
+ if (typeof arg === "string") return renameSubTemplate(arg, renames, /* @__PURE__ */ new Set());
21312
+ if (Array.isArray(arg) && arg.length >= 1 && typeof arg[0] === "string") {
21313
+ const variables = arg[1];
21314
+ const shadowed = new Set(variables !== null && typeof variables === "object" && !Array.isArray(variables) ? Object.keys(variables) : []);
21315
+ return [renameSubTemplate(arg[0], renames, shadowed), ...arg.slice(1).map((item) => renameReferencesInValue(item, renames))];
21316
+ }
21317
+ return renameReferencesInValue(arg, renames);
21318
+ }
21319
+ function renameSubTemplate(template, renames, shadowed) {
21320
+ return template.replace(/\$\{([^}]*)\}/g, (whole, inner) => {
21321
+ if (inner.startsWith("!")) return whole;
21322
+ const dot = inner.indexOf(".");
21323
+ const target = dot === -1 ? inner : inner.slice(0, dot);
21324
+ if (shadowed.has(target) || shadowed.has(inner)) return whole;
21325
+ const renamed = renames.get(target);
21326
+ if (renamed === void 0) return whole;
21327
+ return `\${${renamed}${dot === -1 ? "" : inner.slice(dot)}}`;
21328
+ });
21329
+ }
21330
+ function removeMovedRecords(state, moves) {
21331
+ const leavingIds = /* @__PURE__ */ new Set();
21332
+ for (const { from } of moves) {
21333
+ if (!hasOwnKey(state.resources, from)) throw new Error(`Logical ID ${from} is not in the source stack's state`);
21334
+ leavingIds.add(from);
21335
+ }
21336
+ const resources = {};
21337
+ const leaving = [];
21338
+ for (const [logicalId, record] of Object.entries(state.resources)) {
21339
+ if (leavingIds.has(logicalId)) {
21340
+ leaving.push({
21341
+ logicalId,
21342
+ record
21343
+ });
21344
+ continue;
21345
+ }
21346
+ defineOwnKey(resources, logicalId, withoutDependencies(record, leavingIds));
21347
+ }
21348
+ const { skippedOutputs: _dropped, ...rest } = state;
21349
+ return {
21350
+ ...rest,
21351
+ ...stackInstanceIdCarriedFrom(state),
21352
+ resources,
21353
+ ...retiredNameGenerationsAfter(state, leaving),
21354
+ ...Array.isArray(state.orphans) && { orphans: state.orphans.map((entry) => entry === null || typeof entry !== "object" ? entry : {
21355
+ ...entry,
21356
+ state: withoutDependencies(entry.state, leavingIds)
21357
+ }) },
21358
+ lastModified: Date.now()
21359
+ };
21360
+ }
21361
+ function insertMovedRecords(state, moved, template) {
21362
+ const renamesBySource = /* @__PURE__ */ new Map();
21363
+ for (const m of moved) {
21364
+ const group = renamesBySource.get(m.source) ?? /* @__PURE__ */ new Map();
21365
+ group.set(m.from, m.to);
21366
+ renamesBySource.set(m.source, group);
21367
+ }
21368
+ const resources = {};
21369
+ for (const [logicalId, record] of Object.entries(state.resources)) defineOwnKey(resources, logicalId, record);
21370
+ const retired = state.retiredNameGenerations ?? {};
21371
+ for (const { to, record, source } of moved) {
21372
+ if (hasOwnKey(state.resources, to) || hasOwnKey(resources, to)) throw new Error(`Logical ID ${to} is already in the destination stack's state`);
21373
+ const group = renamesBySource.get(source);
21374
+ const coMoved = new Set(group.values());
21375
+ const renamed = rewriteRecordReferences(record, group);
21376
+ const kept = renamed !== null && typeof renamed === "object" && Array.isArray(renamed.dependencies) ? {
21377
+ ...renamed,
21378
+ dependencies: renamed.dependencies.filter((dep) => typeof dep !== "string" || coMoved.has(dep))
21379
+ } : renamed;
21380
+ const constructPath = constructPathOf(template, to);
21381
+ defineOwnKey(resources, to, withNameGenerationReached({
21382
+ ...kept,
21383
+ ...constructPath !== void 0 && { constructPath }
21384
+ }, to, hasOwnKey(retired, to) ? retired[to] : void 0));
21385
+ }
21386
+ const { skippedOutputs: _dropped, ...rest } = state;
21387
+ return {
21388
+ ...rest,
21389
+ ...stackInstanceIdCarriedFrom(state),
21390
+ resources,
21391
+ lastModified: Date.now()
21392
+ };
21393
+ }
21394
+ function withoutDependencies(record, drop) {
21395
+ if (record === null || typeof record !== "object" || !Array.isArray(record.dependencies)) return record;
21396
+ return {
21397
+ ...record,
21398
+ dependencies: record.dependencies.filter((dep) => typeof dep !== "string" || !drop.has(dep))
21399
+ };
21400
+ }
21401
+
21402
+ //#endregion
21403
+ //#region src/utils/deferred-interrupts.ts
21404
+ async function withDeferredInterrupts(fn, onDeferred) {
21405
+ let held;
21406
+ const hold = (signal) => {
21407
+ if (held === void 0) {
21408
+ held = signal;
21409
+ onDeferred(signal);
21410
+ }
21411
+ };
21412
+ process.on("SIGINT", hold);
21413
+ process.on("SIGTERM", hold);
21414
+ let result;
21415
+ try {
21416
+ result = await fn();
21417
+ } finally {
21418
+ process.removeListener("SIGINT", hold);
21419
+ process.removeListener("SIGTERM", hold);
21420
+ }
21421
+ if (held !== void 0) throw new CdkdError(`Interrupted (${held}) after the state writes finished; they are complete.`, "INTERRUPTED");
21422
+ return result;
21423
+ }
21424
+
21425
+ //#endregion
21426
+ //#region src/cli/commands/refactor-move.ts
21427
+ const rowKey = (stack, region, logicalId) => JSON.stringify([
21428
+ stack,
21429
+ region,
21430
+ logicalId
21431
+ ]);
21432
+ const location = (stack, logicalId) => `${stack}.${logicalId}`;
21433
+ async function planMoves(plans, envOf, overrides) {
21434
+ const planAt = (stack, region) => plans.find((p) => p.stackName === stack && p.region === region);
21435
+ const result = {
21436
+ moves: [],
21437
+ differing: [],
21438
+ refused: [],
21439
+ ambiguous: []
21440
+ };
21441
+ const takenFrom = /* @__PURE__ */ new Set();
21442
+ const takenTo = /* @__PURE__ */ new Set();
21443
+ const candidates = [];
21444
+ const move = (source, from, dest, to, resourceType, origin) => ({
21445
+ fromStack: source.stackName,
21446
+ fromRegion: source.region,
21447
+ from,
21448
+ toStack: dest.stackName,
21449
+ toRegion: dest.region,
21450
+ to,
21451
+ resourceType,
21452
+ source: origin
21453
+ });
21454
+ for (const o of overrides) {
21455
+ const source = planAt(o.fromStack, o.region);
21456
+ const dest = planAt(o.toStack, o.region);
21457
+ const refuse = (reason) => {
21458
+ result.refused.push({
21459
+ fromStack: o.fromStack,
21460
+ from: o.from,
21461
+ toStack: o.toStack,
21462
+ to: o.to,
21463
+ reason
21464
+ });
21465
+ };
21466
+ if (source === void 0 || dest === void 0) {
21467
+ refuse("both stacks must be selected and hold cdkd state; a refactor never creates a stack");
21468
+ continue;
21469
+ }
21470
+ if (envOf(source) !== o.env || envOf(dest) !== o.env) {
21471
+ refuse("the two stacks are not both in the mapping environment's account and region");
21472
+ continue;
21473
+ }
21474
+ const d = source.unpaired.deletes.find((x) => x.logicalId === o.from);
21475
+ const c = dest.unpaired.creates.find((x) => x.logicalId === o.to);
21476
+ if (d === void 0) refuse(`${o.from} is not a resource ${o.fromStack}'s state holds and its template no longer declares`);
21477
+ else if (c === void 0) refuse(`${o.to} is not a resource ${o.toStack}'s template declares and its state does not hold`);
21478
+ else if (d.resourceType !== c.resourceType) refuse(`the types differ (${d.resourceType} and ${c.resourceType})`);
21479
+ else if (!isPairableType(d.resourceType)) refuse(`cdkd refactor cannot move a ${d.resourceType} resource`);
21480
+ else if (takenFrom.has(rowKey(o.fromStack, source.region, o.from)) || takenTo.has(rowKey(o.toStack, dest.region, o.to))) refuse("the mapping names one of these locations more than once");
21481
+ else {
21482
+ takenFrom.add(rowKey(o.fromStack, source.region, o.from));
21483
+ takenTo.add(rowKey(o.toStack, dest.region, o.to));
21484
+ candidates.push(move(source, o.from, dest, o.to, d.resourceType, "override"));
21485
+ }
21486
+ }
21487
+ const envs = new Set(plans.map(envOf));
21488
+ for (const env of envs) {
21489
+ const envPlans = plans.filter((p) => envOf(p) === env);
21490
+ const deletes = envPlans.flatMap((plan) => plan.unpaired.deletes.filter((d) => !takenFrom.has(rowKey(plan.stackName, plan.region, d.logicalId))).map((d) => ({
21491
+ plan,
21492
+ row: d
21493
+ })));
21494
+ const creates = envPlans.flatMap((plan) => plan.unpaired.creates.filter((c) => !takenTo.has(rowKey(plan.stackName, plan.region, c.logicalId))).map((c) => ({
21495
+ plan,
21496
+ row: c
21497
+ })));
21498
+ const types = [...new Set(creates.map((c) => c.row.resourceType))].sort();
21499
+ for (const type of types) {
21500
+ if (!isPairableType(type)) continue;
21501
+ const ds = deletes.filter((d) => d.row.resourceType === type);
21502
+ const cs = creates.filter((c) => c.row.resourceType === type);
21503
+ if (ds.length === 0 || cs.length === 0) continue;
21504
+ if (ds.length === 1 && cs.length === 1) {
21505
+ if (ds[0].plan !== cs[0].plan) candidates.push(move(ds[0].plan, ds[0].row.logicalId, cs[0].plan, cs[0].row.logicalId, type, "detected"));
21506
+ continue;
21507
+ }
21508
+ const matchesOf = /* @__PURE__ */ new Map();
21509
+ const claims = /* @__PURE__ */ new Map();
21510
+ for (const c of cs) {
21511
+ const matches = ds.filter((d) => d.plan !== c.plan && looselyEqual(c.row.properties, d.row.properties));
21512
+ matchesOf.set(c, matches);
21513
+ for (const d of matches) claims.set(d, (claims.get(d) ?? 0) + 1);
21514
+ }
21515
+ const groupFrom = /* @__PURE__ */ new Set();
21516
+ const groupTo = /* @__PURE__ */ new Set();
21517
+ let groupPlan;
21518
+ for (const c of cs) {
21519
+ const matches = matchesOf.get(c) ?? [];
21520
+ if (matches.length === 0) continue;
21521
+ if (matches.length === 1 && claims.get(matches[0]) === 1) {
21522
+ const d = matches[0];
21523
+ candidates.push(move(d.plan, d.row.logicalId, c.plan, c.row.logicalId, type, "detected"));
21524
+ continue;
21525
+ }
21526
+ groupTo.add(location(c.plan.stackName, c.row.logicalId));
21527
+ for (const d of matches) {
21528
+ groupFrom.add(location(d.plan.stackName, d.row.logicalId));
21529
+ groupPlan ??= d.plan;
21530
+ }
21531
+ }
21532
+ if (groupTo.size > 0 && groupPlan !== void 0) result.ambiguous.push({
21533
+ resourceType: type,
21534
+ from: [...groupFrom].sort(),
21535
+ to: [...groupTo].sort(),
21536
+ plan: groupPlan
21537
+ });
21538
+ }
21539
+ }
21540
+ let kept = candidates;
21541
+ for (;;) {
21542
+ const failed = [];
21543
+ for (const dest of plans) {
21544
+ const incoming = kept.filter((m) => m.toStack === dest.stackName && m.toRegion === dest.region);
21545
+ if (incoming.length === 0) continue;
21546
+ const renamed = applyLogicalIdRenames(dest.state, dest.renames.map(({ from, to }) => ({
21547
+ from,
21548
+ to
21549
+ })), dest.template);
21550
+ const withMoves = insertMovedRecords(renamed, incoming.map((m) => ({
21551
+ from: m.from,
21552
+ to: m.to,
21553
+ record: planAt(m.fromStack, m.fromRegion).state.resources[m.from],
21554
+ source: producerRecordKey(m.fromStack, m.fromRegion)
21555
+ })), dest.template);
21556
+ const { changes } = await dest.diff(withMoves);
21557
+ for (const m of incoming) {
21558
+ const change = changes.get(m.to);
21559
+ if (change?.changeType === "NO_CHANGE") continue;
21560
+ failed.push(m);
21561
+ const paths = (change?.propertyChanges ?? []).map((p) => p.path);
21562
+ for (const a of change?.attributeChanges ?? []) paths.push(a.attribute);
21563
+ if (paths.length === 0) paths.push(`(${change?.changeType ?? "not in the diff"})`);
21564
+ if (m.source === "override") result.refused.push({
21565
+ fromStack: m.fromStack,
21566
+ from: m.from,
21567
+ toStack: m.toStack,
21568
+ to: m.to,
21569
+ reason: `its properties also changed (${paths.join(", ")}); cdkd refactor keeps only an unchanged resource. Revert the property change, run cdkd refactor, then deploy the change`
21570
+ });
21571
+ else result.differing.push({
21572
+ move: m,
21573
+ paths
21574
+ });
21575
+ }
21576
+ }
21577
+ if (failed.length === 0) break;
21578
+ kept = kept.filter((m) => !failed.includes(m));
21579
+ }
21580
+ for (const m of kept) {
21581
+ planAt(m.fromStack, m.fromRegion).movesOut.push(m);
21582
+ planAt(m.toStack, m.toRegion).movesIn.push(m);
21583
+ }
21584
+ result.moves = kept;
21585
+ const both = plans.filter((p) => p.movesOut.length > 0 && p.movesIn.length > 0);
21586
+ if (both.length > 0) throw new CdkdError(safeMsg`cdkd refactor refused: ${both.map((p) => p.stackName).join(", ")} would both lose ` + "and gain a resource in one run, so nothing was written. Refactor one direction at a time: select only the stacks of one move direction, or name one direction in the mapping file.", "REFACTOR_REFUSED");
21587
+ return result;
21588
+ }
21589
+ function renderMovePlan(plan) {
21590
+ const lines = [];
21591
+ if (plan.moves.length === 0 && plan.differing.length === 0 && plan.refused.length === 0 && plan.ambiguous.length === 0) return lines;
21592
+ lines.push("Moves between stacks");
21593
+ for (const m of plan.moves) lines.push(safeMsg` ${m.fromStack}.${m.from} -> ${m.toStack}.${m.to} (${m.resourceType}${m.source === "override" ? ", from the mapping file" : ""})`);
21594
+ for (const { move: m, paths } of plan.differing) lines.push(safeMsg` Not moved: ${m.fromStack}.${m.from} -> ${m.toStack}.${m.to} (${m.resourceType}) also ` + safeMsg`changes ${paths.join(", ")}. cdkd refactor keeps only an unchanged resource: revert ` + "the property change, run cdkd refactor, then deploy the change.");
21595
+ for (const group of plan.ambiguous) lines.push(safeMsg` Ambiguous (${group.resourceType}): ${group.from.join(", ")} could each be ` + safeMsg`${group.to.join(", ")}. Name the pairs with --override-file.`);
21596
+ for (const r of plan.refused) lines.push(safeMsg` Refused: ${r.fromStack}.${r.from} -> ${r.toStack}.${r.to}: ${r.reason}.`);
21597
+ return lines;
21598
+ }
21599
+ const lockKey = (p) => producerRecordKey(p.stackName, p.region);
21600
+ function marksFor(plan, startedAt) {
21601
+ return plan.movesOut.map((m) => ({
21602
+ from: m.from,
21603
+ toStack: m.toStack,
21604
+ toRegion: m.toRegion,
21605
+ to: m.to,
21606
+ startedAt
21607
+ }));
21608
+ }
21609
+ function withMarks(state, marks) {
21610
+ if (marks.length === 0) return state;
21611
+ const { moves } = pendingMovesOutOf(state);
21612
+ return {
21613
+ ...state,
21614
+ ...stackInstanceIdCarriedFrom(state),
21615
+ pendingMovesOut: [...moves, ...marks]
21616
+ };
21617
+ }
21618
+ function withoutMarks(state, done) {
21619
+ const { moves } = pendingMovesOutOf(state);
21620
+ const left = moves.filter((m) => !done.has(m.from));
21621
+ const { pendingMovesOut: _dropped, ...rest } = state;
21622
+ const carried = {
21623
+ ...rest,
21624
+ ...stackInstanceIdCarriedFrom(rest)
21625
+ };
21626
+ return left.length > 0 ? {
21627
+ ...carried,
21628
+ pendingMovesOut: left
21629
+ } : carried;
21630
+ }
21631
+ async function applyMoveGroup(input) {
21632
+ const { stateBackend, lockManager, recovery, contentionMessage } = input;
21633
+ const plans = [...input.plans].sort((a, b) => lockKey(a) < lockKey(b) ? -1 : 1);
21634
+ await withLocks(plans, lockManager, contentionMessage, async () => {
21635
+ const loaded = /* @__PURE__ */ new Map();
21636
+ for (const plan of plans) {
21637
+ const stateData = await stateBackend.getState(plan.stackName, plan.region);
21638
+ if (!stateData || stateData.etag !== plan.etag) throw new CdkdError(safeMsg`The state of stack ${plan.stackName} (${plan.region}) changed after cdkd ` + "refactor planned it, so nothing was written. Re-run cdkd refactor.", "REFACTOR_STATE_CHANGED");
21639
+ refuseReadForWrite(stateData.state, plan.stackName, plan.region, recovery);
21640
+ if (await stateBackend.loadRollbackJournal(plan.stackName, plan.region) !== null) throw new CdkdError(safeMsg`cdkd refactor refused stack ${plan.stackName} (${plan.region}): an earlier ` + safeMsg`deploy left a rollback journal, so nothing was written. Run 'cdkd rollback ` + safeMsg`${plan.stackName}' or a successful 'cdkd deploy' first.`, "REFACTOR_REFUSED");
21641
+ loaded.set(plan, {
21642
+ state: stateData.state,
21643
+ ...stateData.migrationPending && { migrationPending: true }
21644
+ });
21645
+ }
21646
+ const recordOf = (stack, region, logicalId) => {
21647
+ const plan = plans.find((p) => p.stackName === stack && p.region === region);
21648
+ return loaded.get(plan).state.resources[logicalId];
21649
+ };
21650
+ const renamed = (plan) => applyLogicalIdRenames(loaded.get(plan).state, plan.renames.map(({ from, to }) => ({
21651
+ from,
21652
+ to
21653
+ })), plan.template);
21654
+ const startedAt = (input.now ?? Date.now)();
21655
+ const written = [];
21656
+ const fail = (plan, error) => {
21657
+ const sources = plans.filter((p) => p.movesOut.length > 0).map((p) => p.stackName);
21658
+ return new CdkdError(safeMsg`cdkd refactor could not save stack ${plan.stackName} (${plan.region}): ` + safeMsg`${error.message}.\n` + (written.length > 0 ? safeMsg`Written before the failure: ${written.join(", ")}.\n` : "") + safeMsg`Any move that started is recorded in its source stack (${sources.join(", ")}), ` + "whose 'cdkd deploy' and 'cdkd destroy' refuse until it is finished. Re-run " + safeMsg`'cdkd refactor ${sources.join(" ")}' to finish it.`, "REFACTOR_PARTIAL");
21659
+ };
21660
+ const save = async (plan, state, expectedEtag) => {
21661
+ try {
21662
+ const etag = await stateBackend.saveState(plan.stackName, plan.region, state, {
21663
+ expectedEtag,
21664
+ ...loaded.get(plan).migrationPending && { migrateLegacy: true }
21665
+ });
21666
+ written.push(`${plan.stackName} (${plan.region})`);
21667
+ return etag;
21668
+ } catch (error) {
21669
+ throw fail(plan, error);
21670
+ }
21671
+ };
21672
+ const markerMoves = plans.flatMap((p) => p.movesOut.map((m) => ({
21673
+ fromStack: m.fromStack,
21674
+ fromRegion: m.fromRegion,
21675
+ from: m.from,
21676
+ toStack: m.toStack,
21677
+ toRegion: m.toRegion,
21678
+ to: m.to,
21679
+ startedAt
21680
+ })));
21681
+ if (markerMoves.length > 0) await updateRefactorMarker(stateBackend, (moves) => [...moves.filter((m) => !markerMoves.some((n) => sameMove(m, n))), ...markerMoves]);
21682
+ const sourceEtags = /* @__PURE__ */ new Map();
21683
+ const marked = /* @__PURE__ */ new Map();
21684
+ for (const plan of plans.filter((p) => p.movesIn.length === 0)) {
21685
+ const leaving = [...plan.renames.map((r) => r.from), ...plan.movesOut.map((m) => m.from)];
21686
+ if (leaving.length > 0) await stateBackend.rotateCreateTokenNonce(plan.stackName, plan.region, leaving);
21687
+ const state = withMarks(renamed(plan), marksFor(plan, startedAt));
21688
+ marked.set(plan, state);
21689
+ sourceEtags.set(plan, await save(plan, state, plan.etag));
21690
+ }
21691
+ for (const plan of plans.filter((p) => p.movesIn.length > 0)) {
21692
+ if (plan.renames.length > 0) await stateBackend.rotateCreateTokenNonce(plan.stackName, plan.region, plan.renames.map((r) => r.from));
21693
+ await save(plan, insertMovedRecords(renamed(plan), plan.movesIn.map((m) => ({
21694
+ from: m.from,
21695
+ to: m.to,
21696
+ record: recordOf(m.fromStack, m.fromRegion, m.from),
21697
+ source: producerRecordKey(m.fromStack, m.fromRegion)
21698
+ })), plan.template), plan.etag);
21699
+ }
21700
+ for (const plan of plans.filter((p) => p.movesOut.length > 0)) await save(plan, withoutMarks(removeMovedRecords(marked.get(plan), plan.movesOut.map(({ from, to }) => ({
21701
+ from,
21702
+ to
21703
+ }))), new Set(plan.movesOut.map((m) => m.from))), sourceEtags.get(plan));
21704
+ if (markerMoves.length > 0) try {
21705
+ await updateRefactorMarker(stateBackend, (moves) => moves.filter((m) => !markerMoves.some((n) => sameMove(m, n))));
21706
+ } catch (error) {
21707
+ throw new CdkdError(safeMsg`Every record of the refactor was written, but the refactor marker could not ` + safeMsg`be cleared: ${error.message}. Until it is, deploy and destroy of ` + "the moved stacks refuse; re-run cdkd refactor to clear it.", "REFACTOR_PARTIAL");
21708
+ }
21709
+ });
21710
+ }
21711
+ function refuseReadForWrite(state, stackName, region, recovery) {
21712
+ refuseMalformedState(state, stackName, region, recovery);
21713
+ refuseMalformedOrphans(state, stackName, region, recovery);
21714
+ refuseMalformedOrphanRecords(state, stackName, region, recovery);
21715
+ }
21716
+ async function withLocks(plans, lockManager, contentionMessage, fn) {
21717
+ const logger = getLogger();
21718
+ const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
21719
+ const locked = [];
21720
+ try {
21721
+ for (const plan of plans) {
21722
+ if (!await lockManager.acquireLock(plan.stackName, plan.region, owner, "refactor")) throw new Error(await contentionMessage(plan));
21723
+ locked.push(plan);
21724
+ }
21725
+ return await fn();
21726
+ } finally {
21727
+ for (const plan of [...locked].reverse()) await lockManager.releaseLock(plan.stackName, plan.region).catch((err) => {
21728
+ logger.warn(safeMsg`Failed to release lock: ${displayAwsMessage(describeAwsFailure(err).detail)}`);
21729
+ });
21730
+ }
21731
+ }
21732
+ async function finishPendingMoves(input) {
21733
+ const { stackName, region, stateBackend, lockManager, recovery, contentionMessage } = input;
21734
+ const finishedOf = (m) => ({
21735
+ fromStack: stackName,
21736
+ fromRegion: region,
21737
+ from: m.from,
21738
+ toStack: m.toStack,
21739
+ toRegion: m.toRegion,
21740
+ to: m.to
21741
+ });
21742
+ const first = await stateBackend.getState(stackName, region);
21743
+ if (!first) {
21744
+ const finished = [];
21745
+ const stuck = [];
21746
+ for (const m of input.markerMoves ?? []) {
21747
+ const dest = await stateBackend.getState(m.toStack, m.toRegion);
21748
+ if (dest !== null && Object.hasOwn(dest.state.resources, m.to)) finished.push(finishedOf(m));
21749
+ else stuck.push(safeMsg`${stackName}.${m.from} -> ${m.toStack}.${m.to}`);
21750
+ }
21751
+ if (stuck.length > 0) throw new CdkdError(safeMsg`cdkd refactor cannot finish ${stuck.join(", ")}: ${stackName} (${region}) has ` + "no cdkd state any more and the destination does not record the resource. If the resource is still in AWS, adopt it into the destination with cdkd import; then remove the move from the refactor marker in the state bucket.", "REFACTOR_REFUSED");
21752
+ return { finished };
21753
+ }
21754
+ const { moves: marked, malformed } = pendingMovesOutOf(first.state);
21755
+ const moves = [...marked, ...(input.markerMoves ?? []).filter((m) => !marked.some((n) => n.from === m.from))];
21756
+ if (malformed) throw new CdkdError(safeMsg`Stack ${stackName} (${region}) records an unfinished cdkd refactor move this ` + "binary cannot read (its pendingMovesOut field is malformed), so nothing was written. Inspect the record with cdkd state show and repair it by hand.", "REFACTOR_REFUSED");
21757
+ if (moves.length === 0) return { finished: [] };
21758
+ const keyOf = (s) => producerRecordKey(s.stackName, s.region);
21759
+ const stacks = /* @__PURE__ */ new Map();
21760
+ stacks.set(keyOf({
21761
+ stackName,
21762
+ region
21763
+ }), {
21764
+ stackName,
21765
+ region
21766
+ });
21767
+ for (const m of moves) stacks.set(keyOf({
21768
+ stackName: m.toStack,
21769
+ region: m.toRegion
21770
+ }), {
21771
+ stackName: m.toStack,
21772
+ region: m.toRegion
21773
+ });
21774
+ const ordered = [...stacks.values()].sort((a, b) => keyOf(a) < keyOf(b) ? -1 : 1);
21775
+ return withLocks(ordered, lockManager, contentionMessage, async () => {
21776
+ const read = /* @__PURE__ */ new Map();
21777
+ for (const s of ordered) {
21778
+ const data = await stateBackend.getState(s.stackName, s.region);
21779
+ if (data) {
21780
+ refuseReadForWrite(data.state, s.stackName, s.region, recovery);
21781
+ read.set(keyOf(s), {
21782
+ state: data.state,
21783
+ etag: data.etag,
21784
+ ...data.migrationPending && { migrationPending: true }
21785
+ });
21786
+ }
21787
+ }
21788
+ const source = read.get(keyOf({
21789
+ stackName,
21790
+ region
21791
+ }));
21792
+ if (!source) return { finished: [] };
21793
+ const currentMarked = pendingMovesOutOf(source.state).moves;
21794
+ const current = [...currentMarked, ...(input.markerMoves ?? []).filter((m) => !currentMarked.some((n) => n.from === m.from))];
21795
+ const refusals = [];
21796
+ const finished = [];
21797
+ const additions = /* @__PURE__ */ new Map();
21798
+ for (const m of current) {
21799
+ const destKey = keyOf({
21800
+ stackName: m.toStack,
21801
+ region: m.toRegion
21802
+ });
21803
+ const dest = read.get(destKey);
21804
+ const record = Object.hasOwn(source.state.resources, m.from) ? source.state.resources[m.from] : void 0;
21805
+ const held = dest !== void 0 && Object.hasOwn(dest.state.resources, m.to) ? dest.state.resources[m.to] : void 0;
21806
+ const describe = safeMsg`${stackName}.${m.from} -> ${m.toStack}.${m.to}`;
21807
+ if (dest === void 0) refusals.push(safeMsg`${describe}: ${m.toStack} (${m.toRegion}) has no cdkd state`);
21808
+ else if (record === void 0) {
21809
+ if (held === void 0) refusals.push(safeMsg`${describe}: neither stack records the resource; adopt it into ${m.toStack} with cdkd import`);
21810
+ else finished.push(finishedOf(m));
21811
+ } else if (held === void 0 && !input.declaresInDestination(m.toStack, m.toRegion, m.to, record.resourceType)) refusals.push(safeMsg`${describe}: ${m.toStack}'s template does not declare ${m.to} as a ` + safeMsg`${record.resourceType}, so the record is not moved there. Check the move, ` + "and the CDK app the run synthesized");
21812
+ else if (held === void 0) {
21813
+ const list = additions.get(destKey) ?? [];
21814
+ list.push({
21815
+ from: m.from,
21816
+ to: m.to,
21817
+ record,
21818
+ source: keyOf({
21819
+ stackName,
21820
+ region
21821
+ })
21822
+ });
21823
+ additions.set(destKey, list);
21824
+ finished.push(finishedOf(m));
21825
+ } else if (held.physicalId !== record.physicalId) refusals.push(safeMsg`${describe}: ${m.toStack} already holds a different resource under ${m.to} ` + "(created by a deploy before the move finished). Delete or orphan that resource in " + safeMsg`${m.toStack}, then re-run cdkd refactor`);
21826
+ else finished.push(finishedOf(m));
21827
+ }
21828
+ for (const [destKey, list] of additions) {
21829
+ const dest = read.get(destKey);
21830
+ const s = stacks.get(destKey);
21831
+ await stateBackend.saveState(s.stackName, s.region, insertMovedRecords(dest.state, list, { Resources: {} }), {
21832
+ expectedEtag: dest.etag,
21833
+ ...dest.migrationPending && { migrateLegacy: true }
21834
+ });
21835
+ }
21836
+ if (finished.length > 0) {
21837
+ const done = new Set(finished.map((f) => f.from));
21838
+ const leaving = finished.filter((f) => Object.hasOwn(source.state.resources, f.from)).map(({ from, to }) => ({
21839
+ from,
21840
+ to
21841
+ }));
21842
+ await stateBackend.saveState(stackName, region, withoutMarks(leaving.length > 0 ? removeMovedRecords(source.state, leaving) : source.state, done), {
21843
+ expectedEtag: source.etag,
21844
+ ...source.migrationPending && { migrateLegacy: true }
21845
+ });
21846
+ }
21847
+ if (refusals.length > 0) {
21848
+ const error = new CdkdError(safeMsg`cdkd refactor could not finish ${refusals.length} interrupted move(s) out of ` + safeMsg`${stackName} (${region}); they stay recorded, so the deploy and destroy of ` + "both stacks keep refusing" + (finished.length > 0 ? safeMsg` (${finished.length} other move(s) were finished)` : "") + ":\n" + refusals.map((r) => ` ${r}.`).join("\n"), "REFACTOR_REFUSED");
21849
+ Object.assign(error, { finishedMoves: finished });
21850
+ throw error;
21851
+ }
21852
+ return { finished };
21853
+ });
21854
+ }
21855
+ async function finishInterruptedMoves(input) {
21856
+ const { stateBackend } = input;
21857
+ const marker = await stateBackend.getRefactorMarker();
21858
+ const parsed = marker === null ? {
21859
+ moves: [],
21860
+ malformed: false
21861
+ } : refactorMarkerMovesOf(marker.body);
21862
+ if (parsed.malformed) throw new CdkdError(safeMsg`The cdkd refactor marker ${stateBackend.refactorMarkerKey()} cannot be read, so ` + "cdkd refactor cannot tell which moves are unfinished; nothing was written. Inspect it in the state bucket, and delete it once no move is in progress.", "REFACTOR_REFUSED");
21863
+ const keyOf = (stackName, region) => producerRecordKey(stackName, region);
21864
+ const selected = new Set(input.selected.map((s) => keyOf(s.stackName, s.region)));
21865
+ const sources = /* @__PURE__ */ new Map();
21866
+ for (const s of input.selected) {
21867
+ const current = await stateBackend.getState(s.stackName, s.region);
21868
+ const marked = current ? pendingMovesOutOf(current.state).moves : [];
21869
+ if (current && hasPendingMovesOut(current.state)) sources.set(keyOf(s.stackName, s.region), {
21870
+ ...s,
21871
+ markerMoves: [],
21872
+ marked
21873
+ });
21874
+ }
21875
+ for (const m of parsed.moves) {
21876
+ if (!selected.has(keyOf(m.fromStack, m.fromRegion)) && !selected.has(keyOf(m.toStack, m.toRegion))) continue;
21877
+ const key = keyOf(m.fromStack, m.fromRegion);
21878
+ const entry = sources.get(key) ?? {
21879
+ stackName: m.fromStack,
21880
+ region: m.fromRegion,
21881
+ markerMoves: [],
21882
+ marked: []
21883
+ };
21884
+ entry.markerMoves.push({
21885
+ from: m.from,
21886
+ toStack: m.toStack,
21887
+ toRegion: m.toRegion,
21888
+ to: m.to,
21889
+ startedAt: m.startedAt
21890
+ });
21891
+ sources.set(key, entry);
21892
+ }
21893
+ const declaresInDestination = (stackName, region, logicalId, resourceType) => {
21894
+ const resources = input.templateOf(stackName, region)?.Resources ?? {};
21895
+ return Object.hasOwn(resources, logicalId) && resources[logicalId].Type === resourceType;
21896
+ };
21897
+ const finished = [];
21898
+ const pending = [];
21899
+ for (const source of sources.values()) {
21900
+ if (input.dryRun) {
21901
+ for (const m of [...source.marked, ...source.markerMoves.filter((x) => !source.marked.some((y) => y.from === x.from))]) pending.push({
21902
+ fromStack: source.stackName,
21903
+ fromRegion: source.region,
21904
+ from: m.from,
21905
+ toStack: m.toStack,
21906
+ toRegion: m.toRegion,
21907
+ to: m.to
21908
+ });
21909
+ continue;
21910
+ }
21911
+ let result;
21912
+ try {
21913
+ result = await finishPendingMoves({
21914
+ stackName: source.stackName,
21915
+ region: source.region,
21916
+ markerMoves: source.markerMoves,
21917
+ declaresInDestination,
21918
+ stateBackend,
21919
+ lockManager: input.lockManager,
21920
+ recovery: input.recovery,
21921
+ contentionMessage: input.contentionMessage
21922
+ });
21923
+ } catch (error) {
21924
+ const done = error.finishedMoves ?? [];
21925
+ if (done.length > 0) await updateRefactorMarker(stateBackend, (moves) => moves.filter((m) => !done.some((f) => sameMove(m, f))));
21926
+ throw error;
21927
+ }
21928
+ if (result.finished.length > 0) await updateRefactorMarker(stateBackend, (moves) => moves.filter((m) => !result.finished.some((f) => sameMove(m, f))));
21929
+ finished.push(...result.finished);
21930
+ }
21931
+ return {
21932
+ finished,
21933
+ pending
21934
+ };
21935
+ }
21936
+
21937
+ //#endregion
21938
+ //#region src/cli/commands/refactor.ts
21939
+ function changedPaths(change) {
21940
+ if (change === void 0) return ["(not in the diff)"];
21941
+ const paths = (change.propertyChanges ?? []).map((p) => p.path);
21942
+ for (const a of change.attributeChanges ?? []) paths.push(a.attribute);
21943
+ return paths.length > 0 ? paths : [`(${change.changeType})`];
21944
+ }
21945
+ async function planStackRefactor(input) {
21946
+ const { stackName, region, state, etag, template, overrides, diff, recovery } = input;
21947
+ refuseMalformedOrphans(state, stackName, region, recovery);
21948
+ refuseMalformedOrphanRecords(state, stackName, region, recovery);
21949
+ const base = await diff(state);
21950
+ if (base.blocking.length > 0) throw new CdkdError(safeMsg`cdkd refactor refused stack ${stackName} (${region}): ` + `'cdkd diff' reports a condition 'cdkd deploy' refuses to start on. Resolve what 'cdkd diff ${stackName}' reports, then re-run cdkd refactor.`, "REFACTOR_REFUSED");
21951
+ const orphanIds = new Set((Array.isArray(state.orphans) ? state.orphans : []).map((o) => o !== null && typeof o === "object" ? o.logicalId : void 0).filter((id) => typeof id === "string"));
21952
+ const creates = [];
21953
+ const deletes = [];
21954
+ for (const change of base.changes.values()) if (change.changeType === "CREATE" && !orphanIds.has(change.logicalId)) creates.push({
21955
+ logicalId: change.logicalId,
21956
+ resourceType: change.resourceType,
21957
+ properties: change.desiredProperties ?? {}
21958
+ });
21959
+ else if (change.changeType === "DELETE") {
21960
+ const record = state.resources[change.logicalId];
21961
+ deletes.push({
21962
+ logicalId: change.logicalId,
21963
+ resourceType: change.resourceType,
21964
+ properties: record !== void 0 && record.properties !== null && typeof record.properties === "object" ? record.properties : {}
21965
+ });
21966
+ }
21967
+ const proposal = proposeRenames(creates, deletes, overrides);
21968
+ const refusedOverrides = [...proposal.refusedOverrides];
21969
+ const differing = [];
21970
+ const skipped = [];
21971
+ const candidates = proposal.renames.filter((r) => {
21972
+ if (!orphanIds.has(r.from)) return true;
21973
+ const reason = `a rollback-orphan record also names ${r.from}; run 'cdkd deploy' first to settle it`;
21974
+ if (r.source === "override") refusedOverrides.push({
21975
+ from: r.from,
21976
+ to: r.to,
21977
+ reason
21978
+ });
21979
+ else skipped.push({
21980
+ rename: r,
21981
+ reason
21982
+ });
21983
+ return false;
21984
+ });
21985
+ const confirm = async (proposed) => {
21986
+ let kept = [...proposed];
21987
+ while (kept.length > 0) {
21988
+ const renamed = applyLogicalIdRenames(state, toLogicalIdRenames(kept), template);
21989
+ const { changes } = await diff(renamed);
21990
+ const failed = kept.filter((r) => changes.get(r.to)?.changeType !== "NO_CHANGE");
21991
+ if (failed.length === 0) return {
21992
+ kept,
21993
+ changes
21994
+ };
21995
+ for (const rename of failed) {
21996
+ const paths = changedPaths(changes.get(rename.to));
21997
+ if (rename.source === "override") refusedOverrides.push({
21998
+ from: rename.from,
21999
+ to: rename.to,
22000
+ reason: `its properties also changed (${paths.join(", ")}); cdkd refactor keeps only an unchanged resource. Revert the property change, run cdkd refactor, then deploy the change`
22001
+ });
22002
+ else differing.push({
22003
+ rename,
22004
+ paths
22005
+ });
22006
+ }
22007
+ kept = kept.filter((r) => !failed.includes(r));
22008
+ }
22009
+ return {
22010
+ kept,
22011
+ changes: void 0
22012
+ };
22013
+ };
22014
+ let { kept: renames, changes: confirmed } = await confirm(candidates);
22015
+ let ambiguous = proposal.ambiguous;
22016
+ let budget = MAX_TRIAL_DIFFS;
22017
+ for (;;) {
22018
+ const takenFrom = new Set(renames.map((r) => r.from));
22019
+ const takenTo = new Set(renames.map((r) => r.to));
22020
+ const accepted = [];
22021
+ const remaining = [];
22022
+ for (const group of ambiguous) {
22023
+ const froms = group.from.filter((id) => !takenFrom.has(id));
22024
+ const tos = group.to.filter((id) => !takenTo.has(id));
22025
+ if (froms.length === 0 || tos.length === 0) continue;
22026
+ if (froms.length * tos.length > budget) {
22027
+ remaining.push({
22028
+ resourceType: group.resourceType,
22029
+ from: froms,
22030
+ to: tos
22031
+ });
22032
+ continue;
22033
+ }
22034
+ const passing = /* @__PURE__ */ new Map();
22035
+ for (const to of tos) {
22036
+ const matches = [];
22037
+ for (const from of froms) {
22038
+ budget -= 1;
22039
+ const { changes } = await diff(applyLogicalIdRenames(state, [...toLogicalIdRenames(renames), {
22040
+ from,
22041
+ to
22042
+ }], template));
22043
+ if (changes.get(to)?.changeType === "NO_CHANGE") matches.push(from);
22044
+ }
22045
+ passing.set(to, matches);
22046
+ }
22047
+ const claims = /* @__PURE__ */ new Map();
22048
+ for (const matches of passing.values()) for (const from of matches) claims.set(from, (claims.get(from) ?? 0) + 1);
22049
+ const leftFrom = /* @__PURE__ */ new Set();
22050
+ const leftTo = [];
22051
+ for (const [to, matches] of passing) {
22052
+ if (matches.length === 0) continue;
22053
+ if (matches.length === 1 && claims.get(matches[0]) === 1) {
22054
+ accepted.push({
22055
+ from: matches[0],
22056
+ to,
22057
+ resourceType: group.resourceType,
22058
+ source: "detected"
22059
+ });
22060
+ continue;
22061
+ }
22062
+ leftTo.push(to);
22063
+ for (const from of matches) leftFrom.add(from);
22064
+ }
22065
+ if (leftTo.length > 0) remaining.push({
22066
+ resourceType: group.resourceType,
22067
+ from: [...leftFrom].sort(),
22068
+ to: leftTo.sort()
22069
+ });
22070
+ }
22071
+ ambiguous = remaining;
22072
+ if (accepted.length === 0) break;
22073
+ ({kept: renames, changes: confirmed} = await confirm([...renames, ...accepted]));
22074
+ }
22075
+ const renamedTo = new Set(renames.map((r) => r.to));
22076
+ const stillChanging = confirmed === void 0 ? [] : [...confirmed.values()].filter((change) => (change.changeType === "UPDATE" || change.changeType === "CREATE") && !renamedTo.has(change.logicalId) && [...referencedLogicalIds(template, change.logicalId)].some((id) => renamedTo.has(id))).map((change) => change.logicalId).sort();
22077
+ const takenTo = /* @__PURE__ */ new Set([
22078
+ ...renames.map((r) => r.to),
22079
+ ...skipped.map((x) => x.rename.to),
22080
+ ...ambiguous.flatMap((g) => g.to),
22081
+ ...overrides.map((o) => o.to)
22082
+ ]);
22083
+ const takenFrom = /* @__PURE__ */ new Set([
22084
+ ...renames.map((r) => r.from),
22085
+ ...skipped.map((x) => x.rename.from),
22086
+ ...ambiguous.flatMap((g) => g.from),
22087
+ ...overrides.map((o) => o.from),
22088
+ ...orphanIds
22089
+ ]);
22090
+ return {
22091
+ stackName,
22092
+ region,
22093
+ etag,
22094
+ renames,
22095
+ differing,
22096
+ skipped,
22097
+ ambiguous,
22098
+ refusedOverrides,
22099
+ stillChanging,
22100
+ template,
22101
+ unpaired: {
22102
+ creates: creates.filter((c) => !takenTo.has(c.logicalId)),
22103
+ deletes: deletes.filter((d) => !takenFrom.has(d.logicalId))
22104
+ },
22105
+ movesOut: [],
22106
+ movesIn: [],
22107
+ state,
22108
+ diff
22109
+ };
22110
+ }
22111
+ const MAX_TRIAL_DIFFS = 64;
22112
+ function referencedLogicalIds(template, logicalId) {
22113
+ const out = /* @__PURE__ */ new Set();
22114
+ const resources = template.Resources ?? {};
22115
+ if (!Object.hasOwn(resources, logicalId)) return out;
22116
+ const resource = resources[logicalId];
22117
+ const dependsOn = resource.DependsOn;
22118
+ for (const id of Array.isArray(dependsOn) ? dependsOn : [dependsOn]) if (typeof id === "string") out.add(id);
22119
+ const walk = (value) => {
22120
+ if (Array.isArray(value)) {
22121
+ value.forEach(walk);
22122
+ return;
22123
+ }
22124
+ if (value === null || typeof value !== "object") return;
22125
+ for (const [key, arg] of Object.entries(value)) {
22126
+ if (key === "Ref" && typeof arg === "string") out.add(arg);
22127
+ else if (key === "Fn::GetAtt") {
22128
+ if (Array.isArray(arg) && typeof arg[0] === "string") out.add(arg[0]);
22129
+ else if (typeof arg === "string") out.add(arg.split(".")[0]);
22130
+ } else if (key === "Fn::Sub") {
22131
+ const text = typeof arg === "string" ? arg : Array.isArray(arg) ? arg[0] : void 0;
22132
+ if (typeof text === "string") for (const match of text.matchAll(/\$\{([^}!][^}.]*)/g)) out.add(match[1]);
22133
+ }
22134
+ walk(arg);
22135
+ }
22136
+ };
22137
+ walk(resource.Properties);
22138
+ return out;
22139
+ }
22140
+ function toLogicalIdRenames(renames) {
22141
+ return renames.map(({ from, to }) => ({
22142
+ from,
22143
+ to
22144
+ }));
22145
+ }
22146
+ async function applyStackRefactor(input) {
22147
+ const { plan, stateBackend, lockManager, contentionMessage } = input;
22148
+ const logger = getLogger();
22149
+ const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
22150
+ if (!await lockManager.acquireLock(plan.stackName, plan.region, owner, "refactor")) throw new Error(await contentionMessage());
22151
+ try {
22152
+ const stateData = await stateBackend.getState(plan.stackName, plan.region);
22153
+ if (!stateData || stateData.etag !== plan.etag) throw new CdkdError(safeMsg`The state of stack ${plan.stackName} (${plan.region}) changed after cdkd ` + `refactor planned it, so nothing was written for this stack. Re-run cdkd refactor.`, "REFACTOR_STATE_CHANGED");
22154
+ refuseMalformedState(stateData.state, plan.stackName, plan.region, input.recovery);
22155
+ refuseMalformedOrphans(stateData.state, plan.stackName, plan.region, input.recovery);
22156
+ refuseMalformedOrphanRecords(stateData.state, plan.stackName, plan.region, input.recovery);
22157
+ if (await stateBackend.loadRollbackJournal(plan.stackName, plan.region) !== null) throw rollbackJournalRefusal(plan.stackName, plan.region);
22158
+ const renamed = applyLogicalIdRenames(stateData.state, toLogicalIdRenames(plan.renames), plan.template);
22159
+ await stateBackend.rotateCreateTokenNonce(plan.stackName, plan.region, plan.renames.map((r) => r.from));
22160
+ await stateBackend.saveState(plan.stackName, plan.region, renamed, {
22161
+ expectedEtag: plan.etag,
22162
+ ...stateData.migrationPending && { migrateLegacy: true }
22163
+ });
22164
+ } finally {
22165
+ await lockManager.releaseLock(plan.stackName, plan.region).catch((err) => {
22166
+ logger.warn(safeMsg`Failed to release lock: ${displayAwsMessage(describeAwsFailure(err).detail)}`);
22167
+ });
22168
+ }
22169
+ }
22170
+ function rollbackJournalRefusal(stackName, region) {
22171
+ return new CdkdError(safeMsg`cdkd refactor refused stack ${stackName} (${region}): an earlier deploy left a ` + safeMsg`rollback journal, so nothing was written for this stack. Run 'cdkd rollback ${stackName}' ` + `or a successful 'cdkd deploy' first.`, "REFACTOR_REFUSED");
22172
+ }
22173
+ function renderRefactorPlan(plan) {
22174
+ const lines = [safeMsg`Stack ${plan.stackName} (${plan.region})`];
22175
+ if (plan.renames.length === 0) lines.push(" No resource to refactor.");
22176
+ for (const r of plan.renames) lines.push(safeMsg` ${r.from} -> ${r.to} (${r.resourceType}${r.source === "override" ? ", from the mapping file" : ""})`);
22177
+ for (const { rename, paths } of plan.differing) lines.push(safeMsg` Not refactored: ${rename.from} -> ${rename.to} (${rename.resourceType}) also changes ` + safeMsg`${paths.join(", ")}. cdkd refactor keeps only an unchanged resource: revert the ` + "property change, run cdkd refactor, then deploy the change.");
22178
+ for (const { rename, reason } of plan.skipped) lines.push(safeMsg` Not refactored: ${rename.from} -> ${rename.to} (${rename.resourceType}): ${reason}.`);
22179
+ for (const group of plan.ambiguous) lines.push(safeMsg` Ambiguous (${group.resourceType}): ${group.from.join(", ")} could each be ` + safeMsg`${group.to.join(", ")}. Name the pairs with --override-file.`);
22180
+ for (const refused of plan.refusedOverrides) lines.push(safeMsg` Refused: ${refused.from} -> ${refused.to}: ${refused.reason}.`);
22181
+ if (plan.stillChanging.length > 0) lines.push(safeMsg` Warning: ${plan.stillChanging.join(", ")} reference a renamed resource and still ` + "change on the next deploy. Check that each pair above names the resource you meant; 'cdkd diff' after the refactor shows the change.");
22182
+ return lines;
22183
+ }
22184
+ function sampleMappingFile(plans, moveGroups = []) {
22185
+ const moveEnvironments = moveGroups.map(({ group, account }) => {
22186
+ const resources = {};
22187
+ group.from.forEach((from, i) => {
22188
+ Object.defineProperty(resources, from, {
22189
+ value: group.to[i] ?? group.to[0],
22190
+ enumerable: true,
22191
+ writable: true,
22192
+ configurable: true
22193
+ });
22194
+ });
22195
+ return {
22196
+ account,
22197
+ region: group.plan.region,
22198
+ resources
22199
+ };
22200
+ });
22201
+ const stackEnvironments = plans.filter(({ plan }) => plan.ambiguous.length > 0).map(({ plan, account }) => {
22202
+ const resources = {};
22203
+ for (const group of plan.ambiguous) group.from.forEach((from, i) => {
22204
+ const to = group.to[i] ?? group.to[0];
22205
+ Object.defineProperty(resources, `${plan.stackName}.${from}`, {
22206
+ value: `${plan.stackName}.${to}`,
22207
+ enumerable: true,
22208
+ writable: true,
22209
+ configurable: true
22210
+ });
22211
+ });
22212
+ return {
22213
+ account,
22214
+ region: plan.region,
22215
+ resources
22216
+ };
22217
+ });
22218
+ return JSON.stringify({ environments: [...stackEnvironments, ...moveEnvironments] }, null, 2);
22219
+ }
22220
+ function overridesForStack(environments, stackName, account, region, revert) {
22221
+ const out = [];
22222
+ for (const env of environments) {
22223
+ if (env.account !== account || env.region !== region) continue;
22224
+ for (const pair of mappingPairs(env.resources, revert)) {
22225
+ if (pair.fromStack !== stackName || pair.toStack !== stackName) continue;
22226
+ out.push({
22227
+ from: pair.from,
22228
+ to: pair.to
22229
+ });
22230
+ }
22231
+ }
22232
+ return out;
22233
+ }
22234
+ function moveOverridesOf(environments, accounts, revert) {
22235
+ const out = [];
22236
+ for (const env of environments) {
22237
+ if (!accounts.has(env.account)) continue;
22238
+ for (const pair of mappingPairs(env.resources, revert)) {
22239
+ if (pair.fromStack === pair.toStack) continue;
22240
+ out.push({
22241
+ region: env.region,
22242
+ env: envKey(env.account, env.region),
22243
+ ...pair
22244
+ });
22245
+ }
22246
+ }
22247
+ return out;
22248
+ }
22249
+ function envKey(account, region) {
22250
+ return JSON.stringify([account, region]);
22251
+ }
22252
+ async function refactorCommand(stacks, options) {
22253
+ const providerClasses = await loadProviderClasses();
22254
+ const logger = getLogger();
22255
+ const holdNotice = (signal) => {
22256
+ logger.warn(safeMsg`${signal} received: finishing the cdkd state writes already started (a few S3 ` + "writes), then stopping.");
22257
+ };
22258
+ if (options.verbose) logger.setLevel("debug");
22259
+ if (options.revert === true && options.overrideFile === void 0) throw new CdkdError("--revert requires --override-file", "INCOMPATIBLE_OPTIONS");
22260
+ warnIfDeprecatedRegion(options);
22261
+ foldRegionOption(options);
22262
+ await applyRoleArnIfSet({
22263
+ roleArn: options.roleArn,
22264
+ region: options.region
22265
+ });
22266
+ const app = resolveApp(options.app);
22267
+ if (!app) throw new Error("No app command specified. Use --app, set CDKD_APP env var, or add \"app\" to cdk.json");
22268
+ let environments = [];
22269
+ if (options.overrideFile !== void 0) {
22270
+ let text;
22271
+ try {
22272
+ text = readFileSync(options.overrideFile, "utf-8");
22273
+ } catch {
22274
+ throw new CdkdError(safeMsg`Cannot read the mapping file ${options.overrideFile}`, "REFACTOR_MAPPING_FILE");
22275
+ }
22276
+ try {
22277
+ environments = parseMappingFile(text);
22278
+ } catch (error) {
22279
+ throw new CdkdError(safeMsg`Invalid mapping file ${options.overrideFile}: ${error.message}`, "REFACTOR_MAPPING_FILE");
22280
+ }
22281
+ }
22282
+ const effectiveRegion = await resolveEffectiveRegion(options);
22283
+ exportInferredRegionForSdk(effectiveRegion);
22284
+ const region = effectiveRegion.region;
22285
+ const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region, legacyStateBucketFallbackRegion(effectiveRegion));
22286
+ const awsClients = new AwsClients({
22287
+ region: effectiveRegion.region,
22288
+ ...options.profile && { profile: options.profile }
22289
+ });
22290
+ setAwsClients(awsClients);
22291
+ try {
22292
+ logger.info(synthesisStatusMessage(app, "Synthesizing CDK app..."));
22293
+ const synthesizer = new Synthesizer();
22294
+ const context = parseContextOptions(options.context);
22295
+ const synthOptions = {
22296
+ app,
22297
+ output: options.output,
22298
+ ...options.region && { region: options.region },
22299
+ ...options.profile && { profile: options.profile },
22300
+ ...Object.keys(context).length > 0 && { context },
22301
+ stateBucket,
22302
+ ...options.profile && { macroExpandS3ClientOpts: { profile: options.profile } },
22303
+ deferMacroExpansion: true
22304
+ };
22305
+ const { stacks: allStacks } = await synthesizer.synthesize(synthOptions);
22306
+ const targetStacks = selectStacks(allStacks, stacks, options);
22307
+ await synthesizer.expandMacrosForStacks(targetStacks, synthOptions);
22308
+ const stateConfig = {
22309
+ bucket: stateBucket,
22310
+ prefix: options.statePrefix
22311
+ };
22312
+ const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
22313
+ region,
22314
+ ...options.profile && { profile: options.profile }
22315
+ });
22316
+ await stateBackend.verifyBucketExists();
22317
+ const lockManager = new LockManager(awsClients.s3, stateConfig);
22318
+ const recovery = {
22319
+ profile: options.profile,
22320
+ stateBucket,
22321
+ statePrefix: options.statePrefix
22322
+ };
22323
+ const regionForStack = stackRegionResolver({
22324
+ effective: effectiveRegion,
22325
+ probe: stateBackend,
22326
+ logger,
22327
+ siblings: allStacks.filter((s) => !s.region).map((s) => s.stackName)
22328
+ });
22329
+ const diffCalculator = new DiffCalculator();
22330
+ const registry = new ProviderRegistry();
22331
+ registerAllProviders(registry, providerClasses);
22332
+ const canonicalizeProperties = makeCanonicalizePropertiesFn(registry);
22333
+ const producerLookup = producerLookupOver(allStacks);
22334
+ const resolveAssetRedirect = createAssetRedirectResolver({
22335
+ stateBackend,
22336
+ stsRegion: region,
22337
+ ...options.profile && { profile: options.profile },
22338
+ useCdkBootstrapAssets: resolveUseCdkBootstrapAssets(options.useCdkBootstrapAssets),
22339
+ suppressLegacyNotice: true
22340
+ });
22341
+ let callerAccount;
22342
+ const accountOf = async (stackInfo) => {
22343
+ if (stackInfo.account) return stackInfo.account;
22344
+ callerAccount ??= (await getAccountInfo()).accountId;
22345
+ return callerAccount;
22346
+ };
22347
+ const selectedStacks = [];
22348
+ for (const stackInfo of targetStacks) selectedStacks.push({
22349
+ stackName: stackInfo.stackName,
22350
+ region: await regionForStack(stackInfo.stackName, stackInfo.region)
22351
+ });
22352
+ const templateOf = (stackName, region) => allStacks.find((s) => s.stackName === stackName && (s.region === void 0 || s.region === region))?.template;
22353
+ const { finished: finishedMoves, pending: pendingMoves } = await withDeferredInterrupts(() => finishInterruptedMoves({
22354
+ selected: selectedStacks,
22355
+ templateOf,
22356
+ dryRun: options.dryRun === true,
22357
+ stateBackend,
22358
+ lockManager,
22359
+ recovery,
22360
+ contentionMessage: (st) => buildLockContentionMessage({
22361
+ lockManager,
22362
+ stackName: st.stackName,
22363
+ region: st.region,
22364
+ recovery
22365
+ })
22366
+ }), holdNotice);
22367
+ for (const f of finishedMoves) logger.info(safeMsg`Finished an interrupted move: ${f.fromStack}.${f.from} -> ${f.toStack}.${f.to}`);
22368
+ if (pendingMoves.length > 0) {
22369
+ for (const f of pendingMoves) logger.info(safeMsg`An interrupted move would be finished: ${f.fromStack}.${f.from} -> ${f.toStack}.${f.to}`);
22370
+ logger.info("\n--dry-run: state was NOT written. Re-run without --dry-run to finish these moves; the refactor plan is computed after them.");
22371
+ return;
22372
+ }
22373
+ const plans = [];
22374
+ const planStacks = /* @__PURE__ */ new Map();
22375
+ for (const stackInfo of targetStacks) {
22376
+ const stackRegion = await regionForStack(stackInfo.stackName, stackInfo.region);
22377
+ const stateData = await stateBackend.getState(stackInfo.stackName, stackRegion);
22378
+ if (!stateData) {
22379
+ logger.info(safeMsg`Stack ${stackInfo.stackName} (${stackRegion}) has no cdkd state: nothing to refactor.`);
22380
+ continue;
22381
+ }
22382
+ refuseMalformedState(stateData.state, stackInfo.stackName, stackRegion, recovery);
22383
+ if (await stateBackend.loadRollbackJournal(stackInfo.stackName, stackRegion) !== null) throw rollbackJournalRefusal(stackInfo.stackName, stackRegion);
22384
+ const assetRedirect = await resolveAssetRedirect(stackInfo.assetManifestPath, stackRegion);
22385
+ if (assetRedirect) rewriteTemplateAssetReferences(stackInfo.template, assetRedirect);
22386
+ const overrides = environments.length === 0 ? [] : overridesForStack(environments, stackInfo.stackName, await accountOf(stackInfo), stackRegion, options.revert === true);
22387
+ const diff = async (state) => {
22388
+ const result = await computeStackDiff(state, stackInfo.template, stackRegion, stackInfo.stackName, stateBackend, diffCalculator, {
22389
+ canonicalizeProperties,
22390
+ ...options.cfnFallback === false && { cfnFallback: false },
22391
+ producerLookup,
22392
+ ...stackInfo.account && { consumerAccount: stackInfo.account },
22393
+ refusalRecovery: recovery,
22394
+ inheritSecretBearingTemplate: false,
22395
+ previewMaskedInputs: true,
22396
+ ...stackInfo.nestedTemplates && { nestedTemplates: stackInfo.nestedTemplates }
22397
+ });
22398
+ return {
22399
+ changes: result.changes,
22400
+ blocking: result.blocking
22401
+ };
22402
+ };
22403
+ const plan = await planStackRefactor({
22404
+ stackName: stackInfo.stackName,
22405
+ region: stackRegion,
22406
+ state: stateData.state,
22407
+ etag: stateData.etag,
22408
+ template: stackInfo.template,
22409
+ overrides,
22410
+ diff,
22411
+ recovery
22412
+ });
22413
+ plans.push(plan);
22414
+ planStacks.set(plan, stackInfo);
22415
+ }
22416
+ const accountByPlan = /* @__PURE__ */ new Map();
22417
+ if (plans.length > 1) for (const plan of plans) accountByPlan.set(plan, await accountOf(planStacks.get(plan)));
22418
+ const movePlan = plans.length > 1 ? await planMoves(plans, (plan) => envKey(accountByPlan.get(plan), plan.region), moveOverridesOf(environments, new Set(accountByPlan.values()), options.revert === true)) : {
22419
+ moves: [],
22420
+ differing: [],
22421
+ refused: [],
22422
+ ambiguous: []
22423
+ };
22424
+ if (plans.length <= 1 && environments.length > 0) {
22425
+ const lone = moveOverridesOf(environments, new Set(plans.length === 1 ? [await accountOf(planStacks.get(plans[0]))] : []), options.revert === true);
22426
+ for (const o of lone) movePlan.refused.push({
22427
+ fromStack: o.fromStack,
22428
+ from: o.from,
22429
+ toStack: o.toStack,
22430
+ to: o.to,
22431
+ reason: "a move needs both stacks selected; name both, or pass --all"
22432
+ });
22433
+ }
22434
+ for (const plan of plans) for (const line of renderRefactorPlan(plan)) logger.info(line);
22435
+ for (const line of renderMovePlan(movePlan)) logger.info(line);
22436
+ if (plans.some((p) => p.ambiguous.length > 0) || movePlan.ambiguous.length > 0) {
22437
+ const withAccounts = [];
22438
+ for (const plan of plans) {
22439
+ if (plan.ambiguous.length === 0) continue;
22440
+ withAccounts.push({
22441
+ plan,
22442
+ account: await accountOf(planStacks.get(plan))
22443
+ });
22444
+ }
22445
+ const moveGroups = [];
22446
+ for (const group of movePlan.ambiguous) moveGroups.push({
22447
+ group,
22448
+ account: await accountOf(planStacks.get(group.plan))
22449
+ });
22450
+ logger.info("\nA mapping file naming each ambiguous pair (edit the pairs, then pass it with --override-file):");
22451
+ for (const line of sampleMappingFile(withAccounts, moveGroups).split("\n")) logger.info(displaySafe(line));
22452
+ throw new CdkdError("cdkd refactor found resources it cannot pair on its own; nothing was written. Name each ambiguous pair in a mapping file and re-run with --override-file.", "REFACTOR_AMBIGUOUS");
22453
+ }
22454
+ const refused = [...plans.flatMap((p) => p.refusedOverrides), ...movePlan.refused];
22455
+ if (refused.length > 0) throw new CdkdError(`cdkd refactor refused ${refused.length} pair(s) the mapping file names; nothing was written. Fix or remove each refused pair in the mapping file (the reasons are above), then re-run cdkd refactor.`, "REFACTOR_REFUSED");
22456
+ const toApply = plans.filter((p) => p.renames.length > 0 || p.movesOut.length > 0 || p.movesIn.length > 0);
22457
+ if (toApply.length === 0) {
22458
+ logger.info("\nNothing to refactor.");
22459
+ return;
22460
+ }
22461
+ if (options.dryRun) {
22462
+ logger.info("\n--dry-run: state was NOT written. Re-run without --dry-run to apply.");
22463
+ return;
22464
+ }
22465
+ const count = toApply.reduce((n, p) => n + p.renames.length, 0) + movePlan.moves.length;
22466
+ if (!options.yes && !options.force) {
22467
+ if (!await confirmOrRefuse(`\nRename or move ${count} resource(s) in cdkd state as listed above? AWS resources are not touched.`, { refusal: "The cdkd refactor confirmation prompt cannot run in a non-interactive environment. Pass -y / --yes (or -f / --force) to confirm, or run the command from a real terminal." })) {
22468
+ logger.info("Refactor cancelled.");
22469
+ return;
22470
+ }
22471
+ }
22472
+ if (movePlan.moves.length > 0) {
22473
+ await withDeferredInterrupts(() => applyMoveGroup({
22474
+ plans: toApply,
22475
+ stateBackend,
22476
+ lockManager,
22477
+ recovery,
22478
+ contentionMessage: (plan) => buildLockContentionMessage({
22479
+ lockManager,
22480
+ stackName: plan.stackName,
22481
+ region: plan.region,
22482
+ recovery
22483
+ })
22484
+ }), holdNotice);
22485
+ logger.info(safeMsg`Refactored ${count} resource(s) across ${toApply.length} stack(s): ` + safeMsg`${toApply.map((p) => `${p.stackName} (${p.region})`).join(", ")}.`);
22486
+ logger.info("\nAWS resources were not touched. Run 'cdkd diff' to confirm the refactored resources show no change, and deploy the destination stacks before the stacks that import from them.");
22487
+ return;
22488
+ }
22489
+ const done = [];
22490
+ for (const plan of toApply) {
22491
+ try {
22492
+ await withDeferredInterrupts(() => applyStackRefactor({
22493
+ plan,
22494
+ stateBackend,
22495
+ lockManager,
22496
+ recovery,
22497
+ contentionMessage: () => buildLockContentionMessage({
22498
+ lockManager,
22499
+ stackName: plan.stackName,
22500
+ region: plan.region,
22501
+ recovery
22502
+ })
22503
+ }), holdNotice);
22504
+ } catch (error) {
22505
+ if (done.length > 0) logger.error(safeMsg`Already refactored before this failure, and kept: ${done.join(", ")}.`);
22506
+ throw error;
22507
+ }
22508
+ done.push(`${plan.stackName} (${plan.region})`);
22509
+ logger.info(safeMsg`Refactored ${plan.renames.length} resource(s) in stack ${plan.stackName} (${plan.region}).`);
22510
+ }
22511
+ logger.info("\nAWS resources were not touched. Run 'cdkd diff' to confirm the renamed resources show no change.");
22512
+ } finally {
22513
+ awsClients.destroy();
22514
+ }
22515
+ }
22516
+ function selectStacks(allStacks, stacks, options) {
22517
+ const logger = getLogger();
22518
+ const stackPatterns = stacks.length > 0 ? stacks : options.stack ? [options.stack] : [];
22519
+ if (allStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
22520
+ let targetStacks;
22521
+ if (options.all) {
22522
+ const { topLevel, inStages } = partitionTopLevel(allStacks);
22523
+ if (topLevel.length === 0) throw new Error(renderAllNoTopLevelStacks(inStages));
22524
+ if (inStages.length > 0) logger.info(renderAllLeftOutStageStacks(inStages));
22525
+ targetStacks = topLevel;
22526
+ } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
22527
+ else if (allStacks.length === 1) targetStacks = allStacks;
22528
+ else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all (top-level stacks; '**' for every stack)`);
22529
+ if (targetStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
22530
+ return targetStacks;
22531
+ }
22532
+ function createRefactorCommand() {
22533
+ const cmd = new Command("refactor").description("Keep resources whose logical IDs a construct rename changed, instead of replacing them (mirrors 'cdk refactor'). Rewrites cdkd state only; AWS resources are not touched.").argument("[stacks...]", "Stack name(s) to refactor. Accepts CDK display paths (e.g. 'MyStage/Api') with wildcards, or exact physical CloudFormation names.").option("--all", "Refactor every top-level stack (Stage stacks: '**')", false).option("--dry-run", "Print the refactor plan without writing state", false).option("--override-file <path>", "A JSON mapping file naming pairs the detection finds ambiguous, in the cdk refactor format: {\"environments\":[{\"account\",\"region\",\"resources\":{\"Stack.OldId\":\"Stack.NewId\"}}]}").option("--revert", "Apply the mapping file in reverse (requires --override-file)", false).option("-f, --force", "Skip the confirmation prompt", false).addOption(useCdkBootstrapAssetsOption).addOption(noCfnFallbackOption).action(withErrorHandling(refactorCommand));
22534
+ [
22535
+ ...commonOptions,
22536
+ ...appOptions,
22537
+ ...stateOptions,
22538
+ ...stackOptions,
22539
+ ...contextOptions
22540
+ ].forEach((opt) => cmd.addOption(opt));
22541
+ cmd.addOption(deprecatedRegionOption);
22542
+ return cmd;
22543
+ }
22544
+
22545
+ //#endregion
22546
+ //#region src/cli/commands/publish-assets.ts
22547
+ async function publishAssetsCommand(stacks, options) {
22548
+ const logger = getLogger();
22549
+ if (options.verbose) logger.setLevel("debug");
22550
+ warnIfDeprecatedRegion(options);
22551
+ const rawNamedRegion = rawCliRegion(options.region);
22552
+ foldRegionOption(options);
22553
+ await applyRoleArnIfSet({
22554
+ roleArn: options.roleArn,
22555
+ region: options.region
22556
+ });
22557
+ const app = resolveApp(options.app);
22558
+ if (!app) throw new Error("No app command specified. Use --app, set CDKD_APP env var, or add \"app\" to cdk.json");
22559
+ logger.info(synthesisStatusMessage(app, "Synthesizing CDK app..."));
22560
+ const synthesizer = new Synthesizer();
22561
+ const context = parseContextOptions(options.context);
22562
+ const synthOptions = {
22563
+ app,
22564
+ output: options.output,
22565
+ ...options.region && { region: options.region },
22566
+ ...options.profile && { profile: options.profile },
22567
+ ...Object.keys(context).length > 0 && { context }
22568
+ };
22569
+ const { stacks: allStacks } = await synthesizer.synthesize(synthOptions);
22570
+ logger.debug(`Found ${allStacks.length} stack(s) in assembly`);
22571
+ const stackPatterns = stacks.length > 0 ? stacks : options.stack ? [options.stack] : [];
22572
+ let targetStacks;
22573
+ if (allStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
22574
+ if (options.all) targetStacks = allStacks;
22575
+ else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
22576
+ else if (allStacks.length === 1) targetStacks = allStacks;
22577
+ else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all`);
22578
+ if (targetStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
22579
+ const effectiveRegion = await resolveEffectiveRegion(options);
22580
+ exportInferredRegionForSdk(effectiveRegion);
22581
+ const baseRegion = effectiveRegion.region;
22582
+ const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
22583
+ const stsClient = new STSClient({
22584
+ ...ambientClientDefaults(),
22585
+ region: baseRegion
22586
+ });
22587
+ const accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
22588
+ stsClient.destroy();
22589
+ const useCdkBootstrapAssets = resolveUseCdkBootstrapAssets(options.useCdkBootstrapAssets);
22590
+ let markerAccess;
22591
+ const getModeResolver = async () => {
22592
+ if (markerAccess !== void 0) return markerAccess?.resolver ?? null;
22593
+ let bucket;
22594
+ try {
22595
+ bucket = await resolveStateBucketWithDefault(options.stateBucket, baseRegion, legacyStateBucketFallbackRegion(effectiveRegion));
22596
+ } catch {
22597
+ logger.info("No cdkd state bucket found — publishing to the asset-manifest destinations (CDK bootstrap storage) verbatim. Run 'cdkd bootstrap' to opt into cdkd-owned asset storage that 'cdk gc' never touches.");
22598
+ markerAccess = null;
22599
+ return null;
22600
+ }
22601
+ const markerClients = new AwsClients({
22602
+ region: baseRegion,
22603
+ ...options.profile && { profile: options.profile }
22604
+ });
22605
+ const backend = new S3StateBackend(markerClients.s3, {
22606
+ bucket,
22607
+ prefix: options.statePrefix
22608
+ }, {
22609
+ region: baseRegion,
22610
+ ...options.profile && { profile: options.profile }
22611
+ });
22612
+ const resolver = new AssetModeResolver(backend, accountId, { ...options.profile && { profile: options.profile } });
22613
+ markerAccess = {
22614
+ resolver,
22615
+ regionFor: stackRegionResolver({
22616
+ effective: effectiveRegion,
22617
+ probe: backend,
22618
+ logger,
22619
+ siblings: allStacks.filter((s) => !s.region).map((s) => s.stackName)
22620
+ }),
22621
+ dispose: () => markerClients.destroy()
22622
+ };
22623
+ return resolver;
22624
+ };
22625
+ const regionForStack = async (stack) => {
22626
+ if (stack.region) return stack.region;
20931
22627
  if (!regionNeedsReconciliation(effectiveRegion)) return baseRegion;
20932
22628
  await getModeResolver();
20933
22629
  return markerAccess ? markerAccess.regionFor(stack.stackName) : baseRegion;
@@ -21835,7 +23531,8 @@ function parseMappingJson(raw, source) {
21835
23531
  try {
21836
23532
  parsed = JSON.parse(raw);
21837
23533
  } catch (err) {
21838
- throw new Error(`Failed to parse ${source} as JSON: ` + describeAwsFailure(err).detail);
23534
+ getLogger().debug(safeMsg`${source} failed to parse: ${parseFailureDebugDetail(err)}`);
23535
+ throw new Error(`Failed to parse ${source} as JSON: ` + describeJsonParseFailure(err, utf8ByteLength(raw)));
21839
23536
  }
21840
23537
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${source} must be a JSON object {logicalId: physicalId}`);
21841
23538
  const out = {};
@@ -21983,7 +23680,7 @@ function buildStackState(stackName, region, rows, templateParser, template, exis
21983
23680
  dependencies: deps,
21984
23681
  deletionPolicy: tmplResource.DeletionPolicy,
21985
23682
  updateReplacePolicy: tmplResource.UpdateReplacePolicy,
21986
- ...constructPathField(constructPathOf(template, row.logicalId)),
23683
+ ...constructPathField(constructPathOf$1(template, row.logicalId)),
21987
23684
  provisionedBy: row.provisionedBy ?? "sdk",
21988
23685
  ...prior && prior.physicalId === row.physicalId && (hasUnverifiableParameterRefusal(prior) || hasReasonlessBaselineRefusal(prior) && (namesParameter ??= resourcesNamingDeclaredParameter(template))(row.logicalId)) && {
21989
23686
  observedBaselineRefused: true,
@@ -22508,7 +24205,8 @@ function readNestedChildTemplate(templatePath, childLogicalId) {
22508
24205
  try {
22509
24206
  return JSON.parse(raw);
22510
24207
  } catch (err) {
22511
- throw new Error(`Failed to parse nested-stack template for '${childLogicalId}' at ${templatePath}: ${describeAwsFailure(err).detail}`);
24208
+ getLogger().debug(safeMsg`Nested-stack template for '${childLogicalId}' failed to parse: ${parseFailureDebugDetail(err)}`);
24209
+ throw new Error(`Failed to parse nested-stack template for '${childLogicalId}' at ${templatePath}: ${describeJsonParseFailure(err, utf8ByteLength(raw))}`);
22512
24210
  }
22513
24211
  }
22514
24212
  function indexGrandchildTemplatePaths(childTemplate, childTemplatePath) {
@@ -24764,7 +26462,7 @@ function attachWebSocketServer(opts) {
24764
26462
  });
24765
26463
  });
24766
26464
  ws.on("error", (err) => {
24767
- logger.debug(`WebSocket error for connection ${connectionId}: ${err instanceof Error ? err.message : String(err)}`);
26465
+ logger.debug(`WebSocket error for connection ${connectionId}: ${describeAwsFailure(err).detail}`);
24768
26466
  });
24769
26467
  for (const frame of preVerdictFrames) {
24770
26468
  const { body, isBase64Encoded } = bufferToBody$1(frame.raw, frame.isBinary);
@@ -26282,7 +27980,8 @@ function readEnvOverridesFile$3(filePath) {
26282
27980
  try {
26283
27981
  parsed = JSON.parse(raw);
26284
27982
  } catch (err) {
26285
- throw new Error(`Failed to parse --env-vars file '${filePath}' as JSON: ${describeAwsFailure(err).detail}`);
27983
+ getLogger().debug(safeMsg`--env-vars file failed to parse: ${parseFailureDebugDetail(err)}`);
27984
+ throw new Error(`Failed to parse --env-vars file '${filePath}' as JSON: ${describeJsonParseFailure(err, utf8ByteLength(raw))}`);
26286
27985
  }
26287
27986
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`--env-vars file '${filePath}' must contain a JSON object at the top level.`);
26288
27987
  return parsed;
@@ -27580,7 +29279,7 @@ async function localRunTaskCommand(target, options) {
27580
29279
  await channels.profileCredsFile.dispose();
27581
29280
  credsHostPath = void 0;
27582
29281
  } catch (err) {
27583
- getLogger().debug(`Failed to remove profile credentials tmpdir ${channels.profileCredsFile.hostPath}: ${err instanceof Error ? err.message : String(err)}`);
29282
+ getLogger().debug(`Failed to remove profile credentials tmpdir ${channels.profileCredsFile.hostPath}: ${describeAwsFailure(err).detail}`);
27584
29283
  }
27585
29284
  };
27586
29285
  try {
@@ -27589,7 +29288,7 @@ async function localRunTaskCommand(target, options) {
27589
29288
  afterContainersStopped: disposeCreds
27590
29289
  });
27591
29290
  } catch (err) {
27592
- getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
29291
+ getLogger().debug(`cleanup failed: ${describeAwsFailure(err).detail}`);
27593
29292
  }
27594
29293
  await disposeCreds();
27595
29294
  await flushStdio();
@@ -27873,13 +29572,14 @@ function readEnvOverridesFile$2(filePath) {
27873
29572
  try {
27874
29573
  raw = readFileSync(filePath, "utf-8");
27875
29574
  } catch (err) {
27876
- throw new Error(`Failed to read --env-vars file '${filePath}': ${err instanceof Error ? err.message : String(err)}`);
29575
+ throw new Error(`Failed to read --env-vars file '${filePath}': ${describeAwsFailure(err).detail}`);
27877
29576
  }
27878
29577
  let parsed;
27879
29578
  try {
27880
29579
  parsed = JSON.parse(raw);
27881
29580
  } catch (err) {
27882
- throw new Error(`Failed to parse --env-vars file '${filePath}' as JSON: ${err instanceof Error ? err.message : String(err)}`);
29581
+ getLogger().debug(safeMsg`--env-vars file failed to parse: ${parseFailureDebugDetail(err)}`);
29582
+ throw new Error(`Failed to parse --env-vars file '${filePath}' as JSON: ${describeJsonParseFailure(err, utf8ByteLength(raw))}`);
27883
29583
  }
27884
29584
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`--env-vars file '${filePath}' must contain a JSON object at the top level.`);
27885
29585
  return parsed;
@@ -28249,7 +29949,7 @@ async function localInvokeAgentCoreCommand(target, options) {
28249
29949
  const stream = logStream;
28250
29950
  logStream = void 0;
28251
29951
  drainInFlight = killAndDrainContainerLogs(containerId, stream).catch((err) => {
28252
- getLogger().debug(safeMsg`container log drain failed: ${err instanceof Error ? err.message : String(err)}`);
29952
+ getLogger().debug(safeMsg`container log drain failed: ${describeAwsFailure(err).detail}`);
28253
29953
  }).finally(() => {
28254
29954
  drainInFlight = void 0;
28255
29955
  });
@@ -28269,7 +29969,7 @@ async function localInvokeAgentCoreCommand(target, options) {
28269
29969
  if (stateProvider) try {
28270
29970
  stateProvider.dispose();
28271
29971
  } catch (err) {
28272
- getLogger().debug(`state provider dispose failed: ${err instanceof Error ? err.message : String(err)}`);
29972
+ getLogger().debug(`state provider dispose failed: ${describeAwsFailure(err).detail}`);
28273
29973
  }
28274
29974
  if (startPending) getLogger().info("Waiting for the in-flight docker run so its container can be removed...");
28275
29975
  if (startInFlight && !await settlesWithin(startInFlight, containerStartWait.ms)) {
@@ -28283,16 +29983,16 @@ async function localInvokeAgentCoreCommand(target, options) {
28283
29983
  if (containerId) try {
28284
29984
  await removeContainer(containerId);
28285
29985
  } catch (err) {
28286
- getLogger().debug(`removeContainer(${containerId}) failed: ${err instanceof Error ? err.message : String(err)}`);
29986
+ getLogger().debug(`removeContainer(${containerId}) failed: ${describeAwsFailure(err).detail}`);
28287
29987
  }
28288
29988
  if (profileCredsFile) try {
28289
29989
  await profileCredsFile.dispose();
28290
29990
  } catch (err) {
28291
- getLogger().debug(`Failed to remove profile credentials tmpdir ${profileCredsFile.hostPath}: ${err instanceof Error ? err.message : String(err)}`);
29991
+ getLogger().debug(`Failed to remove profile credentials tmpdir ${profileCredsFile.hostPath}: ${describeAwsFailure(err).detail}`);
28292
29992
  }
28293
29993
  await flushStdio();
28294
29994
  }, (err) => {
28295
- getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
29995
+ getLogger().debug(`cleanup failed: ${describeAwsFailure(err).detail}`);
28296
29996
  });
28297
29997
  try {
28298
29998
  if (typeof options.assumeRole === "string") explicitRoleArnOrThrow("--assume-role", options.assumeRole, (message) => new CdkdError(message, "LOCAL_INVOKE_AGENTCORE_ASSUME_ROLE_INVALID"));
@@ -29102,7 +30802,7 @@ async function readEvent$1(options) {
29102
30802
  try {
29103
30803
  raw = readFileSync(options.event, "utf-8");
29104
30804
  } catch (err) {
29105
- throw new CdkdError(`Failed to read --event file '${options.event}': ${err instanceof Error ? err.message : String(err)}`, "LOCAL_INVOKE_AGENTCORE_EVENT_READ_FAILED");
30805
+ throw new CdkdError(`Failed to read --event file '${options.event}': ${describeAwsFailure(err).detail}`, "LOCAL_INVOKE_AGENTCORE_EVENT_READ_FAILED");
29106
30806
  }
29107
30807
  return parseEvent$1(raw, options.event);
29108
30808
  }
@@ -29112,7 +30812,8 @@ function parseEvent$1(raw, source) {
29112
30812
  try {
29113
30813
  return JSON.parse(raw);
29114
30814
  } catch (err) {
29115
- throw new CdkdError(`Failed to parse event payload from ${source} as JSON: ${err instanceof Error ? err.message : String(err)}`, "LOCAL_INVOKE_AGENTCORE_EVENT_PARSE_FAILED");
30815
+ getLogger().debug(safeMsg`Event payload failed to parse: ${parseFailureDebugDetail(err)}`);
30816
+ throw new CdkdError(`Failed to parse event payload from ${source} as JSON: ${describeJsonParseFailure(err, utf8ByteLength(raw))}`, "LOCAL_INVOKE_AGENTCORE_EVENT_PARSE_FAILED");
29116
30817
  }
29117
30818
  }
29118
30819
  async function readStdin$1() {
@@ -29149,13 +30850,14 @@ function readEnvOverridesFile$1(filePath) {
29149
30850
  try {
29150
30851
  raw = readFileSync(filePath, "utf-8");
29151
30852
  } catch (err) {
29152
- throw new CdkdError(`Failed to read --env-vars file '${filePath}': ${err instanceof Error ? err.message : String(err)}`, "LOCAL_INVOKE_AGENTCORE_ENV_VARS_READ_FAILED");
30853
+ throw new CdkdError(`Failed to read --env-vars file '${filePath}': ${describeAwsFailure(err).detail}`, "LOCAL_INVOKE_AGENTCORE_ENV_VARS_READ_FAILED");
29153
30854
  }
29154
30855
  let parsed;
29155
30856
  try {
29156
30857
  parsed = JSON.parse(raw);
29157
30858
  } catch (err) {
29158
- throw new CdkdError(`Failed to parse --env-vars file '${filePath}' as JSON: ${err instanceof Error ? err.message : String(err)}`, "LOCAL_INVOKE_AGENTCORE_ENV_VARS_PARSE_FAILED");
30859
+ getLogger().debug(safeMsg`--env-vars file failed to parse: ${parseFailureDebugDetail(err)}`);
30860
+ throw new CdkdError(`Failed to parse --env-vars file '${filePath}' as JSON: ${describeJsonParseFailure(err, utf8ByteLength(raw))}`, "LOCAL_INVOKE_AGENTCORE_ENV_VARS_PARSE_FAILED");
29159
30861
  }
29160
30862
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new CdkdError(`--env-vars file '${filePath}' must contain a JSON object at the top level.`, "LOCAL_INVOKE_AGENTCORE_ENV_VARS_NOT_OBJECT");
29161
30863
  return parsed;
@@ -29267,14 +30969,14 @@ async function localInvokeCommand(target, options) {
29267
30969
  const drainLogs = singleFlight(async () => {
29268
30970
  await killAndDrainContainerLogs(containerId, logStream);
29269
30971
  }, (err) => {
29270
- getLogger().debug(safeMsg`container log drain failed: ${err instanceof Error ? err.message : String(err)}`);
30972
+ getLogger().debug(safeMsg`container log drain failed: ${describeAwsFailure(err).detail}`);
29271
30973
  });
29272
30974
  const cleanup = singleFlight(async () => {
29273
30975
  await drainLogs();
29274
30976
  if (containerId) try {
29275
30977
  await removeContainer(containerId);
29276
30978
  } catch (err) {
29277
- getLogger().debug(`removeContainer(${containerId}) failed: ${err instanceof Error ? err.message : String(err)}`);
30979
+ getLogger().debug(`removeContainer(${containerId}) failed: ${describeAwsFailure(err).detail}`);
29278
30980
  }
29279
30981
  if (imagePlan?.inlineTmpDir) try {
29280
30982
  rmSync(imagePlan.inlineTmpDir, {
@@ -29282,7 +30984,7 @@ async function localInvokeCommand(target, options) {
29282
30984
  force: true
29283
30985
  });
29284
30986
  } catch (err) {
29285
- getLogger().debug(`Failed to remove inline-code tmpdir ${imagePlan.inlineTmpDir}: ${err instanceof Error ? err.message : String(err)}`);
30987
+ getLogger().debug(`Failed to remove inline-code tmpdir ${imagePlan.inlineTmpDir}: ${describeAwsFailure(err).detail}`);
29286
30988
  }
29287
30989
  if (imagePlan?.layersTmpDir) try {
29288
30990
  rmSync(imagePlan.layersTmpDir, {
@@ -29290,7 +30992,7 @@ async function localInvokeCommand(target, options) {
29290
30992
  force: true
29291
30993
  });
29292
30994
  } catch (err) {
29293
- getLogger().debug(`Failed to remove merged-layers tmpdir ${imagePlan.layersTmpDir}: ${err instanceof Error ? err.message : String(err)}`);
30995
+ getLogger().debug(`Failed to remove merged-layers tmpdir ${imagePlan.layersTmpDir}: ${describeAwsFailure(err).detail}`);
29294
30996
  }
29295
30997
  if (imagePlan?.layerArnTmpDirs) for (const dir of imagePlan.layerArnTmpDirs) try {
29296
30998
  rmSync(dir, {
@@ -29298,16 +31000,16 @@ async function localInvokeCommand(target, options) {
29298
31000
  force: true
29299
31001
  });
29300
31002
  } catch (err) {
29301
- getLogger().debug(`Failed to remove ARN-layer tmpdir ${dir}: ${err instanceof Error ? err.message : String(err)}`);
31003
+ getLogger().debug(`Failed to remove ARN-layer tmpdir ${dir}: ${describeAwsFailure(err).detail}`);
29302
31004
  }
29303
31005
  if (profileCredsFile) try {
29304
31006
  await profileCredsFile.dispose();
29305
31007
  } catch (err) {
29306
- getLogger().debug(`Failed to remove profile credentials tmpdir ${profileCredsFile.hostPath}: ${err instanceof Error ? err.message : String(err)}`);
31008
+ getLogger().debug(`Failed to remove profile credentials tmpdir ${profileCredsFile.hostPath}: ${describeAwsFailure(err).detail}`);
29307
31009
  }
29308
31010
  await flushStdio();
29309
31011
  }, (err) => {
29310
- getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
31012
+ getLogger().debug(`cleanup failed: ${describeAwsFailure(err).detail}`);
29311
31013
  });
29312
31014
  try {
29313
31015
  if (typeof options.assumeRole === "string") explicitRoleArnOrThrow("--assume-role", options.assumeRole);
@@ -29695,13 +31397,14 @@ function readEnvOverridesFile(filePath) {
29695
31397
  try {
29696
31398
  raw = readFileSync(filePath, "utf-8");
29697
31399
  } catch (err) {
29698
- throw new Error(`Failed to read --env-vars file '${filePath}': ${err instanceof Error ? err.message : String(err)}`);
31400
+ throw new Error(`Failed to read --env-vars file '${filePath}': ${describeAwsFailure(err).detail}`);
29699
31401
  }
29700
31402
  let parsed;
29701
31403
  try {
29702
31404
  parsed = JSON.parse(raw);
29703
31405
  } catch (err) {
29704
- throw new Error(`Failed to parse --env-vars file '${filePath}' as JSON: ${err instanceof Error ? err.message : String(err)}`);
31406
+ getLogger().debug(safeMsg`--env-vars file failed to parse: ${parseFailureDebugDetail(err)}`);
31407
+ throw new Error(`Failed to parse --env-vars file '${filePath}' as JSON: ${describeJsonParseFailure(err, utf8ByteLength(raw))}`);
29705
31408
  }
29706
31409
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`--env-vars file '${filePath}' must contain a JSON object at the top level.`);
29707
31410
  return parsed;
@@ -29716,7 +31419,8 @@ function parseEvent(raw, source) {
29716
31419
  try {
29717
31420
  return JSON.parse(raw);
29718
31421
  } catch (err) {
29719
- throw new Error(`Failed to parse event payload from ${source} as JSON: ${err instanceof Error ? err.message : String(err)}`);
31422
+ getLogger().debug(safeMsg`Event payload failed to parse: ${parseFailureDebugDetail(err)}`);
31423
+ throw new Error(`Failed to parse event payload from ${source} as JSON: ${describeJsonParseFailure(err, utf8ByteLength(raw))}`);
29720
31424
  }
29721
31425
  }
29722
31426
  async function readStdin() {
@@ -29935,6 +31639,7 @@ function buildProgram() {
29935
31639
  program.addCommand(createEventsCommand());
29936
31640
  program.addCommand(createGcCommand());
29937
31641
  program.addCommand(createOrphanCommand());
31642
+ program.addCommand(createRefactorCommand());
29938
31643
  program.addCommand(createImportCommand());
29939
31644
  program.addCommand(createPublishAssetsCommand());
29940
31645
  program.addCommand(createForceUnlockCommand());
@@ -29960,4 +31665,4 @@ function collectVerbFlags(program) {
29960
31665
 
29961
31666
  //#endregion
29962
31667
  export { resolveSecretDerivedPrincipals as a, buildProgram, isResolvableSecretPrincipalList as i, runDestroyForStack as n, canonicalizeIpProtocolValue as o, holdsUnprovenSecretPrincipalToken as r, resolvedResourceTimeoutMs as s, canonicalizeIpv4Cidr as t };
29963
- //# sourceMappingURL=program-CAibYjpk.js.map
31668
+ //# sourceMappingURL=program-TEYrbsKm.js.map