@go-to-k/cdkd 0.290.33 → 0.290.34

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.
@@ -1,8 +1,8 @@
1
- import { $ as secretBearing, $n as recordMaskOnlyValue, $r as AssetManifestLoader, $t as s3BucketArn, A as extractDeploymentEventError, Ai as getAwsClients, An as refuseMalformedState, Ar as BOOTSTRAP_MARKER_PREFIX, At as isImpossibleEmptyStoredAttribute, B as toCfnInteger, Bi as IntrinsicResolutionRefusalError, Bn as STATE_SOURCED_BASELINE_RULES, Br as buildDockerImage, Bt as coerceCfnBoolean, C as buildFinalSnapshotIdentifier, Ci as canonicalizeRegion, Cn as producerRecordKey, Cr as stringifyValue, Ct as isTerminationProtectionPropagationError, D as refusesFinalSnapshot, Dn as refuseMalformedOutputsForDestroy, Dr as loadPublishableAssetManifest, Dt as cfnRefValueFromPhysicalId, E as isFinalSnapshotError, Ei as processStackMessages, En as refuseMalformedOutputs, Er as createAssetRedirectResolver, Et as carriesFetchableDynamicReference, F as isStatefulRecreateTargetSync, Fn as findSilentDropProperties, Fr as parseBootstrapMarker, Ft as isSettledInstanceState, G as gray, Gi as NestedStackChildDirectDestroyError, Gn as createSecretMasker, Gr as formatDockerLoginError, Gt as readConfigString, H as formatResourceLine, Hi as LocalStartServiceError, Hn as STATE_SOURCED_READBACK_RULES, Hr as describeDockerExecFailure, Ht as configBooleanRefusal, I as renderStatefulReason, Ii as CrossAccountSecretRefusalError, In as describeTypeWithThrottleRetry, Ir as readBootstrapMarkerBody, It as WAFv2WebACLProvider, J as yellow, Ji as ResourceTimeoutError, Jn as identityKeyFor, Jr as redactDockerArgvValues, Jt as requireConfigObject, K as green, Ki as PartialFailureError, Kn as dynamicReferenceTokens, Kr as getDockerCmd, Kt as replayWarn, L as WARM_THROUGHPUT_MEMBERS, Ln as withRetry, Lr as validateAssetBucketName, Lt as normalizeAwsTagsToCfn, M as planOrphanAdoption, Mi as setAwsClients, Mn as repairMalformedResourcePropertiesForReadOnly, Mr as ensureAssetStorage, Mt as isUnboundTemplateParameter, N as MULTI_REGION_RECREATE_BLOCKED_TYPES, Nn as repairMalformedResourcesForReadOnly, Nr as getBootstrapMarkerKey, Nt as parameterTypeMayLoseSecretIdentity, O as unsupportedFinalSnapshotError, Oi as resolveBucketRegion, On as refuseMalformedResourcePropertiesForOrphan, Or as rewriteTemplateAssetReferences, Ot as coerceParameterTypedValue, P as isStatefulRecreateTargetForReplace, Pi as CdkdError, Pn as findActionableSilentDrops, Pr as isCrossRegionRedirect, Pt as refStateLookupFromResource, Q as isExportAliasCollision, Qn as maskSecretsInText, Qr as stripControlChars, Qt as withSharedDrainBudget, R as coerceWarmThroughput$1, Ri as DeployCancelledError, Rn as DagBuilder, Rr as validateContainerRepoName, Rt as resolveExplicitPhysicalId, S as PRE_DELETE_SNAPSHOT_TYPES, Si as PARTITION_TABLE, Sn as malformedStateRefusalMessage, Sr as AssetPublisher, St as disableInstanceApiTermination, T as createPreDeleteFinalSnapshot, Ti as AssemblyReader, Tn as refuseMalformedNestedChildOutputs, Tr as buildAssetRedirectMap, Tt as carriesDynamicReference, U as bold, Un as TEMPLATE_SOURCED_RULES, Ur as describeDockerFailure, Ut as configIntegerRefusal, V as toFiniteNumber, Vi as LocalInvokeBuildError$1, Vn as STATE_SOURCED_CROSS_GENERATION_RULES, Vr as describeDockerCapturedOutput, Vt as coerceCfnInteger, W as cyan, Wi as MalformedProducerRecordRefusalError, Wn as carriesSecretMask, Wr as dockerSpawnEnvWithSensitive, Wt as configStringRefusal, X as collectPublishedOutputNames, Xi as StackHasActiveImportsError, Xn as markSameGenerationBag, Xr as runDockerStreaming, Xt as classifyReplaySecretRegion, Y as collectDeclaredOutputNames, Yi as ResourceUpdateNotSupportedError, Yn as isSingleDynamicReferenceToken, Yr as runDockerForeground, Yt as requireConfigString, Z as exportAliasCollisionScrubWarning, Zi as StackTerminationProtectionError, Zn as maskSecretsInError, Zr as escapeRegExp, Zt as producerRegionsFromState, _ as isSecretBearingReferenceString, _i as findLargeInlineResources, _n as malformedOutputsRefusalMessage, _r as importableOutputs, _t as isWaitAbandonedError, a as DeploymentEventsStore, aa as isRetryableTransientError, ai as resolveApp, an as AWS_CREDENTIAL_ENV_KEYS, ar as rebuildClientForBucketRegion, at as clearOnUpdateRemoval, b as bindingSkippedOutputs, bi as decodeListingKey, bn as malformedResourcePropertiesWarning, br as orphansCarriedFrom, bt as deleteIndeterminateGuards, c as replayFailedOperations, ca as markNonRetryable, ci as resolveSkipPrefix, cn as envCredentialsAreAssumedRole, cr as buildLockContentionMessage, ct as createMaskedRetryLogger, d as updatePartialReason, da as describeAwsFailure, di as resolveUseCdkBootstrapAssets, dn as STATE_RESOURCES_MALFORMED, dr as shellQuote, dt as beginCommandInterruptScope, ei as getDockerImageBySourceHash, en as s3BucketDomainName, er as recoverMaskedOutput, et as secretBearingStateKeyWarning, f as withResourceDeadline, fa as safeStringify, fi as stateBucketExistenceConfirmed, fn as hasReadableOutputs, fr as CUSTOM_RESOURCE_RESPONSE_PREFIX, ft as endCommandInterruptScope, g as bagHoldsSecretExpression, gi as MIGRATE_TMP_PREFIX, gn as malformedLocalOutputsWarning, gr as importableOutputKeys, gt as CloudControlProvider, h as computeImplicitDeleteEdges, hi as CFN_TEMPLATE_URL_LIMIT, hn as malformedExportSourceWarning, hr as hasReadableExportSet, ht as startInterruptWatch, i as DeploymentEventsReader, ia as isMarkedNonRetryable, ii as getLegacyStateBucketName, in as applyRoleArnIfSet, ir as S3StateBackend, it as collectInlinePolicyNamesManagedBySiblings, j as makeSiblingClaimReader, ji as resetAwsClients, jn as repairMalformedOutputsForReadOnly, jr as assertAssetBucketRegion, jt as isNamelessDynamicReferenceError, k as makeCanonicalizePropertiesFn, ki as AwsClients, kn as refuseMalformedResourcesForDestroy, kr as AssetModeResolver, kt as getAccountInfo, l as replayRollback, la as markRedactedCause, li as resolveStateBucketWithDefault, ln as DiffCalculator, lr as forceQuitRecoveryClause, lt as maskDeep, m as IMPLICIT_DELETE_DEPENDENCIES, mi as CFN_TEMPLATE_BODY_LIMIT, mn as malformedExportNamesWarning, mr as exportNamesCarriedFrom, mt as isInterruptedWaitError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, na as normalizeAwsError, ni as synthesisStatusMessage, nn as s3BucketRegionalDomainName, nr as scrubResourceRecord, nt as getCurrentResourceSecrets, o as planFailedOps, oa as isThrottlingError, oi as resolveAutoAssetStorage, on as applyCallerIdentityCredentials, or as UNREPRODUCIBLE_LOCK_CLAUSE, ot as ProviderRegistry, p as maskingRetryLogger, pi as warnDeprecatedNoPrefixCliFlag, pn as hasReadableResources, pr as DEFAULT_STATE_PREFIX, pt as interruptWatchListenerCount, q as red, qi as ProvisioningError, qn as errorCauseChain, qr as partitionSensitiveEnv, qt as requireConfigArray, r as DeployEngine, ra as withErrorHandling, ri as getDefaultStateBucketName, rn as s3BucketWebsiteUrl, rr as LockManager, rt as IAMRoleProvider, s as planRollback, sa as isTransientServerError, si as resolveCaptureObservedState, sn as callerEnvCredentials, sr as buildForceUnlockCommand, st as wouldReturnToSdkProvider, t as DEFAULT_RESOURCE_TIMEOUT_MS, ti as Synthesizer, tn as s3BucketDualStackDomainName, tr as redactSecretsForState, tt as secretSafeKeyDisplay, u as updatePartialMessage, ua as retryClassificationText, ui as resolveStateBucketWithDefaultAndSource, un as INTRINSIC_KEYS, ur as formatLockExpiry, ut as maskerOrIdentity, v as keptWholeReasonText, vi as uploadCfnTemplate, vn as malformedOutputsWarning, vr as isReadableBag, vt as slowCcOperationTimeoutMs, w as ccRoutedFinalSnapshotError, wi as derivePartitionAndUrlSuffix, wn as refuseDivergentRecordRegionForDestroy, wr as WorkGraph, wt as IntrinsicFunctionResolver, x as ATOMIC_FINAL_SNAPSHOT_TYPES, xi as expectedOwnerParam, xn as malformedResourcesWarning, xr as shouldRetainResource, xt as deleteSkipReason, y as mergeNoChangeOutputs, yi as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, yn as malformedRenderedContainersWarning, yr as orphansAfterRollback, yt as UNSPECIFIED_SKIP_REASON, z as isWarmThroughputDecrease, zi as DynamicReferenceRegionAmbiguousError, zn as TemplateParser, zr as buildDenyExternalAccessPolicy, zt as assertRegionMatch } from "./deploy-engine-B6TcGQSU.js";
1
+ import { $ as isExportAliasCollision, $n as maskSecretsInText, $r as stripControlChars, $t as withSharedDrainBudget, A as makeCanonicalizePropertiesFn, Ai as AwsClients, An as refuseMalformedResourcesForDestroy, Ar as AssetModeResolver, At as getAccountInfo, B as isWarmThroughputDecrease, Bi as DynamicReferenceRegionAmbiguousError, Bn as TemplateParser, Br as buildDenyExternalAccessPolicy, Bt as assertRegionMatch, C as PRE_DELETE_SNAPSHOT_TYPES, Ci as PARTITION_TABLE, Cn as malformedStateRefusalMessage, Cr as AssetPublisher, Ct as disableInstanceApiTermination, D as isFinalSnapshotError, Di as processStackMessages, Dn as refuseMalformedOutputs, Dr as createAssetRedirectResolver, Dt as carriesFetchableDynamicReference, E as createPreDeleteFinalSnapshot, Ei as AssemblyReader, En as refuseMalformedNestedChildOutputs, Er as buildAssetRedirectMap, Et as carriesDynamicReference, F as isStatefulRecreateTargetForReplace, Fi as CdkdError, Fn as findActionableSilentDrops, Fr as isCrossRegionRedirect, Ft as refStateLookupFromResource, G as cyan, Gi as MalformedProducerRecordRefusalError, Gn as carriesSecretMask, Gr as dockerSpawnEnvWithSensitive, Gt as configStringRefusal, H as toFiniteNumber, Hi as LocalInvokeBuildError$1, Hn as STATE_SOURCED_CROSS_GENERATION_RULES, Hr as describeDockerCapturedOutput, Ht as coerceCfnInteger, I as isStatefulRecreateTargetSync, In as findSilentDropProperties, Ir as parseBootstrapMarker, It as isSettledInstanceState, J as red, Ji as ProvisioningError, Jn as errorCauseChain, Jr as partitionSensitiveEnv, Jt as requireConfigArray, K as gray, Ki as NestedStackChildDirectDestroyError, Kn as createSecretMasker, Kr as formatDockerLoginError, Kt as readConfigString, L as renderStatefulReason, Li as CrossAccountSecretRefusalError, Ln as describeTypeWithThrottleRetry, Lr as readBootstrapMarkerBody, Lt as WAFv2WebACLProvider, M as makeSiblingClaimReader, Mi as resetAwsClients, Mn as repairMalformedOutputsForReadOnly, Mr as assertAssetBucketRegion, Mt as isNamelessDynamicReferenceError, N as planOrphanAdoption, Ni as setAwsClients, Nn as repairMalformedResourcePropertiesForReadOnly, Nr as ensureAssetStorage, Nt as isUnboundTemplateParameter, O as refusesFinalSnapshot, On as refuseMalformedOutputsForDestroy, Or as loadPublishableAssetManifest, Ot as cfnRefValueFromPhysicalId, P as MULTI_REGION_RECREATE_BLOCKED_TYPES, Pn as repairMalformedResourcesForReadOnly, Pr as getBootstrapMarkerKey, Pt as parameterTypeMayLoseSecretIdentity, Q as exportAliasCollisionScrubWarning, Qi as StackTerminationProtectionError, Qn as maskSecretsInError, Qr as escapeRegExp, Qt as producerRegionsFromState, R as WARM_THROUGHPUT_MEMBERS, Rn as withRetry, Rr as validateAssetBucketName, Rt as normalizeAwsTagsToCfn, S as ATOMIC_FINAL_SNAPSHOT_TYPES, Si as expectedOwnerParam, Sn as malformedResourcesWarning, Sr as shouldRetainResource, St as deleteSkipReason, T as ccRoutedFinalSnapshotError, Ti as derivePartitionAndUrlSuffix, Tn as refuseDivergentRecordRegionForDestroy, Tr as WorkGraph, Tt as IntrinsicFunctionResolver, U as formatResourceLine, Ui as LocalStartServiceError, Un as STATE_SOURCED_READBACK_RULES, Ur as describeDockerExecFailure, Ut as configBooleanRefusal, V as toCfnInteger, Vi as IntrinsicResolutionRefusalError, Vn as STATE_SOURCED_BASELINE_RULES, Vr as buildDockerImage, Vt as coerceCfnBoolean, W as bold, Wn as TEMPLATE_SOURCED_RULES, Wr as describeDockerFailure, Wt as configIntegerRefusal, X as collectDeclaredOutputNames, Xi as ResourceUpdateNotSupportedError, Xn as isSingleDynamicReferenceToken, Xr as runDockerForeground, Xt as requireConfigString, Y as yellow, Yi as ResourceTimeoutError, Yn as identityKeyFor, Yr as redactDockerArgvValues, Yt as requireConfigObject, Z as collectPublishedOutputNames, Zi as StackHasActiveImportsError, Zn as markSameGenerationBag, Zr as runDockerStreaming, Zt as classifyReplaySecretRegion, _ as bagHoldsSecretExpression, _i as MIGRATE_TMP_PREFIX, _n as malformedLocalOutputsWarning, _r as importableOutputKeys, _t as CloudControlProvider, a as DeploymentEventsStore, aa as isMarkedNonRetryable, ai as getLegacyStateBucketName, an as applyRoleArnIfSet, ar as S3StateBackend, at as collectInlinePolicyNamesManagedBySiblings, b as mergeNoChangeOutputs, bi as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, bn as malformedRenderedContainersWarning, br as orphansAfterRollback, bt as UNSPECIFIED_SKIP_REASON, c as replayFailedOperations, ca as isTransientServerError, ci as resolveCaptureObservedState, cn as callerEnvCredentials, cr as buildForceUnlockCommand, ct as wouldReturnToSdkProvider, d as updatePartialMessage, da as retryClassificationText, di as resolveStateBucketWithDefaultAndSource, dn as INTRINSIC_KEYS, dr as formatLockExpiry, dt as maskerOrIdentity, ea as SynthesisError, ei as AssetManifestLoader, en as s3BucketArn, er as recordMaskOnlyValue, et as secretBearing, f as updatePartialReason, fa as describeAwsFailure, fi as resolveUseCdkBootstrapAssets, fn as STATE_RESOURCES_MALFORMED, fr as shellQuote, ft as beginCommandInterruptScope, g as computeImplicitDeleteEdges, gi as CFN_TEMPLATE_URL_LIMIT, gn as malformedExportSourceWarning, gr as hasReadableExportSet, gt as startInterruptWatch, h as IMPLICIT_DELETE_DEPENDENCIES, hi as CFN_TEMPLATE_BODY_LIMIT, hn as malformedExportNamesWarning, hr as exportNamesCarriedFrom, ht as isInterruptedWaitError, i as DeploymentEventsReader, ia as withErrorHandling, ii as getDefaultStateBucketName, in as s3BucketWebsiteUrl, ir as LockManager, it as IAMRoleProvider, j as extractDeploymentEventError, ji as getAwsClients, jn as refuseMalformedState, jr as BOOTSTRAP_MARKER_PREFIX, jt as isImpossibleEmptyStoredAttribute, k as unsupportedFinalSnapshotError, ki as resolveBucketRegion, kn as refuseMalformedResourcePropertiesForOrphan, kr as rewriteTemplateAssetReferences, kt as coerceParameterTypedValue, l as replayRollback, la as markNonRetryable, li as resolveSkipPrefix, ln as envCredentialsAreAssumedRole, lr as buildLockContentionMessage, lt as createMaskedRetryLogger, m as maskingRetryLogger, mi as warnDeprecatedNoPrefixCliFlag, mn as hasReadableResources, mr as DEFAULT_STATE_PREFIX, mt as interruptWatchListenerCount, n as DEFAULT_RESOURCE_WARN_AFTER_MS, ni as Synthesizer, nn as s3BucketDualStackDomainName, nr as redactSecretsForState, nt as secretSafeKeyDisplay, o as planFailedOps, oa as isRetryableTransientError, oi as resolveApp, on as AWS_CREDENTIAL_ENV_KEYS, or as rebuildClientForBucketRegion, ot as clearOnUpdateRemoval, p as withResourceDeadline, pa as safeStringify, pi as stateBucketExistenceConfirmed, pn as hasReadableOutputs, pr as CUSTOM_RESOURCE_RESPONSE_PREFIX, pt as endCommandInterruptScope, q as green, qi as PartialFailureError, qn as dynamicReferenceTokens, qr as getDockerCmd, qt as replayWarn, r as DeployEngine, ra as normalizeAwsError, ri as synthesisStatusMessage, rn as s3BucketRegionalDomainName, rr as scrubResourceRecord, rt as getCurrentResourceSecrets, s as planRollback, sa as isThrottlingError, si as resolveAutoAssetStorage, sn as applyCallerIdentityCredentials, sr as UNREPRODUCIBLE_LOCK_CLAUSE, st as ProviderRegistry, t as DEFAULT_RESOURCE_TIMEOUT_MS, ti as getDockerImageBySourceHash, tn as s3BucketDomainName, tr as recoverMaskedOutput, tt as secretBearingStateKeyWarning, u as resolveReplacementOldType, ua as markRedactedCause, ui as resolveStateBucketWithDefault, un as DiffCalculator, ur as forceQuitRecoveryClause, ut as maskDeep, v as isSecretBearingReferenceString, vi as findLargeInlineResources, vn as malformedOutputsRefusalMessage, vr as importableOutputs, vt as isWaitAbandonedError, w as buildFinalSnapshotIdentifier, wi as canonicalizeRegion, wn as producerRecordKey, wr as stringifyValue, wt as isTerminationProtectionPropagationError, x as bindingSkippedOutputs, xi as decodeListingKey, xn as malformedResourcePropertiesWarning, xr as orphansCarriedFrom, xt as deleteIndeterminateGuards, y as keptWholeReasonText, yi as uploadCfnTemplate, yn as malformedOutputsWarning, yr as isReadableBag, yt as slowCcOperationTimeoutMs, z as coerceWarmThroughput$1, zi as DeployCancelledError, zn as DagBuilder, zr as validateContainerRepoName, zt as resolveExplicitPhysicalId } from "./deploy-engine-efiVJ-rX.js";
2
2
  import { C as displayAwsMessage, D as truncateCodePoints, E as isPasteableIdent, S as UNRENDERABLE, T as displaySafe, _ as withSkipPrefix, b as SECRET_REF_MAX_CODE_POINTS, c as PATTERN_B_NAME_OPTIONS, f as explicitNamePropertyFor, h as getCurrentStackName, i as reserveStdoutForPayload, l as PATTERN_B_NAME_PROPERTIES, m as generateResourceNameWithFallback, n as getLogger, o as runStackBuffered, p as generateResourceName, s as getLiveRenderer, u as PATTERN_B_RESOURCE_TYPES, v as withStackName, w as displayIdent, x as STACK_REF_MAX_CODE_POINTS } from "./logger-BX4pJk0T.js";
