@go-to-k/cdkd 0.283.0 → 0.283.1

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/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { $ as configStringRefusal, $t as resolveStateBucketWithDefaultAndSource, A as green, An as NestedStackChildDirectDestroyError, At as BOOTSTRAP_MARKER_PREFIX, B as slowCcOperationTimeoutMs, Bt as runDockerForeground, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ct as stringifyValue, D as bold, Dn as LocalStartServiceError, Dt as loadPublishableAssetManifest, E as formatResourceLine, En as LocalMigrateError, Et as createAssetRedirectResolver, F as clearOnUpdateRemoval, Fn as StackHasActiveImportsError, Ft as validateContainerRepoName, G as getAccountInfo, Gt as synthesisStatusMessage, H as isTerminationProtectionPropagationError, Hn as withErrorHandling, Ht as AssetManifestLoader, I as ProviderRegistry, In as StackTerminationProtectionError, It as buildDenyExternalAccessPolicy, J as normalizeAwsTagsToCfn, Jt as resolveApp, K as refStateLookupFromResource, Kt as getDefaultStateBucketName, L as findActionableSilentDrops, Lt as buildDockerImage, M as yellow, Mn as ProvisioningError, Mt as getBootstrapMarkerKey, N as IAMRoleProvider, Nn as ResourceTimeoutError, Nt as parseBootstrapMarker, O as cyan, Ot as rewriteTemplateAssetReferences, P as collectInlinePolicyNamesManagedBySiblings, Pn as ResourceUpdateNotSupportedError, Pt as validateAssetBucketName, Q as configBooleanRefusal, Qt as resolveStateBucketWithDefault, R as findSilentDropProperties, Rt as formatDockerLoginError, S as extractDeploymentEventError, St as AssetPublisher, T as renderStatefulReason, Tn as LocalInvokeBuildError$1, Tt as buildAssetRedirectMap, U as IntrinsicFunctionResolver, Ut as getDockerImageBySourceHash, V as disableInstanceApiTermination, Vn as normalizeAwsError, Vt as runDockerStreaming, W as cfnRefValueFromPhysicalId, Wt as Synthesizer, X as assertRegionMatch, Xt as resolveCaptureObservedState, Y as resolveExplicitPhysicalId, Yt as resolveAutoAssetStorage, Z as coerceCfnBoolean, Zt as resolveSkipPrefix, _ as createPreDeleteFinalSnapshot, _n as getAwsClients, _t as TemplateParser, a as DeploymentEventsStore, an as MIGRATE_TMP_PREFIX, at as s3BucketArn, b as unsupportedFinalSnapshotError, bt as rebuildClientForBucketRegion, c as replayFailedOperations, cn as expectedOwnerParam, ct as s3BucketRegionalDomainName, d as IMPLICIT_DELETE_DEPENDENCIES, dn as derivePartitionAndUrlSuffix, dt as DiffCalculator, en as resolveUseCdkBootstrapAssets, et as readConfigString, f as computeImplicitDeleteEdges, fn as AssemblyReader, ft as describeTypeWithThrottleRetry, g as ccRoutedFinalSnapshotError, gn as AwsClients, gt as DagBuilder, h as buildFinalSnapshotIdentifier, hn as resolveBucketRegion, ht as isThrottlingError, i as DeploymentEventsReader, in as CFN_TEMPLATE_URL_LIMIT, it as requireConfigString, j as red, jn as PartialFailureError, jt as ensureAssetStorage, k as gray, kn as MissingCdkCliError, kt as AssetModeResolver, l as replayRollback, ln as PARTITION_TABLE, lt as s3BucketWebsiteUrl, m as PRE_DELETE_SNAPSHOT_TYPES, mt as isRetryableTransientError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as warnDeprecatedNoPrefixCliFlag, nt as requireConfigArray, o as planFailedOps, on as findLargeInlineResources, ot as s3BucketDomainName, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as processStackMessages, pt as withRetry, q as WAFv2WebACLProvider, qt as getLegacyStateBucketName, r as DeployEngine, rn as CFN_TEMPLATE_BODY_LIMIT, rt as requireConfigObject, s as planRollback, sn as uploadCfnTemplate, st as s3BucketDualStackDomainName, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as stateBucketExistenceConfirmed, tt as replayWarn, u as withResourceDeadline, un as canonicalizeRegion, ut as applyRoleArnIfSet, v as isFinalSnapshotError, vn as resetAwsClients, vt as LockManager, w as isStatefulRecreateTargetSync, wn as DeployCancelledError, wt as WorkGraph, x as makeCanonicalizePropertiesFn, xn as CdkdError, xt as shouldRetainResource, y as refusesFinalSnapshot, yn as setAwsClients, yt as S3StateBackend, z as CloudControlProvider, zt as getDockerCmd } from "./deploy-engine-CEzMNZTA.js";
2
+ import { $ as configStringRefusal, $t as resolveStateBucketWithDefaultAndSource, A as green, An as NestedStackChildDirectDestroyError, At as BOOTSTRAP_MARKER_PREFIX, B as slowCcOperationTimeoutMs, Bt as runDockerForeground, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ct as stringifyValue, D as bold, Dn as LocalStartServiceError, Dt as loadPublishableAssetManifest, E as formatResourceLine, En as LocalMigrateError, Et as createAssetRedirectResolver, F as clearOnUpdateRemoval, Fn as StackHasActiveImportsError, Ft as validateContainerRepoName, G as getAccountInfo, Gt as synthesisStatusMessage, H as isTerminationProtectionPropagationError, Hn as withErrorHandling, Ht as AssetManifestLoader, I as ProviderRegistry, In as StackTerminationProtectionError, It as buildDenyExternalAccessPolicy, J as normalizeAwsTagsToCfn, Jt as resolveApp, K as refStateLookupFromResource, Kt as getDefaultStateBucketName, L as findActionableSilentDrops, Lt as buildDockerImage, M as yellow, Mn as ProvisioningError, Mt as getBootstrapMarkerKey, N as IAMRoleProvider, Nn as ResourceTimeoutError, Nt as parseBootstrapMarker, O as cyan, Ot as rewriteTemplateAssetReferences, P as collectInlinePolicyNamesManagedBySiblings, Pn as ResourceUpdateNotSupportedError, Pt as validateAssetBucketName, Q as configBooleanRefusal, Qt as resolveStateBucketWithDefault, R as findSilentDropProperties, Rt as formatDockerLoginError, S as extractDeploymentEventError, St as AssetPublisher, T as renderStatefulReason, Tn as LocalInvokeBuildError$1, Tt as buildAssetRedirectMap, U as IntrinsicFunctionResolver, Ut as getDockerImageBySourceHash, V as disableInstanceApiTermination, Vn as normalizeAwsError, Vt as runDockerStreaming, W as cfnRefValueFromPhysicalId, Wt as Synthesizer, X as assertRegionMatch, Xt as resolveCaptureObservedState, Y as resolveExplicitPhysicalId, Yt as resolveAutoAssetStorage, Z as coerceCfnBoolean, Zt as resolveSkipPrefix, _ as createPreDeleteFinalSnapshot, _n as getAwsClients, _t as TemplateParser, a as DeploymentEventsStore, an as MIGRATE_TMP_PREFIX, at as s3BucketArn, b as unsupportedFinalSnapshotError, bt as rebuildClientForBucketRegion, c as replayFailedOperations, cn as expectedOwnerParam, ct as s3BucketRegionalDomainName, d as IMPLICIT_DELETE_DEPENDENCIES, dn as derivePartitionAndUrlSuffix, dt as DiffCalculator, en as resolveUseCdkBootstrapAssets, et as readConfigString, f as computeImplicitDeleteEdges, fn as AssemblyReader, ft as describeTypeWithThrottleRetry, g as ccRoutedFinalSnapshotError, gn as AwsClients, gt as DagBuilder, h as buildFinalSnapshotIdentifier, hn as resolveBucketRegion, ht as isThrottlingError, i as DeploymentEventsReader, in as CFN_TEMPLATE_URL_LIMIT, it as requireConfigString, j as red, jn as PartialFailureError, jt as ensureAssetStorage, k as gray, kn as MissingCdkCliError, kt as AssetModeResolver, l as replayRollback, ln as PARTITION_TABLE, lt as s3BucketWebsiteUrl, m as PRE_DELETE_SNAPSHOT_TYPES, mt as isRetryableTransientError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as warnDeprecatedNoPrefixCliFlag, nt as requireConfigArray, o as planFailedOps, on as findLargeInlineResources, ot as s3BucketDomainName, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as processStackMessages, pt as withRetry, q as WAFv2WebACLProvider, qt as getLegacyStateBucketName, r as DeployEngine, rn as CFN_TEMPLATE_BODY_LIMIT, rt as requireConfigObject, s as planRollback, sn as uploadCfnTemplate, st as s3BucketDualStackDomainName, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as stateBucketExistenceConfirmed, tt as replayWarn, u as withResourceDeadline, un as canonicalizeRegion, ut as applyRoleArnIfSet, v as isFinalSnapshotError, vn as resetAwsClients, vt as LockManager, w as isStatefulRecreateTargetSync, wn as DeployCancelledError, wt as WorkGraph, x as makeCanonicalizePropertiesFn, xn as CdkdError, xt as shouldRetainResource, y as refusesFinalSnapshot, yn as setAwsClients, yt as S3StateBackend, z as CloudControlProvider, zt as getDockerCmd } from "./deploy-engine-InwDI9o0.js";
3
3
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, 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";
4
- import { t as ASGProvider } from "./asg-provider-BNuwJ11q.js";
4
+ import { t as ASGProvider } from "./asg-provider-R3IdAR_3.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";
@@ -15484,10 +15484,16 @@ var DynamoDBGlobalTableProvider = class {
15484
15484
  };
