@go-to-k/cdkd 0.308.1 → 0.309.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 (26) hide show
  1. package/dist/{asg-provider-B7pAjRIc.js → asg-provider-DQoKGfKH.js} +2 -2
  2. package/dist/{asg-provider-B7pAjRIc.js.map → asg-provider-DQoKGfKH.js.map} +1 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/{deploy-engine-CDjAtIrn.js → deploy-engine-tQ0aqZMo.js} +1235 -247
  5. package/dist/deploy-engine-tQ0aqZMo.js.map +1 -0
  6. package/dist/iam-policy-targets-D94wh05t.js.map +1 -1
  7. package/dist/{iam-role-provider-DbtvFel_.js → iam-role-provider-BI8Acvps.js} +2 -2
  8. package/dist/{iam-role-provider-DbtvFel_.js.map → iam-role-provider-BI8Acvps.js.map} +1 -1
  9. package/dist/index.d.ts +7 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -2
  12. package/dist/{neptune-provider-Y3Ii8oYI.js → neptune-provider-DmVmx69p.js} +2 -2
  13. package/dist/{neptune-provider-Y3Ii8oYI.js.map → neptune-provider-DmVmx69p.js.map} +1 -1
  14. package/dist/{program-Ymf7svYk.js → program-Bnt3Yt0k.js} +100 -256
  15. package/dist/program-Bnt3Yt0k.js.map +1 -0
  16. package/dist/{provider-classes-BxfIHcea.js → provider-classes-DYke4HKr.js} +724 -133
  17. package/dist/provider-classes-DYke4HKr.js.map +1 -0
  18. package/dist/{rds-provider-CZhBLQgJ.js → rds-provider-Qpf09VQv.js} +27 -13
  19. package/dist/rds-provider-Qpf09VQv.js.map +1 -0
  20. package/dist/{version-BWqrjGBS.js → version-9LVuCtBU.js} +2 -2
  21. package/dist/{version-BWqrjGBS.js.map → version-9LVuCtBU.js.map} +1 -1
  22. package/package.json +2 -2
  23. package/dist/deploy-engine-CDjAtIrn.js.map +0 -1
  24. package/dist/program-Ymf7svYk.js.map +0 -1
  25. package/dist/provider-classes-BxfIHcea.js.map +0 -1
  26. package/dist/rds-provider-CZhBLQgJ.js.map +0 -1
@@ -2,13 +2,13 @@ import { r as getAwsClients, s as withApiGatewayPacing } from "./aws-clients-Bu9
2
2
  import { B as SECRET_REF_MAX_CODE_POINTS, C as generateResourceName, D as getCurrentStackInstanceId, J as displayStackName, K as displayIdent, M as recordedGeneratedNameKept, Q as safeMsg, T as generatedNameFor, Y as isPasteableIdent, Z as plainIdentOr, a as safeStringify, i as isAwsAuthoredFailure, k as isBeforeStateRead, n as describeAwsFailure, q as displaySafe, r as describeAwsStatusReason, s as getLogger, t as VERBOSE_POINTER, w as generateResourceNameWithFallback } from "./aws-failure-text-NSBdKPYK.js";
3
3
  import { $ as userPoolProtectionSite, $t as injectiveKeyPrefix, A as isPlainImportJson, C as setBounded, Cr as markNonRetryable, Ct as createMaskedLogSinks, D as markNotGone, Dn as ResourceUpdateNotSupportedError, Dt as maskerOrIdentity, Et as maskDeep, F as refusalTypeShown, Ft as isAuxiliaryFailure, G as isTerminalDbWaitStatus, H as deleteWithProtectionCompensation, Hn as hasClauseBreak, I as remedyLogicalId, J as observeThenDisableProtection, K as isTerminalDeleteFailure, Kn as plainOrDescribed, L as resolveExplicitPhysicalId, Lt as markAuxiliaryFailure, M as isQuotableImportValue, N as normalizeAwsTagsToCfn, O as assertRegionMatch, Ot as withDerivedNameMasks, P as quotedRemedyLogicalId, Qt as injectiveKey, Rt as markCreatedBeforeFailure, S as replayedSendWindow, Sr as isThrottlingError, St as stateOrphanRecordRemedy, T as RESOURCE_NOT_FOUND, Tn as ProvisioningError, Tr as wrapMaskedAwsError, Tt as isSecretDerivedValue, Un as isInertUnquoted, V as deleteAfterProtectionFlipWithFinalSnapshot, Vn as commandHole, Wn as pasteableCommand, X as rdsFamilyProtectionSite, Xn as withheldTargetClause, Y as protectionFlipKey, Yn as shellQuote, _ as RecentIdSet, _r as isRetryableTransientError, _t as compositeIdSkipResult, a as onlySecretDerived, an as ambientCredentialConfig, ar as markNameCollision, at as protectedReplacementAdvice, b as isInsideWindow, br as THROTTLING_ERROR_NAMES, c as recordedPrincipalsRepair, cn as AccountIdUnavailableError, dr as explicitDenyPolicyKind, ft as isInterruptedWaitError, g as AmbiguousCreateLatch, gt as compositeIdSeparatorRefusal, h as AMBIGUOUS_LATCH_TTL_MS, hr as isExplicitDenyError, ht as compositeIdFormatMessage, i as holdsSecretDerivedEntry, in as ambientClientDefaults, it as pasteableAwsCommand, j as isPlainImportValue, jt as clearCreatedBeforeFailure, k as VALUE_NOT_SHOWN, mr as isAmbiguousOutcomeError, mt as canonicalizeRoute53QueryName, nt as WITHHELD_AWS_COMMAND, o as readPrincipalLists, on as clientDefaultsFor, or as markReplayMayCollide, ot as renderDisableCommand, p as withRemovalDefaults, pt as startInterruptWatch, q as logGroupProtectionSite, r as SECRET_DERIVED_READ_LIVE, rn as withPasteableAwsProfile, rt as isAwsCliLiteral, sn as credentialFingerprint, sr as relayedNameCollision, st as ElapsedBudgetRegistry, tt as UNNAMEABLE_ID_CLAUSE, u as clearOnUpdateRemoval, un as CdkdError, v as ambiguousAttemptLead, vr as isTransientServerError, vt as logicalIdShown, w as withoutServerErrorRetries, wr as markRedactedCause, wt as createMaskedRetryLogger, x as replayFollowedAmbiguousAttempt, xr as isMarkedNonRetryable, xt as segmentAfterAnchor, y as createAttemptKey, yt as packCompositeId, z as ProtectionFlipRegistry, zt as markSupersedesEarlierCreate } from "./iam-policy-targets-D94wh05t.js";
4
4
  import { c as ambientRegion } from "./aws-client-defaults-BX9Y_fKp.js";
5
- import { $c as recordAttributeIdCopy, $s as blockDeviceMappingsDifferOnlyInDeleteOnTermination, $t as lookupEachName, A as beginDeleteWait, Ai as refuseMalformedDesiredTags, An as REDACTED_DELETE_ADDRESS_SKIP_REASON, B as waitForIndexesSettled, Bi as waitForLambdaFunctionActive, Bl as timePhase, Bs as coerceCfnInteger, Bt as getCurrentNestedStackContext, C as planContributorInsightsOp, Cc as redactForState, Cs as findSilentDropProperties, D as reverseMapTableContributorInsights, Da as outputReferenceProvenanceOf, Di as DBPROXY_TAG_OPTIONS, E as reverseMapIndexContributorInsights, Ei as DBPROXY_TAGS_WHAT, Er as getStackRecords, F as DELETE_INDEX_WAIT_PROCEED_NOTE, Fs as coerceWarmThroughput$1, G as sendTtlWaitingOutRateLimit, Gs as replayWarn, H as isTtlRateLimited, Hc as withoutPhysicalNameCopies, Hs as configIntegerRefusal, I as INDEX_SETTLE_POLL_INTERVAL_MS, Is as isWarmThroughputDecrease, It as revertNestedChildFromJournal, J as hasCdkAutoDeleteTag, Jl as rewriteTemplateAssetReferences, Js as requireConfigString, K as ECR_AUTO_DELETE_IMAGES_TAG, Ks as requireConfigArray, L as deleteTableWithIndexBusyRetry, Ls as toCfnInteger, M as deleteBudgetKey, Mi as tagPlanWarning, Mn as redactedDeleteAddressFields, N as resolveDynamoDbDeleteBudgetClock, Ni as definedAttributes, Nn as redactedDeleteAddressSkip, Nt as getNestedRevertRun, O as stripIndexContributorInsights, Oc as hasMaskableValues, Oi as planTagDiff, On as getCurrentProducerRegions, Or as replacedDeleteFailureVerdict, P as resolveDynamoDbDeleteBudgetMs, Pi as stringifyIfAssigned, Ps as WARM_THROUGHPUT_MEMBERS, Qc as physicalNameCopiesOf, Qi as unchangedBehindSecretReference, Qs as withRetry, Qt as isAccessDeniedError, R as maskedLogger, Rs as toFiniteNumber, S as indexDeclaresContributorInsights, Sa as s3BucketWebsiteUrl, Sc as markSameGenerationBag, T as readContributorInsightsSpec, Tc as snapshotPassProvenance, Ti as markDeleteStarted, Ts as withoutSilentDropProperties, U as planTimeToLive, Ul as stringifyValue, Uo as refuseMalformedNestedChildOutputs, Us as configStringRefusal, V as isTtlAlreadyDisabled, Vs as configBooleanRefusal, Vt as withNestedStackContext, W as readTtlSpec, Wc as dynamicReferenceTokens, Wi as getCurrentResourceSecrets, Ws as readConfigString, X as getPriorAttempts, Xi as slowCcOperationTimeoutMs, Xu as canonicalizeRegion, Y as isTruthyCfnBoolean, Z as markRefusedBeforeApplying, Zc as recoverMaskedOutput, Zi as onlySecretReferencesDiffer, Zt as chunks, Zu as derivePartitionAndUrlSuffix, _ as streamMemberRefusals, _a as isSettledInstanceState, aa as isWaitAbandonedError, b as CONTRIBUTOR_INSIGHTS_KEY, ba as s3BucketDualStackDomainName, bi as acquireIdempotencyToken, c as DynamoDBGlobalTableProvider, ca as ec2InstanceProtectionSite, ct as listNestedTemplateRows, d as declaredStreamPolicyMember, da as reDisableInstanceApiTermination, dd as displayAssemblyPath, ec as ecsServiceLaunchTypeSetOrChanged, en as withApiLimit, f as declaredStreamTagsMember, fa as reEnableInstanceApiTermination, fd as renderAssemblyPathEscape, g as streamDeclaresTags, gc as passedNoEchoParametersOf, gi as earliestDefined, gt as enclosingDeadlineRemainingMs, h as streamDeclaresPolicy, ht as enclosingDeadlineExpired, ia as withIndeterminateGuard, ic as sameLambdaFunctionAddress, io as parseWebACLArn, j as compensateRemovedDeletionProtection, ji as tagMapAsList, jn as isRedactedRecordedValue, k as DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS, ki as readTagList, l as STREAM_POLICY_KEY, la as isTerminationProtectionPropagationError, ls as refuseMalformedResourcesForDestroy, lt as renderNestedTemplateTreeDefect, m as reverseMapStreamPolicy, mo as accountArgs, nc as canonicalLambdaFunctionName, nl as carriesSecretMask, oa as markWaitAbandoned, ot as findNestedTemplateTreeDefect, p as planStreamMemberOps, pd as resolveAssemblyPath, q as S3_AUTO_DELETE_OBJECTS_TAG, qa as getAccountInfo, qs as requireConfigObject, qu as decodeListingKey, ra as deleteSkipReason, rc as lambdaFunctionNameForMask, ri as secretNamedAttributeNamesOf, so as passedParameterClassesOf, st as isAbsoluteAssetPath, t as DeployEngine, tc as emrClusterInstancesReplaced, u as STREAM_TAGS_KEY, ua as observeThenDisableInstanceApiTermination, ud as describeFileReadFailure, v as streamPolicyMatchesDeclared, va as s3BucketArn, vi as reserveStackCreateToken, w as planIndexContributorInsightsOps, wc as recordReferenceProvenanceEntry, wi as isRefusedByName, wr as awaitInFlightSibling, x as contributorInsightsRefusals, xa as s3BucketRegionalDomainName, xs as withheldAccountClause, y as streamTagsMatchDeclared, ya as s3BucketDomainName, z as relayedIndexBusyDelete, zs as coerceCfnBoolean } from "./deploy-engine-CDjAtIrn.js";
6
- import { n as collectInlinePolicyNamesManagedBySiblings, r as IamCreateClientCache, t as IAMRoleProvider } from "./iam-role-provider-DbtvFel_.js";
7
- import { a as resolveSecretDerivedPrincipals, i as isResolvableSecretPrincipalList, n as runDestroyForStack, o as canonicalizeIpProtocolValue, r as holdsUnprovenSecretPrincipalToken, s as resolvedResourceTimeoutMs, t as canonicalizeIpv4Cidr } from "./program-Ymf7svYk.js";
5
+ import { $l as stringifyValue, $s as readConfigString, $t as lookupEachName, A as beginDeleteWait, Aa as s3BucketRegionalDomainName, Ai as isRefusedByName, Ar as awaitInFlightSibling, As as withheldAccountClause, B as waitForIndexesSettled, Bi as stringifyIfAssigned, Bt as getCurrentNestedStackContext, C as planContributorInsightsOp, Cd as resolveAssemblyPath, Co as accountArgs, D as reverseMapTableContributorInsights, Da as s3BucketArn, E as reverseMapIndexContributorInsights, Ea as isSettledInstanceState, Ec as passedNoEchoParametersOf, Ei as acquireIdempotencyToken, F as DELETE_INDEX_WAIT_PROCEED_NOTE, Fc as snapshotPassProvenance, Fi as readTagList, G as sendTtlWaitingOutRateLimit, Gs as isWarmThroughputDecrease, H as isTtlRateLimited, I as INDEX_SETTLE_POLL_INTERVAL_MS, Ia as outputReferenceProvenanceOf, Ii as refuseMalformedDesiredTags, In as REDACTED_DELETE_ADDRESS_SKIP_REASON, It as revertNestedChildFromJournal, J as hasCdkAutoDeleteTag, Js as coerceCfnBoolean, K as ECR_AUTO_DELETE_IMAGES_TAG, Ki as waitForLambdaFunctionActive, Ks as toCfnInteger, L as deleteTableWithIndexBusyRetry, Li as tagMapAsList, Ln as isRedactedRecordedValue, M as deleteBudgetKey, Mc as markSameGenerationBag, Mi as DBPROXY_TAGS_WHAT, Mr as getStackRecords, Ms as findSilentDropProperties, N as resolveDynamoDbDeleteBudgetClock, Nc as redactForState, Ni as DBPROXY_TAG_OPTIONS, Nt as getNestedRevertRun, O as stripIndexContributorInsights, Oa as s3BucketDomainName, P as resolveDynamoDbDeleteBudgetMs, Pc as recordReferenceProvenanceEntry, Pi as planTagDiff, Pn as getCurrentProducerRegions, Pr as replacedDeleteFailureVerdict, Ps as withoutSilentDropProperties, Qc as withoutPhysicalNameCopies, Qo as refuseMalformedNestedChildOutputs, Qs as configStringRefusal, Qt as isAccessDeniedError, R as maskedLogger, Rc as hasMaskableValues, Ri as tagPlanWarning, Rn as redactedDeleteAddressFields, S as indexDeclaresContributorInsights, Sd as renderAssemblyPathEscape, Si as earliestDefined, T as readContributorInsightsSpec, U as planTimeToLive, Us as WARM_THROUGHPUT_MEMBERS, V as isTtlAlreadyDisabled, Vt as withNestedStackContext, W as readTtlSpec, Ws as coerceWarmThroughput$1, X as getPriorAttempts, Xi as getCurrentResourceSecrets, Xl as timePhase, Xs as configBooleanRefusal, Y as isTruthyCfnBoolean, Ys as coerceCfnInteger, Z as markRefusedBeforeApplying, Zs as configIntegerRefusal, Zt as chunks, _ as streamMemberRefusals, _a as reDisableInstanceApiTermination, b as CONTRIBUTOR_INSIGHTS_KEY, bd as describeFileReadFailure, c as DynamoDBGlobalTableProvider, cc as blockDeviceMappingsDifferOnlyInDeleteOnTermination, cl as physicalNameCopiesOf, ct as listNestedTemplateRows, d as declaredStreamPolicyMember, da as isWaitAbandonedError, dc as emrClusterInstancesReplaced, ec as replayWarn, el as dynamicReferenceTokens, en as withApiLimit, f as declaredStreamTagsMember, fa as markWaitAbandoned, fc as canonicalLambdaFunctionName, fl as carriesSecretMask, g as streamDeclaresTags, ga as observeThenDisableInstanceApiTermination, go as passedParameterClassesOf, gt as enclosingDeadlineRemainingMs, h as streamDeclaresPolicy, ha as isTerminationProtectionPropagationError, ht as enclosingDeadlineExpired, ia as unchangedBehindSecretReference, iu as rewriteTemplateAssetReferences, j as compensateRemovedDeletionProtection, ja as s3BucketWebsiteUrl, ji as markDeleteStarted, k as DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS, ka as s3BucketDualStackDomainName, l as STREAM_POLICY_KEY, la as deleteSkipReason, li as secretNamedAttributeNamesOf, ll as recordAttributeIdCopy, lt as renderNestedTemplateTreeDefect, m as reverseMapStreamPolicy, ma as ec2InstanceProtectionSite, mc as sameLambdaFunctionAddress, na as slowCcOperationTimeoutMs, nc as requireConfigObject, no as getAccountInfo, od as canonicalizeRegion, ot as findNestedTemplateTreeDefect, p as planStreamMemberOps, pc as lambdaFunctionNameForMask, po as parseWebACLArn, q as S3_AUTO_DELETE_OBJECTS_TAG, qs as toFiniteNumber, ra as onlySecretReferencesDiffer, rc as requireConfigString, rd as decodeListingKey, sc as withRetry, sd as derivePartitionAndUrlSuffix, sl as recoverMaskedOutput, st as isAbsoluteAssetPath, t as DeployEngine, tc as requireConfigArray, u as STREAM_TAGS_KEY, ua as withIndeterminateGuard, uc as ecsServiceLaunchTypeSetOrChanged, v as streamPolicyMatchesDeclared, va as reEnableInstanceApiTermination, vs as refuseMalformedResourcesForDestroy, w as planIndexContributorInsightsOps, wi as reserveStackCreateToken, x as contributorInsightsRefusals, xd as displayAssemblyPath, y as streamTagsMatchDeclared, z as relayedIndexBusyDelete, zi as definedAttributes, zn as redactedDeleteAddressSkip } from "./deploy-engine-tQ0aqZMo.js";
6
+ import { n as collectInlinePolicyNamesManagedBySiblings, r as IamCreateClientCache, t as IAMRoleProvider } from "./iam-role-provider-BI8Acvps.js";
7
+ import { a as resolveSecretDerivedPrincipals, i as isResolvableSecretPrincipalList, n as runDestroyForStack, o as canonicalizeIpProtocolValue, r as holdsUnprovenSecretPrincipalToken, s as resolvedResourceTimeoutMs, t as canonicalizeIpv4Cidr } from "./program-Bnt3Yt0k.js";
8
8
  import { t as modifyDbInstanceWhenAvailable } from "./db-instance-modify-retry-BUG7NMWS.js";
9
- import { RDSProvider } from "./rds-provider-CZhBLQgJ.js";
10
- import { NeptuneProvider } from "./neptune-provider-Y3Ii8oYI.js";
11
- import { ASGProvider } from "./asg-provider-B7pAjRIc.js";
9
+ import { RDSProvider } from "./rds-provider-Qpf09VQv.js";
10
+ import { NeptuneProvider } from "./neptune-provider-DmVmx69p.js";
11
+ import { ASGProvider } from "./asg-provider-DQoKGfKH.js";
12
12
  import { createHash, randomUUID } from "node:crypto";
13
13
  import { 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, ListBucketsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client } from "@aws-sdk/client-s3";
14
14
  import { AddRoleToInstanceProfileCommand, AddUserToGroupCommand, AttachGroupPolicyCommand, AttachRolePolicyCommand, AttachUserPolicyCommand, CreateAccessKeyCommand, CreateGroupCommand, CreateInstanceProfileCommand, CreateLoginProfileCommand, CreatePolicyCommand, CreatePolicyVersionCommand, CreateUserCommand, DeleteAccessKeyCommand, DeleteGroupCommand, DeleteGroupPolicyCommand, DeleteInstanceProfileCommand, DeleteLoginProfileCommand, DeletePolicyCommand, DeletePolicyVersionCommand, DeleteRolePolicyCommand, DeleteUserCommand, DeleteUserPermissionsBoundaryCommand, DeleteUserPolicyCommand, DetachGroupPolicyCommand, DetachRolePolicyCommand, DetachUserPolicyCommand, GetAccessKeyLastUsedCommand, GetGroupCommand, GetGroupPolicyCommand, GetInstanceProfileCommand, GetPolicyCommand, GetPolicyVersionCommand, GetRolePolicyCommand, GetUserCommand, GetUserPolicyCommand, IAMClient, ListAccessKeysCommand, ListAttachedGroupPoliciesCommand, ListAttachedUserPoliciesCommand, ListEntitiesForPolicyCommand, ListGroupPoliciesCommand, ListGroupsForUserCommand, ListPoliciesCommand, ListPolicyTagsCommand, ListPolicyVersionsCommand, ListUserPoliciesCommand, NoSuchEntityException, PutGroupPolicyCommand, PutRolePolicyCommand, PutUserPermissionsBoundaryCommand, PutUserPolicyCommand, RemoveRoleFromInstanceProfileCommand, RemoveUserFromGroupCommand, TagPolicyCommand, TagUserCommand, UntagPolicyCommand, UntagUserCommand, UpdateAccessKeyCommand, UpdateGroupCommand, UpdateLoginProfileCommand, UpdateUserCommand } from "@aws-sdk/client-iam";
