@go-to-k/cdkd 0.290.35 → 0.290.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
- import { $ as isExportAliasCollision, $i as StackTerminationProtectionError, $n as maskSecretsInText, $r as stripControlChars, $t as withSharedDrainBudget, A as makeCanonicalizePropertiesFn, Ai as resolveBucketRegion, An as refuseMalformedResourcesForDestroy, Ar as AssetModeResolver, At as getAccountInfo, B as isWarmThroughputDecrease, Bi as DeployCancelledError, Bn as TemplateParser, Br as buildDenyExternalAccessPolicy, Bt as assertRegionMatch, C as PRE_DELETE_SNAPSHOT_TYPES, Ci as expectedOwnerParam, Cn as malformedStateRefusalMessage, Cr as AssetPublisher, Ct as disableInstanceApiTermination, D as isFinalSnapshotError, Di as AssemblyReader, Dn as refuseMalformedOutputs, Dr as createAssetRedirectResolver, Dt as carriesFetchableDynamicReference, E as createPreDeleteFinalSnapshot, Ei as derivePartitionAndUrlSuffix, En as refuseMalformedNestedChildOutputs, Er as buildAssetRedirectMap, Et as carriesDynamicReference, F as isStatefulRecreateTargetForReplace, Fn as findActionableSilentDrops, Fr as isCrossRegionRedirect, Ft as refStateLookupFromResource, G as cyan, Gn as carriesSecretMask, Gr as dockerSpawnEnvWithSensitive, Gt as configStringRefusal, H as toFiniteNumber, Hi as IntrinsicResolutionRefusalError, Hn as STATE_SOURCED_CROSS_GENERATION_RULES, Hr as describeDockerCapturedOutput, Ht as coerceCfnInteger, I as isStatefulRecreateTargetSync, Ii as CdkdError, In as findSilentDropProperties, Ir as parseBootstrapMarker, It as isSettledInstanceState, J as red, Ji as PartialFailureError, Jn as errorCauseChain, Jr as partitionSensitiveEnv, Jt as requireConfigArray, K as gray, Ki as MalformedProducerRecordRefusalError, Kn as createSecretMasker, Kr as formatDockerLoginError, Kt as readConfigString, L as renderStatefulReason, Ln as describeTypeWithThrottleRetry, Lr as readBootstrapMarkerBody, Lt as WAFv2WebACLProvider, M as makeSiblingClaimReader, Mi as getAwsClients, Mn as repairMalformedOutputsForReadOnly, Mr as assertAssetBucketRegion, Mt as isNamelessDynamicReferenceError, N as planOrphanAdoption, Ni as resetAwsClients, Nn as repairMalformedResourcePropertiesForReadOnly, Nr as ensureAssetStorage, Nt as isUnboundTemplateParameter, O as refusesFinalSnapshot, Oi as processStackMessages, On as refuseMalformedOutputsForDestroy, Or as loadPublishableAssetManifest, Ot as cfnRefValueFromPhysicalId, P as MULTI_REGION_RECREATE_BLOCKED_TYPES, Pi as setAwsClients, Pn as repairMalformedResourcesForReadOnly, Pr as getBootstrapMarkerKey, Pt as parameterTypeMayLoseSecretIdentity, Q as exportAliasCollisionScrubWarning, Qi as StackHasActiveImportsError, Qn as maskSecretsInError, Qr as escapeRegExp, Qt as producerRegionsFromState, R as WARM_THROUGHPUT_MEMBERS, Ri as CrossAccountSecretRefusalError, Rn as withRetry, Rr as validateAssetBucketName, Rt as normalizeAwsTagsToCfn, S as ATOMIC_FINAL_SNAPSHOT_TYPES, Si as decodeListingKey, Sn as malformedResourcesWarning, Sr as shouldRetainResource, St as deleteSkipReason, T as ccRoutedFinalSnapshotError, Ti as canonicalizeRegion, Tn as refuseDivergentRecordRegionForDestroy, Tr as WorkGraph, Tt as IntrinsicFunctionResolver, U as formatResourceLine, Ui as LocalInvokeBuildError$1, Un as STATE_SOURCED_READBACK_RULES, Ur as describeDockerExecFailure, Ut as configBooleanRefusal, V as toCfnInteger, Vi as DynamicReferenceRegionAmbiguousError, Vn as STATE_SOURCED_BASELINE_RULES, Vr as buildDockerImage, Vt as coerceCfnBoolean, W as bold, Wi as LocalStartServiceError, Wn as TEMPLATE_SOURCED_RULES, Wr as describeDockerFailure, Wt as configIntegerRefusal, X as collectDeclaredOutputNames, Xi as ResourceTimeoutError, Xn as isSingleDynamicReferenceToken, Xr as runDockerForeground, Xt as requireConfigString, Y as yellow, Yi as ProvisioningError, Yn as identityKeyFor, Yr as redactDockerArgvValues, Yt as requireConfigObject, Z as collectPublishedOutputNames, Zi as ResourceUpdateNotSupportedError, Zn as markSameGenerationBag, Zr as runDockerStreaming, Zt as classifyReplaySecretRegion, _ as bagHoldsSecretExpression, _i as CFN_TEMPLATE_URL_LIMIT, _n as malformedLocalOutputsWarning, _r as importableOutputKeys, _t as CloudControlProvider, a as DeploymentEventsStore, aa as withErrorHandling, ai as getLegacyStateBucketName, an as applyRoleArnIfSet, ar as S3StateBackend, at as collectInlinePolicyNamesManagedBySiblings, b as mergeNoChangeOutputs, bi as uploadCfnTemplate, bn as malformedRenderedContainersWarning, br as orphansAfterRollback, bt as UNSPECIFIED_SKIP_REASON, c as replayFailedOperations, ca as isThrottlingError, ci as resolveCaptureObservedState, cn as callerEnvCredentials, cr as buildForceUnlockCommand, ct as wouldReturnToSdkProvider, d as updatePartialMessage, da as markRedactedCause, di as resolveStateBucketWithDefaultAndSource, dn as INTRINSIC_KEYS, dr as formatLockExpiry, dt as maskerOrIdentity, ei as AssetManifestLoader, en as s3BucketArn, er as recordMaskOnlyValue, et as secretBearing, f as updatePartialReason, fa as retryClassificationText, fi as resolveUseCdkBootstrapAssets, fn as STATE_RESOURCES_MALFORMED, fr as shellQuote, ft as beginCommandInterruptScope, g as computeImplicitDeleteEdges, gi as CFN_TEMPLATE_BODY_LIMIT, gn as malformedExportSourceWarning, gr as hasReadableExportSet, gt as startInterruptWatch, h as IMPLICIT_DELETE_DEPENDENCIES, hi as ssmResolvedValueType, hn as malformedExportNamesWarning, hr as exportNamesCarriedFrom, ht as isInterruptedWaitError, i as DeploymentEventsReader, ia as normalizeAwsError, ii as getDefaultStateBucketName, in as s3BucketWebsiteUrl, ir as LockManager, it as IAMRoleProvider, j as extractDeploymentEventError, ji as AwsClients, jn as refuseMalformedState, jr as BOOTSTRAP_MARKER_PREFIX, jt as isImpossibleEmptyStoredAttribute, k as unsupportedFinalSnapshotError, kn as refuseMalformedResourcePropertiesForOrphan, kr as rewriteTemplateAssetReferences, kt as coerceParameterTypedValue, l as replayRollback, la as isTransientServerError, li as resolveSkipPrefix, ln as envCredentialsAreAssumedRole, lr as buildLockContentionMessage, lt as createMaskedRetryLogger, m as maskingRetryLogger, ma as safeStringify, mi as warnDeprecatedNoPrefixCliFlag, mn as hasReadableResources, mr as DEFAULT_STATE_PREFIX, mt as interruptWatchListenerCount, n as DEFAULT_RESOURCE_WARN_AFTER_MS, ni as Synthesizer, nn as s3BucketDualStackDomainName, nr as redactSecretsForState, nt as secretSafeKeyDisplay, o as planFailedOps, oa as isMarkedNonRetryable, oi as resolveApp, on as AWS_CREDENTIAL_ENV_KEYS, or as rebuildClientForBucketRegion, ot as clearOnUpdateRemoval, p as withResourceDeadline, pa as describeAwsFailure, pi as stateBucketExistenceConfirmed, pn as hasReadableOutputs, pr as CUSTOM_RESOURCE_RESPONSE_PREFIX, pt as endCommandInterruptScope, q as green, qi as NestedStackChildDirectDestroyError, qn as dynamicReferenceTokens, qr as getDockerCmd, qt as replayWarn, r as DeployEngine, ri as synthesisStatusMessage, rn as s3BucketRegionalDomainName, rr as scrubResourceRecord, rt as getCurrentResourceSecrets, s as planRollback, sa as isRetryableTransientError, si as resolveAutoAssetStorage, sn as applyCallerIdentityCredentials, sr as UNREPRODUCIBLE_LOCK_CLAUSE, st as ProviderRegistry, t as DEFAULT_RESOURCE_TIMEOUT_MS, ta as SynthesisError, ti as getDockerImageBySourceHash, tn as s3BucketDomainName, tr as recoverMaskedOutput, tt as secretBearingStateKeyWarning, u as resolveReplacementOldType, ua as markNonRetryable, ui as resolveStateBucketWithDefault, un as DiffCalculator, ur as forceQuitRecoveryClause, ut as maskDeep, v as isSecretBearingReferenceString, vi as MIGRATE_TMP_PREFIX, vn as malformedOutputsRefusalMessage, vr as importableOutputs, vt as isWaitAbandonedError, w as buildFinalSnapshotIdentifier, wi as PARTITION_TABLE, wn as producerRecordKey, wr as stringifyValue, wt as isTerminationProtectionPropagationError, x as bindingSkippedOutputs, xi as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, xn as malformedResourcePropertiesWarning, xr as orphansCarriedFrom, xt as deleteIndeterminateGuards, y as keptWholeReasonText, yi as findLargeInlineResources, yn as malformedOutputsWarning, yr as isReadableBag, yt as slowCcOperationTimeoutMs, z as coerceWarmThroughput$1, zn as DagBuilder, zr as validateContainerRepoName, zt as resolveExplicitPhysicalId } from "./deploy-engine-DhZtBBq0.js";
1
+ import { $ as yellow, $i as NestedStackChildDirectDestroyError, $n as identityKeyFor, $r as getDockerCmd, $t as requireConfigObject, A as createPreDeleteFinalSnapshot, Ai as PARTITION_TABLE, An as refuseMalformedNestedChildOutputs, Ar as stringifyValue, At as carriesDynamicReference, B as isStatefulRecreateTargetSync, Bi as setAwsClients, Bn as findSilentDropProperties, Br as getBootstrapMarkerKey, Bt as isSettledInstanceState, C as namesAnyDeclaredParameter, Ci as CFN_TEMPLATE_URL_LIMIT, Cn as malformedOutputsWarning, Cr as importableOutputKeys, Ct as slowCcOperationTimeoutMs, D as PRE_DELETE_SNAPSHOT_TYPES, Di as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, Dn as malformedStateRefusalMessage, Dr as orphansCarriedFrom, Dt as disableInstanceApiTermination, E as ATOMIC_FINAL_SNAPSHOT_TYPES, Ei as uploadCfnTemplate, En as malformedResourcesWarning, Er as orphansAfterRollback, Et as deleteSkipReason, F as extractDeploymentEventError, Fn as refuseMalformedState, Fr as rewriteTemplateAssetReferences, Ft as isImpossibleEmptyStoredAttribute, G as toCfnInteger, Gn as STATE_SOURCED_BASELINE_RULES, Gr as validateContainerRepoName, Gt as coerceCfnBoolean, H as WARM_THROUGHPUT_MEMBERS, Hi as CdkdError, Hn as withRetry, Hr as parseBootstrapMarker, Ht as normalizeAwsTagsToCfn, I as makeSiblingClaimReader, Ii as resolveBucketRegion, In as repairMalformedOutputsForReadOnly, Ir as AssetModeResolver, It as isNamelessDynamicReferenceError, J as bold, Ji as IntrinsicResolutionRefusalError, Jn as TEMPLATE_SOURCED_RULES, Jr as describeDockerCapturedOutput, Jt as configIntegerRefusal, K as toFiniteNumber, Ki as DeployCancelledError, Kn as STATE_SOURCED_CROSS_GENERATION_RULES, Kr as buildDenyExternalAccessPolicy, Kt as coerceCfnInteger, L as planOrphanAdoption, Li as AwsClients, Ln as repairMalformedResourcePropertiesForReadOnly, Lr as BOOTSTRAP_MARKER_PREFIX, Lt as isUnboundTemplateParameter, M as refusesFinalSnapshot, Mi as derivePartitionAndUrlSuffix, Mn as refuseMalformedOutputsForDestroy, Mr as buildAssetRedirectMap, Mt as cfnRefValueFromPhysicalId, N as unsupportedFinalSnapshotError, Ni as AssemblyReader, Nn as refuseMalformedResourcePropertiesForOrphan, Nr as createAssetRedirectResolver, Nt as coerceParameterTypedValue, O as buildFinalSnapshotIdentifier, Oi as decodeListingKey, On as producerRecordKey, Or as shouldRetainResource, Ot as isTerminationProtectionPropagationError, P as makeCanonicalizePropertiesFn, Pi as processStackMessages, Pn as refuseMalformedResourcesForDestroy, Pr as loadPublishableAssetManifest, Pt as getAccountInfo, Q as red, Qi as MalformedProducerRecordRefusalError, Qn as errorCauseChain, Qr as formatDockerLoginError, Qt as requireConfigArray, R as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ri as getAwsClients, Rn as repairMalformedResourcesForReadOnly, Rr as assertAssetBucketRegion, Rt as parameterTypeMayLoseSecretIdentity, S as computeParameterTaint, Si as CFN_TEMPLATE_BODY_LIMIT, Sn as malformedOutputsRefusalMessage, Sr as hasUnverifiableParameterRefusal, St as isWaitAbandonedError, T as resourcesNamingDeclaredParameter, Ti as findLargeInlineResources, Tn as malformedResourcePropertiesWarning, Tr as isReadableBag, Tt as deleteIndeterminateGuards, U as coerceWarmThroughput$1, Un as DagBuilder, Ur as readBootstrapMarkerBody, Ut as resolveExplicitPhysicalId, V as renderStatefulReason, Vn as describeTypeWithThrottleRetry, Vr as isCrossRegionRedirect, Vt as WAFv2WebACLProvider, W as isWarmThroughputDecrease, Wi as CrossAccountSecretRefusalError, Wn as TemplateParser, Wr as validateAssetBucketName, Wt as assertRegionMatch, X as gray, Xi as LocalStartServiceError, Xn as createSecretMasker, Xr as describeDockerFailure, Xt as readConfigString, Y as cyan, Yi as LocalInvokeBuildError$1, Yn as carriesSecretMask, Yr as describeDockerExecFailure, Yt as configStringRefusal, Z as green, Zn as dynamicReferenceTokens, Zr as dockerSpawnEnvWithSensitive, Zt as replayWarn, _ as bagHoldsSecretExpression, _a as markRedactedCause, _i as resolveStateBucketWithDefaultAndSource, _n as hasReadableOutputs, _r as CUSTOM_RESOURCE_RESPONSE_PREFIX, _t as endCommandInterruptScope, a as DeploymentEventsStore, aa as StackTerminationProtectionError, ai as stripControlChars, an as s3BucketDomainName, ar as recoverMaskedOutput, at as secretBearingStateKeyWarning, b as mergeNoChangeOutputs, ba as safeStringify, bi as warnDeprecatedNoPrefixCliFlag, bn as malformedExportSourceWarning, br as hasReadableExportSet, bt as startInterruptWatch, c as replayFailedOperations, ci as Synthesizer, cn as s3BucketWebsiteUrl, cr as LockManager, ct as IAMRoleProvider, d as updatePartialMessage, da as withErrorHandling, di as getLegacyStateBucketName, dn as applyCallerIdentityCredentials, dr as UNREPRODUCIBLE_LOCK_CLAUSE, dt as ProviderRegistry, ea as PartialFailureError, ei as partitionSensitiveEnv, en as requireConfigString, er as isSingleDynamicReferenceToken, et as collectDeclaredOutputNames, f as updatePartialReason, fa as isMarkedNonRetryable, fi as resolveApp, fn as callerEnvCredentials, fr as buildForceUnlockCommand, ft as wouldReturnToSdkProvider, g as computeImplicitDeleteEdges, ga as markNonRetryable, gi as resolveStateBucketWithDefault, gn as STATE_RESOURCES_MALFORMED, gr as shellQuote, gt as beginCommandInterruptScope, h as IMPLICIT_DELETE_DEPENDENCIES, ha as isTransientServerError, hi as resolveSkipPrefix, hn as INTRINSIC_KEYS, hr as formatLockExpiry, ht as maskerOrIdentity, i as DeploymentEventsReader, ia as StackHasActiveImportsError, ii as escapeRegExp, in as s3BucketArn, ir as recordMaskOnlyValue, it as secretBearing, j as isFinalSnapshotError, ji as canonicalizeRegion, jn as refuseMalformedOutputs, jr as WorkGraph, jt as carriesFetchableDynamicReference, k as ccRoutedFinalSnapshotError, ki as expectedOwnerParam, kn as refuseDivergentRecordRegionForDestroy, kr as AssetPublisher, kt as IntrinsicFunctionResolver, l as replayRollback, li as synthesisStatusMessage, ln as applyRoleArnIfSet, lr as S3StateBackend, lt as collectInlinePolicyNamesManagedBySiblings, m as maskingRetryLogger, ma as isThrottlingError, mi as resolveCaptureObservedState, mn as DiffCalculator, mr as forceQuitRecoveryClause, mt as maskDeep, n as DEFAULT_RESOURCE_WARN_AFTER_MS, na as ResourceTimeoutError, ni as runDockerForeground, nn as producerRegionsFromState, nr as maskSecretsInError, nt as exportAliasCollisionScrubWarning, o as planFailedOps, oi as AssetManifestLoader, on as s3BucketDualStackDomainName, or as redactSecretsForState, ot as secretSafeKeyDisplay, p as withResourceDeadline, pa as isRetryableTransientError, pi as resolveAutoAssetStorage, pn as envCredentialsAreAssumedRole, pr as buildLockContentionMessage, pt as createMaskedRetryLogger, q as formatResourceLine, qi as DynamicReferenceRegionAmbiguousError, qn as STATE_SOURCED_READBACK_RULES, qr as buildDockerImage, qt as configBooleanRefusal, r as DeployEngine, ra as ResourceUpdateNotSupportedError, ri as runDockerStreaming, rn as withSharedDrainBudget, rr as maskSecretsInText, rt as isExportAliasCollision, s as planRollback, sa as SynthesisError, si as getDockerImageBySourceHash, sn as s3BucketRegionalDomainName, sr as scrubResourceRecord, st as getCurrentResourceSecrets, t as DEFAULT_RESOURCE_TIMEOUT_MS, ta as ProvisioningError, ti as redactDockerArgvValues, tn as classifyReplaySecretRegion, tr as markSameGenerationBag, tt as collectPublishedOutputNames, u as resolveReplacementOldType, ua as normalizeAwsError, ui as getDefaultStateBucketName, un as AWS_CREDENTIAL_ENV_KEYS, ur as rebuildClientForBucketRegion, ut as clearOnUpdateRemoval, v as isSecretBearingReferenceString, va as retryClassificationText, vi as resolveUseCdkBootstrapAssets, vn as hasReadableResources, vr as DEFAULT_STATE_PREFIX, vt as interruptWatchListenerCount, w as reachableDivergentParameters, wi as MIGRATE_TMP_PREFIX, wn as malformedRenderedContainersWarning, wr as importableOutputs, wt as UNSPECIFIED_SKIP_REASON, x as bindingSkippedOutputs, xi as ssmResolvedValueType, xn as malformedLocalOutputsWarning, xr as hasReasonlessBaselineRefusal, xt as CloudControlProvider, y as keptWholeReasonText, ya as describeAwsFailure, yi as stateBucketExistenceConfirmed, yn as malformedExportNamesWarning, yr as exportNamesCarriedFrom, yt as isInterruptedWaitError, z as isStatefulRecreateTargetForReplace, zi as resetAwsClients, zn as findActionableSilentDrops, zr as ensureAssetStorage, zt as refStateLookupFromResource } from "./deploy-engine-pVC4fG22.js";
2
2
  import { C as displayAwsMessage, D as truncateCodePoints, E as isPasteableIdent, S as UNRENDERABLE, T as displaySafe, _ as withSkipPrefix, b as SECRET_REF_MAX_CODE_POINTS, c as PATTERN_B_NAME_OPTIONS, f as explicitNamePropertyFor, h as getCurrentStackName, i as reserveStdoutForPayload, l as PATTERN_B_NAME_PROPERTIES, m as generateResourceNameWithFallback, n as getLogger, o as runStackBuffered, p as generateResourceName, s as getLiveRenderer, u as PATTERN_B_RESOURCE_TYPES, v as withStackName, w as displayIdent, x as STACK_REF_MAX_CODE_POINTS } from "./logger-BX4pJk0T.js";