3
3
  import { n as awsClientDefaults } from "./aws-client-defaults-BoIxyCir.js";
4
- import { t as getCdkdVersion } from "./version-xHGBnQbJ.js";
5
- import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-BCpZ70Ws.js";
4
+ import { t as getCdkdVersion } from "./version-CpyoQ3PO.js";
5
+ import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-BTxYWlwu.js";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
  import { createHash, randomBytes, randomUUID } from "node:crypto";
8
8
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -2758,16 +2758,13 @@ const EMPTY_ALLOW_SET$1 = /* @__PURE__ */ new Set();
2758
2758
  * is spelled once, or the note could name ids the validator does not refuse.
2759
2759
  *
2760
2760
  * The two are NOT the same set, and deliberately so. The refusal fires when
2761
- * EITHER the state record or the template says nested, because the two types
2762
- * select different halves of the destructive path: the TEMPLATE's type picks
2763
- * the provider that deletes the old resource (a Type change emits an UPDATE
2764
- * carrying `resourceType: desiredResource.Type`, which is what
2765
- * `oldDeleteProvider` resolves from), while the STATE's type is what
2766
- * `NestedStackProvider` owns and derives `<parent>~<logicalId>` from. The note
2767
- * keys on the TEMPLATE alone, because it is telling the user what their current
2768
- * template contains. Which type governs was argued from plausibility twice and
2769
- * settled by reading `analyzer/diff-calculator.ts` and `deploy-engine.ts`'s
2770
- * `oldDeleteProvider`; do not re-derive it from either name. Other modules spell it
2761
+ * EITHER the state record or the template says nested, because a recreate has
2762
+ * two halves with two types (issue #2668): the STATE's type routes the delete
2763
+ * of the old resource — `NestedStackProvider` derives `<parent>~<logicalId>`
2764
+ * from it — and the TEMPLATE's type routes the create, which for a nested row
2765
+ * is a whole child-stack deploy. Either half alone is outside what a recreate
2766
+ * is built for. The note keys on the TEMPLATE alone, because it is telling the
2767
+ * user what their current template contains. Other modules spell it
2771
2768
  * for themselves rather than sharing one export: the only EXPORTED copy lives
2772
2769
  * in `src/cli/commands/retire-cfn-stack.ts`, and importing a CLI command module
2773
2770
  * from the deployment layer would invert the dependency direction. (No count of
@@ -3382,6 +3379,297 @@ function analyzePinCcApiReachability(pinnedLogicalIds, stacks) {
3382
3379
  };
3383
3380
  }
3384
3381
 
3382
+ //#endregion
3383
+ //#region src/utils/nested-template-cycle.ts
3384
+ /**
3385
+ * Static, READ-ONLY validation of a nested-template tree, run BEFORE anything
3386
+ * is deployed from it (issue go-to-k/cdkd#3247).
3387
+ *
3388
+ * `NestedStackProvider` follows `Metadata['aws:asset:path']` from one nested
3389
+ * template to the next and runs a whole child `DeployEngine` per level. A
3390
+ * relative path that resolves back onto the same nesting chain therefore
3391
+ * DEPLOYS every level of the cycle until S3's key limit stops it. Threading an
3392
+ * ancestor chain through the provider's recursion would only refuse at the
3393
+ * first repeat, by which point every level above it is already provisioned.
3394
+ * Everything the walk follows is on disk before the first child engine exists,
3395
+ * so the whole subtree is validated up front instead.
3396
+ *
3397
+ * Two properties are copied from the `cdkd diff --recursive` guard (issue
3398
+ * go-to-k/cdkd#3239), because re-deriving them gets them wrong:
3399
+ *
3400
+ * - The refused shape is a repeat along ONE root-to-node chain, never a repeat
3401
+ * anywhere in the tree: two sibling rows may name the same child template,
3402
+ * and that diamond is a legitimate assembly.
3403
+ * - It is a refusal, not a depth cap. A cyclic assembly has no correct deploy.
3404
+ *
3405
+ * `Condition`s are deliberately NOT evaluated: a row whose condition would be
3406
+ * false at deploy time still counts. A self-including template that terminates
3407
+ * through a condition is refused here exactly as the diff walk refuses it, so
3408
+ * the two commands agree about which assemblies are well-formed.
3409
+ *
3410
+ * A leaf apart from `display-safe.ts`, so any layer may import it.
3411
+ */
3412
+ const NESTED_STACK_TYPE$1 = "AWS::CloudFormation::Stack";
3413
+ /**
3414
+ * Same predicate `NestedStackProvider` applies per level. The `startsWith('/')`
3415
+ * arm covers a POSIX-style absolute path consumed on Windows, where
3416
+ * `path.isAbsolute` alone answers `false`.
3417
+ */
3418
+ function isAbsoluteAssetPath(p) {
3419
+ return path.isAbsolute(p) || p.startsWith("/");
3420
+ }
3421
+ /**
3422
+ * What "the same template" means ON A CHAIN: the file's name inside its REAL
3423
+ * directory.
3424
+ *
3425
+ * The directory is `realpath`ed because a symlinked DIRECTORY (`d -> .`) makes
3426
+ * every level's joined path a new, longer string (`d/a.json`, `d/d/a.json`,
3427
+ * ...) for one and the same file, which a comparison of resolved path strings
3428
+ * never sees repeat. There are finitely many (real directory, name) pairs, so
3429
+ * an endless descent must repeat one, however it is spelled.
3430
+ *
3431
+ * It is NOT what decides a template's children. Those resolve LEXICALLY
3432
+ * against the directory the template was reached in (`path.join` folds `d/..`
3433
+ * without following the link), so one identity reached through two spellings
3434
+ * can have two different subtrees. That is why the clean-subtree memo in
3435
+ * `findNestedTemplateTreeDefect` is keyed on the lexical path instead, and why
3436
+ * an identity repeat is a conservative refusal rather than an exact one: with
3437
+ * a symlinked directory AND a `..` row it can refuse a tree that would have
3438
+ * terminated. Such an assembly is hand-built by definition.
3439
+ *
3440
+ * Falls back to `path.resolve` for a directory that does not exist; the walk
3441
+ * stops there anyway.
3442
+ */
3443
+ function templateIdentity(templatePath) {
3444
+ const dir = path.dirname(templatePath);
3445
+ let realDir;
3446
+ try {
3447
+ realDir = fs.realpathSync(dir);
3448
+ } catch {
3449
+ realDir = path.resolve(dir);
3450
+ }
3451
+ return path.join(realDir, path.basename(templatePath));
3452
+ }
3453
+ /**
3454
+ * The nested-stack rows of a parsed template that name a child template file.
3455
+ *
3456
+ * THE ONE SPELLING, shared by this module's walk and by
3457
+ * `NestedStackProvider.indexGrandchildTemplates`, because the walk is only a
3458
+ * guard if it follows exactly the rows the deploy follows. Two hand-written
3459
+ * copies disagreed on an ARRAY-valued `Resources`: `Object.entries` indexes an
3460
+ * array as `'0'`, `'1'`, ..., the deploy followed those rows, and a walk that
3461
+ * skipped them accepted a cyclic tree. So this takes whatever `Object.entries`
3462
+ * takes, and does not pre-judge the container's shape.
3463
+ */
3464
+ function listNestedTemplateRows(template) {
3465
+ if (template === null || typeof template !== "object") return [];
3466
+ const resources = template.Resources;
3467
+ if (resources === null || resources === void 0) return [];
3468
+ const rows = [];
3469
+ for (const [logicalId, resource] of Object.entries(resources)) {
3470
+ const row = resource;
3471
+ if (row?.Type !== NESTED_STACK_TYPE$1) continue;
3472
+ const assetPath = row.Metadata?.["aws:asset:path"];
3473
+ if (typeof assetPath !== "string" || assetPath.length === 0) continue;
3474
+ rows.push({
3475
+ logicalId,
3476
+ assetPath
3477
+ });
3478
+ }
3479
+ return rows;
3480
+ }
3481
+ /**
3482
+ * The rows of the template FILE at `templatePath`. Unreadable or unparseable
3483
+ * input yields `undefined`: reporting that is the job of the site that
3484
+ * actually loads the template, with its own message, and a walk that cannot
3485
+ * descend cannot loop.
3486
+ */
3487
+ function readNestedRows(templatePath) {
3488
+ let parsed;
3489
+ try {
3490
+ parsed = JSON.parse(fs.readFileSync(templatePath, "utf-8"));
3491
+ } catch {
3492
+ return;
3493
+ }
3494
+ return listNestedTemplateRows(parsed);
3495
+ }
3496
+ /**
3497
+ * Deeper than this cannot deploy at all, so it is refused rather than walked.
3498
+ * A child's state key is `cdkd/<root>~<id>~<id>.../<region>/state.json`; each
3499
+ * level adds at least two bytes (`~` plus a one-character logical id) and S3
3500
+ * caps a key at 1024 bytes. The bound exists so a hostile chain of tens of
3501
+ * thousands of DISTINCT templates is a readable refusal instead of a
3502
+ * `RangeError` from the recursion below. It is not a cycle heuristic: a cycle
3503
+ * is refused at its first repeat, long before this.
3504
+ */
3505
+ const MAX_NESTING_DEPTH = 512;
3506
+ /**
3507
+ * Rows the walk will follow before it refuses the tree as too large.
3508
+ *
3509
+ * The clean-subtree memo is keyed on the LEXICAL path (it has to be, see
3510
+ * `templateIdentity`), and symlinked directories give one file arbitrarily
3511
+ * many lexical spellings: with `d1 -> .` and `d2 -> .`, rows naming
3512
+ * `t.json`, `d1/t.json` and `d2/t.json` at every level multiply the spellings
3513
+ * per level while no chain ever repeats an identity. Such a walk is finite but
3514
+ * exponential, so it needs a budget rather than a better key. Far above any
3515
+ * real assembly: a CDK app's nested templates number in the tens, and a memo
3516
+ * hit costs one row, not a subtree.
3517
+ */
3518
+ const MAX_ROWS_FOLLOWED = 1e4;
3519
+ /**
3520
+ * Walk every nested template reachable from `nestedTemplates` (logical id ->
3521
+ * template file path, the shape `AssemblyReader` and the provider's own
3522
+ * per-level index produce) and return the first defect, or `undefined` when
3523
+ * the tree is well-formed.
3524
+ *
3525
+ * `ancestorTemplatePaths` seeds the chain with templates ABOVE the entry rows,
3526
+ * for a caller that knows them. Detection does not depend on it: a cycle
3527
+ * through an unseeded ancestor is followed once around and refused when it
3528
+ * re-enters the first template the walk did see.
3529
+ */
3530
+ function findNestedTemplateTreeDefect(nestedTemplates, ancestorTemplatePaths = []) {
3531
+ const onChain = /* @__PURE__ */ new Set();
3532
+ for (const p of ancestorTemplatePaths) onChain.add(templateIdentity(p));
3533
+ const clean = /* @__PURE__ */ new Set();
3534
+ const chain = [];
3535
+ let rowsFollowed = 0;
3536
+ const visit = (logicalId, templatePath) => {
3537
+ if (typeof templatePath !== "string") return void 0;
3538
+ const identity = templateIdentity(templatePath);
3539
+ const lexical = path.resolve(templatePath);
3540
+ chain.push({
3541
+ logicalId,
3542
+ templatePath: identity
3543
+ });
3544
+ try {
3545
+ if (onChain.has(identity)) return {
3546
+ kind: "cycle",
3547
+ chain: [...chain]
3548
+ };
3549
+ if (chain.length > 512) return {
3550
+ kind: "too-deep",
3551
+ chain: [...chain]
3552
+ };
3553
+ if (++rowsFollowed > 1e4) return {
3554
+ kind: "too-large",
3555
+ chain: [...chain]
3556
+ };
3557
+ if (clean.has(lexical)) return void 0;
3558
+ const rows = readNestedRows(templatePath);
3559
+ if (rows === void 0) return void 0;
3560
+ onChain.add(identity);
3561
+ try {
3562
+ const dir = path.dirname(templatePath);
3563
+ for (const row of rows) {
3564
+ if (isAbsoluteAssetPath(row.assetPath)) return {
3565
+ kind: "absolute-path",
3566
+ chain: [...chain],
3567
+ logicalId: row.logicalId,
3568
+ assetPath: row.assetPath
3569
+ };
3570
+ const defect = visit(row.logicalId, path.join(dir, row.assetPath));
3571
+ if (defect) return defect;
3572
+ }
3573
+ } finally {
3574
+ onChain.delete(identity);
3575
+ }
3576
+ clean.add(lexical);
3577
+ return;
3578
+ } finally {
3579
+ chain.pop();
3580
+ }
3581
+ };
3582
+ for (const [logicalId, templatePath] of Object.entries(nestedTemplates)) {
3583
+ const defect = visit(logicalId, templatePath);
3584
+ if (defect) return defect;
3585
+ }
3586
+ }
3587
+ /** Hops rendered in full before the middle of a long chain is elided. */
3588
+ const MAX_RENDERED_HOPS = 8;
3589
+ /**
3590
+ * `'A' (/x/a.json) -> 'B' (/x/b.json)`. Every interpolation goes through
3591
+ * `displaySafe`: this text exists FOR a hand-modified assembly, so a logical id
3592
+ * (a template key) and a path (derived from `aws:asset:path`) are both
3593
+ * attacker-controlled, and a bare `Error` message is not sanitized downstream.
3594
+ * A long chain keeps both ends, since the entry row and the closing row are
3595
+ * the two a reader needs.
3596
+ */
3597
+ function renderChain(chain) {
3598
+ const hop = (h) => `'${displaySafe(h.logicalId)}' (${displaySafe(h.templatePath)})`;
3599
+ if (chain.length <= MAX_RENDERED_HOPS) return chain.map(hop).join(" -> ");
3600
+ const keep = MAX_RENDERED_HOPS / 2;
3601
+ return [
3602
+ ...chain.slice(0, keep).map(hop),
3603
+ `... ${chain.length - 8} more ...`,
3604
+ ...chain.slice(-4).map(hop)
3605
+ ].join(" -> ");
3606
+ }
3607
+ /**
3608
+ * The refusal text for a defect found under `stackName`. `action` completes
3609
+ * "Refusing to ..." so each caller states what it declined to do.
3610
+ */
3611
+ function renderNestedTemplateTreeDefect(defect, stackName, action) {
3612
+ const provenance = `CDK emits an acyclic nested template tree with relative asset paths, so this indicates the synth output was hand-modified or generated by a non-CDK toolchain. Refusing to ${action}.`;
3613
+ const owner = (chain) => {
3614
+ const ids = chain.slice(0, -1).map((h) => h.logicalId);
3615
+ const keep = MAX_RENDERED_HOPS / 2;
3616
+ const shown = ids.length <= MAX_RENDERED_HOPS ? ids : [
3617
+ ...ids.slice(0, keep),
3618
+ `...${ids.length - 8} more...`,
3619
+ ...ids.slice(-4)
3620
+ ];
3621
+ return displaySafe([stackName, ...shown].join("~"));
3622
+ };
3623
+ if (defect.kind === "cycle") {
3624
+ const closing = defect.chain[defect.chain.length - 1];
3625
+ return `The nested template tree under stack '${displaySafe(stackName)}' contains a cycle: ${renderChain(defect.chain)}. Nested stack '${displaySafe(closing.logicalId)}' (declared in stack '${owner(defect.chain)}') resolves to a template that is already on that nesting chain, so its Metadata['aws:asset:path'] closes a cycle. ${provenance}`;
3626
+ }
3627
+ if (defect.kind === "too-large") return `The nested template tree under stack '${displaySafe(stackName)}' has more than ${MAX_ROWS_FOLLOWED} nested-stack rows to follow (the walk stopped at ${renderChain(defect.chain)}). That is far beyond any CDK-generated assembly. Symlinked directories can give one template file many paths, which multiplies the tree without ever repeating on one chain. Refusing to ${action}.`;
3628
+ if (defect.kind === "too-deep") return `The nested template tree under stack '${displaySafe(stackName)}' nests more than ${512} levels deep: ${renderChain(defect.chain)}. No tree that deep can deploy, because each level lengthens the child's state key and S3 caps a key at 1024 bytes. ${provenance}`;
3629
+ return `The nested template tree under stack '${displaySafe(stackName)}' has nested stack '${displaySafe(defect.logicalId)}' (reached through ${renderChain(defect.chain)}) with Metadata['aws:asset:path']='${displaySafe(defect.assetPath)}' which is absolute. ${provenance}`;
3630
+ }
3631
+
3632
+ //#endregion
3633
+ //#region src/cli/commands/nested-template-preflight.ts
3634
+ /**
3635
+ * Refuse a malformed nested-template tree (a cycle, an absolute
3636
+ * `aws:asset:path` below the top level, a chain too deep or a tree too large
3637
+ * to deploy) for every SELECTED stack, before `cdkd deploy` does anything a
3638
+ * refusal would have to undo (issue go-to-k/cdkd#3449).
3639
+ *
3640
+ * `NestedStackProvider` runs the same walk per nested-stack row
3641
+ * (go-to-k/cdkd#3247), which is the earliest point the provider owns: by then
3642
+ * the stack's assets are published, its lock is held, and any root resource
3643
+ * that does not depend on the nested row may already be created and must be
3644
+ * rolled back. Everything the walk reads is on disk as soon as synth returns,
3645
+ * so the CLI asks first and the deploy never starts. The provider call stays
3646
+ * as the guard for a context this command did not build.
3647
+ *
3648
+ * Read-only and synchronous: a few file reads per nested template, none at all
3649
+ * for a stack without nested-stack rows. One walk covers all of a stack's
3650
+ * top-level rows, so the walker's row budget is per STACK here and per row in
3651
+ * the provider; no CDK-generated assembly comes near either.
3652
+ *
3653
+ * The root template's own path is not seeded into the walk (`StackInfo` does
3654
+ * not carry it). Detection does not depend on the seed: a child that points
3655
+ * back at the root template is followed once around and refused when the walk
3656
+ * re-enters the first nested template it saw.
3657
+ *
3658
+ * `SynthesisError` because the defect is in the synthesized assembly, like the
3659
+ * absolute-path refusal `AssemblyReader` raises for a top-level row.
3660
+ * `markNonRetryable` because the message carries template-controlled text the
3661
+ * substring-matching retry classifier must never read, wherever the error ends
3662
+ * up being caught.
3663
+ */
3664
+ function refuseMalformedNestedTemplateTrees(stacks) {
3665
+ for (const stack of stacks) {
3666
+ if (!stack.nestedTemplates) continue;
3667
+ const defect = findNestedTemplateTreeDefect(stack.nestedTemplates);
3668
+ if (!defect) continue;
3669
+ throw markNonRetryable(new SynthesisError(renderNestedTemplateTreeDefect(defect, stack.stackName, "start the deploy; nothing has been published or provisioned")));
3670
+ }
3671
+ }
3672
+
3385
3673
  //#endregion
3386
3674
  //#region src/cli/commands/confirm-prompt.ts
3387
3675
  /**
@@ -26356,7 +26644,8 @@ var SSMParameterProvider = class {
26356
26644
  * question cdkd can answer correctly — and would hand `cdkd drift` a baseline
26357
26645
  * AWS does not hold. Dropping the `Arn` instead degrades to the resolver's LOUD
26358
26646
  * `*Arn` shape-guard failure, which is exactly the pre-fix behavior, and the
26359
- * resource's next UPDATE re-records it. A loud missing value beats a quiet
26647
+ * resource's next UPDATE re-records it (as does the deploy engine's re-read
26648
+ * on a `Fn::GetAtt` miss, issue #1852). A loud missing value beats a quiet
26360
26649
  * wrong one — the same reasoning the `fabricated`-account arm above applies.
26361
26650
  *
26362
26651
  * Two honest bounds on that "next update re-records it". `getAccountInfo`
@@ -41121,10 +41410,14 @@ var RDSProvider = class {
41121
41410
  async importDBInstance(input) {
41122
41411
  const explicit = resolveExplicitPhysicalId(input, "DBInstanceIdentifier");
41123
41412
  if (explicit) try {
41124
- await this.getClient().send(new DescribeDBInstancesCommand({ DBInstanceIdentifier: explicit }));
41413
+ const described = (await this.getClient().send(new DescribeDBInstancesCommand({ DBInstanceIdentifier: explicit }))).DBInstances?.[0];
41125
41414
  return {
41126
41415
  physicalId: explicit,
41127
- attributes: {}
41416
+ attributes: definedAttributes({
41417
+ "Endpoint.Address": described?.Endpoint?.Address,
41418
+ "Endpoint.Port": stringifyIfAssigned(described?.Endpoint?.Port),
41419
+ Arn: described?.DBInstanceArn
41420
+ })
41128
41421
  };
41129
41422
  } catch (err) {
41130
41423
  if (err.name === "DBInstanceNotFoundFault") return null;
@@ -42714,10 +43007,14 @@ var DocDBProvider = class {
42714
43007
  async importDBInstance(input) {
42715
43008
  const explicit = resolveExplicitPhysicalId(input, "DBInstanceIdentifier");
42716
43009
  if (explicit) try {
42717
- await this.getClient().send(new DescribeDBInstancesCommand$1({ DBInstanceIdentifier: explicit }));
43010
+ const described = (await this.getClient().send(new DescribeDBInstancesCommand$1({ DBInstanceIdentifier: explicit }))).DBInstances?.[0];
42718
43011
  return {
42719
43012
  physicalId: explicit,
42720
- attributes: {}
43013
+ attributes: definedAttributes({
43014
+ "Endpoint.Address": described?.Endpoint?.Address,
43015
+ "Endpoint.Port": stringifyIfAssigned(described?.Endpoint?.Port),
43016
+ Arn: described?.DBInstanceArn
43017
+ })
42721
43018
  };
42722
43019
  } catch (err) {
42723
43020
  if (err.name === "DBInstanceNotFoundFault") return null;
@@ -43357,10 +43654,14 @@ var NeptuneProvider = class {
43357
43654
  async importDBInstance(input) {
43358
43655
  const explicit = resolveExplicitPhysicalId(input, "DBInstanceIdentifier");
43359
43656
  if (explicit) try {
43360
- await this.getClient().send(new DescribeDBInstancesCommand$2({ DBInstanceIdentifier: explicit }));
43657
+ const described = (await this.getClient().send(new DescribeDBInstancesCommand$2({ DBInstanceIdentifier: explicit }))).DBInstances?.[0];
43361
43658
  return {
43362
43659
  physicalId: explicit,
43363
- attributes: {}
43660
+ attributes: definedAttributes({
43661
+ "Endpoint.Address": described?.Endpoint?.Address,
43662
+ "Endpoint.Port": stringifyIfAssigned(described?.Endpoint?.Port),
43663
+ Arn: described?.DBInstanceArn
43664
+ })
43364
43665
  };
43365
43666
  } catch (err) {
43366
43667
  if (err.name === "DBInstanceNotFoundFault") return null;
@@ -48076,7 +48377,7 @@ var AppSyncProvider = class {
48076
48377
  return await this.buildAppSyncArn(suffix, regionOverride);
48077
48378
  } catch (error) {
48078
48379
  if (!omitArnOnFailure) throw error;
48079
- this.logger.warn(`Imported ${resourceType} (${physicalId}) but its ARN attribute was NOT recorded: ${describeAwsFailure(error).detail}. Ref will resolve to the compound physical id, and Fn::GetAtt on the ARN will fail, until the resource's next update heals the record.`);
48380
+ this.logger.warn(`Imported ${resourceType} (${physicalId}) but its ARN attribute was NOT recorded: ${describeAwsFailure(error).detail}. Ref will resolve to the compound physical id, and Fn::GetAtt on the ARN will fail, until the resource's next update — or a later deploy that needs the attribute and re-reads it from AWS — heals the record.`);
48080
48381
  return;
48081
48382
  }
48082
48383
  };
@@ -48164,7 +48465,7 @@ var AppSyncProvider = class {
48164
48465
  try {
48165
48466
  return await this.childRefAttributes(resourceType, physicalId, region, true) ?? {};
48166
48467
  } catch (error) {
48167
- this.logger.warn(`Imported ${resourceType} (${physicalId}) but could not build its ARN attribute: ${describeAwsFailure(error).detail}. Ref will resolve to the compound physical id, and Fn::GetAtt on the ARN will fail, until the resource's next update heals the record.`);
48468
+ this.logger.warn(`Imported ${resourceType} (${physicalId}) but could not build its ARN attribute: ${describeAwsFailure(error).detail}. Ref will resolve to the compound physical id, and Fn::GetAtt on the ARN will fail, until the resource's next update — or a later deploy that needs the attribute and re-reads it from AWS — heals the record.`);
48168
48469
  return {};
48169
48470
  }
48170
48471
  }
@@ -63555,7 +63856,7 @@ function nestedStackChildFailureMessage(childStackName, errorCount, alsoSkippedC
63555
63856
  * `path.isAbsolute()` alone. Exported for unit testing.
63556
63857
  */
63557
63858
  function isAbsoluteCrossPlatform$1(p) {
63558
- return path.isAbsolute(p) || p.startsWith("/");
63859
+ return isAbsoluteAssetPath(p);
63559
63860
  }
63560
63861
  /**
63561
63862
  * Provider for `AWS::CloudFormation::Stack` — cdkd's recursive nested-stack
@@ -63642,14 +63943,14 @@ var NestedStackProvider = class {
63642
63943
  const ctx = this.requireContext();
63643
63944
  this.requireDeployContext(ctx, "create");
63644
63945
  const childTemplatePath = ctx.nestedTemplates[logicalId];
63645
- if (!childTemplatePath) throw new Error(`Nested template file not found for AWS::CloudFormation::Stack '${logicalId}' under parent '${ctx.parentStackName}'. Verify the synth output emits Metadata['aws:asset:path'] on this resource (CDK 2.x cdk.NestedStack does so by default).`);
63646
- const childTemplate = this.readChildTemplate(childTemplatePath, ctx.assetRedirect);
63946
+ if (!childTemplatePath) throw new Error(`Nested template file not found for AWS::CloudFormation::Stack '${displaySafe(logicalId)}' under parent '${displaySafe(ctx.parentStackName)}'. Verify the synth output emits Metadata['aws:asset:path'] on this resource (CDK 2.x cdk.NestedStack does so by default).`);
63947
+ this.refuseMalformedNestedTemplateTree(ctx, logicalId, childTemplatePath);
63948
+ const { template: childTemplate, grandchildTemplates } = this.readChildTemplate(childTemplatePath, ctx.assetRedirect);
63647
63949
  const childStackName = this.deriveChildStackName(ctx.parentStackName, logicalId);
63648
63950
  const childRegion = ctx.parentRegion;
63649
63951
  const childParameters = this.extractParameters(properties);
63650
- const grandchildTemplates = this.indexGrandchildTemplates(childTemplate, childTemplatePath);
63651
63952
  const resourceCount = Object.keys(childTemplate.Resources ?? {}).length;
63652
- this.logger.info(`Deploying nested stack ${childStackName} (logicalId=${logicalId}, ${resourceCount} resource(s))`);
63953
+ this.logger.info(`Deploying nested stack ${displaySafe(childStackName)} (logicalId=${displaySafe(logicalId)}, ${resourceCount} resource(s))`);
63653
63954
  await this.runChildDeploy(ctx, logicalId, childStackName, childRegion, childTemplate, childParameters, grandchildTemplates);
63654
63955
  const childOutputs = await this.readChildOutputsAsAttributes(ctx, childStackName, childRegion);
63655
63956
  return {
@@ -63662,14 +63963,14 @@ var NestedStackProvider = class {
63662
63963
  const ctx = this.requireContext();
63663
63964
  this.requireDeployContext(ctx, "update");
63664
63965
  const childTemplatePath = ctx.nestedTemplates[logicalId];
63665
- if (!childTemplatePath) throw new Error(`Nested template file not found for AWS::CloudFormation::Stack '${logicalId}' on update.`);
63666
- const childTemplate = this.readChildTemplate(childTemplatePath, ctx.assetRedirect);
63966
+ if (!childTemplatePath) throw new Error(`Nested template file not found for AWS::CloudFormation::Stack '${displaySafe(logicalId)}' on update.`);
63967
+ this.refuseMalformedNestedTemplateTree(ctx, logicalId, childTemplatePath);
63968
+ const { template: childTemplate, grandchildTemplates } = this.readChildTemplate(childTemplatePath, ctx.assetRedirect);
63667
63969
  const childStackName = this.deriveChildStackName(ctx.parentStackName, logicalId);
63668
63970
  const childRegion = ctx.parentRegion;
63669
63971
  const childParameters = this.extractParameters(properties);
63670
- const grandchildTemplates = this.indexGrandchildTemplates(childTemplate, childTemplatePath);
63671
63972
  const resourceCount = Object.keys(childTemplate.Resources ?? {}).length;
63672
- this.logger.info(`Updating nested stack ${childStackName} (logicalId=${logicalId}, ${resourceCount} resource(s))`);
63973
+ this.logger.info(`Updating nested stack ${displaySafe(childStackName)} (logicalId=${displaySafe(logicalId)}, ${resourceCount} resource(s))`);
63673
63974
  await this.runChildDeploy(ctx, logicalId, childStackName, childRegion, childTemplate, childParameters, grandchildTemplates);
63674
63975
  const updatedOutputs = await this.readChildOutputsAsAttributes(ctx, childStackName, childRegion);
63675
63976
  return {
@@ -63685,12 +63986,12 @@ var NestedStackProvider = class {
63685
63986
  const childRegion = ctx.parentRegion;
63686
63987
  const childStateData = await ctx.stateBackend.getState(childStackName, childRegion);
63687
63988
  if (!childStateData) {
63688
- this.logger.debug(`Nested stack ${childStackName} has no state — treating delete as idempotent success.`);
63989
+ this.logger.debug(`Nested stack ${displaySafe(childStackName)} has no state — treating delete as idempotent success.`);
63689
63990
  return;
63690
63991
  }
63691
63992
  refuseMalformedResourcesForDestroy(childStateData.state, childStackName, childRegion);
63692
63993
  const resourceCount = Object.keys(childStateData.state.resources).length;
63693
- this.logger.info(`Destroying nested stack ${childStackName} (logicalId=${logicalId}, ${resourceCount} resource(s))`);
63994
+ this.logger.info(`Destroying nested stack ${displaySafe(childStackName)} (logicalId=${displaySafe(logicalId)}, ${resourceCount} resource(s))`);
63694
63995
  const childCtx = {
63695
63996
  ...ctx,
63696
63997
  parentStackName: childStackName,
@@ -63726,12 +64027,12 @@ var NestedStackProvider = class {
63726
64027
  if (childResult.interrupted) causes.push("was interrupted");
63727
64028
  return {
63728
64029
  outcome: "skipped",
63729
- reason: `nested stack ${childStackName} ${causes.join(" and ")}`
64030
+ reason: `nested stack ${displaySafe(childStackName)} ${causes.join(" and ")}`
63730
64031
  };
63731
64032
  }
63732
64033
  }
63733
64034
  async getAttribute(_physicalId, _resourceType, attributeName) {
63734
- throw new Error(`AWS::CloudFormation::Stack: attribute '${attributeName}' is not in the recorded Outputs map. Only 'Outputs.<Key>' references to declared Output names on the child template are supported.`);
64035
+ throw new Error(`AWS::CloudFormation::Stack: attribute '${displaySafe(attributeName)}' is not in the recorded Outputs map. Only 'Outputs.<Key>' references to declared Output names on the child template are supported.`);
63735
64036
  }
63736
64037
  async runChildDeploy(parentCtx, logicalId, childStackName, childRegion, childTemplate, childParameters, grandchildTemplates) {
63737
64038
  const inheritedSecrets = getCurrentResourceSecrets();
@@ -63782,7 +64083,7 @@ var NestedStackProvider = class {
63782
64083
  */
63783
64084
  async readChildOutputsAsAttributes(ctx, childStackName, childRegion) {
63784
64085
  const childStateData = await ctx.stateBackend.getState(childStackName, childRegion);
63785
- if (!childStateData) throw new Error(`Child stack state '${childStackName}' not found after deploy — NestedStackProvider invariant violated.`);
64086
+ if (!childStateData) throw new Error(`Child stack state '${displaySafe(childStackName)}' not found after deploy — NestedStackProvider invariant violated.`);
63786
64087
  refuseMalformedNestedChildOutputs(childStateData.state, childStackName, childRegion);
63787
64088
  const attributes = this.buildOutputsAttributes(childStateData.state.outputs ?? {});
63788
64089
  const noEchoAttributeNames = [];
@@ -63807,6 +64108,40 @@ var NestedStackProvider = class {
63807
64108
  requireDeployContext(ctx, op) {
63808
64109
  if (!ctx.nestedTemplates || !ctx.dagBuilder || !ctx.diffCalculator) throw new Error(`NestedStackProvider.${op}: deploy-mode context fields (nestedTemplates / dagBuilder / diffCalculator) are missing. This usually means a destroy-mode entry point called into create/update by mistake.`);
63809
64110
  }
64111
+ /**
64112
+ * Validate the WHOLE nested-template subtree under this row before the first
64113
+ * child engine is built (issue go-to-k/cdkd#3247).
64114
+ *
64115
+ * Up front rather than as an ancestor chain threaded through the recursion,
64116
+ * because here a level is not a read, it is a DEPLOY: refusing at the first
64117
+ * repeat would leave every level above it provisioned, with a state record
64118
+ * each, for the rollback to unwind. Every file the recursion would follow is
64119
+ * already on disk, so the top-most row's call sees the entire cycle and
64120
+ * nothing below it ever starts. Deeper levels re-run the same walk over
64121
+ * their own (already proven) subtree; it is a few file reads next to a
64122
+ * deploy, and it keeps the guard independent of who built the context.
64123
+ *
64124
+ * This is the earliest point THIS FILE owns. The parent stack's other
64125
+ * resources may already be in flight when its nested-stack row is
64126
+ * dispatched; they are unwound by the parent's ordinary rollback. No level of
64127
+ * the cyclic tree is deployed.
64128
+ *
64129
+ * It also reports an absolute `aws:asset:path` at ANY depth, for the same
64130
+ * reason: `indexGrandchildTemplates` refuses one too, but only on reaching
64131
+ * that level, after the levels above it deployed. That check stays as the
64132
+ * per-level backstop.
64133
+ *
64134
+ * `markNonRetryable`: the verdict is computed from files no retry changes,
64135
+ * while the message carries template-controlled text (logical ids, paths)
64136
+ * that the SUBSTRING-matching retry classifier would otherwise read. Latent
64137
+ * while `disableOuterRetry` is set, and declared anyway, like the sibling
64138
+ * marks in this file.
64139
+ */
64140
+ refuseMalformedNestedTemplateTree(ctx, logicalId, childTemplatePath) {
64141
+ const defect = findNestedTemplateTreeDefect({ [logicalId]: childTemplatePath });
64142
+ if (!defect) return;
64143
+ throw markNonRetryable(/* @__PURE__ */ new Error(`NestedStackProvider: ${renderNestedTemplateTreeDefect(defect, ctx.parentStackName, "deploy any level of it")}`));
64144
+ }
63810
64145
  deriveChildStackName(parentStackName, nestedLogicalId) {
63811
64146
  return `${parentStackName}~${nestedLogicalId}`;
63812
64147
  }
@@ -63851,35 +64186,50 @@ var NestedStackProvider = class {
63851
64186
  * points at `[2]` rather than at the whole parameter.
63852
64187
  */
63853
64188
  refuseNonScalarParameter(k, offender, where) {
63854
- throw new Error(`NestedStackProvider: child Parameter '${k}'${where} resolved to a non-scalar value (type=${offender === null ? "null" : typeof offender}). Parameters must be scalars (string / number / boolean), or an ARRAY of them from a list-typed parameter, by the time they reach the provider — an unresolved intrinsic here means IntrinsicFunctionResolver upstream did not handle the value, which is a bug. Surface the unresolved input rather than silently coercing to '[object Object]'.`);
64189
+ throw new Error(`NestedStackProvider: child Parameter '${displaySafe(k)}'${where} resolved to a non-scalar value (type=${offender === null ? "null" : typeof offender}). Parameters must be scalars (string / number / boolean), or an ARRAY of them from a list-typed parameter, by the time they reach the provider — an unresolved intrinsic here means IntrinsicFunctionResolver upstream did not handle the value, which is a bug. Surface the unresolved input rather than silently coercing to '[object Object]'.`);
63855
64190
  }
64191
+ /**
64192
+ * The child template as the child engine deploys it, plus the grandchild
64193
+ * template paths indexed from it.
64194
+ *
64195
+ * The index is taken BEFORE the asset-reference rewrite, and returning both
64196
+ * from here is what keeps that order from being undone by a caller. The
64197
+ * rewrite walks every string in the template, `Metadata['aws:asset:path']`
64198
+ * included, and a path segment that spells a bootstrap bucket name is
64199
+ * rewritten like any other occurrence. `aws:asset:path` is a LOCAL file
64200
+ * path, never an asset-storage reference; indexing after the rewrite made
64201
+ * the deploy follow a different file than the one
64202
+ * `refuseMalformedNestedTemplateTree` had validated from the raw file, which
64203
+ * is a way around that guard (issue go-to-k/cdkd#3247).
64204
+ */
63856
64205
  readChildTemplate(templatePath, assetRedirect) {
63857
64206
  let raw;
63858
64207
  try {
63859
64208
  raw = fs.readFileSync(templatePath, "utf-8");
63860
64209
  } catch (err) {
63861
- throw new Error(`Failed to read nested template at ${templatePath}: ${err instanceof Error ? err.message : String(err)}`);
64210
+ throw new Error(`Failed to read nested template at ${displaySafe(templatePath)}: ${displaySafe(err instanceof Error ? err.message : String(err))}`);
63862
64211
  }
63863
64212
  let template;
63864
64213
  try {
63865
64214
  template = JSON.parse(raw);
63866
64215
  } catch (err) {
63867
- throw new Error(`Failed to parse nested template at ${templatePath}: ${err instanceof Error ? err.message : String(err)}`);
64216
+ throw new Error(`Failed to parse nested template at ${displaySafe(templatePath)}: ${displaySafe(err instanceof Error ? err.message : String(err))}`);
63868
64217
  }
64218
+ const grandchildTemplates = this.indexGrandchildTemplates(template, templatePath);
63869
64219
  if (assetRedirect) {
63870
64220
  const n = rewriteTemplateAssetReferences(template, assetRedirect);
63871
- if (n > 0) this.logger.debug(`Rewrote ${n} asset reference(s) to cdkd asset storage in nested template ${templatePath}`);
64221
+ if (n > 0) this.logger.debug(`Rewrote ${n} asset reference(s) to cdkd asset storage in nested template ${displaySafe(templatePath)}`);
63872
64222
  }
63873
- return template;
64223
+ return {
64224
+ template,
64225
+ grandchildTemplates
64226
+ };
63874
64227
  }
63875
64228
  indexGrandchildTemplates(childTemplate, childTemplatePath) {
63876
64229
  const dir = path.dirname(childTemplatePath);
63877
- const result = {};
63878
- for (const [grandLogicalId, resource] of Object.entries(childTemplate.Resources ?? {})) {
63879
- if (resource?.Type !== "AWS::CloudFormation::Stack") continue;
63880
- const assetPath = resource.Metadata?.["aws:asset:path"];
63881
- if (typeof assetPath !== "string" || assetPath.length === 0) continue;
63882
- if (isAbsoluteCrossPlatform$1(assetPath)) throw new Error(`NestedStackProvider: nested-stack '${grandLogicalId}' has Metadata['aws:asset:path']='${assetPath}' which is absolute. CDK emits relative asset paths for nested templates; an absolute path indicates the synth output was hand-modified or generated by a non-CDK toolchain. Refusing to load.`);
64230
+ const result = Object.create(null);
64231
+ for (const { logicalId: grandLogicalId, assetPath } of listNestedTemplateRows(childTemplate)) {
64232
+ if (isAbsoluteCrossPlatform$1(assetPath)) throw markNonRetryable(/* @__PURE__ */ new Error(`NestedStackProvider: nested-stack '${displaySafe(grandLogicalId)}' has Metadata['aws:asset:path']='${displaySafe(assetPath)}' which is absolute. CDK emits relative asset paths for nested templates; an absolute path indicates the synth output was hand-modified or generated by a non-CDK toolchain. Refusing to load.`));
63883
64233
  result[grandLogicalId] = path.join(dir, assetPath);
63884
64234
  }
63885
64235
  return result;
@@ -64931,6 +65281,7 @@ async function deployCommand(stacks, options) {
64931
65281
  strict: options.strict === true,
64932
65282
  ignoreErrors: options.ignoreErrors === true
64933
65283
  });
65284
+ refuseMalformedNestedTemplateTrees(targetStacks);
64934
65285
  await synthesizer.expandMacrosForStacks(targetStacks, synthOptions);
64935
65286
  const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
64936
65287
  const stsClient = new STSClient({
@@ -81555,6 +81906,15 @@ function safeRoleArn(value) {
81555
81906
  * the Snapshot label would otherwise promise a final snapshot the run is about
81556
81907
  * to skip — a data-loss-relevant lie in the one preview the user reads.
81557
81908
  */
81909
+ /**
81910
+ * The type(s) a reversed replacement touches (issue #2668): `NEW -> OLD` when
81911
+ * the replacement changed the resource's `Type` — the replay deletes the first
81912
+ * and re-creates the second — and the single type otherwise.
81913
+ */
81914
+ function replacementTypes(op) {
81915
+ const routing = resolveReplacementOldType(op);
81916
+ return routing.ok && routing.oldType !== op.resourceType ? `${safe(op.resourceType)} -> ${safe(routing.oldType)}` : safe(op.resourceType);
81917
+ }
81558
81918
  function actionLabel(item, skipFinalSnapshot) {
81559
81919
  const { op, action, replacement } = item;
81560
81920
  const rep = replacement ? " [replacement occurred, best-effort revert]" : "";
@@ -81564,11 +81924,15 @@ function actionLabel(item, skipFinalSnapshot) {
81564
81924
  case "orphan-retain": return ` - orphan ${safe(op.logicalId)} (${safe(op.resourceType)}) [DeletionPolicy Retain — left in AWS]`;
81565
81925
  case "orphan-flag": return ` - orphan ${safe(op.logicalId)} (${safe(op.resourceType)}) [--orphan]`;
81566
81926
  case "revert": return ` - revert ${safe(op.logicalId)} (${safe(op.resourceType)})${rep}`;
81567
- case "reverse-replacement": return item.retainsNewResource ? ` - reverse-replace ${safe(op.logicalId)} (${safe(op.resourceType)}) [re-create old resource; new one RETAINED (UpdateReplacePolicy: Retain) and left untracked — REFUSED instead if the re-create collides with the name the retained resource still holds]` : ` - reverse-replace ${safe(op.logicalId)} (${safe(op.resourceType)}) [re-create old resource, delete new]`;
81568
- case "reverse-replacement-readopt": return item.retainsNewResource ? ` - reverse-replace ${safe(op.logicalId)} (${safe(op.resourceType)}) [re-adopt retained old resource; new one RETAINED (UpdateReplacePolicy: Retain) and left untracked]` : ` - reverse-replace ${safe(op.logicalId)} (${safe(op.resourceType)}) [delete new, re-adopt retained old resource]`;
81927
+ case "reverse-replacement": return item.retainsNewResource ? ` - reverse-replace ${safe(op.logicalId)} (${replacementTypes(op)}) [re-create old resource; new one RETAINED (UpdateReplacePolicy: Retain) and left untracked — REFUSED instead if the re-create collides with the name the retained resource still holds]` : ` - reverse-replace ${safe(op.logicalId)} (${replacementTypes(op)}) [re-create old resource, delete new]`;
81928
+ case "reverse-replacement-readopt": return item.retainsNewResource ? ` - reverse-replace ${safe(op.logicalId)} (${replacementTypes(op)}) [re-adopt retained old resource; new one RETAINED (UpdateReplacePolicy: Retain) and left untracked]` : ` - reverse-replace ${safe(op.logicalId)} (${replacementTypes(op)}) [delete new, re-adopt retained old resource]`;
81569
81929
  case "unrecoverable-delete": return ` - (cannot restore) ${safe(op.logicalId)} (${safe(op.resourceType)}) — was DELETED, unrecoverable`;
81570
81930
  case "skip-mismatch": return ` - skip ${safe(op.logicalId)} (${safe(op.resourceType)}) — physical id changed, needs manual attention`;
81571
81931
  case "skip-absent": return ` - skip ${safe(op.logicalId)} (${safe(op.resourceType)}) — no longer in state`;
81932
+ case "refuse-replacement-routing": {
81933
+ const routing = resolveReplacementOldType(op);
81934
+ return ` - (REFUSED) ${safe(op.logicalId)} (${safe(op.resourceType)}) — cannot reverse the replacement: ${routing.ok ? "its old type could not be routed" : routing.reason}`;
81935
+ }
81572
81936
  case "skip-already-done": return ` - skip ${safe(op.logicalId)} (${safe(op.resourceType)}) — already reverted`;
81573
81937
  }
81574
81938
  }
@@ -81588,6 +81952,7 @@ function failedActionLabel(item, skipFinalSnapshot) {
81588
81952
  case "skip-failed-unknown": return ` - skip ${safe(op.logicalId)} (${safe(op.resourceType)}) — failed CREATE recorded no physical id`;
81589
81953
  case "skip-failed-noop": return ` - skip ${safe(op.logicalId)} (${safe(op.resourceType)}) — failed ${safe(op.changeType)} left nothing to revert`;
81590
81954
  case "skip-failed-absent": return ` - skip ${safe(op.logicalId)} (${safe(op.resourceType)}) — no previous state available`;
81955
+ case "skip-failed-type-change": return ` - skip ${safe(op.logicalId)} (${safe(op.previousState?.resourceType)} -> ${safe(op.resourceType)}) — failed Type change is a replacement, no in-place revert exists`;
81591
81956
  }
81592
81957
  }
81593
81958
  /**
@@ -95673,4 +96038,4 @@ function buildProgram() {
95673
96038
 
95674
96039
  //#endregion
95675
96040
  export { buildProgram };
95676
- //# sourceMappingURL=program-D75-DVWT.js.map
96041
+ //# sourceMappingURL=program-Dh1J573K.js.map