@go-to-k/cdkd 0.284.59 → 0.284.61

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.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { An as Synthesizer, Dr as formatError, Er as SynthesisError, Jt as TemplateParser, Or as isCdkdError, Qn as AssemblyReader, Tr as StateError, Ut as DiffCalculator, W as IAMRoleProvider, Yt as LockManager, Zt as S3StateBackend, ar as setAwsClients, br as ProvisioningError, cr as ConfigError, er as clearBucketRegionCache, gr as LockError, ir as resetAwsClients, kr as normalizeAwsError, nr as AwsClients, or as AssetError, q as ProviderRegistry, qt as DagBuilder, r as DeployEngine, rn as AssetPublisher, rr as getAwsClients, rt as CloudControlProvider, sr as CdkdError, tr as resolveBucketRegion, ur as DependencyError } from "./deploy-engine-B6cbj8-j.js";
1
+ import { Ar as isCdkdError, Dr as StateError, Jt as TemplateParser, Mn as Synthesizer, Or as SynthesisError, Sr as ProvisioningError, Ut as DiffCalculator, W as IAMRoleProvider, Yt as LockManager, Zt as S3StateBackend, ar as getAwsClients, cr as AssetError, er as AssemblyReader, fr as DependencyError, ir as AwsClients, jr as normalizeAwsError, kr as formatError, lr as CdkdError, nr as clearBucketRegionCache, or as resetAwsClients, q as ProviderRegistry, qt as DagBuilder, r as DeployEngine, rn as AssetPublisher, rr as resolveBucketRegion, rt as CloudControlProvider, sr as setAwsClients, ur as ConfigError, vr as LockError } from "./deploy-engine-0d-g0TT4.js";
2
2
  import { n as getLogger, r as setLogger, t as ConsoleLogger } from "./logger-zRrlbaQt.js";
3
3
 
4
4
  export { AssemblyReader, AssetError, AssetPublisher, AwsClients, CdkdError, CloudControlProvider, ConfigError, ConsoleLogger, DagBuilder, DependencyError, DeployEngine, DiffCalculator, IAMRoleProvider, LockError, LockManager, ProviderRegistry, ProvisioningError, S3StateBackend, StateError, SynthesisError, Synthesizer, TemplateParser, clearBucketRegionCache, formatError, getAwsClients, getLogger, isCdkdError, normalizeAwsError, resetAwsClients, resolveBucketRegion, setAwsClients, setLogger };