15485
15485
  if (tableArn) await this.applyTagDiff(tableArn, extractLocalTags(previousProperties), extractLocalTags(properties));
15486
15486
  const recordedOldBilling = previousProperties["BillingMode"];
15487
- const recordedOldBillingUsable = recordedOldBilling === void 0 || typeof recordedOldBilling === "string" && recordedOldBilling.trim() !== "";
15488
- const liveBillingMode = describeResp.Table?.BillingModeSummary?.BillingMode ?? "PROVISIONED";
15489
- const oldBilling = recordedOldBillingUsable ? recordedOldBilling ?? "PAY_PER_REQUEST" : liveBillingMode;
15490
- if (!recordedOldBillingUsable) this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: the recorded previous BillingMode is unusable (${JSON.stringify(recordedOldBilling)}) — using the table's actual billing mode (${oldBilling}) as the comparison baseline for this update so a corrected template does not issue a same-mode UpdateTable.`);
15487
+ const recordedOldBillingAbsent = recordedOldBilling === void 0;
15488
+ const recordedOldBillingUsable = typeof recordedOldBilling === "string" && recordedOldBilling.trim() !== "";
15489
+ const rawLiveBillingMode = describeResp.Table?.BillingModeSummary?.BillingMode;
15490
+ const reportedBillingMode = rawLiveBillingMode === "PROVISIONED" || rawLiveBillingMode === "PAY_PER_REQUEST" ? rawLiveBillingMode : void 0;
15491
+ const liveBillingMode = reportedBillingMode ?? "PROVISIONED";
15492
+ const desiredDeclaresBillingMode = properties["BillingMode"] !== void 0;
15493
+ const seedAbsentFromLive = recordedOldBillingAbsent && desiredDeclaresBillingMode;
15494
+ const oldBilling = recordedOldBillingUsable ? recordedOldBilling : recordedOldBillingAbsent ? seedAbsentFromLive ? liveBillingMode : "PAY_PER_REQUEST" : liveBillingMode;
15495
+ if (!recordedOldBillingUsable && !recordedOldBillingAbsent) this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: the recorded previous BillingMode is unusable (${JSON.stringify(recordedOldBilling)}) — using the table's actual billing mode (${oldBilling}) as the comparison baseline for this update so a corrected template does not issue a same-mode UpdateTable.`);
15496
+ if (seedAbsentFromLive && oldBilling !== "PAY_PER_REQUEST") this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: the cdkd state record declares no BillingMode — using ${oldBilling} as the comparison baseline for this update (${reportedBillingMode !== void 0 ? "the mode DescribeTable reports" : "inferred: DescribeTable reports no BillingModeSummary, which means the table was created without an explicit mode"}), so a template declaring a different mode still applies the flip instead of comparing equal to the create-path default.`);
15491
15497
  let billingUnusable = false;
15492
15498
  const requestedBilling = requireConfigString(properties["BillingMode"], "PAY_PER_REQUEST", "AWS::DynamoDB::GlobalTable BillingMode", { onUnusable: (message) => {
15493
15499
  billingUnusable = true;
@@ -15575,6 +15581,7 @@ var DynamoDBGlobalTableProvider = class {
15575
15581
  effectiveProperties = { ...effectiveProperties ?? properties };
15576
15582
  if (recordedOldBilling === void 0) delete effectiveProperties["BillingMode"];
15577
15583
  else effectiveProperties["BillingMode"] = oldBilling;
15584
+ effectiveProperties = retainUnsendableCapacityMembers(effectiveProperties, previousProperties, newBilling);
15578
15585
  }
15579
15586
  const awsOnDemand = describeResp.Table?.OnDemandThroughput;
15580
15587
  const onDemandPayload = {};
@@ -17533,6 +17540,185 @@ function stripProvisionedCapacityKeys(properties) {
17533
17540
  return result;
17534
17541
  }
17535
17542
  /**
17543
+ * The capacity member keys that can only reach AWS while the table is
17544
+ * PROVISIONED, per container level (issue #1738).
17545
+ *
17546
+ * Identical to the set {@link stripProvisionedCapacityKeys} removes, and that
17547
+ * is not a coincidence: both answer "which members are unsendable once the mode
17548
+ * is PAY_PER_REQUEST". The two spellings a pre-#1387 cdkd wrote into state
17549
+ * (`ProvisionedThroughput` / `ProvisionedThroughputOverride`) are included for
17550
+ * the same reason — a state replay is exactly that population.
17551
+ */
17552
+ const PROVISIONED_ONLY_CAPACITY_KEYS = {
17553
+ table: ["WriteProvisionedThroughputSettings"],
17554
+ index: [
17555
+ "WriteProvisionedThroughputSettings",
17556
+ "ReadProvisionedThroughputSettings",
17557
+ "ProvisionedThroughput"
17558
+ ],
17559
+ replica: ["ReadProvisionedThroughputSettings", "ProvisionedThroughputOverride"],
17560
+ replicaIndex: ["ReadProvisionedThroughputSettings", "ProvisionedThroughputOverride"]
17561
+ };
17562
+ /**
17563
+ * The mirror set: capacity members that can only reach AWS while the table is
17564
+ * PAY_PER_REQUEST (issue #1738).
17565
+ *
17566
+ * `stripProvisionedCapacityKeys` has no equivalent because the create arm it
17567
+ * serves always substitutes PAY_PER_REQUEST — the mode under which these ARE
17568
+ * sent, which is why its header says they are deliberately not stripped. On the
17569
+ * UPDATE path the kept mode can be PROVISIONED, and then it is this half that
17570
+ * never leaves the process.
17571
+ */
17572
+ const ON_DEMAND_ONLY_CAPACITY_KEYS = {
17573
+ table: ["WriteOnDemandThroughputSettings"],
17574
+ index: [
17575
+ "WriteOnDemandThroughputSettings",
17576
+ "ReadOnDemandThroughputSettings",
17577
+ "OnDemandThroughput"
17578
+ ],
17579
+ replica: ["ReadOnDemandThroughputSettings", "OnDemandThroughputOverride"],
17580
+ replicaIndex: ["ReadOnDemandThroughputSettings", "OnDemandThroughputOverride"]
17581
+ };
17582
+ /**
17583
+ * Replace every capacity member the KEPT billing mode cannot send with the
17584
+ * PREVIOUS record's value (issue #1738).
17585
+ *
17586
+ * Called from `update()`'s `BillingMode` warn-and-KEEP arm, where an unusable
17587
+ * desired mode suppresses the flip: AWS is left holding the mode it already
17588
+ * had, so every block belonging to the OTHER mode was silently dropped on the
17589
+ * way out while the engine recorded what the template declared.
17590
+ *
17591
+ * **The split is per MEMBER against the KEPT mode**, and each side was read off
17592
+ * the gates in this file rather than off the member's name-shape (the
17593
+ * name-shape trap #1726 records — an on-demand ceiling looks like capacity and
17594
+ * goes on the wire under precisely the on-demand mode):
17595
+ *
17596
+ * - KEPT `PROVISIONED` — the on-demand half is unsendable. Step 3's table-level
17597
+ * `OnDemandThroughput` is gated on `newBilling !== 'PROVISIONED'`;
17598
+ * `toSdkGlobalSecondaryIndexes` and `toSdkReplicaThroughputOverrides` both
17599
+ * drop their on-demand branch under PROVISIONED. The provisioned half is NOT
17600
+ * retained: step 4b and step 6b's auto-scaling reconcile are live whenever
17601
+ * either side is PROVISIONED, and step 6's GSI diff carries per-index
17602
+ * `ProvisionedThroughput` — those blocks really are applied.
17603
+ * - KEPT `PAY_PER_REQUEST` — the provisioned half is unsendable. The table-level
17604
+ * `ProvisionedThroughput` rides step 4's flip and nothing else, the two
17605
+ * auto-scaling reconciles are gated on either side being PROVISIONED, and both
17606
+ * translators drop their provisioned branch. The on-demand half is NOT
17607
+ * retained: step 3 sends the table-level ceilings and step 6 the per-index
17608
+ * ones under exactly this mode.
17609
+ *
17610
+ * One residual is deliberately NOT covered, because the suppression did not
17611
+ * create it: the TABLE-level provisioned capacity NUMBER rides step 4's flip
17612
+ * and nothing else, so on ANY non-flip PROVISIONED -> PROVISIONED update it is
17613
+ * unsent while its `*CapacityAutoScalingSettings` sibling in the same block IS
17614
+ * reconciled. Retaining the block wholesale under a kept PROVISIONED mode would
17615
+ * therefore erase a real auto-scaling update to hide a pre-existing gap — so
17616
+ * the block stays as declared and the gap stays where it already lives.
17617
+ *
17618
+ * Retaining rather than DROPPING is the UPDATE row of
17619
+ * `.claude/rules/providers.md`: the call never ran, so AWS still holds the
17620
+ * previously-applied block and that IS what state should describe. Dropping
17621
+ * would leave a later template that REMOVES the block deriving no removal, so
17622
+ * the live setting would survive forever.
17623
+ *
17624
+ * **The previous side is VALIDATED before it is retained** (the #1653-review
17625
+ * rule) through `asRecord` — the SAME predicate every wire read of these blocks
17626
+ * applies, so the two cannot disagree about what a bare string / an array / a
17627
+ * number means. Be honest about what that buys: it refuses exactly the
17628
+ * not-a-plain-object shapes, and a block whose NUMERIC member is an unresolved
17629
+ * intrinsic passes it, because the wire accepts that block too (and then sends
17630
+ * nothing for the member, which is the same "AWS keeps what it had" outcome).
17631
+ * When the previous side is unusable OR absent the key is DROPPED — there is no
17632
+ * value cdkd can vouch for either way.
17633
+ *
17634
+ * COPIES each retained block one level rather than aliasing it: the rollback
17635
+ * executor spreads the returned bag shallowly, so handing back the previous
17636
+ * record's own object would leave two state records sharing one mutable value.
17637
+ * Scope that claim honestly — it covers the retained blocks only; every other
17638
+ * key of the input bag stays aliased, exactly as the sibling arms leave it.
17639
+ *
17640
+ * Deliberately NOT paired with a `canonicalizeDesiredProperties` twin: this is
17641
+ * a SKIP, not a narrowing, so there is no pure function of the desired bag to
17642
+ * fold both comparison sides with, and folding one would derive a REMOVAL of a
17643
+ * live capacity block from a template whose only fault is `BillingMode`.
17644
+ *
17645
+ * Pure and non-mutating at every level.
17646
+ */
17647
+ function retainUnsendableCapacityMembers(desired, previous, keptBillingMode) {
17648
+ const unsendable = keptBillingMode === "PROVISIONED" ? ON_DEMAND_ONLY_CAPACITY_KEYS : PROVISIONED_ONLY_CAPACITY_KEYS;
17649
+ const result = retainCapacityKeys({ ...desired }, previous, unsendable.table);
17650
+ const indexes = result["GlobalSecondaryIndexes"];
17651
+ if (Array.isArray(indexes)) {
17652
+ const previousIndexes = indexCapacityContainers(previous["GlobalSecondaryIndexes"], "IndexName");
17653
+ result["GlobalSecondaryIndexes"] = indexes.map((entry) => {
17654
+ const gsi = asRecord$1(entry);
17655
+ if (!gsi) return entry;
17656
+ const previousGsi = previousIndexes.get(gsi["IndexName"]);
17657
+ return retainCapacityKeys({ ...gsi }, previousGsi, unsendable.index);
17658
+ });
17659
+ }
17660
+ const replicas = result["Replicas"];
17661
+ if (Array.isArray(replicas)) {
17662
+ const previousReplicas = indexCapacityContainers(previous["Replicas"], "Region");
17663
+ result["Replicas"] = replicas.map((entry) => {
17664
+ const replica = asRecord$1(entry);
17665
+ if (!replica) return entry;
17666
+ const previousReplica = previousReplicas.get(replica["Region"]);
17667
+ const copy = retainCapacityKeys({ ...replica }, previousReplica, unsendable.replica);
17668
+ const replicaIndexes = copy["GlobalSecondaryIndexes"];
17669
+ if (Array.isArray(replicaIndexes)) {
17670
+ const previousReplicaIndexes = indexCapacityContainers(previousReplica?.["GlobalSecondaryIndexes"], "IndexName");
17671
+ const kept = replicaIndexes.map((indexEntry) => {
17672
+ const gsi = asRecord$1(indexEntry);
17673
+ if (!gsi) return indexEntry;
17674
+ const previousGsi = previousReplicaIndexes.get(gsi["IndexName"]);
17675
+ return retainCapacityKeys({ ...gsi }, previousGsi, unsendable.replicaIndex);
17676
+ }).filter((entry) => {
17677
+ const gsi = asRecord$1(entry);
17678
+ if (!gsi) return true;
17679
+ return Object.keys(gsi).some((k) => k !== "IndexName");
17680
+ });
17681
+ if (kept.length > 0) copy["GlobalSecondaryIndexes"] = kept;
17682
+ else delete copy["GlobalSecondaryIndexes"];
17683
+ }
17684
+ return copy;
17685
+ });
17686
+ }
17687
+ return result;
17688
+ }
17689
+ /**
17690
+ * Retain (or drop) one container's unsendable capacity members, in place on a
17691
+ * bag the caller already copied.
17692
+ *
17693
+ * The counterpart container being `undefined` — no matching index / replica in
17694
+ * the previous record — is the ABSENT case, not a special one: there is nothing
17695
+ * to vouch for, so the key is dropped exactly as it is for an unusable value.
17696
+ */
17697
+ function retainCapacityKeys(target, previousContainer, keys) {
17698
+ for (const key of keys) {
17699
+ const previousValue = asRecord$1(previousContainer?.[key]);
17700
+ if (previousValue) target[key] = { ...previousValue };
17701
+ else delete target[key];
17702
+ }
17703
+ return target;
17704
+ }
17705
+ /**
17706
+ * Index a previous-side array by its identity member, so a per-index /
17707
+ * per-replica retain reads the counterpart entry rather than the positional
17708
+ * one — AWS does not guarantee readback order and a template edit can reorder
17709
+ * either list.
17710
+ */
17711
+ function indexCapacityContainers(value, identityKey) {
17712
+ const byIdentity = /* @__PURE__ */ new Map();
17713
+ if (!Array.isArray(value)) return byIdentity;
17714
+ for (const entry of value) {
17715
+ const record = asRecord$1(entry);
17716
+ const identity = record?.[identityKey];
17717
+ if (record && typeof identity === "string") byIdentity.set(identity, record);
17718
+ }
17719
+ return byIdentity;
17720
+ }
17721
+ /**
17536
17722
  * True when a CFn sub-object is nothing but an unresolved intrinsic
17537
17723
  * (`{"Fn::If": […]}` / `{"Ref": …}`), i.e. the template DID declare the block
17538
17724
  * but its value could not be resolved to a shape with members.
@@ -76252,7 +76438,7 @@ function createMigrateCommand() {
76252
76438
  */
76253
76439
  function buildProgram() {
76254
76440
  const program = new Command();
76255
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.283.0");
76441
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.283.1");
76256
76442
  program.hook("preAction", (_thisCommand, actionCommand) => {
76257
76443
  const { profile } = actionCommand.optsWithGlobals();
76258
76444
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;