@@ -53,17 +53,17 @@ import { BudgetsClient, CreateBudgetCommand, CreateNotificationCommand, CreateSu
53
53
  import { AddTagsToStreamCommand, CreateStreamCommand, DecreaseStreamRetentionPeriodCommand, DeleteStreamCommand, DeregisterStreamConsumerCommand, DescribeStreamCommand, DescribeStreamConsumerCommand, DescribeStreamSummaryCommand, DisableEnhancedMonitoringCommand, EnableEnhancedMonitoringCommand, IncreaseStreamRetentionPeriodCommand, KinesisClient, ListTagsForResourceCommand as ListTagsForResourceCommand$16, ListTagsForStreamCommand, RegisterStreamConsumerCommand, RemoveTagsFromStreamCommand, ResourceNotFoundException as ResourceNotFoundException$12, StartStreamEncryptionCommand, StopStreamEncryptionCommand, TagResourceCommand as TagResourceCommand$21, UntagResourceCommand as UntagResourceCommand$22, UpdateMaxRecordSizeCommand, UpdateShardCountCommand, UpdateStreamModeCommand, UpdateStreamRecordDistributionStrategyCommand } from "@aws-sdk/client-kinesis";
54
54
  import { CreateScheduleCommand, DeleteScheduleCommand, GetScheduleCommand, ListSchedulesCommand, ResourceNotFoundException as ResourceNotFoundException$13, SchedulerClient, UpdateScheduleCommand } from "@aws-sdk/client-scheduler";
55
55
  import { CreatePipeCommand, DeletePipeCommand, DescribePipeCommand, NotFoundException as NotFoundException$6, PipesClient, TagResourceCommand as TagResourceCommand$22, UntagResourceCommand as UntagResourceCommand$23, UpdatePipeCommand } from "@aws-sdk/client-pipes";
56
- import { AccessPointAlreadyExists, AccessPointNotFound, CreateAccessPointCommand, CreateFileSystemCommand, CreateMountTargetCommand, DeleteAccessPointCommand, DeleteFileSystemCommand, DeleteMountTargetCommand, DescribeAccessPointsCommand, DescribeBackupPolicyCommand, DescribeFileSystemPolicyCommand, DescribeFileSystemsCommand, DescribeLifecycleConfigurationCommand, DescribeMountTargetSecurityGroupsCommand, DescribeMountTargetsCommand, EFSClient, FileSystemAlreadyExists, FileSystemNotFound, ModifyMountTargetSecurityGroupsCommand, MountTargetNotFound, PutBackupPolicyCommand, PutFileSystemPolicyCommand, PutLifecycleConfigurationCommand, UpdateFileSystemCommand, UpdateFileSystemProtectionCommand } from "@aws-sdk/client-efs";
57
- import { CreateFileSystemCommand as CreateFileSystemCommand$1, CreateFileSystemFromBackupCommand, DeleteFileSystemCommand as DeleteFileSystemCommand$1, DescribeFileSystemsCommand as DescribeFileSystemsCommand$1, FSxClient, FileSystemNotFound as FileSystemNotFound$1, TagResourceCommand as TagResourceCommand$23, UntagResourceCommand as UntagResourceCommand$24, UpdateFileSystemCommand as UpdateFileSystemCommand$1 } from "@aws-sdk/client-fsx";
56
+ import { AccessPointAlreadyExists, AccessPointNotFound, CreateAccessPointCommand, CreateFileSystemCommand, CreateMountTargetCommand, DeleteAccessPointCommand, DeleteFileSystemCommand, DeleteFileSystemPolicyCommand, DeleteMountTargetCommand, DescribeAccessPointsCommand, DescribeBackupPolicyCommand, DescribeFileSystemPolicyCommand, DescribeFileSystemsCommand, DescribeLifecycleConfigurationCommand, DescribeMountTargetSecurityGroupsCommand, DescribeMountTargetsCommand, EFSClient, FileSystemAlreadyExists, FileSystemNotFound, ModifyMountTargetSecurityGroupsCommand, MountTargetNotFound, PutBackupPolicyCommand, PutFileSystemPolicyCommand, PutLifecycleConfigurationCommand, TagResourceCommand as TagResourceCommand$23, UntagResourceCommand as UntagResourceCommand$24, UpdateFileSystemCommand, UpdateFileSystemProtectionCommand } from "@aws-sdk/client-efs";
57
+ import { AssociateFileSystemAliasesCommand, CreateFileSystemCommand as CreateFileSystemCommand$1, CreateFileSystemFromBackupCommand, DeleteFileSystemCommand as DeleteFileSystemCommand$1, DescribeFileSystemAliasesCommand, DescribeFileSystemsCommand as DescribeFileSystemsCommand$1, DisassociateFileSystemAliasesCommand, FSxClient, FileSystemNotFound as FileSystemNotFound$1, TagResourceCommand as TagResourceCommand$24, UntagResourceCommand as UntagResourceCommand$25, UpdateFileSystemCommand as UpdateFileSystemCommand$1 } from "@aws-sdk/client-fsx";
58
58
  import { AddInstanceFleetCommand, AddInstanceGroupsCommand, AddTagsCommand as AddTagsCommand$1, DescribeClusterCommand, EMRClient, InvalidRequestException, ListClustersCommand, ListInstanceFleetsCommand, ListInstanceGroupsCommand, ModifyClusterCommand, ModifyInstanceFleetCommand, ModifyInstanceGroupsCommand, PutAutoScalingPolicyCommand, PutAutoTerminationPolicyCommand, PutManagedScalingPolicyCommand, RemoveAutoScalingPolicyCommand, RemoveAutoTerminationPolicyCommand, RemoveManagedScalingPolicyCommand, RemoveTagsCommand as RemoveTagsCommand$1, RunJobFlowCommand, SetTerminationProtectionCommand, SetUnhealthyNodeReplacementCommand, SetVisibleToAllUsersCommand, TerminateJobFlowsCommand } from "@aws-sdk/client-emr";
59
59
  import { CreateDeliveryStreamCommand, DeleteDeliveryStreamCommand, DescribeDeliveryStreamCommand, FirehoseClient, ListTagsForDeliveryStreamCommand, ResourceNotFoundException as ResourceNotFoundException$14, StartDeliveryStreamEncryptionCommand, StopDeliveryStreamEncryptionCommand, TagDeliveryStreamCommand, UntagDeliveryStreamCommand, UpdateDestinationCommand } from "@aws-sdk/client-firehose";
60
60
  import { AddTagsCommand as AddTagsCommand$2, CloudTrailClient, CreateTrailCommand, DeleteTrailCommand, GetEventSelectorsCommand, GetInsightSelectorsCommand, GetTrailCommand, GetTrailStatusCommand, ListTagsCommand as ListTagsCommand$2, PutEventSelectorsCommand, PutInsightSelectorsCommand, RemoveTagsCommand as RemoveTagsCommand$2, StartLoggingCommand, StopLoggingCommand, TrailNotFoundException, UpdateTrailCommand } from "@aws-sdk/client-cloudtrail";
61
61
  import { BatchGetProjectsCommand, CodeBuildClient, CreateProjectCommand, DeleteProjectCommand, ResourceNotFoundException as ResourceNotFoundException$15, UpdateProjectCommand, UpdateProjectVisibilityCommand } from "@aws-sdk/client-codebuild";
62
- import { CodeCommitClient, CreateCommitCommand, CreateRepositoryCommand as CreateRepositoryCommand$1, DeleteRepositoryCommand as DeleteRepositoryCommand$1, GetRepositoryCommand, GetRepositoryTriggersCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$17, PutRepositoryTriggersCommand, RepositoryDoesNotExistException, TagResourceCommand as TagResourceCommand$24, UntagResourceCommand as UntagResourceCommand$25, UpdateRepositoryDescriptionCommand, UpdateRepositoryEncryptionKeyCommand, UpdateRepositoryNameCommand } from "@aws-sdk/client-codecommit";
63
- import { CreateLifecyclePolicyCommand, DLMClient, DeleteLifecyclePolicyCommand as DeleteLifecyclePolicyCommand$1, GetLifecyclePoliciesCommand, GetLifecyclePolicyCommand as GetLifecyclePolicyCommand$1, ResourceNotFoundException as ResourceNotFoundException$16, TagResourceCommand as TagResourceCommand$25, UntagResourceCommand as UntagResourceCommand$26, UpdateLifecyclePolicyCommand } from "@aws-sdk/client-dlm";
64
- import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketCommand, GetVectorBucketCommand, ListIndexesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$18, S3VectorsClient, TagResourceCommand as TagResourceCommand$26, UntagResourceCommand as UntagResourceCommand$27 } from "@aws-sdk/client-s3vectors";
65
- import { ListTagsForResourceCommand as ListTagsForResourceCommand$19, S3ControlClient, TagResourceCommand as TagResourceCommand$27, UntagResourceCommand as UntagResourceCommand$28 } from "@aws-sdk/client-s3-control";
66
- import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetNamespaceCommand as GetNamespaceCommand$1, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$20, NotFoundException as NotFoundException$7, RenameTableCommand, S3TablesClient, TagResourceCommand as TagResourceCommand$28, UntagResourceCommand as UntagResourceCommand$29 } from "@aws-sdk/client-s3tables";
62
+ import { CodeCommitClient, CreateCommitCommand, CreateRepositoryCommand as CreateRepositoryCommand$1, DeleteRepositoryCommand as DeleteRepositoryCommand$1, GetRepositoryCommand, GetRepositoryTriggersCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$17, PutRepositoryTriggersCommand, RepositoryDoesNotExistException, TagResourceCommand as TagResourceCommand$25, UntagResourceCommand as UntagResourceCommand$26, UpdateRepositoryDescriptionCommand, UpdateRepositoryEncryptionKeyCommand, UpdateRepositoryNameCommand } from "@aws-sdk/client-codecommit";
63
+ import { CreateLifecyclePolicyCommand, DLMClient, DeleteLifecyclePolicyCommand as DeleteLifecyclePolicyCommand$1, GetLifecyclePoliciesCommand, GetLifecyclePolicyCommand as GetLifecyclePolicyCommand$1, ResourceNotFoundException as ResourceNotFoundException$16, TagResourceCommand as TagResourceCommand$26, UntagResourceCommand as UntagResourceCommand$27, UpdateLifecyclePolicyCommand } from "@aws-sdk/client-dlm";
64
+ import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketCommand, GetVectorBucketCommand, ListIndexesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$18, S3VectorsClient, TagResourceCommand as TagResourceCommand$27, UntagResourceCommand as UntagResourceCommand$28 } from "@aws-sdk/client-s3vectors";
65
+ import { ListTagsForResourceCommand as ListTagsForResourceCommand$19, S3ControlClient, TagResourceCommand as TagResourceCommand$28, UntagResourceCommand as UntagResourceCommand$29 } from "@aws-sdk/client-s3-control";
66
+ import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetNamespaceCommand as GetNamespaceCommand$1, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$20, NotFoundException as NotFoundException$7, RenameTableCommand, S3TablesClient, TagResourceCommand as TagResourceCommand$29, UntagResourceCommand as UntagResourceCommand$30 } from "@aws-sdk/client-s3tables";
67
67
 
68
68
  //#region src/provisioning/providers/iam-policy-provider.ts
69
69
  const POLICY_NAME_SKIP_REASON = "no policy name in state — no delete issued";
@@ -7924,6 +7924,13 @@ function inlineCodeFileNameForRuntime(runtime) {
7924
7924
  if (runtime?.startsWith("python")) return "index.py";
7925
7925
  return "index.js";
7926
7926
  }
7927
+ const SEPARATELY_APPLIED_KEYS = /* @__PURE__ */ new Set([
7928
+ "Tags",
7929
+ "ReservedConcurrentExecutions",
7930
+ "RecursiveLoop",
7931
+ "CodeSigningConfigArn",
7932
+ "RuntimeManagementConfig"
7933
+ ]);
7927
7934
  var LambdaFunctionProvider = class {
7928
7935
  lambdaClient;
7929
7936
  createClient = new LambdaCreateClientCache(() => this.lambdaClient);
@@ -8168,6 +8175,7 @@ var LambdaFunctionProvider = class {
8168
8175
  }));
8169
8176
  }
8170
8177
  async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
8178
+ const markUnsettled = (key) => context?.markUnsettled?.(key);
8171
8179
  properties = withRemovalDefaults(this.removalDefaults, resourceType, properties, previousProperties, context);
8172
8180
  const log = lambdaOperationSinks(this.logger, context?.maskSecrets, [[physicalId, physicalId], [previousProperties["FunctionName"], physicalId]], properties);
8173
8181
  const operationMask = log.mask;
@@ -8195,12 +8203,9 @@ var LambdaFunctionProvider = class {
8195
8203
  "LoggingConfig",
8196
8204
  "DurableConfig"
8197
8205
  ];
