@go-to-k/cdkd 0.308.1 → 0.310.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-I1bFHVsO.js} +2 -2
  2. package/dist/{asg-provider-B7pAjRIc.js.map → asg-provider-I1bFHVsO.js.map} +1 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/{deploy-engine-CDjAtIrn.js → deploy-engine-DZO2SOQJ.js} +1238 -248
  5. package/dist/deploy-engine-DZO2SOQJ.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-BWw7I-SZ.js} +2 -2
  8. package/dist/{iam-role-provider-DbtvFel_.js.map → iam-role-provider-BWw7I-SZ.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-8kjFmR1l.js} +2 -2
  13. package/dist/{neptune-provider-Y3Ii8oYI.js.map → neptune-provider-8kjFmR1l.js.map} +1 -1
  14. package/dist/{program-Ymf7svYk.js → program-CS420Kx9.js} +101 -257
  15. package/dist/program-CS420Kx9.js.map +1 -0
  16. package/dist/{provider-classes-BxfIHcea.js → provider-classes-KsrvwO_r.js} +942 -166
  17. package/dist/provider-classes-KsrvwO_r.js.map +1 -0
  18. package/dist/{rds-provider-CZhBLQgJ.js → rds-provider-BqwTQeS-.js} +27 -13
  19. package/dist/rds-provider-BqwTQeS-.js.map +1 -0
  20. package/dist/{version-BWqrjGBS.js → version-QOtLxcEo.js} +2 -2
  21. package/dist/{version-BWqrjGBS.js.map → version-QOtLxcEo.js.map} +1 -1
  22. package/package.json +9 -10
  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-DZO2SOQJ.js";
