@go-to-k/cdkd 0.309.0 → 0.311.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 (33) hide show
  1. package/dist/{asg-provider-DQoKGfKH.js → asg-provider-CIg_guZ-.js} +5 -3
  2. package/dist/asg-provider-CIg_guZ-.js.map +1 -0
  3. package/dist/cli.js +2 -2
  4. package/dist/{iam-policy-targets-D94wh05t.js → created-resource-sink-DlzoIY-1.js} +51 -2
  5. package/dist/created-resource-sink-DlzoIY-1.js.map +1 -0
  6. package/dist/{db-instance-modify-retry-BUG7NMWS.js → db-instance-modify-retry-1y0kIPCO.js} +2 -2
  7. package/dist/{db-instance-modify-retry-BUG7NMWS.js.map → db-instance-modify-retry-1y0kIPCO.js.map} +1 -1
  8. package/dist/{deploy-engine-tQ0aqZMo.js → deploy-engine-BF5exXUb.js} +620 -114
  9. package/dist/deploy-engine-BF5exXUb.js.map +1 -0
  10. package/dist/{iam-role-provider-BI8Acvps.js → iam-role-provider-qvhlVnrn.js} +5 -3
  11. package/dist/iam-role-provider-qvhlVnrn.js.map +1 -0
  12. package/dist/index.d.ts +9 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +3 -3
  15. package/dist/{neptune-provider-DmVmx69p.js → neptune-provider-D9ac71Ca.js} +6 -4
  16. package/dist/neptune-provider-D9ac71Ca.js.map +1 -0
  17. package/dist/{program-Bnt3Yt0k.js → program-DbnTHlwR.js} +27 -15
  18. package/dist/program-DbnTHlwR.js.map +1 -0
  19. package/dist/{provider-classes-DYke4HKr.js → provider-classes-DktsDsTf.js} +1277 -175
  20. package/dist/provider-classes-DktsDsTf.js.map +1 -0
  21. package/dist/{rds-provider-Qpf09VQv.js → rds-provider-0LUsn9Wl.js} +7 -4
  22. package/dist/rds-provider-0LUsn9Wl.js.map +1 -0
  23. package/dist/{version-9LVuCtBU.js → version-BA4rBBLp.js} +2 -2
  24. package/dist/{version-9LVuCtBU.js.map → version-BA4rBBLp.js.map} +1 -1
  25. package/package.json +8 -9
  26. package/dist/asg-provider-DQoKGfKH.js.map +0 -1
  27. package/dist/deploy-engine-tQ0aqZMo.js.map +0 -1
  28. package/dist/iam-policy-targets-D94wh05t.js.map +0 -1
  29. package/dist/iam-role-provider-BI8Acvps.js.map +0 -1
  30. package/dist/neptune-provider-DmVmx69p.js.map +0 -1
  31. package/dist/program-Bnt3Yt0k.js.map +0 -1
  32. package/dist/provider-classes-DYke4HKr.js.map +0 -1
  33. package/dist/rds-provider-Qpf09VQv.js.map +0 -1
@@ -1,14 +1,14 @@
1
1
  import { r as getAwsClients, s as withApiGatewayPacing } from "./aws-clients-Bu9EMILF.js";
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
- 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";
3
+ import { $ as observeThenDisableProtection, A as RESOURCE_NOT_FOUND, An as ProvisioningError, Ar as wrapMaskedAwsError, At as isSecretDerivedValue, B as refusalTypeShown, Bt as isAuxiliaryFailure, C as ambiguousAttemptLead, Cr as isTransientServerError, Ct as logicalIdShown, D as replayedSendWindow, Dr as isThrottlingError, Dt as stateOrphanRecordRemedy, E as replayFollowedAmbiguousAttempt, Er as isMarkedNonRetryable, Et as segmentAfterAnchor, F as isPlainImportJson, H as resolveExplicitPhysicalId, Ht as markAuxiliaryFailure, I as isPlainImportValue, It as clearCreatedBeforeFailure, Jn as isInertUnquoted, K as deleteAfterProtectionFlipWithFinalSnapshot, Kn as commandHole, L as isQuotableImportValue, M as markNotGone, Mn as ResourceUpdateNotSupportedError, Mt as maskerOrIdentity, N as assertRegionMatch, Nt as withDerivedNameMasks, O as setBounded, Or as markNonRetryable, Ot as createMaskedLogSinks, P as VALUE_NOT_SHOWN, Q as logGroupProtectionSite, R as normalizeAwsTagsToCfn, S as RecentIdSet, Sr as isRetryableTransientError, St as compositeIdSkipResult, T as isInsideWindow, Tr as THROTTLING_ERROR_NAMES, Ut as markCreatedBeforeFailure, V as remedyLogicalId, W as ProtectionFlipRegistry, Wt as markSupersedesEarlierCreate, X as isTerminalDbWaitStatus, Yn as pasteableCommand, Z as isTerminalDeleteFailure, Zn as plainOrDescribed, _t as isInterruptedWaitError, a as retractCreatedResource, b as AMBIGUOUS_LATCH_TTL_MS, br as isExplicitDenyError, bt as compositeIdFormatMessage, c as SECRET_DERIVED_READ_LIVE, cn as withPasteableAwsProfile, ct as isAwsCliLiteral, d as readPrincipalLists, dn as clientDefaultsFor, dr as markReplayMayCollide, dt as renderDisableCommand, er as shellQuote, et as protectionFlipKey, fn as credentialFingerprint, fr as relayedNameCollision, ft as ElapsedBudgetRegistry, gr as explicitDenyPolicyKind, h as clearOnUpdateRemoval, hn as CdkdError, i as reportCreatedResource, in as injectiveKeyPrefix, it as userPoolProtectionSite, jt as maskDeep, k as withoutServerErrorRetries, kr as markRedactedCause, kt as createMaskedRetryLogger, l as holdsSecretDerivedEntry, ln as ambientClientDefaults, lt as pasteableAwsCommand, ot as UNNAMEABLE_ID_CLAUSE, p as recordedPrincipalsRepair, pn as AccountIdUnavailableError, q as deleteWithProtectionCompensation, qn as hasClauseBreak, rn as injectiveKey, st as WITHHELD_AWS_COMMAND, tr as withheldTargetClause, tt as rdsFamilyProtectionSite, u as onlySecretDerived, un as ambientCredentialConfig, ur as markNameCollision, ut as protectedReplacementAdvice, v as withRemovalDefaults, vt as startInterruptWatch, w as createAttemptKey, wt as packCompositeId, x as AmbiguousCreateLatch, xt as compositeIdSeparatorRefusal, yr as isAmbiguousOutcomeError, yt as canonicalizeRoute53QueryName, z as quotedRemedyLogicalId } from "./created-resource-sink-DlzoIY-1.js";
4
4
  import { c as ambientRegion } from "./aws-client-defaults-BX9Y_fKp.js";