8198
- let hasConfigChanges = false;
8199
- for (const field of configFields) if (JSON.stringify(properties[field]) !== JSON.stringify(previousProperties[field])) {
8200
- hasConfigChanges = true;
8201
- break;
8202
- }
8203
- if (hasConfigChanges) {
8206
+ const changedConfigFields = [];
8207
+ for (const field of configFields) if (JSON.stringify(properties[field]) !== JSON.stringify(previousProperties[field])) changedConfigFields.push(field);
8208
+ if (changedConfigFields.length > 0) {
8204
8209
  const configParams = {
8205
8210
  FunctionName: physicalId,
8206
8211
  Role: properties["Role"],
@@ -8222,6 +8227,7 @@ var LambdaFunctionProvider = class {
8222
8227
  LoggingConfig: properties["LoggingConfig"],
8223
8228
  DurableConfig: properties["DurableConfig"]
8224
8229
  };
8230
+ for (const field of changedConfigFields) markUnsettled(field);
8225
8231
  await this.lambdaClient.send(new UpdateFunctionConfigurationCommand(configParams));
8226
8232
  log.debug(`Updated configuration for Lambda function ${log.value(physicalId)}`);
8227
8233
  await this.waitForFunctionUpdated(logicalId, resourceType, physicalId, log);
@@ -8229,6 +8235,7 @@ var LambdaFunctionProvider = class {
8229
8235
  const newCodeSigningConfigArn = properties["CodeSigningConfigArn"];
8230
8236
  const codeSigningChanged = newCodeSigningConfigArn !== previousProperties["CodeSigningConfigArn"];
8231
8237
  if (codeSigningChanged && newCodeSigningConfigArn === void 0) {
8238
+ markUnsettled("CodeSigningConfigArn");
8232
8239
  await this.lambdaClient.send(new DeleteFunctionCodeSigningConfigCommand({ FunctionName: physicalId }));
8233
8240
  log.debug(`Detached CodeSigningConfigArn from Lambda function ${log.value(physicalId)} (template removed the property)`);
8234
8241
  }
@@ -8249,6 +8256,8 @@ var LambdaFunctionProvider = class {
8249
8256
  ImageUri: builtCode.ImageUri,
8250
8257
  Architectures: architecturesChanged ? normalizeArchitectures(properties["Architectures"]) : void 0
8251
8258
  };
8259
+ markUnsettled("Code");
8260
+ if (architecturesChanged) markUnsettled("Architectures");
8252
8261
  await this.lambdaClient.send(new UpdateFunctionCodeCommand(codeParams));
8253
8262
  log.debug(`Updated code for Lambda function ${log.value(physicalId)}`);
8254
8263
  await this.waitForFunctionUpdated(logicalId, resourceType, physicalId, log);
@@ -8256,6 +8265,7 @@ var LambdaFunctionProvider = class {
8256
8265
  const newRecursiveLoop = properties["RecursiveLoop"];
8257
8266
  const prevRecursiveLoop = previousProperties["RecursiveLoop"];
8258
8267
  if (newRecursiveLoop !== void 0 && newRecursiveLoop !== prevRecursiveLoop) {
8268
+ markUnsettled("RecursiveLoop");
8259
8269
  await this.lambdaClient.send(new PutFunctionRecursionConfigCommand({
8260
8270
  FunctionName: physicalId,
8261
8271
  RecursiveLoop: newRecursiveLoop
@@ -8264,6 +8274,7 @@ var LambdaFunctionProvider = class {
8264
8274
  }
8265
8275
  const newReservedConcurrentExecutions = properties["ReservedConcurrentExecutions"];
8266
8276
  if (newReservedConcurrentExecutions !== previousProperties["ReservedConcurrentExecutions"]) {
8277
+ markUnsettled("ReservedConcurrentExecutions");
8267
8278
  if (newReservedConcurrentExecutions === void 0) {
8268
8279
  await this.lambdaClient.send(new DeleteFunctionConcurrencyCommand({ FunctionName: physicalId }));
8269
8280
  log.debug(`Cleared ReservedConcurrentExecutions for Lambda function ${log.value(physicalId)} (template removed the property)`);
@@ -8276,6 +8287,7 @@ var LambdaFunctionProvider = class {
8276
8287
  }
8277
8288
  }
8278
8289
  if (codeSigningChanged && newCodeSigningConfigArn !== void 0) {
8290
+ markUnsettled("CodeSigningConfigArn");
8279
8291
  await this.lambdaClient.send(new PutFunctionCodeSigningConfigCommand({
8280
8292
  FunctionName: physicalId,
8281
8293
  CodeSigningConfigArn: newCodeSigningConfigArn
@@ -8285,12 +8297,16 @@ var LambdaFunctionProvider = class {
8285
8297
  const newRuntimeManagementConfig = properties["RuntimeManagementConfig"];
8286
8298
  const prevRuntimeManagementConfig = previousProperties["RuntimeManagementConfig"];
8287
8299
  if (newRuntimeManagementConfig?.["UpdateRuntimeOn"] !== prevRuntimeManagementConfig?.["UpdateRuntimeOn"] || newRuntimeManagementConfig?.["RuntimeVersionArn"] !== prevRuntimeManagementConfig?.["RuntimeVersionArn"]) {
8300
+ markUnsettled("RuntimeManagementConfig");
8288
8301
  await this.putRuntimeManagementConfig(physicalId, newRuntimeManagementConfig ?? { UpdateRuntimeOn: "Auto" });
8289
8302
  log.debug(`Updated RuntimeManagementConfig for Lambda function ${log.value(physicalId)} to ${JSON.stringify(maskDeep(newRuntimeManagementConfig ?? { UpdateRuntimeOn: "Auto" }, operationMask))}`);
8290
8303
  }
8291
8304
  const getResponse = await this.lambdaClient.send(new GetFunctionCommand({ FunctionName: physicalId }));
8292
8305
  const functionArn = getResponse.Configuration?.FunctionArn;
8293
- await this.applyTagDiff(functionArn, physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], log);
8306
+ await this.applyTagDiff(functionArn, physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], log, {
8307
+ forceUpsert: context?.unsettledProperties?.has("Tags") === true,
8308
+ beforeWrite: () => markUnsettled("Tags")
8309
+ });
8294
8310
  return {
8295
8311
  physicalId,
8296
8312
  wasReplaced: false,
@@ -8377,13 +8393,17 @@ var LambdaFunctionProvider = class {
8377
8393
  const subnets = raw["SubnetIds"];
8378
8394
  return Array.isArray(subnets) && subnets.length > 0;
8379
8395
  }
8380
- async applyTagDiff(functionArn, functionName, resourceType, logicalId, oldTagsRaw, newTagsRaw, log) {
8396
+ async applyTagDiff(functionArn, functionName, resourceType, logicalId, oldTagsRaw, newTagsRaw, log, unsettled = {
8397
+ forceUpsert: false,
8398
+ beforeWrite: () => void 0
8399
+ }) {
8381
8400
  if (!functionArn) return;
8382
8401
  const plan = planTagDiff(oldTagsRaw, newTagsRaw);
8383
8402
  const tagWarning = tagPlanWarning(plan, resourceType, logicalId);
8384
8403
  if (tagWarning !== void 0) log.warn(tagWarning);
8385
- const tagsToAdd = Object.fromEntries(plan.set);
8404
+ const tagsToAdd = Object.fromEntries(unsettled.forceUpsert ? planTagDiff(void 0, newTagsRaw).set : plan.set);
8386
8405
  const tagsToRemove = plan.remove;
8406
+ if (tagsToRemove.length > 0 || Object.keys(tagsToAdd).length > 0) unsettled.beforeWrite();
8387
8407
  if (tagsToRemove.length > 0) {
8388
8408
  await this.lambdaClient.send(new UntagResourceCommand$1({
8389
8409
  Resource: functionArn,
@@ -8623,6 +8643,43 @@ var LambdaFunctionProvider = class {
8623
8643
  throw err;
8624
8644
  }
8625
8645
  }
8646
+ async readUnsettled(physicalId, logicalId, resourceType, names) {
8647
+ const live = await this.readCurrentState(physicalId, logicalId, resourceType);
8648
+ if (typeof live !== "object" || live === null) return live;
8649
+ const out = { ...live };
8650
+ const strict = async (read) => {
8651
+ try {
8652
+ return await read();
8653
+ } catch (error) {
8654
+ if (error instanceof ResourceNotFoundException) return void 0;
8655
+ throw error;
8656
+ }
8657
+ };
8658
+ const set = (key, value) => {
8659
+ if (value === void 0) delete out[key];
8660
+ else out[key] = value;
8661
+ };
8662
+ if (names.has("ReservedConcurrentExecutions")) set("ReservedConcurrentExecutions", (await strict(() => this.lambdaClient.send(new GetFunctionConcurrencyCommand({ FunctionName: physicalId }))))?.ReservedConcurrentExecutions);
8663
+ if (names.has("RecursiveLoop")) set("RecursiveLoop", (await strict(() => this.lambdaClient.send(new GetFunctionRecursionConfigCommand({ FunctionName: physicalId }))))?.RecursiveLoop);
8664
+ if (names.has("RuntimeManagementConfig")) {
8665
+ const r = await strict(() => this.lambdaClient.send(new GetRuntimeManagementConfigCommand({ FunctionName: physicalId })));
8666
+ set("RuntimeManagementConfig", r?.UpdateRuntimeOn === void 0 ? void 0 : {
8667
+ UpdateRuntimeOn: r.UpdateRuntimeOn,
8668
+ ...r.RuntimeVersionArn !== void 0 && { RuntimeVersionArn: r.RuntimeVersionArn }
8669
+ });
8670
+ }
8671
+ if (names.has("CodeSigningConfigArn")) set("CodeSigningConfigArn", (await strict(() => this.lambdaClient.send(new GetFunctionCodeSigningConfigCommand({ FunctionName: physicalId }))))?.CodeSigningConfigArn);
8672
+ return out;
8673
+ }
8674
+ async unsettledInTransition(physicalId, _logicalId, _resourceType, names) {
8675
+ try {
8676
+ const cfg = (await this.lambdaClient.send(new GetFunctionCommand({ FunctionName: physicalId }))).Configuration;
8677
+ if (cfg?.State !== "Pending" && cfg?.LastUpdateStatus !== "InProgress") return /* @__PURE__ */ new Set();
8678
+ return new Set([...names].filter((name) => !SEPARATELY_APPLIED_KEYS.has(name)));
8679
+ } catch {
8680
+ return names;
8681
+ }
8682
+ }
8626
8683
  async readCurrentState(physicalId, _logicalId, _resourceType) {
8627
8684
  try {
8628
8685
  const resp = await this.lambdaClient.send(new GetFunctionCommand({ FunctionName: physicalId }));
@@ -12267,6 +12324,7 @@ var DynamoDBTableProvider = class {
12267
12324
  }
12268
12325
  }
12269
12326
  async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
12327
+ const markUnsettled = (key) => context?.markUnsettled?.(key);
12270
12328
  const maskSecrets = context?.maskSecrets ?? ((text) => text);
12271
12329
  const warn = (message) => this.logger.warn(maskSecrets(message));
12272
12330
  const debug = (message) => this.logger.debug(maskSecrets(message));
@@ -12310,7 +12368,10 @@ var DynamoDBTableProvider = class {
12310
12368
  warn(`${lsiMessage}; the LocalSecondaryIndexes change was not applied`);
12311
12369
  }
12312
12370
  let latestStreamArn = table?.LatestStreamArn;
12313
- if (table?.TableArn) await this.applyTagDiff(table.TableArn, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
12371
+ if (table?.TableArn) await this.applyTagDiff(table.TableArn, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], {
12372
+ forceUpsert: context?.unsettledProperties?.has("Tags") === true,
12373
+ beforeWrite: () => markUnsettled("Tags")
12374
+ });
12314
12375
  const normalizeTableClass = (v) => typeof v === "string" && v.length > 0 ? v : "STANDARD";
12315
12376
  const tableClassChanged = normalizeTableClass(properties["TableClass"]) !== normalizeTableClass(previousProperties["TableClass"]);
12316
12377
  const liveBillingMode = table?.BillingModeSummary?.BillingMode ?? "PROVISIONED";
@@ -12369,6 +12430,7 @@ var DynamoDBTableProvider = class {
12369
12430
  warn(`AWS::DynamoDB::Table ${logicalId}: this deploy removes global secondary index(es) ${removable.map((n) => maskSecrets(n)).join(", ")} and flips BillingMode to PROVISIONED. The removal would normally be applied BEFORE the flip, but ${reasons.join(" and ")}, so AWS rejects the flip either way. Nothing was removed.`);
12370
12431
  } else if (removable.length > 0) {
12371
12432
  debug(`Deleting GSI(s) ${removable.join(", ")} on DynamoDB table ${physicalId} before the BillingMode flip to PROVISIONED`);
12433
+ markUnsettled("GlobalSecondaryIndexes");
12372
12434
  await this.runGsiOps(physicalId, removable.map((name) => ({ Delete: { IndexName: name } })), void 0, maskSecrets);
12373
12435
  for (const name of removable) preFlipDeletedIndexNames.add(name);
12374
12436
  }
@@ -12415,6 +12477,10 @@ var DynamoDBTableProvider = class {
12415
12477
  if (indexUpdates.length > 0) updateInput.GlobalSecondaryIndexUpdates = indexUpdates;
12416
12478
  if (unspecified.length > 0) warn(`AWS::DynamoDB::Table ${logicalId}: flipping BillingMode to PROVISIONED, but the template declares no usable ProvisionedThroughput for live index(es) ${unspecified.map((n) => maskSecrets(n)).join(", ")}. AWS requires per-index capacity in the same UpdateTable and will reject the flip naming them. Declare GlobalSecondaryIndexes[].ProvisionedThroughput (both ReadCapacityUnits and WriteCapacityUnits) for each. An index this deploy REMOVES is deleted BEFORE the flip automatically, so a name here is one the template still keeps, one that exists in AWS but in neither the template nor cdkd state (created out of band), or one whose pre-flip removal was skipped for the reason warned above.`);
12417
12479
  }
12480
+ if (billingMode !== prevBillingMode) markUnsettled("BillingMode");
12481
+ if (JSON.stringify(properties["ProvisionedThroughput"]) !== JSON.stringify(previousProperties["ProvisionedThroughput"])) markUnsettled("ProvisionedThroughput");
12482
+ if (tableClassChanged) markUnsettled("TableClass");
12483
+ if (updateInput.GlobalSecondaryIndexUpdates !== void 0) markUnsettled("GlobalSecondaryIndexes");
12418
12484
  await this.dynamoDBClient.send(new UpdateTableCommand(updateInput));
12419
12485
  if (billingMode !== liveBillingMode) await this.waitForTableAndIndexesActive(physicalId, BILLING_FLIP_ACTIVE_WAIT_ATTEMPTS);
12420
12486
  else await this.waitForTableActiveAfterUpdate(physicalId, 60);
@@ -12425,6 +12491,7 @@ var DynamoDBTableProvider = class {
12425
12491
  if (properties["OnDemandThroughput"] || ceilingRemovals.length > 0) {
12426
12492
  const declaredForSend = properties["OnDemandThroughput"] ? this.coerceOnDemandCeilingsForSend(`AWS::DynamoDB::Table ${logicalId}`, properties["OnDemandThroughput"], maskSecrets) : {};
12427
12493
  if (ceilingRemovals.length > 0) debug(`AWS::DynamoDB::Table ${logicalId}: removing the OnDemandThroughput ${ceilingRemovals.join(" / ")} the template no longer declares (sending ${ON_DEMAND_LIMIT_RESET}, DynamoDB's reset sentinel)`);
12494
+ markUnsettled("OnDemandThroughput");
12428
12495
  await this.dynamoDBClient.send(new UpdateTableCommand({
12429
12496
  TableName: physicalId,
12430
12497
  OnDemandThroughput: withOnDemandCeilingRemovals(declaredForSend, ceilingRemovals)
@@ -12437,6 +12504,7 @@ var DynamoDBTableProvider = class {
12437
12504
  this.warnRefusedWarmThroughput(`AWS::DynamoDB::Table ${logicalId}`, properties["WarmThroughput"], maskSecrets);
12438
12505
  const warmThroughputToSend = this.coerceWarmThroughputForSend(`AWS::DynamoDB::Table ${logicalId}`, properties["WarmThroughput"], maskSecrets);
12439
12506
  if (warmThroughputToSend !== void 0 && !this.skipWarmThroughputDecrease(logicalId, physicalId, warmThroughputToSend, table?.WarmThroughput, maskSecrets)) {
12507
+ markUnsettled("WarmThroughput");
12440
12508
  await this.dynamoDBClient.send(new UpdateTableCommand({
12441
12509
  TableName: physicalId,
12442
12510
  WarmThroughput: warmThroughputToSend
@@ -12452,6 +12520,7 @@ var DynamoDBTableProvider = class {
12452
12520
  if (liveSseStatus === "UPDATING" || liveSseStatus === "ENABLING" || liveSseStatus === "DISABLING") liveTable = await this.waitForTableSseSettled(physicalId, maskSecrets);
12453
12521
  const sseUpdate = sseSpecificationToSend(properties["SSESpecification"], previousProperties["SSESpecification"], liveTable?.SSEDescription, liveTable !== void 0);
12454
12522
  if (sseUpdate !== void 0) {
12523
+ markUnsettled("SSESpecification");
12455
12524
  await this.dynamoDBClient.send(new UpdateTableCommand({
12456
12525
  TableName: physicalId,
12457
12526
  SSESpecification: sseUpdate
@@ -12465,6 +12534,7 @@ var DynamoDBTableProvider = class {
12465
12534
  const desiredDeletionProtection = rawDeletionProtection === void 0 ? false : coerceCfnBoolean(rawDeletionProtection);
12466
12535
  if (desiredDeletionProtection === void 0) warn(`AWS::DynamoDB::Table ${logicalId}: DeletionProtectionEnabled is not a boolean, so it was not applied`);
12467
12536
  else if (table?.DeletionProtectionEnabled !== desiredDeletionProtection) {
12537
+ markUnsettled("DeletionProtectionEnabled");
12468
12538
  await this.dynamoDBClient.send(new UpdateTableCommand({
12469
12539
  TableName: physicalId,
12470
12540
  DeletionProtectionEnabled: desiredDeletionProtection
@@ -12474,6 +12544,7 @@ var DynamoDBTableProvider = class {
12474
12544
  }
12475
12545
  }
12476
12546
  if (JSON.stringify(properties["StreamSpecification"]) !== JSON.stringify(previousProperties["StreamSpecification"])) {
12547
+ markUnsettled("StreamSpecification");
12477
12548
  const newViewType = this.extractStreamViewType(properties["StreamSpecification"]);
12478
12549
  const prevViewType = this.extractStreamViewType(previousProperties["StreamSpecification"]);
12479
12550
  const liveStream = table?.StreamSpecification;
@@ -12521,10 +12592,18 @@ var DynamoDBTableProvider = class {
12521
12592
  }
12522
12593
  if (newViewType) await this.applyStreamMembers(logicalId, resourceType, physicalId, latestStreamArn, properties["StreamSpecification"], previousProperties["StreamSpecification"], mintedStream, maskSecrets, mintedStream ? preUpdateStreamArn : void 0, contentsUnknown);
12523
12594
  }
12524
- if (JSON.stringify(properties["GlobalSecondaryIndexes"]) !== JSON.stringify(previousProperties["GlobalSecondaryIndexes"])) await this.applyGsiUpdates(physicalId, resourceType, logicalId, previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"], properties["AttributeDefinitions"], gsiHandledByBillingFlip, currentLiveIndexNames, currentLiveIndexByName, liveCapacityComparable, effectiveBillingMode === "PAY_PER_REQUEST", maskSecrets);
12525
- if (JSON.stringify(properties["PointInTimeRecoverySpecification"]) !== JSON.stringify(previousProperties["PointInTimeRecoverySpecification"])) await this.applyPointInTimeRecovery(physicalId, properties["PointInTimeRecoverySpecification"], previousProperties["PointInTimeRecoverySpecification"], maskSecrets);
12595
+ if (context?.unsettledProperties?.has("GlobalSecondaryIndexes") === true && currentLiveIndexNames !== void 0) this.warnUndeclaredLiveIndexes(physicalId, currentLiveIndexNames, [previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"]], maskSecrets);
12596
+ if (JSON.stringify(properties["GlobalSecondaryIndexes"]) !== JSON.stringify(previousProperties["GlobalSecondaryIndexes"])) {
12597
+ markUnsettled("GlobalSecondaryIndexes");
12598
+ await this.applyGsiUpdates(physicalId, resourceType, logicalId, previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"], properties["AttributeDefinitions"], gsiHandledByBillingFlip, currentLiveIndexNames, currentLiveIndexByName, liveCapacityComparable, effectiveBillingMode === "PAY_PER_REQUEST", maskSecrets);
12599
+ }
12600
+ if (JSON.stringify(properties["PointInTimeRecoverySpecification"]) !== JSON.stringify(previousProperties["PointInTimeRecoverySpecification"])) {
12601
+ markUnsettled("PointInTimeRecoverySpecification");
12602
+ await this.applyPointInTimeRecovery(physicalId, properties["PointInTimeRecoverySpecification"], previousProperties["PointInTimeRecoverySpecification"], maskSecrets);
12603
+ }
12526
12604
  if (JSON.stringify(properties["TimeToLiveSpecification"]) !== JSON.stringify(previousProperties["TimeToLiveSpecification"])) {
12527
12605
  this.assertNoActiveTtlAttributeNameChange(logicalId, resourceType, physicalId, properties["TimeToLiveSpecification"], previousProperties["TimeToLiveSpecification"]);
12606
+ markUnsettled("TimeToLiveSpecification");
12528
12607
  await this.applyTimeToLive(physicalId, properties["TimeToLiveSpecification"], previousProperties["TimeToLiveSpecification"], "update", {
12529
12608
  logicalId,
12530
12609
  resourceType,
@@ -12533,11 +12612,18 @@ var DynamoDBTableProvider = class {
12533
12612
  }
12534
12613
  if (JSON.stringify(properties["ResourcePolicy"]) !== JSON.stringify(previousProperties["ResourcePolicy"])) {
12535
12614
  if (!table?.TableArn) throw new ProvisioningError(`Cannot apply ResourcePolicy change for DynamoDB table ${logicalId}: DescribeTable returned no TableArn`, resourceType, logicalId, physicalId);
12615
+ markUnsettled("ResourcePolicy");
12536
12616
  await this.applyResourcePolicy(table.TableArn, properties["ResourcePolicy"], previousProperties["ResourcePolicy"]);
12537
12617
  }
12538
- if (JSON.stringify(properties["KinesisStreamSpecification"]) !== JSON.stringify(previousProperties["KinesisStreamSpecification"])) await this.applyKinesisStreamingDestination(physicalId, properties["KinesisStreamSpecification"], previousProperties["KinesisStreamSpecification"], maskSecrets);
12539
- if (JSON.stringify(properties["ContributorInsightsSpecification"]) !== JSON.stringify(previousProperties["ContributorInsightsSpecification"])) await this.applyContributorInsights(physicalId, properties["ContributorInsightsSpecification"], previousProperties["ContributorInsightsSpecification"], maskSecrets);
12540
- await this.applyIndexContributorInsights(physicalId, properties["GlobalSecondaryIndexes"], previousProperties["GlobalSecondaryIndexes"], maskSecrets);
12618
+ if (JSON.stringify(properties["KinesisStreamSpecification"]) !== JSON.stringify(previousProperties["KinesisStreamSpecification"])) {
12619
+ markUnsettled("KinesisStreamSpecification");
12620
+ await this.applyKinesisStreamingDestination(physicalId, properties["KinesisStreamSpecification"], previousProperties["KinesisStreamSpecification"], maskSecrets);
12621
+ }
12622
+ if (JSON.stringify(properties["ContributorInsightsSpecification"]) !== JSON.stringify(previousProperties["ContributorInsightsSpecification"])) {
12623
+ markUnsettled("ContributorInsightsSpecification");
12624
+ await this.applyContributorInsights(physicalId, properties["ContributorInsightsSpecification"], previousProperties["ContributorInsightsSpecification"], maskSecrets);
12625
+ }
12626
+ await this.applyIndexContributorInsights(physicalId, properties["GlobalSecondaryIndexes"], previousProperties["GlobalSecondaryIndexes"], maskSecrets, () => markUnsettled("GlobalSecondaryIndexes"));
12541
12627
  return {
12542
12628
  physicalId,
12543
12629
  wasReplaced: false,
@@ -12675,15 +12761,19 @@ var DynamoDBTableProvider = class {
12675
12761
  throw error instanceof Error && error.name.includes("NotFound") ? markNotGone(thrown) : thrown;
12676
12762
  }
12677
12763
  }
12678
- async applyTagDiff(tableArn, resourceType, logicalId, oldTagsRaw, newTagsRaw) {
12764
+ async applyTagDiff(tableArn, resourceType, logicalId, oldTagsRaw, newTagsRaw, unsettled = {
12765
+ forceUpsert: false,
12766
+ beforeWrite: () => void 0
12767
+ }) {
12679
12768
  const plan = planTagDiff(oldTagsRaw, newTagsRaw);
12680
12769
  const tagWarning = tagPlanWarning(plan, resourceType, logicalId);
12681
12770
  if (tagWarning !== void 0) this.logger.warn(tagWarning);
12682
- const tagsToAdd = [...plan.set].map(([k, v]) => ({
12771
+ const tagsToAdd = [...unsettled.forceUpsert ? planTagDiff(void 0, newTagsRaw).set : plan.set].map(([k, v]) => ({
12683
12772
  Key: k,
12684
12773
  Value: v
12685
12774
  }));
12686
12775
  const tagsToRemove = plan.remove;
12776
+ if (tagsToRemove.length > 0 || tagsToAdd.length > 0) unsettled.beforeWrite();
12687
12777
  if (tagsToRemove.length > 0) {
12688
12778
  await this.dynamoDBClient.send(new UntagResourceCommand$2({
12689
12779
  ResourceArn: tableArn,
@@ -12996,12 +13086,15 @@ var DynamoDBTableProvider = class {
12996
13086
  if (op === void 0) return;
12997
13087
  await this.sendContributorInsightsOp(tableName, op, maskSecrets);
12998
13088
  }
12999
- async applyIndexContributorInsights(tableName, desiredIndexes, previousIndexes, maskSecrets) {
13089
+ async applyIndexContributorInsights(tableName, desiredIndexes, previousIndexes, maskSecrets, beforeSend = () => void 0) {
13000
13090
  const warn = (message) => this.logger.warn(maskSecrets(message));
13001
13091
  const ops = planIndexContributorInsightsOps(desiredIndexes, previousIndexes, (indexName, reason) => warn(`${this.indexScopeAt(indexName, tableName, maskSecrets)}: ${reason}, so its Contributor Insights was left as it is. Fix the template value and re-deploy.`));
13002
13092
  if (ops.length === 0) return;
13003
13093
  await this.waitForTableAndIndexesActive(tableName);
13004
- for (const op of ops) await this.sendContributorInsightsOp(tableName, op, maskSecrets);
13094
+ for (const op of ops) {
13095
+ beforeSend();
13096
+ await this.sendContributorInsightsOp(tableName, op, maskSecrets);
13097
+ }
13005
13098
  }
13006
13099
  async sendContributorInsightsOp(tableName, op, maskSecrets) {
13007
13100
  const debug = (message) => this.logger.debug(maskSecrets(message));
@@ -13153,6 +13246,21 @@ var DynamoDBTableProvider = class {
13153
13246
  indexScope(indexName, logicalId, maskSecrets) {
13154
13247
  return `GSI ${typeof indexName === "string" ? maskSecrets(indexName) : "<unnamed>"} on AWS::DynamoDB::Table ${logicalId}`;
13155
13248
  }
13249
+ warnUndeclaredLiveIndexes(physicalId, liveIndexNames, lists, maskSecrets) {
13250
+ const named = /* @__PURE__ */ new Set();
13251
+ for (const list of lists) {
13252
+ if (!Array.isArray(list)) continue;
13253
+ for (const entry of list) {
13254
+ const name = typeof entry === "object" && entry !== null ? entry["IndexName"] : void 0;
13255
+ if (typeof name === "string") named.add(name);
13256
+ }
13257
+ }
13258
+ for (const name of liveIndexNames) {
13259
+ if (named.has(name)) continue;
13260
+ const secretDerived = maskSecrets(name) !== name || maskSecrets(physicalId) !== physicalId;
13261
+ this.logger.warn(maskSecrets(`${this.indexScopeAt(name, physicalId, maskSecrets)} is live, but neither cdkd's record nor the template declares it, so cdkd left it in place while converging the unsettled GlobalSecondaryIndexes (CloudFormation never deletes an index it did not record). It may belong to another tool, or an earlier failed cdkd update may have created it; cdkd cannot tell which. If it should not exist, delete it ` + (secretDerived ? `with an UpdateTable GlobalSecondaryIndexUpdates Delete for the index.` : `with: aws dynamodb update-table --table-name ${physicalId} --global-secondary-index-updates '[{"Delete":{"IndexName":"${name}"}}]' (in the table's region)`)));
13262
+ }
13263
+ }
13156
13264
  indexScopeAt(indexName, physicalId, maskSecrets) {
13157
13265
  return `GSI ${typeof indexName === "string" ? maskSecrets(indexName) : "<unnamed>"} on DynamoDB table ${physicalId}`;
13158
13266
  }
@@ -13439,6 +13547,62 @@ var DynamoDBTableProvider = class {
13439
13547
  aws
13440
13548
  };
13441
13549
  }
13550
+ async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties) {
13551
+ const live = await this.readCurrentState(physicalId, logicalId, resourceType, recordedProperties);
13552
+ if (typeof live !== "object" || live === null) return live;
13553
+ const out = { ...live };
13554
+ if (out["BillingMode"] === "PAY_PER_REQUEST") delete out["ProvisionedThroughput"];
13555
+ if (names.has("GlobalSecondaryIndexes")) {
13556
+ out["GlobalSecondaryIndexes"] = projectIndexesOnto(out["GlobalSecondaryIndexes"], recordedProperties?.["GlobalSecondaryIndexes"], desiredProperties?.["GlobalSecondaryIndexes"]);
13557
+ if (out["GlobalSecondaryIndexes"] === void 0) delete out["GlobalSecondaryIndexes"];
13558
+ }
13559
+ const strict = async (key, read) => {
13560
+ if (!names.has(key)) return;
13561
+ const value = await read();
13562
+ if (value === void 0) delete out[key];
13563
+ else out[key] = value;
13564
+ };
13565
+ await strict("PointInTimeRecoverySpecification", () => this.readPointInTimeRecovery(physicalId, true));
13566
+ await strict("TimeToLiveSpecification", () => this.readTimeToLive(physicalId, true));
13567
+ await strict("KinesisStreamSpecification", () => this.readKinesisStreamSpecification(physicalId, true));
13568
+ await strict("ContributorInsightsSpecification", () => this.readTableContributorInsights(physicalId, true));
13569
+ if (names.has("ResourcePolicy")) {
13570
+ const table = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table;
13571
+ if (!table?.TableArn) throw new ProvisioningError(`DescribeTable returned no TableArn for the table, which reading its unsettled ResourcePolicy needs`, resourceType, logicalId, physicalId);
13572
+ const tableArn = table.TableArn;
13573
+ await strict("ResourcePolicy", () => this.readTableResourcePolicy(physicalId, tableArn, true));
13574
+ }
13575
+ return out;
13576
+ }
13577
+ async unsettledInTransition(physicalId, _logicalId, _resourceType, names) {
13578
+ const SEPARATE = /* @__PURE__ */ new Set([
13579
+ "Tags",
13580
+ "PointInTimeRecoverySpecification",
13581
+ "TimeToLiveSpecification",
13582
+ "ResourcePolicy",
13583
+ "KinesisStreamSpecification",
13584
+ "ContributorInsightsSpecification"
13585
+ ]);
13586
+ try {
13587
+ const table = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table;
13588
+ const moving = /* @__PURE__ */ new Set();
13589
+ if (table?.TableStatus === "CREATING" || table?.TableStatus === "UPDATING" || table?.TableStatus === "DELETING") {
13590
+ for (const name of names) if (!SEPARATE.has(name)) moving.add(name);
13591
+ }
13592
+ if (names.has("GlobalSecondaryIndexes") && (table?.GlobalSecondaryIndexes ?? []).some((index) => index.IndexStatus === "CREATING" || index.IndexStatus === "UPDATING" || index.IndexStatus === "DELETING")) moving.add("GlobalSecondaryIndexes");
13593
+ const sse = table?.SSEDescription?.Status;
13594
+ if (names.has("SSESpecification") && (sse === "ENABLING" || sse === "DISABLING" || sse === "UPDATING")) moving.add("SSESpecification");
13595
+ if (names.has("TimeToLiveSpecification")) {
13596
+ if ((await this.dynamoDBClient.send(new DescribeTimeToLiveCommand({ TableName: physicalId }))).TimeToLiveDescription?.TimeToLiveStatus === "ENABLING") moving.add("TimeToLiveSpecification");
13597
+ }
13598
+ if (names.has("KinesisStreamSpecification")) {
13599
+ if (((await this.dynamoDBClient.send(new DescribeKinesisStreamingDestinationCommand({ TableName: physicalId }))).KinesisDataStreamDestinations ?? []).some((d) => d.DestinationStatus === "ENABLING" || d.DestinationStatus === "DISABLING" || d.DestinationStatus === "UPDATING")) moving.add("KinesisStreamSpecification");
13600
+ }
13601
+ return moving;
13602
+ } catch {
13603
+ return names;
13604
+ }
13605
+ }
13442
13606
  async readCurrentState(physicalId, _logicalId, _resourceType, properties, context) {
13443
13607
  try {
13444
13608
  const table = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table;
@@ -13521,7 +13685,7 @@ var DynamoDBTableProvider = class {
13521
13685
  throw err;
13522
13686
  }
13523
13687
  }
13524
- async readPointInTimeRecovery(physicalId) {
13688
+ async readPointInTimeRecovery(physicalId, strict = false) {
13525
13689
  try {
13526
13690
  const pitrDesc = (await this.dynamoDBClient.send(new DescribeContinuousBackupsCommand({ TableName: physicalId }))).ContinuousBackupsDescription?.PointInTimeRecoveryDescription;
13527
13691
  const pitrStatus = pitrDesc?.PointInTimeRecoveryStatus;
@@ -13530,11 +13694,12 @@ var DynamoDBTableProvider = class {
13530
13694
  if (pitrStatus === "ENABLED" && pitrDesc?.RecoveryPeriodInDays !== void 0) pitr["RecoveryPeriodInDays"] = pitrDesc.RecoveryPeriodInDays;
13531
13695
  return pitr;
13532
13696
  } catch (err) {
13697
+ if (strict) throw err;
13533
13698
  this.logger.debug(`Could not read PointInTimeRecovery for ${physicalId}: ${describeAwsFailure(err).detail}`);
13534
13699
  return;
13535
13700
  }
13536
13701
  }
13537
- async readTimeToLive(physicalId) {
13702
+ async readTimeToLive(physicalId, strict = false) {
13538
13703
  try {
13539
13704
  const ttlDesc = (await this.dynamoDBClient.send(new DescribeTimeToLiveCommand({ TableName: physicalId }))).TimeToLiveDescription;
13540
13705
  if (ttlDesc?.TimeToLiveStatus === "ENABLED" && ttlDesc.AttributeName) return {
@@ -13543,11 +13708,12 @@ var DynamoDBTableProvider = class {
13543
13708
  };
13544
13709
  return;
13545
13710
  } catch (err) {
13711
+ if (strict) throw err;
13546
13712
  this.logger.debug(`Could not read TimeToLive for ${physicalId}: ${describeAwsFailure(err).detail}`);
13547
13713
  return;
13548
13714
  }
13549
13715
  }
13550
- async readTableResourcePolicy(physicalId, tableArn) {
13716
+ async readTableResourcePolicy(physicalId, tableArn, strict = false) {
13551
13717
  try {
13552
13718
  const rpResp = await this.dynamoDBClient.send(new GetResourcePolicyCommand({ ResourceArn: tableArn }));
13553
13719
  if (!rpResp.Policy) return void 0;
@@ -13557,11 +13723,12 @@ var DynamoDBTableProvider = class {
13557
13723
  } catch {}
13558
13724
  return { PolicyDocument: doc };
13559
13725
  } catch (err) {
13726
+ if (strict && !(err instanceof ResourceNotFoundException$1) && !(err instanceof PolicyNotFoundException)) throw err;
13560
13727
  if (!(err instanceof ResourceNotFoundException$1)) this.logger.debug(`Could not read ResourcePolicy for ${physicalId}: ${describeAwsFailure(err).detail}`);
13561
13728
  return;
13562
13729
  }
13563
13730
  }
13564
- async readKinesisStreamSpecification(physicalId) {
13731
+ async readKinesisStreamSpecification(physicalId, strict = false) {
13565
13732
  try {
13566
13733
  const active = ((await this.dynamoDBClient.send(new DescribeKinesisStreamingDestinationCommand({ TableName: physicalId }))).KinesisDataStreamDestinations ?? []).find((d) => d.DestinationStatus === "ACTIVE" || d.DestinationStatus === "ENABLING" || d.DestinationStatus === "UPDATING");
13567
13734
  if (!active?.StreamArn) return void 0;
@@ -13569,15 +13736,17 @@ var DynamoDBTableProvider = class {
13569
13736
  if (active.ApproximateCreationDateTimePrecision !== void 0) kspec["ApproximateCreationDateTimePrecision"] = active.ApproximateCreationDateTimePrecision;
13570
13737
  return kspec;
13571
13738
  } catch (err) {
13739
+ if (strict) throw err;
13572
13740
  this.logger.debug(`Could not read KinesisStreamingDestination for ${physicalId}: ${describeAwsFailure(err).detail}`);
13573
13741
  return;
13574
13742
  }
13575
13743
  }
13576
- async readTableContributorInsights(physicalId) {
13744
+ async readTableContributorInsights(physicalId, strict = false) {
13577
13745
  try {
13578
13746
  const ciResp = await this.dynamoDBClient.send(new DescribeContributorInsightsCommand({ TableName: physicalId }));
13579
13747
  return reverseMapTableContributorInsights(ciResp.ContributorInsightsStatus, ciResp.ContributorInsightsMode);
13580
13748
  } catch (err) {
13749
+ if (strict) throw err;
13581
13750
  this.logger.debug(`Could not read ContributorInsights for ${physicalId}: ${describeAwsFailure(err).detail}`);
13582
13751
  return;
13583
13752
  }
@@ -13701,6 +13870,22 @@ var DynamoDBTableProvider = class {
13701
13870
  function isTransientStreamReadFailure(err) {
13702
13871
  return isThrottlingError(err) || isTransientServerError(err) || isAmbiguousOutcomeError(err) || err instanceof ResourceNotFoundException$1;
13703
13872
  }
13873
+ function projectIndexesOnto(live, recorded, desired) {
13874
+ if (!Array.isArray(live)) return void 0;
13875
+ const named = /* @__PURE__ */ new Set();
13876
+ for (const list of [recorded, desired]) {
13877
+ if (!Array.isArray(list)) continue;
13878
+ for (const entry of list) {
13879
+ const name = typeof entry === "object" && entry !== null ? entry["IndexName"] : void 0;
13880
+ if (typeof name === "string") named.add(name);
13881
+ }
13882
+ }
13883
+ const kept = live.filter((entry) => {
13884
+ const name = typeof entry === "object" && entry !== null ? entry["IndexName"] : void 0;
13885
+ return typeof name === "string" && named.has(name);
13886
+ });
13887
+ return kept.length > 0 ? kept : void 0;
13888
+ }
13704
13889
 
13705
13890
  //#endregion
13706
13891
  //#region src/provisioning/providers/logs-loggroup-provider.ts
@@ -18323,7 +18508,7 @@ var EC2Provider = class {
18323
18508
  if (!Array.isArray(ingressRules) || ingressRules.length === 0) return;
18324
18509
  await this.ec2Client.send(new AuthorizeSecurityGroupIngressCommand({
18325
18510
  GroupId: groupId,
18326
- IpPermissions: ingressRules.map((rule) => this.buildIpPermission(rule))
18511
+ IpPermissions: ingressRules.map((rule) => this.buildIpPermission(rule, "ingress", true))
18327
18512
  }));
18328
18513
  }
18329
18514
  async applyInlineEgress(groupId, egressRules) {
@@ -19491,7 +19676,7 @@ var EC2Provider = class {
19491
19676
  const raw = obj["CPUCredits"] ?? obj["CpuCredits"];
19492
19677
  return typeof raw === "string" ? raw : void 0;
19493
19678
  }
19494
- buildIpPermission(properties, direction = "ingress") {
19679
+ buildIpPermission(properties, direction = "ingress", inline = false) {
19495
19680
  const ipProtocol = properties["IpProtocol"] ?? "-1";
19496
19681
  const fromPort = properties["FromPort"];
19497
19682
  const toPort = properties["ToPort"];
@@ -19512,8 +19697,9 @@ var EC2Provider = class {
19512
19697
  permission.Ipv6Ranges = [ipv6Range];
19513
19698
  }
19514
19699
  const peerGroupId = direction === "egress" ? properties["DestinationSecurityGroupId"] : properties["SourceSecurityGroupId"];
19515
- if (peerGroupId) {
19516
- const groupPair = { GroupId: peerGroupId };
19700
+ const peerGroupName = inline && direction === "ingress" ? properties["SourceSecurityGroupName"] : void 0;
19701
+ if (peerGroupId || peerGroupName) {
19702
+ const groupPair = peerGroupId ? { GroupId: peerGroupId } : { GroupName: peerGroupName };
19517
19703
  if (direction === "ingress") {
19518
19704
  const peerOwnerId = properties["SourceSecurityGroupOwnerId"];
19519
19705
  if (peerOwnerId) groupPair.UserId = peerOwnerId;
@@ -19534,6 +19720,7 @@ var EC2Provider = class {
19534
19720
  const peerKey = direction === "egress" ? rule["DestinationSecurityGroupId"] : rule["SourceSecurityGroupId"];
19535
19721
  const prefixKey = direction === "egress" ? rule["DestinationPrefixListId"] : rule["SourcePrefixListId"];
19536
19722
  const peerOwner = direction === "ingress" ? rule["SourceSecurityGroupOwnerId"] : void 0;
19723
+ const peerName = direction === "ingress" ? rule["SourceSecurityGroupName"] : void 0;
19537
19724
  return JSON.stringify({
19538
19725
  p: sgProtocolKey(rule["IpProtocol"]),
19539
19726
  f: rule["FromPort"] ?? null,
@@ -19541,6 +19728,7 @@ var EC2Provider = class {
19541
19728
  c4: rule["CidrIp"] ?? null,
19542
19729
  c6: rule["CidrIpv6"] ?? null,
19543
19730
  peer: peerKey ?? null,
19731
+ peerName: peerKey ? null : peerName ?? null,
19544
19732
  peerOwner: peerOwner ?? null,
19545
19733
  pl: prefixKey ?? null,
19546
19734
  d: rule["Description"] ?? null
@@ -19569,7 +19757,7 @@ var EC2Provider = class {
19569
19757
  }));
19570
19758
  else await this.ec2Client.send(new RevokeSecurityGroupIngressCommand({
19571
19759
  GroupId: groupId,
19572
- IpPermissions: [this.buildIpPermission(rule, "ingress")]
19760
+ IpPermissions: [this.buildIpPermission(rule, "ingress", true)]
19573
19761
  }));
19574
19762
  } catch (error) {
19575
19763
  if (!this.isNotFoundError(error)) throw error;
@@ -19582,7 +19770,7 @@ var EC2Provider = class {
19582
19770
  }));
19583
19771
  else await this.ec2Client.send(new AuthorizeSecurityGroupIngressCommand({
19584
19772
  GroupId: groupId,
19585
- IpPermissions: [this.buildIpPermission(rule, "ingress")]
19773
+ IpPermissions: [this.buildIpPermission(rule, "ingress", true)]
19586
19774
  }));
19587
19775
  } catch (error) {
19588
19776
  if (!(error instanceof Error && error.message.includes("already exists"))) throw error;
@@ -30866,6 +31054,18 @@ var DocDBSubnetGroupProvider = class {
30866
31054
  function isZoneDisabledForMutationError(error) {
30867
31055
  return error instanceof Error && error.message.includes("is marked disabled for mutation");
30868
31056
  }
31057
+ function declaresAcceleratedRecovery(properties, acceptReadSideKey = false) {
31058
+ const features = properties["HostedZoneFeatures"];
31059
+ if (isTruthyCfnBoolean(features?.["EnableAcceleratedRecovery"])) return true;
31060
+ const legacyStatus = features?.["AcceleratedRecoveryStatus"];
31061
+ return acceptReadSideKey && features?.["EnableAcceleratedRecovery"] === void 0 && typeof legacyStatus === "string" && ACCELERATED_RECOVERY_ON_STATUSES.has(legacyStatus);
31062
+ }
31063
+ const ACCELERATED_RECOVERY_ON_STATUSES = /* @__PURE__ */ new Set([
31064
+ "ENABLED",
31065
+ "ENABLING",
31066
+ "ENABLING_HOSTED_ZONE_LOCKED",
31067
+ "DISABLE_FAILED"
31068
+ ]);
30869
31069
  var HostedZoneNameNotFoundError = class HostedZoneNameNotFoundError extends ProvisioningError {
30870
31070
  constructor(message, resourceType, logicalId, physicalId, cause) {
30871
31071
  super(message, resourceType, logicalId, physicalId, cause);
@@ -31081,26 +31281,29 @@ var Route53Provider = class {
31081
31281
  }
31082
31282
  await this.applyHostedZoneTags(zoneId, properties, logicalId, void 0, mask);
31083
31283
  await this.applyQueryLoggingConfig(zoneId, properties, logicalId);
31084
- if (properties["HostedZoneFeatures"]?.["AcceleratedRecoveryStatus"] === "ENABLED") try {
31085
- await this.getClient().send(new UpdateHostedZoneFeaturesCommand({
31086
- HostedZoneId: zoneId,
31087
- EnableAcceleratedRecovery: true
31088
- }));
31089
- } catch (uhfError) {
31090
- this.logger.error(`UpdateHostedZoneFeatures failed for ${zoneId} after CreateHostedZone — rolling back the hosted zone to keep deploy retry idempotent`);
31284
+ if (declaresAcceleratedRecovery(properties)) {
31091
31285
  try {
31092
- await this.deleteQueryLoggingConfigForZone(zoneId, logicalId);
31093
- await this.getClient().send(new DeleteHostedZoneCommand({ Id: zoneId }));
31094
- zoneRolledBack = true;
31095
- callerReferenceToken.release();
31096
- } catch (deleteError) {
31097
- const head = `Best-effort rollback DeleteHostedZone for ${zoneId} also failed: `;
31098
- const m = maskerOrIdentity(mask);
31099
- this.logger.warn(m(`${head}${this.warnFailureText(head, deleteError, mask)} The operator may need to clean up the orphan zone.`));
31286
+ await this.getClient().send(new UpdateHostedZoneFeaturesCommand({
31287
+ HostedZoneId: zoneId,
31288
+ EnableAcceleratedRecovery: true
31289
+ }));
31290
+ } catch (uhfError) {
31291
+ this.logger.error(`UpdateHostedZoneFeatures failed for ${zoneId} after CreateHostedZone — rolling back the hosted zone to keep deploy retry idempotent`);
31292
+ try {
31293
+ await this.deleteQueryLoggingConfigForZone(zoneId, logicalId);
31294
+ await this.getClient().send(new DeleteHostedZoneCommand({ Id: zoneId }));
31295
+ zoneRolledBack = true;
31296
+ callerReferenceToken.release();
31297
+ } catch (deleteError) {
31298
+ const head = `Best-effort rollback DeleteHostedZone for ${zoneId} also failed: `;
31299
+ const m = maskerOrIdentity(mask);
31300
+ this.logger.warn(m(`${head}${this.warnFailureText(head, deleteError, mask)} The operator may need to clean up the orphan zone.`));
31301
+ }
31302
+ const cause = uhfError instanceof Error ? uhfError : void 0;
31303
+ markAuxiliaryFailure(uhfError, logicalId);
31304
+ throw this.wrapCaughtError(mask, uhfError, (text) => new ProvisioningError(`Failed to enable Accelerated Recovery on hosted zone ${logicalId} (${zoneId}): ${text}`, resourceType, logicalId, zoneId, cause));
31100
31305
  }
31101
- const cause = uhfError instanceof Error ? uhfError : void 0;
31102
- markAuxiliaryFailure(uhfError, logicalId);
31103
- throw this.wrapCaughtError(mask, uhfError, (text) => new ProvisioningError(`Failed to enable Accelerated Recovery on hosted zone ${logicalId} (${zoneId}): ${text}`, resourceType, logicalId, zoneId, cause));
31306
+ await this.waitForAcceleratedRecoveryFeatureSettled(zoneId, logicalId, resourceType, true, true);
31104
31307
  }
31105
31308
  const nameServers = response.DelegationSet?.NameServers ?? [];
31106
31309
  this.logger.debug(`Successfully created hosted zone ${logicalId}: ${zoneId}`);
@@ -31178,12 +31381,15 @@ var Route53Provider = class {
31178
31381
  await this.applyHostedZoneTags(physicalId, properties, logicalId, previousProperties, mask);
31179
31382
  await this.applyQueryLoggingConfig(physicalId, properties, logicalId, previousProperties);
31180
31383
  await this.syncVPCAssociations(physicalId, properties, logicalId);
31181
- const prevEnabled = previousProperties["HostedZoneFeatures"]?.["AcceleratedRecoveryStatus"] === "ENABLED";
31182
- const nextEnabled = properties["HostedZoneFeatures"]?.["AcceleratedRecoveryStatus"] === "ENABLED";
31183
- if (prevEnabled !== nextEnabled) await this.getClient().send(new UpdateHostedZoneFeaturesCommand({
31184
- HostedZoneId: physicalId,
31185
- EnableAcceleratedRecovery: nextEnabled
31186
- }));
31384
+ const prevEnabled = declaresAcceleratedRecovery(previousProperties, true);
31385
+ const nextEnabled = declaresAcceleratedRecovery(properties, context?.desiredFromAwsReadback === true);
31386
+ if (prevEnabled !== nextEnabled) {
31387
+ await this.getClient().send(new UpdateHostedZoneFeaturesCommand({
31388
+ HostedZoneId: physicalId,
31389
+ EnableAcceleratedRecovery: nextEnabled
31390
+ }));
31391
+ await this.waitForAcceleratedRecoveryFeatureSettled(physicalId, logicalId, resourceType, nextEnabled);
31392
+ }
31187
31393
  const nameServers = (await this.getClient().send(new GetHostedZoneCommand({ Id: physicalId }))).DelegationSet?.NameServers ?? [];
31188
31394
  this.logger.debug(`Successfully updated hosted zone ${logicalId}`);
31189
31395
  if (context?.desiredFromAwsReadback !== true && declaresNoVpcs(properties["VPCs"]) && Array.isArray(previousProperties["VPCs"]) && previousProperties["VPCs"].length > 0) this.logger.warn(context?.replayingState ? safeMsg`${logicalId} (AWS::Route53::HostedZone): VPCs is absent from the state being restored, so the rollback leaves the zone's VPC associations in place. ${VPCS_KEPT_ON_REMOVAL_NOTE}` : safeMsg`${logicalId} (AWS::Route53::HostedZone): VPCs was removed from the template, and the zone keeps its current VPC associations, as CloudFormation leaves them. ${VPCS_KEPT_ON_REMOVAL_NOTE}`);
@@ -31438,25 +31644,43 @@ var Route53Provider = class {
31438
31644
  throw this.wrapDeleteError(context?.maskSecrets, error, (text) => new ProvisioningError(`Failed to delete record set ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
31439
31645
  }
31440
31646
  }
31441
- async waitForAcceleratedRecoveryMutable(zoneId, logicalId, resourceType) {
31647
+ async waitForAcceleratedRecoveryFeatureSettled(zoneId, logicalId, resourceType, enabled, freshZone = false) {
31648
+ const verb = enabled ? "enable" : "disable";
31649
+ await this.waitForAcceleratedRecoveryMutable(zoneId, logicalId, resourceType, {
31650
+ blocked: `the hosted zone ${logicalId} can be deployed`,
31651
+ retry: `after the ${verb} of Accelerated Recovery (hosted zone ${logicalId}); re-run the deploy once the transition settles`,
31652
+ settledAt: enabled ? "ENABLED" : "DISABLED",
31653
+ freshZone
31654
+ });
31655
+ }
31656
+ async waitForAcceleratedRecoveryMutable(zoneId, logicalId, resourceType, purpose = {
31657
+ blocked: `the record set ${logicalId} can be deleted`,
31658
+ retry: `(record set ${logicalId}); re-run the destroy once the transition settles`
31659
+ }) {
31442
31660
  const client = this.getClient();
31443
31661
  const parsedInterval = Number.parseInt(process.env["CDKD_R53_ACCEL_RECOVERY_POLL_INTERVAL_MS"] ?? "15000", 10);
31444
31662
  const pollIntervalMs = Number.isFinite(parsedInterval) && parsedInterval > 0 ? parsedInterval : 15e3;
31445
31663
  const parsedTimeout = Number.parseInt(process.env["CDKD_R53_ACCEL_RECOVERY_POLL_TIMEOUT_MS"] ?? "600000", 10);
31446
31664
  const timeoutMs = Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? parsedTimeout : 6e5;
31447
31665
  const deadline = Date.now() + timeoutMs;
31448
- const TERMINAL_FAILED = /* @__PURE__ */ new Set(["ENABLE_FAILED", "DISABLE_FAILED"]);
31449
- const MUTABLE = /* @__PURE__ */ new Set(["ENABLED", "DISABLED"]);
31666
+ const TERMINAL_FAILED = new Set(purpose.settledAt === "ENABLED" ? ["ENABLE_FAILED"] : purpose.settledAt === "DISABLED" ? ["DISABLE_FAILED"] : ["ENABLE_FAILED", "DISABLE_FAILED"]);
31667
+ const MUTABLE = new Set(purpose.settledAt !== void 0 ? [purpose.settledAt] : ["ENABLED", "DISABLED"]);
31668
+ let sawTransition = purpose.settledAt === void 0 || purpose.freshZone === true;
31669
+ let lastStatus;
31450
31670
  while (Date.now() < deadline) {
31451
31671
  let status;
31452
31672
  try {
31453
31673
  status = (await client.send(new GetHostedZoneCommand({ Id: zoneId }))).HostedZone?.Features?.AcceleratedRecoveryStatus;
31454
31674
  } catch (err) {
31455
- if (err instanceof Error && err.name === "NoSuchHostedZone") return;
31675
+ if (err instanceof Error && err.name === "NoSuchHostedZone" && purpose.settledAt === void 0) return;
31456
31676
  throw err;
31457
31677
  }
31458
- if (status === void 0 || MUTABLE.has(status)) return;
31459
- if (TERMINAL_FAILED.has(status)) throw new ProvisioningError(`Cannot mutate hosted zone ${zoneId}: AcceleratedRecoveryStatus is '${status}' — operator must resolve before the record set ${logicalId} can be deleted`, resourceType, logicalId, zoneId);
31678
+ if (status === void 0) {
31679
+ if (purpose.settledAt !== "ENABLED") return;
31680
+ } else if (MUTABLE.has(status)) return;
31681
+ lastStatus = status;
31682
+ if (status?.includes("ING") === true) sawTransition = true;
31683
+ if (status !== void 0 && sawTransition && TERMINAL_FAILED.has(status)) throw new ProvisioningError(`Cannot mutate hosted zone ${zoneId}: AcceleratedRecoveryStatus is '${status}' — operator must resolve before ${purpose.blocked}`, resourceType, logicalId, zoneId);
31460
31684
  this.logger.debug(`Polling AcceleratedRecoveryStatus for ${zoneId}: ${status} (waiting for a mutable state, will re-poll in ~${pollIntervalMs}ms)`);
31461
31685
  const sliceEnd = Math.min(Date.now() + pollIntervalMs, deadline);
31462
31686
  while (Date.now() < sliceEnd) {
@@ -31465,7 +31689,7 @@ var Route53Provider = class {
31465
31689
  await new Promise((resolve) => setTimeout(resolve, tick));
31466
31690
  }
31467
31691
  }
31468
- throw new ProvisioningError(`Timed out after ${timeoutMs}ms waiting for AcceleratedRecoveryStatus to reach a mutable state on hosted zone ${zoneId} (record set ${logicalId}); re-run the destroy once the transition settles`, resourceType, logicalId, zoneId);
31692
+ throw new ProvisioningError(`Timed out after ${timeoutMs}ms waiting for AcceleratedRecoveryStatus to reach a mutable state on hosted zone ${zoneId} ${purpose.retry}${purpose.settledAt !== void 0 ? ` (last status: ${lastStatus ?? "none"})` : ""}`, resourceType, logicalId, zoneId);
31469
31693
  }
31470
31694
  buildResourceRecordSet(properties) {
31471
31695
  const name = properties["Name"];
@@ -31773,7 +31997,8 @@ var Route53Provider = class {
31773
31997
  const bare = resp.DelegationSet.Id.replace(/^\/delegationset\//, "");
31774
31998
  result["DelegationSetId"] = properties?.["DelegationSetId"] === `/delegationset/${bare}` ? `/delegationset/${bare}` : bare;
31775
31999
  }
31776
- if (resp.HostedZone.Features?.AcceleratedRecoveryStatus !== void 0) result["HostedZoneFeatures"] = { AcceleratedRecoveryStatus: resp.HostedZone.Features.AcceleratedRecoveryStatus };
32000
+ const acceleratedRecoveryStatus = resp.HostedZone.Features?.AcceleratedRecoveryStatus;
32001
+ if (acceleratedRecoveryStatus !== void 0) result["HostedZoneFeatures"] = { EnableAcceleratedRecovery: ACCELERATED_RECOVERY_ON_STATUSES.has(acceleratedRecoveryStatus) };
31777
32002
  if (resp.HostedZone.Config?.PrivateZone === true) result["VPCs"] = (resp.VPCs ?? []).map((v) => {
31778
32003
  const out = {};
31779
32004
  if (v.VPCId !== void 0) out["VPCId"] = v.VPCId;
@@ -33893,11 +34118,7 @@ var ElastiCacheProvider = class {
33893
34118
  if (templateLowered && desiredCount !== void 0 && desiredCount < liveNodes.length) {
33894
34119
  if (liveNodes.length !== previousCount) throw new ProvisioningError(safeMsg`Cannot update CacheCluster ${logicalId}: the template lowers NumCacheNodes from ${String(previousCount)} ` + safeMsg`to ${String(desiredCount)}, but the cluster has ${String(liveNodes.length)} nodes, so ` + "the removal would delete nodes the template change does not account for. Deploy NumCacheNodes set to the live count first, then lower it.", resourceType, logicalId, physicalId);
33895
34120
  const plan = nodesToRemove(liveNodes, desiredCount, zones);
33896
- if (plan === void 0) {
33897
- const liveZones = liveNodes.map((n) => n.zone);
33898
- const disjoint = zones !== void 0 && !zones.some((z) => liveZones.includes(z));
33899
- throw new ProvisioningError(safeMsg`Cannot update CacheCluster ${logicalId}: lowering NumCacheNodes to ${String(desiredCount)} ` + "with this PreferredAvailabilityZones list needs a node removed and a node added in a zone no live node occupies, in one update, which ModifyCacheCluster cannot do. " + (disjoint ? `CloudFormation replaces the cluster for a move to disjoint zones; cdkd does not yet (issue #5458). ` : "") + `Replace the cluster (for example by changing its logical ID), or list only zones the kept nodes occupy.`, resourceType, logicalId, physicalId);
33900
- }
34121
+ if (plan === void 0) throw new ProvisioningError(safeMsg`Cannot update CacheCluster ${logicalId}: lowering NumCacheNodes to ${String(desiredCount)} ` + "with this PreferredAvailabilityZones list needs a node removed and a node added in a zone no live node occupies, in one update, which ModifyCacheCluster cannot do. Replace the cluster (for example by changing its logical ID), or list only zones the kept nodes occupy.", resourceType, logicalId, physicalId);
33901
34122
  removeIds = plan;
33902
34123
  this.logger.info(safeMsg`CacheCluster ${logicalId}: NumCacheNodes ${String(previousProperties["NumCacheNodes"])} -> ${String(desiredCount)}, removing cache nodes ${removeIds.join(", ")}`);
33903
34124
  }
@@ -38237,15 +38458,20 @@ function desiredGlueTags(raw, resourceType, logicalId, physicalId) {
38237
38458
  const tags = refuseMalformedDesiredTags(tagMapAsList(raw), resourceType, logicalId, physicalId, "Tags", GLUE_TAGS_WHAT);
38238
38459
  return tags.length > 0 ? Object.fromEntries(tags.map((t) => [t.Key, t.Value])) : void 0;
38239
38460
  }
38240
- async function applyGlueTagDiff(client, resourceArn, recorded, desired, resourceType, logicalId, warn) {
38461
+ async function applyGlueTagDiff(client, resourceArn, recorded, desired, resourceType, logicalId, warn, unsettled = {
38462
+ forceUpsert: false,
38463
+ beforeWrite: () => void 0
38464
+ }) {
38241
38465
  const plan = planTagDiff(tagMapAsList(recorded), tagMapAsList(desired));
38242
38466
  const warning = tagPlanWarning(plan, resourceType, logicalId);
38243
38467
  if (warning !== void 0) warn(warning);
38244
- if (plan.set.size === 0 && plan.remove.length === 0) return;
38468
+ const toSet = unsettled.forceUpsert ? planTagDiff([], tagMapAsList(desired)).set : plan.set;
38469
+ if (toSet.size === 0 && plan.remove.length === 0) return;
38470
+ unsettled.beforeWrite();
38245
38471
  const arn = await resourceArn();
38246
- if (plan.set.size > 0) await client.send(new TagResourceCommand$19({
38472
+ if (toSet.size > 0) await client.send(new TagResourceCommand$19({
38247
38473
  ResourceArn: arn,
38248
- TagsToAdd: Object.fromEntries(plan.set)
38474
+ TagsToAdd: Object.fromEntries(toSet)
38249
38475
  }));
38250
38476
  if (plan.remove.length > 0) await client.send(new UntagResourceCommand$20({
38251
38477
  ResourceArn: arn,
@@ -38280,6 +38506,28 @@ const crawlerLeftInPlaceWarning = (logicalId, names, caller) => {
38280
38506
  const cfnKeeps = names.includes("LineageConfiguration") ? "" : `, as CloudFormation leaves ${one ? "it" : "them"}`;
38281
38507
  return caller === "rollback" ? safeMsg`${logicalId} (AWS::Glue::Crawler): ${subject} ${names.join(", ")} ${one ? "is" : "are"} absent from the state being restored; UpdateCrawler keeps a setting it is not sent, so the rollback leaves the value the failed deploy applied in place.` : safeMsg`${logicalId} (AWS::Glue::Crawler): ${subject} ${names.join(", ")} ${one ? "was" : "were"} removed from the template and ${one ? "keeps its" : "keep their"} current AWS value${cfnKeeps}; UpdateCrawler keeps a setting it is not sent. Declare the intended value explicitly to change it.`;
38282
38508
  };
38509
+ const CRAWLER_UPDATE_KEYS = [
38510
+ "Role",
38511
+ "Targets",
38512
+ "Classifiers",
38513
+ "Configuration",
38514
+ "CrawlerSecurityConfiguration",
38515
+ "DatabaseName",
38516
+ "Description",
38517
+ "LakeFormationConfiguration",
38518
+ "LineageConfiguration",
38519
+ "RecrawlPolicy",
38520
+ "Schedule",
38521
+ "SchemaChangePolicy",
38522
+ "TablePrefix"
38523
+ ];
38524
+ const TRIGGER_UPDATE_KEYS = [
38525
+ "Description",
38526
+ "Schedule",
38527
+ "Actions",
38528
+ "Predicate",
38529
+ "EventBatchingCondition"
38530
+ ];
38283
38531
  var GlueCrawlerProvider = class {
38284
38532
  client;
38285
38533
  createClient;
@@ -38362,6 +38610,7 @@ var GlueCrawlerProvider = class {
38362
38610
  const { value: v } = log;
38363
38611
  log.debug(`Updating Glue Crawler ${logicalId}: ${v(physicalId)}`);
38364
38612
  desiredGlueTags(properties["Tags"], resourceType, logicalId, physicalId);
38613
+ const markUnsettled = (key) => context?.markUnsettled?.(key);
38365
38614
  try {
38366
38615
  const updateInput = {
38367
38616
  Name: physicalId,
@@ -38369,6 +38618,7 @@ var GlueCrawlerProvider = class {
38369
38618
  ...properties["Targets"] !== void 0 && { Targets: toSdkCrawlerTargets(properties["Targets"]) },
38370
38619
  ...buildCrawlerCommonFields(properties)
38371
38620
  };
38621
+ for (const key of CRAWLER_UPDATE_KEYS) if (JSON.stringify(properties[key]) !== JSON.stringify(previousProperties[key])) markUnsettled(key);
38372
38622
  try {
38373
38623
  await this.getClient().send(new UpdateCrawlerCommand(updateInput));
38374
38624
  } catch (err) {
@@ -38378,7 +38628,10 @@ var GlueCrawlerProvider = class {
38378
38628
  await this.getClient().send(new UpdateCrawlerCommand(updateInput));
38379
38629
  } else throw err;
38380
38630
  }
38381
- await applyGlueTagDiff(this.getClient(), () => this.resourceArn(physicalId), previousProperties["Tags"], properties["Tags"], resourceType, logicalId, log.warn);
38631
+ await applyGlueTagDiff(this.getClient(), () => this.resourceArn(physicalId), previousProperties["Tags"], properties["Tags"], resourceType, logicalId, log.warn, {
38632
+ forceUpsert: context?.unsettledProperties?.has("Tags") === true,
38633
+ beforeWrite: () => markUnsettled("Tags")
38634
+ });
38382
38635
  if (!context?.desiredFromAwsReadback) {
38383
38636
  const removed = context?.removedProperties;
38384
38637
  const leftInPlace = [];
@@ -38854,6 +39107,7 @@ var GlueTriggerProvider = class {
38854
39107
  const { value: v } = log;
38855
39108
  log.debug(`Updating Glue Trigger ${logicalId}: ${v(physicalId)}`);
38856
39109
  desiredGlueTags(properties["Tags"], resourceType, logicalId, physicalId);
39110
+ const markUnsettled = (key) => context?.markUnsettled?.(key);
38857
39111
  try {
38858
39112
  let restart = false;
38859
39113
  try {
@@ -38873,6 +39127,7 @@ var GlueTriggerProvider = class {
38873
39127
  ...properties["EventBatchingCondition"] !== void 0 && { EventBatchingCondition: properties["EventBatchingCondition"] }
38874
39128
  };
38875
39129
  let updateError;
39130
+ for (const key of TRIGGER_UPDATE_KEYS) if (JSON.stringify(properties[key]) !== JSON.stringify(previousProperties[key])) markUnsettled(key);
38876
39131
  try {
38877
39132
  await this.getClient().send(new UpdateTriggerCommand({
38878
39133
  Name: physicalId,
@@ -38890,7 +39145,10 @@ var GlueTriggerProvider = class {
38890
39145
  if (restartFailure.redacted) log.debug(`Failed to re-activate Glue Trigger ${v(physicalId)} after a failed update: ${restartFailure.detail}`);
38891
39146
  }
38892
39147
  if (updateError !== void 0) throw updateError;
38893
- await applyGlueTagDiff(this.getClient(), () => this.resourceArn(physicalId), previousProperties["Tags"], properties["Tags"], resourceType, logicalId, log.warn);
39148
+ await applyGlueTagDiff(this.getClient(), () => this.resourceArn(physicalId), previousProperties["Tags"], properties["Tags"], resourceType, logicalId, log.warn, {
39149
+ forceUpsert: context?.unsettledProperties?.has("Tags") === true,
39150
+ beforeWrite: () => markUnsettled("Tags")
39151
+ });
38894
39152
  return {
38895
39153
  physicalId,
38896
39154
  wasReplaced: false
@@ -38900,6 +39158,14 @@ var GlueTriggerProvider = class {
38900
39158
  throw this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to update Glue Trigger ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
38901
39159
  }
38902
39160
  }
39161
+ async unsettledInTransition(physicalId, _logicalId, _resourceType, names) {
39162
+ try {
39163
+ const state = (await this.getClient().send(new GetTriggerCommand({ Name: physicalId }))).Trigger?.State;
39164
+ return state === "ACTIVATING" || state === "DEACTIVATING" || state === "CREATING" || state === "UPDATING" ? new Set([...names].filter((name) => name !== "Tags")) : /* @__PURE__ */ new Set();
39165
+ } catch {
39166
+ return names;
39167
+ }
39168
+ }
38903
39169
  async waitForTriggerDeactivated(physicalId) {
38904
39170
  for (let attempt = 0; attempt < TRIGGER_DEACTIVATE_MAX_ATTEMPTS; attempt++) {
38905
39171
  try {
@@ -40655,6 +40921,7 @@ var KinesisStreamProvider = class {
40655
40921
  const desiredRetention = readRetentionHours(properties["RetentionPeriodHours"], mask);
40656
40922
  if (desiredRetention.kind === "unusable" && context?.replayingState !== true) throw new ProvisioningError(desiredRetention.reason, resourceType, logicalId, physicalId);
40657
40923
  if (desiredRetention.kind === "unusable") warn(`${desiredRetention.reason}. Replaying a state record, so the retention period of ${physicalId} is left as it is rather than refusing the restore`);
40924
+ const markUnsettled = (key) => context?.markUnsettled?.(key);
40658
40925
  const previousRetention = readRetentionHours(previousProperties["RetentionPeriodHours"], mask);
40659
40926
  try {
40660
40927
  const streamModeDetails = properties["StreamModeDetails"];
@@ -40664,6 +40931,7 @@ var KinesisStreamProvider = class {
40664
40931
  if (modeChanged) {
40665
40932
  const streamArn = await this.resolveStreamArn(physicalId);
40666
40933
  this.logger.debug(`Switching stream mode for ${physicalId}: from ${oldStreamMode} to ${streamMode}`);
40934
+ markUnsettled("StreamModeDetails");
40667
40935
  await this.getClient().send(new UpdateStreamModeCommand({
40668
40936
  StreamARN: streamArn,
40669
40937
  StreamModeDetails: { StreamMode: streamMode }
@@ -40672,9 +40940,10 @@ var KinesisStreamProvider = class {
40672
40940
  }
40673
40941
  if (streamMode === "PROVISIONED") {
40674
40942
  const newShardCount = Number(properties["ShardCount"] ?? 1);
40675
- const oldShardCount = modeChanged ? await this.getOpenShardCount(physicalId) : Number(previousProperties["ShardCount"] ?? 1);
40943
+ const oldShardCount = modeChanged || context?.unsettledProperties?.has("StreamModeDetails") === true ? await this.getOpenShardCount(physicalId) : Number(previousProperties["ShardCount"] ?? 1);
40676
40944
  if (newShardCount !== oldShardCount) {
40677
40945
  this.logger.debug(`Updating shard count for ${physicalId}: from ${oldShardCount} to ${newShardCount}`);
40946
+ markUnsettled("ShardCount");
40678
40947
  await this.getClient().send(new UpdateShardCountCommand({
40679
40948
  StreamName: physicalId,
40680
40949
  TargetShardCount: newShardCount,
@@ -40687,6 +40956,7 @@ var KinesisStreamProvider = class {
40687
40956
  const effectiveOldRetention = previousRetention.kind === "usable" ? previousRetention.hours ?? 24 : 24;
40688
40957
  if (desiredRetention.kind !== "unusable" && effectiveNewRetention !== effectiveOldRetention) {
40689
40958
  this.logger.debug(`Updating retention period for ${physicalId}: from ${effectiveOldRetention} to ${effectiveNewRetention}`);
40959
+ markUnsettled("RetentionPeriodHours");
40690
40960
  if (effectiveNewRetention > effectiveOldRetention) await this.getClient().send(new IncreaseStreamRetentionPeriodCommand({
40691
40961
  StreamName: physicalId,
40692
40962
  RetentionPeriodHours: effectiveNewRetention
@@ -40697,7 +40967,10 @@ var KinesisStreamProvider = class {
40697
40967
  }));
40698
40968
  await this.waitForStreamActive(physicalId);
40699
40969
  }
40700
- await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
40970
+ await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], {
40971
+ forceUpsert: context?.unsettledProperties?.has("Tags") === true,
40972
+ beforeWrite: () => markUnsettled("Tags")
40973
+ });
40701
40974
  const newEncryption = properties["StreamEncryption"];
40702
40975
  const oldEncryption = previousProperties["StreamEncryption"];
40703
40976
  const oldIsKms = isKmsEncryption(oldEncryption);
@@ -40705,6 +40978,7 @@ var KinesisStreamProvider = class {
40705
40978
  const oldKeyId = oldIsKms ? oldEncryption["KeyId"] : void 0;
40706
40979
  const newKeyId = newIsKms ? newEncryption["KeyId"] : void 0;
40707
40980
  if (oldIsKms !== newIsKms || oldIsKms && newIsKms && oldKeyId !== newKeyId) {
40981
+ markUnsettled("StreamEncryption");
40708
40982
  if (oldIsKms) {
40709
40983
  await this.getClient().send(new StopStreamEncryptionCommand({
40710
40984
  StreamName: physicalId,
@@ -40728,13 +41002,14 @@ var KinesisStreamProvider = class {
40728
41002
  const recordedMaxRecordSize = comparableRecordSize(previousProperties["MaxRecordSizeInKiB"], mask);
40729
41003
  if (newMaxRecordSize !== void 0 && newMaxRecordSize !== (recordedMaxRecordSize ?? DEFAULT_MAX_RECORD_SIZE_KIB)) {
40730
41004
  this.logger.debug(`Updating max record size for ${physicalId}: from ${recordedMaxRecordSize ?? "no value"} to ${newMaxRecordSize}`);
41005
+ markUnsettled("MaxRecordSizeInKiB");
40731
41006
  await this.getClient().send(new UpdateMaxRecordSizeCommand({
40732
41007
  StreamARN: await this.resolveStreamArn(physicalId),
40733
41008
  MaxRecordSizeInKiB: newMaxRecordSize
40734
41009
  }));
40735
41010
  await this.waitForStreamActive(physicalId);
40736
41011
  }
40737
- await this.reconcileDistributionStrategy(physicalId, streamMode, properties, previousProperties, mask, warn);
41012
+ await this.reconcileDistributionStrategy(physicalId, streamMode, properties, previousProperties, mask, warn, markUnsettled);
40738
41013
  const desiredRead = readShardLevelMetrics(properties["DesiredShardLevelMetrics"], mask);
40739
41014
  let desiredMetrics;
40740
41015
  if (desiredRead.kind === "unusable") warn(`${desiredRead.reason}. Leaving the shard-level metrics on ${physicalId} unchanged rather than disabling the live ones; the same value is REFUSED on a template-path create`);
@@ -40743,7 +41018,9 @@ var KinesisStreamProvider = class {
40743
41018
  const desiredSet = desiredRead.kind === "usable" ? desiredRead.metrics : [];
40744
41019
  const previousSet = previousMetricNames(previousProperties["DesiredShardLevelMetrics"]);
40745
41020
  const toDisable = previousSet.filter((m) => !desiredSet.includes(m));
41021
+ if (context?.unsettledProperties?.has("DesiredShardLevelMetrics") === true) await this.warnUndeclaredLiveMetrics(physicalId, [...previousSet, ...desiredSet], warn, mask);
40746
41022
  const toEnable = desiredSet.filter((m) => !previousSet.includes(m));
41023
+ if (toDisable.length > 0 || toEnable.length > 0) markUnsettled("DesiredShardLevelMetrics");
40747
41024
  if (toDisable.length > 0) {
40748
41025
  this.logger.debug(`Disabling ${toDisable.length} shard-level metric(s) on ${physicalId}`);
40749
41026
  await this.getClient().send(new DisableEnhancedMonitoringCommand({
@@ -40855,7 +41132,7 @@ var KinesisStreamProvider = class {
40855
41132
  throw error;
40856
41133
  }
40857
41134
  }
40858
- async reconcileDistributionStrategy(physicalId, streamMode, properties, previousProperties, mask, warn) {
41135
+ async reconcileDistributionStrategy(physicalId, streamMode, properties, previousProperties, mask, warn, markUnsettled) {
40859
41136
  const desired = readDistributionStrategy(properties["RecordDistributionStrategy"], mask);
40860
41137
  if (desired.kind === "unusable") {
40861
41138
  warn(`${desired.reason}. Leaving the record distribution strategy on ${physicalId} unchanged; the same value is REFUSED on a template-path create`);
@@ -40873,6 +41150,7 @@ var KinesisStreamProvider = class {
40873
41150
  target = DEFAULT_RECORD_DISTRIBUTION_STRATEGY;
40874
41151
  }
40875
41152
  this.logger.debug(mask(safeMsg`Updating record distribution strategy for ${physicalId}: from ${recorded ?? "no value"} to ${target}`));
41153
+ markUnsettled("RecordDistributionStrategy");
40876
41154
  await this.getClient().send(new UpdateStreamRecordDistributionStrategyCommand({
40877
41155
  StreamARN: await this.resolveStreamArn(physicalId),
40878
41156
  RecordDistributionStrategy: target
@@ -40901,12 +41179,16 @@ var KinesisStreamProvider = class {
40901
41179
  if (resourceType !== "AWS::Kinesis::Stream") return [];
40902
41180
  return ["DesiredShardLevelMetrics"];
40903
41181
  }
40904
- async applyTagDiff(streamName, resourceType, logicalId, oldTagsRaw, newTagsRaw) {
41182
+ async applyTagDiff(streamName, resourceType, logicalId, oldTagsRaw, newTagsRaw, unsettled = {
41183
+ forceUpsert: false,
41184
+ beforeWrite: () => void 0
41185
+ }) {
40905
41186
  const plan = planTagDiff(oldTagsRaw, newTagsRaw);
40906
41187
  const tagWarning = tagPlanWarning(plan, resourceType, logicalId);
40907
41188
  if (tagWarning !== void 0) this.logger.warn(tagWarning);
40908
- const tagsToAdd = Object.fromEntries(plan.set);
41189
+ const tagsToAdd = Object.fromEntries(unsettled.forceUpsert ? planTagDiff(void 0, newTagsRaw).set : plan.set);
40909
41190
  const tagsToRemove = plan.remove;
41191
+ if (tagsToRemove.length > 0 || Object.keys(tagsToAdd).length > 0) unsettled.beforeWrite();
40910
41192
  if (tagsToRemove.length > 0) {
40911
41193
  await this.getClient().send(new RemoveTagsFromStreamCommand({
40912
41194
  StreamName: streamName,
@@ -40922,6 +41204,46 @@ var KinesisStreamProvider = class {
40922
41204
  this.logger.debug(`Added/updated ${Object.keys(tagsToAdd).length} tag(s) on Kinesis stream ${streamName}`);
40923
41205
  }
40924
41206
  }
41207
+ async warnUndeclaredLiveMetrics(physicalId, named, warn, mask) {
41208
+ let live;
41209
+ try {
41210
+ live = ((await this.getClient().send(new DescribeStreamSummaryCommand({ StreamName: physicalId }))).StreamDescriptionSummary?.EnhancedMonitoring ?? []).flatMap((entry) => entry.ShardLevelMetrics ?? []);
41211
+ } catch {
41212
+ return;
41213
+ }
41214
+ const expandedLive = expandShardLevelMetrics(live);
41215
+ const undeclared = (Array.isArray(expandedLive) ? expandedLive : live).filter((metric) => metric !== "ALL" && !named.includes(metric));
41216
+ if (undeclared.length === 0) return;
41217
+ const secretDerived = mask(physicalId) !== physicalId;
41218
+ warn(`Kinesis stream ${physicalId} has shard-level metrics enabled that neither cdkd's record nor the template declares (${undeclared.join(", ")}), so cdkd left them enabled while converging the unsettled DesiredShardLevelMetrics (CloudFormation never disables a metric it did not record). Another tool may have enabled them, or an earlier failed cdkd update may have; cdkd cannot tell which. If they should be off, disable them ` + (secretDerived ? `with DisableEnhancedMonitoring for those metrics.` : `with: aws kinesis disable-enhanced-monitoring --stream-name ${physicalId} --shard-level-metrics ${undeclared.join(" ")} (in the stream's region)`));
41219
+ }
41220
+ async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties) {
41221
+ const live = await this.readCurrentState(physicalId, logicalId, resourceType);
41222
+ if (typeof live !== "object" || live === null) return live;
41223
+ const out = { ...live };
41224
+ if (names.has("DesiredShardLevelMetrics") && Array.isArray(out["DesiredShardLevelMetrics"])) {
41225
+ const named = new Set([recordedProperties, desiredProperties].flatMap((bag) => {
41226
+ const expanded = expandShardLevelMetrics(bag?.["DesiredShardLevelMetrics"]);
41227
+ return isUsableMetricsList(expanded) ? expanded : [];
41228
+ }));
41229
+ const liveMetrics = expandShardLevelMetrics(out["DesiredShardLevelMetrics"]);
41230
+ out["DesiredShardLevelMetrics"] = (Array.isArray(liveMetrics) ? liveMetrics : []).filter((metric) => typeof metric === "string" && named.has(metric));
41231
+ }
41232
+ if (!names.has("ShardCount")) return out;
41233
+ return {
41234
+ ...out,
41235
+ ShardCount: await this.getOpenShardCount(physicalId)
41236
+ };
41237
+ }
41238
+ async unsettledInTransition(physicalId, _logicalId, _resourceType, names) {
41239
+ try {
41240
+ const status = (await this.getClient().send(new DescribeStreamSummaryCommand({ StreamName: physicalId }))).StreamDescriptionSummary?.StreamStatus;
41241
+ if (status !== "UPDATING" && status !== "CREATING") return /* @__PURE__ */ new Set();
41242
+ return new Set([...names].filter((name) => name !== "Tags"));
41243
+ } catch {
41244
+ return names;
41245
+ }
41246
+ }
40925
41247
  async readCurrentState(physicalId, _logicalId, resourceType, _properties) {
40926
41248
  if (resourceType !== "AWS::Kinesis::Stream") return void 0;
40927
41249
  let stream;
@@ -41687,6 +42009,13 @@ function pipeIdentityToken(name, arn, creationTime) {
41687
42009
  return `${arn}@${Math.floor(ms / 1e3)}`;
41688
42010
  }
41689
42011
  const SETTLED_STATES = /* @__PURE__ */ new Set(["RUNNING", "STOPPED"]);
42012
+ const MOVING_STATES = /* @__PURE__ */ new Set([
42013
+ "CREATING",
42014
+ "UPDATING",
42015
+ "STARTING",
42016
+ "STOPPING",
42017
+ "DELETING"
42018
+ ]);
41690
42019
  const PIPE_POLL_INTERVAL_MS = 5e3;
41691
42020
  const PIPE_SETTLE_MAX_WAIT_MS = 9e5;
41692
42021
  const PIPE_DELETE_MAX_WAIT_MS = 6e5;
@@ -41980,13 +42309,19 @@ var PipesPipeProvider = class {
41980
42309
  };
41981
42310
  const sourceParameters = toUpdateSourceParameters(desired["SourceParameters"], previousProperties["SourceParameters"]);
41982
42311
  if (sourceParameters !== void 0) input.SourceParameters = sourceParameters;
42312
+ for (const key of this.changedPipeFields(desired, previousProperties)) context?.markUnsettled?.(key);
41983
42313
  const accepted = await this.getClient().send(new UpdatePipeCommand(input));
41984
42314
  settled = await this.waitForSettled(physicalId, logicalId, resourceType, "update", mask, accepted.LastModifiedTime);
41985
42315
  }
41986
- const plan = planTagDiff(tagMapAsList(previousProperties["Tags"]), tagMapAsList(desiredTags));
42316
+ const recordedPlan = planTagDiff(tagMapAsList(previousProperties["Tags"]), tagMapAsList(desiredTags));
42317
+ const plan = context?.unsettledProperties?.has("Tags") === true ? {
42318
+ ...recordedPlan,
42319
+ set: planTagDiff([], tagMapAsList(desiredTags)).set
42320
+ } : recordedPlan;
41987
42321
  const warning = tagPlanWarning(plan, resourceType, logicalId);
41988
42322
  if (warning) this.logger.warn(warning);
41989
42323
  if (plan.set.size > 0 || plan.remove.length > 0) {
42324
+ context?.markUnsettled?.("Tags");
41990
42325
  settled ??= await this.describe(physicalId);
41991
42326
  const arn = settled.Arn;
41992
42327
  if (!arn) throw new Error("DescribePipe returned no Arn, which tagging needs");
@@ -42146,10 +42481,30 @@ var PipesPipeProvider = class {
42146
42481
  return value;
42147
42482
  }
42148
42483
  pipeFieldsChanged(desired, previous) {
42484
+ return this.changedPipeFields(desired, previous).length > 0;
42485
+ }
42486
+ changedPipeFields(desired, previous) {
42149
42487
  const keys = /* @__PURE__ */ new Set([...Object.keys(desired), ...Object.keys(previous)]);
42150
42488
  keys.delete("Tags");
42151
- for (const key of keys) if (JSON.stringify(desired[key]) !== JSON.stringify(previous[key])) return true;
42152
- return false;
42489
+ return [...keys].filter((key) => JSON.stringify(desired[key]) !== JSON.stringify(previous[key]));
42490
+ }
42491
+ async unsettledInTransition(physicalId, _logicalId, _resourceType, names) {
42492
+ try {
42493
+ const state = (await this.describe(physicalId)).CurrentState;
42494
+ if (state === void 0 || !MOVING_STATES.has(state)) return /* @__PURE__ */ new Set();
42495
+ return new Set([...names].filter((name) => name !== "Tags"));
42496
+ } catch {
42497
+ return names;
42498
+ }
42499
+ }
42500
+ async readUnsettled(physicalId, logicalId, resourceType, names) {
42501
+ const live = await this.readCurrentState(physicalId, logicalId, resourceType);
42502
+ if (typeof live !== "object" || live === null) return live;
42503
+ const state = (await this.describe(physicalId)).CurrentState;
42504
+ if (state === void 0 || !state.endsWith("_FAILED")) return live;
42505
+ const out = { ...live };
42506
+ for (const name of names) delete out[name];
42507
+ return out;
42153
42508
  }
42154
42509
  async readStateForDelete(name) {
42155
42510
  try {
@@ -42312,6 +42667,7 @@ var EFSProvider = class {
42312
42667
  providerRegion = ambientRegion();
42313
42668
  logger = getLogger().child("EFSProvider");
42314
42669
  unconfirmedCreationTokens = /* @__PURE__ */ new Map();
42670
+ removalDefaults = /* @__PURE__ */ new Map([["AWS::EFS::FileSystem", /* @__PURE__ */ new Map([["BackupPolicy", { Status: "DISABLED" }], ["FileSystemProtection", { ReplicationOverwriteProtection: "ENABLED" }]])]]);
42315
42671
  handledProperties = /* @__PURE__ */ new Map([
42316
42672
  ["AWS::EFS::FileSystem", /* @__PURE__ */ new Set([
42317
42673
  "FileSystemTags",
@@ -42383,13 +42739,56 @@ var EFSProvider = class {
42383
42739
  }
42384
42740
  update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
42385
42741
  const log = createMaskedLogSinks(this.logger, context?.maskSecrets);
42742
+ properties = withRemovalDefaults(this.removalDefaults, resourceType, properties, previousProperties, context);
42386
42743
  switch (resourceType) {
42387
42744
  case "AWS::EFS::FileSystem": return this.updateFileSystem(logicalId, physicalId, resourceType, properties, previousProperties, log);
42388
42745
  case "AWS::EFS::MountTarget": return this.updateMountTarget(logicalId, physicalId, resourceType, properties, log);
42389
- case "AWS::EFS::AccessPoint": return Promise.reject(new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS EFS AccessPoint has no in-place update API — there is no UpdateAccessPoint command; every property change requires DeleteAccessPoint + CreateAccessPoint. Re-deploy with cdkd deploy --replace, or destroy + redeploy the stack."));
42746
+ case "AWS::EFS::AccessPoint": return this.updateAccessPoint(logicalId, physicalId, resourceType, properties, previousProperties, log);
42390
42747
  default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
42391
42748
  }
42392
42749
  }
42750
+ async applyTagDiff(resourceId, resourceType, logicalId, recorded, desired, log) {
42751
+ const plan = planTagDiff(recorded, desired);
42752
+ const warning = tagPlanWarning(plan, resourceType, logicalId);
42753
+ if (warning !== void 0) log.warn(warning);
42754
+ if (plan.remove.length > 0) await this.retryOnTransientControlPlane(() => this.getClient().send(new UntagResourceCommand$24({
42755
+ ResourceId: resourceId,
42756
+ TagKeys: plan.remove
42757
+ })), `UntagResource ${resourceId}`, log);
42758
+ if (plan.set.size > 0) await this.retryOnTransientControlPlane(() => this.getClient().send(new TagResourceCommand$23({
42759
+ ResourceId: resourceId,
42760
+ Tags: [...plan.set].map(([Key, Value]) => ({
42761
+ Key,
42762
+ Value
42763
+ }))
42764
+ })), `TagResource ${resourceId}`, log);
42765
+ }
42766
+ async updateAccessPoint(logicalId, physicalId, resourceType, properties, previousProperties, log) {
42767
+ const isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
42768
+ const sameExceptSecretLeaves = (desired, recorded) => {
42769
+ if (desired !== void 0 && typeof recorded === "string" && holdsSecretDerivedEntry(recorded)) return true;
42770
+ if (Array.isArray(desired) && Array.isArray(recorded)) return desired.length === recorded.length && desired.every((d, i) => sameExceptSecretLeaves(d, recorded[i]));
42771
+ if (isPlainObject(desired) && isPlainObject(recorded)) return [.../* @__PURE__ */ new Set([...Object.keys(desired), ...Object.keys(recorded)])].every((k) => sameExceptSecretLeaves(desired[k], recorded[k]));
42772
+ return isDeepStrictEqual(desired, recorded);
42773
+ };
42774
+ const keys = /* @__PURE__ */ new Set([...Object.keys(properties), ...Object.keys(previousProperties)]);
42775
+ for (const key of keys) {
42776
+ if (key === "AccessPointTags") continue;
42777
+ if (!sameExceptSecretLeaves(properties[key], previousProperties[key])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS EFS AccessPoint ${key} changed or was removed, and it is immutable on AWS — there is no UpdateAccessPoint command, and only AccessPointTags can change in place; any other property change requires DeleteAccessPoint + CreateAccessPoint. Re-deploy with cdkd deploy --replace, or destroy + redeploy the stack.`);
42778
+ }
42779
+ refuseMalformedDesiredTags(properties["AccessPointTags"], resourceType, logicalId, physicalId, "AccessPointTags");
42780
+ try {
42781
+ await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["AccessPointTags"], properties["AccessPointTags"], log);
42782
+ return {
42783
+ physicalId,
42784
+ wasReplaced: false
42785
+ };
42786
+ } catch (error) {
42787
+ if (error instanceof ProvisioningError) throw error;
42788
+ const cause = error instanceof Error ? error : void 0;
42789
+ throw this.wrapMaskedError(log, error, (text) => new ProvisioningError(`Failed to update EFS AccessPoint ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
42790
+ }
42791
+ }
42393
42792
  async updateFileSystem(logicalId, physicalId, resourceType, properties, previousProperties, log) {
42394
42793
  for (const key of [
42395
42794
  "Encrypted",
@@ -42413,7 +42812,9 @@ var EFSProvider = class {
42413
42812
  const backupChanged = changed("BackupPolicy");
42414
42813
  const policyChanged = changed("FileSystemPolicy") || changed("BypassPolicyLockoutSafetyCheck");
42415
42814
  const protectionChanged = changed("FileSystemProtection");
42416
- if (!throughputModeChanged && !provisionedChanged && !lifecycleChanged && !backupChanged && !policyChanged && !protectionChanged) {
42815
+ const tagsChanged = changed("FileSystemTags");
42816
+ if (tagsChanged) refuseMalformedDesiredTags(properties["FileSystemTags"], resourceType, logicalId, physicalId, "FileSystemTags");
42817
+ if (!throughputModeChanged && !provisionedChanged && !lifecycleChanged && !backupChanged && !policyChanged && !protectionChanged && !tagsChanged) {
42417
42818
  log.debug(`No mutable diff for EFS FileSystem ${logicalId}, skipping update`);
42418
42819
  return {
42419
42820
  physicalId,
@@ -42432,8 +42833,12 @@ var EFSProvider = class {
42432
42833
  }
42433
42834
  if (lifecycleChanged) await this.applyLifecyclePolicies(physicalId, properties["LifecyclePolicies"], log, previousProperties["LifecyclePolicies"]);
42434
42835
  if (backupChanged) await this.applyBackupPolicy(physicalId, properties["BackupPolicy"], log);
42435
- if (policyChanged) await this.applyFileSystemPolicy(physicalId, properties["FileSystemPolicy"], properties["BypassPolicyLockoutSafetyCheck"], log);
42836
+ if (policyChanged) {
42837
+ if (properties["FileSystemPolicy"] === void 0 && previousProperties["FileSystemPolicy"] !== void 0) await this.deleteFileSystemPolicy(physicalId, log);
42838
+ else await this.applyFileSystemPolicy(physicalId, properties["FileSystemPolicy"], properties["BypassPolicyLockoutSafetyCheck"], log);
42839
+ }
42436
42840
  if (protectionChanged) await this.applyFileSystemProtection(physicalId, properties["FileSystemProtection"], log);
42841
+ if (tagsChanged) await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["FileSystemTags"], properties["FileSystemTags"], log);
42437
42842
  log.debug(`Successfully updated EFS FileSystem ${logicalId}`);
42438
42843
  return {
42439
42844
  physicalId,
@@ -42641,6 +43046,10 @@ var EFSProvider = class {
42641
43046
  })), `set FileSystemPolicy on ${fileSystemId}`, log);
42642
43047
  log.debug(`Set FileSystemPolicy on EFS FileSystem ${fileSystemId}`);
42643
43048
  }
43049
+ async deleteFileSystemPolicy(fileSystemId, log) {
43050
+ await this.retryOnTransientControlPlane(() => this.getClient().send(new DeleteFileSystemPolicyCommand({ FileSystemId: fileSystemId })), `delete FileSystemPolicy on ${fileSystemId}`, log);
43051
+ log.debug(`Deleted FileSystemPolicy on EFS FileSystem ${fileSystemId}`);
43052
+ }
42644
43053
  async applyFileSystemProtection(fileSystemId, spec, log) {
42645
43054
  if (spec === void 0 || spec === null) return;
42646
43055
  const protection = spec.ReplicationOverwriteProtection;
@@ -43149,6 +43558,23 @@ const routeTableDelta = (next, prev) => {
43149
43558
  ...remove.length > 0 && { remove }
43150
43559
  };
43151
43560
  };
43561
+ const STALE_FAILED_READS = 3;
43562
+ const ALIAS_NON_BLOCKING_ACTIONS = /* @__PURE__ */ new Set(["STORAGE_OPTIMIZATION", "IOPS_OPTIMIZATION"]);
43563
+ const runningAliasBlockingActions = (fs) => (fs.AdministrativeActions ?? []).filter((a) => (a.Status === "PENDING" || a.Status === "IN_PROGRESS") && !ALIAS_NON_BLOCKING_ACTIONS.has(a.AdministrativeActionType ?? "")).map((a) => a.AdministrativeActionType ?? "unknown");
43564
+ const isAdministrativeActionInProgress = (error) => error instanceof Error && error.name === "BadRequest" && /in progress/i.test(describeAwsFailure(error).detail);
43565
+ const isTransientFsxError = (error) => {
43566
+ const name = error instanceof Error ? error.name : "";
43567
+ return name === "ThrottlingException" || name === "ServiceLimitExceeded" || name === "InternalServerError" || name === "TimeoutError" || /rate exceeded|too many requests|timed? ?out|ECONNRESET|EPIPE|socket hang up/i.test(describeAwsFailure(error).detail);
43568
+ };
43569
+ const aliasDelta = (next, prev) => {
43570
+ const names = (value) => new Set((Array.isArray(value) ? value : []).filter((v) => typeof v === "string").map((v) => v.toLowerCase()));
43571
+ const nextNames = names(next);
43572
+ const prevNames = names(prev);
43573
+ return {
43574
+ add: [...nextNames].filter((n) => !prevNames.has(n)),
43575
+ remove: [...prevNames].filter((n) => !nextNames.has(n))
43576
+ };
43577
+ };
43152
43578
  const TOP_LEVEL_IMMUTABLE_PROPS = [
43153
43579
  "FileSystemType",
43154
43580
  "SubnetIds",
@@ -43551,11 +43977,16 @@ var FSxFileSystemProvider = class {
43551
43977
  if (JSON.stringify(next ?? null) !== JSON.stringify(prev ?? null)) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS FSx FileSystem ${key} is immutable on AWS — UpdateFileSystem does not accept ${key}; the property is fixed at creation. Re-deploy with cdkd deploy --replace --force-stateful-recreation (the type is in cdkd's stateful-recreate guard set, so a bare --replace is refused a second time with STATEFUL_REPLACE_BLOCKED), or destroy + redeploy the stack.`);
43552
43978
  }
43553
43979
  const variantConfigKey = this.detectVariantConfigKey(properties, previousProperties);
43554
- const { diff: variantDiff, hasMutableDiff: variantHasMutableDiff, leftInPlace } = variantConfigKey ? this.computeVariantConfigDiff(resourceType, logicalId, variantConfigKey, properties[variantConfigKey] ?? {}, previousProperties[variantConfigKey] ?? {}) : {
43980
+ const { diff: variantDiff, hasMutableDiff: variantHasMutableDiff, leftInPlace, aliases } = variantConfigKey ? this.computeVariantConfigDiff(resourceType, logicalId, variantConfigKey, properties[variantConfigKey] ?? {}, previousProperties[variantConfigKey] ?? {}) : {
43555
43981
  diff: {},
43556
43982
  hasMutableDiff: false,
43557
- leftInPlace: []
43983
+ leftInPlace: [],
43984
+ aliases: {
43985
+ add: [],
43986
+ remove: []
43987
+ }
43558
43988
  };
43989
+ const aliasesChanged = aliases.add.length > 0 || aliases.remove.length > 0;
43559
43990
  const leftInPlaceNames = [...TOP_LEVEL_LEFT_IN_PLACE_PROPS.filter((key) => properties[key] === void 0 && previousProperties[key] !== void 0), ...leftInPlace.map((key) => `${variantConfigKey}.${key}`)];
43560
43991
  const warnLeftInPlace = () => {
43561
43992
  if (leftInPlaceNames.length === 0 || context?.desiredFromAwsReadback) return;
@@ -43576,7 +44007,7 @@ var FSxFileSystemProvider = class {
43576
44007
  const typeVersionChanged = sendsChange("FileSystemTypeVersion");
43577
44008
  const networkTypeChanged = sendsChange("NetworkType");
43578
44009
  const tagsChanged = changed("Tags");
43579
- if (!variantHasMutableDiff && !storageCapacityChanged && !storageTypeChanged && !typeVersionChanged && !networkTypeChanged && !tagsChanged) {
44010
+ if (!variantHasMutableDiff && !storageCapacityChanged && !storageTypeChanged && !typeVersionChanged && !networkTypeChanged && !aliasesChanged && !tagsChanged) {
43580
44011
  this.logger.debug(`No mutable diff for FSx FileSystem ${logicalId}, skipping update`);
43581
44012
  warnLeftInPlace();
43582
44013
  return {
@@ -43586,6 +44017,7 @@ var FSxFileSystemProvider = class {
43586
44017
  }
43587
44018
  this.logger.debug(`Updating FSx FileSystem ${logicalId}: ${physicalId}`);
43588
44019
  try {
44020
+ const deadline = Date.now() + this.maxWaitMs;
43589
44021
  const needsUpdateCall = variantHasMutableDiff || storageCapacityChanged || storageTypeChanged || typeVersionChanged || networkTypeChanged;
43590
44022
  let updatedFs;
43591
44023
  if (needsUpdateCall) {
@@ -43600,8 +44032,9 @@ var FSxFileSystemProvider = class {
43600
44032
  }))).FileSystem?.AdministrativeActions ?? []).filter((a) => a.AdministrativeActionType === "FILE_SYSTEM_UPDATE" && (a.Status === "PENDING" || a.Status === "IN_PROGRESS"));
43601
44033
  const requestTimes = respPendingActions.map((a) => a.RequestTime?.getTime()).filter((t) => t !== void 0);
43602
44034
  const actionThresholdMs = requestTimes.length > 0 ? Math.min(...requestTimes) : callTimeMs - 6e4;
43603
- updatedFs = await this.waitForUpdateActionComplete(physicalId, logicalId, resourceType, actionThresholdMs, respPendingActions.length > 0, context?.maskSecrets);
44035
+ updatedFs = await this.waitForUpdateActionComplete(physicalId, logicalId, resourceType, actionThresholdMs, respPendingActions.length > 0, deadline, context?.maskSecrets);
43604
44036
  }
44037
+ if (aliasesChanged) await this.applyAliasDelta(physicalId, logicalId, resourceType, aliases, deadline);
43605
44038
  if (tagsChanged) await this.applyTagDiff(physicalId, resourceType, logicalId, properties["Tags"], previousProperties["Tags"]);
43606
44039
  if (!updatedFs) try {
43607
44040
  updatedFs = (await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [physicalId] }))).FileSystems?.[0];
@@ -43629,12 +44062,20 @@ var FSxFileSystemProvider = class {
43629
44062
  const keys = /* @__PURE__ */ new Set([...Object.keys(next), ...Object.keys(prev)]);
43630
44063
  const diff = {};
43631
44064
  const leftInPlace = [];
44065
+ let aliases = {
44066
+ add: [],
44067
+ remove: []
44068
+ };
43632
44069
  let hasMutableDiff = false;
43633
44070
  for (const key of keys) {
43634
44071
  const nextVal = next[key];
43635
44072
  const prevVal = prev[key];
43636
44073
  if (JSON.stringify(nextVal) === JSON.stringify(prevVal)) continue;
43637
44074
  if (configKey === "OpenZFSConfiguration" && key === "Options") continue;
44075
+ if (configKey === "WindowsConfiguration" && key === "Aliases") {
44076
+ aliases = aliasDelta(nextVal, prevVal);
44077
+ continue;
44078
+ }
43638
44079
  if (!mutable.has(key)) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS FSx FileSystem ${configKey}.${key} is immutable on AWS — UpdateFileSystem cannot change it after creation. Re-deploy with cdkd deploy --replace --force-stateful-recreation (the type is in cdkd's stateful-recreate guard set, so a bare --replace is refused a second time with STATEFUL_REPLACE_BLOCKED), or destroy + redeploy the stack.`);
43639
44080
  if (nextVal === void 0 && key !== "RouteTableIds") {
43640
44081
  leftInPlace.push(key);
@@ -43650,7 +44091,8 @@ var FSxFileSystemProvider = class {
43650
44091
  return {
43651
44092
  diff,
43652
44093
  hasMutableDiff,
43653
- leftInPlace
44094
+ leftInPlace,
44095
+ aliases
43654
44096
  };
43655
44097
  }
43656
44098
  unmappedMutableSubprop(ctx, key) {
@@ -43782,6 +44224,104 @@ var FSxFileSystemProvider = class {
43782
44224
  }
43783
44225
  return true;
43784
44226
  }
44227
+ async applyAliasDelta(physicalId, logicalId, resourceType, delta, deadline) {
44228
+ await this.waitForNoAdministrativeAction(physicalId, logicalId, resourceType, deadline);
44229
+ const live = new Map((await this.describeAliases(physicalId)).map((a) => [a.Name?.toLowerCase(), a.Lifecycle]));
44230
+ const retryAdd = delta.add.filter((n) => {
44231
+ const lifecycle = live.get(n);
44232
+ return lifecycle === "CREATE_FAILED" || lifecycle === "DELETING" || lifecycle === "DELETE_FAILED";
44233
+ });
44234
+ const awaitGone = [...delta.remove, ...retryAdd];
44235
+ const sendRemove = awaitGone.filter((n) => live.has(n) && live.get(n) !== "DELETING");
44236
+ const sendAdd = delta.add.filter((n) => live.get(n) !== "AVAILABLE" && live.get(n) !== "CREATING");
44237
+ if (sendRemove.length > 0) await this.sendAliasCall(physicalId, logicalId, resourceType, () => new DisassociateFileSystemAliasesCommand({
44238
+ FileSystemId: physicalId,
44239
+ Aliases: sendRemove
44240
+ }), deadline);
44241
+ if (awaitGone.length > 0) await this.waitForAliases(physicalId, logicalId, resourceType, awaitGone, "gone", deadline);
44242
+ if (sendAdd.length > 0) await this.sendAliasCall(physicalId, logicalId, resourceType, () => new AssociateFileSystemAliasesCommand({
44243
+ FileSystemId: physicalId,
44244
+ Aliases: sendAdd
44245
+ }), deadline);
44246
+ if (delta.add.length > 0) await this.waitForAliases(physicalId, logicalId, resourceType, delta.add, "AVAILABLE", deadline);
44247
+ }
44248
+ async describeAliases(physicalId) {
44249
+ const aliases = [];
44250
+ let nextToken;
44251
+ do {
44252
+ const resp = await this.getClient().send(new DescribeFileSystemAliasesCommand({
44253
+ FileSystemId: physicalId,
44254
+ NextToken: nextToken
44255
+ }));
44256
+ aliases.push(...resp.Aliases ?? []);
44257
+ nextToken = resp.NextToken;
44258
+ } while (nextToken);
44259
+ return aliases;
44260
+ }
44261
+ async waitForNoAdministrativeAction(physicalId, logicalId, resourceType, deadline) {
44262
+ const transientState = { count: 0 };
44263
+ let running = [];
44264
+ while (Date.now() < deadline) {
44265
+ const fs = await this.describeForPoll(physicalId, transientState);
44266
+ if (fs) {
44267
+ running = runningAliasBlockingActions(fs);
44268
+ if (running.length === 0) return;
44269
+ this.logger.debug(safeMsg`FSx FileSystem ${physicalId}: waiting for ${running.join(", ")} to finish before changing DNS aliases...`);
44270
+ }
44271
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
44272
+ }
44273
+ throw new ProvisioningError(safeMsg`Timed out waiting for FSx FileSystem ${physicalId} administrative actions (${running.join(", ") || "unknown"}) to finish before changing its DNS aliases (${Math.round(this.maxWaitMs / 6e4)} min). Re-deploy once they complete.`, resourceType, logicalId, physicalId);
44274
+ }
44275
+ async sendAliasCall(physicalId, logicalId, resourceType, command, deadline) {
44276
+ for (;;) try {
44277
+ const call = command();
44278
+ if (call instanceof AssociateFileSystemAliasesCommand) await this.getClient().send(call);
44279
+ else await this.getClient().send(call);
44280
+ return;
44281
+ } catch (error) {
44282
+ if (!isAdministrativeActionInProgress(error)) throw error;
44283
+ if (Date.now() >= deadline) {
44284
+ let running = [];
44285
+ try {
44286
+ running = ((await this.describeForPoll(physicalId, { count: 0 }))?.AdministrativeActions ?? []).filter((a) => a.Status === "PENDING" || a.Status === "IN_PROGRESS").map((a) => a.AdministrativeActionType ?? "unknown");
44287
+ } catch {}
44288
+ throw new ProvisioningError(safeMsg`Timed out changing FSx FileSystem ${physicalId} DNS aliases: FSx kept refusing the call while an administrative action (${running.join(", ") || "unknown"}) is in progress (${Math.round(this.maxWaitMs / 6e4)} min). Re-deploy once it completes.`, resourceType, logicalId, physicalId, error);
44289
+ }
44290
+ this.logger.debug(safeMsg`FSx FileSystem ${physicalId}: DNS alias call refused while an administrative action is in progress, re-sending...`);
44291
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
44292
+ }
44293
+ }
44294
+ async waitForAliases(physicalId, logicalId, resourceType, names, target, deadline) {
44295
+ const failedLifecycle = target === "AVAILABLE" ? "CREATE_FAILED" : "DELETE_FAILED";
44296
+ const transitionLifecycle = target === "AVAILABLE" ? "CREATING" : "DELETING";
44297
+ const seenTransition = /* @__PURE__ */ new Set();
44298
+ const failedReads = /* @__PURE__ */ new Map();
44299
+ let transient = 0;
44300
+ while (Date.now() < deadline) {
44301
+ let aliases;
44302
+ try {
44303
+ aliases = await this.describeAliases(physicalId);
44304
+ transient = 0;
44305
+ } catch (error) {
44306
+ if (!isTransientFsxError(error) || transient >= 5) throw error;
44307
+ transient += 1;
44308
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
44309
+ continue;
44310
+ }
44311
+ const byName = new Map(aliases.map((a) => [a.Name?.toLowerCase(), a.Lifecycle]));
44312
+ for (const n of names) {
44313
+ const lifecycle = byName.get(n);
44314
+ if (lifecycle === transitionLifecycle) seenTransition.add(n);
44315
+ failedReads.set(n, lifecycle === failedLifecycle ? (failedReads.get(n) ?? 0) + 1 : 0);
44316
+ }
44317
+ const failed = names.filter((n) => byName.get(n) === failedLifecycle && (seenTransition.has(n) || (failedReads.get(n) ?? 0) >= STALE_FAILED_READS));
44318
+ if (failed.length > 0) throw new ProvisioningError(safeMsg`FSx FileSystem ${physicalId}: DNS alias ${failed.join(", ")} entered ${failedLifecycle}. Check the alias name and the file system's Active Directory, then re-deploy.`, resourceType, logicalId, physicalId);
44319
+ if (names.every((n) => target === "AVAILABLE" ? byName.get(n) === "AVAILABLE" : !byName.has(n))) return;
44320
+ this.logger.debug(safeMsg`FSx FileSystem ${physicalId}: waiting for DNS aliases ${names.join(", ")} to be ${target}...`);
44321
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
44322
+ }
44323
+ throw new ProvisioningError(safeMsg`Timed out waiting for FSx FileSystem ${physicalId} DNS aliases ${names.join(", ")} to be ${target} (${Math.round(this.maxWaitMs / 6e4)} min)`, resourceType, logicalId, physicalId);
44324
+ }
43785
44325
  async applyTagDiff(physicalId, resourceType, logicalId, nextTags, prevTags) {
43786
44326
  const plan = planTagDiff(prevTags, nextTags);
43787
44327
  const arn = (await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [physicalId] }))).FileSystems?.[0]?.ResourceARN;
@@ -43793,11 +44333,11 @@ var FSxFileSystemProvider = class {
43793
44333
  Value
43794
44334
  }));
43795
44335
  const toRemove = plan.remove;
43796
- if (toSet.length > 0) await this.getClient().send(new TagResourceCommand$23({
44336
+ if (toSet.length > 0) await this.getClient().send(new TagResourceCommand$24({
43797
44337
  ResourceARN: arn,
43798
44338
  Tags: toSet
43799
44339
  }));
43800
- if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$24({
44340
+ if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$25({
43801
44341
  ResourceARN: arn,
43802
44342
  TagKeys: toRemove
43803
44343
  }));
@@ -43863,9 +44403,8 @@ var FSxFileSystemProvider = class {
43863
44403
  transientState.count = 0;
43864
44404
  return response.FileSystems?.[0];
43865
44405
  } catch (error) {
43866
- const name = error instanceof Error ? error.name : "";
43867
44406
  const msg = describeAwsFailure(error).detail;
43868
- if ((name === "ThrottlingException" || name === "ServiceLimitExceeded" || name === "InternalServerError" || name === "TimeoutError" || /rate exceeded|too many requests|timed? ?out|ECONNRESET|EPIPE|socket hang up/i.test(msg)) && transientState.count < maxConsecutiveTransient) {
44407
+ if (isTransientFsxError(error) && transientState.count < maxConsecutiveTransient) {
43869
44408
  transientState.count += 1;
43870
44409
  this.logger.debug(`Transient DescribeFileSystems error while polling ${fileSystemId} (${transientState.count}/${maxConsecutiveTransient}): ${msg} — retrying`);
43871
44410
  return;
@@ -43886,11 +44425,10 @@ var FSxFileSystemProvider = class {
43886
44425
  }
43887
44426
  throw new ProvisioningError(`Timed out waiting for FSx FileSystem ${fileSystemId} to become AVAILABLE (${Math.round(this.maxWaitMs / 6e4)} min)`, resourceType, logicalId, fileSystemId);
43888
44427
  }
43889
- async waitForUpdateActionComplete(fileSystemId, logicalId, resourceType, actionThresholdMs, requireActionObservation, mask) {
43890
- const startTime = Date.now();
44428
+ async waitForUpdateActionComplete(fileSystemId, logicalId, resourceType, actionThresholdMs, requireActionObservation, deadline, mask) {
43891
44429
  const transientState = { count: 0 };
43892
44430
  let seenTrackedAction = false;
43893
- while (Date.now() - startTime < this.maxWaitMs) {
44431
+ while (Date.now() < deadline) {
43894
44432
  const fs = await this.describeForPoll(fileSystemId, transientState);
43895
44433
  if (fs) {
43896
44434
  const updateActions = (fs.AdministrativeActions ?? []).filter((a) => a.AdministrativeActionType === "FILE_SYSTEM_UPDATE" && (a.RequestTime === void 0 || a.RequestTime.getTime() >= actionThresholdMs));
@@ -44079,13 +44617,26 @@ var FSxFileSystemProvider = class {
44079
44617
  canonicalizeDriftProperties(resourceType, properties) {
44080
44618
  if (resourceType !== "AWS::FSx::FileSystem") return properties;
44081
44619
  const lustre = properties["LustreConfiguration"];
44082
- if (typeof lustre !== "object" || lustre === null || Array.isArray(lustre)) return properties;
44620
+ if (typeof lustre !== "object" || lustre === null || Array.isArray(lustre)) return this.canonicalizeWindowsAliases(properties);
44083
44621
  const log = lustre["LogConfiguration"];
44084
- if (typeof log !== "object" || log === null || Array.isArray(log) || JSON.stringify(log) !== JSON.stringify({ Level: "DISABLED" })) return properties;
44622
+ if (typeof log !== "object" || log === null || Array.isArray(log) || JSON.stringify(log) !== JSON.stringify({ Level: "DISABLED" })) return this.canonicalizeWindowsAliases(properties);
44085
44623
  const { LogConfiguration: _disabled, ...rest } = lustre;
44086
- return {
44624
+ return this.canonicalizeWindowsAliases({
44087
44625
  ...properties,
44088
44626
  LustreConfiguration: rest
44627
+ });
44628
+ }
44629
+ canonicalizeWindowsAliases(properties) {
44630
+ const windows = properties["WindowsConfiguration"];
44631
+ if (typeof windows !== "object" || windows === null || Array.isArray(windows)) return properties;
44632
+ const aliases = windows["Aliases"];
44633
+ if (!Array.isArray(aliases) || aliases.every((a) => typeof a !== "string" || a === a.toLowerCase())) return properties;
44634
+ return {
44635
+ ...properties,
44636
+ WindowsConfiguration: {
44637
+ ...windows,
44638
+ Aliases: aliases.map((a) => typeof a === "string" ? a.toLowerCase() : a)
44639
+ }
44089
44640
  };
44090
44641
  }
44091
44642
  getDriftUnknownPaths(resourceType) {
@@ -44226,6 +44777,12 @@ const toNumber$2 = (v) => {
44226
44777
  const jsonEqual$2 = (a, b) => JSON.stringify(a) === JSON.stringify(b);
44227
44778
  const addInstanceGroupsLatch = new AmbiguousCreateLatch("emr:AddInstanceGroups");
44228
44779
  const groupsCreatedByThisProcess = new RecentIdSet();
44780
+ const MOVING_GROUP_STATES = /* @__PURE__ */ new Set([
44781
+ "PROVISIONING",
44782
+ "BOOTSTRAPPING",
44783
+ "RESIZING",
44784
+ "RECONFIGURING"
44785
+ ]);
44229
44786
  var EMRInstanceGroupConfigProvider = class {
44230
44787
  disableCcApiFallback = true;
44231
44788
  client;
@@ -44426,6 +44983,7 @@ var EMRInstanceGroupConfigProvider = class {
44426
44983
  this.logger.debug(`Updating EMR instance group ${logicalId}: ${physicalId}`);
44427
44984
  try {
44428
44985
  if (instanceCountChanged) {
44986
+ context?.markUnsettled?.("InstanceCount");
44429
44987
  await this.getClient().send(new ModifyInstanceGroupsCommand({
44430
44988
  ...jobFlowId && { ClusterId: jobFlowId },
44431
44989
  InstanceGroups: [{
@@ -44438,6 +44996,7 @@ var EMRInstanceGroupConfigProvider = class {
44438
44996
  if (autoScalingChanged) {
44439
44997
  if (!jobFlowId) throw new ProvisioningError(`EMR InstanceGroupConfig ${logicalId} AutoScalingPolicy update needs JobFlowId (the cluster id), which is absent`, resourceType, logicalId, physicalId);
44440
44998
  const policy = properties["AutoScalingPolicy"];
44999
+ context?.markUnsettled?.("AutoScalingPolicy");
44441
45000
  if (policy) await this.getClient().send(new PutAutoScalingPolicyCommand({
44442
45001
  ClusterId: jobFlowId,
44443
45002
  InstanceGroupId: physicalId,
@@ -44521,6 +45080,27 @@ var EMRInstanceGroupConfigProvider = class {
44521
45080
  }
44522
45081
  throw new ProvisioningError(`Timed out waiting for EMR instance group ${groupId} to reach RUNNING with ${expectedCount} instance(s) (${Math.round(this.maxWaitMs / 6e4)} min)`, resourceType, logicalId, groupId);
44523
45082
  }
45083
+ async readUnsettled(physicalId, logicalId, resourceType, _names, recordedProperties) {
45084
+ const jobFlowId = recordedProperties?.["JobFlowId"];
45085
+ if (typeof jobFlowId !== "string" || jobFlowId === "") throw new ProvisioningError(`EMR InstanceGroupConfig ${logicalId} has no JobFlowId (the cluster id) recorded, so cdkd cannot read the group to converge what an earlier failed update left unsettled`, resourceType, logicalId, physicalId);
45086
+ const group = await this.findGroupForPoll(jobFlowId, physicalId, { count: 0 }, 0);
45087
+ if (group === void 0) return void 0;
45088
+ return {
45089
+ ...group.RunningInstanceCount !== void 0 && { InstanceCount: group.RunningInstanceCount },
45090
+ ...group.AutoScalingPolicy !== void 0 && { AutoScalingPolicy: group.AutoScalingPolicy }
45091
+ };
45092
+ }
45093
+ async unsettledInTransition(physicalId, _logicalId, _resourceType, names, recordedProperties) {
45094
+ if (!names.has("InstanceCount")) return /* @__PURE__ */ new Set();
45095
+ const jobFlowId = recordedProperties?.["JobFlowId"];
45096
+ if (typeof jobFlowId !== "string" || jobFlowId === "") return /* @__PURE__ */ new Set();
45097
+ try {
45098
+ const state = (await this.findGroupForPoll(jobFlowId, physicalId, { count: 0 }, 0))?.Status?.State;
45099
+ return state !== void 0 && MOVING_GROUP_STATES.has(state) ? /* @__PURE__ */ new Set(["InstanceCount"]) : /* @__PURE__ */ new Set();
45100
+ } catch {
45101
+ return /* @__PURE__ */ new Set(["InstanceCount"]);
45102
+ }
45103
+ }
44524
45104
  async findGroupForPoll(clusterId, groupId, transientState, maxConsecutiveTransient = 5) {
44525
45105
  try {
44526
45106
  let marker;
@@ -46182,7 +46762,7 @@ var FirehoseProvider = class {
46182
46762
  async applyUpdate(logicalId, physicalId, resourceType, properties, previousProperties, context) {
46183
46763
  this.logger.debug(`Updating Firehose delivery stream ${logicalId}: ${physicalId}`);
46184
46764
  const desiredEncryption = readEncryptionInput(properties[ENCRYPTION_KEY], context?.desiredFromAwsReadback === true);
46185
- const encryptionChanged = !sameEncryptionInput(properties[ENCRYPTION_KEY], desiredEncryption, previousProperties[ENCRYPTION_KEY]);
46765
+ const encryptionChanged = !sameEncryptionInput(properties[ENCRYPTION_KEY], desiredEncryption, previousProperties[ENCRYPTION_KEY]) || context?.unsettledProperties?.has(ENCRYPTION_KEY) === true && desiredEncryption.kind !== "unusable";
46186
46766
  let encryptionSkipped = false;
46187
46767
  if (encryptionChanged && desiredEncryption.kind === "unusable") {
46188
46768
  const message = `${ENCRYPTION_KEY} of Firehose delivery stream ${logicalId} is not an object with a string KeyType (and a string KeyARN, if any)`;
@@ -46251,7 +46831,7 @@ var FirehoseProvider = class {
46251
46831
  const prevDest = previousProperties[activeDest] ?? {};
46252
46832
  if (JSON.stringify(nextDest) !== JSON.stringify(prevDest)) await this.applySnowflakeDestinationUpdate(logicalId, physicalId, nextDest);
46253
46833
  }
46254
- if (encryptionChanged && desiredEncryption.kind !== "unusable") await this.applyEncryptionUpdate(logicalId, physicalId, resourceType, desiredEncryption, maskerOrIdentity(context?.maskSecrets));
46834
+ if (encryptionChanged && desiredEncryption.kind !== "unusable") await this.applyEncryptionUpdate(logicalId, physicalId, resourceType, desiredEncryption, maskerOrIdentity(context?.maskSecrets), context?.markUnsettled);
46255
46835
  const description = await this.getClient().send(new DescribeDeliveryStreamCommand({ DeliveryStreamName: physicalId }));
46256
46836
  this.warnUnappliedS3BackupMode(logicalId, properties, unappliedS3BackupModeDestination(properties, previousProperties, destKey, context?.changedProperties), description.DeliveryStreamDescription);
46257
46837
  const desc = description.DeliveryStreamDescription;
@@ -46332,7 +46912,7 @@ var FirehoseProvider = class {
46332
46912
  }))
46333
46913
  }));
46334
46914
  }
46335
- async applyEncryptionUpdate(logicalId, physicalId, resourceType, desired, mask) {
46915
+ async applyEncryptionUpdate(logicalId, physicalId, resourceType, desired, mask, markUnsettled) {
46336
46916
  const settled = await this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46337
46917
  what: "settle",
46338
46918
  done: (enc) => enc?.Status !== "ENABLING" && enc?.Status !== "DISABLING"
@@ -46340,8 +46920,9 @@ var FirehoseProvider = class {
46340
46920
  if (desired.kind === "absent") {
46341
46921
  if (settled?.Status !== "ENABLED" && settled?.Status !== "DISABLING_FAILED") return;
46342
46922
  this.refuseToStartTransition(logicalId, physicalId, resourceType, "disable");
46923
+ markUnsettled?.(ENCRYPTION_KEY);
46343
46924
  await this.getClient().send(new StopDeliveryStreamEncryptionCommand({ DeliveryStreamName: physicalId }));
46344
- await this.warnIfUnfinished(logicalId, "StopDeliveryStreamEncryption", () => this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46925
+ await this.warnIfUnfinished(logicalId, "StopDeliveryStreamEncryption", markUnsettled, () => this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46345
46926
  what: "disable",
46346
46927
  done: (enc) => enc === void 0 || enc.Status === "DISABLED",
46347
46928
  inProgress: "DISABLING",
@@ -46352,6 +46933,7 @@ var FirehoseProvider = class {
46352
46933
  }
46353
46934
  if (encryptionMatches(settled, desired)) return;
46354
46935
  this.refuseToStartTransition(logicalId, physicalId, resourceType, "enable");
46936
+ markUnsettled?.(ENCRYPTION_KEY);
46355
46937
  await this.getClient().send(new StartDeliveryStreamEncryptionCommand({
46356
46938
  DeliveryStreamName: physicalId,
46357
46939
  DeliveryStreamEncryptionConfigurationInput: {
@@ -46359,7 +46941,7 @@ var FirehoseProvider = class {
46359
46941
  ...desired.keyArn !== void 0 && { KeyARN: desired.keyArn }
46360
46942
  }
46361
46943
  }));
46362
- await this.warnIfUnfinished(logicalId, "StartDeliveryStreamEncryption", () => this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46944
+ await this.warnIfUnfinished(logicalId, "StartDeliveryStreamEncryption", markUnsettled, () => this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46363
46945
  what: "enable",
46364
46946
  done: (enc) => encryptionMatches(enc, desired),
46365
46947
  inProgress: "ENABLING",
@@ -46367,12 +46949,12 @@ var FirehoseProvider = class {
46367
46949
  staleFailure: settled?.Status === "ENABLING_FAILED"
46368
46950
  }));
46369
46951
  }
46370
- async warnIfUnfinished(logicalId, call, wait) {
46952
+ async warnIfUnfinished(logicalId, call, markUnsettled, wait) {
46371
46953
  try {
46372
46954
  return await wait();
46373
46955
  } catch (error) {
46374
46956
  const outcome = typeof error === "object" && error !== null && terminalEncryptionFailures.has(error) ? "AWS reported the change failed, so the stream may no longer match" : "the stream may still finish the change, so it may no longer match";
46375
- this.logger.warn(safeMsg`Firehose delivery stream ${logicalId}: ${call} was sent but the encryption change did not finish; ${outcome} the previous setting cdkd keeps recorded. Run 'cdkd drift' to compare, then 'cdkd drift --revert' to apply the recorded setting or 'cdkd drift --accept' to record the stream's.`);
46957
+ this.logger.warn(safeMsg`Firehose delivery stream ${logicalId}: ${call} was sent but the encryption change did not finish; ${outcome} the previous setting cdkd keeps recorded. `.concat(markUnsettled === void 0 ? "Run 'cdkd drift' to compare, then 'cdkd drift --revert' to apply the recorded setting or 'cdkd drift --accept' to record the stream's." : `cdkd records ${ENCRYPTION_KEY} as unsettled, so the next 'cdkd deploy' reads the stream and applies the template's setting. To keep the stream as it ends up instead, run 'cdkd drift --accept' once the stream no longer reads ENABLING or DISABLING (an accept during the transition keeps the key unsettled).`));
46376
46958
  throw error;
46377
46959
  }
46378
46960
  }
@@ -46790,6 +47372,15 @@ var FirehoseProvider = class {
46790
47372
  if (config["CloudWatchLoggingOptions"] !== void 0) result.CloudWatchLoggingOptions = config["CloudWatchLoggingOptions"];
46791
47373
  return result;
46792
47374
  }
47375
+ async unsettledInTransition(physicalId, _logicalId, _resourceType, names) {
47376
+ if (!names.has(ENCRYPTION_KEY)) return /* @__PURE__ */ new Set();
47377
+ try {
47378
+ const status = (await this.getClient().send(new DescribeDeliveryStreamCommand({ DeliveryStreamName: physicalId }))).DeliveryStreamDescription?.DeliveryStreamEncryptionConfiguration?.Status;
47379
+ return status === "ENABLING" || status === "DISABLING" ? /* @__PURE__ */ new Set([ENCRYPTION_KEY]) : /* @__PURE__ */ new Set();
47380
+ } catch {
47381
+ return /* @__PURE__ */ new Set([ENCRYPTION_KEY]);
47382
+ }
47383
+ }
46793
47384
  async readCurrentState(physicalId, _logicalId, _resourceType) {
46794
47385
  let desc;
46795
47386
  try {
@@ -48105,11 +48696,11 @@ var CodeCommitRepositoryProvider = class {
48105
48696
  const repoArn = metadata?.Arn;
48106
48697
  if (repoArn) {
48107
48698
  const removedKeys = Object.keys(oldTagMap).filter((k) => !Object.hasOwn(newTagMap, k));
48108
- if (removedKeys.length > 0) await this.getClient().send(new UntagResourceCommand$25({
48699
+ if (removedKeys.length > 0) await this.getClient().send(new UntagResourceCommand$26({
48109
48700
  resourceArn: repoArn,
48110
48701
  tagKeys: removedKeys
48111
48702
  }));
48112
- if (Object.keys(newTagMap).length > 0) await this.getClient().send(new TagResourceCommand$24({
48703
+ if (Object.keys(newTagMap).length > 0) await this.getClient().send(new TagResourceCommand$25({
48113
48704
  resourceArn: repoArn,
48114
48705
  tags: newTagMap
48115
48706
  }));
@@ -48552,7 +49143,7 @@ var DLMLifecyclePolicyProvider = class {
48552
49143
  if (tagsChanged && arn) {
48553
49144
  const removedKeys = plan.remove;
48554
49145
  if (removedKeys.length > 0) {
48555
- await this.getClient().send(new UntagResourceCommand$26({
49146
+ await this.getClient().send(new UntagResourceCommand$27({
48556
49147
  ResourceArn: arn,
48557
49148
  TagKeys: removedKeys
48558
49149
  }));
@@ -48560,7 +49151,7 @@ var DLMLifecyclePolicyProvider = class {
48560
49151
  }
48561
49152
  const tagsToAdd = Object.fromEntries(plan.set);
48562
49153
  if (Object.keys(tagsToAdd).length > 0) {
48563
- await this.getClient().send(new TagResourceCommand$25({
49154
+ await this.getClient().send(new TagResourceCommand$26({
48564
49155
  ResourceArn: arn,
48565
49156
  Tags: tagsToAdd
48566
49157
  }));
@@ -48724,11 +49315,11 @@ var S3VectorsProvider = class {
48724
49315
  }
48725
49316
  if (!resourceArn) throw new ProvisioningError(`Could not resolve ARN for S3 VectorBucket ${logicalId} (${mask(physicalId)}); cannot apply tag update.`, resourceType, logicalId, physicalId);
48726
49317
  try {
48727
- if (Object.keys(toSet).length > 0) await this.getClient().send(new TagResourceCommand$26({
49318
+ if (Object.keys(toSet).length > 0) await this.getClient().send(new TagResourceCommand$27({
48728
49319
  resourceArn,
48729
49320
  tags: toSet
48730
49321
  }));
48731
- if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$27({
49322
+ if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$28({
48732
49323
  resourceArn,
48733
49324
  tagKeys: toRemove
48734
49325
  }));
@@ -49011,12 +49602,12 @@ var S3DirectoryBucketProvider = class {
49011
49602
  if (removedKeys.length > 0 || tagsToApply.length > 0) {
49012
49603
  const accountId = await this.getAccountId();
49013
49604
  const resourceArn = await this.buildBucketArn(physicalId, accountId);
49014
- if (removedKeys.length > 0) await this.getS3ControlClient().send(new UntagResourceCommand$28({
49605
+ if (removedKeys.length > 0) await this.getS3ControlClient().send(new UntagResourceCommand$29({
49015
49606
  AccountId: accountId,
49016
49607
  ResourceArn: resourceArn,
49017
49608
  TagKeys: removedKeys
49018
49609
  }));
49019
- if (tagsToApply.length > 0) await this.getS3ControlClient().send(new TagResourceCommand$27({
49610
+ if (tagsToApply.length > 0) await this.getS3ControlClient().send(new TagResourceCommand$28({
49020
49611
  AccountId: accountId,
49021
49612
  ResourceArn: resourceArn,
49022
49613
  Tags: tagsToApply
@@ -49864,7 +50455,7 @@ var S3TablesProvider = class {
49864
50455
  const resourceArn = await this.lookupTableArn(tableBucketARN, namespace, name);
49865
50456
  if (!resourceArn) throw new ProvisioningError(safeMsg`applyTableTagsDiff: GetTable returned no tableARN for ${physicalId} — table is gone ` + `or state is out-of-sync. Refusing to silently drop the tag update. If the table was deleted out-of-band, drop just this resource's record with the command below, filling in the construct path the CDK app gave this resource — its aws:cdk:path Metadata entry in the synthesized template.\nClean up with: cdkd orphan ${commandHole("constructPath")}`, resourceType, logicalId, physicalId);
49866
50457
  if (removedKeys.length > 0) try {
49867
- await this.getClient().send(new UntagResourceCommand$29({
50458
+ await this.getClient().send(new UntagResourceCommand$30({
49868
50459
  resourceArn,
49869
50460
  tagKeys: removedKeys
49870
50461
  }));
@@ -49873,7 +50464,7 @@ var S3TablesProvider = class {
49873
50464
  throw this.wrapCaughtError(mask, err, (text) => new ProvisioningError(`applyTableTagsDiff: UntagResource failed for ${resourceArn} (keys: ${removedKeys.join(", ")}): ${sentence(text)} State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause));
49874
50465
  }
49875
50466
  if (Object.keys(upserts).length > 0) try {
49876
- await this.getClient().send(new TagResourceCommand$28({
50467
+ await this.getClient().send(new TagResourceCommand$29({
49877
50468
  resourceArn,
49878
50469
  tags: upserts
49879
50470
  }));
@@ -49891,7 +50482,7 @@ var S3TablesProvider = class {
49891
50482
  if (removedKeys.length === 0 && Object.keys(upserts).length === 0) return;
49892
50483
  const resourceArn = physicalId;
49893
50484
  if (removedKeys.length > 0) try {
49894
- await this.getClient().send(new UntagResourceCommand$29({
50485
+ await this.getClient().send(new UntagResourceCommand$30({
49895
50486
  resourceArn,
49896
50487
  tagKeys: removedKeys
49897
50488
  }));
@@ -49900,7 +50491,7 @@ var S3TablesProvider = class {
49900
50491
  throw this.wrapCaughtError(mask, err, (text) => new ProvisioningError(`applyTableBucketTagsDiff: UntagResource failed for ${resourceArn} (keys: ${removedKeys.join(", ")}): ${sentence(text)} State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause));
49901
50492
  }
49902
50493
  if (Object.keys(upserts).length > 0) try {
49903
- await this.getClient().send(new TagResourceCommand$28({
50494
+ await this.getClient().send(new TagResourceCommand$29({
49904
50495
  resourceArn,
49905
50496
  tags: upserts
49906
50497
  }));
@@ -51020,4 +51611,4 @@ var ACMCertificateProvider = class {
51020
51611
 
51021
51612
  //#endregion
51022
51613
  export { ACMCertificateProvider, ASGProvider, AgentCoreBrowserProvider, AgentCoreCodeInterpreterProvider, AgentCoreEvaluatorProvider, AgentCoreRuntimeProvider, ApiGatewayProvider, ApiGatewayV2Provider, AppSyncProvider, BudgetsBudgetProvider, CloudFrontDistributionProvider, CloudFrontOACProvider, CloudFrontOAIProvider, CloudTrailProvider, CloudWatchAlarmProvider, CloudWatchAnomalyDetectorProvider, CodeBuildProvider, CodeCommitRepositoryProvider, CognitoUserPoolProvider, DLMLifecyclePolicyProvider, DocDBProvider, DocDBSubnetGroupProvider, DynamoDBGlobalTableProvider, DynamoDBTableProvider, EC2Provider, ECRProvider, ECSProvider, EFSProvider, ELBv2Provider, EMRClusterProvider, EMRInstanceFleetConfigProvider, EMRInstanceGroupConfigProvider, ElastiCacheProvider, EventBridgeBusProvider, EventBridgeRuleProvider, FSxFileSystemProvider, FirehoseProvider, GlueConnectionProvider, GlueCrawlerProvider, GlueJobProvider, GlueProvider, GlueSecurityConfigurationProvider, GlueTriggerProvider, GlueWorkflowProvider, IAMAccessKeyProvider, IAMInstanceProfileProvider, IAMManagedPolicyProvider, IAMPolicyProvider, IAMRoleProvider, IAMUserGroupProvider, KMSProvider, KinesisStreamConsumerProvider, KinesisStreamProvider, LambdaEventInvokeConfigProvider, LambdaEventSourceMappingProvider, LambdaFunctionProvider, LambdaLayerVersionProvider, LambdaMicrovmImageProvider, LambdaNetworkConnectorProvider, LambdaPermissionProvider, LambdaUrlProvider, LambdaWebFunctionEndpointProvider, LambdaWebFunctionRevisionProvider, LogsLogGroupProvider, NeptuneProvider, NestedStackProvider, PipesPipeProvider, RDSDBProxyEndpointProvider, RDSDBProxyProvider, RDSDBProxyTargetGroupProvider, RDSProvider, Route53Provider, S3BucketPolicyProvider, S3BucketProvider, S3DirectoryBucketProvider, S3TablesProvider, S3VectorsProvider, SNSSubscriptionProvider, SNSTopicPolicyProvider, SNSTopicProvider, SQSQueuePolicyProvider, SQSQueueProvider, SSMParameterProvider, SchedulerScheduleProvider, SecretsManagerSecretProvider, ServiceDiscoveryProvider, StepFunctionsProvider, WAFv2WebACLProvider, WaitConditionHandleProvider };
51023
- //# sourceMappingURL=provider-classes-BxfIHcea.js.map
51614
+ //# sourceMappingURL=provider-classes-DYke4HKr.js.map