@@ -1,7 +1,7 @@
1
- import { $ as endCommandInterruptScope, $n as processStackMessages, $t as exportNamesCarriedFrom, A as renderStatefulReason, An as Synthesizer, Ar as withErrorHandling, At as isSingleDynamicReferenceToken, B as exportAliasCollisionScrubWarning, Bn as resolveUseCdkBootstrapAssets, Bt as s3BucketRegionalDomainName, C as isFinalSnapshotError, Cn as formatDockerLoginError, Cr as StackHasActiveImportsError, Ct as requireConfigString, D as extractDeploymentEventError, Dn as runDockerStreaming, Dt as createSecretMasker, E as makeCanonicalizePropertiesFn, En as runDockerForeground, Et as TEMPLATE_SOURCED_RULES, F as green, Fn as resolveAutoAssetStorage, Ft as classifyReplaySecretRegion, G as collectInlinePolicyNamesManagedBySiblings, Gn as MIGRATE_TMP_PREFIX, Gt as describeTypeWithThrottleRetry, H as secretBearingStateKeyWarning, Hn as warnDeprecatedNoPrefixCliFlag, Ht as applyRoleArnIfSet, I as red, In as resolveCaptureObservedState, It as producerRegionsFromState, J as findActionableSilentDrops, Jn as expectedOwnerParam, Jt as TemplateParser, K as clearOnUpdateRemoval, Kn as findLargeInlineResources, Kt as withRetry, L as yellow, Ln as resolveSkipPrefix, Lt as s3BucketArn, M as bold, Mn as getDefaultStateBucketName, Mr as isRetryableTransientError, Mt as maskSecretsInText, N as cyan, Nn as getLegacyStateBucketName, Nr as isThrottlingError, Nt as redactSecretsForState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as AssetManifestLoader, Ot as dynamicReferenceTokens, P as gray, Pn as resolveApp, Pr as markNonRetryable, Pt as scrubResourceRecord, Q as beginCommandInterruptScope, Qn as AssemblyReader, Qt as rebuildClientForBucketRegion, R as collectDeclaredOutputNames, Rn as resolveStateBucketWithDefault, Rt as s3BucketDomainName, S as createPreDeleteFinalSnapshot, Sn as dockerSpawnEnvWithSensitive, Sr as ResourceUpdateNotSupportedError, St as requireConfigObject, T as unsupportedFinalSnapshotError, Tn as partitionSensitiveEnv, Tt as STATE_SOURCED_READBACK_RULES, U as stateKeySecretExposure, Un as CFN_TEMPLATE_BODY_LIMIT, Ut as DiffCalculator, V as isExportAliasCollision, Vn as stateBucketExistenceConfirmed, Vt as s3BucketWebsiteUrl, W as IAMRoleProvider, Wn as CFN_TEMPLATE_URL_LIMIT, Wt as INTRINSIC_KEYS, X as CUSTOM_RESOURCE_RESPONSE_PREFIX, Xn as canonicalizeRegion, Xt as displaySafe, Y as findSilentDropProperties, Yn as PARTITION_TABLE, Yt as LockManager, Z as DEFAULT_STATE_PREFIX, Zn as derivePartitionAndUrlSuffix, Zt as S3StateBackend, _ as computeImplicitDeleteEdges, _n as readBootstrapMarkerBody, _r as MissingCdkCliError, _t as configBooleanRefusal, a as DeploymentEventsStore, an as WorkGraph, ar as setAwsClients, at as disableInstanceApiTermination, b as buildFinalSnapshotIdentifier, bn as buildDenyExternalAccessPolicy, br as ProvisioningError, bt as replayWarn, c as replayFailedOperations, cn as loadPublishableAssetManifest, ct as carriesDynamicReference, d as updatePartialReason, dn as stripControlChars, dr as DeployCancelledError, dt as refStateLookupFromResource, en as importableOutputKeys, et as interruptWatchListenerCount, f as UNSPECIFIED_SKIP_REASON, fn as AssetModeResolver, fr as DynamicReferenceRegionAmbiguousError, ft as WAFv2WebACLProvider, g as IMPLICIT_DELETE_DEPENDENCIES, gn as parseBootstrapMarker, gt as coerceCfnBoolean, h as maskingRetryLogger, hn as getBootstrapMarkerKey, hr as LocalStartServiceError, ht as assertRegionMatch, i as DeploymentEventsReader, in as stringifyValue, ir as resetAwsClients, it as slowCcOperationTimeoutMs, j as formatResourceLine, jn as synthesisStatusMessage, jr as isMarkedNonRetryable, jt as maskSecretsInError, k as isStatefulRecreateTargetSync, kn as getDockerImageBySourceHash, kr as normalizeAwsError, kt as errorCauseChain, l as replayRollback, ln as rewriteTemplateAssetReferences, lr as CrossAccountSecretRefusalError, lt as cfnRefValueFromPhysicalId, m as withResourceDeadline, mn as ensureAssetStorage, mr as LocalMigrateError, mt as resolveExplicitPhysicalId, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as shouldRetainResource, nr as AwsClients, nt as startInterruptWatch, o as planFailedOps, on as buildAssetRedirectMap, ot as isTerminationProtectionPropagationError, p as deleteSkipReason, pn as BOOTSTRAP_MARKER_PREFIX, pr as LocalInvokeBuildError$1, pt as normalizeAwsTagsToCfn, q as ProviderRegistry, qn as uploadCfnTemplate, qt as DagBuilder, r as DeployEngine, rn as AssetPublisher, rr as getAwsClients, rt as CloudControlProvider, s as planRollback, sn as createAssetRedirectResolver, sr as CdkdError, st as IntrinsicFunctionResolver, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as importableOutputs, tr as resolveBucketRegion, tt as isInterruptedWaitError, u as updatePartialMessage, un as escapeRegExp, ut as getAccountInfo, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as validateAssetBucketName, vr as NestedStackChildDirectDestroyError, vt as configStringRefusal, w as refusesFinalSnapshot, wn as getDockerCmd, wr as StackTerminationProtectionError, wt as STATE_SOURCED_CROSS_GENERATION_RULES, x as ccRoutedFinalSnapshotError, xn as buildDockerImage, xr as ResourceTimeoutError, xt as requireConfigArray, y as PRE_DELETE_SNAPSHOT_TYPES, yn as validateContainerRepoName, yr as PartialFailureError, yt as readConfigString, z as collectPublishedOutputNames, zn as resolveStateBucketWithDefaultAndSource, zt as s3BucketDualStackDomainName } from "./deploy-engine-B6cbj8-j.js";
1
+ import { $ as endCommandInterruptScope, $n as derivePartitionAndUrlSuffix, $t as exportNamesCarriedFrom, A as renderStatefulReason, An as AssetManifestLoader, At as isSingleDynamicReferenceToken, B as exportAliasCollisionScrubWarning, Bn as resolveStateBucketWithDefault, Bt as s3BucketRegionalDomainName, C as isFinalSnapshotError, Cn as buildDockerImage, Cr as ResourceTimeoutError, Ct as requireConfigString, D as extractDeploymentEventError, Dn as partitionSensitiveEnv, Dt as createSecretMasker, E as makeCanonicalizePropertiesFn, En as getDockerCmd, Er as StackTerminationProtectionError, Et as TEMPLATE_SOURCED_RULES, F as green, Fn as getLegacyStateBucketName, Fr as isThrottlingError, Ft as classifyReplaySecretRegion, G as collectInlinePolicyNamesManagedBySiblings, Gn as CFN_TEMPLATE_BODY_LIMIT, Gt as describeTypeWithThrottleRetry, H as secretBearingStateKeyWarning, Hn as resolveUseCdkBootstrapAssets, Ht as applyRoleArnIfSet, I as red, In as resolveApp, Ir as markNonRetryable, It as producerRegionsFromState, J as findActionableSilentDrops, Jn as findLargeInlineResources, Jt as TemplateParser, K as clearOnUpdateRemoval, Kn as CFN_TEMPLATE_URL_LIMIT, Kt as withRetry, L as yellow, Ln as resolveAutoAssetStorage, Lt as s3BucketArn, M as bold, Mn as Synthesizer, Mr as withErrorHandling, Mt as maskSecretsInText, N as cyan, Nn as synthesisStatusMessage, Nr as isMarkedNonRetryable, Nt as redactSecretsForState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as runDockerForeground, Ot as dynamicReferenceTokens, P as gray, Pn as getDefaultStateBucketName, Pr as isRetryableTransientError, Pt as scrubResourceRecord, Q as beginCommandInterruptScope, Qn as canonicalizeRegion, Qt as rebuildClientForBucketRegion, R as collectDeclaredOutputNames, Rn as resolveCaptureObservedState, Rt as s3BucketDomainName, S as createPreDeleteFinalSnapshot, Sn as buildDenyExternalAccessPolicy, Sr as ProvisioningError, St as requireConfigObject, T as unsupportedFinalSnapshotError, Tn as formatDockerLoginError, Tr as StackHasActiveImportsError, Tt as STATE_SOURCED_READBACK_RULES, U as stateKeySecretExposure, Un as stateBucketExistenceConfirmed, Ut as DiffCalculator, V as isExportAliasCollision, Vn as resolveStateBucketWithDefaultAndSource, Vt as s3BucketWebsiteUrl, W as IAMRoleProvider, Wn as warnDeprecatedNoPrefixCliFlag, Wt as INTRINSIC_KEYS, X as CUSTOM_RESOURCE_RESPONSE_PREFIX, Xn as expectedOwnerParam, Xt as displaySafe, Y as findSilentDropProperties, Yn as uploadCfnTemplate, Yt as LockManager, Z as DEFAULT_STATE_PREFIX, Zn as PARTITION_TABLE, Zt as S3StateBackend, _ as computeImplicitDeleteEdges, _n as isCrossRegionRedirect, _r as LocalStartServiceError, _t as configBooleanRefusal, a as DeploymentEventsStore, an as WorkGraph, ar as getAwsClients, at as disableInstanceApiTermination, b as buildFinalSnapshotIdentifier, bn as validateAssetBucketName, br as NestedStackChildDirectDestroyError, bt as replayWarn, c as replayFailedOperations, cn as loadPublishableAssetManifest, ct as carriesDynamicReference, d as updatePartialReason, dn as stripControlChars, dr as CrossAccountSecretRefusalError, dt as refStateLookupFromResource, en as importableOutputKeys, er as AssemblyReader, et as interruptWatchListenerCount, f as UNSPECIFIED_SKIP_REASON, fn as AssetModeResolver, ft as WAFv2WebACLProvider, g as IMPLICIT_DELETE_DEPENDENCIES, gn as getBootstrapMarkerKey, gr as LocalMigrateError, gt as coerceCfnBoolean, h as maskingRetryLogger, hn as ensureAssetStorage, hr as LocalInvokeBuildError$1, ht as assertRegionMatch, i as DeploymentEventsReader, in as stringifyValue, ir as AwsClients, it as slowCcOperationTimeoutMs, j as formatResourceLine, jn as getDockerImageBySourceHash, jr as normalizeAwsError, jt as maskSecretsInError, k as isStatefulRecreateTargetSync, kn as runDockerStreaming, kt as errorCauseChain, l as replayRollback, ln as rewriteTemplateAssetReferences, lr as CdkdError, lt as cfnRefValueFromPhysicalId, m as withResourceDeadline, mn as assertAssetBucketRegion, mr as DynamicReferenceRegionAmbiguousError, mt as resolveExplicitPhysicalId, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as shouldRetainResource, nt as startInterruptWatch, o as planFailedOps, on as buildAssetRedirectMap, or as resetAwsClients, ot as isTerminationProtectionPropagationError, p as deleteSkipReason, pn as BOOTSTRAP_MARKER_PREFIX, pr as DeployCancelledError, pt as normalizeAwsTagsToCfn, q as ProviderRegistry, qn as MIGRATE_TMP_PREFIX, qt as DagBuilder, r as DeployEngine, rn as AssetPublisher, rr as resolveBucketRegion, rt as CloudControlProvider, s as planRollback, sn as createAssetRedirectResolver, sr as setAwsClients, st as IntrinsicFunctionResolver, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as importableOutputs, tr as processStackMessages, tt as isInterruptedWaitError, u as updatePartialMessage, un as escapeRegExp, ut as getAccountInfo, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as parseBootstrapMarker, vt as configStringRefusal, w as refusesFinalSnapshot, wn as dockerSpawnEnvWithSensitive, wr as ResourceUpdateNotSupportedError, wt as STATE_SOURCED_CROSS_GENERATION_RULES, x as ccRoutedFinalSnapshotError, xn as validateContainerRepoName, xr as PartialFailureError, xt as requireConfigArray, y as PRE_DELETE_SNAPSHOT_TYPES, yn as readBootstrapMarkerBody, yr as MissingCdkCliError, yt as readConfigString, z as collectPublishedOutputNames, zn as resolveSkipPrefix, zt as s3BucketDualStackDomainName } from "./deploy-engine-0d-g0TT4.js";
2
2
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
3
- import { t as getCdkdVersion } from "./version-Biow6J38.js";
4
- import { t as ASGProvider } from "./asg-provider-BkbyCmqe.js";
3
+ import { t as getCdkdVersion } from "./version-iXYxz3AH.js";
4
+ import { t as ASGProvider } from "./asg-provider-DTolzTHQ.js";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import { createHash, randomBytes, randomUUID } from "node:crypto";
7
7
  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, 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";