6
+ import { n as collectInlinePolicyNamesManagedBySiblings, r as IamCreateClientCache, t as IAMRoleProvider } from "./iam-role-provider-BWw7I-SZ.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-CS420Kx9.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-BqwTQeS-.js";
10
+ import { NeptuneProvider } from "./neptune-provider-8kjFmR1l.js";
11
+ import { ASGProvider } from "./asg-provider-I1bFHVsO.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
- 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";
60
+ import { AddTagsCommand as AddTagsCommand$2, CloudTrailClient, CreateTrailCommand, DeleteTrailCommand, GetEventConfigurationCommand, GetEventSelectorsCommand, GetInsightSelectorsCommand, GetTrailCommand, GetTrailStatusCommand, ListTagsCommand as ListTagsCommand$2, PutEventConfigurationCommand, 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;
@@ -45941,6 +46521,9 @@ function liveEncryptionAsCfn(live) {
45941
46521
  }
45942
46522
  const ENCRYPTION_POLL_INTERVAL_MS = 5e3;
45943
46523
  const ENCRYPTION_POLL_MAX_ATTEMPTS = 120;
46524
+ const ACTIVE_POLL_INTERVAL_MS = 5e3;
46525
+ const ACTIVE_POLL_MAX_ATTEMPTS = 360;
46526
+ const ACTIVE_DEADLINE_MARGIN_MS = 2e3;
45944
46527
  const terminalEncryptionFailures = /* @__PURE__ */ new WeakSet();
45945
46528
  function isReadableTagList(value) {
45946
46529
  if (value === void 0 || value === null) return true;
@@ -46158,7 +46741,7 @@ var FirehoseProvider = class {
46158
46741
  createdStreamName = physicalId;
46159
46742
  const arn = response.DeliveryStreamARN;
46160
46743
  this.logger.debug(`Successfully created Firehose delivery stream ${logicalId}: ${physicalId}`);
46161
- await this.waitForActive(physicalId, logicalId);
46744
+ await this.waitForActive(physicalId, logicalId, resourceType, maskerOrIdentity(context?.maskSecrets));
46162
46745
  return {
46163
46746
  physicalId,
46164
46747
  attributes: { Arn: arn }
@@ -46182,7 +46765,7 @@ var FirehoseProvider = class {
46182
46765
  async applyUpdate(logicalId, physicalId, resourceType, properties, previousProperties, context) {
46183
46766
  this.logger.debug(`Updating Firehose delivery stream ${logicalId}: ${physicalId}`);
46184
46767
  const desiredEncryption = readEncryptionInput(properties[ENCRYPTION_KEY], context?.desiredFromAwsReadback === true);
46185
- const encryptionChanged = !sameEncryptionInput(properties[ENCRYPTION_KEY], desiredEncryption, previousProperties[ENCRYPTION_KEY]);
46768
+ const encryptionChanged = !sameEncryptionInput(properties[ENCRYPTION_KEY], desiredEncryption, previousProperties[ENCRYPTION_KEY]) || context?.unsettledProperties?.has(ENCRYPTION_KEY) === true && desiredEncryption.kind !== "unusable";
46186
46769
  let encryptionSkipped = false;
46187
46770
  if (encryptionChanged && desiredEncryption.kind === "unusable") {
46188
46771
  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 +46834,7 @@ var FirehoseProvider = class {
46251
46834
  const prevDest = previousProperties[activeDest] ?? {};
46252
46835
  if (JSON.stringify(nextDest) !== JSON.stringify(prevDest)) await this.applySnowflakeDestinationUpdate(logicalId, physicalId, nextDest);
46253
46836
  }
46254
- if (encryptionChanged && desiredEncryption.kind !== "unusable") await this.applyEncryptionUpdate(logicalId, physicalId, resourceType, desiredEncryption, maskerOrIdentity(context?.maskSecrets));
46837
+ if (encryptionChanged && desiredEncryption.kind !== "unusable") await this.applyEncryptionUpdate(logicalId, physicalId, resourceType, desiredEncryption, maskerOrIdentity(context?.maskSecrets), context?.markUnsettled);
46255
46838
  const description = await this.getClient().send(new DescribeDeliveryStreamCommand({ DeliveryStreamName: physicalId }));
46256
46839
  this.warnUnappliedS3BackupMode(logicalId, properties, unappliedS3BackupModeDestination(properties, previousProperties, destKey, context?.changedProperties), description.DeliveryStreamDescription);
46257
46840
  const desc = description.DeliveryStreamDescription;
@@ -46332,7 +46915,7 @@ var FirehoseProvider = class {
46332
46915
  }))
46333
46916
  }));
46334
46917
  }
46335
- async applyEncryptionUpdate(logicalId, physicalId, resourceType, desired, mask) {
46918
+ async applyEncryptionUpdate(logicalId, physicalId, resourceType, desired, mask, markUnsettled) {
46336
46919
  const settled = await this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46337
46920
  what: "settle",
46338
46921
  done: (enc) => enc?.Status !== "ENABLING" && enc?.Status !== "DISABLING"
@@ -46340,8 +46923,9 @@ var FirehoseProvider = class {
46340
46923
  if (desired.kind === "absent") {
46341
46924
  if (settled?.Status !== "ENABLED" && settled?.Status !== "DISABLING_FAILED") return;
46342
46925
  this.refuseToStartTransition(logicalId, physicalId, resourceType, "disable");
46926
+ markUnsettled?.(ENCRYPTION_KEY);
46343
46927
  await this.getClient().send(new StopDeliveryStreamEncryptionCommand({ DeliveryStreamName: physicalId }));
46344
- await this.warnIfUnfinished(logicalId, "StopDeliveryStreamEncryption", () => this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46928
+ await this.warnIfUnfinished(logicalId, "StopDeliveryStreamEncryption", markUnsettled, () => this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46345
46929
  what: "disable",
46346
46930
  done: (enc) => enc === void 0 || enc.Status === "DISABLED",
46347
46931
  inProgress: "DISABLING",
@@ -46352,6 +46936,7 @@ var FirehoseProvider = class {
46352
46936
  }
46353
46937
  if (encryptionMatches(settled, desired)) return;
46354
46938
  this.refuseToStartTransition(logicalId, physicalId, resourceType, "enable");
46939
+ markUnsettled?.(ENCRYPTION_KEY);
46355
46940
  await this.getClient().send(new StartDeliveryStreamEncryptionCommand({
46356
46941
  DeliveryStreamName: physicalId,
46357
46942
  DeliveryStreamEncryptionConfigurationInput: {
@@ -46359,7 +46944,7 @@ var FirehoseProvider = class {
46359
46944
  ...desired.keyArn !== void 0 && { KeyARN: desired.keyArn }
46360
46945
  }
46361
46946
  }));
46362
- await this.warnIfUnfinished(logicalId, "StartDeliveryStreamEncryption", () => this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46947
+ await this.warnIfUnfinished(logicalId, "StartDeliveryStreamEncryption", markUnsettled, () => this.waitForEncryption(logicalId, physicalId, resourceType, mask, {
46363
46948
  what: "enable",
46364
46949
  done: (enc) => encryptionMatches(enc, desired),
46365
46950
  inProgress: "ENABLING",
@@ -46367,12 +46952,12 @@ var FirehoseProvider = class {
46367
46952
  staleFailure: settled?.Status === "ENABLING_FAILED"
46368
46953
  }));
46369
46954
  }
46370
- async warnIfUnfinished(logicalId, call, wait) {
46955
+ async warnIfUnfinished(logicalId, call, markUnsettled, wait) {
46371
46956
  try {
46372
46957
  return await wait();
46373
46958
  } catch (error) {
46374
46959
  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.`);
46960
+ 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
46961
  throw error;
46377
46962
  }
46378
46963
  }
@@ -46790,6 +47375,15 @@ var FirehoseProvider = class {
46790
47375
  if (config["CloudWatchLoggingOptions"] !== void 0) result.CloudWatchLoggingOptions = config["CloudWatchLoggingOptions"];
46791
47376
  return result;
46792
47377
  }
47378
+ async unsettledInTransition(physicalId, _logicalId, _resourceType, names) {
47379
+ if (!names.has(ENCRYPTION_KEY)) return /* @__PURE__ */ new Set();
47380
+ try {
47381
+ const status = (await this.getClient().send(new DescribeDeliveryStreamCommand({ DeliveryStreamName: physicalId }))).DeliveryStreamDescription?.DeliveryStreamEncryptionConfiguration?.Status;
47382
+ return status === "ENABLING" || status === "DISABLING" ? /* @__PURE__ */ new Set([ENCRYPTION_KEY]) : /* @__PURE__ */ new Set();
47383
+ } catch {
47384
+ return /* @__PURE__ */ new Set([ENCRYPTION_KEY]);
47385
+ }
47386
+ }
46793
47387
  async readCurrentState(physicalId, _logicalId, _resourceType) {
46794
47388
  let desc;
46795
47389
  try {
@@ -46846,18 +47440,59 @@ var FirehoseProvider = class {
46846
47440
  }
46847
47441
  return null;
46848
47442
  }
46849
- async waitForActive(streamName, logicalId) {
46850
- const maxAttempts = 30;
46851
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
46852
- const status = (await this.getClient().send(new DescribeDeliveryStreamCommand({ DeliveryStreamName: streamName }))).DeliveryStreamDescription?.DeliveryStreamStatus;
46853
- if (status === "ACTIVE") {
46854
- this.logger.debug(`Firehose ${logicalId} is ACTIVE`);
46855
- return;
47443
+ async waitForActive(streamName, logicalId, resourceType, mask) {
47444
+ const watch = startInterruptWatch(`Firehose ${logicalId} create`);
47445
+ try {
47446
+ let last;
47447
+ let deadlineNear = false;
47448
+ for (let attempt = 1; attempt <= ACTIVE_POLL_MAX_ATTEMPTS; attempt++) {
47449
+ if (watch.isInterrupted()) throw watch.onInterrupted();
47450
+ if (enclosingDeadlineRemainingMs() <= ACTIVE_DEADLINE_MARGIN_MS) {
47451
+ deadlineNear = true;
47452
+ break;
47453
+ }
47454
+ const resp = await this.describeBeforeDeadline(streamName);
47455
+ if (resp === "deadline") {
47456
+ deadlineNear = true;
47457
+ break;
47458
+ }
47459
+ const description = resp.DeliveryStreamDescription;
47460
+ last = description?.DeliveryStreamStatus;
47461
+ if (last === "ACTIVE") {
47462
+ this.logger.debug(`Firehose ${logicalId} is ACTIVE`);
47463
+ return;
47464
+ }
47465
+ if (last !== void 0 && last.endsWith("_FAILED")) {
47466
+ const failure = description?.FailureDescription;
47467
+ throw markNonRetryable(new ProvisioningError(`Firehose delivery stream ${logicalId} did not become ACTIVE: AWS reports ${last}` + (failure ? ` (${mask(`${failure.Type ?? ""}: ${failure.Details ?? ""}`)})` : ""), resourceType, logicalId, streamName));
47468
+ }
47469
+ this.logger.debug(`Firehose ${logicalId} status: ${last} (attempt ${attempt}/${ACTIVE_POLL_MAX_ATTEMPTS})`);
47470
+ if (watch.isInterrupted()) throw watch.onInterrupted();
47471
+ if (enclosingDeadlineRemainingMs() <= 7e3) {
47472
+ deadlineNear = true;
47473
+ break;
47474
+ }
47475
+ await new Promise((resolve) => setTimeout(resolve, ACTIVE_POLL_INTERVAL_MS));
46856
47476
  }
46857
- this.logger.debug(`Firehose ${logicalId} status: ${status} (attempt ${attempt}/${maxAttempts})`);
46858
- await new Promise((resolve) => setTimeout(resolve, 2e3));
47477
+ throw markNonRetryable(new ProvisioningError((deadlineNear ? `The resource timeout would expire while waiting for Firehose delivery stream ${logicalId} to become ACTIVE ` : `Timed out waiting for Firehose delivery stream ${logicalId} to become ACTIVE `) + `(last status: ${last ?? "none reported"})`, resourceType, logicalId, streamName));
47478
+ } finally {
47479
+ watch.dispose();
47480
+ }
47481
+ }
47482
+ async describeBeforeDeadline(streamName) {
47483
+ const command = new DescribeDeliveryStreamCommand({ DeliveryStreamName: streamName });
47484
+ const remaining = enclosingDeadlineRemainingMs();
47485
+ if (!Number.isFinite(remaining)) return this.getClient().send(command);
47486
+ const abort = new AbortController();
47487
+ const timer = setTimeout(() => abort.abort(), Math.max(0, remaining - ACTIVE_DEADLINE_MARGIN_MS));
47488
+ try {
47489
+ return await this.getClient().send(command, { abortSignal: abort.signal });
47490
+ } catch (error) {
47491
+ if (abort.signal.aborted) return "deadline";
47492
+ throw error;
47493
+ } finally {
47494
+ clearTimeout(timer);
46859
47495
  }
46860
- this.logger.warn(`Firehose ${logicalId} did not reach ACTIVE after ${maxAttempts} attempts`);
46861
47496
  }
46862
47497
  };
46863
47498
  function pickDefinedDeep(input) {
@@ -46985,6 +47620,77 @@ function resolveCloudWatchLogsPair(properties) {
46985
47620
  roleArn: desiredRole
46986
47621
  };
46987
47622
  }
47623
+ function readListBlock(raw, path) {
47624
+ if (raw == null) return { kind: "absent" };
47625
+ try {
47626
+ return {
47627
+ kind: "list",
47628
+ value: requireConfigArray(raw, path)
47629
+ };
47630
+ } catch (error) {
47631
+ return {
47632
+ kind: "unusable",
47633
+ detail: describeAwsFailure(error).detail
47634
+ };
47635
+ }
47636
+ }
47637
+ function listOf(read) {
47638
+ return read.kind === "list" ? read.value : void 0;
47639
+ }
47640
+ function retainPreviousLists(desired, previous, keys, live) {
47641
+ const out = Object.fromEntries(Object.entries(desired).filter(([key]) => !keys.includes(key)));
47642
+ for (const key of keys) {
47643
+ const prev = previous[key];
47644
+ if (Array.isArray(prev)) out[key] = structuredClone(prev);
47645
+ else if (prev != null && Array.isArray(live?.[key])) out[key] = structuredClone(live[key]);
47646
+ }
47647
+ return out;
47648
+ }
47649
+ const UNORDERED_LIST_BLOCKS = ["AdvancedEventSelectors", "AggregationConfigurations"];
47650
+ function setKey(value) {
47651
+ if (value === void 0) return "undefined";
47652
+ if (Array.isArray(value)) return [
47653
+ "[",
47654
+ value.map(setKey).sort().join(","),
47655
+ "]"
47656
+ ].join("");
47657
+ if (value !== null && typeof value === "object") {
47658
+ const bag = value;
47659
+ return [
47660
+ "{",
47661
+ Object.keys(bag).filter((k) => bag[k] !== void 0).sort().map((k) => [JSON.stringify(k), setKey(bag[k])].join(":")).join(","),
47662
+ "}"
47663
+ ].join("");
47664
+ }
47665
+ return JSON.stringify(value) ?? "null";
47666
+ }
47667
+ function nonEmptyListOf(read) {
47668
+ return read.kind === "list" && read.value.length > 0 ? read.value : void 0;
47669
+ }
47670
+ function eventSelectorRequest(basic, advanced) {
47671
+ const hasBasic = basic !== void 0 && basic.length > 0;
47672
+ if (advanced !== void 0 && advanced.length > 0) return {
47673
+ members: {
47674
+ AdvancedEventSelectors: advanced,
47675
+ ...hasBasic ? { EventSelectors: basic } : {}
47676
+ },
47677
+ isReset: false
47678
+ };
47679
+ if (hasBasic) return {
47680
+ members: { EventSelectors: basic },
47681
+ isReset: false
47682
+ };
47683
+ return {
47684
+ members: { EventSelectors: [...DEFAULT_EVENT_SELECTORS] },
47685
+ isReset: true
47686
+ };
47687
+ }
47688
+ function advancedSelectorsToCfn(selectors) {
47689
+ return selectors.map((s) => ({
47690
+ ...s.Name !== void 0 && { Name: s.Name },
47691
+ FieldSelectors: (s.FieldSelectors ?? []).map((f) => Object.fromEntries(Object.entries(f).filter(([, v]) => v !== void 0)))
47692
+ }));
47693
+ }
46988
47694
  function describeValue(value) {
46989
47695
  if (value === null) return "null";
46990
47696
  if (value === void 0) return "nothing";
@@ -47034,7 +47740,9 @@ var CloudTrailProvider = class {
47034
47740
  "SnsTopicName",
47035
47741
  "EventSelectors",
47036
47742
  "InsightSelectors",
47037
- "IsOrganizationTrail"
47743
+ "IsOrganizationTrail",
47744
+ "AdvancedEventSelectors",
47745
+ "AggregationConfigurations"
47038
47746
  ])]]);
47039
47747
  getClient() {
47040
47748
  if (!this.client) {
@@ -47071,6 +47779,9 @@ var CloudTrailProvider = class {
47071
47779
  const isOrganizationTrail = properties["IsOrganizationTrail"];
47072
47780
  const eventSelectors = properties["EventSelectors"];
47073
47781
  const insightSelectors = properties["InsightSelectors"];
47782
+ const advancedEventSelectors = properties["AdvancedEventSelectors"] == null ? void 0 : requireConfigArray(properties["AdvancedEventSelectors"], "AWS::CloudTrail::Trail AdvancedEventSelectors", replayWarn(this.logger, context));
47783
+ const aggregationConfigurations = properties["AggregationConfigurations"] == null ? void 0 : requireConfigArray(properties["AggregationConfigurations"], "AWS::CloudTrail::Trail AggregationConfigurations", replayWarn(this.logger, context));
47784
+ const skippedOnReplay = [...properties["AdvancedEventSelectors"] != null && advancedEventSelectors === void 0 ? ["AdvancedEventSelectors"] : [], ...properties["AggregationConfigurations"] != null && aggregationConfigurations === void 0 ? ["AggregationConfigurations"] : []];
47074
47785
  let trailCreated = false;
47075
47786
  let createdTrailArn;
47076
47787
  try {
@@ -47094,11 +47805,19 @@ var CloudTrailProvider = class {
47094
47805
  trailCreated = true;
47095
47806
  const trailArn = result.TrailARN;
47096
47807
  createdTrailArn = result.TrailARN;
47097
- if (eventSelectors && eventSelectors.length > 0) {
47808
+ const basicForCreate = eventSelectors && eventSelectors.length > 0 ? eventSelectors : void 0;
47809
+ if (basicForCreate || advancedEventSelectors && advancedEventSelectors.length > 0) {
47098
47810
  this.logger.debug(`Setting event selectors for CloudTrail Trail ${logicalId}`);
47099
47811
  await this.getClient().send(new PutEventSelectorsCommand({
47100
47812
  TrailName: trailArn,
47101
- EventSelectors: eventSelectors
47813
+ ...eventSelectorRequest(basicForCreate, advancedEventSelectors).members
47814
+ }));
47815
+ }
47816
+ if (aggregationConfigurations && aggregationConfigurations.length > 0) {
47817
+ this.logger.debug(safeMsg`Setting aggregation configurations for CloudTrail Trail ${logicalId}`);
47818
+ await this.getClient().send(new PutEventConfigurationCommand({
47819
+ TrailName: trailArn,
47820
+ AggregationConfigurations: aggregationConfigurations
47102
47821
  }));
47103
47822
  }
47104
47823
  if (insightSelectors && insightSelectors.length > 0) {
@@ -47115,7 +47834,8 @@ var CloudTrailProvider = class {
47115
47834
  this.logger.debug(`Successfully created CloudTrail Trail ${logicalId}: ${trailArn}`);
47116
47835
  return {
47117
47836
  physicalId: trailArn,
47118
- attributes: { Arn: trailArn }
47837
+ attributes: { Arn: trailArn },
47838
+ ...skippedOnReplay.length > 0 && { effectiveProperties: retainPreviousLists(properties, {}, skippedOnReplay) }
47119
47839
  };
47120
47840
  } catch (error) {
47121
47841
  if (trailCreated) markAuxiliaryFailure(error, logicalId);
@@ -47126,6 +47846,7 @@ var CloudTrailProvider = class {
47126
47846
  }
47127
47847
  }
47128
47848
  async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
47849
+ const desiredProperties = properties;
47129
47850
  properties = withRemovalDefaults(this.removalDefaults, resourceType, properties, previousProperties, context);
47130
47851
  this.logger.debug(`Updating CloudTrail Trail ${logicalId}: ${physicalId}`);
47131
47852
  refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
@@ -47142,6 +47863,7 @@ var CloudTrailProvider = class {
47142
47863
  const kmsKeyId = clearOnUpdateRemoval(emptyToUndefined(properties["KMSKeyId"]), emptyToUndefined(previousProperties["KMSKeyId"]), "");
47143
47864
  const snsTopicName = clearOnUpdateRemoval(emptyToUndefined(properties["SnsTopicName"]), emptyToUndefined(previousProperties["SnsTopicName"]), "");
47144
47865
  const isOrganizationTrail = properties["IsOrganizationTrail"];
47866
+ const appliedBeforeFailure = [];
47145
47867
  try {
47146
47868
  await this.getClient().send(new UpdateTrailCommand({
47147
47869
  Name: physicalId,
@@ -47156,36 +47878,61 @@ var CloudTrailProvider = class {
47156
47878
  SnsTopicName: snsTopicName,
47157
47879
  IsOrganizationTrail: isOrganizationTrail
47158
47880
  }));
47159
- const rawEventSelectors = properties["EventSelectors"];
47160
- let eventSelectorsUnusable = false;
47161
- let newEventSelectors;
47162
- if (rawEventSelectors != null) try {
47163
- newEventSelectors = requireConfigArray(rawEventSelectors, "AWS::CloudTrail::Trail EventSelectors");
47164
- } catch (error) {
47165
- eventSelectorsUnusable = true;
47166
- this.logger.warn(`${describeAwsFailure(error).detail} The trail's existing event selectors are left untouched for this update rather than reset to the AWS default.`);
47167
- }
47881
+ const basicRead = readListBlock(properties["EventSelectors"], "AWS::CloudTrail::Trail EventSelectors");
47882
+ const advancedRead = readListBlock(properties["AdvancedEventSelectors"], "AWS::CloudTrail::Trail AdvancedEventSelectors");
47883
+ for (const read of [basicRead, advancedRead]) if (read.kind === "unusable") this.logger.warn(safeMsg`${read.detail} The trail's existing event selectors are left untouched for this update rather than reset to the AWS default.`);
47884
+ const selectorsUnusable = basicRead.kind === "unusable" || advancedRead.kind === "unusable";
47885
+ const newEventSelectors = listOf(basicRead);
47886
+ const newAdvancedSelectors = listOf(advancedRead);
47168
47887
  const oldEventSelectors = previousProperties["EventSelectors"];
47169
- if (!eventSelectorsUnusable && JSON.stringify(newEventSelectors) !== JSON.stringify(oldEventSelectors)) {
47170
- const isRemoval = newEventSelectors === void 0 || newEventSelectors.length === 0;
47171
- const eventSelectorsToSend = newEventSelectors === void 0 || newEventSelectors.length === 0 ? DEFAULT_EVENT_SELECTORS : newEventSelectors;
47888
+ const oldAdvancedSelectors = previousProperties["AdvancedEventSelectors"];
47889
+ const hadAdvancedSelectors = Array.isArray(oldAdvancedSelectors) && oldAdvancedSelectors.length > 0;
47890
+ const aggregationRead = readListBlock(properties["AggregationConfigurations"], "AWS::CloudTrail::Trail AggregationConfigurations");
47891
+ if (aggregationRead.kind === "unusable") this.logger.warn(safeMsg`${aggregationRead.detail} The trail's existing aggregation configurations are left untouched for this update rather than cleared.`);
47892
+ const newAggregation = listOf(aggregationRead);
47893
+ const aggregationChanged = aggregationRead.kind !== "unusable" && setKey(newAggregation) !== setKey(previousProperties["AggregationConfigurations"]);
47894
+ const aggregationCleared = aggregationChanged && nonEmptyListOf(aggregationRead) === void 0;
47895
+ const putAggregation = async () => {
47896
+ this.logger.debug(safeMsg`Updating aggregation configurations for CloudTrail Trail ${logicalId}`);
47897
+ await this.getClient().send(new PutEventConfigurationCommand({
47898
+ TrailName: physicalId,
47899
+ AggregationConfigurations: newAggregation ?? []
47900
+ }));
47901
+ };
47902
+ if (aggregationCleared) {
47903
+ await putAggregation();
47904
+ appliedBeforeFailure.push("AggregationConfigurations was cleared");
47905
+ }
47906
+ if (!selectorsUnusable && (JSON.stringify(newEventSelectors) !== JSON.stringify(oldEventSelectors) || setKey(newAdvancedSelectors) !== setKey(oldAdvancedSelectors))) {
47907
+ let basicToSend = newEventSelectors;
47908
+ let advancedToSend = newAdvancedSelectors;
47909
+ if (context?.desiredFromAwsReadback === true && nonEmptyListOf(basicRead) !== void 0 && nonEmptyListOf(advancedRead) !== void 0) {
47910
+ if (JSON.stringify(newEventSelectors) === JSON.stringify(oldEventSelectors)) basicToSend = void 0;
47911
+ else if (setKey(newAdvancedSelectors) === setKey(oldAdvancedSelectors)) advancedToSend = void 0;
47912
+ }
47913
+ const { members, isReset: isRemoval } = eventSelectorRequest(basicToSend, advancedToSend);
47172
47914
  this.logger.debug(isRemoval ? `Resetting event selectors to the AWS default for CloudTrail Trail ${logicalId}` : `Updating event selectors for CloudTrail Trail ${logicalId}`);
47173
47915
  try {
47174
47916
  await this.getClient().send(new PutEventSelectorsCommand({
47175
47917
  TrailName: physicalId,
47176
- EventSelectors: [...eventSelectorsToSend]
47918
+ ...members
47177
47919
  }));
47920
+ appliedBeforeFailure.push("the event selectors were updated");
47178
47921
  } catch (error) {
47179
47922
  const failure = describeAwsFailure(error);
47180
47923
  const message = withoutTrailIdentifiers(failure.detail, physicalId);
47181
47924
  const errorClass = error instanceof Error ? error.name : "";
47182
- if (!isRemoval || ACCESS_DENIAL_CLASS.test(errorClass) || !ADVANCED_SELECTOR_PHRASE.test(message)) throw error;
47925
+ if (!isRemoval || hadAdvancedSelectors || ACCESS_DENIAL_CLASS.test(errorClass) || !ADVANCED_SELECTOR_PHRASE.test(message)) throw error;
47183
47926
  const m = maskerOrIdentity(context?.maskSecrets);
47184
47927
  const head = `CloudTrail Trail ${logicalId}: skipping the EventSelectors reset — the trail is using AdvancedEventSelectors, which AWS manages through a separate API, so there are no basic event selectors to clear (`;
47185
47928
  if (failure.redacted) this.logger.debug(m(`${head}${m(failure.detail)})`));
47186
47929
  this.logger.warn(m(`${head}${failure.redacted ? failure.summary : failure.detail})`));
47187
47930
  }
47188
47931
  }
47932
+ if (aggregationChanged && !aggregationCleared) {
47933
+ await putAggregation();
47934
+ appliedBeforeFailure.push("AggregationConfigurations was updated");
47935
+ }
47189
47936
  const newInsightSelectors = properties["InsightSelectors"];
47190
47937
  const oldInsightSelectors = previousProperties["InsightSelectors"];
47191
47938
  if (JSON.stringify(newInsightSelectors) !== JSON.stringify(oldInsightSelectors)) {
@@ -47207,13 +47954,19 @@ var CloudTrailProvider = class {
47207
47954
  }
47208
47955
  await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
47209
47956
  this.logger.debug(`Successfully updated CloudTrail Trail ${logicalId}`);
47210
- return {
47957
+ const skipped = [...selectorsUnusable ? ["EventSelectors", "AdvancedEventSelectors"] : [], ...aggregationRead.kind === "unusable" ? ["AggregationConfigurations"] : []];
47958
+ if (skipped.length === 0) return {
47211
47959
  physicalId,
47212
47960
  wasReplaced: false
47213
47961
  };
47962
+ return {
47963
+ physicalId,
47964
+ wasReplaced: false,
47965
+ effectiveProperties: retainPreviousLists(desiredProperties, previousProperties, skipped, skipped.some((key) => previousProperties[key] != null && !Array.isArray(previousProperties[key])) ? await this.readLiveForRecord(physicalId, resourceType) : void 0)
47966
+ };
47214
47967
  } catch (error) {
47215
47968
  const cause = error instanceof Error ? error : void 0;
47216
- throw this.wrapCaughtError(context?.maskSecrets, error, (text) => new ProvisioningError(`Failed to update CloudTrail Trail ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
47969
+ throw this.wrapCaughtError(context?.maskSecrets, error, (text) => new ProvisioningError(`Failed to update CloudTrail Trail ${logicalId}: ${text}` + (appliedBeforeFailure.length > 0 ? ` (selector/aggregation writes already applied before this failure: ${appliedBeforeFailure.join("; ")})` : ""), resourceType, logicalId, physicalId, cause));
47217
47970
  }
47218
47971
  }
47219
47972
  async delete(logicalId, physicalId, resourceType, properties, context) {
@@ -47243,6 +47996,19 @@ var CloudTrailProvider = class {
47243
47996
  throw stripped ? markDeleteStarted(notGone) : notGone;
47244
47997
  }
47245
47998
  }
47999
+ async readLiveForRecord(physicalId, resourceType) {
48000
+ try {
48001
+ const live = await this.readCurrentState(physicalId, "", resourceType);
48002
+ return live !== void 0 && live !== RESOURCE_NOT_FOUND ? live : void 0;
48003
+ } catch (error) {
48004
+ this.logger.debug(safeMsg`CloudTrail read-back for the record failed: ${describeAwsFailure(error).detail}`);
48005
+ return;
48006
+ }
48007
+ }
48008
+ getDriftUnorderedPaths(resourceType) {
48009
+ if (resourceType !== "AWS::CloudTrail::Trail") return [];
48010
+ return [...UNORDERED_LIST_BLOCKS];
48011
+ }
47246
48012
  getAttribute(_physicalId, _resourceType, attributeName) {
47247
48013
  return Promise.resolve(attributeName);
47248
48014
  }
@@ -47301,7 +48067,9 @@ var CloudTrailProvider = class {
47301
48067
  } catch {}
47302
48068
  try {
47303
48069
  const sel = await this.getClient().send(new GetEventSelectorsCommand({ TrailName: physicalId }));
47304
- if (!(Array.isArray(sel.AdvancedEventSelectors) && sel.AdvancedEventSelectors.length > 0)) result["EventSelectors"] = (sel.EventSelectors ?? []).map((es) => es);
48070
+ const hasAdvanced = Array.isArray(sel.AdvancedEventSelectors) && sel.AdvancedEventSelectors.length > 0;
48071
+ if (!hasAdvanced) result["EventSelectors"] = (sel.EventSelectors ?? []).map((es) => es);
48072
+ result["AdvancedEventSelectors"] = hasAdvanced ? advancedSelectorsToCfn(sel.AdvancedEventSelectors ?? []) : [];
47305
48073
  } catch {}
47306
48074
  let insightSelectors = [];
47307
48075
  try {
@@ -47316,6 +48084,14 @@ var CloudTrailProvider = class {
47316
48084
  this.logger.debug(`CloudTrail ListTags(${trail.TrailARN}) failed: ${describeAwsFailure(err).detail}`);
47317
48085
  }
47318
48086
  result["Tags"] = tags;
48087
+ try {
48088
+ result["AggregationConfigurations"] = ((await this.getClient().send(new GetEventConfigurationCommand({ TrailName: physicalId }))).AggregationConfigurations ?? []).map((a) => ({
48089
+ ...a.EventCategory !== void 0 && { EventCategory: a.EventCategory },
48090
+ ...a.Templates !== void 0 && { Templates: a.Templates }
48091
+ }));
48092
+ } catch (err) {
48093
+ this.logger.debug(safeMsg`CloudTrail GetEventConfiguration(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
48094
+ }
47319
48095
  return result;
47320
48096
  }
47321
48097
  async import(input) {
@@ -48105,11 +48881,11 @@ var CodeCommitRepositoryProvider = class {
48105
48881
  const repoArn = metadata?.Arn;
48106
48882
  if (repoArn) {
48107
48883
  const removedKeys = Object.keys(oldTagMap).filter((k) => !Object.hasOwn(newTagMap, k));
48108
- if (removedKeys.length > 0) await this.getClient().send(new UntagResourceCommand$25({
48884
+ if (removedKeys.length > 0) await this.getClient().send(new UntagResourceCommand$26({
48109
48885
  resourceArn: repoArn,
48110
48886
  tagKeys: removedKeys
48111
48887
  }));
48112
- if (Object.keys(newTagMap).length > 0) await this.getClient().send(new TagResourceCommand$24({
48888
+ if (Object.keys(newTagMap).length > 0) await this.getClient().send(new TagResourceCommand$25({
48113
48889
  resourceArn: repoArn,
48114
48890
  tags: newTagMap
48115
48891
  }));
@@ -48552,7 +49328,7 @@ var DLMLifecyclePolicyProvider = class {
48552
49328
  if (tagsChanged && arn) {
48553
49329
  const removedKeys = plan.remove;
48554
49330
  if (removedKeys.length > 0) {
48555
- await this.getClient().send(new UntagResourceCommand$26({
49331
+ await this.getClient().send(new UntagResourceCommand$27({
48556
49332
  ResourceArn: arn,
48557
49333
  TagKeys: removedKeys
48558
49334
  }));
@@ -48560,7 +49336,7 @@ var DLMLifecyclePolicyProvider = class {
48560
49336
  }
48561
49337
  const tagsToAdd = Object.fromEntries(plan.set);
48562
49338
  if (Object.keys(tagsToAdd).length > 0) {
48563
- await this.getClient().send(new TagResourceCommand$25({
49339
+ await this.getClient().send(new TagResourceCommand$26({
48564
49340
  ResourceArn: arn,
48565
49341
  Tags: tagsToAdd
48566
49342
  }));
@@ -48724,11 +49500,11 @@ var S3VectorsProvider = class {
48724
49500
  }
48725
49501
  if (!resourceArn) throw new ProvisioningError(`Could not resolve ARN for S3 VectorBucket ${logicalId} (${mask(physicalId)}); cannot apply tag update.`, resourceType, logicalId, physicalId);
48726
49502
  try {
48727
- if (Object.keys(toSet).length > 0) await this.getClient().send(new TagResourceCommand$26({
49503
+ if (Object.keys(toSet).length > 0) await this.getClient().send(new TagResourceCommand$27({
48728
49504
  resourceArn,
48729
49505
  tags: toSet
48730
49506
  }));
48731
- if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$27({
49507
+ if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$28({
48732
49508
  resourceArn,
48733
49509
  tagKeys: toRemove
48734
49510
  }));
@@ -49011,12 +49787,12 @@ var S3DirectoryBucketProvider = class {
49011
49787
  if (removedKeys.length > 0 || tagsToApply.length > 0) {
49012
49788
  const accountId = await this.getAccountId();
49013
49789
  const resourceArn = await this.buildBucketArn(physicalId, accountId);
49014
- if (removedKeys.length > 0) await this.getS3ControlClient().send(new UntagResourceCommand$28({
49790
+ if (removedKeys.length > 0) await this.getS3ControlClient().send(new UntagResourceCommand$29({
49015
49791
  AccountId: accountId,
49016
49792
  ResourceArn: resourceArn,
49017
49793
  TagKeys: removedKeys
49018
49794
  }));
49019
- if (tagsToApply.length > 0) await this.getS3ControlClient().send(new TagResourceCommand$27({
49795
+ if (tagsToApply.length > 0) await this.getS3ControlClient().send(new TagResourceCommand$28({
49020
49796
  AccountId: accountId,
49021
49797
  ResourceArn: resourceArn,
49022
49798
  Tags: tagsToApply
@@ -49864,7 +50640,7 @@ var S3TablesProvider = class {
49864
50640
  const resourceArn = await this.lookupTableArn(tableBucketARN, namespace, name);
49865
50641
  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
50642
  if (removedKeys.length > 0) try {
49867
- await this.getClient().send(new UntagResourceCommand$29({
50643
+ await this.getClient().send(new UntagResourceCommand$30({
49868
50644
  resourceArn,
49869
50645
  tagKeys: removedKeys
49870
50646
  }));
@@ -49873,7 +50649,7 @@ var S3TablesProvider = class {
49873
50649
  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
50650
  }
49875
50651
  if (Object.keys(upserts).length > 0) try {
49876
- await this.getClient().send(new TagResourceCommand$28({
50652
+ await this.getClient().send(new TagResourceCommand$29({
49877
50653
  resourceArn,
49878
50654
  tags: upserts
49879
50655
  }));
@@ -49891,7 +50667,7 @@ var S3TablesProvider = class {
49891
50667
  if (removedKeys.length === 0 && Object.keys(upserts).length === 0) return;
49892
50668
  const resourceArn = physicalId;
49893
50669
  if (removedKeys.length > 0) try {
49894
- await this.getClient().send(new UntagResourceCommand$29({
50670
+ await this.getClient().send(new UntagResourceCommand$30({
49895
50671
  resourceArn,
49896
50672
  tagKeys: removedKeys
49897
50673
  }));
@@ -49900,7 +50676,7 @@ var S3TablesProvider = class {
49900
50676
  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
50677
  }
49902
50678
  if (Object.keys(upserts).length > 0) try {
49903
- await this.getClient().send(new TagResourceCommand$28({
50679
+ await this.getClient().send(new TagResourceCommand$29({
49904
50680
  resourceArn,
49905
50681
  tags: upserts
49906
50682
  }));
@@ -51020,4 +51796,4 @@ var ACMCertificateProvider = class {
51020
51796
 
51021
51797
  //#endregion
51022
51798
  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
51799
+ //# sourceMappingURL=provider-classes-KsrvwO_r.js.map