3
3
  import { n as awsClientDefaults } from "./aws-client-defaults-BoIxyCir.js";
4
- import { t as getCdkdVersion } from "./version-BIpCWEQx.js";
5
- import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-BguZAQtF.js";
4
+ import { t as getCdkdVersion } from "./version-COEQwjCP.js";
5
+ import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-CXLgFrPg.js";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
  import { createHash, randomBytes, randomUUID } from "node:crypto";
8
8
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -12,7 +12,7 @@ import { CreateTopicCommand, DeleteTopicCommand, GetSubscriptionAttributesComman
12
12
  import { AddPermissionCommand, CreateEventSourceMappingCommand, CreateFunctionCommand, CreateFunctionUrlConfigCommand, DeleteEventSourceMappingCommand, DeleteFunctionCodeSigningConfigCommand, DeleteFunctionCommand, DeleteFunctionConcurrencyCommand, DeleteFunctionEventInvokeConfigCommand, DeleteFunctionUrlConfigCommand, DeleteLayerVersionCommand, GetEventSourceMappingCommand, GetFunctionCodeSigningConfigCommand, GetFunctionCommand, GetFunctionConcurrencyCommand, GetFunctionEventInvokeConfigCommand, GetFunctionRecursionConfigCommand, GetFunctionUrlConfigCommand, GetLayerVersionByArnCommand, GetPolicyCommand as GetPolicyCommand$1, GetRuntimeManagementConfigCommand, LambdaClient, ListTagsCommand, PublishLayerVersionCommand, PutFunctionCodeSigningConfigCommand, PutFunctionConcurrencyCommand, PutFunctionEventInvokeConfigCommand, PutFunctionRecursionConfigCommand, PutRuntimeManagementConfigCommand, RemovePermissionCommand, ResourceNotFoundException, TagResourceCommand as TagResourceCommand$1, UntagResourceCommand as UntagResourceCommand$1, UpdateEventSourceMappingCommand, UpdateFunctionCodeCommand, UpdateFunctionConfigurationCommand, UpdateFunctionUrlConfigCommand, waitUntilFunctionActiveV2, waitUntilFunctionUpdatedV2 } from "@aws-sdk/client-lambda";
13
13
  import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
14
14
  import { AllocateAddressCommand, AssociateAddressCommand, AssociateIamInstanceProfileCommand, AssociateRouteTableCommand, AttachInternetGatewayCommand, AuthorizeSecurityGroupEgressCommand, AuthorizeSecurityGroupIngressCommand, CreateInternetGatewayCommand, CreateNatGatewayCommand, CreateNetworkAclCommand, CreateNetworkAclEntryCommand, CreateRouteCommand, CreateRouteTableCommand, CreateSecurityGroupCommand, CreateSubnetCommand, CreateTagsCommand, CreateVpcCommand, DeleteInternetGatewayCommand, DeleteNatGatewayCommand, DeleteNetworkAclCommand, DeleteNetworkAclEntryCommand, DeleteNetworkInterfaceCommand, DeleteRouteCommand, DeleteRouteTableCommand, DeleteSecurityGroupCommand, DeleteSubnetCommand, DeleteTagsCommand, DeleteVpcCommand, DescribeAddressesCommand, DescribeAvailabilityZonesCommand, DescribeIamInstanceProfileAssociationsCommand, DescribeInstanceAttributeCommand, DescribeInstanceCreditSpecificationsCommand, DescribeInstancesCommand, DescribeInternetGatewaysCommand, DescribeNatGatewaysCommand, DescribeNetworkAclsCommand, DescribeNetworkInterfacesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupRulesCommand, DescribeSecurityGroupsCommand, DescribeSubnetsCommand, DescribeVolumesCommand, DescribeVpcAttributeCommand, DescribeVpcsCommand, DetachInternetGatewayCommand, DisassociateAddressCommand, DisassociateRouteTableCommand, EC2Client, ModifyInstanceAttributeCommand, ModifyInstanceCreditSpecificationCommand, ModifyInstanceMetadataOptionsCommand, ModifySubnetAttributeCommand, ModifyVpcAttributeCommand, MonitorInstancesCommand, ReleaseAddressCommand, ReplaceNetworkAclAssociationCommand, RevokeSecurityGroupEgressCommand, RevokeSecurityGroupIngressCommand, RunInstancesCommand, TerminateInstancesCommand, UnmonitorInstancesCommand, waitUntilInstanceRunning, waitUntilInstanceTerminated, waitUntilNatGatewayAvailable, waitUntilNatGatewayDeleted } from "@aws-sdk/client-ec2";
15
- import { CreateTableCommand, DeleteResourcePolicyCommand, DeleteTableCommand, DescribeContinuousBackupsCommand, DescribeContributorInsightsCommand, DescribeKinesisStreamingDestinationCommand, DescribeTableCommand, DescribeTimeToLiveCommand, DisableKinesisStreamingDestinationCommand, DynamoDBClient, EnableKinesisStreamingDestinationCommand, GetResourcePolicyCommand, ListTagsOfResourceCommand, PutResourcePolicyCommand, ResourceNotFoundException as ResourceNotFoundException$1, TagResourceCommand as TagResourceCommand$2, UntagResourceCommand as UntagResourceCommand$2, UpdateContinuousBackupsCommand, UpdateContributorInsightsCommand, UpdateTableCommand, UpdateTimeToLiveCommand } from "@aws-sdk/client-dynamodb";
15
+ import { CreateTableCommand, DeleteResourcePolicyCommand, DeleteTableCommand, DescribeContinuousBackupsCommand, DescribeContributorInsightsCommand, DescribeKinesisStreamingDestinationCommand, DescribeTableCommand, DescribeTimeToLiveCommand, DisableKinesisStreamingDestinationCommand, DynamoDBClient, EnableKinesisStreamingDestinationCommand, GetResourcePolicyCommand, ListTagsOfResourceCommand, PolicyNotFoundException, PutResourcePolicyCommand, ResourceNotFoundException as ResourceNotFoundException$1, TagResourceCommand as TagResourceCommand$2, UntagResourceCommand as UntagResourceCommand$2, UpdateContinuousBackupsCommand, UpdateContributorInsightsCommand, UpdateTableCommand, UpdateTimeToLiveCommand } from "@aws-sdk/client-dynamodb";
16
16
  import { CloudFormationClient, CreateChangeSetCommand, DeleteChangeSetCommand, DeleteStackCommand, DescribeChangeSetCommand, DescribeStackEventsCommand, DescribeStackResourcesCommand, DescribeStacksCommand, ExecuteChangeSetCommand, GetTemplateCommand, UpdateStackCommand, waitUntilChangeSetCreateComplete, waitUntilStackDeleteComplete, waitUntilStackImportComplete, waitUntilStackUpdateComplete } from "@aws-sdk/client-cloudformation";
17
17
  import { APIGatewayClient, CreateAuthorizerCommand, CreateDeploymentCommand, CreateResourceCommand, CreateStageCommand, DeleteAuthorizerCommand, DeleteDeploymentCommand, DeleteMethodCommand, DeleteResourceCommand, DeleteStageCommand, GetAccountCommand, GetAuthorizerCommand, GetDeploymentCommand, GetMethodCommand, GetResourceCommand, GetStageCommand, NotFoundException as NotFoundException$1, PutIntegrationCommand, PutIntegrationResponseCommand, PutMethodCommand, PutMethodResponseCommand, TagResourceCommand as TagResourceCommand$3, UntagResourceCommand as UntagResourceCommand$3, UpdateAccountCommand, UpdateAuthorizerCommand, UpdateMethodCommand, UpdateStageCommand } from "@aws-sdk/client-api-gateway";
18
18
  import { CreateEventBusCommand, DeleteEventBusCommand, DeleteRuleCommand, DescribeEventBusCommand, DescribeRuleCommand, EventBridgeClient, ListRulesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$1, ListTargetsByRuleCommand, PutRuleCommand, PutTargetsCommand, RemoveTargetsCommand, ResourceNotFoundException as ResourceNotFoundException$2, TagResourceCommand as TagResourceCommand$4, UntagResourceCommand as UntagResourceCommand$4, UpdateEventBusCommand } from "@aws-sdk/client-eventbridge";
@@ -7137,7 +7137,7 @@ function manualBucketDeletionClause(bucketName, maskSecrets) {
7137
7137
  * disagree about what an `Id` is.
7138
7138
  */
7139
7139
  function configItemId(item) {
7140
- if (!isPlainObject$1(item)) return void 0;
7140
+ if (!isPlainObject$2(item)) return void 0;
7141
7141
  const id = item["Id"];
7142
7142
  if (typeof id === "string") return id;
7143
7143
  if (typeof id === "number" && Number.isFinite(id)) return String(id);
@@ -7157,7 +7157,7 @@ function configItemId(item) {
7157
7157
  function declaresBucketObjectLock(properties) {
7158
7158
  return properties["ObjectLockEnabled"] === true || properties["ObjectLockEnabled"] === "true";
7159
7159
  }
7160
- function isPlainObject$1(value) {
7160
+ function isPlainObject$2(value) {
7161
7161
  return typeof value === "object" && value !== null && !Array.isArray(value);
7162
7162
  }
7163
7163
  /**
@@ -7192,7 +7192,7 @@ function isFlattenedDestination(dest) {
7192
7192
  * via the critic's `--providers-dir=` seam.
7193
7193
  */
7194
7194
  function s3BucketDestinationPath(dest, destinationPath) {
7195
- return isPlainObject$1(dest) && isFlattenedDestination(dest) ? destinationPath : `${destinationPath}.S3BucketDestination`;
7195
+ return isPlainObject$2(dest) && isFlattenedDestination(dest) ? destinationPath : `${destinationPath}.S3BucketDestination`;
7196
7196
  }
7197
7197
  /**
7198
7198
  * The FLATTENED CFn `Destination` block cdkd actually SENDS for `declared`
@@ -7231,9 +7231,9 @@ function s3BucketDestinationPath(dest, destinationPath) {
7231
7231
  * resolver's own refusal to report).
7232
7232
  */
7233
7233
  function effectiveS3BucketDestination(declared, sentFormat) {
7234
- if (!isPlainObject$1(declared)) return declared;
7234
+ if (!isPlainObject$2(declared)) return declared;
7235
7235
  const bag = isFlattenedDestination(declared) ? declared : declared["S3BucketDestination"];
7236
- if (!isPlainObject$1(bag)) return declared;
7236
+ if (!isPlainObject$2(bag)) return declared;
7237
7237
  if (!bag["BucketArn"] && !bag["Bucket"]) return declared;
7238
7238
  const out = {};
7239
7239
  const bucketArn = bag["BucketArn"] ?? bag["Bucket"];
@@ -7364,7 +7364,7 @@ function effectiveInventoryItem(item, sent) {
7364
7364
  const scheduleContainerUsable = configStringRefusal(declaredSchedule, "Frequency", INVENTORY_DEFAULT_SCHEDULE_FREQUENCY, "AWS::S3::Bucket InventoryConfigurations[].Schedule") === void 0;
7365
7365
  const canFoldSchedule = sent?.frequency !== void 0 || scheduleFrequencyUsable || !declaresScheduleFrequency && scheduleContainerUsable;
7366
7366
  if (canFoldSchedule) {
7367
- const declaredFrequency = declaresScheduleFrequency ? item["ScheduleFrequency"] : isPlainObject$1(declaredSchedule) && declaredSchedule["Frequency"] !== void 0 ? declaredSchedule["Frequency"] : INVENTORY_DEFAULT_SCHEDULE_FREQUENCY;
7367
+ const declaredFrequency = declaresScheduleFrequency ? item["ScheduleFrequency"] : isPlainObject$2(declaredSchedule) && declaredSchedule["Frequency"] !== void 0 ? declaredSchedule["Frequency"] : INVENTORY_DEFAULT_SCHEDULE_FREQUENCY;
7368
7368
  const frequency = sent?.frequency ?? declaredFrequency;
7369
7369
  if (!Object.is(item["ScheduleFrequency"], frequency)) patch["ScheduleFrequency"] = frequency;
7370
7370
  }
@@ -7395,9 +7395,9 @@ function effectiveInventoryItem(item, sent) {
7395
7395
  */
7396
7396
  function effectiveAnalyticsItem(item, sent) {
7397
7397
  const storageClassAnalysis = item["StorageClassAnalysis"];
7398
- if (!isPlainObject$1(storageClassAnalysis)) return item;
7398
+ if (!isPlainObject$2(storageClassAnalysis)) return item;
7399
7399
  const dataExport = storageClassAnalysis["DataExport"];
7400
- if (!isPlainObject$1(dataExport)) return item;
7400
+ if (!isPlainObject$2(dataExport)) return item;
7401
7401
  const patch = {};
7402
7402
  const outputSchemaVersion = sent?.outputSchemaVersion ?? declaredOrDefault(dataExport, "OutputSchemaVersion", ANALYTICS_DEFAULT_OUTPUT_SCHEMA_VERSION);
7403
7403
  if (!Object.is(dataExport["OutputSchemaVersion"], outputSchemaVersion)) patch["OutputSchemaVersion"] = outputSchemaVersion;
@@ -7513,7 +7513,7 @@ const EVENTBRIDGE_DEFAULT_ENABLED = true;
7513
7513
  * correct once every declared-but-unusable value has been refused.
7514
7514
  */
7515
7515
  function eventBridgeEnabledOf(eb) {
7516
- const declared = isPlainObject$1(eb) ? eb["EventBridgeEnabled"] : void 0;
7516
+ const declared = isPlainObject$2(eb) ? eb["EventBridgeEnabled"] : void 0;
7517
7517
  return coerceCfnBoolean(declared) ?? EVENTBRIDGE_DEFAULT_ENABLED;
7518
7518
  }
7519
7519
  /** The notification families whose empty declaration is never SENT (issue #1759). */
@@ -7620,7 +7620,7 @@ function foldNotificationEvents(item) {
7620
7620
  * handling).
7621
7621
  */
7622
7622
  function effectiveNotificationConfiguration(config) {
7623
- if (!isPlainObject$1(config)) return config;
7623
+ if (!isPlainObject$2(config)) return config;
7624
7624
  let out = config;
7625
7625
  for (const [listKey, aliases] of NOTIFICATION_ARN_ALIASES) out = canonicalizeItemList(out, listKey, (item) => foldNotificationEvents(foldToleratedAliases(item, aliases)));
7626
7626
  out = dropEmptyNotificationFamilies(out);
@@ -7677,8 +7677,8 @@ function foldEventBridgeConfiguration(config) {
7677
7677
  if (eb === void 0) return config;
7678
7678
  if (eb !== null && configBooleanRefusal(eb, "EventBridgeEnabled", EVENTBRIDGE_CONFIG_PATH)) return config;
7679
7679
  const enabled = eb === null ? false : eventBridgeEnabledOf(eb);
7680
- const declared = isPlainObject$1(eb) ? eb["EventBridgeEnabled"] : void 0;
7681
- if (isPlainObject$1(eb) && Object.keys(eb).length === 1 && Object.is(declared, enabled)) return config;
7680
+ const declared = isPlainObject$2(eb) ? eb["EventBridgeEnabled"] : void 0;
7681
+ if (isPlainObject$2(eb) && Object.keys(eb).length === 1 && Object.is(declared, enabled)) return config;
7682
7682
  return {
7683
7683
  ...config,
7684
7684
  [EVENTBRIDGE_CONFIG_KEY]: { EventBridgeEnabled: enabled }
@@ -7758,7 +7758,7 @@ function deepSameValue(a, b) {
7758
7758
  if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
7759
7759
  return a.every((element, index) => deepSameValue(element, b[index]));
7760
7760
  }
7761
- if (isPlainObject$1(a) && isPlainObject$1(b)) {
7761
+ if (isPlainObject$2(a) && isPlainObject$2(b)) {
7762
7762
  const keysA = Object.keys(a);
7763
7763
  if (keysA.length !== Object.keys(b).length) return false;
7764
7764
  return keysA.every((key) => key in b && deepSameValue(a[key], b[key]));
@@ -7833,9 +7833,9 @@ function foldLegacySingularTransitions(rule) {
7833
7833
  let out;
7834
7834
  for (const [pluralKey, singularKey] of LEGACY_SINGULAR_TRANSITIONS) {
7835
7835
  const singular = rule[singularKey];
7836
- const hasSingular = isPlainObject$1(singular);
7836
+ const hasSingular = isPlainObject$2(singular);
7837
7837
  const plural = rule[pluralKey];
7838
- const needsFilter = Array.isArray(plural) && plural.some((element) => !isPlainObject$1(element));
7838
+ const needsFilter = Array.isArray(plural) && plural.some((element) => !isPlainObject$2(element));
7839
7839
  if (!hasSingular && !needsFilter) continue;
7840
7840
  let collided = false;
7841
7841
  const merged = mergeLegacySingular(plural, hasSingular ? singular : void 0, () => {
@@ -7943,7 +7943,7 @@ function foldLifecycleExpiration(rule) {
7943
7943
  const iso = cfnDateToIso(expiration);
7944
7944
  if (iso === void 0) return rule;
7945
7945
  date = iso;
7946
- } else if (isPlainObject$1(expiration)) {
7946
+ } else if (isPlainObject$2(expiration)) {
7947
7947
  if (expiration["Days"] !== void 0) days = expiration["Days"];
7948
7948
  if (expiration["Date"]) {
7949
7949
  const iso = cfnDateToIso(expiration["Date"]);
@@ -7991,10 +7991,10 @@ function foldNoncurrentVersionExpiration(rule) {
7991
7991
  const legacy = rule["NoncurrentVersionExpirationInDays"];
7992
7992
  if (legacy === void 0) return rule;
7993
7993
  const declaredObject = rule["NoncurrentVersionExpiration"];
7994
- if (declaredObject !== void 0 && !isPlainObject$1(declaredObject)) return rule;
7994
+ if (declaredObject !== void 0 && !isPlainObject$2(declaredObject)) return rule;
7995
7995
  const out = { ...rule };
7996
7996
  delete out["NoncurrentVersionExpirationInDays"];
7997
- if (isPlainObject$1(declaredObject)) return out;
7997
+ if (isPlainObject$2(declaredObject)) return out;
7998
7998
  const days = coerceCfnNumber(legacy);
7999
7999
  if (days === void 0) return rule;
8000
8000
  out["NoncurrentVersionExpiration"] = { NoncurrentDays: days };
@@ -8089,10 +8089,10 @@ function foldLifecycleScope(rule, useFilterForm) {
8089
8089
  * @returns `config` BY IDENTITY when the declared bag IS what goes on the wire.
8090
8090
  */
8091
8091
  function effectiveLifecycleConfiguration(config) {
8092
- if (!isPlainObject$1(config)) return config;
8092
+ if (!isPlainObject$2(config)) return config;
8093
8093
  const rules = config["Rules"];
8094
8094
  if (!Array.isArray(rules)) return config;
8095
- const objectRules = rules.filter(isPlainObject$1);
8095
+ const objectRules = rules.filter(isPlainObject$2);
8096
8096
  if (objectRules.length !== rules.length || objectRules.length === 0) return config;
8097
8097
  if (objectRules.some(lifecycleRuleRefused)) return config;
8098
8098
  const useFilterForm = lifecycleUsesFilterForm(objectRules);
@@ -8178,7 +8178,7 @@ function canonicalizeItemList(properties, key, fold) {
8178
8178
  if (!Array.isArray(list)) return properties;
8179
8179
  let changed = false;
8180
8180
  const mapped = list.map((element) => {
8181
- if (!isPlainObject$1(element)) return element;
8181
+ if (!isPlainObject$2(element)) return element;
8182
8182
  const next = fold(element);
8183
8183
  if (next !== element) changed = true;
8184
8184
  return next;
@@ -8198,7 +8198,7 @@ function describeValue$1(value, maskSecrets = (text) => text) {
8198
8198
  if (value === null) return "null";
8199
8199
  if (Array.isArray(value)) return "an array";
8200
8200
  if (typeof value === "string") return `a string ${JSON.stringify(maskDeep(value, maskSecrets))}`;
8201
- if (isPlainObject$1(value)) return `an object with keys [${Object.keys(value).map((key) => maskSecrets(key)).join(", ")}]`;
8201
+ if (isPlainObject$2(value)) return `an object with keys [${Object.keys(value).map((key) => maskSecrets(key)).join(", ")}]`;
8202
8202
  return `a ${typeof value} (${maskSecrets(String(value))})`;
8203
8203
  }
8204
8204
  /**
@@ -8223,8 +8223,8 @@ function coerceCfnNumber(value) {
8223
8223
  * StorageClass collision, and say so rather than dropping in silence.
8224
8224
  */
8225
8225
  function mergeLegacySingular(plural, singular, onCollision) {
8226
- const out = (Array.isArray(plural) ? plural : []).filter(isPlainObject$1);
8227
- if (!isPlainObject$1(singular)) return out;
8226
+ const out = (Array.isArray(plural) ? plural : []).filter(isPlainObject$2);
8227
+ if (!isPlainObject$2(singular)) return out;
8228
8228
  const sc = singular["StorageClass"];
8229
8229
  if (typeof sc === "string" && out.some((e) => e["StorageClass"] === sc)) {
8230
8230
  onCollision(sc);
@@ -8722,7 +8722,7 @@ var S3BucketProvider = class S3BucketProvider {
8722
8722
  if (!(exp?.["Days"] !== void 0 || exp?.["Date"] !== void 0)) sdkRule.Expiration = { ExpiredObjectDeleteMarker: true };
8723
8723
  else this.logger.warn(`Lifecycle rule '${rule["Id"] ?? "<unnamed>"}' on ${bucketName} sets ExpiredObjectDeleteMarker alongside an expiration Days/Date; S3 forbids combining them, so the delete-marker cleanup was not applied.`);
8724
8724
  }
8725
- const nve = isPlainObject$1(rule["NoncurrentVersionExpiration"]) ? rule["NoncurrentVersionExpiration"] : void 0;
8725
+ const nve = isPlainObject$2(rule["NoncurrentVersionExpiration"]) ? rule["NoncurrentVersionExpiration"] : void 0;
8726
8726
  const legacyNveDays = rule["NoncurrentVersionExpirationInDays"];
8727
8727
  if (nve) sdkRule.NoncurrentVersionExpiration = {
8728
8728
  NoncurrentDays: nve["NoncurrentDays"],
@@ -8747,7 +8747,7 @@ var S3BucketProvider = class S3BucketProvider {
8747
8747
  const singularTransition = rule["Transition"];
8748
8748
  const allTransitions = mergeLegacySingular(transitions, singularTransition, (sc) => this.logger.warn(`Lifecycle rule '${rule["Id"] ?? "<unnamed>"}' on ${bucketName} declares both Transitions and the legacy Transition for storage class ${sc}; S3 rejects duplicates, so the legacy singular was ignored.`));
8749
8749
  if (allTransitions.length > 0) sdkRule.Transitions = allTransitions.map(toSdkTransition);
8750
- const abort = isPlainObject$1(rule["AbortIncompleteMultipartUpload"]) ? rule["AbortIncompleteMultipartUpload"] : void 0;
8750
+ const abort = isPlainObject$2(rule["AbortIncompleteMultipartUpload"]) ? rule["AbortIncompleteMultipartUpload"] : void 0;
8751
8751
  if (abort) sdkRule.AbortIncompleteMultipartUpload = { DaysAfterInitiation: abort["DaysAfterInitiation"] };
8752
8752
  const { prefix, tagFilters, sizeGt, sizeLt } = lifecycleRuleScope(rule);
8753
8753
  const hasTags = tagFilters != null && tagFilters.length > 0;
@@ -9081,10 +9081,10 @@ var S3BucketProvider = class S3BucketProvider {
9081
9081
  throw new Error(message);
9082
9082
  };
9083
9083
  if (dest === void 0 || dest === null) return;
9084
- if (!isPlainObject$1(dest)) return drop(`${destinationPath} must be an object (got ${describeValue$1(dest, maskSecrets)}) — check for an unresolved intrinsic or a mis-nested template value; the destination would otherwise be dropped from the request with no error`);
9084
+ if (!isPlainObject$2(dest)) return drop(`${destinationPath} must be an object (got ${describeValue$1(dest, maskSecrets)}) — check for an unresolved intrinsic or a mis-nested template value; the destination would otherwise be dropped from the request with no error`);
9085
9085
  const bag = isFlattenedDestination(dest) ? dest : dest["S3BucketDestination"];
9086
9086
  if (bag === void 0 || bag === null) return drop(`${destinationPath} carries neither a bucket (BucketArn / Bucket) nor a nested S3BucketDestination object (got ${describeValue$1(dest, maskSecrets)}) — the destination would otherwise be dropped from the request with no error`);
9087
- if (!isPlainObject$1(bag)) return drop(`${nestedPath} must be an object (got ${describeValue$1(bag, maskSecrets)}) — check for an unresolved intrinsic or a mis-nested template value; the destination would otherwise be dropped from the request with no error`);
9087
+ if (!isPlainObject$2(bag)) return drop(`${nestedPath} must be an object (got ${describeValue$1(bag, maskSecrets)}) — check for an unresolved intrinsic or a mis-nested template value; the destination would otherwise be dropped from the request with no error`);
9088
9088
  if (!bag["BucketArn"] && !bag["Bucket"]) return drop(`${bag === dest ? destinationPath : nestedPath} has no destination bucket (BucketArn / Bucket) (got ${describeValue$1(bag, maskSecrets)}) — the request would be rejected by S3, or silently carry no destination`);
9089
9089
  return bag;
9090
9090
  }
@@ -17153,6 +17153,301 @@ function reverseMapIndexContributorInsights(status, mode, declaredBlock) {
17153
17153
  return block;
17154
17154
  }
17155
17155
 
17156
+ //#endregion
17157
+ //#region src/provisioning/dynamodb-stream-members.ts
17158
+ /**
17159
+ * The two `AWS::DynamoDB::Table` `StreamSpecification` members that are NOT
17160
+ * members of the SDK's `StreamSpecification`: `ResourcePolicy`
17161
+ * (`{ PolicyDocument }`, the resource-based policy of the STREAM) and `Tags`
17162
+ * (issue [#3458](https://github.com/go-to-k/cdkd/issues/3458)).
17163
+ *
17164
+ * `CreateTable` / `UpdateTable` take only `{ StreamEnabled, StreamViewType }`,
17165
+ * so a block carrying either member deployed green with neither applied — a
17166
+ * template granting access to a table's stream left the stream with no policy.
17167
+ * CloudFormation applies both against the STREAM arn (`LatestStreamArn`),
17168
+ * re-applies both after a `StreamViewType` change (which mints a NEW arn), and
17169
+ * REMOVES both when the member leaves a block whose stream stays (measured on
17170
+ * real CloudFormation; the measurements are on the issue).
17171
+ *
17172
+ * Pure, so the write plan, the create-time refusal and the drift read-back
17173
+ * gate cannot answer "does this block declare the member" differently.
17174
+ */
17175
+ /** The CFn property holding both members. */
17176
+ const STREAM_SPECIFICATION_KEY = "StreamSpecification";
17177
+ /** The stream's resource-based policy member. */
17178
+ const STREAM_POLICY_KEY = "ResourcePolicy";
17179
+ /** The stream's tag-list member. */
17180
+ const STREAM_TAGS_KEY = "Tags";
17181
+ const POLICY_PATH = `${STREAM_SPECIFICATION_KEY}.${STREAM_POLICY_KEY}`;
17182
+ const TAGS_PATH = `${STREAM_SPECIFICATION_KEY}.${STREAM_TAGS_KEY}`;
17183
+ function isPlainObject$1(value) {
17184
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17185
+ }
17186
+ /** The message a `config-shape` guard would throw, or `undefined`. */
17187
+ function refusalOf(guard) {
17188
+ try {
17189
+ guard();
17190
+ return;
17191
+ } catch (error) {
17192
+ return describeAwsFailure(error).detail;
17193
+ }
17194
+ }
17195
+ /** The members of a `StreamSpecification` block, or none for a non-object. */
17196
+ function blockMembers(block) {
17197
+ return isPlainObject$1(block) ? block : {};
17198
+ }
17199
+ /**
17200
+ * Read `StreamSpecification.ResourcePolicy`.
17201
+ *
17202
+ * The CFn shape is `{ PolicyDocument: <object | JSON string> }` and the
17203
+ * document is REQUIRED, so a block without one is unreadable rather than "no
17204
+ * policy": reading it as absent would DELETE the live policy on an update.
17205
+ */
17206
+ function readStreamPolicy(block) {
17207
+ const value = blockMembers(block)[STREAM_POLICY_KEY];
17208
+ if (value === void 0 || value === null) return { kind: "absent" };
17209
+ const containerRefusal = refusalOf(() => requireConfigObject(value, POLICY_PATH));
17210
+ if (containerRefusal !== void 0) return {
17211
+ kind: "unusable",
17212
+ reason: containerRefusal
17213
+ };
17214
+ const documentPath = `${POLICY_PATH}.PolicyDocument`;
17215
+ const document = value["PolicyDocument"];
17216
+ if (typeof document === "string") return document.trim() === "" ? {
17217
+ kind: "unusable",
17218
+ reason: `${documentPath} must not be a blank string`
17219
+ } : {
17220
+ kind: "usable",
17221
+ document
17222
+ };
17223
+ if (document === void 0 || document === null) return {
17224
+ kind: "unusable",
17225
+ reason: `${documentPath} is required when ${POLICY_PATH} is declared`
17226
+ };
17227
+ const documentRefusal = refusalOf(() => requireConfigObject(document, documentPath));
17228
+ if (documentRefusal !== void 0) return {
17229
+ kind: "unusable",
17230
+ reason: documentRefusal
17231
+ };
17232
+ return {
17233
+ kind: "usable",
17234
+ document: JSON.stringify(document)
17235
+ };
17236
+ }
17237
+ /**
17238
+ * Read `StreamSpecification.Tags`.
17239
+ *
17240
+ * Refusals name an entry by POSITION, never by its key: the key is a RESOLVED
17241
+ * template value, and a copy embedded here would reach only the substring
17242
+ * mask, which ignores a value shorter than its minimum needle.
17243
+ *
17244
+ * ONE unreadable entry makes the whole list unusable. Filtering it out would
17245
+ * send a list nobody declared, and on an update would untag a key the
17246
+ * unreadable entry may well have named.
17247
+ */
17248
+ function readStreamTags(block) {
17249
+ const value = blockMembers(block)[STREAM_TAGS_KEY];
17250
+ if (value === void 0 || value === null) return { kind: "absent" };
17251
+ if (!Array.isArray(value)) return {
17252
+ kind: "unusable",
17253
+ reason: `${TAGS_PATH} must be an array of {Key, Value} entries`
17254
+ };
17255
+ const tags = /* @__PURE__ */ new Map();
17256
+ for (const [position, entry] of value.entries()) {
17257
+ const entryPath = `${TAGS_PATH}[${position}]`;
17258
+ const refusal = refusalOf(() => requireConfigObject(entry, entryPath)) ?? configStringRefusal(entry, "Key", "required", entryPath) ?? configStringRefusal(entry, "Value", "", entryPath);
17259
+ if (refusal !== void 0) return {
17260
+ kind: "unusable",
17261
+ reason: refusal
17262
+ };
17263
+ const { Key: key, Value: tagValue } = entry;
17264
+ if (typeof key !== "string") return {
17265
+ kind: "unusable",
17266
+ reason: `${entryPath}.Key is required`
17267
+ };
17268
+ tags.set(key, typeof tagValue === "string" ? tagValue : "");
17269
+ }
17270
+ return {
17271
+ kind: "usable",
17272
+ tags
17273
+ };
17274
+ }
17275
+ /**
17276
+ * Every refusal a CREATE must raise before `CreateTable` goes out. A create has
17277
+ * no live setting to leave alone, so an unreadable member there is a template
17278
+ * error, not a skip — and refusing after the table exists would create it only
17279
+ * to delete it again.
17280
+ */
17281
+ function streamMemberRefusals(block) {
17282
+ const refusals = [];
17283
+ const policy = readStreamPolicy(block);
17284
+ if (policy.kind === "unusable") refusals.push(policy.reason);
17285
+ const tags = readStreamTags(block);
17286
+ if (tags.kind === "unusable") refusals.push(tags.reason);
17287
+ return refusals;
17288
+ }
17289
+ /**
17290
+ * The calls one update (or create) needs against the CURRENT stream arn.
17291
+ *
17292
+ * `freshStream` says the arn the calls will address was minted by THIS
17293
+ * operation — a create, an update-time enable, or the disable / re-enable a
17294
+ * `StreamViewType` change is applied as. A fresh stream holds nothing, so the
17295
+ * previous side is irrelevant there: every readable declared member is
17296
+ * applied, and nothing is deleted. Otherwise the stream is the one the previous
17297
+ * side was applied to, and the plan is the difference. `contentsUnknown` is
17298
+ * the third case: a live stream this operation did NOT mint and the previous
17299
+ * side does not describe (a re-run after a deploy that enabled the stream,
17300
+ * applied a policy, and failed before state recorded any of it). It may hold a
17301
+ * policy, so it is never planned as empty: a policy the desired side does not
17302
+ * declare is deleted, and a declared one is always put.
17303
+ *
17304
+ * On a stream the previous side describes:
17305
+ *
17306
+ * - a member `absent` with a DECLARED previous is a template REMOVAL and is
17307
+ * removed (CloudFormation does the same). Because the rule is symmetric in
17308
+ * its two sides, a rollback — which replays `update()` with the sides SWAPPED
17309
+ * — restores the old policy and tags through the same arms, a view-type
17310
+ * change included (the rollback mints yet another arn, and `freshStream`
17311
+ * applies the old members to it).
17312
+ * - an `unusable` member reaches this plan only from a STATE-borne caller (a
17313
+ * rollback replay, `drift --revert`): the provider refuses it on the template
17314
+ * path before any call. It reports through `onUnusable` and the live setting
17315
+ * is left alone rather than overwritten with a guess: no call on a stream
17316
+ * that stays, and the PREVIOUS member carried over onto a fresh one.
17317
+ * - an `unusable` PREVIOUS tag list cannot say which keys cdkd applied, so a
17318
+ * removal against it untags nothing.
17319
+ *
17320
+ * ORDER is part of the contract, because a resource policy is an access grant
17321
+ * and can condition on `aws:ResourceTag`: `deletePolicy` comes FIRST and
17322
+ * `putPolicy` LAST. A policy that CHANGES together with the tags is therefore
17323
+ * deleted before the first tag call and put back after the last, so neither
17324
+ * the old policy nor the new one is ever evaluated against the other side's
17325
+ * tag set — also when a call in between fails. The price is a window with NO
17326
+ * policy, which drops that policy's `Deny` statements along with its grants;
17327
+ * nothing here is atomic, and that window is the narrower of the two hazards.
17328
+ * An UNCHANGED policy stays in place across a tag-only change: both sides
17329
+ * declare it, and the two tag calls cannot be made one.
17330
+ *
17331
+ * The caller asks only while the DESIRED side has a stream: a disabled stream
17332
+ * is gone and takes both members with it, so nothing addresses its dead arn.
17333
+ */
17334
+ function planStreamMemberOps(desiredBlock, previousBlock, options, onUnusable) {
17335
+ let desiredPolicy = readStreamPolicy(desiredBlock);
17336
+ let desiredTags = readStreamTags(desiredBlock);
17337
+ if (desiredPolicy.kind === "unusable") onUnusable(desiredPolicy.reason);
17338
+ if (desiredTags.kind === "unusable") onUnusable(desiredTags.reason);
17339
+ let previousPolicy = readStreamPolicy(previousBlock);
17340
+ let previousTags = readStreamTags(previousBlock);
17341
+ if (options.freshStream) {
17342
+ if (desiredPolicy.kind === "unusable" && previousPolicy.kind === "usable") desiredPolicy = previousPolicy;
17343
+ if (desiredTags.kind === "unusable" && previousTags.kind === "usable") desiredTags = previousTags;
17344
+ previousPolicy = { kind: "absent" };
17345
+ previousTags = { kind: "absent" };
17346
+ } else if (options.contentsUnknown === true) {
17347
+ previousPolicy = {
17348
+ kind: "unusable",
17349
+ reason: ""
17350
+ };
17351
+ previousTags = { kind: "absent" };
17352
+ }
17353
+ const tagOps = [];
17354
+ if (desiredTags.kind !== "unusable") {
17355
+ const desired = desiredTags.kind === "usable" ? desiredTags.tags : /* @__PURE__ */ new Map();
17356
+ const previous = previousTags.kind === "usable" ? previousTags.tags : /* @__PURE__ */ new Map();
17357
+ const keysToRemove = [...previous.keys()].filter((key) => !desired.has(key));
17358
+ if (keysToRemove.length > 0) tagOps.push({
17359
+ kind: "untag",
17360
+ keys: keysToRemove
17361
+ });
17362
+ const tagsToSet = [...desired].filter(([key, value]) => previous.get(key) !== value).map(([Key, Value]) => ({
17363
+ Key,
17364
+ Value
17365
+ }));
17366
+ if (tagsToSet.length > 0) tagOps.push({
17367
+ kind: "tag",
17368
+ tags: tagsToSet
17369
+ });
17370
+ }
17371
+ const policyPut = desiredPolicy.kind === "usable" && !(previousPolicy.kind === "usable" && samePolicyDocument(previousPolicy.document, desiredPolicy.document));
17372
+ const policyDelete = previousPolicy.kind !== "absent" && (desiredPolicy.kind === "absent" || policyPut && tagOps.length > 0);
17373
+ const ops = [];
17374
+ if (policyDelete) ops.push({ kind: "deletePolicy" });
17375
+ ops.push(...tagOps);
17376
+ if (policyPut && desiredPolicy.kind === "usable") ops.push({
17377
+ kind: "putPolicy",
17378
+ document: desiredPolicy.document
17379
+ });
17380
+ return ops;
17381
+ }
17382
+ /** Two policy JSON strings saying the same thing, whatever their key order. */
17383
+ function samePolicyDocument(left, right) {
17384
+ if (left === right) return true;
17385
+ try {
17386
+ return canonicalJson$1(JSON.parse(left)) === canonicalJson$1(JSON.parse(right));
17387
+ } catch {
17388
+ return false;
17389
+ }
17390
+ }
17391
+ /** The drift read-back gates: one API call each, so each is asked separately. */
17392
+ function streamDeclaresPolicy(desiredBlock) {
17393
+ return readStreamPolicy(desiredBlock).kind === "usable";
17394
+ }
17395
+ /** See {@link streamDeclaresPolicy}. */
17396
+ function streamDeclaresTags(desiredBlock) {
17397
+ return readStreamTags(desiredBlock).kind === "usable";
17398
+ }
17399
+ /**
17400
+ * Re-shape a `GetResourcePolicy` answer into the CFn member, in the DECLARED
17401
+ * spelling of `PolicyDocument`: a template may carry the document as an object
17402
+ * or as a JSON string, and the comparator does not convert between them.
17403
+ * `undefined` when AWS holds no policy.
17404
+ */
17405
+ function reverseMapStreamPolicy(livePolicy, desiredBlock) {
17406
+ if (livePolicy === void 0 || livePolicy === "") return void 0;
17407
+ const declared = blockMembers(blockMembers(desiredBlock)[STREAM_POLICY_KEY])["PolicyDocument"];
17408
+ let parsed;
17409
+ try {
17410
+ parsed = JSON.parse(livePolicy);
17411
+ } catch {
17412
+ return { PolicyDocument: livePolicy };
17413
+ }
17414
+ if (typeof declared !== "string") return { PolicyDocument: parsed };
17415
+ let declaredParsed;
17416
+ try {
17417
+ declaredParsed = JSON.parse(declared);
17418
+ } catch {
17419
+ return { PolicyDocument: livePolicy };
17420
+ }
17421
+ return { PolicyDocument: canonicalJson$1(declaredParsed) === canonicalJson$1(parsed) ? declared : livePolicy };
17422
+ }
17423
+ /**
17424
+ * Does the live policy say what the DECLARED one says? The read-back's
17425
+ * "settled" test: `GetResourcePolicy` is eventually consistent and can answer
17426
+ * with the PREVIOUS policy right after a put, so an answer that differs from
17427
+ * the declaration is re-asked before it is believed.
17428
+ */
17429
+ function streamPolicyMatchesDeclared(livePolicy, desiredBlock) {
17430
+ const declared = readStreamPolicy(desiredBlock);
17431
+ if (declared.kind !== "usable" || livePolicy === void 0) return false;
17432
+ try {
17433
+ return canonicalJson$1(JSON.parse(livePolicy)) === canonicalJson$1(JSON.parse(declared.document));
17434
+ } catch {
17435
+ return false;
17436
+ }
17437
+ }
17438
+ /** The tag twin of {@link streamPolicyMatchesDeclared}, over USER tags. */
17439
+ function streamTagsMatchDeclared(liveTags, desiredBlock) {
17440
+ const declared = readStreamTags(desiredBlock);
17441
+ if (declared.kind !== "usable" || liveTags.length !== declared.tags.size) return false;
17442
+ return liveTags.every((tag) => declared.tags.get(tag.Key) === tag.Value);
17443
+ }
17444
+ /** A key-order-independent serialization. */
17445
+ function canonicalJson$1(value) {
17446
+ if (Array.isArray(value)) return `[${value.map(canonicalJson$1).join(",")}]`;
17447
+ if (isPlainObject$1(value)) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson$1(value[key])}`).join(",")}}`;
17448
+ return JSON.stringify(value) ?? "null";
17449
+ }
17450
+
17156
17451
  //#endregion
17157
17452
  //#region src/provisioning/dynamodb-index-busy-delete.ts
17158
17453
  /**
@@ -19249,6 +19544,8 @@ var DynamoDBTableProvider = class {
19249
19544
  if (context?.replayingState !== true) {
19250
19545
  const [refusal] = contributorInsightsRefusals(properties["ContributorInsightsSpecification"], properties["GlobalSecondaryIndexes"]);
19251
19546
  if (refusal !== void 0) throw new Error(`${refusal}. Fix the template value`);
19547
+ const [streamRefusal] = streamMemberRefusals(properties["StreamSpecification"]);
19548
+ if (streamRefusal !== void 0) throw new Error(`${streamRefusal}. Fix the template value`);
19252
19549
  }
19253
19550
  const createParams = {
19254
19551
  TableName: tableName,
@@ -19293,6 +19590,7 @@ var DynamoDBTableProvider = class {
19293
19590
  await this.applyKinesisStreamingDestination(tableName, properties["KinesisStreamSpecification"], void 0, maskSecrets);
19294
19591
  await this.applyContributorInsights(tableName, properties["ContributorInsightsSpecification"], void 0, maskSecrets);
19295
19592
  await this.applyIndexContributorInsights(tableName, properties["GlobalSecondaryIndexes"], void 0, maskSecrets);
19593
+ await this.applyStreamMembers(logicalId, resourceType, tableName, tableInfo.streamArn, properties["StreamSpecification"], void 0, true, maskSecrets);
19296
19594
  this.logger.debug(`Successfully created DynamoDB table ${logicalId}: ${tableName}`);
19297
19595
  return {
19298
19596
  physicalId: tableName,
@@ -19328,6 +19626,10 @@ var DynamoDBTableProvider = class {
19328
19626
  const debug = (message) => this.logger.debug(maskSecrets(message));
19329
19627
  debug(`Updating DynamoDB table ${logicalId}: ${maskSecrets(physicalId)}`);
19330
19628
  try {
19629
+ if (context?.replayingState !== true && context?.desiredFromAwsReadback !== true && JSON.stringify(properties["StreamSpecification"]) !== JSON.stringify(previousProperties["StreamSpecification"])) {
19630
+ const [streamRefusal] = streamMemberRefusals(properties["StreamSpecification"]);
19631
+ if (streamRefusal !== void 0) throw new ProvisioningError(`${streamRefusal}. Nothing was applied to DynamoDB table ${logicalId}; fix the template value`, resourceType, logicalId, physicalId);
19632
+ }
19331
19633
  const table = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table;
19332
19634
  let latestStreamArn = table?.LatestStreamArn;
19333
19635
  if (table?.TableArn) await this.applyTagDiff(table.TableArn, previousProperties["Tags"], properties["Tags"]);
@@ -19479,6 +19781,10 @@ var DynamoDBTableProvider = class {
19479
19781
  if (JSON.stringify(properties["StreamSpecification"]) !== JSON.stringify(previousProperties["StreamSpecification"])) {
19480
19782
  const newViewType = this.extractStreamViewType(properties["StreamSpecification"]);
19481
19783
  const prevViewType = this.extractStreamViewType(previousProperties["StreamSpecification"]);
19784
+ const liveStream = table?.StreamSpecification;
19785
+ const preUpdateStreamArn = table?.LatestStreamArn;
19786
+ let mintedStream = false;
19787
+ let contentsUnknown = false;
19482
19788
  if (newViewType && prevViewType && newViewType !== prevViewType) {
19483
19789
  await this.dynamoDBClient.send(new UpdateTableCommand({
19484
19790
  TableName: physicalId,
@@ -19493,9 +19799,11 @@ var DynamoDBTableProvider = class {
19493
19799
  }
19494
19800
  }));
19495
19801
  await this.waitForTableActiveAfterUpdate(physicalId);
19496
- latestStreamArn = reenable.TableDescription?.LatestStreamArn ?? await this.describeLatestStreamArn(physicalId);
19802
+ latestStreamArn = await this.resolveMintedStreamArn(physicalId, reenable.TableDescription?.LatestStreamArn, preUpdateStreamArn);
19803
+ mintedStream = true;
19497
19804
  this.logger.debug(`Changed StreamViewType on DynamoDB table ${physicalId} to ${newViewType}`);
19498
- } else if (newViewType) {
19805
+ } else if (newViewType && liveStream?.StreamEnabled === true && liveStream.StreamViewType === newViewType) contentsUnknown = prevViewType !== newViewType;
19806
+ else if (newViewType) {
19499
19807
  const enable = await this.dynamoDBClient.send(new UpdateTableCommand({
19500
19808
  TableName: physicalId,
19501
19809
  StreamSpecification: {
@@ -19504,7 +19812,8 @@ var DynamoDBTableProvider = class {
19504
19812
  }
19505
19813
  }));
19506
19814
  await this.waitForTableActiveAfterUpdate(physicalId);
19507
- latestStreamArn = enable.TableDescription?.LatestStreamArn ?? await this.describeLatestStreamArn(physicalId);
19815
+ latestStreamArn = await this.resolveMintedStreamArn(physicalId, enable.TableDescription?.LatestStreamArn, preUpdateStreamArn);
19816
+ mintedStream = true;
19508
19817
  this.logger.debug(`Enabled DynamoDB Stream on table ${physicalId} (${newViewType})`);
19509
19818
  } else {
19510
19819
  await this.dynamoDBClient.send(new UpdateTableCommand({
@@ -19515,6 +19824,7 @@ var DynamoDBTableProvider = class {
19515
19824
  latestStreamArn = void 0;
19516
19825
  this.logger.debug(`Disabled DynamoDB Stream on table ${physicalId}`);
19517
19826
  }
19827
+ if (newViewType) await this.applyStreamMembers(logicalId, resourceType, physicalId, latestStreamArn, properties["StreamSpecification"], previousProperties["StreamSpecification"], mintedStream, maskSecrets, mintedStream ? preUpdateStreamArn : void 0, contentsUnknown);
19518
19828
  }
19519
19829
  if (JSON.stringify(properties["GlobalSecondaryIndexes"]) !== JSON.stringify(previousProperties["GlobalSecondaryIndexes"])) await this.applyGsiUpdates(physicalId, resourceType, logicalId, previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"], properties["AttributeDefinitions"], gsiHandledByBillingFlip, currentLiveIndexNames, currentLiveIndexByName, liveCapacityComparable, effectiveBillingMode === "PAY_PER_REQUEST", maskSecrets);
19520
19830
  if (JSON.stringify(properties["PointInTimeRecoverySpecification"]) !== JSON.stringify(previousProperties["PointInTimeRecoverySpecification"])) await this.applyPointInTimeRecovery(physicalId, properties["PointInTimeRecoverySpecification"], previousProperties["PointInTimeRecoverySpecification"], maskSecrets);
@@ -19745,15 +20055,16 @@ var DynamoDBTableProvider = class {
19745
20055
  * Backoff: ~2s,4s,8s,16s,30s,30s... bounded to ~2min total, which comfortably
19746
20056
  * covers the few-second PITR-enable window.
19747
20057
  */
19748
- async retryOnTransientControlPlane(op, label, maxAttempts = 8) {
20058
+ async retryOnTransientControlPlane(op, label, maxAttempts = 8, options = {}) {
19749
20059
  let delayMs = 2e3;
19750
20060
  for (let attempt = 1;; attempt++) try {
19751
20061
  return await op();
19752
20062
  } catch (error) {
19753
20063
  const msg = describeAwsFailure(error).detail;
19754
20064
  const name = error instanceof Error ? error.name : "";
19755
- if (!(/being enabled|being updated|please retry later|backups are being/i.test(msg) || name === "ResourceInUseException" || name === "LimitExceededException") || attempt >= maxAttempts) throw error;
19756
- this.logger.debug(`Transient error on "${label}" (attempt ${attempt}/${maxAttempts}): ${msg} — retrying in ${delayMs}ms`);
20065
+ if (!(/being enabled|being updated|please retry later|backups are being/i.test(msg) || name === "ResourceInUseException" || name === "LimitExceededException" || options.alsoTransient?.(error) === true) || attempt >= maxAttempts) throw error;
20066
+ const retryLine = `Transient error on "${label}" (attempt ${attempt}/${maxAttempts}): ${msg} — retrying in ${delayMs}ms`;
20067
+ this.logger.debug(options.maskSecrets ? options.maskSecrets(retryLine) : retryLine);
19757
20068
  await new Promise((resolve) => setTimeout(resolve, delayMs));
19758
20069
  delayMs = Math.min(delayMs * 2, 3e4);
19759
20070
  }
@@ -19929,6 +20240,90 @@ var DynamoDBTableProvider = class {
19929
20240
  return typeof viewType === "string" && viewType.length > 0 ? viewType : void 0;
19930
20241
  }
19931
20242
  /**
20243
+ * Apply `StreamSpecification.ResourcePolicy` / `.Tags` (issue
20244
+ * [#3458](https://github.com/go-to-k/cdkd/issues/3458)) against the STREAM
20245
+ * arn. Neither is a member of the SDK's `StreamSpecification`, so until this
20246
+ * existed both were dropped on `CreateTable` / `UpdateTable`: the deploy was
20247
+ * green and the stream had no policy.
20248
+ *
20249
+ * `streamArn` must be the table's CURRENT `LatestStreamArn` — after a
20250
+ * `StreamViewType` change that is the arn the re-enable minted, never the
20251
+ * recorded one. What to call, in which order, and the removal / rollback /
20252
+ * unreadable-member rules live on {@link planStreamMemberOps}.
20253
+ *
20254
+ * A plan with calls to make and no arn to make them against — or, when this
20255
+ * operation minted the stream, only the `deadStreamArn` read before it —
20256
+ * fails LOUDLY: a
20257
+ * silent skip would record the policy in state as applied, the next deploy
20258
+ * would see no difference, and the grant would stay missing for good.
20259
+ *
20260
+ * The policy text is never logged: it names principals and can carry a
20261
+ * resolved secret in a condition value.
20262
+ */
20263
+ async applyStreamMembers(logicalId, resourceType, tableName, streamArn, desiredBlock, previousBlock, freshStream, maskSecrets, deadStreamArn, contentsUnknown = false) {
20264
+ const warn = (message) => this.logger.warn(maskSecrets(message));
20265
+ const debug = (message) => this.logger.debug(maskSecrets(message));
20266
+ const ops = planStreamMemberOps(desiredBlock, previousBlock, {
20267
+ freshStream,
20268
+ contentsUnknown
20269
+ }, (reason) => warn(`DynamoDB table ${tableName}: ${reason}, so that member of the stream was left as it is. The value came from a recorded state, which a template edit cannot reach.`));
20270
+ if (ops.length === 0) return;
20271
+ if (streamArn === void 0 || streamArn === "" || streamArn === deadStreamArn) throw new ProvisioningError(`Cannot apply StreamSpecification.ResourcePolicy / Tags for DynamoDB table ${logicalId}: DescribeTable returned no ${deadStreamArn === void 0 ? "" : "new "}LatestStreamArn`, resourceType, logicalId, tableName);
20272
+ for (const op of ops) {
20273
+ await this.sendStreamMemberOp(streamArn, op, freshStream, maskSecrets);
20274
+ debug(`Applied ${op.kind} to the stream of DynamoDB table ${tableName}`);
20275
+ }
20276
+ }
20277
+ /** Issue ONE {@link StreamMemberOp} against the stream arn. */
20278
+ async sendStreamMemberOp(streamArn, op, freshStream, maskSecrets) {
20279
+ const target = maskSecrets(streamArn);
20280
+ const retryOptions = {
20281
+ maskSecrets,
20282
+ ...freshStream ? { alsoTransient: (error) => error instanceof ResourceNotFoundException$1 } : {}
20283
+ };
20284
+ const send = (call, label) => this.retryOnTransientControlPlane(call, label, void 0, retryOptions);
20285
+ switch (op.kind) {
20286
+ case "deletePolicy":
20287
+ try {
20288
+ await send(() => this.dynamoDBClient.send(new DeleteResourcePolicyCommand({ ResourceArn: streamArn })), `delete the stream ResourcePolicy of ${target}`);
20289
+ } catch (error) {
20290
+ if (!(error instanceof PolicyNotFoundException)) throw error;
20291
+ }
20292
+ return;
20293
+ case "untag":
20294
+ await send(() => this.dynamoDBClient.send(new UntagResourceCommand$2({
20295
+ ResourceArn: streamArn,
20296
+ TagKeys: op.keys
20297
+ })), `untag the stream ${target}`);
20298
+ return;
20299
+ case "tag":
20300
+ await send(() => this.dynamoDBClient.send(new TagResourceCommand$2({
20301
+ ResourceArn: streamArn,
20302
+ Tags: op.tags
20303
+ })), `tag the stream ${target}`);
20304
+ return;
20305
+ case "putPolicy":
20306
+ await send(() => this.dynamoDBClient.send(new PutResourcePolicyCommand({
20307
+ ResourceArn: streamArn,
20308
+ Policy: op.document
20309
+ })), `put the stream ResourcePolicy of ${target}`);
20310
+ return;
20311
+ }
20312
+ }
20313
+ /**
20314
+ * The arn of the stream an enabling `UpdateTable` just minted.
20315
+ *
20316
+ * The arn that call echoes is believed only when it DIFFERS from the one read
20317
+ * before the update: DynamoDB keeps reporting a disabled stream's arn as
20318
+ * `LatestStreamArn`, so an echo equal to it (or no echo) is re-read from
20319
+ * `DescribeTable` after the ACTIVE wait. Shared by the enable and the
20320
+ * view-type arms — a table whose stream was disabled by an earlier deploy is
20321
+ * in the same state as one mid view-type change.
20322
+ */
20323
+ async resolveMintedStreamArn(tableName, echoedArn, preUpdateArn) {
20324
+ return echoedArn !== void 0 && echoedArn !== preUpdateArn ? echoedArn : this.describeLatestStreamArn(tableName);
20325
+ }
20326
+ /**
19932
20327
  * Fetch the table's current `LatestStreamArn` via DescribeTable. Used as a
19933
20328
  * fallback when an UpdateTable that enabled a stream did not echo the ARN
19934
20329
  * back in its TableDescription, so `Fn::GetAtt [Table, StreamArn]` still
@@ -21115,9 +21510,12 @@ var DynamoDBTableProvider = class {
21115
21510
  * shape differences are wrapping:
21116
21511
  * - BillingMode lives under `BillingModeSummary.BillingMode` in the API
21117
21512
  * response, but the CFn property is a flat `BillingMode` string.
21118
- * - StreamSpecification's CFn shape includes only `StreamViewType`; the
21119
- * API response carries `StreamEnabled` too. We surface both since the
21120
- * drift comparator only descends into keys present in state.
21513
+ * - StreamSpecification's CFn shape is `StreamViewType`, `ResourcePolicy`
21514
+ * and `Tags`; the API response carries `StreamEnabled` and
21515
+ * `StreamViewType` only. `StreamEnabled` is surfaced too, since the
21516
+ * comparator descends a `properties` baseline by the keys state holds.
21517
+ * `ResourcePolicy` / `Tags` (issue #3458) live on the STREAM arn and are
21518
+ * read from it, each only when the desired block declares that member.
21121
21519
  * - GSI / LSI in the API response include `IndexStatus`, `Backfilling`,
21122
21520
  * `ItemCount`, `IndexArn` and sizing fields cdkd never sets. They used to
21123
21521
  * be forwarded VERBATIM under a comment claiming "the comparator filters
@@ -21173,10 +21571,14 @@ var DynamoDBTableProvider = class {
21173
21571
  if (table.WarmThroughput.WriteUnitsPerSecond !== void 0) wt["WriteUnitsPerSecond"] = table.WarmThroughput.WriteUnitsPerSecond;
21174
21572
  if (Object.keys(wt).length > 0) result["WarmThroughput"] = wt;
21175
21573
  }
21176
- if (table.StreamSpecification?.StreamEnabled && table.StreamSpecification.StreamViewType) result["StreamSpecification"] = {
21177
- StreamEnabled: true,
21178
- StreamViewType: table.StreamSpecification.StreamViewType
21179
- };
21574
+ if (table.StreamSpecification?.StreamEnabled && table.StreamSpecification.StreamViewType) {
21575
+ const streamBlock = {
21576
+ StreamEnabled: true,
21577
+ StreamViewType: table.StreamSpecification.StreamViewType
21578
+ };
21579
+ result["StreamSpecification"] = streamBlock;
21580
+ await this.readStreamMembers(physicalId, table.LatestStreamArn, properties?.["StreamSpecification"], streamBlock);
21581
+ }
21180
21582
  const bagInformative = desiredBagIsInformative(properties);
21181
21583
  if (table.GlobalSecondaryIndexes && table.GlobalSecondaryIndexes.length > 0) {
21182
21584
  const desiredByName = desiredIndexEntriesByName(properties?.["GlobalSecondaryIndexes"]);
@@ -21277,6 +21679,92 @@ var DynamoDBTableProvider = class {
21277
21679
  }
21278
21680
  }
21279
21681
  /**
21682
+ * How long an eventually-consistent stream-member read that does NOT match
21683
+ * the declaration is re-asked before it is believed: one entry per extra
21684
+ * attempt.
21685
+ */
21686
+ streamMemberRereadDelaysMs = [
21687
+ 500,
21688
+ 1e3,
21689
+ 2e3
21690
+ ];
21691
+ /** Run `read`, re-asking after each configured delay until `settled` accepts the answer. */
21692
+ async reAskUntilSettled(read, settled) {
21693
+ let answer = await read();
21694
+ for (const delayMs of this.streamMemberRereadDelaysMs) {
21695
+ if (settled(answer)) break;
21696
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
21697
+ answer = await read();
21698
+ }
21699
+ return answer;
21700
+ }
21701
+ /**
21702
+ * Read `StreamSpecification.ResourcePolicy` / `.Tags` (issue #3458) off the
21703
+ * table's CURRENT stream arn into `streamBlock`.
21704
+ *
21705
+ * One API call per member, so each is GATED on the desired block declaring a
21706
+ * member cdkd would send — the same reader the write plan runs. The gate is
21707
+ * also what keeps an undeclared member out of an `observedProperties`
21708
+ * baseline, which is compared by the UNION of both sides' keys.
21709
+ *
21710
+ * No policy (`PolicyNotFoundException`) and an empty user tag set emit
21711
+ * NOTHING: that is "absent" in the template's own spelling, which a
21712
+ * declared member then reports as drift (a declared EMPTY list is the one
21713
+ * exception, and reads back as the empty list it is). `aws:`-prefixed system tags are
21714
+ * dropped like the table-level ones, and the list needs no unordered path —
21715
+ * the comparator sorts every `{Key, ...}` list on both sides. Any other
21716
+ * failed read omits the member and says why at debug level, like the sibling
21717
+ * reads of this method.
21718
+ *
21719
+ * Both reads are EVENTUALLY consistent — right after a write they can answer
21720
+ * "absent" or with the PREVIOUS value (their command docs say so) — and the
21721
+ * deploy captures `observedProperties` right after the writes. So an answer
21722
+ * that does not match the DECLARED member is re-asked a few times before it
21723
+ * is believed, or a lagging read would freeze a baseline the settled stream
21724
+ * can never equal. A member that really drifted costs those few seconds per
21725
+ * drift run.
21726
+ *
21727
+ * `cdkd drift --revert` replays through `update()`, where the read-back is
21728
+ * the PREVIOUS side and {@link planStreamMemberOps} derives the restore.
21729
+ */
21730
+ async readStreamMembers(tableName, streamArn, desiredBlock, streamBlock) {
21731
+ if (streamArn === void 0 || streamArn === "") return;
21732
+ if (streamDeclaresPolicy(desiredBlock)) try {
21733
+ const livePolicy = await this.reAskUntilSettled(async () => {
21734
+ try {
21735
+ return (await this.dynamoDBClient.send(new GetResourcePolicyCommand({ ResourceArn: streamArn }))).Policy;
21736
+ } catch (err) {
21737
+ if (err instanceof PolicyNotFoundException) return void 0;
21738
+ throw err;
21739
+ }
21740
+ }, (answer) => streamPolicyMatchesDeclared(answer, desiredBlock));
21741
+ const member = reverseMapStreamPolicy(livePolicy, desiredBlock);
21742
+ if (member !== void 0) streamBlock[STREAM_POLICY_KEY] = member;
21743
+ } catch (err) {
21744
+ this.logger.debug(`Could not read the stream ResourcePolicy for ${tableName}: ${describeAwsFailure(err).detail}`);
21745
+ }
21746
+ if (streamDeclaresTags(desiredBlock)) try {
21747
+ const listOnce = async () => {
21748
+ const liveTags = [];
21749
+ let nextToken;
21750
+ do {
21751
+ const response = await this.dynamoDBClient.send(new ListTagsOfResourceCommand({
21752
+ ResourceArn: streamArn,
21753
+ NextToken: nextToken
21754
+ }));
21755
+ liveTags.push(...response.Tags ?? []);
21756
+ nextToken = response.NextToken;
21757
+ } while (nextToken !== void 0 && nextToken !== "");
21758
+ return normalizeAwsTagsToCfn(liveTags);
21759
+ };
21760
+ const tags = await this.reAskUntilSettled(listOnce, (answer) => streamTagsMatchDeclared(answer, desiredBlock));
21761
+ const declared = desiredBlock[STREAM_TAGS_KEY];
21762
+ if (tags.length > 0 || Array.isArray(declared) && declared.length === 0) streamBlock[STREAM_TAGS_KEY] = tags;
21763
+ } catch (err) {
21764
+ this.logger.debug(`Could not read the stream Tags for ${tableName}: ${describeAwsFailure(err).detail}`);
21765
+ }
21766
+ }
21767
+ /**
21280
21768
  * Adopt an existing DynamoDB table into cdkd state.
21281
21769
  *
21282
21770
  * Lookup order:
@@ -65944,7 +66432,7 @@ function templateUsesSub(templateValue) {
65944
66432
  * The leaf predicate answers `false` for a non-string, and an output's `Value`
65945
66433
  * is very often an OBJECT: `secret.secretValueFromJson(...)` renders the
65946
66434
  * secret's ARN as a `Ref`, so the value is an `Fn::Join` / `Fn::Sub` — which
65947
- * CLAUDE.md's #1916 note calls the DOMINANT CDK shape, not an edge case.
66435
+ * AGENTS.md's #1916 note calls the DOMINANT CDK shape, not an edge case.
65948
66436
  * Feeding the raw value to the leaf predicate therefore reported "no secret
65949
66437
  * here" for exactly the templates most likely to have one, which silently
65950
66438
  * disarmed BOTH signals built on it: the export-alias decision below (issue
@@ -85273,6 +85761,10 @@ function createForceUnlockCommand() {
85273
85761
  * object renders nothing, and an SDK failure is reported by its error NAME
85274
85762
  * alone, because an SDK message can echo request input.
85275
85763
  *
85764
+ * THE DEPENDENCE WALK ITSELF lives in `src/analyzer/parameter-dependence.ts`
85765
+ * (`cdkd deploy` reads it too, issue #3468); this module keeps the half that
85766
+ * touches AWS and the deployed values.
85767
+ *
85276
85768
  * TAINT THROUGH ANOTHER RESOURCE'S ATTRIBUTES IS FOLLOWED within one stack: the
85277
85769
  * walk records the target of every `Fn::GetAtt` / `${A.Attr}`, and the caller
85278
85770
  * closes the refused set over those targets, so a resource reading an attribute
@@ -85379,232 +85871,33 @@ function divergentParameterNames(template, bound, deployed) {
85379
85871
  }
85380
85872
  return divergent;
85381
85873
  }
85382
- /**
85383
- * Every intrinsic the dependence walk knows how to read. An `Fn::`-prefixed
85384
- * key OUTSIDE this list is unclassifiable: it may name a parameter in a way
85385
- * the generic recursion cannot see, so the walk fails closed on it.
85386
- */
85387
- const KNOWN_INTRINSICS = /* @__PURE__ */ new Set([
85388
- "Fn::GetAtt",
85389
- "Fn::Join",
85390
- "Fn::Sub",
85391
- "Fn::Select",
85392
- "Fn::Split",
85393
- "Fn::If",
85394
- "Fn::Equals",
85395
- "Fn::And",
85396
- "Fn::Or",
85397
- "Fn::Not",
85398
- "Fn::ImportValue",
85399
- "Fn::GetStackOutput",
85400
- "Fn::FindInMap",
85401
- "Fn::Base64",
85402
- "Fn::GetAZs",
85403
- "Fn::Cidr"
85404
- ]);
85405
- /** `${Name}` / `${Name.Attr}` in an `Fn::Sub` string; `${!Literal}` is an escape. */
85406
- const SUB_VARIABLE = /\$\{([^!}][^}]*)\}/g;
85407
- /**
85408
- * Which names (parameters, but also resources and pseudo parameters — the
85409
- * caller intersects with the divergent set) the RAW `Properties` of a resource
85410
- * depend on, plus its resource-level `Condition`.
85411
- *
85412
- * Generic by design: instead of modelling each intrinsic's argument grammar it
85413
- * recurses into EVERY value, so a `Ref` nested in an `Fn::Join` / `Fn::Select`
85414
- * / `Fn::Split` operand, an `Fn::FindInMap` key, or an `Fn::Sub` variable-map
85415
- * value is found without being named. Only the three forms that name something
85416
- * by BARE STRING need their own arm: `Ref`, `Fn::Sub`'s template text, and a
85417
- * condition name (`Fn::If`'s first argument, and `Condition` inside the
85418
- * `Conditions` section), which is followed transitively through
85419
- * `template.Conditions`.
85420
- *
85421
- * May throw `RangeError` on a bag deeper than the call stack; the caller wraps
85422
- * it fail-closed, like the discard walk beside it.
85423
- */
85424
- function collectParameterDependencies(properties, resourceCondition, template) {
85425
- const names = /* @__PURE__ */ new Set();
85426
- const attributeTargets = /* @__PURE__ */ new Set();
85427
- const visitedConditions = /* @__PURE__ */ new Set();
85428
- let unclassifiable = false;
85429
- const conditions = template.Conditions !== null && typeof template.Conditions === "object" ? template.Conditions : {};
85430
- const followCondition = (name) => {
85431
- if (typeof name !== "string") {
85432
- unclassifiable = true;
85433
- return;
85434
- }
85435
- if (visitedConditions.has(name)) return;
85436
- visitedConditions.add(name);
85437
- if (!Object.hasOwn(conditions, name)) {
85438
- unclassifiable = true;
85439
- return;
85440
- }
85441
- walk(conditions[name], true);
85442
- };
85443
- const walk = (node, inConditions) => {
85444
- if (node === null || typeof node !== "object") return;
85445
- if (Array.isArray(node)) {
85446
- for (const element of node) walk(element, inConditions);
85447
- return;
85448
- }
85449
- for (const [key, value] of Object.entries(node)) {
85450
- if (key === "Ref") {
85451
- if (typeof value === "string") names.add(value);
85452
- else unclassifiable = true;
85453
- continue;
85454
- }
85455
- if (key === "Fn::Sub") {
85456
- const text = Array.isArray(value) ? value[0] : value;
85457
- if (typeof text !== "string" || Array.isArray(value) && value.length !== 2) unclassifiable = true;
85458
- else for (const match of text.matchAll(SUB_VARIABLE)) {
85459
- const variable = (match[1] ?? "").trim();
85460
- names.add(variable);
85461
- const dot = variable.indexOf(".");
85462
- if (dot > 0) {
85463
- names.add(variable.slice(0, dot));
85464
- attributeTargets.add(variable.slice(0, dot));
85465
- }
85466
- }
85467
- if (Array.isArray(value)) walk(value[1], inConditions);
85468
- continue;
85469
- }
85470
- if (key === "Fn::GetAtt") {
85471
- const target = Array.isArray(value) ? value[0] : value;
85472
- if (typeof target === "string") {
85473
- const dot = target.indexOf(".");
85474
- const logicalId = Array.isArray(value) || dot <= 0 ? target : target.slice(0, dot);
85475
- names.add(logicalId);
85476
- attributeTargets.add(logicalId);
85477
- } else unclassifiable = true;
85478
- walk(value, inConditions);
85479
- continue;
85480
- }
85481
- if (key === "Fn::If") {
85482
- if (Array.isArray(value) && value.length === 3) {
85483
- followCondition(value[0]);
85484
- walk(value[1], inConditions);
85485
- walk(value[2], inConditions);
85486
- } else unclassifiable = true;
85487
- continue;
85488
- }
85489
- if (key === "Condition" && inConditions) {
85490
- followCondition(value);
85491
- continue;
85492
- }
85493
- if (key.startsWith("Fn::") && !KNOWN_INTRINSICS.has(key)) unclassifiable = true;
85494
- walk(value, inConditions);
85495
- }
85496
- };
85497
- walk(properties, false);
85498
- if (resourceCondition !== void 0) followCondition(resourceCondition);
85499
- return {
85500
- names,
85501
- attributeTargets,
85502
- unclassifiable
85503
- };
85504
- }
85505
- /**
85506
- * The divergent parameters that ANYTHING in the template names. A declared
85507
- * parameter nothing names cannot have shaped a resource — and CDK's
85508
- * `BootstrapVersion` is exactly that on every default-synthesized stack: SSM
85509
- * typed, never bound by the resolver because nothing references it, hence
85510
- * always "divergent". Left in, it would arm the unclassifiable-shape refusal on
85511
- * stacks whose every real parameter is proven.
85512
- *
85513
- * "Names" is the UNION of this module's walk and `TemplateParser`'s reference
85514
- * scan — the same scan the resolver uses to decide an SSM-typed parameter is
85515
- * unreferenced — so the two cannot disagree about `BootstrapVersion`. An
85516
- * unclassifiable shape does NOT keep the whole set here: CloudFormation names a
85517
- * parameter only through `Ref`, `Fn::Sub` text or a condition, and the generic
85518
- * recursion reads those inside any intrinsic, known or not. A walk that THROWS
85519
- * keeps the whole set (fail closed).
85520
- */
85521
- function reachableDivergentParameters(template, divergent, rawBags) {
85522
- if (divergent.size === 0) return /* @__PURE__ */ new Set();
85523
- try {
85524
- const roots = [
85525
- rawBags,
85526
- template.Resources,
85527
- template.Outputs,
85528
- template.Conditions
85529
- ];
85530
- const named = new Set(collectParameterDependencies(roots, void 0, template).names);
85531
- const parser = new TemplateParser();
85532
- for (const root of roots) {
85533
- if (root === null || typeof root !== "object") continue;
85534
- for (const name of parser.extractReferences(root)) named.add(name);
85535
- }
85536
- return new Set([...divergent].filter((name) => named.has(name)));
85537
- } catch {
85538
- return new Set(divergent);
85539
- }
85540
- }
85541
- /** Whether any DECLARED parameter is named by anything in the template. */
85542
- function namesAnyDeclaredParameter(template) {
85543
- const declared = template.Parameters;
85544
- if (declared === null || typeof declared !== "object") return false;
85545
- const names = new Set(Object.keys(declared));
85546
- return names.size > 0 && reachableDivergentParameters(template, names, []).size > 0;
85547
- }
85548
- /**
85549
- * The per-stack ARM 4 verdict. Each resource is judged on its TEMPLATE
85550
- * definition (`Properties` + `Condition`) AND on the raw bag the state record
85551
- * carries, unioned: a record preserved by a selective merge holds a previous
85552
- * run's RESOLVED literal (`Value: 'CHANGEME'`), which names no parameter, so
85553
- * judging it on the state bag alone would leave nothing to carry to the
85554
- * freshly imported resource that reads its attribute. Template resources that
85555
- * are not in state at all are judged too, for the same reason.
85556
- *
85557
- * Seeds are direct dependents and unclassifiable bags (a bag that cannot be
85558
- * read cannot be vouched for, and neither can what reads its attributes); the
85559
- * refused set is then closed over ATTRIBUTE reads, to a fixpoint.
85560
- */
85561
- function computeParameterTaint(template, stateBags, divergent) {
85562
- const refused = /* @__PURE__ */ new Set();
85563
- const unclassifiable = /* @__PURE__ */ new Set();
85564
- const parametersHit = /* @__PURE__ */ new Set();
85565
- if (divergent.size === 0) return {
85566
- refused,
85567
- unclassifiable,
85568
- parametersHit
85569
- };
85570
- const templateResources = template.Resources !== null && typeof template.Resources === "object" ? template.Resources : {};
85571
- const readers = /* @__PURE__ */ new Map();
85572
- for (const logicalId of /* @__PURE__ */ new Set([...Object.keys(templateResources), ...stateBags.keys()])) {
85573
- const definition = Object.hasOwn(templateResources, logicalId) ? templateResources[logicalId] : void 0;
85574
- const record = definition !== null && typeof definition === "object" ? definition : {};
85575
- try {
85576
- const dependencies = collectParameterDependencies([record["Properties"], stateBags.get(logicalId)], record["Condition"], template);
85577
- readers.set(logicalId, new Set(dependencies.attributeTargets));
85578
- const hits = [...dependencies.names].filter((name) => divergent.has(name));
85579
- for (const name of hits) parametersHit.add(name);
85580
- if (hits.length > 0) refused.add(logicalId);
85581
- else if (dependencies.unclassifiable) {
85582
- refused.add(logicalId);
85583
- unclassifiable.add(logicalId);
85584
- }
85585
- } catch {
85586
- refused.add(logicalId);
85587
- unclassifiable.add(logicalId);
85588
- }
85589
- }
85590
- for (let grew = refused.size > 0; grew;) {
85591
- grew = false;
85592
- for (const [logicalId, targets] of readers) {
85593
- if (refused.has(logicalId)) continue;
85594
- if (![...targets].some((target) => refused.has(target))) continue;
85595
- refused.add(logicalId);
85596
- grew = true;
85597
- }
85598
- }
85599
- return {
85600
- refused,
85601
- unclassifiable,
85602
- parametersHit
85603
- };
85604
- }
85605
85874
 
85606
85875
  //#endregion
85607
85876
  //#region src/cli/commands/import.ts
85877
+ /**
85878
+ * What {@link resolveImportedProperties} refused, as ONE value (issue #3462).
85879
+ *
85880
+ * It is still the set of logical ids whose observed baseline must not be
85881
+ * captured — every existing reader calls `.has()` — and it additionally carries
85882
+ * the two facts `captureObservedForImportedResources` needs to write, keep or
85883
+ * clear `ResourceState.observedBaselineRefusalReason`. They travel ON the set
85884
+ * rather than beside it, and the capture's parameter is THIS type, so a call
85885
+ * site that copies the ids into a plain `Set` — dropping both facts, and with
85886
+ * them the reason every deploy-side guard keys on — does not compile.
85887
+ */
85888
+ var ObservedBaselineRefusals = class extends Set {
85889
+ /**
85890
+ * The subset ARM 4 named — directly, through an attribute read, or as an
85891
+ * unclassifiable bag — whether or not another arm refused it too.
85892
+ */
85893
+ unverifiableParameter = /* @__PURE__ */ new Set();
85894
+ /**
85895
+ * Whether this run HAD deployed parameter values to compare against. Only
85896
+ * then does "ARM 4 did not name it" mean the placeholder was PROVEN; without
85897
+ * a source it means nothing was judged at all.
85898
+ */
85899
+ hadDeployedParameterSource = false;
85900
+ };
85608
85901
  async function importCommand(stackArg, options) {
85609
85902
  const logger = getLogger();
85610
85903
  if (options.verbose) {
@@ -86164,10 +86457,13 @@ function rebuiltLogicalIdsFrom(rows, template) {
86164
86457
  * import flow never derives outputs (they're computed at deploy time from
86165
86458
  * each resource's attributes), so even an auto-mode rebuild has no reason
86166
86459
  * to wipe them.
86460
+ *
86461
+ * Exported for unit testing — internal to the command flow otherwise.
86167
86462
  */
86168
86463
  function buildStackState(stackName, region, rows, templateParser, template, existingState, selectiveMode) {
86169
86464
  const resources = selectiveMode && existingState ? { ...existingState.resources } : {};
86170
86465
  const parameterNames = new Set(Object.keys(template.Parameters ?? {}));
86466
+ let namesParameter;
86171
86467
  for (const row of rows) {
86172
86468
  if (row.outcome !== "imported" || !row.physicalId) continue;
86173
86469
  const tmplResource = template.Resources[row.logicalId];
@@ -86182,9 +86478,14 @@ function buildStackState(stackName, region, rows, templateParser, template, exis
86182
86478
  properties: tmplResource.Properties ?? {},
86183
86479
  attributes: rowAttributes ?? priorAttributes ?? {},
86184
86480
  dependencies: deps,
86185
- provisionedBy: "sdk"
86481
+ provisionedBy: "sdk",
86482
+ ...prior && prior.physicalId === row.physicalId && (hasUnverifiableParameterRefusal(prior) || hasReasonlessBaselineRefusal(prior) && (namesParameter ??= resourcesNamingDeclaredParameter(template))(row.logicalId)) && {
86483
+ observedBaselineRefused: true,
86484
+ observedBaselineRefusalReason: "unverifiable-parameter"
86485
+ }
86186
86486
  };
86187
86487
  }
86488
+ if (namesParameter?.failedClosed !== void 0) getLogger().debug(`The template's parameter dependence could not be judged (${namesParameter.failedClosed}): every prior observed-baseline refusal recorded without a reason is carried as an unverifiable-parameter refusal.`);
86188
86489
  return {
86189
86490
  version: 10,
86190
86491
  stackName,
@@ -86345,12 +86646,13 @@ function defaultOnlyParameterTemplate(template) {
86345
86646
  * `DescribeStacks` parameters are the comparison); what REMAINS is an
86346
86647
  * import with NO CloudFormation stack, where no deployed-parameter source
86347
86648
  * exists, taint across the nested-stack `Outputs` boundary
86348
- * (`import-deployed-parameters.ts` states it), and the NEXT DEPLOY: the
86349
- * refusal marker is cleared by any UPDATE that rebuilds the record, and
86350
- * `cdkd deploy` binds the same placeholder `Default`, so an UPDATE that does
86351
- * not rewrite the placeholder-bound property captures the readback against
86352
- * it ([#3462](https://github.com/go-to-k/cdkd/issues/3462);
86353
- * `deploy-engine.ts` owns the fix). ARM 4 also WIDENS the population of
86649
+ * (`import-deployed-parameters.ts` states it). The NEXT DEPLOY and a
86650
+ * source-less RE-IMPORT used to be on this list
86651
+ * ([#3462](https://github.com/go-to-k/cdkd/issues/3462)): both bind the
86652
+ * same placeholder `Default`, so both now honour
86653
+ * `ResourceState.observedBaselineRefusalReason`, which this arm's verdict
86654
+ * is recorded as. A binary older than that field still clears the marker on
86655
+ * any UPDATE. ARM 4 also WIDENS the population of
86354
86656
  * [#2872](https://github.com/go-to-k/cdkd/issues/2872): a record preserved
86355
86657
  * by a selective merge that a pre-#2854 import already gave a plaintext
86356
86658
  * baseline is now refused, and a refusal leaves that old baseline in place;
@@ -86378,7 +86680,8 @@ function defaultOnlyParameterTemplate(template) {
86378
86680
  * deployer, which is where the structural remedy for all of the above lives.
86379
86681
  *
86380
86682
  * The set is returned rather than recorded on the state, because it describes
86381
- * THIS run's resolution and nothing downstream of the save has any use for it.
86683
+ * THIS run's resolution; `captureObservedForImportedResources` turns it into
86684
+ * the two record fields that DO outlive the run.
86382
86685
  *
86383
86686
  * Exported for unit testing — internal to the command flow otherwise. The
86384
86687
  * masking this walk applies (issue #2803) is only provable against the REAL
@@ -86386,7 +86689,8 @@ function defaultOnlyParameterTemplate(template) {
86386
86689
  * own throw rather than through anything this function writes.
86387
86690
  */
86388
86691
  async function resolveImportedProperties(stackState, template, region, stateBackend, logger, deployedParameters) {
86389
- const unsafeObservedBaselineLogicalIds = /* @__PURE__ */ new Set();
86692
+ const unsafeObservedBaselineLogicalIds = new ObservedBaselineRefusals();
86693
+ unsafeObservedBaselineLogicalIds.hadDeployedParameterSource = deployedParameters !== void 0;
86390
86694
  const entries = Object.entries(stackState.resources ?? {});
86391
86695
  if (entries.length === 0) return unsafeObservedBaselineLogicalIds;
86392
86696
  const resolver = new IntrinsicFunctionResolver(region);
@@ -86455,6 +86759,7 @@ async function resolveImportedProperties(stackState, template, region, stateBack
86455
86759
  }
86456
86760
  if (recordedSecretValues.size > 0 && resource.attributes !== void 0) resource.attributes = redactSecretsForState(resource.attributes, recordedSecretValues);
86457
86761
  const dependsOnDivergent = parameterTaint?.refused.has(logicalId) === true;
86762
+ if (dependsOnDivergent) unsafeObservedBaselineLogicalIds.unverifiableParameter.add(logicalId);
86458
86763
  if (threw || dependsOnDivergent) {
86459
86764
  unsafeObservedBaselineLogicalIds.add(logicalId);
86460
86765
  continue;
@@ -86835,15 +87140,19 @@ async function captureObservedForImportedResources(stackState, providerRegistry,
86835
87140
  if (entries.length === 0) return;
86836
87141
  await Promise.all(entries.map(async ([logicalId, resource]) => {
86837
87142
  if (resource.observedBaselineRefused === true && !rebuiltLogicalIds.has(logicalId)) {
86838
- logger.debug(`observedProperties capture SKIPPED for preserved ${logicalId} (${resource.resourceType}): a previous 'cdkd import' run refused this record's baseline and this run did not re-import it, so its recorded properties are still the ones that refusal distrusted. Deploy a change to this resource to restore a baseline.`);
87143
+ logger.debug(`observedProperties capture SKIPPED for preserved ${logicalId} (${resource.resourceType}): a previous 'cdkd import' run refused this record's baseline and this run did not re-import it, so its recorded properties are still the ones that refusal distrusted. Re-import it, or deploy a change to it, to restore a baseline — unless its refusal is an unverifiable-parameter one, which only a replacement or a proving re-import discharges.`);
86839
87144
  return;
86840
87145
  }
86841
- if (unsafeObservedBaselineLogicalIds.has(logicalId)) {
87146
+ const refusals = unsafeObservedBaselineLogicalIds;
87147
+ const parameterRefusalStands = refusals.unverifiableParameter.has(logicalId) || hasUnverifiableParameterRefusal(resource) && !refusals.hadDeployedParameterSource;
87148
+ if (unsafeObservedBaselineLogicalIds.has(logicalId) || parameterRefusalStands) {
86842
87149
  resource.observedBaselineRefused = true;
86843
- logger.debug(`observedProperties capture SKIPPED for imported ${logicalId} (${resource.resourceType}): the recorded properties cannot be shown to spell every dynamic reference the deployed resource was built from, so they cannot position a redaction — capturing an AWS readback against them could persist a resolved secret in plaintext. Drift will compare against the recorded properties for this resource until the next successful deploy.`);
87150
+ resource.observedBaselineRefusalReason = parameterRefusalStands ? "unverifiable-parameter" : "incomplete-resolution";
87151
+ logger.debug(`observedProperties capture SKIPPED for imported ${logicalId} (${resource.resourceType}): the recorded properties cannot be shown to spell every dynamic reference the deployed resource was built from, so they cannot position a redaction — capturing an AWS readback against them could persist a resolved secret in plaintext. Drift will compare against the recorded properties for this resource until ${parameterRefusalStands ? `it is REPLACED, or re-imported while a CloudFormation stack can prove its parameters were deployed at their 'Default' — an in-place deploy binds the same 'Default' and cannot restore the baseline` : `the next successful deploy`}.`);
86844
87152
  return;
86845
87153
  }
86846
87154
  delete resource.observedBaselineRefused;
87155
+ delete resource.observedBaselineRefusalReason;
86847
87156
  try {
86848
87157
  const provider = providerRegistry.getProviderFor({
86849
87158
  resourceType: resource.resourceType,
@@ -96714,4 +97023,4 @@ function buildProgram() {
96714
97023
 
96715
97024
  //#endregion
96716
97025
  export { buildProgram };
96717
- //# sourceMappingURL=program-COiS7GZJ.js.map
97026
+ //# sourceMappingURL=program-CUOo1x11.js.map