@@ -1229,7 +1229,7 @@ async function scanStateReferences(stateBackend, names) {
1229
1229
  * (skip, info line) when the bucket does not exist — the idempotency
1230
1230
  * mirror of `ensureAssetStorage`.
1231
1231
  */
1232
- async function emptyAndDeleteBucket(s3Client, bucket, accountId, label, logger) {
1232
+ async function emptyAndDeleteBucket(s3Client, bucket, accountId, label, logger, expectedRegion) {
1233
1233
  try {
1234
1234
  await s3Client.send(new HeadBucketCommand({
1235
1235
  Bucket: bucket,
@@ -1242,6 +1242,7 @@ async function emptyAndDeleteBucket(s3Client, bucket, accountId, label, logger)
1242
1242
  return false;
1243
1243
  }
1244
1244
  if (err.$metadata?.httpStatusCode === 403) throw new CdkdError(`${label} '${bucket}' exists but is not owned by account ${accountId} (or access is denied). Refusing to delete it.`, "ASSET_STORAGE_FOREIGN_BUCKET", error);
1245
+ if (expectedRegion !== void 0 && isCrossRegionRedirect(error)) await assertAssetBucketRegion(s3Client, bucket, expectedRegion, accountId, error);
1245
1246
  throw normalizeAwsError(error, {
1246
1247
  bucket,
1247
1248
  operation: "HeadBucket"
@@ -1499,7 +1500,7 @@ async function bootstrapDestroyCommand(options) {
1499
1500
  return;
1500
1501
  }
1501
1502
  if (marker) {
1502
- await emptyAndDeleteBucket(awsClients.s3, marker.assetBucket, accountId, "Asset bucket", logger);
1503
+ await emptyAndDeleteBucket(awsClients.s3, marker.assetBucket, accountId, "Asset bucket", logger, region);
1503
1504
  await deleteContainerRepo(marker.containerRepo, region, options.profile, logger);
1504
1505
  await stateBackend.deleteRawObjects([resolvedMarkerKey]);
1505
1506
  logger.info(`✓ Deleted bootstrap marker (${resolvedMarkerKey})`);
@@ -1510,7 +1511,7 @@ async function bootstrapDestroyCommand(options) {
1510
1511
  if (options.includeStateBucket) {
1511
1512
  const rebuiltStateBucketClient = await rebuildClientForBucketRegion(awsClients.s3, bucketName, { ...options.profile && { profile: options.profile } });
1512
1513
  try {
1513
- await emptyAndDeleteBucket(rebuiltStateBucketClient ?? awsClients.s3, bucketName, accountId, "State bucket", logger);
1514
+ await emptyAndDeleteBucket(rebuiltStateBucketClient ?? awsClients.s3, bucketName, accountId, "State bucket", logger, void 0);
1514
1515
  } finally {
1515
1516
  rebuiltStateBucketClient?.destroy();
1516
1517
  }
@@ -34029,6 +34030,86 @@ const DEPLOYMENT_CONFIG_PRESERVE_KEYS_CAMEL = /* @__PURE__ */ new Set(["hookDeta
34029
34030
  */
34030
34031
  const SERVICE_CONNECT_PRESERVE_KEYS = /* @__PURE__ */ new Set(["Options"]);
34031
34032
  /**
34033
+ * SHARED RATIONALE for both `CIRCUIT_BREAKER_*_DEFAULT` constants below —
34034
+ * WHERE THE VALUES COME FROM, and when they may be sent (issue #1861).
34035
+ *
34036
+ * They are the values CloudFormation was MEASURED to produce when a template
34037
+ * that previously DECLARED the member stops declaring it (us-east-1,
34038
+ * 2026-08-13, same service, `Rollback` flipped in the same call so the update
34039
+ * demonstrably applied and service identity captured on both sides so a
34040
+ * replacement could not be mistaken for a reset): `resetOnHealthyTask` false
34041
+ * -> `true`, `thresholdConfiguration` {COUNT, 7} -> {BOUNDED_PERCENT, 50}.
34042
+ * They match the SDK's documented defaults for both members, and the SDK
34043
+ * documents those unconditionally — they do not vary by scheduling strategy or
34044
+ * deployment type (see the strategy note in `updateService`'s comment block).
34045
+ *
34046
+ * They are used ONLY as `clearOnUpdateRemoval`'s clear value, i.e. only on a
34047
+ * previous-present / current-absent REMOVAL. They must NEVER be sent for a
34048
+ * member the template never declared — a third measurement in the same
34049
+ * session set both members OUT OF BAND on a service whose template never
34050
+ * declared them, then ran a CloudFormation update that flipped `Rollback`
34051
+ * INSIDE the block: the out-of-band `false` / {COUNT, 9} BOTH survived. That
34052
+ * arm is what excludes the competing reading "CFn re-serializes the struct
34053
+ * whenever its declared content changed" and makes this a genuine removal.
34054
+ */
34055
+ /**
34056
+ * `DeploymentCircuitBreaker.ResetOnHealthyTask`'s AWS default. A primitive, so
34057
+ * it needs no copy-on-use treatment — unlike its object-valued sibling below.
34058
+ * Provenance and the send-only-on-removal rule: see the shared note above.
34059
+ */
34060
+ const CIRCUIT_BREAKER_RESET_ON_HEALTHY_TASK_DEFAULT = true;
34061
+ /**
34062
+ * `DeploymentCircuitBreaker.ThresholdConfiguration`'s AWS default. Provenance
34063
+ * and the send-only-on-removal rule: see the shared note above.
34064
+ *
34065
+ * FROZEN, and spread into a fresh object at the use site rather than handed
34066
+ * over by reference. `ECSProvider` is a singleton serving concurrent
34067
+ * resources, so a module-level object reaching the SDK input directly would be
34068
+ * one shared mutable value across every in-flight `UpdateService` — a
34069
+ * middleware or a future normalization step mutating it would corrupt every
34070
+ * other caller. The two halves guard different failures and BOTH are pinned by
34071
+ * unit arms: the copy means no caller can ever reach this object, and the
34072
+ * freeze means a caller that somehow does fails LOUDLY instead of silently
34073
+ * poisoning every later update.
34074
+ *
34075
+ * @internal EXPORTED for tests only (issue #1861). Every production consumer
34076
+ * is in this file. The export exists because the freeze is otherwise
34077
+ * UNOBSERVABLE from a test: the resolver hands out a copy by design, so the
34078
+ * payload a test can reach is never this object, and dropping `Object.freeze`
34079
+ * left the whole suite green. Asserting it through a source grep was the
34080
+ * alternative and is the weaker fence this repo has retired elsewhere.
34081
+ */
34082
+ const CIRCUIT_BREAKER_THRESHOLD_CONFIGURATION_DEFAULT = Object.freeze({
34083
+ type: "BOUNDED_PERCENT",
34084
+ value: 50
34085
+ });
34086
+ /**
34087
+ * A plain object — something a CFn config block can legitimately be. Arrays
34088
+ * and non-objects are excluded on purpose: `typeof [] === 'object'` and every
34089
+ * non-empty string is truthy, so a truthiness check would wave a malformed
34090
+ * template through into a spread.
34091
+ *
34092
+ * Deliberately a module-local copy rather than an export added to
34093
+ * `src/provisioning/config-shape.ts`, whose private `isPlainObject` is
34094
+ * byte-identical: this lane may not widen a shared module's API.
34095
+ *
34096
+ * No "promote it if a third copy appears" trigger, because that already fired
34097
+ * long before this PR and adding it here would read as a new one. Grepped for
34098
+ * a standalone helper whose body is exactly this predicate: NINE across nine
34099
+ * files under six different names — `config-shape.ts`, `wafv2-provider.ts`,
34100
+ * `s3-bucket-provider.ts` (`isPlainObject`), `emr-configuration.ts`,
34101
+ * `lambda-microvm-image-provider.ts` (`isRecord`),
34102
+ * `apigateway-provider.ts` (`isPlainObjectBlock`), `drift.ts`
34103
+ * (`isPlainRecord`), `lambda-vpc-deps.ts` (`isObject`), and this one — plus
34104
+ * further INLINE copies (`route53-provider.ts` x2,
34105
+ * `custom-resource-provider.ts`, `diff-recursive.ts`,
34106
+ * `intrinsic-function-resolver.ts`). Consolidating them touches files across
34107
+ * several lanes and is a separate lane's job, not this PR's.
34108
+ */
34109
+ function isPlainCfnObject(value) {
34110
+ return typeof value === "object" && value !== null && !Array.isArray(value);
34111
+ }
34112
+ /**
34032
34113
  * Derive the cluster name from a long-format ECS Service ARN
34033
34114
  * (`arn:<partition>:ecs:<region>:<account>:service/<clusterName>/<serviceName>`)
34034
34115
  * so `DescribeServices` can be scoped to the right cluster (issue #1170).
@@ -34466,6 +34547,7 @@ var ECSProvider = class {
34466
34547
  const vpcLatticeConfigurationsInput = JSON.stringify(previousProperties["VpcLatticeConfigurations"] ?? null) !== JSON.stringify(properties["VpcLatticeConfigurations"] ?? null) ? clearOnUpdateRemoval(this.convertVpcLatticeConfigurations(properties["VpcLatticeConfigurations"]), previousProperties["VpcLatticeConfigurations"], []) : void 0;
34467
34548
  const monitoringInput = JSON.stringify(previousProperties["Monitoring"] ?? null) !== JSON.stringify(properties["Monitoring"] ?? null) && properties["Monitoring"] != null ? this.convertMonitoringConfiguration(properties["Monitoring"]) : void 0;
34468
34549
  const forceNewDeploymentInput = this.resolveForceNewDeployment(properties, previousProperties);
34550
+ const deploymentConfigurationInput = this.resolveDeploymentConfiguration(properties, previousProperties);
34469
34551
  try {
34470
34552
  const service = (await client.send(new UpdateServiceCommand({
34471
34553
  cluster: properties["Cluster"],
@@ -34474,7 +34556,7 @@ var ECSProvider = class {
34474
34556
  desiredCount: properties["DesiredCount"],
34475
34557
  networkConfiguration: this.convertNetworkConfiguration(properties["NetworkConfiguration"]),
34476
34558
  capacityProviderStrategy: capacityProviderStrategyInput,
34477
- deploymentConfiguration: this.convertDeploymentConfiguration(properties["DeploymentConfiguration"]),
34559
+ deploymentConfiguration: deploymentConfigurationInput,
34478
34560
  placementConstraints: placementConstraintsInput,
34479
34561
  placementStrategy: placementStrategyInput,
34480
34562
  platformVersion: platformVersionInput,
@@ -35186,6 +35268,93 @@ var ECSProvider = class {
35186
35268
  return pascalToCamelCaseKeys(config, DEPLOYMENT_CONFIG_PRESERVE_KEYS);
35187
35269
  }
35188
35270
  /**
35271
+ * UPDATE-path `DeploymentConfiguration` resolver: the verbatim conversion
35272
+ * above, plus the ONE member-level removal reset real AWS measurement found
35273
+ * in this property tree (issue #1861).
35274
+ *
35275
+ * The rule this keys on is previous-present / current-absent — exactly the
35276
+ * semantic `clearOnUpdateRemoval` implements for TOP-LEVEL properties, which
35277
+ * is why this reuses that helper rather than re-spelling the predicate. What
35278
+ * is new is only the DEPTH: the member lives inside a nested struct the
35279
+ * template STILL DECLARES.
35280
+ *
35281
+ * Scope is deliberately narrow, and each boundary is measured rather than
35282
+ * reasoned about (us-east-1, 2026-08-13; the full A/B table is in the long
35283
+ * comment inside `updateService`):
35284
+ * - Only `DeploymentCircuitBreaker`'s two OPTIONAL members
35285
+ * (`ResetOnHealthyTask`, `ThresholdConfiguration`). Its REQUIRED sibling
35286
+ * `Rollback` reads as REPLACED, so one block holds members with
35287
+ * different semantics and no row generalizes to its neighbours.
35288
+ * - NOT the depth-1 siblings `LinearConfiguration` / `CanaryConfiguration`
35289
+ * / `LifecycleHooks[].TimeoutConfiguration`: those are already PARITY
35290
+ * because the ECS API ITSELF replaces the struct and default-fills the
35291
+ * omitted member, so adding a reset there would be the divergence.
35292
+ * - NOT the whole-struct cases. Removing the whole `DeploymentConfiguration`
35293
+ * resets nothing under either engine, and the parent
35294
+ * `DeploymentCircuitBreaker` disappearing entirely was never measured —
35295
+ * so BOTH sides must still declare the block for a member omission to
35296
+ * read as a removal.
35297
+ * - NOT "always send the defaults": a member the template NEVER declared
35298
+ * is left alone by CloudFormation even when the block around it changes,
35299
+ * and `clearOnUpdateRemoval` returning `undefined` for that case is what
35300
+ * keeps cdkd from clobbering an out-of-band value CFn preserves.
35301
+ * - NOT scoped by scheduling strategy, and that is a deliberate omission
35302
+ * rather than an unconsidered one. The A/B ran on a ROLLING / REPLICA /
35303
+ * Fargate service and DAEMON was never exercised, so the question is
35304
+ * fair — and DAEMON is genuinely REACHABLE here, because the SDK states
35305
+ * that CODE_DEPLOY / EXTERNAL controllers do not support DAEMON, so a
35306
+ * DAEMON service necessarily runs the ECS rolling-update type and can
35307
+ * carry a circuit breaker. What makes the omission safe is narrower and
35308
+ * PER-FIELD: the SDK documents these TWO members' defaults with no
35309
+ * strategy dimension. It is not a general property of this block —
35310
+ * `minimumHealthyPercent`'s default IS strategy-dependent (100% replica
35311
+ * vs 0% DAEMON), and stays correct only because cdkd passes it through
35312
+ * rather than defaulting it.
35313
+ *
35314
+ * The previous side stays RAW CFn PascalCase on purpose: `clearOnUpdateRemoval`
35315
+ * only inspects it for PRESENCE, the same shortcut the top-level call sites
35316
+ * in `updateService` take.
35317
+ *
35318
+ * SCOPE OF THAT PRESENCE TEST — state it as what it literally is, because
35319
+ * the obvious reading is stronger than the truth. It means "the previous
35320
+ * BAG carried this member", NOT "the previous TEMPLATE declared it". Those
35321
+ * coincide on the deploy path, where `previousProperties` is the last
35322
+ * deployed template. They do NOT at `drift --revert`
35323
+ * (`src/cli/commands/drift.ts`, the `provider.update(...)` call that passes
35324
+ * `outcome.awsProperties`), where the previous bag is an AWS READBACK: a
35325
+ * member the template never declared but AWS reports is present there, so a
35326
+ * desired side that omits it reads as a removal and gets the default sent.
35327
+ * The window is narrow — the revert path's own desired bag is built from
35328
+ * `observedProperties`, which normally carries the member too, and its
35329
+ * `preserveUntemplated` arm recurses via `mergeUntemplatedValue` and keeps
35330
+ * AWS-only members — but it is real when an `observedProperties` snapshot
35331
+ * predates AWS reporting the member. This is NOT specific to this resolver:
35332
+ * every `clearOnUpdateRemoval` site in the codebase — 78 across 14 provider
35333
+ * files before this PR, 80 with this resolver's two — carries the same
35334
+ * exposure, so fixing it belongs to that shared contract, not here. It is
35335
+ * written down and unit-pinned so the next member copied onto this pattern
35336
+ * does not inherit the premise unchecked.
35337
+ */
35338
+ resolveDeploymentConfiguration(properties, previousProperties) {
35339
+ const desired = this.convertDeploymentConfiguration(properties["DeploymentConfiguration"]);
35340
+ const desiredBreaker = desired?.deploymentCircuitBreaker;
35341
+ if (!desired || !isPlainCfnObject(desiredBreaker)) return desired;
35342
+ const previousDeploymentConfiguration = previousProperties["DeploymentConfiguration"];
35343
+ const previousBreaker = isPlainCfnObject(previousDeploymentConfiguration) ? previousDeploymentConfiguration["DeploymentCircuitBreaker"] : void 0;
35344
+ if (!isPlainCfnObject(previousBreaker)) return desired;
35345
+ const resetOnHealthyTask = clearOnUpdateRemoval(desiredBreaker.resetOnHealthyTask, previousBreaker["ResetOnHealthyTask"], CIRCUIT_BREAKER_RESET_ON_HEALTHY_TASK_DEFAULT);
35346
+ const thresholdConfiguration = clearOnUpdateRemoval(desiredBreaker.thresholdConfiguration, previousBreaker["ThresholdConfiguration"], { ...CIRCUIT_BREAKER_THRESHOLD_CONFIGURATION_DEFAULT });
35347
+ if (resetOnHealthyTask === desiredBreaker.resetOnHealthyTask && thresholdConfiguration === desiredBreaker.thresholdConfiguration) return desired;
35348
+ return {
35349
+ ...desired,
35350
+ deploymentCircuitBreaker: {
35351
+ ...desiredBreaker,
35352
+ ...resetOnHealthyTask !== void 0 ? { resetOnHealthyTask } : {},
35353
+ ...thresholdConfiguration !== void 0 ? { thresholdConfiguration } : {}
35354
+ }
35355
+ };
35356
+ }
35357
+ /**
35189
35358
  * Convert the CFn PascalCase `CapacityProviderStrategy` array to the ECS SDK
35190
35359
  * camelCase input shape (issue #1165). Each element `{CapacityProvider,
35191
35360
  * Weight, Base}` is a pure first-letter case flip to `{capacityProvider,
@@ -87704,4 +87873,4 @@ function buildProgram() {
87704
87873
 
87705
87874
  //#endregion
87706
87875
  export { buildProgram };
87707
- //# sourceMappingURL=program-D2zqjYCT.js.map
87876
+ //# sourceMappingURL=program-CrJMVg4e.js.map