5
- import { $l as stringifyValue, $s as readConfigString, $t as lookupEachName, A as beginDeleteWait, Aa as s3BucketRegionalDomainName, Ai as isRefusedByName, Ar as awaitInFlightSibling, As as withheldAccountClause, B as waitForIndexesSettled, Bi as stringifyIfAssigned, Bt as getCurrentNestedStackContext, C as planContributorInsightsOp, Cd as resolveAssemblyPath, Co as accountArgs, D as reverseMapTableContributorInsights, Da as s3BucketArn, E as reverseMapIndexContributorInsights, Ea as isSettledInstanceState, Ec as passedNoEchoParametersOf, Ei as acquireIdempotencyToken, F as DELETE_INDEX_WAIT_PROCEED_NOTE, Fc as snapshotPassProvenance, Fi as readTagList, G as sendTtlWaitingOutRateLimit, Gs as isWarmThroughputDecrease, H as isTtlRateLimited, I as INDEX_SETTLE_POLL_INTERVAL_MS, Ia as outputReferenceProvenanceOf, Ii as refuseMalformedDesiredTags, In as REDACTED_DELETE_ADDRESS_SKIP_REASON, It as revertNestedChildFromJournal, J as hasCdkAutoDeleteTag, Js as coerceCfnBoolean, K as ECR_AUTO_DELETE_IMAGES_TAG, Ki as waitForLambdaFunctionActive, Ks as toCfnInteger, L as deleteTableWithIndexBusyRetry, Li as tagMapAsList, Ln as isRedactedRecordedValue, M as deleteBudgetKey, Mc as markSameGenerationBag, Mi as DBPROXY_TAGS_WHAT, Mr as getStackRecords, Ms as findSilentDropProperties, N as resolveDynamoDbDeleteBudgetClock, Nc as redactForState, Ni as DBPROXY_TAG_OPTIONS, Nt as getNestedRevertRun, O as stripIndexContributorInsights, Oa as s3BucketDomainName, P as resolveDynamoDbDeleteBudgetMs, Pc as recordReferenceProvenanceEntry, Pi as planTagDiff, Pn as getCurrentProducerRegions, Pr as replacedDeleteFailureVerdict, Ps as withoutSilentDropProperties, Qc as withoutPhysicalNameCopies, Qo as refuseMalformedNestedChildOutputs, Qs as configStringRefusal, Qt as isAccessDeniedError, R as maskedLogger, Rc as hasMaskableValues, Ri as tagPlanWarning, Rn as redactedDeleteAddressFields, S as indexDeclaresContributorInsights, Sd as renderAssemblyPathEscape, Si as earliestDefined, T as readContributorInsightsSpec, U as planTimeToLive, Us as WARM_THROUGHPUT_MEMBERS, V as isTtlAlreadyDisabled, Vt as withNestedStackContext, W as readTtlSpec, Ws as coerceWarmThroughput$1, X as getPriorAttempts, Xi as getCurrentResourceSecrets, Xl as timePhase, Xs as configBooleanRefusal, Y as isTruthyCfnBoolean, Ys as coerceCfnInteger, Z as markRefusedBeforeApplying, Zs as configIntegerRefusal, Zt as chunks, _ as streamMemberRefusals, _a as reDisableInstanceApiTermination, b as CONTRIBUTOR_INSIGHTS_KEY, bd as describeFileReadFailure, c as DynamoDBGlobalTableProvider, cc as blockDeviceMappingsDifferOnlyInDeleteOnTermination, cl as physicalNameCopiesOf, ct as listNestedTemplateRows, d as declaredStreamPolicyMember, da as isWaitAbandonedError, dc as emrClusterInstancesReplaced, ec as replayWarn, el as dynamicReferenceTokens, en as withApiLimit, f as declaredStreamTagsMember, fa as markWaitAbandoned, fc as canonicalLambdaFunctionName, fl as carriesSecretMask, g as streamDeclaresTags, ga as observeThenDisableInstanceApiTermination, go as passedParameterClassesOf, gt as enclosingDeadlineRemainingMs, h as streamDeclaresPolicy, ha as isTerminationProtectionPropagationError, ht as enclosingDeadlineExpired, ia as unchangedBehindSecretReference, iu as rewriteTemplateAssetReferences, j as compensateRemovedDeletionProtection, ja as s3BucketWebsiteUrl, ji as markDeleteStarted, k as DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS, ka as s3BucketDualStackDomainName, l as STREAM_POLICY_KEY, la as deleteSkipReason, li as secretNamedAttributeNamesOf, ll as recordAttributeIdCopy, lt as renderNestedTemplateTreeDefect, m as reverseMapStreamPolicy, ma as ec2InstanceProtectionSite, mc as sameLambdaFunctionAddress, na as slowCcOperationTimeoutMs, nc as requireConfigObject, no as getAccountInfo, od as canonicalizeRegion, ot as findNestedTemplateTreeDefect, p as planStreamMemberOps, pc as lambdaFunctionNameForMask, po as parseWebACLArn, q as S3_AUTO_DELETE_OBJECTS_TAG, qs as toFiniteNumber, ra as onlySecretReferencesDiffer, rc as requireConfigString, rd as decodeListingKey, sc as withRetry, sd as derivePartitionAndUrlSuffix, sl as recoverMaskedOutput, st as isAbsoluteAssetPath, t as DeployEngine, tc as requireConfigArray, u as STREAM_TAGS_KEY, ua as withIndeterminateGuard, uc as ecsServiceLaunchTypeSetOrChanged, v as streamPolicyMatchesDeclared, va as reEnableInstanceApiTermination, vs as refuseMalformedResourcesForDestroy, w as planIndexContributorInsightsOps, wi as reserveStackCreateToken, x as contributorInsightsRefusals, xd as displayAssemblyPath, y as streamTagsMatchDeclared, z as relayedIndexBusyDelete, zi as definedAttributes, zn as redactedDeleteAddressSkip } from "./deploy-engine-tQ0aqZMo.js";
6
- import { n as collectInlinePolicyNamesManagedBySiblings, r as IamCreateClientCache, t as IAMRoleProvider } from "./iam-role-provider-BI8Acvps.js";
7
- import { a as resolveSecretDerivedPrincipals, i as isResolvableSecretPrincipalList, n as runDestroyForStack, o as canonicalizeIpProtocolValue, r as holdsUnprovenSecretPrincipalToken, s as resolvedResourceTimeoutMs, t as canonicalizeIpv4Cidr } from "./program-Bnt3Yt0k.js";
8
- import { t as modifyDbInstanceWhenAvailable } from "./db-instance-modify-retry-BUG7NMWS.js";
9
- import { RDSProvider } from "./rds-provider-Qpf09VQv.js";
10
- import { NeptuneProvider } from "./neptune-provider-DmVmx69p.js";
11
- import { ASGProvider } from "./asg-provider-DQoKGfKH.js";
5
+ import { $s as coerceCfnBoolean, $t as isAccessDeniedError, A as DYNAMODB_DELETE_POLL_COST_MS, B as relayedIndexBusyDelete, Bc as snapshotPassProvenance, Bi as tagPlanWarning, Bn as redactedDeleteAddressSkip, C as planContributorInsightsOp, Ca as isUsableAttemptedName, Cs as refuseMalformedResourcesForDestroy, D as reverseMapTableContributorInsights, Dd as renderAssemblyPathEscape, E as reverseMapIndexContributorInsights, Ed as displayAssemblyPath, Ei as reserveStackCreateToken, F as resolveDynamoDbDeleteBudgetMs, Fa as s3BucketRegionalDomainName, Fi as DBPROXY_TAG_OPTIONS, Fn as getCurrentProducerRegions, Fr as replacedDeleteFailureVerdict, Fs as withheldAccountClause, G as readTtlSpec, H as isTtlAlreadyDisabled, Hi as stringifyIfAssigned, Ht as withNestedStackContext, I as DELETE_INDEX_WAIT_PROCEED_NOTE, Ia as s3BucketWebsiteUrl, Ii as planTagDiff, J as S3_AUTO_DELETE_OBJECTS_TAG, Ji as waitForLambdaFunctionActive, Js as WARM_THROUGHPUT_MEMBERS, K as sendTtlWaitingOutRateLimit, L as INDEX_SETTLE_POLL_INTERVAL_MS, Lc as markSameGenerationBag, Li as readTagList, Ln as REDACTED_DELETE_ADDRESS_SKIP_REASON, Ls as findSilentDropProperties, Lt as revertNestedChildFromJournal, M as compensateRemovedDeletionProtection, Ma as s3BucketArn, Mi as isRefusedByName, N as deleteBudgetKey, Na as s3BucketDomainName, Ni as markDeleteStarted, Nr as getStackRecords, O as stripIndexContributorInsights, Od as resolveAssemblyPath, Oi as acquireIdempotencyToken, Oo as accountArgs, P as resolveDynamoDbDeleteBudgetClock, Pa as s3BucketDualStackDomainName, Pi as DBPROXY_TAGS_WHAT, Pt as getNestedRevertRun, Q as markRefusedBeforeApplying, Qi as getCurrentResourceSecrets, Qs as toFiniteNumber, Qt as chunks, R as deleteTableWithIndexBusyRetry, Rc as redactForState, Ri as refuseMalformedDesiredTags, Rn as isRedactedRecordedValue, S as indexDeclaresContributorInsights, T as readContributorInsightsSpec, Td as describeFileReadFailure, U as isTtlRateLimited, Uc as hasMaskableValues, V as waitForIndexesSettled, Va as outputReferenceProvenanceOf, Vi as definedAttributes, Vt as getCurrentNestedStackContext, W as planTimeToLive, X as isTruthyCfnBoolean, Xs as isWarmThroughputDecrease, Y as hasCdkAutoDeleteTag, Ys as coerceWarmThroughput$1, Z as getPriorAttempts, Zs as toCfnInteger, _ as streamMemberRefusals, _a as isTerminationProtectionPropagationError, _c as canonicalLambdaFunctionName, _l as carriesSecretMask, _t as enclosingDeadlineRemainingMs, aa as onlySecretReferencesDiffer, ac as replayWarn, al as dynamicReferenceTokens, b as CONTRIBUTOR_INSIGHTS_KEY, ba as reEnableInstanceApiTermination, c as DynamoDBGlobalTableProvider, cc as requireConfigString, cd as decodeListingKey, ct as isAbsoluteAssetPath, d as declaredStreamPolicyMember, da as deleteSkipReason, dd as canonicalizeRegion, di as secretNamedAttributeNamesOf, ec as coerceCfnInteger, en as lookupEachName, f as declaredStreamTagsMember, fa as withIndeterminateGuard, fc as withRetry, fd as derivePartitionAndUrlSuffix, fl as recoverMaskedOutput, g as streamDeclaresTags, ga as ec2InstanceProtectionSite, gc as emrClusterInstancesReplaced, gt as enclosingDeadlineExpired, h as streamDeclaresPolicy, hc as ecsServiceLaunchTypeSetOrChanged, ia as slowCcOperationTimeoutMs, ic as readConfigString, iu as stringifyValue, j as beginDeleteWait, ja as isSettledInstanceState, jc as passedNoEchoParametersOf, jr as awaitInFlightSibling, k as DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS, l as STREAM_POLICY_KEY, lt as listNestedTemplateRows, lu as rewriteTemplateAssetReferences, m as reverseMapStreamPolicy, ma as markWaitAbandoned, ml as recordAttributeIdCopy, nc as configIntegerRefusal, oa as unchangedBehindSecretReference, oc as requireConfigArray, p as planStreamMemberOps, pa as isWaitAbandonedError, pc as blockDeviceMappingsDifferOnlyInDeleteOnTermination, pl as physicalNameCopiesOf, q as ECR_AUTO_DELETE_IMAGES_TAG, rc as configStringRefusal, rl as withoutPhysicalNameCopies, rs as refuseMalformedNestedChildOutputs, sc as requireConfigObject, so as getAccountInfo, st as findNestedTemplateTreeDefect, t as DeployEngine, tc as configBooleanRefusal, tn as withApiLimit, tu as timePhase, u as STREAM_TAGS_KEY, ut as renderNestedTemplateTreeDefect, v as streamPolicyMatchesDeclared, va as observeThenDisableInstanceApiTermination, vc as lambdaFunctionNameForMask, vo as parseWebACLArn, w as planIndexContributorInsightsOps, wi as earliestDefined, x as contributorInsightsRefusals, xo as passedParameterClassesOf, y as streamTagsMatchDeclared, ya as reDisableInstanceApiTermination, yc as sameLambdaFunctionAddress, z as maskedLogger, zc as recordReferenceProvenanceEntry, zi as tagMapAsList, zn as redactedDeleteAddressFields, zs as withoutSilentDropProperties } from "./deploy-engine-BF5exXUb.js";
6
+ import { n as collectInlinePolicyNamesManagedBySiblings, r as IamCreateClientCache, t as IAMRoleProvider } from "./iam-role-provider-qvhlVnrn.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-DbnTHlwR.js";
8
+ import { t as modifyDbInstanceWhenAvailable } from "./db-instance-modify-retry-1y0kIPCO.js";
9
+ import { RDSProvider } from "./rds-provider-0LUsn9Wl.js";
10
+ import { NeptuneProvider } from "./neptune-provider-D9ac71Ca.js";
11
+ import { ASGProvider } from "./asg-provider-CIg_guZ-.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";
@@ -57,7 +57,7 @@ import { AccessPointAlreadyExists, AccessPointNotFound, CreateAccessPointCommand
57
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
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
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";
@@ -656,6 +656,7 @@ var IAMManagedPolicyProvider = class {
656
656
  if (!policyArn) throw new ProvisioningError(`CreatePolicy succeeded but no Arn returned for ${logicalId}`, resourceType, logicalId, policyName);
657
657
  leftBehindArn = policyArn;
658
658
  createdPolicyIdentity = policyIdentityToken(response.Policy?.PolicyId);
659
+ reportCreatedResource(logicalId, resourceType, policyArn, createdPolicyIdentity);
659
660
  log.debug(`Created IAM managed policy: ${v(policyArn)}`);
660
661
  try {
661
662
  await this.attachToPrincipals(policyArn, principals.lists.Groups, principals.lists.Roles, principals.lists.Users, log);
@@ -664,6 +665,7 @@ var IAMManagedPolicyProvider = class {
664
665
  await this.detachAllPrincipals(policyArn);
665
666
  await this.deleteAllNonDefaultVersions(policyArn);
666
667
  await this.iamClient.send(new DeletePolicyCommand({ PolicyArn: policyArn }));
668
+ retractCreatedResource(logicalId, resourceType, policyArn);
667
669
  leftBehindArn = void 0;
668
670
  log.debug(`Cleaned up partially-created managed policy ${logicalId} (${v(policyArn)}) after attachment failure`);
669
671
  } catch (cleanupError) {
@@ -1263,6 +1265,7 @@ var IAMInstanceProfileProvider = class {
1263
1265
  }));
1264
1266
  leftBehind = true;
1265
1267
  createdProfileIdentity = instanceProfileIdentityToken(response.InstanceProfile?.InstanceProfileId);
1268
+ reportCreatedResource(logicalId, resourceType, instanceProfileName, createdProfileIdentity);
1266
1269
  log.debug(`Created IAM instance profile: ${v(instanceProfileName)}`);
1267
1270
  const attachedRoles = [];
1268
1271
  try {
@@ -1285,6 +1288,7 @@ var IAMInstanceProfileProvider = class {
1285
1288
  if (!(err instanceof NoSuchEntityException)) throw err;
1286
1289
  }
1287
1290
  await this.iamClient.send(new DeleteInstanceProfileCommand({ InstanceProfileName: instanceProfileName }));
1291
+ retractCreatedResource(logicalId, resourceType, instanceProfileName);
1288
1292
  leftBehind = false;
1289
1293
  log.debug(`Cleaned up partially-created IAM instance profile ${logicalId} (${v(instanceProfileName)}) after wiring failure`);
1290
1294
  } catch (cleanupError) {
@@ -1534,12 +1538,14 @@ var IAMAccessKeyProvider = class {
1534
1538
  const accessKeyId = response.AccessKey?.AccessKeyId;
1535
1539
  const secretAccessKey = response.AccessKey?.SecretAccessKey;
1536
1540
  leftBehindKeyId = accessKeyId;
1541
+ reportCreatedResource(logicalId, resourceType, accessKeyId ?? "");
1537
1542
  if (!accessKeyId || !secretAccessKey) {
1538
1543
  if (accessKeyId) try {
1539
1544
  await this.iamClient.send(new DeleteAccessKeyCommand({
1540
1545
  UserName: userName,
1541
1546
  AccessKeyId: accessKeyId
1542
1547
  }));
1548
+ retractCreatedResource(logicalId, resourceType, accessKeyId);
1543
1549
  leftBehindKeyId = void 0;
1544
1550
  } catch (cleanupError) {
1545
1551
  const lead = `Failed to clean up IAM access key ${logicalId} (${v(accessKeyId)}) minted by a partial CreateAccessKey response`;
@@ -1559,6 +1565,7 @@ var IAMAccessKeyProvider = class {
1559
1565
  UserName: userName,
1560
1566
  AccessKeyId: accessKeyId
1561
1567
  }));
1568
+ retractCreatedResource(logicalId, resourceType, accessKeyId);
1562
1569
  leftBehindKeyId = void 0;
1563
1570
  log.debug(`Cleaned up partially-created IAM access key ${logicalId} (${v(accessKeyId)}) after status wiring failure`);
1564
1571
  } catch (cleanupError) {
@@ -1584,7 +1591,10 @@ var IAMAccessKeyProvider = class {
1584
1591
  };
1585
1592
  } catch (error) {
1586
1593
  const reconciled = await this.deleteOrphanFromFailedAttempt(userName, logicalId, baseline, attemptStartMs, log);
1587
- if (leftBehindKeyId !== void 0 && reconciled.has(leftBehindKeyId)) leftBehindKeyId = void 0;
1594
+ if (leftBehindKeyId !== void 0 && reconciled.has(leftBehindKeyId)) {
1595
+ retractCreatedResource(logicalId, resourceType, leftBehindKeyId);
1596
+ leftBehindKeyId = void 0;
1597
+ }
1588
1598
  const cause = error instanceof Error ? error : void 0;
1589
1599
  const thrown = this.wrapMaskedError(log, error, (text) => new ProvisioningError(`Failed to create IAM access key ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
1590
1600
  if (leftBehindKeyId !== void 0) {
@@ -1935,6 +1945,7 @@ var IAMUserGroupProvider = class {
1935
1945
  const response = await (await this.createClient.get()).send(new CreateUserCommand(createParams));
1936
1946
  leftBehind = true;
1937
1947
  createdUserIdentity = userOrGroupIdentityToken(response.User?.UserId);
1948
+ reportCreatedResource(logicalId, resourceType, userName, createdUserIdentity);
1938
1949
  try {
1939
1950
  const permissionsBoundary = properties["PermissionsBoundary"];
1940
1951
  if (permissionsBoundary) {
@@ -1995,6 +2006,7 @@ var IAMUserGroupProvider = class {
1995
2006
  if (!(err instanceof NoSuchEntityException)) throw err;
1996
2007
  }
1997
2008
  await this.iamClient.send(new DeleteUserCommand({ UserName: userName }));
2009
+ retractCreatedResource(logicalId, resourceType, userName);
1998
2010
  leftBehind = false;
1999
2011
  log.debug(`Cleaned up partially-created IAM user ${logicalId} (${v(userName)}) after wiring failure`);
2000
2012
  } catch (cleanupError) {
@@ -2337,6 +2349,7 @@ var IAMUserGroupProvider = class {
2337
2349
  const response = await (await this.createClient.get()).send(new CreateGroupCommand(createParams));
2338
2350
  leftBehind = true;
2339
2351
  createdGroupIdentity = userOrGroupIdentityToken(response.Group?.GroupId);
2352
+ reportCreatedResource(logicalId, resourceType, groupName, createdGroupIdentity);
2340
2353
  try {
2341
2354
  const managedPolicyArns = properties["ManagedPolicyArns"];
2342
2355
  if (managedPolicyArns && Array.isArray(managedPolicyArns)) for (const policyArn of managedPolicyArns) {
@@ -2361,6 +2374,7 @@ var IAMUserGroupProvider = class {
2361
2374
  await this.detachAllGroupPolicies(groupName, log);
2362
2375
  await this.deleteAllGroupInlinePolicies(groupName, log);
2363
2376
  await this.iamClient.send(new DeleteGroupCommand({ GroupName: groupName }));
2377
+ retractCreatedResource(logicalId, resourceType, groupName);
2364
2378
  leftBehind = false;
2365
2379
  log.debug(`Cleaned up partially-created IAM group ${logicalId} (${v(groupName)}) after wiring failure`);
2366
2380
  } catch (cleanupError) {
@@ -4803,6 +4817,7 @@ var S3BucketProvider = class S3BucketProvider {
4803
4817
  }
4804
4818
  createdNewBucket = adoptedOwnLeftover || preflight.kind === "absent";
4805
4819
  bucketLeftBehind = createdNewBucket;
4820
+ if (createdNewBucket) reportCreatedResource(logicalId, resourceType, bucketName);
4806
4821
  if (createdNewBucket) windowSpent = true;
4807
4822
  if (preflight.kind === "region" && preflight.region !== "us-east-1") this.refuseForeignRegionAdopt(logicalId, resourceType, bucketName, "us-east-1", preflight.region);
4808
4823
  if (preflight.kind === "region" && !adoptedOwnLeftover) this.logger.warn(`S3 bucket ${this.shown(bucketName)} for ${displaySafe(logicalId)} (${resourceType}) already existed in ${preflight.region} and was ADOPTED, not created. In us-east-1 S3 answers a re-create of a bucket you already own with 200 OK and RESETS that bucket's access control lists, so any ACL previously set on ${this.shown(bucketName)} is now the default. cdkd will not delete this bucket if the rest of this create fails.`);
@@ -4832,6 +4847,7 @@ var S3BucketProvider = class S3BucketProvider {
4832
4847
  if (createdNewBucket) try {
4833
4848
  await this.s3Client.send(new DeleteBucketCommand({ Bucket: bucketName }));
4834
4849
  bucketLeftBehind = false;
4850
+ retractCreatedResource(logicalId, resourceType, bucketName);
4835
4851
  this.logger.debug(`Cleaned up partially-created S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}) after wiring failure`);
4836
4852
  } catch (cleanupError) {
4837
4853
  this.logger.debug(`DeleteBucket cleanup failed for S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}): ${describeAwsFailure(cleanupError).detail}`);
@@ -6263,7 +6279,7 @@ function normalizeStatement(statement) {
6263
6279
  for (const key of PRINCIPAL_KEYS) if (Object.prototype.hasOwnProperty.call(out, key)) out[key] = normalizePrincipal(out[key]);
6264
6280
  return out;
6265
6281
  }
6266
- function canonicalJson$2(value) {
6282
+ function canonicalJson$3(value) {
6267
6283
  const sortKeys = (v) => {
6268
6284
  if (Array.isArray(v)) return v.map(sortKeys);
6269
6285
  if (v !== null && typeof v === "object") {
@@ -6287,7 +6303,7 @@ function policyContentKey(document) {
6287
6303
  if (Object.prototype.hasOwnProperty.call(doc, "Statement")) doc["Statement"] = (Array.isArray(doc["Statement"]) ? doc["Statement"] : [doc["Statement"]]).map(normalizeStatement);
6288
6304
  value = doc;
6289
6305
  }
6290
- return canonicalJson$2(value);
6306
+ return canonicalJson$3(value);
6291
6307
  }
6292
6308
 
6293
6309
  //#endregion
@@ -6565,7 +6581,7 @@ function listedQueues(bag) {
6565
6581
  function isListedQueueUrl(value) {
6566
6582
  return isSqsQueueUrl(value) && !value.includes(",") && !value.includes("*");
6567
6583
  }
6568
- function canonicalJson$1(value) {
6584
+ function canonicalJson$2(value) {
6569
6585
  const sortKeys = (v) => {
6570
6586
  if (Array.isArray(v)) return v.map(sortKeys);
6571
6587
  if (v !== null && typeof v === "object") {
@@ -6580,14 +6596,14 @@ function canonicalJson$1(value) {
6580
6596
  }
6581
6597
  function canonicalPolicy$1(text) {
6582
6598
  try {
6583
- return canonicalJson$1(JSON.parse(text));
6599
+ return canonicalJson$2(JSON.parse(text));
6584
6600
  } catch {
6585
6601
  return `raw:${text}`;
6586
6602
  }
6587
6603
  }
6588
6604
  function policyReference(document) {
6589
6605
  if (typeof document === "string" && document.length > 0) return canonicalPolicy$1(document);
6590
- if (document !== null && typeof document === "object") return canonicalJson$1(document);
6606
+ if (document !== null && typeof document === "object") return canonicalJson$2(document);
6591
6607
  }
6592
6608
  function splitQueueUrls(physicalId) {
6593
6609
  return physicalId.split(",").filter((url) => url.length > 0);
@@ -6683,7 +6699,8 @@ var SNSTopicProvider = class {
6683
6699
  if (properties["MaximumMessageSize"] != null) topicAttributes["MaximumMessageSize"] = stringifyValue(properties["MaximumMessageSize"]);
6684
6700
  let tags;
6685
6701
  if (properties["Tags"] != null) tags = desiredTags;
6686
- const heldBefore = Boolean(properties["ArchivePolicy"]) || Boolean(properties["DataProtectionPolicy"]) || properties["DeliveryStatusLogging"] != null || Array.isArray(properties["Subscription"]) ? await this.topicHeldBefore(topicName) : "free";
6702
+ const wiringDeclared = Boolean(properties["ArchivePolicy"]) || Boolean(properties["DataProtectionPolicy"]) || properties["DeliveryStatusLogging"] != null || Array.isArray(properties["Subscription"]);
6703
+ const heldBefore = wiringDeclared ? await this.topicHeldBefore(topicName) : "free";
6687
6704
  const createParams = {
6688
6705
  Name: topicName,
6689
6706
  ...Object.keys(topicAttributes).length > 0 && { Attributes: topicAttributes },
@@ -6691,6 +6708,7 @@ var SNSTopicProvider = class {
6691
6708
  };
6692
6709
  const topicArn = (await this.snsClient.send(new CreateTopicCommand(createParams))).TopicArn;
6693
6710
  if (!topicArn) throw new Error("CreateTopic did not return TopicArn");
6711
+ if (wiringDeclared && heldBefore === "free") reportCreatedResource(logicalId, resourceType, topicArn);
6694
6712
  try {
6695
6713
  if (properties["ArchivePolicy"]) {
6696
6714
  const archivePolicy = typeof properties["ArchivePolicy"] === "string" ? properties["ArchivePolicy"] : JSON.stringify(properties["ArchivePolicy"]);
@@ -6722,6 +6740,7 @@ var SNSTopicProvider = class {
6722
6740
  if (heldBefore !== "free") warn(skippedCleanupText(heldBefore, `SNS topic ${logicalId} (${topicArn})`, pasteableAwsCommand(maskSecrets)`aws sns delete-topic --topic-arn ${topicArn}`.render()));
6723
6741
  else try {
6724
6742
  await this.snsClient.send(new DeleteTopicCommand({ TopicArn: topicArn }));
6743
+ retractCreatedResource(logicalId, resourceType, topicArn);
6725
6744
  this.logger.debug(`Cleaned up partially-created SNS topic ${logicalId} (${topicArn}) after wiring failure`);
6726
6745
  } catch (cleanupError) {
6727
6746
  leftBehindArn = topicArn;
@@ -7609,7 +7628,7 @@ var SNSTopicPolicyProvider = class {
7609
7628
  if (candidates.length === 0) return [];
7610
7629
  let reference;
7611
7630
  if (typeof document === "string" && document.length > 0) reference = canonicalPolicy(document);
7612
- else if (document !== null && typeof document === "object") reference = canonicalJson(document);
7631
+ else if (document !== null && typeof document === "object") reference = canonicalJson$1(document);
7613
7632
  if (reference === void 0) {
7614
7633
  this.logger.warn(mask(safeMsg`The topics ${candidates.join(", ")} listed by ${logicalId} were not checked (no policy document recorded to compare with) and may still carry its policy.`));
7615
7634
  return [];
@@ -7726,7 +7745,7 @@ function defaultTopicPolicy(topicArn) {
7726
7745
  }]
7727
7746
  });
7728
7747
  }
7729
- function canonicalJson(value) {
7748
+ function canonicalJson$1(value) {
7730
7749
  const sortKeys = (v) => {
7731
7750
  if (Array.isArray(v)) return v.map(sortKeys);
7732
7751
  if (v !== null && typeof v === "object") {
@@ -7740,7 +7759,7 @@ function canonicalJson(value) {
7740
7759
  }
7741
7760
  function canonicalPolicy(text) {
7742
7761
  try {
7743
- return canonicalJson(JSON.parse(text));
7762
+ return canonicalJson$1(JSON.parse(text));
7744
7763
  } catch {
7745
7764
  return `raw:${text}`;
7746
7765
  }
@@ -8059,6 +8078,7 @@ var LambdaFunctionProvider = class {
8059
8078
  functionCreated = true;
8060
8079
  createdFunctionName = response.FunctionName || functionName;
8061
8080
  createdFunctionIdentity = functionIdentityToken(response.FunctionArn, response.LastModified);
8081
+ reportCreatedResource(logicalId, resourceType, createdFunctionName, createdFunctionIdentity);
8062
8082
  const recursiveLoop = properties["RecursiveLoop"];
8063
8083
  if (recursiveLoop !== void 0) await this.applyPostCreateConfig(() => this.lambdaClient.send(new PutFunctionRecursionConfigCommand({
8064
8084
  FunctionName: functionName,
@@ -8093,6 +8113,7 @@ var LambdaFunctionProvider = class {
8093
8113
  minDelay: 1,
8094
8114
  maxDelay: 5
8095
8115
  }, { FunctionName: functionName });
8116
+ reportCreatedResource(logicalId, resourceType, createdFunctionName);
8096
8117
  await this.putRuntimeManagementConfig(functionName, runtimeManagementConfig);
8097
8118
  createdFunctionIdentity = void 0;
8098
8119
  }, {
@@ -8117,6 +8138,7 @@ var LambdaFunctionProvider = class {
8117
8138
  const cause = error instanceof Error ? error : void 0;
8118
8139
  const thrown = this.wrapMaskedError(log, error, (text) => new ProvisioningError(`Failed to create Lambda function ${logicalId}: ${text}`, resourceType, logicalId, functionName, cause ?? new Error(safeStringify(error))));
8119
8140
  if (createdFunctionName !== void 0 && !postCreateCleanup.deleted) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdFunctionName, createdFunctionIdentity);
8141
+ else if (createdFunctionName !== void 0) retractCreatedResource(logicalId, resourceType, createdFunctionName);
8120
8142
  throw thrown;
8121
8143
  }
8122
8144
  }
@@ -10398,6 +10420,7 @@ var LambdaMicrovmImageProvider = class {
10398
10420
  const imageArn = response.imageArn;
10399
10421
  createdArn = imageArn;
10400
10422
  if (!imageArn) throw new ProvisioningError(`CreateMicrovmImage succeeded but no imageArn returned for ${logicalId}`, resourceType, logicalId);
10423
+ reportCreatedResource(logicalId, resourceType, imageArn);
10401
10424
  this.logger.debug(`Created MicroVM image ${logicalId}: ${imageArn} (state=${response.state})`);
10402
10425
  const noWait = process.env["CDKD_NO_WAIT"] === "true";
10403
10426
  let latest = {
@@ -10656,15 +10679,15 @@ function buildCommonImageInput(properties) {
10656
10679
  return input;
10657
10680
  }
10658
10681
  function mapCodeArtifact(value) {
10659
- if (!isRecord$1(value)) return void 0;
10682
+ if (!isRecord$2(value)) return void 0;
10660
10683
  const uri = value["Uri"];
10661
10684
  return typeof uri === "string" ? { uri } : void 0;
10662
10685
  }
10663
10686
  function mapLogging(value) {
10664
- if (!isRecord$1(value)) return void 0;
10687
+ if (!isRecord$2(value)) return void 0;
10665
10688
  if (value["Disabled"] === true) return { disabled: {} };
10666
10689
  const cloudWatch = value["CloudWatch"];
10667
- if (isRecord$1(cloudWatch)) {
10690
+ if (isRecord$2(cloudWatch)) {
10668
10691
  const cw = {};
10669
10692
  if (typeof cloudWatch["LogGroup"] === "string") cw.logGroup = cloudWatch["LogGroup"];
10670
10693
  if (typeof cloudWatch["LogStream"] === "string") cw.logStream = cloudWatch["LogStream"];
@@ -10673,32 +10696,32 @@ function mapLogging(value) {
10673
10696
  }
10674
10697
  function mapCpuConfigurations(value) {
10675
10698
  if (!Array.isArray(value)) return void 0;
10676
- return value.filter(isRecord$1).map((c) => ({ architecture: c["Architecture"] }));
10699
+ return value.filter(isRecord$2).map((c) => ({ architecture: c["Architecture"] }));
10677
10700
  }
10678
10701
  function mapResources(value) {
10679
10702
  if (!Array.isArray(value)) return void 0;
10680
- return value.filter(isRecord$1).map((r) => Number(r["MinimumMemoryInMiB"])).filter((n) => Number.isFinite(n)).map((minimumMemoryInMiB) => ({ minimumMemoryInMiB }));
10703
+ return value.filter(isRecord$2).map((r) => Number(r["MinimumMemoryInMiB"])).filter((n) => Number.isFinite(n)).map((minimumMemoryInMiB) => ({ minimumMemoryInMiB }));
10681
10704
  }
10682
10705
  function mapHooks(value) {
10683
- if (!isRecord$1(value)) return void 0;
10706
+ if (!isRecord$2(value)) return void 0;
10684
10707
  return lowerFirstKeysDeep(value);
10685
10708
  }
10686
10709
  function mapKeyValueListToRecord(value) {
10687
10710
  if (!Array.isArray(value)) return void 0;
10688
10711
  const out = {};
10689
- for (const entry of value) if (isRecord$1(entry) && typeof entry["Key"] === "string") out[entry["Key"]] = typeof entry["Value"] === "string" ? entry["Value"] : "";
10712
+ for (const entry of value) if (isRecord$2(entry) && typeof entry["Key"] === "string") out[entry["Key"]] = typeof entry["Value"] === "string" ? entry["Value"] : "";
10690
10713
  return Object.keys(out).length > 0 ? out : void 0;
10691
10714
  }
10692
10715
  function lowerFirstKeysDeep(value) {
10693
10716
  if (Array.isArray(value)) return value.map(lowerFirstKeysDeep);
10694
- if (isRecord$1(value)) {
10717
+ if (isRecord$2(value)) {
10695
10718
  const out = {};
10696
10719
  for (const [k, v] of Object.entries(value)) out[k.charAt(0).toLowerCase() + k.slice(1)] = lowerFirstKeysDeep(v);
10697
10720
  return out;
10698
10721
  }
10699
10722
  return value;
10700
10723
  }
10701
- function isRecord$1(value) {
10724
+ function isRecord$2(value) {
10702
10725
  return typeof value === "object" && value !== null && !Array.isArray(value);
10703
10726
  }
10704
10727
 
@@ -10784,7 +10807,10 @@ var LambdaWebFunctionRevisionProvider = class {
10784
10807
  throw error;
10785
10808
  }
10786
10809
  createdArn = response.revisionArn;
10787
- if (createdArn) revisionsCreatedByThisProcess.add(createdArn);
10810
+ if (createdArn) {
10811
+ revisionsCreatedByThisProcess.add(createdArn);
10812
+ reportCreatedResource(logicalId, resourceType, createdArn);
10813
+ }
10788
10814
  const replayWindow = replayedSendWindow(response, attemptStartMs);
10789
10815
  if (replayWindow !== void 0) await this.reportPossibleRevisionOrphans(logicalId, replayWindow, log, input.functionName);
10790
10816
  if (!createdArn || !response.revisionId) throw new ProvisioningError(`CreateWebFunctionRevision succeeded but returned no revision ARN for ${logicalIdShown(logicalId)}`, resourceType, logicalId);
@@ -10798,6 +10824,7 @@ var LambdaWebFunctionRevisionProvider = class {
10798
10824
  let leftBehindArn = createdArn;
10799
10825
  if (leftBehindArn) try {
10800
10826
  await this.delete(logicalId, leftBehindArn, resourceType, void 0, context?.maskSecrets ? { maskSecrets: context.maskSecrets } : void 0);
10827
+ retractCreatedResource(logicalId, resourceType, leftBehindArn);
10801
10828
  leftBehindArn = void 0;
10802
10829
  } catch (cleanupError) {
10803
10830
  log.warn(safeMsg`Failed to delete partially-created Lambda web function revision ${logicalId}: ${describeAwsFailure(cleanupError).detail}. The failed deploy records it for \`cdkd rollback --revert-failed\`, or delete it by hand`);
@@ -11167,6 +11194,7 @@ var LambdaWebFunctionEndpointProvider = class {
11167
11194
  try {
11168
11195
  createdArn = (await this.client.send(new CreateWebFunctionEndpointCommand(input))).endpointArn;
11169
11196
  if (!createdArn) throw new ProvisioningError(`CreateWebFunctionEndpoint succeeded but returned no endpoint ARN for ${logicalIdShown(logicalId)}`, resourceType, logicalId);
11197
+ reportCreatedResource(logicalId, resourceType, createdArn);
11170
11198
  const settled = await this.waitForSettled(input.functionName, input.endpointName, logicalId, resourceType, "create", void 0, context?.maskSecrets);
11171
11199
  return {
11172
11200
  physicalId: createdArn,
@@ -11510,6 +11538,7 @@ var LambdaNetworkConnectorProvider = class {
11510
11538
  try {
11511
11539
  createdArn = (await this.client.send(new CreateNetworkConnectorCommand(input))).Arn;
11512
11540
  if (!createdArn) throw new ProvisioningError(`CreateNetworkConnector succeeded but returned no ARN for ${logicalIdShown(logicalId)}`, resourceType, logicalId);
11541
+ reportCreatedResource(logicalId, resourceType, createdArn);
11513
11542
  const settled = await this.waitForSettled(createdArn, logicalId, "create");
11514
11543
  createToken.release();
11515
11544
  return {
@@ -11739,6 +11768,58 @@ function versionOfArn(arn) {
11739
11768
  return match ? Number(match[1]) : void 0;
11740
11769
  }
11741
11770
 
11771
+ //#endregion
11772
+ //#region src/provisioning/delete-gone-wait.ts
11773
+ async function waitForGoneAfterDelete(opts) {
11774
+ const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
11775
+ const now = opts.now ?? Date.now;
11776
+ const userTimeoutMs = resolvedResourceTimeoutMs(opts.resourceType);
11777
+ const maxWaitMs = userTimeoutMs === void 0 ? opts.maxWaitMs : Math.min(opts.maxWaitMs, userTimeoutMs / 2);
11778
+ const startedAt = now();
11779
+ const stopped = `${opts.what}: the delete was ACCEPTED by AWS, but cdkd stopped waiting for it to disappear`;
11780
+ const consequence = "AWS finishes the delete on its side; until it does, a create of the same name is refused with \"already exists\".";
11781
+ const watch = startInterruptWatch(`${opts.what} deletion wait`);
11782
+ try {
11783
+ let lastStatus;
11784
+ let sawNonFailedStatus = false;
11785
+ for (;;) {
11786
+ if (watch.isInterrupted()) {
11787
+ opts.logger.warn(safeMsg`${stopped} (interrupted). ${consequence}`);
11788
+ return;
11789
+ }
11790
+ try {
11791
+ const status = await opts.describe();
11792
+ if (status === void 0) {
11793
+ opts.logger.debug(safeMsg`${opts.what} is gone`);
11794
+ return;
11795
+ }
11796
+ const failure = opts.failedStatus?.(status);
11797
+ if (failure !== void 0) {
11798
+ if (sawNonFailedStatus || now() - startedAt >= opts.pollIntervalMs) throw markWaitAbandoned(failure);
11799
+ } else sawNonFailedStatus = true;
11800
+ lastStatus = status;
11801
+ opts.logger.debug(safeMsg`${opts.what} status: ${status}, waiting for it to disappear`);
11802
+ } catch (error) {
11803
+ if (isWaitAbandonedError(error)) throw error;
11804
+ if (!isThrottlingError(error) && !isTransientServerError(error)) {
11805
+ opts.logger.debug(safeMsg`${opts.what}: status read failed: ${describeAwsFailure(error).detail}`);
11806
+ opts.logger.warn(safeMsg`${stopped}: its status could not be read (${describeAwsFailure(error).summary}). ${consequence}`);
11807
+ return;
11808
+ }
11809
+ opts.logger.debug(safeMsg`${opts.what}: status read throttled or failed transiently, re-polling`);
11810
+ }
11811
+ const remainingMs = maxWaitMs - (now() - startedAt);
11812
+ if (remainingMs <= 0) {
11813
+ opts.logger.warn(safeMsg`${stopped} after ${Math.round(maxWaitMs / 1e3)}s` + safeMsg`${lastStatus !== void 0 ? ` (last status: ${lastStatus})` : ""}. ${consequence}`);
11814
+ return;
11815
+ }
11816
+ await sleep(Math.min(opts.pollIntervalMs, remainingMs));
11817
+ }
11818
+ } finally {
11819
+ watch.dispose();
11820
+ }
11821
+ }
11822
+
11742
11823
  //#endregion
11743
11824
  //#region src/provisioning/providers/dynamodb-table-provider.ts
11744
11825
  function isTableName(id) {
@@ -12150,6 +12231,10 @@ const tableNameReleaseWait = {
12150
12231
  maxPolls: 600,
12151
12232
  intervalMs: INDEX_SETTLE_POLL_INTERVAL_MS
12152
12233
  };
12234
+ const tableDeleteGoneWait = {
12235
+ maxWaitMs: 600 * DYNAMODB_DELETE_POLL_COST_MS,
12236
+ pollIntervalMs: INDEX_SETTLE_POLL_INTERVAL_MS
12237
+ };
12153
12238
  var DynamoDBTableProvider = class {
12154
12239
  dynamoDBClient;
12155
12240
  createClient;
@@ -12280,6 +12365,7 @@ var DynamoDBTableProvider = class {
12280
12365
  const createOut = await (await this.getCreateClient()).send(new CreateTableCommand(createParams));
12281
12366
  tableCreated = true;
12282
12367
  createdTableId = createOut?.TableDescription?.TableId;
12368
+ reportCreatedResource(logicalId, resourceType, tableName, createdTableId);
12283
12369
  this.logger.debug(`CreateTable initiated for ${tableName}, waiting for ACTIVE status`);
12284
12370
  const tableInfo = await timePhase("provider waits", "DynamoDB table: wait for ACTIVE", () => this.waitForTableActive(tableName), logicalId);
12285
12371
  await this.applyPointInTimeRecovery(tableName, properties["PointInTimeRecoverySpecification"], void 0, maskSecrets);
@@ -12307,6 +12393,7 @@ var DynamoDBTableProvider = class {
12307
12393
  if (tableCreated) {
12308
12394
  try {
12309
12395
  await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: tableName }));
12396
+ retractCreatedResource(logicalId, resourceType, tableName);
12310
12397
  debug(`Rolled back partially-created DynamoDB table ${tableName}`);
12311
12398
  } catch (cleanupError) {
12312
12399
  tableLeftBehind = true;
@@ -12370,7 +12457,10 @@ var DynamoDBTableProvider = class {
12370
12457
  let latestStreamArn = table?.LatestStreamArn;
12371
12458
  if (table?.TableArn) await this.applyTagDiff(table.TableArn, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], {
12372
12459
  forceUpsert: context?.unsettledProperties?.has("Tags") === true,
12373
- beforeWrite: () => markUnsettled("Tags")
12460
+ beforeWrite: () => markUnsettled("Tags"),
12461
+ afterAdded: (keys) => {
12462
+ if (keys.length > 0) context?.markAttempted?.("Tags", keys);
12463
+ }
12374
12464
  });
12375
12465
  const normalizeTableClass = (v) => typeof v === "string" && v.length > 0 ? v : "STANDARD";
12376
12466
  const tableClassChanged = normalizeTableClass(properties["TableClass"]) !== normalizeTableClass(previousProperties["TableClass"]);
@@ -12595,7 +12685,7 @@ var DynamoDBTableProvider = class {
12595
12685
  if (context?.unsettledProperties?.has("GlobalSecondaryIndexes") === true && currentLiveIndexNames !== void 0) this.warnUndeclaredLiveIndexes(physicalId, currentLiveIndexNames, [previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"]], maskSecrets);
12596
12686
  if (JSON.stringify(properties["GlobalSecondaryIndexes"]) !== JSON.stringify(previousProperties["GlobalSecondaryIndexes"])) {
12597
12687
  markUnsettled("GlobalSecondaryIndexes");
12598
- await this.applyGsiUpdates(physicalId, resourceType, logicalId, previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"], properties["AttributeDefinitions"], gsiHandledByBillingFlip, currentLiveIndexNames, currentLiveIndexByName, liveCapacityComparable, effectiveBillingMode === "PAY_PER_REQUEST", maskSecrets);
12688
+ await this.applyGsiUpdates(physicalId, resourceType, logicalId, previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"], properties["AttributeDefinitions"], gsiHandledByBillingFlip, currentLiveIndexNames, currentLiveIndexByName, liveCapacityComparable, effectiveBillingMode === "PAY_PER_REQUEST", maskSecrets, (indexName) => context?.markAttempted?.("GlobalSecondaryIndexes", [indexName]));
12599
12689
  }
12600
12690
  if (JSON.stringify(properties["PointInTimeRecoverySpecification"]) !== JSON.stringify(previousProperties["PointInTimeRecoverySpecification"])) {
12601
12691
  markUnsettled("PointInTimeRecoverySpecification");
@@ -12743,6 +12833,22 @@ var DynamoDBTableProvider = class {
12743
12833
  },
12744
12834
  sleepSeam: deleteTableRetryDelays
12745
12835
  });
12836
+ const mask = maskerOrIdentity(context?.maskSecrets);
12837
+ await waitForGoneAfterDelete({
12838
+ what: mask(`DynamoDB table ${physicalId}`),
12839
+ resourceType,
12840
+ describe: async () => {
12841
+ try {
12842
+ return (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table?.TableStatus ?? "UNKNOWN";
12843
+ } catch (describeError) {
12844
+ if (describeError instanceof ResourceNotFoundException$1) return void 0;
12845
+ throw describeError;
12846
+ }
12847
+ },
12848
+ logger: loopLogger,
12849
+ pollIntervalMs: tableDeleteGoneWait.pollIntervalMs,
12850
+ maxWaitMs: Math.min(tableDeleteGoneWait.maxWaitMs, budget.remainingMs())
12851
+ });
12746
12852
  this.logger.debug(`Successfully deleted DynamoDB table ${logicalId}`);
12747
12853
  this.deleteBudgets.release(deleteBudgetKey(physicalId, context?.expectedRegion));
12748
12854
  this.protectionFlips.release(deleteBudgetKey(physicalId, context?.expectedRegion));
@@ -12786,6 +12892,13 @@ var DynamoDBTableProvider = class {
12786
12892
  ResourceArn: tableArn,
12787
12893
  Tags: tagsToAdd
12788
12894
  }));
12895
+ let recordedKeys;
12896
+ try {
12897
+ recordedKeys = /* @__PURE__ */ new Set([...planTagDiff(void 0, oldTagsRaw).set.keys()]);
12898
+ } catch {
12899
+ recordedKeys = void 0;
12900
+ }
12901
+ unsettled.afterAdded?.(tagsToAdd.map((t) => t.Key).filter((key) => recordedKeys !== void 0 && !recordedKeys.has(key)));
12789
12902
  this.logger.debug(`Added/updated ${tagsToAdd.length} tag(s) on DynamoDB table ${tableArn}`);
12790
12903
  }
12791
12904
  }
@@ -13159,7 +13272,7 @@ var DynamoDBTableProvider = class {
13159
13272
  }
13160
13273
  throw new Error(`Table ${tableName} and its global secondary indexes did not reach ACTIVE within ${maxAttempts} seconds after UpdateTable`);
13161
13274
  }
13162
- async applyGsiUpdates(physicalId, resourceType, logicalId, previousGsis, desiredGsis, desiredAttributeDefinitions, handledByBillingFlip, liveIndexNames, liveIndexByName, liveCapacityComparable, onDemandCeilingsSendable, maskSecrets) {
13275
+ async applyGsiUpdates(physicalId, resourceType, logicalId, previousGsis, desiredGsis, desiredAttributeDefinitions, handledByBillingFlip, liveIndexNames, liveIndexByName, liveCapacityComparable, onDemandCeilingsSendable, maskSecrets, onCreated = () => void 0) {
13163
13276
  const warn = (message) => this.logger.warn(maskSecrets(message));
13164
13277
  const debug = (message) => this.logger.debug(maskSecrets(message));
13165
13278
  const prev = previousGsis ?? [];
@@ -13234,7 +13347,7 @@ var DynamoDBTableProvider = class {
13234
13347
  }
13235
13348
  if (updateHasMember) ops.push({ Update: update });
13236
13349
  }
13237
- await this.runGsiOps(physicalId, ops, desiredAttributeDefinitions, maskSecrets);
13350
+ await this.runGsiOps(physicalId, ops, desiredAttributeDefinitions, maskSecrets, onCreated);
13238
13351
  }
13239
13352
  coerceWarmThroughputForSend(scope, value, maskSecrets) {
13240
13353
  const warn = (message) => this.logger.warn(maskSecrets(message));
@@ -13398,7 +13511,7 @@ var DynamoDBTableProvider = class {
13398
13511
  }
13399
13512
  return sendable;
13400
13513
  }
13401
- async runGsiOps(physicalId, ops, desiredAttributeDefinitions, maskSecrets) {
13514
+ async runGsiOps(physicalId, ops, desiredAttributeDefinitions, maskSecrets, onCreated = () => void 0) {
13402
13515
  const debug = (message) => this.logger.debug(maskSecrets(message));
13403
13516
  for (const op of ops) {
13404
13517
  const input = {
@@ -13407,6 +13520,7 @@ var DynamoDBTableProvider = class {
13407
13520
  };
13408
13521
  if (op.Create && desiredAttributeDefinitions) input.AttributeDefinitions = desiredAttributeDefinitions;
13409
13522
  await this.dynamoDBClient.send(new UpdateTableCommand(input));
13523
+ if (op.Create?.IndexName !== void 0) onCreated(op.Create.IndexName);
13410
13524
  await this.waitForTableAndIndexesActive(physicalId);
13411
13525
  debug(`${op.Create ? "created" : op.Delete ? "deleted" : "updated"} ${this.indexScopeAt(op.Create?.IndexName ?? op.Delete?.IndexName ?? op.Update?.IndexName, physicalId, maskSecrets)}`);
13412
13526
  }
@@ -13547,13 +13661,13 @@ var DynamoDBTableProvider = class {
13547
13661
  aws
13548
13662
  };
13549
13663
  }
13550
- async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties) {
13664
+ async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties, attemptedItems) {
13551
13665
  const live = await this.readCurrentState(physicalId, logicalId, resourceType, recordedProperties);
13552
13666
  if (typeof live !== "object" || live === null) return live;
13553
13667
  const out = { ...live };
13554
13668
  if (out["BillingMode"] === "PAY_PER_REQUEST") delete out["ProvisionedThroughput"];
13555
13669
  if (names.has("GlobalSecondaryIndexes")) {
13556
- out["GlobalSecondaryIndexes"] = projectIndexesOnto(out["GlobalSecondaryIndexes"], recordedProperties?.["GlobalSecondaryIndexes"], desiredProperties?.["GlobalSecondaryIndexes"]);
13670
+ out["GlobalSecondaryIndexes"] = projectIndexesOnto(out["GlobalSecondaryIndexes"], recordedProperties?.["GlobalSecondaryIndexes"], desiredProperties?.["GlobalSecondaryIndexes"], attemptedItems?.get("GlobalSecondaryIndexes"));
13557
13671
  if (out["GlobalSecondaryIndexes"] === void 0) delete out["GlobalSecondaryIndexes"];
13558
13672
  }
13559
13673
  const strict = async (key, read) => {
@@ -13870,9 +13984,9 @@ var DynamoDBTableProvider = class {
13870
13984
  function isTransientStreamReadFailure(err) {
13871
13985
  return isThrottlingError(err) || isTransientServerError(err) || isAmbiguousOutcomeError(err) || err instanceof ResourceNotFoundException$1;
13872
13986
  }
13873
- function projectIndexesOnto(live, recorded, desired) {
13987
+ function projectIndexesOnto(live, recorded, desired, attempted = /* @__PURE__ */ new Set()) {
13874
13988
  if (!Array.isArray(live)) return void 0;
13875
- const named = /* @__PURE__ */ new Set();
13989
+ const named = new Set([...attempted].filter(isUsableAttemptedName));
13876
13990
  for (const list of [recorded, desired]) {
13877
13991
  if (!Array.isArray(list)) continue;
13878
13992
  for (const entry of list) {
@@ -13928,7 +14042,7 @@ var LogsLogGroupProvider = class {
13928
14042
  "DeletionProtectionEnabled",
13929
14043
  "BearerTokenAuthenticationEnabled"
13930
14044
  ])]]);
13931
- unhandledByDesign = /* @__PURE__ */ new Map([["AWS::Logs::LogGroup", /* @__PURE__ */ new Map([["ResourcePolicyDocument", "covered by the separate account-wide AWS::Logs::ResourcePolicy resource type; logs:PutResourcePolicy is account-scoped, not per-log-group, so it has no CreateLogGroup / PutRetentionPolicy counterpart — routed via Cloud Control instead"]])]]);
14045
+ unhandledByDesign = /* @__PURE__ */ new Map([["AWS::Logs::LogGroup", /* @__PURE__ */ new Map([["ResourcePolicyDocument", "not driven by this provider by decision (issue #1412): no CreateLogGroup / PutRetentionPolicy member carries it, and both policy lifecycles — the account-scoped AWS::Logs::ResourcePolicy type and the log-group-scoped logs:PutResourcePolicy (resourceArn + policyScope RESOURCE) — are ones this provider does not take on — routed via Cloud Control, whose handler applies it"]])]]);
13932
14046
  constructor() {
13933
14047
  const awsClients = getAwsClients();
13934
14048
  this.logsClient = awsClients.cloudWatchLogs;
@@ -13991,6 +14105,7 @@ var LogsLogGroupProvider = class {
13991
14105
  await this.logsClient.send(new CreateLogGroupCommand(createParams));
13992
14106
  createdNewLogGroup = true;
13993
14107
  leftBehind = true;
14108
+ reportCreatedResource(logicalId, resourceType, logGroupName);
13994
14109
  } catch (createError) {
13995
14110
  if (createError instanceof ResourceAlreadyExistsException) this.logger.debug(`Log group ${logGroupName} already exists, using existing`);
13996
14111
  else throw createError;
@@ -14037,6 +14152,7 @@ var LogsLogGroupProvider = class {
14037
14152
  if (createdNewLogGroup) try {
14038
14153
  await this.logsClient.send(new DeleteLogGroupCommand({ logGroupName }));
14039
14154
  leftBehind = false;
14155
+ retractCreatedResource(logicalId, resourceType, logGroupName);
14040
14156
  this.logger.debug(`Cleaned up partially-created log group ${displaySafe(logicalId)} (${displaySafe(logGroupName)}) after wiring failure`);
14041
14157
  } catch (cleanupError) {
14042
14158
  const mask = maskerOrIdentity(context?.maskSecrets);
@@ -14387,6 +14503,29 @@ var LogsLogGroupProvider = class {
14387
14503
 
14388
14504
  //#endregion
14389
14505
  //#region src/provisioning/providers/cloudwatch-alarm-provider.ts
14506
+ function isDefaultEvaluationWindow(value) {
14507
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
14508
+ const keys = Object.keys(value);
14509
+ if (keys.length !== 1 || keys[0] !== "SlidingWindow") return false;
14510
+ const sliding = value["SlidingWindow"];
14511
+ return sliding !== null && typeof sliding === "object" && !Array.isArray(sliding) && Object.keys(sliding).length === 0;
14512
+ }
14513
+ const PROMQL_EXCLUDED_MEMBERS = [
14514
+ "Namespace",
14515
+ "MetricName",
14516
+ "Dimensions",
14517
+ "Period",
14518
+ "Unit",
14519
+ "Statistic",
14520
+ "ExtendedStatistic",
14521
+ "Metrics",
14522
+ "Threshold",
14523
+ "ComparisonOperator",
14524
+ "ThresholdMetricId",
14525
+ "EvaluationPeriods",
14526
+ "DatapointsToAlarm",
14527
+ "EvaluationWindow"
14528
+ ];
14390
14529
  function isAlarmWriteThrottle(error) {
14391
14530
  return isThrottlingError(error) || error instanceof Error && error.message.includes("Rate exceeded");
14392
14531
  }
@@ -14422,9 +14561,13 @@ var CloudWatchAlarmProvider = class {
14422
14561
  "Tags",
14423
14562
  "ExtendedStatistic",
14424
14563
  "EvaluateLowSampleCountPercentile",
14425
- "ThresholdMetricId"
14564
+ "ThresholdMetricId",
14565
+ "ActionConfiguration",
14566
+ "WarmUpConfiguration",
14567
+ "EvaluationWindow",
14568
+ "EvaluationCriteria",
14569
+ "EvaluationInterval"
14426
14570
  ])]]);
14427
- unhandledByDesign = /* @__PURE__ */ new Map([["AWS::CloudWatch::Alarm", /* @__PURE__ */ new Map([["EvaluationCriteria", "Absent from both the SDK PutMetricAlarm input and the aws-cdk-lib CfnAlarm L1 (a newer CFn-schema-only property ahead of SDK/CDK support); no wire path to forward it and no CDK app can emit it."], ["EvaluationInterval", "Absent from both the SDK PutMetricAlarm input and the aws-cdk-lib CfnAlarm L1 (a newer CFn-schema-only property ahead of SDK/CDK support); no wire path to forward it and no CDK app can emit it."]])]]);
14428
14571
  constructor() {
14429
14572
  const awsClients = getAwsClients();
14430
14573
  this.cloudWatchClient = awsClients.cloudWatch;
@@ -14573,7 +14716,12 @@ var CloudWatchAlarmProvider = class {
14573
14716
  Unit: emptyToUndefined(properties["Unit"]),
14574
14717
  ExtendedStatistic: emptyToUndefined(properties["ExtendedStatistic"]),
14575
14718
  EvaluateLowSampleCountPercentile: emptyToUndefined(properties["EvaluateLowSampleCountPercentile"]),
14576
- ThresholdMetricId: emptyToUndefined(properties["ThresholdMetricId"])
14719
+ ThresholdMetricId: emptyToUndefined(properties["ThresholdMetricId"]),
14720
+ ActionConfiguration: properties["ActionConfiguration"],
14721
+ WarmUpConfiguration: properties["WarmUpConfiguration"],
14722
+ EvaluationWindow: properties["EvaluationWindow"],
14723
+ EvaluationCriteria: properties["EvaluationCriteria"],
14724
+ EvaluationInterval: properties["EvaluationInterval"]
14577
14725
  };
14578
14726
  const metricsValue = properties["Metrics"];
14579
14727
  if (Array.isArray(metricsValue) && metricsValue.length > 0) params["Metrics"] = metricsValue.map((m) => {
@@ -14605,6 +14753,7 @@ var CloudWatchAlarmProvider = class {
14605
14753
  params["Period"] = properties["Period"];
14606
14754
  params["Statistic"] = emptyToUndefined(properties["Statistic"]);
14607
14755
  params["Dimensions"] = properties["Dimensions"];
14756
+ if (properties["EvaluationCriteria"] !== void 0 && Array.isArray(params["Dimensions"]) && params["Dimensions"].length === 0) delete params["Dimensions"];
14608
14757
  }
14609
14758
  return params;
14610
14759
  }
@@ -14615,30 +14764,40 @@ var CloudWatchAlarmProvider = class {
14615
14764
  }))).MetricAlarms?.[0];
14616
14765
  if (!alarm) return RESOURCE_NOT_FOUND;
14617
14766
  const result = {};
14767
+ const promql = alarm.EvaluationCriteria !== void 0;
14618
14768
  if (alarm.AlarmName !== void 0) result["AlarmName"] = alarm.AlarmName;
14619
14769
  result["AlarmDescription"] = alarm.AlarmDescription ?? "";
14620
- result["MetricName"] = alarm.MetricName ?? "";
14621
- result["Namespace"] = alarm.Namespace ?? "";
14622
- result["Statistic"] = alarm.Statistic ?? "";
14623
- if (alarm.ComparisonOperator !== void 0) result["ComparisonOperator"] = alarm.ComparisonOperator;
14624
- if (alarm.Threshold !== void 0) result["Threshold"] = alarm.Threshold;
14625
- if (alarm.EvaluationPeriods !== void 0) result["EvaluationPeriods"] = alarm.EvaluationPeriods;
14626
- if (alarm.Period !== void 0) result["Period"] = alarm.Period;
14627
- if (alarm.DatapointsToAlarm !== void 0) result["DatapointsToAlarm"] = alarm.DatapointsToAlarm;
14770
+ if (!promql) {
14771
+ result["MetricName"] = alarm.MetricName ?? "";
14772
+ result["Namespace"] = alarm.Namespace ?? "";
14773
+ result["Statistic"] = alarm.Statistic ?? "";
14774
+ if (alarm.ComparisonOperator !== void 0) result["ComparisonOperator"] = alarm.ComparisonOperator;
14775
+ if (alarm.Threshold !== void 0) result["Threshold"] = alarm.Threshold;
14776
+ if (alarm.EvaluationPeriods !== void 0) result["EvaluationPeriods"] = alarm.EvaluationPeriods;
14777
+ if (alarm.Period !== void 0) result["Period"] = alarm.Period;
14778
+ if (alarm.DatapointsToAlarm !== void 0) result["DatapointsToAlarm"] = alarm.DatapointsToAlarm;
14779
+ }
14628
14780
  result["ActionsEnabled"] = alarm.ActionsEnabled ?? true;
14629
14781
  result["AlarmActions"] = alarm.AlarmActions ? [...alarm.AlarmActions] : [];
14630
14782
  result["OKActions"] = alarm.OKActions ? [...alarm.OKActions] : [];
14631
14783
  result["InsufficientDataActions"] = alarm.InsufficientDataActions ? [...alarm.InsufficientDataActions] : [];
14632
14784
  result["TreatMissingData"] = alarm.TreatMissingData ?? "";
14633
- result["Unit"] = alarm.Unit ?? "";
14634
- result["Dimensions"] = (alarm.Dimensions ?? []).map((d) => ({
14635
- ...d.Name !== void 0 ? { Name: d.Name } : {},
14636
- ...d.Value !== void 0 ? { Value: d.Value } : {}
14637
- }));
14638
- result["Metrics"] = (alarm.Metrics ?? []).map((m) => m);
14639
- if (alarm.ExtendedStatistic !== void 0) result["ExtendedStatistic"] = alarm.ExtendedStatistic;
14785
+ if (!promql) {
14786
+ result["Unit"] = alarm.Unit ?? "";
14787
+ result["Dimensions"] = (alarm.Dimensions ?? []).map((d) => ({
14788
+ ...d.Name !== void 0 ? { Name: d.Name } : {},
14789
+ ...d.Value !== void 0 ? { Value: d.Value } : {}
14790
+ }));
14791
+ result["Metrics"] = (alarm.Metrics ?? []).map((m) => m);
14792
+ }
14793
+ if (!promql && alarm.ExtendedStatistic !== void 0) result["ExtendedStatistic"] = alarm.ExtendedStatistic;
14640
14794
  if (alarm.EvaluateLowSampleCountPercentile !== void 0) result["EvaluateLowSampleCountPercentile"] = alarm.EvaluateLowSampleCountPercentile;
14641
- if (alarm.ThresholdMetricId !== void 0) result["ThresholdMetricId"] = alarm.ThresholdMetricId;
14795
+ if (!promql && alarm.ThresholdMetricId !== void 0) result["ThresholdMetricId"] = alarm.ThresholdMetricId;
14796
+ if (alarm.ActionConfiguration !== void 0) result["ActionConfiguration"] = alarm.ActionConfiguration;
14797
+ if (alarm.WarmUpConfiguration !== void 0) result["WarmUpConfiguration"] = alarm.WarmUpConfiguration;
14798
+ if (!promql && alarm.EvaluationWindow !== void 0 && !isDefaultEvaluationWindow(alarm.EvaluationWindow)) result["EvaluationWindow"] = alarm.EvaluationWindow;
14799
+ if (alarm.EvaluationCriteria !== void 0) result["EvaluationCriteria"] = alarm.EvaluationCriteria;
14800
+ if (promql && alarm.EvaluationInterval !== void 0) result["EvaluationInterval"] = alarm.EvaluationInterval;
14642
14801
  if (alarm.AlarmArn) try {
14643
14802
  const tagsResp = await this.cloudWatchClient.send(new ListTagsForResourceCommand$4({ ResourceARN: alarm.AlarmArn }));
14644
14803
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
@@ -14647,6 +14806,26 @@ var CloudWatchAlarmProvider = class {
14647
14806
  }
14648
14807
  return result;
14649
14808
  }
14809
+ async canonicalizeDriftPair(resourceType, baseline, aws) {
14810
+ if (resourceType !== "AWS::CloudWatch::Alarm" || !isDefaultEvaluationWindow(baseline["EvaluationWindow"]) || aws["EvaluationWindow"] !== void 0) return {
14811
+ baseline,
14812
+ aws
14813
+ };
14814
+ const trimmed = { ...baseline };
14815
+ delete trimmed["EvaluationWindow"];
14816
+ return {
14817
+ baseline: trimmed,
14818
+ aws
14819
+ };
14820
+ }
14821
+ getDriftAbsentMeansDefaultKeys(resourceType, properties) {
14822
+ if (resourceType !== "AWS::CloudWatch::Alarm") return [];
14823
+ if (properties["EvaluationCriteria"] !== void 0) return [...PROMQL_EXCLUDED_MEMBERS].filter((key) => properties[key] === void 0);
14824
+ const keys = ["EvaluationCriteria", "EvaluationInterval"];
14825
+ const declared = properties["EvaluationWindow"];
14826
+ if (declared === void 0 || isDefaultEvaluationWindow(declared)) keys.push("EvaluationWindow");
14827
+ return keys;
14828
+ }
14650
14829
  generatedCreateName(_resourceType, logicalId, properties) {
14651
14830
  if (properties["AlarmName"]) return void 0;
14652
14831
  return generatedNameFor("AWS::CloudWatch::Alarm", logicalId);
@@ -15721,6 +15900,7 @@ var EventBridgeRuleProvider = class {
15721
15900
  if (properties["Tags"]) putRuleParams["Tags"] = desiredTags;
15722
15901
  const ruleArn = (await this.eventBridgeClient.send(new PutRuleCommand(putRuleParams))).RuleArn;
15723
15902
  this.logger.debug(`Created EventBridge rule: ${ruleName} (${ruleArn})`);
15903
+ if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, ruleArn);
15724
15904
  const eventBusName = properties["EventBusName"];
15725
15905
  try {
15726
15906
  if (targets && targets.length > 0) {
@@ -15750,6 +15930,7 @@ var EventBridgeRuleProvider = class {
15750
15930
  Name: ruleName,
15751
15931
  EventBusName: eventBusName
15752
15932
  }));
15933
+ retractCreatedResource(logicalId, resourceType, ruleArn);
15753
15934
  this.logger.debug(`Cleaned up partially-created EventBridge rule ${logicalId} (${ruleName}) after wiring failure`);
15754
15935
  } catch (cleanupError) {
15755
15936
  leftLiveArn = ruleArn;
@@ -16122,6 +16303,7 @@ var EventBridgeBusProvider = class {
16122
16303
  if (properties["LogConfig"] !== void 0) createParams.LogConfig = properties["LogConfig"];
16123
16304
  const response = await (await this.getCreateClient()).send(new CreateEventBusCommand(createParams));
16124
16305
  busCreated = true;
16306
+ reportCreatedResource(logicalId, resourceType, name);
16125
16307
  const policy = policyDocument(properties["Policy"]);
16126
16308
  if (policy !== void 0) await this.eventBridgeClient.send(new PutPermissionCommand({
16127
16309
  EventBusName: name,
@@ -17151,6 +17333,7 @@ var EC2Provider = class {
17151
17333
  }
17152
17334
  const vpcId = response.Vpc.VpcId;
17153
17335
  ec2IdsCreatedByThisProcess.add(vpcId);
17336
+ reportCreatedResource(logicalId, resourceType, vpcId);
17154
17337
  const vpcReplayWindow = replayedSendWindow(response, attemptStartMs);
17155
17338
  if (vpcReplayWindow !== void 0) await this.reportPossibleOrphanVpcs(logicalId, cidrBlock, desiredTags, vpcReplayWindow, context);
17156
17339
  let defaultSgId;
@@ -17179,6 +17362,7 @@ var EC2Provider = class {
17179
17362
  } catch (innerError) {
17180
17363
  try {
17181
17364
  await this.ec2Client.send(new DeleteVpcCommand({ VpcId: vpcId }));
17365
+ retractCreatedResource(logicalId, resourceType, vpcId);
17182
17366
  this.logger.debug(`Cleaned up partially-created VPC ${logicalId} (${vpcId}) after wiring failure`);
17183
17367
  } catch (cleanupError) {
17184
17368
  leftBehindId = vpcId;
@@ -17334,6 +17518,7 @@ var EC2Provider = class {
17334
17518
  }
17335
17519
  const subnetId = response.Subnet.SubnetId;
17336
17520
  ec2IdsCreatedByThisProcess.add(subnetId);
17521
+ reportCreatedResource(logicalId, resourceType, subnetId);
17337
17522
  const subnetReplayWindow = replayedSendWindow(response, attemptStartMs);
17338
17523
  if (subnetReplayWindow !== void 0) await this.reportPossibleOrphanSubnets(logicalId, vpcId, cidrBlock, desiredTags, subnetReplayWindow, context);
17339
17524
  const availabilityZone = response.Subnet.AvailabilityZone;
@@ -17350,6 +17535,7 @@ var EC2Provider = class {
17350
17535
  } catch (innerError) {
17351
17536
  try {
17352
17537
  await this.ec2Client.send(new DeleteSubnetCommand({ SubnetId: subnetId }));
17538
+ retractCreatedResource(logicalId, resourceType, subnetId);
17353
17539
  this.logger.debug(`Cleaned up partially-created Subnet ${logicalId} (${subnetId}) after wiring failure`);
17354
17540
  } catch (cleanupError) {
17355
17541
  leftBehindId = subnetId;
@@ -17604,6 +17790,7 @@ var EC2Provider = class {
17604
17790
  } catch {
17605
17791
  createdId = allocationId;
17606
17792
  }
17793
+ reportCreatedResource(logicalId, resourceType, createdId);
17607
17794
  ec2IdsCreatedByThisProcess.add(allocationId);
17608
17795
  const eipReplayWindow = replayedSendWindow(response, attemptStartMs);
17609
17796
  if (eipReplayWindow !== void 0) await this.reportPossibleOrphanAddresses(logicalId, input, desiredTags, eipReplayWindow, context);
@@ -17636,6 +17823,7 @@ var EC2Provider = class {
17636
17823
  } finally {
17637
17824
  watch.dispose();
17638
17825
  }
17826
+ retractCreatedResource(logicalId, resourceType, createdId);
17639
17827
  createdId = void 0;
17640
17828
  this.logger.debug(safeMsg`Released partially-created EIP ${logicalId} (${allocatedId})`);
17641
17829
  } catch (cleanupError) {
@@ -17772,6 +17960,7 @@ var EC2Provider = class {
17772
17960
  VpnGatewayId: gatewayId
17773
17961
  }));
17774
17962
  attachSent = true;
17963
+ reportCreatedResource(logicalId, resourceType, physicalId);
17775
17964
  await this.waitForVpnGatewayAttachment(gatewayId, vpcId, "attached", logicalId);
17776
17965
  }
17777
17966
  this.logger.debug(`Successfully created VPCGatewayAttachment ${logicalId}: ${physicalId}`);
@@ -18068,6 +18257,7 @@ var EC2Provider = class {
18068
18257
  })));
18069
18258
  const natGatewayId = response.NatGateway.NatGatewayId;
18070
18259
  createdId = natGatewayId;
18260
+ reportCreatedResource(logicalId, resourceType, natGatewayId);
18071
18261
  if (!tagsApplied) await this.applyTags(natGatewayId, desiredTags, logicalId, maskerOrIdentity(context?.maskSecrets));
18072
18262
  let described;
18073
18263
  if (process.env["CDKD_NO_WAIT"] !== "true") {
@@ -18465,6 +18655,7 @@ var EC2Provider = class {
18465
18655
  ...TagSpecifications && { TagSpecifications }
18466
18656
  })));
18467
18657
  const groupId = response.GroupId;
18658
+ reportCreatedResource(logicalId, resourceType, groupId);
18468
18659
  try {
18469
18660
  const ingressRules = properties["SecurityGroupIngress"];
18470
18661
  const egressRules = properties["SecurityGroupEgress"];
@@ -18481,6 +18672,7 @@ var EC2Provider = class {
18481
18672
  } catch (innerError) {
18482
18673
  try {
18483
18674
  await this.ec2Client.send(new DeleteSecurityGroupCommand({ GroupId: groupId }));
18675
+ retractCreatedResource(logicalId, resourceType, groupId);
18484
18676
  this.logger.debug(`Cleaned up partially-created SecurityGroup ${logicalId} (${groupId}) after wiring failure`);
18485
18677
  } catch (cleanupError) {
18486
18678
  leftBehindId = groupId;
@@ -19027,6 +19219,7 @@ var EC2Provider = class {
19027
19219
  const instance = response.Instances?.[0];
19028
19220
  if (!instance?.InstanceId) throw new Error("No instance ID returned from RunInstances");
19029
19221
  const instanceId = instance.InstanceId;
19222
+ reportCreatedResource(logicalId, resourceType, instanceId);
19030
19223
  try {
19031
19224
  if (!tagsApplied) await this.applyTags(instanceId, desiredTags, logicalId, maskerOrIdentity(context?.maskSecrets));
19032
19225
  if (process.env["CDKD_NO_WAIT"] !== "true") {
@@ -19056,6 +19249,7 @@ var EC2Provider = class {
19056
19249
  } catch (innerError) {
19057
19250
  try {
19058
19251
  await this.ec2Client.send(new TerminateInstancesCommand({ InstanceIds: [instanceId] }));
19252
+ retractCreatedResource(logicalId, resourceType, instanceId);
19059
19253
  runInstancesToken.release();
19060
19254
  this.logger.debug(`Terminate requested for partially-created EC2 Instance ${logicalId} (${instanceId}) after wiring failure (not waiting for terminated state)`);
19061
19255
  } catch (cleanupError) {
@@ -21655,6 +21849,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
21655
21849
  documentationVersion: properties["DocumentationVersion"],
21656
21850
  canarySettings: toSdkCanarySettings(properties["CanarySetting"])
21657
21851
  }));
21852
+ reportCreatedResource(logicalId, resourceType, stageName);
21658
21853
  const methodSettings = properties["MethodSettings"];
21659
21854
  const postCreateOps = buildMethodSettingsPatchOps(void 0, methodSettings);
21660
21855
  const accessLogSetting = properties["AccessLogSetting"];
@@ -21688,6 +21883,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
21688
21883
  restApiId,
21689
21884
  stageName
21690
21885
  }));
21886
+ retractCreatedResource(logicalId, resourceType, stageName);
21691
21887
  } catch (cleanupError) {
21692
21888
  stageLeftBehind = true;
21693
21889
  const cleanupFailure = describeAwsFailure(cleanupError);
@@ -21945,6 +22141,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
21945
22141
  }
21946
22142
  await putMethod();
21947
22143
  }
22144
+ reportCreatedResource(logicalId, resourceType, physicalId);
21948
22145
  try {
21949
22146
  const integration = properties["Integration"];
21950
22147
  if (integration) await this.apiGatewayClient.send(new PutIntegrationCommand(putIntegrationInput({
@@ -21973,6 +22170,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
21973
22170
  resourceId,
21974
22171
  httpMethod
21975
22172
  }));
22173
+ retractCreatedResource(logicalId, resourceType, physicalId);
21976
22174
  log.debug(`Cleaned up partially-created API Gateway Method ${logicalId} (${methodPath}) after wiring failure`);
21977
22175
  } catch (cleanupError) {
21978
22176
  methodLeftBehind = true;
@@ -25099,14 +25297,57 @@ function camelToPascalCaseKeys(value, preserveKeys) {
25099
25297
  //#region src/provisioning/providers/agentcore-runtime-provider.ts
25100
25298
  const CFN_MAP_KEYS = /* @__PURE__ */ new Set(["Tags", "AdvertisedScopeMapping"]);
25101
25299
  const SDK_MAP_KEYS = /* @__PURE__ */ new Set(["tags", "advertisedScopeMapping"]);
25300
+ const RUNTIME_TAGS_WHAT = "a map of tag keys to scalar values or a list of tags with a non-empty string Key and a scalar Value";
25301
+ function isUserTagKey(key) {
25302
+ return !key.startsWith("aws:");
25303
+ }
25304
+ function desiredRuntimeTags(raw, resourceType, logicalId, physicalId) {
25305
+ const tags = refuseMalformedDesiredTags(tagMapAsList(raw), resourceType, logicalId, physicalId, "Tags", RUNTIME_TAGS_WHAT);
25306
+ if (!tags.every((t) => isUserTagKey(t.Key))) throw markNonRetryable(new ProvisioningError(`${physicalId !== void 0 ? "desired " : ""}Tags of ${resourceType} ${logicalId} holds a reserved aws: key, which AWS does not let a user set — the resource was not ${physicalId !== void 0 ? "updated" : "created"}`, resourceType, logicalId, physicalId));
25307
+ return tags;
25308
+ }
25309
+ const CREATE_TAG_RETRY_DELAYS_MS = [
25310
+ 500,
25311
+ 1e3,
25312
+ 2e3,
25313
+ 4e3
25314
+ ];
25315
+ function isTransientTagFailure(error) {
25316
+ return isThrottlingError(error) || error instanceof ResourceNotFoundException$6 || error instanceof Error && error.name === "ResourceNotFoundException";
25317
+ }
25318
+ function isNonEmptyObject(value) {
25319
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length > 0;
25320
+ }
25321
+ function writeSharedRuntimeMembers(input, properties) {
25322
+ const requestHeaders = properties["RequestHeaderConfiguration"];
25323
+ if (isNonEmptyObject(requestHeaders)) input["requestHeaderConfiguration"] = pascalToCamelCaseKeys(requestHeaders, CFN_MAP_KEYS);
25324
+ const filesystems = properties["FilesystemConfigurations"];
25325
+ if (Array.isArray(filesystems) && filesystems.length > 0) input["filesystemConfigurations"] = pascalToCamelCaseKeys(filesystems, CFN_MAP_KEYS);
25326
+ const capacityProvider = properties["CapacityProviderConfiguration"];
25327
+ if (isNonEmptyObject(capacityProvider)) input["capacityProviderConfiguration"] = pascalToCamelCaseKeys(capacityProvider, CFN_MAP_KEYS);
25328
+ const platformVersion = properties["PlatformVersion"];
25329
+ if (platformVersion !== void 0 && platformVersion !== null && platformVersion !== "") input["platformVersion"] = platformVersion;
25330
+ }
25102
25331
  var AgentCoreRuntimeProvider = class {
25103
25332
  client;
25104
25333
  logger = getLogger().child("AgentCoreRuntimeProvider");
25334
+ sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
25335
+ async sendCreateTagCall(send) {
25336
+ for (let attempt = 0;; attempt++) try {
25337
+ return await send();
25338
+ } catch (error) {
25339
+ const delay = CREATE_TAG_RETRY_DELAYS_MS[attempt];
25340
+ if (delay === void 0 || !isTransientTagFailure(error)) throw error;
25341
+ this.logger.debug(safeMsg`Post-create tag call failed transiently (${describeAwsFailure(error).summary}); retrying in ${delay}ms`);
25342
+ await this.sleep(delay);
25343
+ }
25344
+ }
25105
25345
  wrapCaughtError(mask, error, build) {
25106
25346
  const failure = describeAwsFailure(error);
25107
25347
  if (!failure.redacted) return wrapMaskedAwsError(mask, error, build);
25108
25348
  this.logger.debug(mask(build(mask(failure.detail)).message));
25109
- const wrapped = build(`${mask(failure.summary)}${relayedNameCollision(failure.detail)}`);
25349
+ const relay = isAuxiliaryFailure(error) ? "" : relayedNameCollision(failure.detail);
25350
+ const wrapped = build(`${mask(failure.summary)}${relay}`);
25110
25351
  return error instanceof Error ? markRedactedCause(wrapped) : wrapped;
25111
25352
  }
25112
25353
  handledProperties = /* @__PURE__ */ new Map([["AWS::BedrockAgentCore::Runtime", /* @__PURE__ */ new Set([
@@ -25119,7 +25360,12 @@ var AgentCoreRuntimeProvider = class {
25119
25360
  "ProtocolConfiguration",
25120
25361
  "LifecycleConfiguration",
25121
25362
  "EnvironmentVariables",
25122
- "ClientToken"
25363
+ "ClientToken",
25364
+ "RequestHeaderConfiguration",
25365
+ "FilesystemConfigurations",
25366
+ "CapacityProviderConfiguration",
25367
+ "PlatformVersion",
25368
+ "Tags"
25123
25369
  ])]]);
25124
25370
  constructor() {
25125
25371
  const awsClients = getAwsClients();
@@ -25131,6 +25377,8 @@ var AgentCoreRuntimeProvider = class {
25131
25377
  if (!agentRuntimeName) throw new ProvisioningError(`AgentRuntimeName is required for ${logicalId}`, resourceType, logicalId);
25132
25378
  const roleArn = properties["RoleArn"];
25133
25379
  if (!roleArn) throw new ProvisioningError(`RoleArn is required for ${logicalId}`, resourceType, logicalId);
25380
+ const desiredTags = desiredRuntimeTags(properties["Tags"], resourceType, logicalId);
25381
+ let createdRuntimeId;
25134
25382
  try {
25135
25383
  const input = {
25136
25384
  agentRuntimeName,
@@ -25148,24 +25396,34 @@ var AgentCoreRuntimeProvider = class {
25148
25396
  if (properties["LifecycleConfiguration"] !== void 0 && typeof properties["LifecycleConfiguration"] === "object" && properties["LifecycleConfiguration"] !== null && Object.keys(properties["LifecycleConfiguration"]).length > 0) input["lifecycleConfiguration"] = pascalToCamelCaseKeys(properties["LifecycleConfiguration"], CFN_MAP_KEYS);
25149
25397
  if (properties["EnvironmentVariables"] !== void 0) input["environmentVariables"] = properties["EnvironmentVariables"];
25150
25398
  if (properties["ClientToken"] !== void 0) input["clientToken"] = properties["ClientToken"];
25399
+ writeSharedRuntimeMembers(input, properties);
25400
+ if (desiredTags.length > 0) input["tags"] = Object.fromEntries(desiredTags.map((t) => [t.Key, t.Value]));
25151
25401
  const response = await this.client.send(new CreateAgentRuntimeCommand(input));
25152
25402
  const agentRuntimeId = response.agentRuntimeId;
25153
25403
  const agentRuntimeArn = response.agentRuntimeArn;
25404
+ createdRuntimeId = agentRuntimeId;
25405
+ reportCreatedResource(logicalId, resourceType, agentRuntimeId);
25154
25406
  this.logger.debug(`Created BedrockAgentCore Runtime: ${agentRuntimeId} (${agentRuntimeArn})`);
25407
+ if (desiredTags.length > 0) await this.ensureCreateTags(agentRuntimeId, agentRuntimeArn, desiredTags);
25155
25408
  return {
25156
25409
  physicalId: agentRuntimeId,
25157
25410
  attributes: this.buildAttributes(response, agentRuntimeName)
25158
25411
  };
25159
25412
  } catch (error) {
25413
+ if (createdRuntimeId !== void 0) markAuxiliaryFailure(error, logicalId);
25160
25414
  const cause = error instanceof Error ? error : void 0;
25161
- throw this.wrapCaughtError(maskerOrIdentity(context?.maskSecrets), error, (text) => new ProvisioningError(`Failed to create BedrockAgentCore Runtime ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
25415
+ const thrown = this.wrapCaughtError(maskerOrIdentity(context?.maskSecrets), error, (text) => new ProvisioningError(`Failed to create BedrockAgentCore Runtime ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
25416
+ if (createdRuntimeId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdRuntimeId);
25417
+ throw thrown;
25162
25418
  }
25163
25419
  }
25164
- async update(logicalId, physicalId, resourceType, properties, _previousProperties, context) {
25420
+ async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
25165
25421
  this.logger.debug(`Updating BedrockAgentCore Runtime ${logicalId}: ${physicalId}`);
25166
25422
  assertRegionMatch(context?.expectedRegion ? await this.client.config.region() : void 0, context?.expectedRegion, resourceType, logicalId, physicalId, "pre-update");
25167
25423
  const roleArn = properties["RoleArn"];
25168
25424
  if (!roleArn) throw new ProvisioningError(`RoleArn is required for ${logicalId}`, resourceType, logicalId, physicalId);
25425
+ desiredRuntimeTags(properties["Tags"], resourceType, logicalId, physicalId);
25426
+ const mask = maskerOrIdentity(context?.maskSecrets);
25169
25427
  try {
25170
25428
  const input = {
25171
25429
  agentRuntimeId: physicalId,
@@ -25183,8 +25441,10 @@ var AgentCoreRuntimeProvider = class {
25183
25441
  if (properties["LifecycleConfiguration"] !== void 0 && typeof properties["LifecycleConfiguration"] === "object" && properties["LifecycleConfiguration"] !== null && Object.keys(properties["LifecycleConfiguration"]).length > 0) input["lifecycleConfiguration"] = pascalToCamelCaseKeys(properties["LifecycleConfiguration"], CFN_MAP_KEYS);
25184
25442
  if (properties["EnvironmentVariables"] !== void 0) input["environmentVariables"] = properties["EnvironmentVariables"];
25185
25443
  if (properties["ClientToken"] !== void 0) input["clientToken"] = properties["ClientToken"];
25444
+ writeSharedRuntimeMembers(input, properties);
25186
25445
  const response = await this.client.send(new UpdateAgentRuntimeCommand(input));
25187
25446
  const agentRuntimeId = response.agentRuntimeId;
25447
+ await this.syncTags(logicalId, resourceType, physicalId, response.agentRuntimeArn, previousProperties["Tags"], properties["Tags"], mask);
25188
25448
  this.logger.debug(`Successfully updated BedrockAgentCore Runtime ${logicalId}`);
25189
25449
  return {
25190
25450
  physicalId: agentRuntimeId,
@@ -25192,10 +25452,44 @@ var AgentCoreRuntimeProvider = class {
25192
25452
  attributes: this.buildAttributes(response, properties["AgentRuntimeName"])
25193
25453
  };
25194
25454
  } catch (error) {
25455
+ if (error instanceof CdkdError) throw error;
25195
25456
  const cause = error instanceof Error ? error : void 0;
25196
- throw this.wrapCaughtError(maskerOrIdentity(context?.maskSecrets), error, (text) => new ProvisioningError(`Failed to update BedrockAgentCore Runtime ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
25457
+ throw this.wrapCaughtError(mask, error, (text) => new ProvisioningError(`Failed to update BedrockAgentCore Runtime ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
25197
25458
  }
25198
25459
  }
25460
+ async ensureCreateTags(agentRuntimeId, resourceArn, desired) {
25461
+ let live;
25462
+ try {
25463
+ live = (await this.sendCreateTagCall(() => this.client.send(new ListTagsForResourceCommand$6({ resourceArn })))).tags ?? {};
25464
+ } catch (err) {
25465
+ this.logger.debug(safeMsg`Could not read the tags of new runtime ${agentRuntimeId} (${describeAwsFailure(err).detail}); setting every declared tag`);
25466
+ }
25467
+ const missing = Object.fromEntries(desired.filter((t) => live?.[t.Key] !== t.Value).map((t) => [t.Key, t.Value]));
25468
+ if (Object.keys(missing).length === 0) return;
25469
+ if (live !== void 0) this.logger.debug(safeMsg`New runtime ${agentRuntimeId} lacks ${Object.keys(missing).length} of the tag(s) CreateAgentRuntime was sent; setting them with TagResource`);
25470
+ await this.sendCreateTagCall(() => this.client.send(new TagResourceCommand$9({
25471
+ resourceArn,
25472
+ tags: missing
25473
+ })));
25474
+ }
25475
+ async syncTags(logicalId, resourceType, physicalId, responseArn, previousTagsRaw, nextTagsRaw, mask) {
25476
+ const plan = planTagDiff(tagMapAsList(previousTagsRaw), tagMapAsList(nextTagsRaw));
25477
+ const warning = tagPlanWarning(plan, resourceType, logicalId);
25478
+ if (warning !== void 0) this.logger.warn(mask(warning));
25479
+ const remove = plan.remove.filter(isUserTagKey);
25480
+ const set = Object.fromEntries([...plan.set].filter(([k]) => isUserTagKey(k)));
25481
+ if (remove.length === 0 && Object.keys(set).length === 0) return;
25482
+ const resourceArn = responseArn ?? (await this.client.send(new GetAgentRuntimeCommand({ agentRuntimeId: physicalId }))).agentRuntimeArn;
25483
+ if (!resourceArn) throw new ProvisioningError(`Cannot apply the Tags change to ${logicalId}: AWS returned no runtime ARN`, resourceType, logicalId, physicalId);
25484
+ if (remove.length > 0) await this.client.send(new UntagResourceCommand$9({
25485
+ resourceArn,
25486
+ tagKeys: remove
25487
+ }));
25488
+ if (Object.keys(set).length > 0) await this.client.send(new TagResourceCommand$9({
25489
+ resourceArn,
25490
+ tags: set
25491
+ }));
25492
+ }
25199
25493
  async delete(logicalId, physicalId, resourceType, _properties, context) {
25200
25494
  this.logger.debug(`Deleting BedrockAgentCore Runtime ${logicalId}: ${physicalId}`);
25201
25495
  try {
@@ -25263,6 +25557,16 @@ var AgentCoreRuntimeProvider = class {
25263
25557
  }
25264
25558
  if (resp.lifecycleConfiguration !== void 0) result["LifecycleConfiguration"] = camelToPascalCaseKeys(resp.lifecycleConfiguration, SDK_MAP_KEYS);
25265
25559
  if (resp.environmentVariables !== void 0) result["EnvironmentVariables"] = resp.environmentVariables;
25560
+ result["RequestHeaderConfiguration"] = resp.requestHeaderConfiguration !== void 0 ? camelToPascalCaseKeys(resp.requestHeaderConfiguration, SDK_MAP_KEYS) : {};
25561
+ result["FilesystemConfigurations"] = resp.filesystemConfigurations !== void 0 ? camelToPascalCaseKeys(resp.filesystemConfigurations, SDK_MAP_KEYS) : [];
25562
+ result["CapacityProviderConfiguration"] = resp.capacityProviderConfiguration !== void 0 ? camelToPascalCaseKeys(resp.capacityProviderConfiguration, SDK_MAP_KEYS) : {};
25563
+ result["PlatformVersion"] = resp.platformVersion ?? "";
25564
+ if (resp.agentRuntimeArn) try {
25565
+ const tagsResp = await this.client.send(new ListTagsForResourceCommand$6({ resourceArn: resp.agentRuntimeArn }));
25566
+ result["Tags"] = Object.fromEntries(Object.entries(tagsResp.tags ?? {}).filter(([k]) => isUserTagKey(k)));
25567
+ } catch (err) {
25568
+ this.logger.debug(safeMsg`Failed to read tags for runtime ${physicalId}: ${describeAwsFailure(err).detail}`);
25569
+ }
25266
25570
  return result;
25267
25571
  }
25268
25572
  async import(input) {
@@ -26532,6 +26836,7 @@ var ECSProvider = class {
26532
26836
  }))).service;
26533
26837
  if (!service || !service.serviceArn) throw new Error("CreateService did not return service ARN");
26534
26838
  log.debug(`Successfully created ECS service ${logicalId}: ${service.serviceArn}`);
26839
+ if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, service.serviceArn);
26535
26840
  try {
26536
26841
  await this.settleService(logicalId, service.serviceName ?? service.serviceArn, properties["Cluster"], log);
26537
26842
  } catch (waitError) {
@@ -26547,6 +26852,7 @@ var ECSProvider = class {
26547
26852
  service: service.serviceArn,
26548
26853
  force: true
26549
26854
  }));
26855
+ retractCreatedResource(logicalId, resourceType, service.serviceArn);
26550
26856
  log.warn(`Deleted partially-created ECS service ${logicalId} (${service.serviceArn}) after the steady-state wait failed, so the next deploy's CreateService does not collide on the name. Its stopped tasks remain inspectable for about an hour: ${listStopped.render()}`);
26551
26857
  } catch (cleanupError) {
26552
26858
  survivorArn = service.serviceArn;
@@ -27982,6 +28288,7 @@ var ELBv2Provider = class {
27982
28288
  if (!lb || !lb.LoadBalancerArn) throw new Error("CreateLoadBalancer did not return LoadBalancer ARN");
27983
28289
  const lbArn = lb.LoadBalancerArn;
27984
28290
  this.logger.debug(`Successfully created LoadBalancer ${logicalId}: ${lbArn}`);
28291
+ if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, lbArn);
27985
28292
  try {
27986
28293
  if (waitForActive) {
27987
28294
  this.logger.debug(`Waiting for LoadBalancer ${logicalId} to reach active state...`);
@@ -28020,6 +28327,7 @@ var ELBv2Provider = class {
28020
28327
  if (heldBefore !== "free") this.logger.warn(maskerOrIdentity(maskSecrets)(skippedCleanupText(heldBefore, `LoadBalancer ${logicalId} (${lbArn})`, pasteableAwsCommand(maskSecrets)`aws elbv2 delete-load-balancer --load-balancer-arn ${lbArn}`.render())));
28021
28328
  else try {
28022
28329
  await this.getClient().send(new DeleteLoadBalancerCommand({ LoadBalancerArn: lbArn }));
28330
+ retractCreatedResource(logicalId, resourceType, lbArn);
28023
28331
  this.logger.debug(`Cleaned up partially-created LoadBalancer ${logicalId} (${lbArn}) after wiring failure`);
28024
28332
  } catch (cleanupError) {
28025
28333
  leftBehindArn = lbArn;
@@ -28288,6 +28596,7 @@ var ELBv2Provider = class {
28288
28596
  if (!tg || !tg.TargetGroupArn) throw new Error("CreateTargetGroup did not return TargetGroup ARN");
28289
28597
  const tgArn = tg.TargetGroupArn;
28290
28598
  this.logger.debug(`Successfully created TargetGroup ${logicalId}: ${tgArn}`);
28599
+ if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, tgArn);
28291
28600
  try {
28292
28601
  if (tgAttributes.length > 0) {
28293
28602
  await this.getClient().send(new ModifyTargetGroupAttributesCommand({
@@ -28310,6 +28619,7 @@ var ELBv2Provider = class {
28310
28619
  if (isInterruptedWaitError(innerError)) this.logger.warn(maskerOrIdentity(maskSecrets)(`Interrupted after creating TargetGroup ${logicalId} (${tgArn}) but before its targets were registered. Nothing in cdkd state refers to it, so cdkd is deleting it now. If that delete fails, remove it yourself: ${pasteableAwsCommand(maskSecrets)`aws elbv2 delete-target-group --target-group-arn ${tgArn}`.render()}`));
28311
28620
  try {
28312
28621
  await this.getClient().send(new DeleteTargetGroupCommand({ TargetGroupArn: tgArn }));
28622
+ retractCreatedResource(logicalId, resourceType, tgArn);
28313
28623
  this.logger.debug(`Cleaned up partially-created TargetGroup ${logicalId} (${tgArn}) after wiring failure`);
28314
28624
  } catch (cleanupError) {
28315
28625
  leftBehindArn = tgArn;
@@ -28483,6 +28793,7 @@ var ELBv2Provider = class {
28483
28793
  if (!listener || !listener.ListenerArn) throw new Error("CreateListener did not return Listener ARN");
28484
28794
  const listenerArn = listener.ListenerArn;
28485
28795
  this.logger.debug(`Successfully created Listener ${logicalId}: ${listenerArn}`);
28796
+ if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, listenerArn);
28486
28797
  try {
28487
28798
  if (listenerAttributes.length > 0) {
28488
28799
  const watch = startInterruptWatch(`ELBv2 Listener ${logicalId} attributes`);
@@ -28508,6 +28819,7 @@ var ELBv2Provider = class {
28508
28819
  if (isInterruptedWaitError(innerError)) this.logger.warn(maskerOrIdentity(maskSecrets)(`Interrupted after creating Listener ${logicalId} (${listenerArn}) but before its attributes were applied. Nothing in cdkd state refers to it, so cdkd is deleting it now — left behind it would fail the next deploy with DuplicateListener and destroy could not reach it. If that delete fails, outside a rollback's re-create, the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise remove it yourself: ${pasteableAwsCommand(maskSecrets)`aws elbv2 delete-listener --listener-arn ${listenerArn}`.render()}`));
28509
28820
  try {
28510
28821
  await this.getClient().send(new DeleteListenerCommand({ ListenerArn: listenerArn }));
28822
+ retractCreatedResource(logicalId, resourceType, listenerArn);
28511
28823
  this.logger.debug(`Cleaned up partially-created Listener ${logicalId} (${listenerArn}) after attributes-wiring failure`);
28512
28824
  } catch (cleanupError) {
28513
28825
  leftBehindArn = listenerArn;
@@ -29128,6 +29440,7 @@ var RDSDBProxyProvider = class {
29128
29440
  } catch (error) {
29129
29441
  throw this.wrapCaughtError(error, "CREATE", resourceType, logicalId, void 0, mask);
29130
29442
  }
29443
+ reportCreatedResource(logicalId, resourceType, dbProxyName);
29131
29444
  let endpoint;
29132
29445
  let dbProxyArn;
29133
29446
  let vpcId;
@@ -29457,6 +29770,7 @@ var RDSDBProxyEndpointProvider = class {
29457
29770
  } catch (error) {
29458
29771
  throw this.wrapCaughtError(error, "CREATE", resourceType, logicalId, void 0, mask);
29459
29772
  }
29773
+ reportCreatedResource(logicalId, resourceType, dbProxyEndpointName);
29460
29774
  let endpoint;
29461
29775
  let arn;
29462
29776
  let isDefault;
@@ -29816,6 +30130,7 @@ var RDSDBProxyTargetGroupProvider = class {
29816
30130
  throw await this.retireRegistrationAfterFailedCreate(this.wrapError(error, "CREATE (describe)", resourceType, logicalId, void 0, mask), dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, context?.maskSecrets);
29817
30131
  }
29818
30132
  if (!targetGroupArn) throw await this.retireRegistrationAfterFailedCreate(new ProvisioningError(`Failed to recover TargetGroupArn for ${dbProxyName}/${targetGroupName} after create`, resourceType, logicalId), dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, context?.maskSecrets);
30133
+ if (dbClusterIdentifiers.length > 0 || dbInstanceIdentifiers.length > 0) reportCreatedResource(logicalId, resourceType, targetGroupArn);
29819
30134
  if (tags.length > 0) try {
29820
30135
  await client.send(new AddTagsToResourceCommand$2({
29821
30136
  ResourceName: targetGroupArn,
@@ -30135,6 +30450,7 @@ var RDSDBProxyTargetGroupProvider = class {
30135
30450
  DBClusterIdentifiers: clusters,
30136
30451
  DBInstanceIdentifiers: instances
30137
30452
  }));
30453
+ if (leftBehind) retractCreatedResource(leftBehind.logicalId, leftBehind.resourceType, leftBehind.physicalId);
30138
30454
  return original;
30139
30455
  } catch (cleanupError) {
30140
30456
  const aws = pasteableAwsCommand(maskSecrets);
@@ -30410,6 +30726,7 @@ var DocDBProvider = class {
30410
30726
  }));
30411
30727
  clusterCreated = true;
30412
30728
  createdResourceId = response.DBCluster?.DbClusterResourceId;
30729
+ reportCreatedResource(logicalId, resourceType, dbClusterIdentifier, createdResourceId);
30413
30730
  if (!response.DBCluster) throw new Error("CreateDBCluster did not return DBCluster");
30414
30731
  this.logger.debug(`Successfully created DocDB DBCluster ${logicalId}: ${dbClusterIdentifier}`);
30415
30732
  if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForClusterAvailable(logicalId, dbClusterIdentifier);
@@ -30565,6 +30882,7 @@ var DocDBProvider = class {
30565
30882
  }));
30566
30883
  instanceCreated = true;
30567
30884
  createdResourceId = response.DBInstance?.DbiResourceId;
30885
+ reportCreatedResource(logicalId, resourceType, dbInstanceIdentifier, createdResourceId);
30568
30886
  if (!response.DBInstance) throw new Error("CreateDBInstance did not return DBInstance");
30569
30887
  this.logger.debug(`Successfully created DocDB DBInstance ${logicalId}: ${dbInstanceIdentifier}`);
30570
30888
  if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForInstanceAvailable(logicalId, dbInstanceIdentifier);
@@ -31268,6 +31586,7 @@ var Route53Provider = class {
31268
31586
  if (!hostedZone?.Id) throw new Error("CreateHostedZone did not return HostedZone.Id");
31269
31587
  const zoneId = hostedZone.Id.replace("/hostedzone/", "");
31270
31588
  createdZoneId = zoneId;
31589
+ reportCreatedResource(logicalId, resourceType, zoneId);
31271
31590
  if (vpcs && vpcs.length > 1) for (let i = 1; i < vpcs.length; i++) {
31272
31591
  const additionalVpc = vpcs[i];
31273
31592
  this.logger.debug(`Associating additional VPC ${String(additionalVpc["VPCId"])} with hosted zone ${zoneId}`);
@@ -31293,6 +31612,7 @@ var Route53Provider = class {
31293
31612
  await this.deleteQueryLoggingConfigForZone(zoneId, logicalId);
31294
31613
  await this.getClient().send(new DeleteHostedZoneCommand({ Id: zoneId }));
31295
31614
  zoneRolledBack = true;
31615
+ retractCreatedResource(logicalId, resourceType, zoneId);
31296
31616
  callerReferenceToken.release();
31297
31617
  } catch (deleteError) {
31298
31618
  const head = `Best-effort rollback DeleteHostedZone for ${zoneId} also failed: `;
@@ -32213,6 +32533,27 @@ function sanitizeDescription(value) {
32213
32533
  function isPlainObject$2(value) {
32214
32534
  return typeof value === "object" && value !== null && !Array.isArray(value);
32215
32535
  }
32536
+ const DATA_PROTECTION_FALSE_DEFAULTS = ["ExcludeRuleMatchDetails", "ExcludeRateBasedDetails"];
32537
+ function toCfnDataProtectionConfig(config, baseline) {
32538
+ const entries = config["DataProtections"];
32539
+ if (!Array.isArray(entries)) return config;
32540
+ const baseEntries = isPlainObject$2(baseline) && Array.isArray(baseline["DataProtections"]) ? baseline["DataProtections"] : [];
32541
+ return {
32542
+ ...config,
32543
+ DataProtections: entries.map((entry, i) => {
32544
+ if (!isPlainObject$2(entry)) return entry;
32545
+ const base = baseEntries[i];
32546
+ const converted = { ...entry };
32547
+ for (const key of DATA_PROTECTION_FALSE_DEFAULTS) if (converted[key] === false && !(isPlainObject$2(base) && key in base)) delete converted[key];
32548
+ return converted;
32549
+ })
32550
+ };
32551
+ }
32552
+ function applicationConfigForUpdate(next, previous) {
32553
+ if (next === void 0 || next === null) return void 0;
32554
+ if (isDeepStrictEqual(next, previous)) return void 0;
32555
+ return next;
32556
+ }
32216
32557
  function toSdkByteMatchStatement(byteMatchStatement) {
32217
32558
  const encoded = byteMatchStatement["SearchStringBase64"];
32218
32559
  if (typeof encoded !== "string") return byteMatchStatement;
@@ -32391,7 +32732,11 @@ var WAFv2WebACLProvider = class {
32391
32732
  "CaptchaConfig",
32392
32733
  "ChallengeConfig",
32393
32734
  "TokenDomains",
32394
- "AssociationConfig"
32735
+ "AssociationConfig",
32736
+ "DataProtectionConfig",
32737
+ "OnSourceDDoSProtectionConfig",
32738
+ "ApplicationConfig",
32739
+ "MonetizationConfig"
32395
32740
  ])]]);
32396
32741
  getClient() {
32397
32742
  if (!this.wafv2Client) {
@@ -32432,7 +32777,11 @@ var WAFv2WebACLProvider = class {
32432
32777
  CaptchaConfig: properties["CaptchaConfig"],
32433
32778
  ChallengeConfig: properties["ChallengeConfig"],
32434
32779
  TokenDomains: properties["TokenDomains"],
32435
- AssociationConfig: properties["AssociationConfig"]
32780
+ AssociationConfig: properties["AssociationConfig"],
32781
+ DataProtectionConfig: properties["DataProtectionConfig"],
32782
+ OnSourceDDoSProtectionConfig: properties["OnSourceDDoSProtectionConfig"],
32783
+ ApplicationConfig: properties["ApplicationConfig"],
32784
+ MonetizationConfig: properties["MonetizationConfig"]
32436
32785
  }))).Summary;
32437
32786
  if (!summary?.ARN || !summary?.Id) throw new Error("CreateWebACL did not return Summary with ARN and Id");
32438
32787
  this.logger.debug(`Successfully created WAFv2 WebACL ${logicalId}: ${summary.ARN}`);
@@ -32486,7 +32835,11 @@ var WAFv2WebACLProvider = class {
32486
32835
  CaptchaConfig: properties["CaptchaConfig"],
32487
32836
  ChallengeConfig: properties["ChallengeConfig"],
32488
32837
  TokenDomains: properties["TokenDomains"],
32489
- AssociationConfig: properties["AssociationConfig"]
32838
+ AssociationConfig: properties["AssociationConfig"],
32839
+ DataProtectionConfig: properties["DataProtectionConfig"],
32840
+ OnSourceDDoSProtectionConfig: properties["OnSourceDDoSProtectionConfig"],
32841
+ ApplicationConfig: applicationConfigForUpdate(properties["ApplicationConfig"], previousProperties["ApplicationConfig"]),
32842
+ MonetizationConfig: properties["MonetizationConfig"]
32490
32843
  }));
32491
32844
  await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
32492
32845
  this.logger.debug(`Successfully updated WAFv2 WebACL ${logicalId}`);
@@ -32593,6 +32946,10 @@ var WAFv2WebACLProvider = class {
32593
32946
  if (webACL.ChallengeConfig) result["ChallengeConfig"] = webACL.ChallengeConfig;
32594
32947
  result["TokenDomains"] = webACL.TokenDomains ? [...webACL.TokenDomains] : [];
32595
32948
  if (webACL.AssociationConfig) result["AssociationConfig"] = webACL.AssociationConfig;
32949
+ if (webACL.DataProtectionConfig) result["DataProtectionConfig"] = toCfnDataProtectionConfig(webACL.DataProtectionConfig, properties?.["DataProtectionConfig"]);
32950
+ if (webACL.OnSourceDDoSProtectionConfig) result["OnSourceDDoSProtectionConfig"] = webACL.OnSourceDDoSProtectionConfig;
32951
+ if (webACL.ApplicationConfig) result["ApplicationConfig"] = webACL.ApplicationConfig;
32952
+ if (webACL.MonetizationConfig) result["MonetizationConfig"] = webACL.MonetizationConfig;
32596
32953
  try {
32597
32954
  const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$13({ ResourceARN: physicalId }));
32598
32955
  result["Tags"] = normalizeAwsTagsToCfn(tagsResp.TagInfoForResource?.TagList);
@@ -33068,6 +33425,7 @@ var CognitoUserPoolProvider = class {
33068
33425
  if (!userPool?.Id) throw new Error("CreateUserPool did not return UserPool.Id");
33069
33426
  const userPoolId = userPool.Id;
33070
33427
  createdUserPoolId = userPoolId;
33428
+ reportCreatedResource(logicalId, resourceType, userPoolId);
33071
33429
  const replayWindow = replayedSendWindow(created, attemptStartMs);
33072
33430
  if (replayWindow !== void 0) await this.reportPossibleOrphanPools(logicalId, poolName, replayWindow, createMaskedLogSinks(this.logger, context?.maskSecrets), userPoolId);
33073
33431
  const userPoolArn = userPool.Arn;
@@ -33095,6 +33453,7 @@ var CognitoUserPoolProvider = class {
33095
33453
  markAuxiliaryFailure(error, logicalId);
33096
33454
  try {
33097
33455
  await this.getClient().send(new DeleteUserPoolCommand({ UserPoolId: createdUserPoolId }));
33456
+ retractCreatedResource(logicalId, resourceType, createdUserPoolId);
33098
33457
  this.logger.debug(`Rolled back partially-created Cognito User Pool ${createdUserPoolId}`);
33099
33458
  } catch (rollbackError) {
33100
33459
  poolLeftBehind = true;
@@ -33976,6 +34335,7 @@ var ElastiCacheProvider = class {
33976
34335
  ...tags.length > 0 && { Tags: tags }
33977
34336
  }));
33978
34337
  clusterCreated = true;
34338
+ reportCreatedResource(logicalId, resourceType, cacheClusterId);
33979
34339
  this.logger.debug(`Successfully created CacheCluster ${logicalId}: ${cacheClusterId}`);
33980
34340
  if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForClusterAvailable(cacheClusterId);
33981
34341
  const described = await this.describeCacheCluster(cacheClusterId);
@@ -34786,6 +35146,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
34786
35146
  if (!service || !service.Id) throw new Error("CreateService did not return Service ID");
34787
35147
  const serviceId = service.Id;
34788
35148
  leftBehindServiceId = serviceId;
35149
+ reportCreatedResource(logicalId, resourceType, serviceId);
34789
35150
  this.logger.debug(`Successfully created service discovery service ${logicalId}: ${serviceId}`);
34790
35151
  try {
34791
35152
  const attrs = this.normalizeServiceAttributes(properties["ServiceAttributes"]);
@@ -34810,6 +35171,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
34810
35171
  try {
34811
35172
  await client.send(new DeleteServiceCommand$1({ Id: serviceId }));
34812
35173
  leftBehindServiceId = void 0;
35174
+ retractCreatedResource(logicalId, resourceType, serviceId);
34813
35175
  this.logger.debug(`Cleaned up partially-created ServiceDiscovery Service ${logicalId} (${serviceId}) after ServiceAttributes wiring failure`);
34814
35176
  } catch (cleanupError) {
34815
35177
  const cleanupFailure = describeAwsFailure(cleanupError);
@@ -36234,6 +36596,7 @@ var AppSyncProvider = class {
36234
36596
  throw error;
36235
36597
  }
36236
36598
  createdApiId = response.graphqlApi?.apiId;
36599
+ if (createdApiId) reportCreatedResource(logicalId, resourceType, createdApiId);
36237
36600
  const apiId = response.graphqlApi.apiId;
36238
36601
  const replayWindow = replayedSendWindow(response, attemptStartMs);
36239
36602
  if (replayWindow !== void 0) await this.reportPossibleOrphanApis(logicalId, input, replayWindow, maskerOrIdentity(context?.maskSecrets), apiId);
@@ -36257,6 +36620,7 @@ var AppSyncProvider = class {
36257
36620
  markAuxiliaryFailure(error, logicalId);
36258
36621
  try {
36259
36622
  await this.getClient().send(new DeleteGraphqlApiCommand({ apiId: createdApiId }));
36623
+ retractCreatedResource(logicalId, resourceType, createdApiId);
36260
36624
  this.logger.debug(`Rolled back partially-created GraphQL API ${createdApiId}`);
36261
36625
  } catch (rollbackError) {
36262
36626
  apiLeftBehind = true;
@@ -39391,6 +39755,7 @@ var KMSProvider = class {
39391
39755
  heldAtMs: Date.now()
39392
39756
  });
39393
39757
  createdKeyId = keyId;
39758
+ reportCreatedResource(logicalId, resourceType, keyId);
39394
39759
  const declinedAtMs = supersededAttempts.get(attemptKey);
39395
39760
  supersededAttempts.delete(attemptKey);
39396
39761
  supersededPending = declinedAtMs !== void 0 && Date.now() - declinedAtMs <= 18e5;
@@ -39398,6 +39763,7 @@ var KMSProvider = class {
39398
39763
  if (replayWindow !== void 0) await this.reportPossibleOrphanKeys(logicalId, input, replayWindow);
39399
39764
  }
39400
39765
  createdKeyId = keyId;
39766
+ reportCreatedResource(logicalId, resourceType, keyId);
39401
39767
  if (enableKeyRotation === true) {
39402
39768
  const rotationPeriodInDays = properties["RotationPeriodInDays"];
39403
39769
  this.logger.debug(`Enabling key rotation for KMS Key ${logicalId}`);
@@ -40623,58 +40989,6 @@ var BudgetsBudgetProvider = class {
40623
40989
  }
40624
40990
  };
40625
40991
 
40626
- //#endregion
40627
- //#region src/provisioning/delete-gone-wait.ts
40628
- async function waitForGoneAfterDelete(opts) {
40629
- const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
40630
- const now = opts.now ?? Date.now;
40631
- const userTimeoutMs = resolvedResourceTimeoutMs(opts.resourceType);
40632
- const maxWaitMs = userTimeoutMs === void 0 ? opts.maxWaitMs : Math.min(opts.maxWaitMs, userTimeoutMs / 2);
40633
- const startedAt = now();
40634
- const stopped = `${opts.what}: the delete was ACCEPTED by AWS, but cdkd stopped waiting for it to disappear`;
40635
- const consequence = "AWS finishes the delete on its side; until it does, a create of the same name is refused with \"already exists\".";
40636
- const watch = startInterruptWatch(`${opts.what} deletion wait`);
40637
- try {
40638
- let lastStatus;
40639
- let sawNonFailedStatus = false;
40640
- for (;;) {
40641
- if (watch.isInterrupted()) {
40642
- opts.logger.warn(safeMsg`${stopped} (interrupted). ${consequence}`);
40643
- return;
40644
- }
40645
- try {
40646
- const status = await opts.describe();
40647
- if (status === void 0) {
40648
- opts.logger.debug(safeMsg`${opts.what} is gone`);
40649
- return;
40650
- }
40651
- const failure = opts.failedStatus?.(status);
40652
- if (failure !== void 0) {
40653
- if (sawNonFailedStatus || now() - startedAt >= opts.pollIntervalMs) throw markWaitAbandoned(failure);
40654
- } else sawNonFailedStatus = true;
40655
- lastStatus = status;
40656
- opts.logger.debug(safeMsg`${opts.what} status: ${status}, waiting for it to disappear`);
40657
- } catch (error) {
40658
- if (isWaitAbandonedError(error)) throw error;
40659
- if (!isThrottlingError(error) && !isTransientServerError(error)) {
40660
- opts.logger.debug(safeMsg`${opts.what}: status read failed: ${describeAwsFailure(error).detail}`);
40661
- opts.logger.warn(safeMsg`${stopped}: its status could not be read (${describeAwsFailure(error).summary}). ${consequence}`);
40662
- return;
40663
- }
40664
- opts.logger.debug(safeMsg`${opts.what}: status read throttled or failed transiently, re-polling`);
40665
- }
40666
- const remainingMs = maxWaitMs - (now() - startedAt);
40667
- if (remainingMs <= 0) {
40668
- opts.logger.warn(safeMsg`${stopped} after ${Math.round(maxWaitMs / 1e3)}s` + safeMsg`${lastStatus !== void 0 ? ` (last status: ${lastStatus})` : ""}. ${consequence}`);
40669
- return;
40670
- }
40671
- await sleep(Math.min(opts.pollIntervalMs, remainingMs));
40672
- }
40673
- } finally {
40674
- watch.dispose();
40675
- }
40676
- }
40677
-
40678
40992
  //#endregion
40679
40993
  //#region src/provisioning/providers/kinesis-provider.ts
40680
40994
  function isKmsEncryption(value) {
@@ -40864,6 +41178,7 @@ var KinesisStreamProvider = class {
40864
41178
  ...Object.keys(tags).length > 0 && { Tags: tags }
40865
41179
  }));
40866
41180
  streamCreated = true;
41181
+ reportCreatedResource(logicalId, resourceType, streamName);
40867
41182
  this.logger.debug(`CreateStream initiated for ${streamName}, waiting for ACTIVE status`);
40868
41183
  const streamInfo = await this.waitForStreamActive(streamName);
40869
41184
  const retentionPeriodHours = retentionRead.kind === "usable" ? retentionRead.hours : void 0;
@@ -40969,7 +41284,10 @@ var KinesisStreamProvider = class {
40969
41284
  }
40970
41285
  await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], {
40971
41286
  forceUpsert: context?.unsettledProperties?.has("Tags") === true,
40972
- beforeWrite: () => markUnsettled("Tags")
41287
+ beforeWrite: () => markUnsettled("Tags"),
41288
+ afterAdded: (keys) => {
41289
+ if (keys.length > 0) context?.markAttempted?.("Tags", keys);
41290
+ }
40973
41291
  });
40974
41292
  const newEncryption = properties["StreamEncryption"];
40975
41293
  const oldEncryption = previousProperties["StreamEncryption"];
@@ -41031,10 +41349,13 @@ var KinesisStreamProvider = class {
41031
41349
  }
41032
41350
  if (toEnable.length > 0) {
41033
41351
  this.logger.debug(`Enabling ${toEnable.length} shard-level metric(s) on ${physicalId}`);
41034
- await this.getClient().send(new EnableEnhancedMonitoringCommand({
41352
+ const current = expandShardLevelMetrics((await this.getClient().send(new EnableEnhancedMonitoringCommand({
41035
41353
  StreamName: physicalId,
41036
41354
  ShardLevelMetrics: toEnable
41037
- }));
41355
+ })))?.CurrentShardLevelMetrics ?? []);
41356
+ const before = new Set(Array.isArray(current) ? current : []);
41357
+ const added = toEnable.filter((metric) => !before.has(metric));
41358
+ if (added.length > 0) context?.markAttempted?.("DesiredShardLevelMetrics", added);
41038
41359
  await this.waitForStreamActive(physicalId);
41039
41360
  }
41040
41361
  }
@@ -41201,6 +41522,13 @@ var KinesisStreamProvider = class {
41201
41522
  StreamName: streamName,
41202
41523
  Tags: tagsToAdd
41203
41524
  }));
41525
+ let recordedKeys;
41526
+ try {
41527
+ recordedKeys = /* @__PURE__ */ new Set([...planTagDiff(void 0, oldTagsRaw).set.keys()]);
41528
+ } catch {
41529
+ recordedKeys = void 0;
41530
+ }
41531
+ unsettled.afterAdded?.(Object.keys(tagsToAdd).filter((key) => recordedKeys !== void 0 && !recordedKeys.has(key)));
41204
41532
  this.logger.debug(`Added/updated ${Object.keys(tagsToAdd).length} tag(s) on Kinesis stream ${streamName}`);
41205
41533
  }
41206
41534
  }
@@ -41217,7 +41545,7 @@ var KinesisStreamProvider = class {
41217
41545
  const secretDerived = mask(physicalId) !== physicalId;
41218
41546
  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
41547
  }
41220
- async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties) {
41548
+ async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties, attemptedItems) {
41221
41549
  const live = await this.readCurrentState(physicalId, logicalId, resourceType);
41222
41550
  if (typeof live !== "object" || live === null) return live;
41223
41551
  const out = { ...live };
@@ -41226,6 +41554,7 @@ var KinesisStreamProvider = class {
41226
41554
  const expanded = expandShardLevelMetrics(bag?.["DesiredShardLevelMetrics"]);
41227
41555
  return isUsableMetricsList(expanded) ? expanded : [];
41228
41556
  }));
41557
+ for (const metric of attemptedItems?.get("DesiredShardLevelMetrics") ?? []) if (metric !== "ALL" && isUsableAttemptedName(metric)) named.add(metric);
41229
41558
  const liveMetrics = expandShardLevelMetrics(out["DesiredShardLevelMetrics"]);
41230
41559
  out["DesiredShardLevelMetrics"] = (Array.isArray(liveMetrics) ? liveMetrics : []).filter((metric) => typeof metric === "string" && named.has(metric));
41231
41560
  }
@@ -41386,6 +41715,7 @@ var KinesisStreamConsumerProvider = class {
41386
41715
  if (!consumer?.ConsumerARN || !consumer.ConsumerName) throw new ProvisioningError("RegisterStreamConsumer did not return ConsumerARN/ConsumerName", resourceType, logicalId);
41387
41716
  const consumerArn = consumer.ConsumerARN;
41388
41717
  createdArn = consumerArn;
41718
+ reportCreatedResource(logicalId, resourceType, consumerArn);
41389
41719
  await this.waitForConsumerActive(consumerArn);
41390
41720
  this.logger.debug(`Successfully registered Kinesis stream consumer ${logicalId}`);
41391
41721
  return {
@@ -42259,6 +42589,7 @@ var PipesPipeProvider = class {
42259
42589
  ...Object.keys(tags).length > 0 && { Tags: tags }
42260
42590
  }));
42261
42591
  createdIdentity = pipeIdentityToken(name, created?.Arn, created?.CreationTime);
42592
+ reportCreatedResource(logicalId, resourceType, name, createdIdentity);
42262
42593
  } catch (error) {
42263
42594
  const cause = error instanceof Error ? error : void 0;
42264
42595
  throw this.wrapCaughtError(mask, error, (text) => new ProvisioningError(`Failed to create Pipe ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
@@ -42566,7 +42897,10 @@ var PipesPipeProvider = class {
42566
42897
  try {
42567
42898
  await this.getClient().send(new DeletePipeCommand({ Name: name }));
42568
42899
  } catch (cleanupError) {
42569
- if (cleanupError instanceof NotFoundException$6) return original;
42900
+ if (cleanupError instanceof NotFoundException$6) {
42901
+ retractCreatedResource(logicalId, resourceType, name);
42902
+ return original;
42903
+ }
42570
42904
  return orphaned(describeAwsFailure(cleanupError).summary);
42571
42905
  }
42572
42906
  let gone = false;
@@ -42592,10 +42926,12 @@ var PipesPipeProvider = class {
42592
42926
  return orphaned("its delete did not complete (AWS reports a failed or rolled-back delete)");
42593
42927
  }
42594
42928
  if (gone) {
42929
+ retractCreatedResource(logicalId, resourceType, name);
42595
42930
  original.message += " (cdkd deleted the pipe it had created, so nothing is left behind)";
42596
42931
  return original;
42597
42932
  }
42598
42933
  if (sawDeleting) {
42934
+ retractCreatedResource(logicalId, resourceType, name);
42599
42935
  original.message += " (cdkd started deleting the pipe it had created; a re-deploy may report the name in use until AWS finishes)";
42600
42936
  return original;
42601
42937
  }
@@ -42926,6 +43262,7 @@ var EFSProvider = class {
42926
43262
  }))
42927
43263
  });
42928
43264
  fileSystemId = created.fileSystemId;
43265
+ reportCreatedResource(logicalId, resourceType, fileSystemId);
42929
43266
  const available = await this.waitForFileSystemAvailable(fileSystemId, logicalId, resourceType, log);
42930
43267
  const arn = created.arn ?? available.FileSystemArn;
42931
43268
  await this.applyLifecyclePolicies(fileSystemId, properties["LifecyclePolicies"], log);
@@ -42947,6 +43284,7 @@ var EFSProvider = class {
42947
43284
  try {
42948
43285
  await this.getClient().send(new DeleteFileSystemCommand({ FileSystemId: fileSystemId }));
42949
43286
  this.unconfirmedCreationTokens.delete(creationToken);
43287
+ retractCreatedResource(logicalId, resourceType, fileSystemId);
42950
43288
  log.debug(`Rolled back partially-created EFS FileSystem ${fileSystemId}`);
42951
43289
  } catch (cleanupError) {
42952
43290
  fileSystemLeftBehind = true;
@@ -43124,6 +43462,7 @@ var EFSProvider = class {
43124
43462
  }));
43125
43463
  const mountTargetId = response.MountTargetId;
43126
43464
  createdMountTargetId = mountTargetId;
43465
+ reportCreatedResource(logicalId, resourceType, mountTargetId);
43127
43466
  log.debug(`Created EFS MountTarget ${logicalId}: ${mountTargetId}, waiting for available state`);
43128
43467
  await this.waitForMountTargetAvailable(mountTargetId, logicalId, resourceType, log);
43129
43468
  log.debug(`Successfully created EFS MountTarget ${logicalId}: ${mountTargetId}`);
@@ -43775,6 +44114,7 @@ var FSxFileSystemProvider = class {
43775
44114
  throw markNonRetryable(new ProvisioningError(safeMsg`FSx answered the create of ${logicalId} with file system ${returnedId}, which ${createdAt === void 0 ? "carries no creation time" : "predates this create"}: the create token cdkd derives for this stack's file system is held by it, and it is NOT recorded in cdkd state. It is not one this deploy, or an interrupted earlier deploy of this stack, made: it was created under this token by an earlier cdkd version, or a completed deploy recorded it and cdkd later let go of it, and it may hold data, so cdkd neither records nor deletes it. Inspect it with: ${inspect} --file-system-ids ${returnedId} -- then import it into this stack, or delete it once you are sure its data is not needed, and deploy again.`, resourceType, logicalId));
43776
44115
  }
43777
44116
  fileSystemId = returnedId;
44117
+ reportCreatedResource(logicalId, resourceType, returnedId);
43778
44118
  const fs = await this.waitForFileSystemAvailable(fileSystemId, logicalId, resourceType, context?.maskSecrets);
43779
44119
  this.logger.debug(`Successfully created FSx FileSystem ${logicalId}: ${fileSystemId}`);
43780
44120
  this.createTokenFirstSentAt.delete(clientRequestToken);
@@ -43786,6 +44126,7 @@ var FSxFileSystemProvider = class {
43786
44126
  let survivorId;
43787
44127
  if (fileSystemId !== void 0) try {
43788
44128
  await this.getClient().send(new DeleteFileSystemCommand$1({ FileSystemId: fileSystemId }));
44129
+ retractCreatedResource(logicalId, resourceType, fileSystemId);
43789
44130
  this.createTokenFirstSentAt.delete(clientRequestToken);
43790
44131
  this.logger.warn(`Rolled back partially-created FSx FileSystem ${fileSystemId}`);
43791
44132
  } catch (cleanupError) {
@@ -44712,11 +45053,11 @@ var FSxFileSystemProvider = class {
44712
45053
 
44713
45054
  //#endregion
44714
45055
  //#region src/provisioning/emr-configuration.ts
44715
- function isRecord(value) {
45056
+ function isRecord$1(value) {
44716
45057
  return typeof value === "object" && value !== null && !Array.isArray(value);
44717
45058
  }
44718
45059
  function toSdkConfiguration(raw) {
44719
- if (!isRecord(raw)) return raw;
45060
+ if (!isRecord$1(raw)) return raw;
44720
45061
  const { ConfigurationProperties, Configurations, ...rest } = raw;
44721
45062
  return {
44722
45063
  ...rest,
@@ -44733,9 +45074,9 @@ function toSdkStepConfigs(value) {
44733
45074
  if (value === void 0) return void 0;
44734
45075
  if (!Array.isArray(value)) return value;
44735
45076
  return value.map((step) => {
44736
- if (!isRecord(step)) return step;
45077
+ if (!isRecord$1(step)) return step;
44737
45078
  const hadoopJarStep = step["HadoopJarStep"];
44738
- if (!isRecord(hadoopJarStep) || hadoopJarStep["StepProperties"] === void 0) return step;
45079
+ if (!isRecord$1(hadoopJarStep) || hadoopJarStep["StepProperties"] === void 0) return step;
44739
45080
  const { StepProperties, ...restHadoopJarStep } = hadoopJarStep;
44740
45081
  return {
44741
45082
  ...step,
@@ -44750,7 +45091,7 @@ function toSdkInstanceTypeConfigs(value) {
44750
45091
  if (value === void 0) return void 0;
44751
45092
  if (!Array.isArray(value)) return value;
44752
45093
  return value.map((instanceTypeConfig) => {
44753
- if (!isRecord(instanceTypeConfig) || instanceTypeConfig["Configurations"] === void 0) return instanceTypeConfig;
45094
+ if (!isRecord$1(instanceTypeConfig) || instanceTypeConfig["Configurations"] === void 0) return instanceTypeConfig;
44754
45095
  return {
44755
45096
  ...instanceTypeConfig,
44756
45097
  Configurations: toSdkConfigurations(instanceTypeConfig["Configurations"])
@@ -44897,6 +45238,7 @@ var EMRInstanceGroupConfigProvider = class {
44897
45238
  const groupId = response.InstanceGroupIds?.[0];
44898
45239
  if (groupId) groupsCreatedByThisProcess.add(groupId);
44899
45240
  createdGroupId = groupId;
45241
+ reportCreatedResource(logicalId, resourceType, groupId ?? "");
44900
45242
  const replayWindow = replayedSendWindow(response, attemptStartMs);
44901
45243
  if (replayWindow !== void 0 && group.InstanceRole === "TASK") await reportOrphans(replayWindow);
44902
45244
  if (!groupId) throw new ProvisioningError(`EMR AddInstanceGroups for ${logicalId} returned no instance group id`, resourceType, logicalId);
@@ -44923,6 +45265,7 @@ var EMRInstanceGroupConfigProvider = class {
44923
45265
  }]
44924
45266
  }));
44925
45267
  log.warn(safeMsg`Scaled partially-created EMR TASK instance group ${logicalId} (${leftBehindGroupId}) to 0; EMR has no delete API, so the empty group stays on cluster ${log.value(jobFlowId)} until it terminates`);
45268
+ retractCreatedResource(logicalId, resourceType, leftBehindGroupId);
44926
45269
  leftBehindGroupId = void 0;
44927
45270
  } catch (cleanupError) {
44928
45271
  const cleanupHead = safeMsg`Failed to scale partially-created EMR TASK instance group ${logicalId} (${leftBehindGroupId}) to 0: `;
@@ -45272,6 +45615,7 @@ var EMRInstanceFleetConfigProvider = class {
45272
45615
  const fleetId = response.InstanceFleetId;
45273
45616
  if (fleetId) fleetsCreatedByThisProcess.add(fleetId);
45274
45617
  createdFleetId = fleetId;
45618
+ reportCreatedResource(logicalId, resourceType, fleetId ?? "");
45275
45619
  const replayWindow = replayedSendWindow(response, attemptStartMs);
45276
45620
  if (replayWindow !== void 0 && fleet.InstanceFleetType === "TASK") await reportOrphans(replayWindow);
45277
45621
  if (!fleetId) throw new ProvisioningError(`EMR AddInstanceFleet for ${logicalId} returned no instance fleet id`, resourceType, logicalId);
@@ -45763,6 +46107,7 @@ var EMRClusterProvider = class {
45763
46107
  }
45764
46108
  clusterId = response.JobFlowId;
45765
46109
  if (clusterId) clustersCreatedByThisProcess.add(clusterId);
46110
+ reportCreatedResource(logicalId, resourceType, clusterId ?? "");
45766
46111
  const replayWindow = replayedSendWindow(response, attemptStartMs);
45767
46112
  if (replayWindow !== void 0) await reportOrphans(replayWindow);
45768
46113
  if (!clusterId) throw new ProvisioningError(`EMR RunJobFlow for ${logicalId} returned no JobFlowId`, resourceType, logicalId);
@@ -45780,6 +46125,7 @@ var EMRClusterProvider = class {
45780
46125
  TerminationProtected: false
45781
46126
  }));
45782
46127
  await this.getClient().send(new TerminateJobFlowsCommand({ JobFlowIds: [clusterId] }));
46128
+ retractCreatedResource(logicalId, resourceType, clusterId);
45783
46129
  this.logger.warn(`Rolled back partially-created EMR Cluster ${clusterId}`);
45784
46130
  } catch (cleanupError) {
45785
46131
  survivorId = clusterId;
@@ -46521,6 +46867,9 @@ function liveEncryptionAsCfn(live) {
46521
46867
  }
46522
46868
  const ENCRYPTION_POLL_INTERVAL_MS = 5e3;
46523
46869
  const ENCRYPTION_POLL_MAX_ATTEMPTS = 120;
46870
+ const ACTIVE_POLL_INTERVAL_MS = 5e3;
46871
+ const ACTIVE_POLL_MAX_ATTEMPTS = 360;
46872
+ const ACTIVE_DEADLINE_MARGIN_MS = 2e3;
46524
46873
  const terminalEncryptionFailures = /* @__PURE__ */ new WeakSet();
46525
46874
  function isReadableTagList(value) {
46526
46875
  if (value === void 0 || value === null) return true;
@@ -46736,9 +47085,10 @@ var FirehoseProvider = class {
46736
47085
  const response = await this.getCreateClient().send(new CreateDeliveryStreamCommand(input));
46737
47086
  const physicalId = deliveryStreamName || input.DeliveryStreamName || response.DeliveryStreamARN?.split("/").pop() || "";
46738
47087
  createdStreamName = physicalId;
47088
+ reportCreatedResource(logicalId, resourceType, physicalId);
46739
47089
  const arn = response.DeliveryStreamARN;
46740
47090
  this.logger.debug(`Successfully created Firehose delivery stream ${logicalId}: ${physicalId}`);
46741
- await this.waitForActive(physicalId, logicalId);
47091
+ await this.waitForActive(physicalId, logicalId, resourceType, maskerOrIdentity(context?.maskSecrets));
46742
47092
  return {
46743
47093
  physicalId,
46744
47094
  attributes: { Arn: arn }
@@ -47437,18 +47787,59 @@ var FirehoseProvider = class {
47437
47787
  }
47438
47788
  return null;
47439
47789
  }
47440
- async waitForActive(streamName, logicalId) {
47441
- const maxAttempts = 30;
47442
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
47443
- const status = (await this.getClient().send(new DescribeDeliveryStreamCommand({ DeliveryStreamName: streamName }))).DeliveryStreamDescription?.DeliveryStreamStatus;
47444
- if (status === "ACTIVE") {
47445
- this.logger.debug(`Firehose ${logicalId} is ACTIVE`);
47446
- return;
47790
+ async waitForActive(streamName, logicalId, resourceType, mask) {
47791
+ const watch = startInterruptWatch(`Firehose ${logicalId} create`);
47792
+ try {
47793
+ let last;
47794
+ let deadlineNear = false;
47795
+ for (let attempt = 1; attempt <= ACTIVE_POLL_MAX_ATTEMPTS; attempt++) {
47796
+ if (watch.isInterrupted()) throw watch.onInterrupted();
47797
+ if (enclosingDeadlineRemainingMs() <= ACTIVE_DEADLINE_MARGIN_MS) {
47798
+ deadlineNear = true;
47799
+ break;
47800
+ }
47801
+ const resp = await this.describeBeforeDeadline(streamName);
47802
+ if (resp === "deadline") {
47803
+ deadlineNear = true;
47804
+ break;
47805
+ }
47806
+ const description = resp.DeliveryStreamDescription;
47807
+ last = description?.DeliveryStreamStatus;
47808
+ if (last === "ACTIVE") {
47809
+ this.logger.debug(`Firehose ${logicalId} is ACTIVE`);
47810
+ return;
47811
+ }
47812
+ if (last !== void 0 && last.endsWith("_FAILED")) {
47813
+ const failure = description?.FailureDescription;
47814
+ throw markNonRetryable(new ProvisioningError(`Firehose delivery stream ${logicalId} did not become ACTIVE: AWS reports ${last}` + (failure ? ` (${mask(`${failure.Type ?? ""}: ${failure.Details ?? ""}`)})` : ""), resourceType, logicalId, streamName));
47815
+ }
47816
+ this.logger.debug(`Firehose ${logicalId} status: ${last} (attempt ${attempt}/${ACTIVE_POLL_MAX_ATTEMPTS})`);
47817
+ if (watch.isInterrupted()) throw watch.onInterrupted();
47818
+ if (enclosingDeadlineRemainingMs() <= 7e3) {
47819
+ deadlineNear = true;
47820
+ break;
47821
+ }
47822
+ await new Promise((resolve) => setTimeout(resolve, ACTIVE_POLL_INTERVAL_MS));
47447
47823
  }
47448
- this.logger.debug(`Firehose ${logicalId} status: ${status} (attempt ${attempt}/${maxAttempts})`);
47449
- await new Promise((resolve) => setTimeout(resolve, 2e3));
47824
+ 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));
47825
+ } finally {
47826
+ watch.dispose();
47827
+ }
47828
+ }
47829
+ async describeBeforeDeadline(streamName) {
47830
+ const command = new DescribeDeliveryStreamCommand({ DeliveryStreamName: streamName });
47831
+ const remaining = enclosingDeadlineRemainingMs();
47832
+ if (!Number.isFinite(remaining)) return this.getClient().send(command);
47833
+ const abort = new AbortController();
47834
+ const timer = setTimeout(() => abort.abort(), Math.max(0, remaining - ACTIVE_DEADLINE_MARGIN_MS));
47835
+ try {
47836
+ return await this.getClient().send(command, { abortSignal: abort.signal });
47837
+ } catch (error) {
47838
+ if (abort.signal.aborted) return "deadline";
47839
+ throw error;
47840
+ } finally {
47841
+ clearTimeout(timer);
47450
47842
  }
47451
- this.logger.warn(`Firehose ${logicalId} did not reach ACTIVE after ${maxAttempts} attempts`);
47452
47843
  }
47453
47844
  };
47454
47845
  function pickDefinedDeep(input) {
@@ -47576,6 +47967,77 @@ function resolveCloudWatchLogsPair(properties) {
47576
47967
  roleArn: desiredRole
47577
47968
  };
47578
47969
  }
47970
+ function readListBlock(raw, path) {
47971
+ if (raw == null) return { kind: "absent" };
47972
+ try {
47973
+ return {
47974
+ kind: "list",
47975
+ value: requireConfigArray(raw, path)
47976
+ };
47977
+ } catch (error) {
47978
+ return {
47979
+ kind: "unusable",
47980
+ detail: describeAwsFailure(error).detail
47981
+ };
47982
+ }
47983
+ }
47984
+ function listOf$1(read) {
47985
+ return read.kind === "list" ? read.value : void 0;
47986
+ }
47987
+ function retainPreviousLists(desired, previous, keys, live) {
47988
+ const out = Object.fromEntries(Object.entries(desired).filter(([key]) => !keys.includes(key)));
47989
+ for (const key of keys) {
47990
+ const prev = previous[key];
47991
+ if (Array.isArray(prev)) out[key] = structuredClone(prev);
47992
+ else if (prev != null && Array.isArray(live?.[key])) out[key] = structuredClone(live[key]);
47993
+ }
47994
+ return out;
47995
+ }
47996
+ const UNORDERED_LIST_BLOCKS = ["AdvancedEventSelectors", "AggregationConfigurations"];
47997
+ function setKey(value) {
47998
+ if (value === void 0) return "undefined";
47999
+ if (Array.isArray(value)) return [
48000
+ "[",
48001
+ value.map(setKey).sort().join(","),
48002
+ "]"
48003
+ ].join("");
48004
+ if (value !== null && typeof value === "object") {
48005
+ const bag = value;
48006
+ return [
48007
+ "{",
48008
+ Object.keys(bag).filter((k) => bag[k] !== void 0).sort().map((k) => [JSON.stringify(k), setKey(bag[k])].join(":")).join(","),
48009
+ "}"
48010
+ ].join("");
48011
+ }
48012
+ return JSON.stringify(value) ?? "null";
48013
+ }
48014
+ function nonEmptyListOf(read) {
48015
+ return read.kind === "list" && read.value.length > 0 ? read.value : void 0;
48016
+ }
48017
+ function eventSelectorRequest(basic, advanced) {
48018
+ const hasBasic = basic !== void 0 && basic.length > 0;
48019
+ if (advanced !== void 0 && advanced.length > 0) return {
48020
+ members: {
48021
+ AdvancedEventSelectors: advanced,
48022
+ ...hasBasic ? { EventSelectors: basic } : {}
48023
+ },
48024
+ isReset: false
48025
+ };
48026
+ if (hasBasic) return {
48027
+ members: { EventSelectors: basic },
48028
+ isReset: false
48029
+ };
48030
+ return {
48031
+ members: { EventSelectors: [...DEFAULT_EVENT_SELECTORS] },
48032
+ isReset: true
48033
+ };
48034
+ }
48035
+ function advancedSelectorsToCfn(selectors) {
48036
+ return selectors.map((s) => ({
48037
+ ...s.Name !== void 0 && { Name: s.Name },
48038
+ FieldSelectors: (s.FieldSelectors ?? []).map((f) => Object.fromEntries(Object.entries(f).filter(([, v]) => v !== void 0)))
48039
+ }));
48040
+ }
47579
48041
  function describeValue(value) {
47580
48042
  if (value === null) return "null";
47581
48043
  if (value === void 0) return "nothing";
@@ -47625,7 +48087,9 @@ var CloudTrailProvider = class {
47625
48087
  "SnsTopicName",
47626
48088
  "EventSelectors",
47627
48089
  "InsightSelectors",
47628
- "IsOrganizationTrail"
48090
+ "IsOrganizationTrail",
48091
+ "AdvancedEventSelectors",
48092
+ "AggregationConfigurations"
47629
48093
  ])]]);
47630
48094
  getClient() {
47631
48095
  if (!this.client) {
@@ -47662,6 +48126,9 @@ var CloudTrailProvider = class {
47662
48126
  const isOrganizationTrail = properties["IsOrganizationTrail"];
47663
48127
  const eventSelectors = properties["EventSelectors"];
47664
48128
  const insightSelectors = properties["InsightSelectors"];
48129
+ const advancedEventSelectors = properties["AdvancedEventSelectors"] == null ? void 0 : requireConfigArray(properties["AdvancedEventSelectors"], "AWS::CloudTrail::Trail AdvancedEventSelectors", replayWarn(this.logger, context));
48130
+ const aggregationConfigurations = properties["AggregationConfigurations"] == null ? void 0 : requireConfigArray(properties["AggregationConfigurations"], "AWS::CloudTrail::Trail AggregationConfigurations", replayWarn(this.logger, context));
48131
+ const skippedOnReplay = [...properties["AdvancedEventSelectors"] != null && advancedEventSelectors === void 0 ? ["AdvancedEventSelectors"] : [], ...properties["AggregationConfigurations"] != null && aggregationConfigurations === void 0 ? ["AggregationConfigurations"] : []];
47665
48132
  let trailCreated = false;
47666
48133
  let createdTrailArn;
47667
48134
  try {
@@ -47685,11 +48152,20 @@ var CloudTrailProvider = class {
47685
48152
  trailCreated = true;
47686
48153
  const trailArn = result.TrailARN;
47687
48154
  createdTrailArn = result.TrailARN;
47688
- if (eventSelectors && eventSelectors.length > 0) {
48155
+ if (createdTrailArn) reportCreatedResource(logicalId, resourceType, createdTrailArn);
48156
+ const basicForCreate = eventSelectors && eventSelectors.length > 0 ? eventSelectors : void 0;
48157
+ if (basicForCreate || advancedEventSelectors && advancedEventSelectors.length > 0) {
47689
48158
  this.logger.debug(`Setting event selectors for CloudTrail Trail ${logicalId}`);
47690
48159
  await this.getClient().send(new PutEventSelectorsCommand({
47691
48160
  TrailName: trailArn,
47692
- EventSelectors: eventSelectors
48161
+ ...eventSelectorRequest(basicForCreate, advancedEventSelectors).members
48162
+ }));
48163
+ }
48164
+ if (aggregationConfigurations && aggregationConfigurations.length > 0) {
48165
+ this.logger.debug(safeMsg`Setting aggregation configurations for CloudTrail Trail ${logicalId}`);
48166
+ await this.getClient().send(new PutEventConfigurationCommand({
48167
+ TrailName: trailArn,
48168
+ AggregationConfigurations: aggregationConfigurations
47693
48169
  }));
47694
48170
  }
47695
48171
  if (insightSelectors && insightSelectors.length > 0) {
@@ -47706,7 +48182,8 @@ var CloudTrailProvider = class {
47706
48182
  this.logger.debug(`Successfully created CloudTrail Trail ${logicalId}: ${trailArn}`);
47707
48183
  return {
47708
48184
  physicalId: trailArn,
47709
- attributes: { Arn: trailArn }
48185
+ attributes: { Arn: trailArn },
48186
+ ...skippedOnReplay.length > 0 && { effectiveProperties: retainPreviousLists(properties, {}, skippedOnReplay) }
47710
48187
  };
47711
48188
  } catch (error) {
47712
48189
  if (trailCreated) markAuxiliaryFailure(error, logicalId);
@@ -47717,6 +48194,7 @@ var CloudTrailProvider = class {
47717
48194
  }
47718
48195
  }
47719
48196
  async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
48197
+ const desiredProperties = properties;
47720
48198
  properties = withRemovalDefaults(this.removalDefaults, resourceType, properties, previousProperties, context);
47721
48199
  this.logger.debug(`Updating CloudTrail Trail ${logicalId}: ${physicalId}`);
47722
48200
  refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
@@ -47733,6 +48211,7 @@ var CloudTrailProvider = class {
47733
48211
  const kmsKeyId = clearOnUpdateRemoval(emptyToUndefined(properties["KMSKeyId"]), emptyToUndefined(previousProperties["KMSKeyId"]), "");
47734
48212
  const snsTopicName = clearOnUpdateRemoval(emptyToUndefined(properties["SnsTopicName"]), emptyToUndefined(previousProperties["SnsTopicName"]), "");
47735
48213
  const isOrganizationTrail = properties["IsOrganizationTrail"];
48214
+ const appliedBeforeFailure = [];
47736
48215
  try {
47737
48216
  await this.getClient().send(new UpdateTrailCommand({
47738
48217
  Name: physicalId,
@@ -47747,36 +48226,61 @@ var CloudTrailProvider = class {
47747
48226
  SnsTopicName: snsTopicName,
47748
48227
  IsOrganizationTrail: isOrganizationTrail
47749
48228
  }));
47750
- const rawEventSelectors = properties["EventSelectors"];
47751
- let eventSelectorsUnusable = false;
47752
- let newEventSelectors;
47753
- if (rawEventSelectors != null) try {
47754
- newEventSelectors = requireConfigArray(rawEventSelectors, "AWS::CloudTrail::Trail EventSelectors");
47755
- } catch (error) {
47756
- eventSelectorsUnusable = true;
47757
- 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.`);
47758
- }
48229
+ const basicRead = readListBlock(properties["EventSelectors"], "AWS::CloudTrail::Trail EventSelectors");
48230
+ const advancedRead = readListBlock(properties["AdvancedEventSelectors"], "AWS::CloudTrail::Trail AdvancedEventSelectors");
48231
+ 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.`);
48232
+ const selectorsUnusable = basicRead.kind === "unusable" || advancedRead.kind === "unusable";
48233
+ const newEventSelectors = listOf$1(basicRead);
48234
+ const newAdvancedSelectors = listOf$1(advancedRead);
47759
48235
  const oldEventSelectors = previousProperties["EventSelectors"];
47760
- if (!eventSelectorsUnusable && JSON.stringify(newEventSelectors) !== JSON.stringify(oldEventSelectors)) {
47761
- const isRemoval = newEventSelectors === void 0 || newEventSelectors.length === 0;
47762
- const eventSelectorsToSend = newEventSelectors === void 0 || newEventSelectors.length === 0 ? DEFAULT_EVENT_SELECTORS : newEventSelectors;
48236
+ const oldAdvancedSelectors = previousProperties["AdvancedEventSelectors"];
48237
+ const hadAdvancedSelectors = Array.isArray(oldAdvancedSelectors) && oldAdvancedSelectors.length > 0;
48238
+ const aggregationRead = readListBlock(properties["AggregationConfigurations"], "AWS::CloudTrail::Trail AggregationConfigurations");
48239
+ 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.`);
48240
+ const newAggregation = listOf$1(aggregationRead);
48241
+ const aggregationChanged = aggregationRead.kind !== "unusable" && setKey(newAggregation) !== setKey(previousProperties["AggregationConfigurations"]);
48242
+ const aggregationCleared = aggregationChanged && nonEmptyListOf(aggregationRead) === void 0;
48243
+ const putAggregation = async () => {
48244
+ this.logger.debug(safeMsg`Updating aggregation configurations for CloudTrail Trail ${logicalId}`);
48245
+ await this.getClient().send(new PutEventConfigurationCommand({
48246
+ TrailName: physicalId,
48247
+ AggregationConfigurations: newAggregation ?? []
48248
+ }));
48249
+ };
48250
+ if (aggregationCleared) {
48251
+ await putAggregation();
48252
+ appliedBeforeFailure.push("AggregationConfigurations was cleared");
48253
+ }
48254
+ if (!selectorsUnusable && (JSON.stringify(newEventSelectors) !== JSON.stringify(oldEventSelectors) || setKey(newAdvancedSelectors) !== setKey(oldAdvancedSelectors))) {
48255
+ let basicToSend = newEventSelectors;
48256
+ let advancedToSend = newAdvancedSelectors;
48257
+ if (context?.desiredFromAwsReadback === true && nonEmptyListOf(basicRead) !== void 0 && nonEmptyListOf(advancedRead) !== void 0) {
48258
+ if (JSON.stringify(newEventSelectors) === JSON.stringify(oldEventSelectors)) basicToSend = void 0;
48259
+ else if (setKey(newAdvancedSelectors) === setKey(oldAdvancedSelectors)) advancedToSend = void 0;
48260
+ }
48261
+ const { members, isReset: isRemoval } = eventSelectorRequest(basicToSend, advancedToSend);
47763
48262
  this.logger.debug(isRemoval ? `Resetting event selectors to the AWS default for CloudTrail Trail ${logicalId}` : `Updating event selectors for CloudTrail Trail ${logicalId}`);
47764
48263
  try {
47765
48264
  await this.getClient().send(new PutEventSelectorsCommand({
47766
48265
  TrailName: physicalId,
47767
- EventSelectors: [...eventSelectorsToSend]
48266
+ ...members
47768
48267
  }));
48268
+ appliedBeforeFailure.push("the event selectors were updated");
47769
48269
  } catch (error) {
47770
48270
  const failure = describeAwsFailure(error);
47771
48271
  const message = withoutTrailIdentifiers(failure.detail, physicalId);
47772
48272
  const errorClass = error instanceof Error ? error.name : "";
47773
- if (!isRemoval || ACCESS_DENIAL_CLASS.test(errorClass) || !ADVANCED_SELECTOR_PHRASE.test(message)) throw error;
48273
+ if (!isRemoval || hadAdvancedSelectors || ACCESS_DENIAL_CLASS.test(errorClass) || !ADVANCED_SELECTOR_PHRASE.test(message)) throw error;
47774
48274
  const m = maskerOrIdentity(context?.maskSecrets);
47775
48275
  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 (`;
47776
48276
  if (failure.redacted) this.logger.debug(m(`${head}${m(failure.detail)})`));
47777
48277
  this.logger.warn(m(`${head}${failure.redacted ? failure.summary : failure.detail})`));
47778
48278
  }
47779
48279
  }
48280
+ if (aggregationChanged && !aggregationCleared) {
48281
+ await putAggregation();
48282
+ appliedBeforeFailure.push("AggregationConfigurations was updated");
48283
+ }
47780
48284
  const newInsightSelectors = properties["InsightSelectors"];
47781
48285
  const oldInsightSelectors = previousProperties["InsightSelectors"];
47782
48286
  if (JSON.stringify(newInsightSelectors) !== JSON.stringify(oldInsightSelectors)) {
@@ -47798,13 +48302,19 @@ var CloudTrailProvider = class {
47798
48302
  }
47799
48303
  await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
47800
48304
  this.logger.debug(`Successfully updated CloudTrail Trail ${logicalId}`);
47801
- return {
48305
+ const skipped = [...selectorsUnusable ? ["EventSelectors", "AdvancedEventSelectors"] : [], ...aggregationRead.kind === "unusable" ? ["AggregationConfigurations"] : []];
48306
+ if (skipped.length === 0) return {
47802
48307
  physicalId,
47803
48308
  wasReplaced: false
47804
48309
  };
48310
+ return {
48311
+ physicalId,
48312
+ wasReplaced: false,
48313
+ effectiveProperties: retainPreviousLists(desiredProperties, previousProperties, skipped, skipped.some((key) => previousProperties[key] != null && !Array.isArray(previousProperties[key])) ? await this.readLiveForRecord(physicalId, resourceType) : void 0)
48314
+ };
47805
48315
  } catch (error) {
47806
48316
  const cause = error instanceof Error ? error : void 0;
47807
- throw this.wrapCaughtError(context?.maskSecrets, error, (text) => new ProvisioningError(`Failed to update CloudTrail Trail ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
48317
+ 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));
47808
48318
  }
47809
48319
  }
47810
48320
  async delete(logicalId, physicalId, resourceType, properties, context) {
@@ -47834,6 +48344,19 @@ var CloudTrailProvider = class {
47834
48344
  throw stripped ? markDeleteStarted(notGone) : notGone;
47835
48345
  }
47836
48346
  }
48347
+ async readLiveForRecord(physicalId, resourceType) {
48348
+ try {
48349
+ const live = await this.readCurrentState(physicalId, "", resourceType);
48350
+ return live !== void 0 && live !== RESOURCE_NOT_FOUND ? live : void 0;
48351
+ } catch (error) {
48352
+ this.logger.debug(safeMsg`CloudTrail read-back for the record failed: ${describeAwsFailure(error).detail}`);
48353
+ return;
48354
+ }
48355
+ }
48356
+ getDriftUnorderedPaths(resourceType) {
48357
+ if (resourceType !== "AWS::CloudTrail::Trail") return [];
48358
+ return [...UNORDERED_LIST_BLOCKS];
48359
+ }
47837
48360
  getAttribute(_physicalId, _resourceType, attributeName) {
47838
48361
  return Promise.resolve(attributeName);
47839
48362
  }
@@ -47892,7 +48415,9 @@ var CloudTrailProvider = class {
47892
48415
  } catch {}
47893
48416
  try {
47894
48417
  const sel = await this.getClient().send(new GetEventSelectorsCommand({ TrailName: physicalId }));
47895
- if (!(Array.isArray(sel.AdvancedEventSelectors) && sel.AdvancedEventSelectors.length > 0)) result["EventSelectors"] = (sel.EventSelectors ?? []).map((es) => es);
48418
+ const hasAdvanced = Array.isArray(sel.AdvancedEventSelectors) && sel.AdvancedEventSelectors.length > 0;
48419
+ if (!hasAdvanced) result["EventSelectors"] = (sel.EventSelectors ?? []).map((es) => es);
48420
+ result["AdvancedEventSelectors"] = hasAdvanced ? advancedSelectorsToCfn(sel.AdvancedEventSelectors ?? []) : [];
47896
48421
  } catch {}
47897
48422
  let insightSelectors = [];
47898
48423
  try {
@@ -47907,6 +48432,14 @@ var CloudTrailProvider = class {
47907
48432
  this.logger.debug(`CloudTrail ListTags(${trail.TrailARN}) failed: ${describeAwsFailure(err).detail}`);
47908
48433
  }
47909
48434
  result["Tags"] = tags;
48435
+ try {
48436
+ result["AggregationConfigurations"] = ((await this.getClient().send(new GetEventConfigurationCommand({ TrailName: physicalId }))).AggregationConfigurations ?? []).map((a) => ({
48437
+ ...a.EventCategory !== void 0 && { EventCategory: a.EventCategory },
48438
+ ...a.Templates !== void 0 && { Templates: a.Templates }
48439
+ }));
48440
+ } catch (err) {
48441
+ this.logger.debug(safeMsg`CloudTrail GetEventConfiguration(${physicalId}) failed: ${describeAwsFailure(err).detail}`);
48442
+ }
47910
48443
  return result;
47911
48444
  }
47912
48445
  async import(input) {
@@ -48178,6 +48711,7 @@ var CodeBuildProvider = class {
48178
48711
  const projectName = result.project.name;
48179
48712
  const projectArn = result.project.arn;
48180
48713
  createdName = projectName;
48714
+ reportCreatedResource(logicalId, resourceType, createdName);
48181
48715
  if (visibilityRead.kind === "usable" && (visibilityRead.visibility !== DEFAULT_PROJECT_VISIBILITY || visibilityRead.resourceAccessRole !== void 0)) await this.applyVisibility(projectArn, visibilityRead);
48182
48716
  this.logger.debug(`Successfully created CodeBuild Project ${logicalId}: ${projectName}`);
48183
48717
  return {
@@ -48599,6 +49133,7 @@ var CodeCommitRepositoryProvider = class {
48599
49133
  if (!metadata?.repositoryName) throw new Error("CreateRepository did not return repository metadata");
48600
49134
  const createdName = metadata.repositoryName;
48601
49135
  leftLiveName = createdName;
49136
+ reportCreatedResource(logicalId, resourceType, createdName);
48602
49137
  try {
48603
49138
  const code = properties["Code"];
48604
49139
  if (code) await this.seedInitialCommit(createdName, code);
@@ -48612,7 +49147,10 @@ var CodeCommitRepositoryProvider = class {
48612
49147
  }
48613
49148
  } catch (postCreateError) {
48614
49149
  this.logger.warn(`Post-create step failed for CodeCommit Repository ${logicalId}; deleting the just-created repository ${createdName} to avoid an orphan`);
48615
- if (await this.bestEffortDelete(createdName, maskerOrIdentity(context?.maskSecrets))) leftLiveName = void 0;
49150
+ if (await this.bestEffortDelete(createdName, maskerOrIdentity(context?.maskSecrets))) {
49151
+ retractCreatedResource(logicalId, resourceType, leftLiveName);
49152
+ leftLiveName = void 0;
49153
+ }
48616
49154
  throw markAuxiliaryFailure(postCreateError, logicalId);
48617
49155
  }
48618
49156
  this.logger.debug(`Successfully created CodeCommit Repository ${logicalId}: ${createdName}`);
@@ -49472,6 +50010,370 @@ function notEmptyRefusalMessage(bucketName, maskSecrets) {
49472
50010
  const remedy = command ? `Delete all objects first (e.g. ${command}) and destroy again.` : secretDerived ? "Delete all objects first, via the console, and destroy again: the bucket name is derived from a secret, so cdkd does not print it." : "Delete all objects first, via the console, and destroy again: the bucket name cdkd recorded cannot be reproduced safely on a command line, so any command shown here could act on a different bucket or run part of the name as shell.";
49473
50011
  return mask(`bucket ${displayIdent(mask(bucketName))} is not empty. Matching CloudFormation, cdkd does not delete a non-empty directory bucket without an explicit opt-in. ${remedy}`);
49474
50012
  }
50013
+ function isRecord(value) {
50014
+ return typeof value === "object" && value !== null && !Array.isArray(value);
50015
+ }
50016
+ function itemId(item) {
50017
+ if (!isRecord(item)) return void 0;
50018
+ const id = item["Id"];
50019
+ return typeof id === "string" && id !== "" ? id : void 0;
50020
+ }
50021
+ function canonicalJson(value) {
50022
+ const sorted = (v) => {
50023
+ if (Array.isArray(v)) return v.map(sorted);
50024
+ if (isRecord(v)) return Object.fromEntries(Object.keys(v).sort().map((k) => [k, sorted(v[k])]));
50025
+ return v;
50026
+ };
50027
+ return JSON.stringify(sorted(value)) ?? "undefined";
50028
+ }
50029
+ function sameJson(a, b) {
50030
+ return canonicalJson(a) === canonicalJson(b);
50031
+ }
50032
+ function optionalString(value, path, refuse) {
50033
+ if (value === void 0 || value === null) return void 0;
50034
+ if (typeof value !== "string") refuse(path, "a string");
50035
+ return value;
50036
+ }
50037
+ function optionalBoolean(value, path, refuse) {
50038
+ if (value === void 0 || value === null) return void 0;
50039
+ if (typeof value === "boolean") return value;
50040
+ if (value === "true") return true;
50041
+ if (value === "false") return false;
50042
+ return refuse(path, "a boolean");
50043
+ }
50044
+ function optionalInteger(value, path, refuse) {
50045
+ if (value === void 0 || value === null) return void 0;
50046
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) return value;
50047
+ if (typeof value === "string" && /^[0-9]{1,15}$/.test(value)) return Number(value);
50048
+ return refuse(path, "a non-negative integer");
50049
+ }
50050
+ function listOf(value, path, refuse) {
50051
+ if (!Array.isArray(value)) refuse(path, "a list");
50052
+ return value;
50053
+ }
50054
+ function encryptionToSdk(value, refuse) {
50055
+ if (value === void 0 || value === null) return void 0;
50056
+ if (!isRecord(value)) refuse("BucketEncryption", "an object");
50057
+ const rules = listOf(value["ServerSideEncryptionConfiguration"], "BucketEncryption.ServerSideEncryptionConfiguration", refuse);
50058
+ if (rules.length === 0) return void 0;
50059
+ return { Rules: rules.map((rule, i) => {
50060
+ const path = `BucketEncryption.ServerSideEncryptionConfiguration[${i}]`;
50061
+ if (!isRecord(rule)) refuse(path, "an object");
50062
+ const out = {};
50063
+ const byDefault = rule["ServerSideEncryptionByDefault"];
50064
+ if (byDefault !== void 0 && byDefault !== null) {
50065
+ if (!isRecord(byDefault)) refuse(`${path}.ServerSideEncryptionByDefault`, "an object");
50066
+ const algorithm = optionalString(byDefault["SSEAlgorithm"], `${path}.ServerSideEncryptionByDefault.SSEAlgorithm`, refuse);
50067
+ const keyId = optionalString(byDefault["KMSMasterKeyID"], `${path}.ServerSideEncryptionByDefault.KMSMasterKeyID`, refuse);
50068
+ out.ApplyServerSideEncryptionByDefault = {
50069
+ SSEAlgorithm: algorithm,
50070
+ ...keyId !== void 0 ? { KMSMasterKeyID: keyId } : {}
50071
+ };
50072
+ }
50073
+ const bucketKey = optionalBoolean(rule["BucketKeyEnabled"], `${path}.BucketKeyEnabled`, refuse);
50074
+ if (bucketKey !== void 0) out.BucketKeyEnabled = bucketKey;
50075
+ return out;
50076
+ }) };
50077
+ }
50078
+ function lifecycleFilterToSdk(rule, path, refuse) {
50079
+ const prefix = optionalString(rule["Prefix"], `${path}.Prefix`, refuse);
50080
+ const greater = optionalInteger(rule["ObjectSizeGreaterThan"], `${path}.ObjectSizeGreaterThan`, refuse);
50081
+ const less = optionalInteger(rule["ObjectSizeLessThan"], `${path}.ObjectSizeLessThan`, refuse);
50082
+ const members = {
50083
+ ...prefix !== void 0 ? { Prefix: prefix } : {},
50084
+ ...greater !== void 0 ? { ObjectSizeGreaterThan: greater } : {},
50085
+ ...less !== void 0 ? { ObjectSizeLessThan: less } : {}
50086
+ };
50087
+ const count = Object.keys(members).length;
50088
+ if (count === 0) return { Prefix: "" };
50089
+ if (count === 1) return members;
50090
+ return { And: members };
50091
+ }
50092
+ function lifecycleToSdk(value, refuse) {
50093
+ if (value === void 0 || value === null) return void 0;
50094
+ if (!isRecord(value)) refuse("LifecycleConfiguration", "an object");
50095
+ const rules = listOf(value["Rules"], "LifecycleConfiguration.Rules", refuse);
50096
+ if (rules.length === 0) return void 0;
50097
+ return { Rules: rules.map((rule, i) => {
50098
+ const path = `LifecycleConfiguration.Rules[${i}]`;
50099
+ if (!isRecord(rule)) refuse(path, "an object");
50100
+ const id = optionalString(rule["Id"], `${path}.Id`, refuse);
50101
+ const status = optionalString(rule["Status"], `${path}.Status`, refuse);
50102
+ const days = optionalInteger(rule["ExpirationInDays"], `${path}.ExpirationInDays`, refuse);
50103
+ const out = {
50104
+ ...id !== void 0 ? { ID: id } : {},
50105
+ Status: status,
50106
+ Filter: lifecycleFilterToSdk(rule, path, refuse)
50107
+ };
50108
+ if (days !== void 0) out.Expiration = { Days: days };
50109
+ const abort = rule["AbortIncompleteMultipartUpload"];
50110
+ if (abort !== void 0 && abort !== null) {
50111
+ if (!isRecord(abort)) refuse(`${path}.AbortIncompleteMultipartUpload`, "an object");
50112
+ const after = optionalInteger(abort["DaysAfterInitiation"], `${path}.AbortIncompleteMultipartUpload.DaysAfterInitiation`, refuse);
50113
+ out.AbortIncompleteMultipartUpload = after !== void 0 ? { DaysAfterInitiation: after } : {};
50114
+ }
50115
+ return out;
50116
+ }) };
50117
+ }
50118
+ function keyedItems(value, property, refuse) {
50119
+ const out = /* @__PURE__ */ new Map();
50120
+ if (value === void 0 || value === null) return out;
50121
+ listOf(value, property, refuse).forEach((item, i) => {
50122
+ if (!isRecord(item)) refuse(`${property}[${i}]`, "an object");
50123
+ const id = itemId(item);
50124
+ if (id === void 0) refuse(`${property}[${i}].Id`, "a non-empty string");
50125
+ if (out.has(id)) refuse(`${property}[${i}].Id`, "an Id no other item of the list carries");
50126
+ out.set(id, item);
50127
+ });
50128
+ return out;
50129
+ }
50130
+ function recordedItems(value) {
50131
+ const out = /* @__PURE__ */ new Map();
50132
+ if (!Array.isArray(value)) return out;
50133
+ for (const item of value) {
50134
+ const id = itemId(item);
50135
+ if (id !== void 0 && !out.has(id)) out.set(id, item);
50136
+ }
50137
+ return out;
50138
+ }
50139
+ function metricsItemToSdk(id, item, path, refuse) {
50140
+ const prefix = optionalString(item["Prefix"], `${path}.Prefix`, refuse);
50141
+ const accessPoint = optionalString(item["AccessPointArn"], `${path}.AccessPointArn`, refuse);
50142
+ if (prefix !== void 0 && accessPoint !== void 0) return {
50143
+ Id: id,
50144
+ Filter: { And: {
50145
+ Prefix: prefix,
50146
+ AccessPointArn: accessPoint
50147
+ } }
50148
+ };
50149
+ if (prefix !== void 0) return {
50150
+ Id: id,
50151
+ Filter: { Prefix: prefix }
50152
+ };
50153
+ if (accessPoint !== void 0) return {
50154
+ Id: id,
50155
+ Filter: { AccessPointArn: accessPoint }
50156
+ };
50157
+ return { Id: id };
50158
+ }
50159
+ function inventoryItemToSdk(id, item, path, refuse) {
50160
+ const destination = item["Destination"];
50161
+ if (!isRecord(destination)) refuse(`${path}.Destination`, "an object");
50162
+ const bucketArn = optionalString(destination["BucketArn"], `${path}.Destination.BucketArn`, refuse);
50163
+ const accountId = optionalString(destination["BucketAccountId"], `${path}.Destination.BucketAccountId`, refuse);
50164
+ const format = optionalString(destination["Format"], `${path}.Destination.Format`, refuse);
50165
+ const destPrefix = optionalString(destination["Prefix"], `${path}.Destination.Prefix`, refuse);
50166
+ const enabled = optionalBoolean(item["Enabled"], `${path}.Enabled`, refuse);
50167
+ const versions = optionalString(item["IncludedObjectVersions"], `${path}.IncludedObjectVersions`, refuse);
50168
+ const prefix = optionalString(item["Prefix"], `${path}.Prefix`, refuse);
50169
+ const frequency = optionalString(item["ScheduleFrequency"], `${path}.ScheduleFrequency`, refuse);
50170
+ const fields = item["OptionalFields"];
50171
+ let optionalFields;
50172
+ if (fields !== void 0 && fields !== null) optionalFields = listOf(fields, `${path}.OptionalFields`, refuse).map((f, j) => {
50173
+ if (typeof f !== "string") refuse(`${path}.OptionalFields[${j}]`, "a string");
50174
+ return f;
50175
+ });
50176
+ return {
50177
+ Id: id,
50178
+ Destination: { S3BucketDestination: {
50179
+ Bucket: bucketArn,
50180
+ Format: format,
50181
+ ...accountId !== void 0 ? { AccountId: accountId } : {},
50182
+ ...destPrefix !== void 0 ? { Prefix: destPrefix } : {}
50183
+ } },
50184
+ IsEnabled: enabled,
50185
+ IncludedObjectVersions: versions,
50186
+ Schedule: { Frequency: frequency },
50187
+ ...prefix !== void 0 ? { Filter: { Prefix: prefix } } : {},
50188
+ ...optionalFields !== void 0 ? { OptionalFields: optionalFields } : {}
50189
+ };
50190
+ }
50191
+ function desiredConfigurations(properties, refuse, onUnusable) {
50192
+ const warnOut = (error, what) => onUnusable?.(`${error.message.replace(/ — the resource was not created$/, "")}; replaying a recorded state, so the bucket is created without ${what}`);
50193
+ const build = (fallback, what, run) => {
50194
+ if (!onUnusable) return run();
50195
+ try {
50196
+ return run();
50197
+ } catch (error) {
50198
+ if (!(error instanceof ProvisioningError)) throw error;
50199
+ warnOut(error, what);
50200
+ return fallback;
50201
+ }
50202
+ };
50203
+ const buildList = (property, toSdk) => {
50204
+ if (!onUnusable) {
50205
+ const out = /* @__PURE__ */ new Map();
50206
+ let i = 0;
50207
+ for (const [id, item] of keyedItems(properties[property], property, refuse)) out.set(id, toSdk(id, item, `${property}[${i++}]`));
50208
+ return out;
50209
+ }
50210
+ const out = /* @__PURE__ */ new Map();
50211
+ const value = properties[property];
50212
+ if (value === void 0 || value === null) return out;
50213
+ build(void 0, `any ${property} item`, () => listOf(value, property, refuse))?.forEach((item, i) => {
50214
+ const path = `${property}[${i}]`;
50215
+ build(void 0, `${path}`, () => {
50216
+ if (!isRecord(item)) refuse(path, "an object");
50217
+ const id = itemId(item);
50218
+ if (id === void 0) refuse(`${path}.Id`, "a non-empty string");
50219
+ if (out.has(id)) refuse(`${path}.Id`, "an Id no other item of the list carries");
50220
+ out.set(id, toSdk(id, item, path));
50221
+ });
50222
+ });
50223
+ return out;
50224
+ };
50225
+ const metrics = buildList("MetricsConfigurations", (id, item, path) => metricsItemToSdk(id, item, path, refuse));
50226
+ const inventory = buildList("InventoryConfigurations", (id, item, path) => inventoryItemToSdk(id, item, path, refuse));
50227
+ return {
50228
+ encryption: build(void 0, "its BucketEncryption", () => encryptionToSdk(properties["BucketEncryption"], refuse)),
50229
+ lifecycle: build(void 0, "its LifecycleConfiguration", () => lifecycleToSdk(properties["LifecycleConfiguration"], refuse)),
50230
+ metrics,
50231
+ inventory
50232
+ };
50233
+ }
50234
+ function configurationRefuser(resourceType, logicalId, physicalId) {
50235
+ const updating = physicalId !== void 0;
50236
+ return (path, expected) => {
50237
+ throw markNonRetryable(new ProvisioningError(`${updating ? "desired " : ""}${path} of ${resourceType} ${logicalId} is not ${expected} — the resource was not ${updating ? "updated" : "created"}`, resourceType, logicalId, physicalId));
50238
+ };
50239
+ }
50240
+ function encryptionFromSdk(rules) {
50241
+ return { ServerSideEncryptionConfiguration: rules.map((rule) => {
50242
+ const out = {};
50243
+ const byDefault = rule.ApplyServerSideEncryptionByDefault;
50244
+ if (byDefault) out["ServerSideEncryptionByDefault"] = {
50245
+ ...byDefault.SSEAlgorithm !== void 0 ? { SSEAlgorithm: byDefault.SSEAlgorithm } : {},
50246
+ ...byDefault.KMSMasterKeyID !== void 0 ? { KMSMasterKeyID: byDefault.KMSMasterKeyID } : {}
50247
+ };
50248
+ if (rule.BucketKeyEnabled !== void 0) out["BucketKeyEnabled"] = rule.BucketKeyEnabled;
50249
+ return out;
50250
+ }) };
50251
+ }
50252
+ function lifecycleFromSdk(rules) {
50253
+ return { Rules: rules.map((rule) => {
50254
+ const out = {};
50255
+ if (rule.ID !== void 0) out["Id"] = rule.ID;
50256
+ if (rule.Status !== void 0) out["Status"] = rule.Status;
50257
+ const scope = {
50258
+ ...rule.Filter?.And ?? {},
50259
+ ...rule.Filter ?? {}
50260
+ };
50261
+ const prefix = scope["Prefix"] ?? rule.Prefix;
50262
+ if (prefix !== void 0 && prefix !== "") out["Prefix"] = prefix;
50263
+ if (typeof scope["ObjectSizeGreaterThan"] === "number") out["ObjectSizeGreaterThan"] = String(scope["ObjectSizeGreaterThan"]);
50264
+ if (typeof scope["ObjectSizeLessThan"] === "number") out["ObjectSizeLessThan"] = String(scope["ObjectSizeLessThan"]);
50265
+ if (rule.Expiration?.Days !== void 0) out["ExpirationInDays"] = rule.Expiration.Days;
50266
+ if (rule.AbortIncompleteMultipartUpload) {
50267
+ const after = rule.AbortIncompleteMultipartUpload.DaysAfterInitiation;
50268
+ out["AbortIncompleteMultipartUpload"] = after !== void 0 ? { DaysAfterInitiation: after } : {};
50269
+ }
50270
+ return out;
50271
+ }) };
50272
+ }
50273
+ function metricsFromSdk(item) {
50274
+ const filter = item.Filter;
50275
+ const scope = filter?.And ?? filter ?? {};
50276
+ return {
50277
+ Id: item.Id,
50278
+ ...scope.Prefix !== void 0 ? { Prefix: scope.Prefix } : {},
50279
+ ...scope.AccessPointArn !== void 0 ? { AccessPointArn: scope.AccessPointArn } : {}
50280
+ };
50281
+ }
50282
+ function inventoryFromSdk(item) {
50283
+ const dest = item.Destination?.S3BucketDestination;
50284
+ return {
50285
+ Id: item.Id,
50286
+ Destination: {
50287
+ ...dest?.Bucket !== void 0 ? { BucketArn: dest.Bucket } : {},
50288
+ ...dest?.AccountId !== void 0 ? { BucketAccountId: dest.AccountId } : {},
50289
+ ...dest?.Format !== void 0 ? { Format: dest.Format } : {},
50290
+ ...dest?.Prefix !== void 0 ? { Prefix: dest.Prefix } : {}
50291
+ },
50292
+ ...item.IsEnabled !== void 0 ? { Enabled: item.IsEnabled } : {},
50293
+ ...item.IncludedObjectVersions !== void 0 ? { IncludedObjectVersions: item.IncludedObjectVersions } : {},
50294
+ ...item.Filter?.Prefix !== void 0 ? { Prefix: item.Filter.Prefix } : {},
50295
+ ...item.Schedule?.Frequency !== void 0 ? { ScheduleFrequency: item.Schedule.Frequency } : {},
50296
+ ...item.OptionalFields !== void 0 && item.OptionalFields.length > 0 ? { OptionalFields: [...item.OptionalFields] } : {}
50297
+ };
50298
+ }
50299
+ function impliedBucketKey(algorithm) {
50300
+ if (algorithm === "AES256") return false;
50301
+ if (algorithm === "aws:kms") return true;
50302
+ }
50303
+ function canonicalizeConfigurationsForDrift(properties) {
50304
+ let out = properties;
50305
+ const encryption = properties["BucketEncryption"];
50306
+ if (isRecord(encryption) && Array.isArray(encryption["ServerSideEncryptionConfiguration"])) {
50307
+ let changed = false;
50308
+ const rules = encryption["ServerSideEncryptionConfiguration"].map((rule) => {
50309
+ if (!isRecord(rule) || !("BucketKeyEnabled" in rule)) return rule;
50310
+ const byDefault = rule["ServerSideEncryptionByDefault"];
50311
+ const implied = impliedBucketKey(isRecord(byDefault) ? byDefault["SSEAlgorithm"] : void 0);
50312
+ const declared = rule["BucketKeyEnabled"];
50313
+ if (implied === void 0 || (declared === "true" ? true : declared === "false" ? false : declared) !== implied) return rule;
50314
+ changed = true;
50315
+ const { BucketKeyEnabled: _dropped, ...rest } = rule;
50316
+ return rest;
50317
+ });
50318
+ if (changed) out = {
50319
+ ...out,
50320
+ BucketEncryption: {
50321
+ ...encryption,
50322
+ ServerSideEncryptionConfiguration: rules
50323
+ }
50324
+ };
50325
+ }
50326
+ const lifecycle = properties["LifecycleConfiguration"];
50327
+ if (isRecord(lifecycle) && Array.isArray(lifecycle["Rules"])) {
50328
+ let changed = false;
50329
+ const rules = lifecycle["Rules"].map((rule) => {
50330
+ if (!isRecord(rule) || rule["Prefix"] !== "") return rule;
50331
+ changed = true;
50332
+ const { Prefix: _dropped, ...rest } = rule;
50333
+ return rest;
50334
+ });
50335
+ if (changed) out = {
50336
+ ...out,
50337
+ LifecycleConfiguration: {
50338
+ ...lifecycle,
50339
+ Rules: rules
50340
+ }
50341
+ };
50342
+ }
50343
+ return out;
50344
+ }
50345
+ function liveMatchesDesired(name, desired, live) {
50346
+ const d = canonicalizeConfigurationsForDrift({ [name]: desired[name] })[name];
50347
+ let l = canonicalizeConfigurationsForDrift({ [name]: live[name] })[name];
50348
+ if (name === "LifecycleConfiguration" && isRecord(d) && isRecord(l)) {
50349
+ const dRules = Array.isArray(d["Rules"]) ? d["Rules"] : [];
50350
+ const lRules = Array.isArray(l["Rules"]) ? l["Rules"] : [];
50351
+ l = {
50352
+ ...l,
50353
+ Rules: lRules.map((rule, i) => {
50354
+ const declared = dRules[i];
50355
+ if (!isRecord(rule) || !isRecord(declared) || "Id" in declared) return rule;
50356
+ const { Id: _assigned, ...rest } = rule;
50357
+ return rest;
50358
+ })
50359
+ };
50360
+ }
50361
+ if (name === "MetricsConfigurations" || name === "InventoryConfigurations") {
50362
+ const withSortedFields = (item) => isRecord(item) && Array.isArray(item["OptionalFields"]) ? {
50363
+ ...item,
50364
+ OptionalFields: [...item["OptionalFields"]].map(String).sort()
50365
+ } : item;
50366
+ const asSet = (v) => Array.isArray(v) ? v.map((item) => canonicalJson(withSortedFields(item))).sort() : [canonicalJson(v)];
50367
+ return sameJson(asSet(d), asSet(l));
50368
+ }
50369
+ return sameJson(d, l);
50370
+ }
50371
+ const CONFIGURATION_READ_ACTIONS = {
50372
+ BucketEncryption: "s3express:GetEncryptionConfiguration",
50373
+ LifecycleConfiguration: "s3express:GetLifecycleConfiguration",
50374
+ MetricsConfigurations: "s3express:GetMetricsConfiguration",
50375
+ InventoryConfigurations: "s3express:GetInventoryConfiguration"
50376
+ };
49475
50377
  var S3DirectoryBucketProvider = class {
49476
50378
  s3Client;
49477
50379
  createClient;
@@ -49489,8 +50391,44 @@ var S3DirectoryBucketProvider = class {
49489
50391
  "DataRedundancy",
49490
50392
  "LocationName",
49491
50393
  "BucketName",
49492
- "Tags"
50394
+ "Tags",
50395
+ "BucketEncryption",
50396
+ "LifecycleConfiguration",
50397
+ "MetricsConfigurations",
50398
+ "InventoryConfigurations"
49493
50399
  ])]]);
50400
+ async readUnsettled(physicalId, _logicalId, _resourceType, names, recordedProperties, desiredProperties) {
50401
+ const live = await this.readState(physicalId);
50402
+ if (live === RESOURCE_NOT_FOUND) return live;
50403
+ const desired = desiredProperties ?? recordedProperties ?? {};
50404
+ const out = {};
50405
+ for (const name of names) {
50406
+ if (!Object.hasOwn(live, name)) continue;
50407
+ if (desired[name] !== void 0 && liveMatchesDesired(name, desired, live)) {
50408
+ out[name] = desired[name];
50409
+ continue;
50410
+ }
50411
+ if (name === "MetricsConfigurations" || name === "InventoryConfigurations") {
50412
+ const named = /* @__PURE__ */ new Set([...recordedItems(recordedProperties?.[name]).keys(), ...recordedItems(desiredProperties?.[name]).keys()]);
50413
+ const items = live[name];
50414
+ out[name] = Array.isArray(items) ? items.filter((item) => {
50415
+ const id = itemId(item);
50416
+ return id !== void 0 && named.has(id);
50417
+ }) : items;
50418
+ continue;
50419
+ }
50420
+ out[name] = live[name];
50421
+ }
50422
+ return out;
50423
+ }
50424
+ getDriftUnorderedPaths(resourceType) {
50425
+ if (resourceType !== "AWS::S3Express::DirectoryBucket") return [];
50426
+ return ["MetricsConfigurations", "InventoryConfigurations"];
50427
+ }
50428
+ canonicalizeDriftProperties(resourceType, properties) {
50429
+ if (resourceType !== "AWS::S3Express::DirectoryBucket") return properties;
50430
+ return canonicalizeConfigurationsForDrift(properties);
50431
+ }
49494
50432
  ec2Client;
49495
50433
  s3ControlClient;
49496
50434
  providerRegion = ambientRegion();
@@ -49554,6 +50492,7 @@ var S3DirectoryBucketProvider = class {
49554
50492
  async create(logicalId, resourceType, properties, context) {
49555
50493
  this.logger.debug(`Creating S3 Express Directory Bucket ${logicalId}`);
49556
50494
  const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
50495
+ const configs = desiredConfigurations(properties, configurationRefuser(resourceType, logicalId), replayWarn(this.logger, context).onUnusable);
49557
50496
  const dataRedundancy = requireConfigString(properties["DataRedundancy"], "SingleAvailabilityZone", "AWS::S3Express::DirectoryBucket DataRedundancy", replayWarn(this.logger, context));
49558
50497
  const azName = properties["LocationName"]?.replace(/--x-s3$/, "") || "us-east-1a";
49559
50498
  const azId = await this.getAzId(azName);
@@ -49561,6 +50500,7 @@ var S3DirectoryBucketProvider = class {
49561
50500
  if (!bucketName) bucketName = generatedNameFor("AWS::S3Express::DirectoryBucket", logicalId, { zoneId: azId });
49562
50501
  const tags = desiredTags;
49563
50502
  const includeTags = tags.length > 0;
50503
+ let bucketCreated = false;
49564
50504
  try {
49565
50505
  const attributes = await this.buildAttributes(bucketName);
49566
50506
  await (await this.getCreateClient()).send(new CreateBucketCommand({
@@ -49577,19 +50517,112 @@ var S3DirectoryBucketProvider = class {
49577
50517
  ...includeTags ? { Tags: tags } : {}
49578
50518
  }
49579
50519
  }));
50520
+ bucketCreated = true;
49580
50521
  this.logger.debug(`Created S3 Express Directory Bucket: ${bucketName}`);
50522
+ await this.applyConfigurations(bucketName, configs, properties, {}, true);
49581
50523
  return {
49582
50524
  physicalId: bucketName,
49583
50525
  attributes
49584
50526
  };
49585
50527
  } catch (error) {
49586
50528
  const cause = error instanceof Error ? error : void 0;
49587
- throw this.wrapCaughtError(maskerOrIdentity(context?.maskSecrets), error, (text) => new ProvisioningError(`Failed to create S3 Express Directory Bucket ${logicalId}: ${text}`, resourceType, logicalId, bucketName, cause));
50529
+ const thrown = this.wrapCaughtError(maskerOrIdentity(context?.maskSecrets), error, (text) => new ProvisioningError(`Failed to create S3 Express Directory Bucket ${logicalId}: ${text}`, resourceType, logicalId, bucketName, cause));
50530
+ if (bucketCreated) markCreatedBeforeFailure(thrown, logicalId, resourceType, bucketName);
50531
+ throw thrown;
50532
+ }
50533
+ }
50534
+ async applyConfigurations(bucketName, desired, desiredRaw, previousRaw, creating, markUnsettled = () => {}) {
50535
+ const changed = (desiredValue, previousValue) => creating || !sameJson(desiredValue, previousValue);
50536
+ const holds = (value, toSdk) => {
50537
+ try {
50538
+ return toSdk(value, () => {
50539
+ throw new Error("malformed");
50540
+ }) !== void 0;
50541
+ } catch {
50542
+ return true;
50543
+ }
50544
+ };
50545
+ if (changed(desiredRaw["BucketEncryption"], previousRaw["BucketEncryption"])) {
50546
+ if (desired.encryption) {
50547
+ markUnsettled("BucketEncryption");
50548
+ await this.s3Client.send(new PutBucketEncryptionCommand({
50549
+ Bucket: bucketName,
50550
+ ServerSideEncryptionConfiguration: desired.encryption
50551
+ }));
50552
+ } else if (!creating && holds(previousRaw["BucketEncryption"], encryptionToSdk)) {
50553
+ markUnsettled("BucketEncryption");
50554
+ await this.s3Client.send(new DeleteBucketEncryptionCommand({ Bucket: bucketName }));
50555
+ this.logger.debug("Sent DeleteBucketEncryption: the default encryption is back to SSE-S3");
50556
+ }
50557
+ }
50558
+ if (changed(desiredRaw["LifecycleConfiguration"], previousRaw["LifecycleConfiguration"])) {
50559
+ if (desired.lifecycle) {
50560
+ markUnsettled("LifecycleConfiguration");
50561
+ await this.s3Client.send(new PutBucketLifecycleConfigurationCommand({
50562
+ Bucket: bucketName,
50563
+ LifecycleConfiguration: desired.lifecycle
50564
+ }));
50565
+ } else if (!creating && holds(previousRaw["LifecycleConfiguration"], lifecycleToSdk)) {
50566
+ markUnsettled("LifecycleConfiguration");
50567
+ await this.s3Client.send(new DeleteBucketLifecycleCommand({ Bucket: bucketName }));
50568
+ this.logger.debug("Sent DeleteBucketLifecycle: every lifecycle rule is removed");
50569
+ }
50570
+ }
50571
+ const desiredMetrics = recordedItems(desiredRaw["MetricsConfigurations"]);
50572
+ const previousMetrics = creating ? /* @__PURE__ */ new Map() : recordedItems(previousRaw["MetricsConfigurations"]);
50573
+ for (const [id, config] of desired.metrics) {
50574
+ if (previousMetrics.has(id) && sameJson(previousMetrics.get(id), desiredMetrics.get(id))) continue;
50575
+ markUnsettled("MetricsConfigurations");
50576
+ await this.s3Client.send(new PutBucketMetricsConfigurationCommand({
50577
+ Bucket: bucketName,
50578
+ Id: id,
50579
+ MetricsConfiguration: config
50580
+ }));
50581
+ }
50582
+ for (const id of previousMetrics.keys()) {
50583
+ if (desired.metrics.has(id)) continue;
50584
+ markUnsettled("MetricsConfigurations");
50585
+ await this.deleteItemIdempotently(new DeleteBucketMetricsConfigurationCommand({
50586
+ Bucket: bucketName,
50587
+ Id: id
50588
+ }));
50589
+ }
50590
+ const desiredInventory = recordedItems(desiredRaw["InventoryConfigurations"]);
50591
+ const previousInventory = creating ? /* @__PURE__ */ new Map() : recordedItems(previousRaw["InventoryConfigurations"]);
50592
+ for (const [id, config] of desired.inventory) {
50593
+ if (previousInventory.has(id) && sameJson(previousInventory.get(id), desiredInventory.get(id))) continue;
50594
+ markUnsettled("InventoryConfigurations");
50595
+ await this.s3Client.send(new PutBucketInventoryConfigurationCommand({
50596
+ Bucket: bucketName,
50597
+ Id: id,
50598
+ InventoryConfiguration: config
50599
+ }));
50600
+ }
50601
+ for (const id of previousInventory.keys()) {
50602
+ if (desired.inventory.has(id)) continue;
50603
+ markUnsettled("InventoryConfigurations");
50604
+ await this.deleteItemIdempotently(new DeleteBucketInventoryConfigurationCommand({
50605
+ Bucket: bucketName,
50606
+ Id: id
50607
+ }));
50608
+ }
50609
+ }
50610
+ async deleteItemIdempotently(command) {
50611
+ try {
50612
+ if (command instanceof DeleteBucketMetricsConfigurationCommand) await this.s3Client.send(command);
50613
+ else await this.s3Client.send(command);
50614
+ } catch (error) {
50615
+ if (error instanceof Error && error.name === "NoSuchConfiguration") {
50616
+ this.logger.debug("A configuration this update deletes is already gone");
50617
+ return;
50618
+ }
50619
+ throw error;
49588
50620
  }
49589
50621
  }
49590
50622
  async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
49591
50623
  if (context?.expectedRegion) for (const clientRegion of [await this.s3Client.config.region(), await this.getS3ControlClient().config.region()]) assertRegionMatch(clientRegion, context.expectedRegion, resourceType, logicalId, physicalId, "pre-update");
49592
50624
  refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
50625
+ const configs = desiredConfigurations(properties, configurationRefuser(resourceType, logicalId, physicalId));
49593
50626
  try {
49594
50627
  const plan = planTagDiff(previousProperties["Tags"], properties["Tags"]);
49595
50628
  const tagWarning = tagPlanWarning(plan, resourceType, logicalId);
@@ -49602,18 +50635,25 @@ var S3DirectoryBucketProvider = class {
49602
50635
  if (removedKeys.length > 0 || tagsToApply.length > 0) {
49603
50636
  const accountId = await this.getAccountId();
49604
50637
  const resourceArn = await this.buildBucketArn(physicalId, accountId);
49605
- if (removedKeys.length > 0) await this.getS3ControlClient().send(new UntagResourceCommand$29({
49606
- AccountId: accountId,
49607
- ResourceArn: resourceArn,
49608
- TagKeys: removedKeys
49609
- }));
49610
- if (tagsToApply.length > 0) await this.getS3ControlClient().send(new TagResourceCommand$28({
49611
- AccountId: accountId,
49612
- ResourceArn: resourceArn,
49613
- Tags: tagsToApply
49614
- }));
50638
+ if (removedKeys.length > 0) {
50639
+ context?.markUnsettled?.("Tags");
50640
+ await this.getS3ControlClient().send(new UntagResourceCommand$29({
50641
+ AccountId: accountId,
50642
+ ResourceArn: resourceArn,
50643
+ TagKeys: removedKeys
50644
+ }));
50645
+ }
50646
+ if (tagsToApply.length > 0) {
50647
+ context?.markUnsettled?.("Tags");
50648
+ await this.getS3ControlClient().send(new TagResourceCommand$28({
50649
+ AccountId: accountId,
50650
+ ResourceArn: resourceArn,
50651
+ Tags: tagsToApply
50652
+ }));
50653
+ }
49615
50654
  this.logger.debug(`Updated tags for S3 Express Directory Bucket ${physicalId}`);
49616
- } else this.logger.debug(`Update for S3 Express Directory Bucket ${logicalId} is a no-op (no tag changes; other properties are immutable)`);
50655
+ }
50656
+ await this.applyConfigurations(physicalId, configs, properties, previousProperties, false, (key) => context?.markUnsettled?.(key));
49617
50657
  return {
49618
50658
  physicalId,
49619
50659
  wasReplaced: false
@@ -49686,6 +50726,9 @@ var S3DirectoryBucketProvider = class {
49686
50726
  } while (continuationToken);
49687
50727
  }
49688
50728
  async readCurrentState(physicalId, _logicalId, _resourceType) {
50729
+ return this.readState(physicalId);
50730
+ }
50731
+ async readState(physicalId) {
49689
50732
  let locationType;
49690
50733
  try {
49691
50734
  locationType = (await this.s3Client.send(new HeadBucketCommand({ Bucket: physicalId })))?.BucketLocationType;
@@ -49697,8 +50740,63 @@ var S3DirectoryBucketProvider = class {
49697
50740
  const result = { BucketName: physicalId };
49698
50741
  if (physicalId.endsWith("--x-s3")) result["DataRedundancy"] = locationType === "LocalZone" ? "SingleLocalZone" : "SingleAvailabilityZone";
49699
50742
  result["Tags"] = await this.readTags(physicalId);
50743
+ const reads = [
50744
+ ["BucketEncryption", () => this.readEncryption(physicalId)],
50745
+ ["LifecycleConfiguration", () => this.readLifecycle(physicalId)],
50746
+ ["MetricsConfigurations", () => this.readMetrics(physicalId)],
50747
+ ["InventoryConfigurations", () => this.readInventory(physicalId)]
50748
+ ];
50749
+ (await Promise.all(reads.map(([key, read]) => read().catch((error) => {
50750
+ const name = error?.name;
50751
+ if (name === "AccessDenied" || name === "AccessDeniedException") throw new Error(`Reading ${key} of an S3 Express directory bucket needs ${CONFIGURATION_READ_ACTIONS[key]}: grant it to read the bucket back`, { cause: error });
50752
+ throw error;
50753
+ })))).forEach((value, i) => {
50754
+ result[reads[i][0]] = value;
50755
+ });
49700
50756
  return result;
49701
50757
  }
50758
+ async readEncryption(bucket) {
50759
+ try {
50760
+ return encryptionFromSdk((await this.s3Client.send(new GetBucketEncryptionCommand({ Bucket: bucket }))).ServerSideEncryptionConfiguration?.Rules ?? []);
50761
+ } catch (err) {
50762
+ if (err.name === "ServerSideEncryptionConfigurationNotFoundError") return { ServerSideEncryptionConfiguration: [] };
50763
+ throw err;
50764
+ }
50765
+ }
50766
+ async readLifecycle(bucket) {
50767
+ try {
50768
+ return lifecycleFromSdk((await this.s3Client.send(new GetBucketLifecycleConfigurationCommand({ Bucket: bucket }))).Rules ?? []);
50769
+ } catch (err) {
50770
+ if (err.name === "NoSuchLifecycleConfiguration") return { Rules: [] };
50771
+ throw err;
50772
+ }
50773
+ }
50774
+ async readMetrics(bucket) {
50775
+ const out = [];
50776
+ let token;
50777
+ do {
50778
+ const resp = await this.s3Client.send(new ListBucketMetricsConfigurationsCommand({
50779
+ Bucket: bucket,
50780
+ ContinuationToken: token
50781
+ }));
50782
+ for (const item of resp.MetricsConfigurationList ?? []) out.push(metricsFromSdk(item));
50783
+ token = resp.IsTruncated ? resp.NextContinuationToken : void 0;
50784
+ } while (token);
50785
+ return out;
50786
+ }
50787
+ async readInventory(bucket) {
50788
+ const out = [];
50789
+ let token;
50790
+ do {
50791
+ const resp = await this.s3Client.send(new ListBucketInventoryConfigurationsCommand({
50792
+ Bucket: bucket,
50793
+ ContinuationToken: token
50794
+ }));
50795
+ for (const item of resp.InventoryConfigurationList ?? []) out.push(inventoryFromSdk(item));
50796
+ token = resp.IsTruncated ? resp.NextContinuationToken : void 0;
50797
+ } while (token);
50798
+ return out;
50799
+ }
49702
50800
  async readTags(bucketName) {
49703
50801
  const accountId = await this.getAccountId();
49704
50802
  const resourceArn = await this.buildBucketArn(bucketName, accountId);
@@ -50055,6 +51153,7 @@ var S3TablesProvider = class {
50055
51153
  ...tags !== void 0 && { tags }
50056
51154
  }));
50057
51155
  tableCreated = true;
51156
+ reportCreatedResource(logicalId, resourceType, physicalId);
50058
51157
  if (!response.tableARN) throw new ProvisioningError(`CreateTable did not return a tableARN for ${logicalId} (${physicalId}) — refusing to record an empty TableARN attribute`, resourceType, logicalId, physicalId);
50059
51158
  const tableARN = response.tableARN;
50060
51159
  this.logger.debug(`Successfully created S3 Tables Table ${logicalId}: ${physicalId}`);
@@ -50582,6 +51681,7 @@ var ECRProvider = class {
50582
51681
  ...tags ? { tags } : {}
50583
51682
  }));
50584
51683
  repositoryCreated = true;
51684
+ reportCreatedResource(logicalId, resourceType, repositoryName);
50585
51685
  const repo = response.repository;
50586
51686
  if (!repo?.repositoryName) throw new Error("CreateRepository did not return repository name");
50587
51687
  const lifecyclePolicy = properties["LifecyclePolicy"];
@@ -51310,6 +52410,7 @@ var ACMCertificateProvider = class {
51310
52410
  const certificateArn = (await this.acmClient.send(new RequestCertificateCommand(input))).CertificateArn;
51311
52411
  if (!certificateArn) throw new ProvisioningError(`RequestCertificate succeeded but no CertificateArn returned for ${logicalId}`, resourceType, logicalId);
51312
52412
  requestedArn = certificateArn;
52413
+ reportCreatedResource(logicalId, resourceType, certificateArn);
51313
52414
  this.logger.debug(`Requested ACM certificate: ${certificateArn}`);
51314
52415
  if (!(process.env["CDKD_NO_WAIT"] === "true")) await this.waitForCertificateIssued(certificateArn, logicalId, resourceType, dnsValidationZones(properties));
51315
52416
  else this.logger.warn(`Skipping wait for ACM certificate ${logicalId} (CDKD_NO_WAIT=true). Downstream consumers (CloudFront / ALB) will fail until the cert reaches ISSUED.`);
@@ -51323,6 +52424,7 @@ var ACMCertificateProvider = class {
51323
52424
  };
51324
52425
  } catch (error) {
51325
52426
  const survivorNote = requestedArn ? await this.cleanupRequestedCertificate(requestedArn, logicalId, idempotencyToken, context?.maskSecrets) : void 0;
52427
+ if (requestedArn && survivorNote === void 0) retractCreatedResource(logicalId, resourceType, requestedArn);
51326
52428
  if (error instanceof CdkdError) {
51327
52429
  if (survivorNote === void 0) throw error;
51328
52430
  const thrown = new ProvisioningError(`${error.message} ${survivorNote}`, resourceType, logicalId, requestedArn, error);
@@ -51611,4 +52713,4 @@ var ACMCertificateProvider = class {
51611
52713
 
51612
52714
  //#endregion
51613
52715
  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 };
51614
- //# sourceMappingURL=provider-classes-DYke4HKr.js.map
52716
+ //# sourceMappingURL=provider-classes-DktsDsTf.js.map