@go-to-k/cdkd 0.278.11 → 0.278.13
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/{asg-provider-DW0eC_5t.js → asg-provider-QQOSO3LR.js} +2 -2
- package/dist/{asg-provider-DW0eC_5t.js.map → asg-provider-QQOSO3LR.js.map} +1 -1
- package/dist/cli.js +353 -43
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-DrlCNItN.js → deploy-engine-BpbIYUuG.js} +3 -3
- package/dist/{deploy-engine-DrlCNItN.js.map → deploy-engine-BpbIYUuG.js.map} +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as DagBuilder, A as red, At as resolveApp, B as isTerminationProtectionPropagationError, Bt as CFN_TEMPLATE_URL_LIMIT, C as isStatefulRecreateTargetSync, Ct as runDockerStreaming, D as cyan, Dt as synthesisStatusMessage, E as bold, Et as Synthesizer, F as ProviderRegistry, Ft as resolveStateBucketWithDefaultAndSource, G as normalizeAwsTagsToCfn, Gt as AssemblyReader, H as cfnRefValueFromPhysicalId, Ht as findLargeInlineResources, I as findActionableSilentDrops, It as resolveUseCdkBootstrapAssets, J as applyRoleArnIfSet, Jt as resolveBucketRegion, K as resolveExplicitPhysicalId, Kt as processStackMessages, L as CloudControlProvider, Lt as stateBucketExistenceConfirmed, M as IAMRoleProvider, Mt as resolveCaptureObservedState, N as collectInlinePolicyNamesManagedBySiblings, Nt as resolveSkipPrefix, O as gray, Ot as getDefaultStateBucketName, P as clearOnUpdateRemoval, Pt as resolveStateBucketWithDefault, Q as isRetryableTransientError, Qt as setAwsClients, R as slowCcOperationTimeoutMs, Rt as warnDeprecatedNoPrefixCliFlag, S as MULTI_REGION_RECREATE_BLOCKED_TYPES, St as runDockerForeground, T as formatResourceLine, Tt as getDockerImageBySourceHash, U as refStateLookupFromResource, Ut as uploadCfnTemplate, V as IntrinsicFunctionResolver, Vt as MIGRATE_TMP_PREFIX, W as WAFv2WebACLProvider, Wt as expectedOwnerParam, X as describeTypeWithThrottleRetry, Xt as getAwsClients, Y as DiffCalculator, Yt as AwsClients, Z as withRetry, Zt as resetAwsClients, _ as createPreDeleteFinalSnapshot, _t as validateAssetBucketName, a as DeploymentEventsStore, an as LocalMigrateError, at as AssetPublisher, b as unsupportedFinalSnapshotError, bn as normalizeAwsError, bt as formatDockerLoginError, c as replayFailedOperations, cn as MissingCdkCliError, ct as buildAssetRedirectMap, d as IMPLICIT_DELETE_DEPENDENCIES, dn as ProvisioningError, dt as rewriteTemplateAssetReferences, en as CdkdError, et as TemplateParser, f as computeImplicitDeleteEdges, fn as ResourceTimeoutError, ft as AssetModeResolver, g as ccRoutedFinalSnapshotError, gt as parseBootstrapMarker, h as buildFinalSnapshotIdentifier, hn as StackTerminationProtectionError, ht as getBootstrapMarkerKey, i as DeploymentEventsReader, in as LocalInvokeBuildError$1, it as shouldRetainResource, j as yellow, jt as resolveAutoAssetStorage, k as green, kt as getLegacyStateBucketName, l as replayRollback, ln as NestedStackChildDirectDestroyError, lt as createAssetRedirectResolver, m as PRE_DELETE_SNAPSHOT_TYPES, mn as StackHasActiveImportsError, mt as ensureAssetStorage, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as S3StateBackend, o as planFailedOps, on as LocalStartServiceError, ot as stringifyValue, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as ResourceUpdateNotSupportedError, pt as BOOTSTRAP_MARKER_PREFIX, q as assertRegionMatch, r as DeployEngine, rn as DeployCancelledError, rt as rebuildClientForBucketRegion, s as planRollback, st as WorkGraph, t as DEFAULT_RESOURCE_TIMEOUT_MS, tt as LockManager, u as withResourceDeadline, un as PartialFailureError, ut as loadPublishableAssetManifest, v as isFinalSnapshotError, vt as validateContainerRepoName, w as renderStatefulReason, wt as AssetManifestLoader, x as extractDeploymentEventError, xn as withErrorHandling, xt as getDockerCmd, y as refusesFinalSnapshot, yt as buildDockerImage, z as disableInstanceApiTermination, zt as CFN_TEMPLATE_BODY_LIMIT } from "./deploy-engine-
|
|
2
|
+
import { $ as DagBuilder, A as red, At as resolveApp, B as isTerminationProtectionPropagationError, Bt as CFN_TEMPLATE_URL_LIMIT, C as isStatefulRecreateTargetSync, Ct as runDockerStreaming, D as cyan, Dt as synthesisStatusMessage, E as bold, Et as Synthesizer, F as ProviderRegistry, Ft as resolveStateBucketWithDefaultAndSource, G as normalizeAwsTagsToCfn, Gt as AssemblyReader, H as cfnRefValueFromPhysicalId, Ht as findLargeInlineResources, I as findActionableSilentDrops, It as resolveUseCdkBootstrapAssets, J as applyRoleArnIfSet, Jt as resolveBucketRegion, K as resolveExplicitPhysicalId, Kt as processStackMessages, L as CloudControlProvider, Lt as stateBucketExistenceConfirmed, M as IAMRoleProvider, Mt as resolveCaptureObservedState, N as collectInlinePolicyNamesManagedBySiblings, Nt as resolveSkipPrefix, O as gray, Ot as getDefaultStateBucketName, P as clearOnUpdateRemoval, Pt as resolveStateBucketWithDefault, Q as isRetryableTransientError, Qt as setAwsClients, R as slowCcOperationTimeoutMs, Rt as warnDeprecatedNoPrefixCliFlag, S as MULTI_REGION_RECREATE_BLOCKED_TYPES, St as runDockerForeground, T as formatResourceLine, Tt as getDockerImageBySourceHash, U as refStateLookupFromResource, Ut as uploadCfnTemplate, V as IntrinsicFunctionResolver, Vt as MIGRATE_TMP_PREFIX, W as WAFv2WebACLProvider, Wt as expectedOwnerParam, X as describeTypeWithThrottleRetry, Xt as getAwsClients, Y as DiffCalculator, Yt as AwsClients, Z as withRetry, Zt as resetAwsClients, _ as createPreDeleteFinalSnapshot, _t as validateAssetBucketName, a as DeploymentEventsStore, an as LocalMigrateError, at as AssetPublisher, b as unsupportedFinalSnapshotError, bn as normalizeAwsError, bt as formatDockerLoginError, c as replayFailedOperations, cn as MissingCdkCliError, ct as buildAssetRedirectMap, d as IMPLICIT_DELETE_DEPENDENCIES, dn as ProvisioningError, dt as rewriteTemplateAssetReferences, en as CdkdError, et as TemplateParser, f as computeImplicitDeleteEdges, fn as ResourceTimeoutError, ft as AssetModeResolver, g as ccRoutedFinalSnapshotError, gt as parseBootstrapMarker, h as buildFinalSnapshotIdentifier, hn as StackTerminationProtectionError, ht as getBootstrapMarkerKey, i as DeploymentEventsReader, in as LocalInvokeBuildError$1, it as shouldRetainResource, j as yellow, jt as resolveAutoAssetStorage, k as green, kt as getLegacyStateBucketName, l as replayRollback, ln as NestedStackChildDirectDestroyError, lt as createAssetRedirectResolver, m as PRE_DELETE_SNAPSHOT_TYPES, mn as StackHasActiveImportsError, mt as ensureAssetStorage, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as S3StateBackend, o as planFailedOps, on as LocalStartServiceError, ot as stringifyValue, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as ResourceUpdateNotSupportedError, pt as BOOTSTRAP_MARKER_PREFIX, q as assertRegionMatch, r as DeployEngine, rn as DeployCancelledError, rt as rebuildClientForBucketRegion, s as planRollback, st as WorkGraph, t as DEFAULT_RESOURCE_TIMEOUT_MS, tt as LockManager, u as withResourceDeadline, un as PartialFailureError, ut as loadPublishableAssetManifest, v as isFinalSnapshotError, vt as validateContainerRepoName, w as renderStatefulReason, wt as AssetManifestLoader, x as extractDeploymentEventError, xn as withErrorHandling, xt as getDockerCmd, y as refusesFinalSnapshot, yt as buildDockerImage, z as disableInstanceApiTermination, zt as CFN_TEMPLATE_BODY_LIMIT } from "./deploy-engine-BpbIYUuG.js";
|
|
3
3
|
import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as withSkipPrefix, i as runStackBuffered, n as getLogger, o as PATTERN_B_NAME_OPTIONS, p as withStackName, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-BYMEE-BS.js";
|
|
4
|
-
import { t as ASGProvider } from "./asg-provider-
|
|
4
|
+
import { t as ASGProvider } from "./asg-provider-QQOSO3LR.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, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, 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";
|
|
@@ -4813,6 +4813,52 @@ function isTruthyCfnBoolean(value) {
|
|
|
4813
4813
|
//#endregion
|
|
4814
4814
|
//#region src/provisioning/providers/s3-bucket-provider.ts
|
|
4815
4815
|
/**
|
|
4816
|
+
* A plain (non-array) object. `typeof x === 'object'` alone accepts arrays and
|
|
4817
|
+
* `null`; a `Transition: []` or an unresolved intrinsic pushed through as a
|
|
4818
|
+
* single transition entry makes S3 answer `MalformedXML` for the WHOLE
|
|
4819
|
+
* lifecycle configuration, so the legacy singular readers screen with this.
|
|
4820
|
+
*/
|
|
4821
|
+
function isPlainObject$1(value) {
|
|
4822
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4823
|
+
}
|
|
4824
|
+
/**
|
|
4825
|
+
* Coerce a CFn numeric to a finite number. CloudFormation is stringly typed —
|
|
4826
|
+
* a hand-written or imported template (the audience the legacy lifecycle
|
|
4827
|
+
* branches exist for) can carry `"365"` where the schema says number.
|
|
4828
|
+
*/
|
|
4829
|
+
function coerceCfnNumber(value) {
|
|
4830
|
+
if (typeof value !== "number" && typeof value !== "string") return void 0;
|
|
4831
|
+
if (value === "") return void 0;
|
|
4832
|
+
const n = Number(value);
|
|
4833
|
+
return Number.isFinite(n) ? n : void 0;
|
|
4834
|
+
}
|
|
4835
|
+
/**
|
|
4836
|
+
* Merge a legacy SINGULAR action object into its modern plural array.
|
|
4837
|
+
*
|
|
4838
|
+
* S3 rejects two transitions with the same `StorageClass` and fails the whole
|
|
4839
|
+
* `PutBucketLifecycleConfiguration`, so a blind concatenation is unsafe. But
|
|
4840
|
+
* dropping the singular wholesale loses a legitimate template: a plural
|
|
4841
|
+
* `[{GLACIER, 30}]` alongside a singular `{DEEP_ARCHIVE, 90}` is two different
|
|
4842
|
+
* classes, which S3 accepts. So: keep both, let the PLURAL win on a
|
|
4843
|
+
* StorageClass collision, and say so rather than dropping in silence.
|
|
4844
|
+
*/
|
|
4845
|
+
function mergeLegacySingular(plural, singular, onCollision) {
|
|
4846
|
+
const out = (Array.isArray(plural) ? plural : []).filter(isPlainObject$1);
|
|
4847
|
+
if (!isPlainObject$1(singular)) return out;
|
|
4848
|
+
const sc = singular["StorageClass"];
|
|
4849
|
+
if (typeof sc === "string" && out.some((e) => e["StorageClass"] === sc)) {
|
|
4850
|
+
onCollision(sc);
|
|
4851
|
+
return out;
|
|
4852
|
+
}
|
|
4853
|
+
return [...out, singular];
|
|
4854
|
+
}
|
|
4855
|
+
/** Coerce a CFn boolean, which may arrive as the string `"true"` / `"false"`. */
|
|
4856
|
+
function coerceCfnBoolean(value) {
|
|
4857
|
+
if (typeof value === "boolean") return value;
|
|
4858
|
+
if (value === "true") return true;
|
|
4859
|
+
if (value === "false") return false;
|
|
4860
|
+
}
|
|
4861
|
+
/**
|
|
4816
4862
|
* SDK Provider for AWS::S3::Bucket
|
|
4817
4863
|
*
|
|
4818
4864
|
* Uses S3 SDK directly instead of CC API for synchronous bucket creation.
|
|
@@ -4982,7 +5028,7 @@ var S3BucketProvider = class {
|
|
|
4982
5028
|
const filter = rule["Filter"];
|
|
4983
5029
|
return {
|
|
4984
5030
|
prefix: filter?.["Prefix"] ?? rule["Prefix"],
|
|
4985
|
-
tagFilters: filter?.["TagFilters"],
|
|
5031
|
+
tagFilters: filter?.["TagFilters"] ?? rule["TagFilters"],
|
|
4986
5032
|
sizeGt: filter?.["ObjectSizeGreaterThan"] ?? rule["ObjectSizeGreaterThan"],
|
|
4987
5033
|
sizeLt: filter?.["ObjectSizeLessThan"] ?? rule["ObjectSizeLessThan"]
|
|
4988
5034
|
};
|
|
@@ -5010,24 +5056,37 @@ var S3BucketProvider = class {
|
|
|
5010
5056
|
ExpiredObjectDeleteMarker: exp["ExpiredObjectDeleteMarker"]
|
|
5011
5057
|
};
|
|
5012
5058
|
}
|
|
5013
|
-
|
|
5059
|
+
if (coerceCfnBoolean(rule["ExpiredObjectDeleteMarker"]) === true) {
|
|
5060
|
+
const exp = sdkRule.Expiration;
|
|
5061
|
+
if (!(exp?.["Days"] !== void 0 || exp?.["Date"] !== void 0)) sdkRule.Expiration = { ExpiredObjectDeleteMarker: true };
|
|
5062
|
+
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.`);
|
|
5063
|
+
}
|
|
5064
|
+
const nve = isPlainObject$1(rule["NoncurrentVersionExpiration"]) ? rule["NoncurrentVersionExpiration"] : void 0;
|
|
5065
|
+
const legacyNveDays = rule["NoncurrentVersionExpirationInDays"];
|
|
5014
5066
|
if (nve) sdkRule.NoncurrentVersionExpiration = {
|
|
5015
5067
|
NoncurrentDays: nve["NoncurrentDays"],
|
|
5016
5068
|
NewerNoncurrentVersions: nve["NewerNoncurrentVersions"]
|
|
5017
5069
|
};
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
NoncurrentDays: nvt["NoncurrentDays"],
|
|
5070
|
+
else if (coerceCfnNumber(legacyNveDays) !== void 0) sdkRule.NoncurrentVersionExpiration = { NoncurrentDays: coerceCfnNumber(legacyNveDays) };
|
|
5071
|
+
const toSdkNvt = (nvt) => ({
|
|
5072
|
+
NoncurrentDays: nvt["TransitionInDays"] ?? nvt["NoncurrentDays"],
|
|
5021
5073
|
StorageClass: nvt["StorageClass"],
|
|
5022
5074
|
NewerNoncurrentVersions: nvt["NewerNoncurrentVersions"]
|
|
5023
|
-
})
|
|
5024
|
-
const
|
|
5025
|
-
|
|
5075
|
+
});
|
|
5076
|
+
const nvts = rule["NoncurrentVersionTransitions"];
|
|
5077
|
+
const singularNvt = rule["NoncurrentVersionTransition"];
|
|
5078
|
+
const allNvts = mergeLegacySingular(nvts, singularNvt, (sc) => this.logger.warn(`Lifecycle rule '${rule["Id"] ?? "<unnamed>"}' on ${bucketName} declares both NoncurrentVersionTransitions and the legacy NoncurrentVersionTransition for storage class ${sc}; S3 rejects duplicates, so the legacy singular was ignored.`));
|
|
5079
|
+
if (allNvts.length > 0) sdkRule.NoncurrentVersionTransitions = allNvts.map(toSdkNvt);
|
|
5080
|
+
const toSdkTransition = (t) => ({
|
|
5026
5081
|
Days: t["TransitionInDays"] ?? t["Days"],
|
|
5027
5082
|
Date: t["TransitionDate"] ?? t["Date"] ? new Date(t["TransitionDate"] ?? t["Date"]) : void 0,
|
|
5028
5083
|
StorageClass: t["StorageClass"]
|
|
5029
|
-
})
|
|
5030
|
-
const
|
|
5084
|
+
});
|
|
5085
|
+
const transitions = rule["Transitions"];
|
|
5086
|
+
const singularTransition = rule["Transition"];
|
|
5087
|
+
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.`));
|
|
5088
|
+
if (allTransitions.length > 0) sdkRule.Transitions = allTransitions.map(toSdkTransition);
|
|
5089
|
+
const abort = isPlainObject$1(rule["AbortIncompleteMultipartUpload"]) ? rule["AbortIncompleteMultipartUpload"] : void 0;
|
|
5031
5090
|
if (abort) sdkRule.AbortIncompleteMultipartUpload = { DaysAfterInitiation: abort["DaysAfterInitiation"] };
|
|
5032
5091
|
const { prefix, tagFilters, sizeGt, sizeLt } = gatherScope(rule);
|
|
5033
5092
|
const hasTags = tagFilters !== void 0 && tagFilters.length > 0;
|
|
@@ -5037,6 +5096,7 @@ var S3BucketProvider = class {
|
|
|
5037
5096
|
ObjectSizeGreaterThan: sizeGt,
|
|
5038
5097
|
ObjectSizeLessThan: sizeLt
|
|
5039
5098
|
} };
|
|
5099
|
+
else if (hasTags && tagFilters.length > 1) sdkRule.Filter = { And: { Tags: tagFilters } };
|
|
5040
5100
|
else if (hasTags) sdkRule.Filter = { Tag: tagFilters[0] };
|
|
5041
5101
|
else if (sizeGt !== void 0) sdkRule.Filter = { ObjectSizeGreaterThan: sizeGt };
|
|
5042
5102
|
else if (sizeLt !== void 0) sdkRule.Filter = { ObjectSizeLessThan: sizeLt };
|
|
@@ -5872,7 +5932,7 @@ var S3BucketProvider = class {
|
|
|
5872
5932
|
}
|
|
5873
5933
|
if (r.NoncurrentVersionTransitions && r.NoncurrentVersionTransitions.length > 0) out["NoncurrentVersionTransitions"] = r.NoncurrentVersionTransitions.map((nvt) => {
|
|
5874
5934
|
const item = {};
|
|
5875
|
-
if (nvt.NoncurrentDays !== void 0) item["
|
|
5935
|
+
if (nvt.NoncurrentDays !== void 0) item["TransitionInDays"] = nvt.NoncurrentDays;
|
|
5876
5936
|
if (nvt.StorageClass !== void 0) item["StorageClass"] = nvt.StorageClass;
|
|
5877
5937
|
if (nvt.NewerNoncurrentVersions !== void 0) item["NewerNoncurrentVersions"] = nvt.NewerNoncurrentVersions;
|
|
5878
5938
|
return item;
|
|
@@ -11948,10 +12008,15 @@ var DynamoDBTableProvider = class {
|
|
|
11948
12008
|
* - `update()` covers every mutable surface — Tags, DeletionProtection,
|
|
11949
12009
|
* TableClass, SSE, StreamSpec, OnDemand throughput, BillingMode flip,
|
|
11950
12010
|
* Replica add / remove / modify, GSI add / remove / modify, TTL toggle.
|
|
11951
|
-
* - The serialization is load-bearing: AWS's `UpdateTable`
|
|
11952
|
-
*
|
|
11953
|
-
*
|
|
11954
|
-
*
|
|
12011
|
+
* - The serialization is load-bearing: AWS's `UpdateTable` does not accept
|
|
12012
|
+
* `ReplicaUpdates` alongside `BillingMode` / `GlobalSecondaryIndexUpdates`,
|
|
12013
|
+
* so each category is its own SDK round-trip with a wait-for-ACTIVE in
|
|
12014
|
+
* between. `BillingMode` and `GlobalSecondaryIndexUpdates` DO combine, and
|
|
12015
|
+
* only in the `PAY_PER_REQUEST -> PROVISIONED` flip, where AWS REQUIRES
|
|
12016
|
+
* per-GSI `ProvisionedThroughput` in the SAME call as `BillingMode` ("you
|
|
12017
|
+
* must specify read and write capacity unit values for the table and for
|
|
12018
|
+
* each global secondary index") — so that path deliberately sends both
|
|
12019
|
+
* together (Issue #1387). Immutable property changes (TableName, KeySchema,
|
|
11955
12020
|
* AttributeDefinitions removal, LocalSecondaryIndexes) throw
|
|
11956
12021
|
* `ProvisioningError` naming the offending field — the deploy engine's
|
|
11957
12022
|
* diff classification should catch these as REPLACEMENT before ever
|
|
@@ -12146,7 +12211,13 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12146
12211
|
StreamViewType: "NEW_AND_OLD_IMAGES"
|
|
12147
12212
|
};
|
|
12148
12213
|
}
|
|
12149
|
-
|
|
12214
|
+
let sdkIndexes;
|
|
12215
|
+
try {
|
|
12216
|
+
sdkIndexes = toSdkGlobalSecondaryIndexes(properties, currentRegion, billingMode);
|
|
12217
|
+
} catch (error) {
|
|
12218
|
+
throw new ProvisioningError(error instanceof Error ? error.message : String(error), resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
|
|
12219
|
+
}
|
|
12220
|
+
if (sdkIndexes.length > 0) createParams.GlobalSecondaryIndexes = sdkIndexes;
|
|
12150
12221
|
if (properties["LocalSecondaryIndexes"]) createParams.LocalSecondaryIndexes = properties["LocalSecondaryIndexes"];
|
|
12151
12222
|
if (properties["SSESpecification"]) {
|
|
12152
12223
|
const sse = properties["SSESpecification"];
|
|
@@ -12237,11 +12308,26 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12237
12308
|
* `DescribeTable` until the replica's `ReplicaStatus` flips to ACTIVE.
|
|
12238
12309
|
* Capped at 10 minutes per replica (AWS Replica provisioning typically
|
|
12239
12310
|
* takes 1–5 min).
|
|
12311
|
+
*
|
|
12312
|
+
* DELIBERATELY UNMAPPED replica sub-keys (Issue #1387 — recorded rather
|
|
12313
|
+
* than silently dropped; `CreateReplicationGroupMemberAction` simply has
|
|
12314
|
+
* no member for them, so they need their own follow-up API calls):
|
|
12315
|
+
* - `ReplicaStreamSpecification.ResourcePolicy` — the DynamoDB Streams
|
|
12316
|
+
* resource policy is set by `PutResourcePolicy` against the replica's
|
|
12317
|
+
* STREAM ARN, not by any `UpdateTable` field.
|
|
12318
|
+
* - `ResourcePolicy` — the table-level resource policy, likewise a
|
|
12319
|
+
* separate `PutResourcePolicy` call.
|
|
12320
|
+
* - `GlobalSecondaryIndexes[].ContributorInsightsSpecification` — a
|
|
12321
|
+
* per-index `UpdateContributorInsights` call.
|
|
12322
|
+
* `Replicas` is declared in `handledProperties` at the TOP level, which
|
|
12323
|
+
* is the granularity cdkd's pre-flight property-coverage check works at;
|
|
12324
|
+
* these nested keys are tracked as a known gap, not a supported surface.
|
|
12240
12325
|
*/
|
|
12241
12326
|
async addReplica(tableName, replica, region, logicalId) {
|
|
12242
12327
|
const create = { RegionName: region };
|
|
12243
12328
|
if (replica["KMSMasterKeyId"]) create.KMSMasterKeyId = replica["KMSMasterKeyId"];
|
|
12244
|
-
|
|
12329
|
+
const replicaIndexes = toSdkReplicaGlobalSecondaryIndexes(replica["GlobalSecondaryIndexes"]);
|
|
12330
|
+
if (replicaIndexes) create.GlobalSecondaryIndexes = replicaIndexes;
|
|
12245
12331
|
if (replica["TableClassOverride"]) create.TableClassOverride = replica["TableClassOverride"];
|
|
12246
12332
|
const replicaUpdates = [{ Create: create }];
|
|
12247
12333
|
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
@@ -12253,10 +12339,14 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12253
12339
|
/**
|
|
12254
12340
|
* Update a DynamoDB Global Table in place.
|
|
12255
12341
|
*
|
|
12256
|
-
* AWS-side state-machine constraint: `UpdateTable`
|
|
12257
|
-
* `
|
|
12342
|
+
* AWS-side state-machine constraint: `UpdateTable` does not accept
|
|
12343
|
+
* `ReplicaUpdates` alongside `BillingMode` / `GlobalSecondaryIndexUpdates`,
|
|
12258
12344
|
* so each category must serialize into its own SDK round-trip with a
|
|
12259
|
-
* `waitForTableActiveAfterUpdate` between every step.
|
|
12345
|
+
* `waitForTableActiveAfterUpdate` between every step. `BillingMode` and
|
|
12346
|
+
* `GlobalSecondaryIndexUpdates` DO combine, and only in step 4's
|
|
12347
|
+
* `PAY_PER_REQUEST -> PROVISIONED` flip, which AWS requires to carry
|
|
12348
|
+
* per-GSI `ProvisionedThroughput` in the same call (Issue #1387).
|
|
12349
|
+
* Order:
|
|
12260
12350
|
* 1. Wait for current ACTIVE (defensive).
|
|
12261
12351
|
* 2. Tags diff (TagResource / UntagResource — no wait needed).
|
|
12262
12352
|
* 3. Non-conflicting flat fields (DeletionProtectionEnabled / TableClass
|
|
@@ -12335,12 +12425,41 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12335
12425
|
}
|
|
12336
12426
|
const oldBilling = previousProperties["BillingMode"] ?? "PAY_PER_REQUEST";
|
|
12337
12427
|
const newBilling = properties["BillingMode"] ?? "PAY_PER_REQUEST";
|
|
12428
|
+
const gsiHandledByBillingFlip = /* @__PURE__ */ new Set();
|
|
12338
12429
|
if (oldBilling !== newBilling) {
|
|
12339
12430
|
const billingUpdate = {
|
|
12340
12431
|
TableName: physicalId,
|
|
12341
12432
|
BillingMode: newBilling
|
|
12342
12433
|
};
|
|
12343
|
-
if (newBilling === "PROVISIONED")
|
|
12434
|
+
if (newBilling === "PROVISIONED") {
|
|
12435
|
+
billingUpdate.ProvisionedThroughput = derivePerCallProvisionedThroughput(properties, currentRegion);
|
|
12436
|
+
const provisionedIndexes = toSdkGlobalSecondaryIndexes(properties, currentRegion, newBilling);
|
|
12437
|
+
const previousCfnIndexes = previousProperties["GlobalSecondaryIndexes"];
|
|
12438
|
+
const existingIndexNames = new Set((Array.isArray(previousCfnIndexes) ? previousCfnIndexes : []).map((entry) => entry?.["IndexName"]).filter((name) => typeof name === "string"));
|
|
12439
|
+
const previousByIndexName = /* @__PURE__ */ new Map();
|
|
12440
|
+
for (const gsi of toSdkGlobalSecondaryIndexes(previousProperties, currentRegion, newBilling)) if (gsi.IndexName) previousByIndexName.set(gsi.IndexName, gsi);
|
|
12441
|
+
const byIndexName = new Map(previousByIndexName);
|
|
12442
|
+
const survivingIndexNames = /* @__PURE__ */ new Set();
|
|
12443
|
+
for (const gsi of provisionedIndexes) {
|
|
12444
|
+
if (!gsi.IndexName) continue;
|
|
12445
|
+
survivingIndexNames.add(gsi.IndexName);
|
|
12446
|
+
byIndexName.set(gsi.IndexName, gsi);
|
|
12447
|
+
}
|
|
12448
|
+
const indexUpdates = [];
|
|
12449
|
+
for (const indexName of existingIndexNames) {
|
|
12450
|
+
const gsi = byIndexName.get(indexName);
|
|
12451
|
+
if (!gsi?.ProvisionedThroughput) continue;
|
|
12452
|
+
const previousWarm = previousByIndexName.get(indexName)?.WarmThroughput;
|
|
12453
|
+
const warmChanged = gsi.WarmThroughput !== void 0 && !deepEqual$1(gsi.WarmThroughput, previousWarm);
|
|
12454
|
+
indexUpdates.push({ Update: {
|
|
12455
|
+
IndexName: indexName,
|
|
12456
|
+
ProvisionedThroughput: gsi.ProvisionedThroughput,
|
|
12457
|
+
...warmChanged && { WarmThroughput: gsi.WarmThroughput }
|
|
12458
|
+
} });
|
|
12459
|
+
if (survivingIndexNames.has(indexName)) gsiHandledByBillingFlip.add(indexName);
|
|
12460
|
+
}
|
|
12461
|
+
if (indexUpdates.length > 0) billingUpdate.GlobalSecondaryIndexUpdates = indexUpdates;
|
|
12462
|
+
}
|
|
12344
12463
|
await this.dynamoDBClient.send(new UpdateTableCommand(billingUpdate));
|
|
12345
12464
|
await this.waitForTableActiveAfterUpdate(physicalId, logicalId);
|
|
12346
12465
|
}
|
|
@@ -12391,7 +12510,8 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12391
12510
|
}
|
|
12392
12511
|
const updateAction = { RegionName: region };
|
|
12393
12512
|
if (replica["KMSMasterKeyId"] !== void 0) updateAction.KMSMasterKeyId = replica["KMSMasterKeyId"];
|
|
12394
|
-
|
|
12513
|
+
const replicaIndexes = toSdkReplicaGlobalSecondaryIndexes(replica["GlobalSecondaryIndexes"]);
|
|
12514
|
+
if (replicaIndexes) updateAction.GlobalSecondaryIndexes = replicaIndexes;
|
|
12395
12515
|
if (replica["TableClassOverride"]) updateAction.TableClassOverride = replica["TableClassOverride"];
|
|
12396
12516
|
if (!(updateAction.KMSMasterKeyId !== void 0 || updateAction.GlobalSecondaryIndexes !== void 0 || updateAction.TableClassOverride !== void 0)) {
|
|
12397
12517
|
this.logger.debug(`Cross-region replica ${region} of ${physicalId}: only Tags-style changes detected; UpdateReplica skipped (AWS rejects empty Update actions). Tags propagation handled above via per-region client.`);
|
|
@@ -12403,7 +12523,10 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12403
12523
|
}));
|
|
12404
12524
|
await this.waitForReplicaActive(physicalId, region, logicalId);
|
|
12405
12525
|
}
|
|
12406
|
-
const
|
|
12526
|
+
const previousSdkIndexes = toSdkGlobalSecondaryIndexes(previousProperties, currentRegion, oldBilling);
|
|
12527
|
+
const gsiDiff = diffGlobalSecondaryIndexes(previousSdkIndexes, toSdkGlobalSecondaryIndexes(properties, currentRegion, newBilling));
|
|
12528
|
+
const previousSdkByName = /* @__PURE__ */ new Map();
|
|
12529
|
+
for (const prev of previousSdkIndexes) if (prev.IndexName) previousSdkByName.set(prev.IndexName, prev);
|
|
12407
12530
|
for (const gsi of gsiDiff.removed) {
|
|
12408
12531
|
if (!gsi.IndexName) continue;
|
|
12409
12532
|
const gsiUpdate = { Delete: { IndexName: gsi.IndexName } };
|
|
@@ -12420,7 +12543,8 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12420
12543
|
KeySchema: gsi.KeySchema,
|
|
12421
12544
|
Projection: gsi.Projection,
|
|
12422
12545
|
...gsi.ProvisionedThroughput && { ProvisionedThroughput: gsi.ProvisionedThroughput },
|
|
12423
|
-
...gsi.OnDemandThroughput && { OnDemandThroughput: gsi.OnDemandThroughput }
|
|
12546
|
+
...gsi.OnDemandThroughput && { OnDemandThroughput: gsi.OnDemandThroughput },
|
|
12547
|
+
...gsi.WarmThroughput && { WarmThroughput: gsi.WarmThroughput }
|
|
12424
12548
|
} };
|
|
12425
12549
|
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
12426
12550
|
TableName: physicalId,
|
|
@@ -12431,11 +12555,18 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12431
12555
|
}
|
|
12432
12556
|
for (const gsi of gsiDiff.modified) {
|
|
12433
12557
|
if (!gsi.IndexName) continue;
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
|
|
12558
|
+
if (gsiHandledByBillingFlip.has(gsi.IndexName)) continue;
|
|
12559
|
+
const billingFlipped = oldBilling !== newBilling;
|
|
12560
|
+
const update = { IndexName: gsi.IndexName };
|
|
12561
|
+
if (gsi.OnDemandThroughput) update.OnDemandThroughput = gsi.OnDemandThroughput;
|
|
12562
|
+
if (!billingFlipped && gsi.ProvisionedThroughput) update.ProvisionedThroughput = gsi.ProvisionedThroughput;
|
|
12563
|
+
const previousSdk = previousSdkByName.get(gsi.IndexName);
|
|
12564
|
+
if (gsi.WarmThroughput !== void 0 && !deepEqual$1(gsi.WarmThroughput, previousSdk?.WarmThroughput)) update.WarmThroughput = gsi.WarmThroughput;
|
|
12565
|
+
if (!update.ProvisionedThroughput && !update.OnDemandThroughput && !update.WarmThroughput) {
|
|
12566
|
+
if (!billingFlipped) this.logger.warn(`GSI '${gsi.IndexName}' on ${physicalId} changed in a way DynamoDB's UpdateTable cannot express (KeySchema / Projection are immutable on an existing index). Recreate the index under a new name to apply the change.`);
|
|
12567
|
+
continue;
|
|
12568
|
+
}
|
|
12569
|
+
const gsiUpdate = { Update: update };
|
|
12439
12570
|
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
12440
12571
|
TableName: physicalId,
|
|
12441
12572
|
GlobalSecondaryIndexUpdates: [gsiUpdate]
|
|
@@ -13200,11 +13331,16 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
13200
13331
|
*
|
|
13201
13332
|
* Source of truth (CFn `AWS::DynamoDB::GlobalTable` shape):
|
|
13202
13333
|
* - WriteCapacityUnits → `properties.WriteProvisionedThroughputSettings`
|
|
13203
|
-
* (top-level on the table).
|
|
13204
|
-
*
|
|
13334
|
+
* (top-level on the table). That block's ONLY member is
|
|
13335
|
+
* `WriteCapacityAutoScalingSettings` — write capacity on a GlobalTable is
|
|
13336
|
+
* always auto-scaled, so there is no literal `WriteCapacityUnits` to
|
|
13337
|
+
* prefer. `CreateTable` needs one concrete number, so the auto-scaling
|
|
13338
|
+
* block's `SeedCapacity` (documented as the value used until the scaling
|
|
13339
|
+
* policies exist) is taken before `MinCapacity`; 5 if the block is absent.
|
|
13205
13340
|
* - ReadCapacityUnits → `Replicas[?Region==<region>].ReadProvisionedThroughputSettings`
|
|
13206
|
-
* (per-replica, the deploy region's setting).
|
|
13207
|
-
* scaling
|
|
13341
|
+
* (per-replica, the deploy region's setting). That block DOES carry a
|
|
13342
|
+
* literal `ReadCapacityUnits`, which is taken before its auto-scaling
|
|
13343
|
+
* `SeedCapacity` / `MinCapacity`; 5 if absent.
|
|
13208
13344
|
*/
|
|
13209
13345
|
/**
|
|
13210
13346
|
* Extract the local replica's `DeletionProtectionEnabled` from a CFn
|
|
@@ -13227,16 +13363,190 @@ function extractLocalDeletionProtection(props, region) {
|
|
|
13227
13363
|
return typeof topLevel === "boolean" ? topLevel : void 0;
|
|
13228
13364
|
}
|
|
13229
13365
|
function derivePerCallProvisionedThroughput(properties, region) {
|
|
13230
|
-
const wps = properties["WriteProvisionedThroughputSettings"];
|
|
13231
|
-
const writeAutoScaling = wps?.["WriteCapacityAutoScalingSettings"];
|
|
13232
|
-
const writeCapacity = Number(wps?.["WriteCapacityUnits"] ?? writeAutoScaling?.["MinCapacity"] ?? 5);
|
|
13233
|
-
const localReadSettings = (properties["Replicas"] ?? []).find((r) => r["Region"] === region)?.["ReadProvisionedThroughputSettings"];
|
|
13234
|
-
const readAutoScaling = localReadSettings?.["ReadCapacityAutoScalingSettings"];
|
|
13235
13366
|
return {
|
|
13236
|
-
ReadCapacityUnits:
|
|
13237
|
-
WriteCapacityUnits:
|
|
13367
|
+
ReadCapacityUnits: deriveReadCapacityUnits(asRecord((properties["Replicas"] ?? []).find((r) => r["Region"] === region)?.["ReadProvisionedThroughputSettings"])) ?? DEFAULT_CAPACITY_UNITS,
|
|
13368
|
+
WriteCapacityUnits: deriveWriteCapacityUnits(asRecord(properties["WriteProvisionedThroughputSettings"])) ?? DEFAULT_CAPACITY_UNITS
|
|
13238
13369
|
};
|
|
13239
13370
|
}
|
|
13371
|
+
/**
|
|
13372
|
+
* Capacity units applied when a PROVISIONED template carries no usable
|
|
13373
|
+
* capacity value at all. Matches the pre-existing table-level default.
|
|
13374
|
+
*/
|
|
13375
|
+
const DEFAULT_CAPACITY_UNITS = 5;
|
|
13376
|
+
/** Narrow an unknown CFn sub-object to a record (or `undefined`). */
|
|
13377
|
+
function asRecord(value) {
|
|
13378
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
13379
|
+
}
|
|
13380
|
+
/** Coerce a CFn numeric (CFn is stringly-typed) to a finite number. */
|
|
13381
|
+
function toFiniteNumber(value) {
|
|
13382
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
13383
|
+
const n = Number(value);
|
|
13384
|
+
return Number.isFinite(n) ? n : void 0;
|
|
13385
|
+
}
|
|
13386
|
+
/**
|
|
13387
|
+
* Derive a single WRITE capacity number from a CFn
|
|
13388
|
+
* `WriteProvisionedThroughputSettings` block.
|
|
13389
|
+
*
|
|
13390
|
+
* The `AWS::DynamoDB::GlobalTable` registry schema (verified 2026-08-09 via
|
|
13391
|
+
* `aws cloudformation describe-type`) declares this block with exactly ONE
|
|
13392
|
+
* member — `WriteCapacityAutoScalingSettings` — i.e. write capacity on a
|
|
13393
|
+
* GlobalTable is ALWAYS auto-scaled; there is no literal `WriteCapacityUnits`
|
|
13394
|
+
* (that is why CDK 2.244's `TableV2` rejects `Capacity.fixed()` for write).
|
|
13395
|
+
* `CreateTable` / `UpdateTable` still require a concrete starting number, so
|
|
13396
|
+
* we take `SeedCapacity` ("the initial provisioned capacity units") when the
|
|
13397
|
+
* template supplies it, else `MinCapacity`.
|
|
13398
|
+
*
|
|
13399
|
+
* A literal `WriteCapacityUnits` is still honored first: the CFn schema
|
|
13400
|
+
* forbids it, but hand-authored / imported templates and cdkd state written
|
|
13401
|
+
* before this helper existed can carry it, and honoring it is strictly more
|
|
13402
|
+
* faithful than ignoring it.
|
|
13403
|
+
*/
|
|
13404
|
+
function deriveWriteCapacityUnits(settings) {
|
|
13405
|
+
if (!settings) return void 0;
|
|
13406
|
+
const literal = toFiniteNumber(settings["WriteCapacityUnits"]);
|
|
13407
|
+
if (literal !== void 0) return literal;
|
|
13408
|
+
const autoScaling = asRecord(settings["WriteCapacityAutoScalingSettings"]);
|
|
13409
|
+
if (!autoScaling) return void 0;
|
|
13410
|
+
return toFiniteNumber(autoScaling["SeedCapacity"]) ?? toFiniteNumber(autoScaling["MinCapacity"]);
|
|
13411
|
+
}
|
|
13412
|
+
/**
|
|
13413
|
+
* Derive a single READ capacity number from a CFn
|
|
13414
|
+
* `ReadProvisionedThroughputSettings` block (both the per-replica shape,
|
|
13415
|
+
* which carries `ReadCapacityUnits` + `ReadCapacityAutoScalingSettings`, and
|
|
13416
|
+
* the GSI/table-level `GlobalReadProvisionedThroughputSettings` shape, which
|
|
13417
|
+
* carries only `ReadCapacityUnits`). Same Seed-before-Min precedence as the
|
|
13418
|
+
* write side.
|
|
13419
|
+
*/
|
|
13420
|
+
function deriveReadCapacityUnits(settings) {
|
|
13421
|
+
if (!settings) return void 0;
|
|
13422
|
+
const literal = toFiniteNumber(settings["ReadCapacityUnits"]);
|
|
13423
|
+
if (literal !== void 0) return literal;
|
|
13424
|
+
const autoScaling = asRecord(settings["ReadCapacityAutoScalingSettings"]);
|
|
13425
|
+
if (!autoScaling) return void 0;
|
|
13426
|
+
return toFiniteNumber(autoScaling["SeedCapacity"]) ?? toFiniteNumber(autoScaling["MinCapacity"]);
|
|
13427
|
+
}
|
|
13428
|
+
/**
|
|
13429
|
+
* Translate the CFn `AWS::DynamoDB::GlobalTable` `GlobalSecondaryIndexes[]`
|
|
13430
|
+
* blob into the SDK's `GlobalSecondaryIndex[]` shape (Issue #1387).
|
|
13431
|
+
*
|
|
13432
|
+
* The two schemas model per-GSI throughput COMPLETELY differently, and the
|
|
13433
|
+
* AWS SDK v3 serializer silently drops unknown members — so the pre-fix raw
|
|
13434
|
+
* cast meant a PROVISIONED GlobalTable with a GSI failed `CreateTable`
|
|
13435
|
+
* outright (AWS requires `ProvisionedThroughput` on every GSI), and every
|
|
13436
|
+
* `TableV2` per-GSI on-demand limit vanished without a trace.
|
|
13437
|
+
*
|
|
13438
|
+
* Verified mapping (CFn registry schema `AWS::DynamoDB::GlobalTable` +
|
|
13439
|
+
* `@aws-sdk/client-dynamodb` `models_0.d.ts`, both read 2026-08-09; the CFn
|
|
13440
|
+
* side additionally confirmed against a real `cdk synth` of `TableV2` with a
|
|
13441
|
+
* GSI under both billing modes):
|
|
13442
|
+
*
|
|
13443
|
+
* | CFn | SDK |
|
|
13444
|
+
* | ---------------------------------------------------------------------- | --------------------------------------- |
|
|
13445
|
+
* | `GSI.WriteProvisionedThroughputSettings.WriteCapacityAutoScalingSettings` | `ProvisionedThroughput.WriteCapacityUnits` |
|
|
13446
|
+
* | `Replicas[local].GlobalSecondaryIndexes[].ReadProvisionedThroughputSettings.ReadCapacityUnits` | `ProvisionedThroughput.ReadCapacityUnits` |
|
|
13447
|
+
* | `GSI.WriteOnDemandThroughputSettings.MaxWriteRequestUnits` | `OnDemandThroughput.MaxWriteRequestUnits` |
|
|
13448
|
+
* | `Replicas[local].GlobalSecondaryIndexes[].ReadOnDemandThroughputSettings.MaxReadRequestUnits` | `OnDemandThroughput.MaxReadRequestUnits` |
|
|
13449
|
+
* | `GSI.WarmThroughput` | `WarmThroughput` (same spelling) |
|
|
13450
|
+
*
|
|
13451
|
+
* READ capacity really does live on the REPLICA's GSI entry, not on the
|
|
13452
|
+
* top-level GSI — CDK's `globalSecondaryIndexes[].readCapacity` synthesizes
|
|
13453
|
+
* to `Replicas[?Region==<deploy region>].GlobalSecondaryIndexes[].
|
|
13454
|
+
* ReadProvisionedThroughputSettings`. `CreateTable` only ever provisions the
|
|
13455
|
+
* LOCAL replica, so the local entry is the right source. The GSI-level
|
|
13456
|
+
* `ReadProvisionedThroughputSettings` / `ReadOnDemandThroughputSettings`
|
|
13457
|
+
* (which the schema also permits) are honored as a fallback for
|
|
13458
|
+
* hand-authored templates.
|
|
13459
|
+
*
|
|
13460
|
+
* Already-SDK-shaped `ProvisionedThroughput` / `OnDemandThroughput` members
|
|
13461
|
+
* win over the derivation: the CFn schema forbids them, but cdkd state
|
|
13462
|
+
* written before this fix (and hand-authored templates) can carry them, and
|
|
13463
|
+
* silently re-deriving over an explicit value would be a regression.
|
|
13464
|
+
*/
|
|
13465
|
+
function toSdkGlobalSecondaryIndexes(properties, region, billingMode) {
|
|
13466
|
+
const rawIndexes = properties["GlobalSecondaryIndexes"];
|
|
13467
|
+
if (rawIndexes !== void 0 && !Array.isArray(rawIndexes)) throw new Error(`AWS::DynamoDB::GlobalTable GlobalSecondaryIndexes must be an array, got ${typeof rawIndexes} (${JSON.stringify(rawIndexes)?.slice(0, 200)}). An unresolved intrinsic here would otherwise deploy a table with no indexes.`);
|
|
13468
|
+
const cfnIndexes = rawIndexes ?? [];
|
|
13469
|
+
if (cfnIndexes.length === 0) return [];
|
|
13470
|
+
const replicas = properties["Replicas"] ?? [];
|
|
13471
|
+
const localReplicaIndexes = (Array.isArray(replicas) ? replicas.find((r) => asRecord(r)?.["Region"] === region) : void 0)?.["GlobalSecondaryIndexes"] ?? [];
|
|
13472
|
+
const localByName = /* @__PURE__ */ new Map();
|
|
13473
|
+
if (Array.isArray(localReplicaIndexes)) for (const entry of localReplicaIndexes) {
|
|
13474
|
+
const record = asRecord(entry);
|
|
13475
|
+
const name = record?.["IndexName"];
|
|
13476
|
+
if (record && typeof name === "string") localByName.set(name, record);
|
|
13477
|
+
}
|
|
13478
|
+
const result = [];
|
|
13479
|
+
for (const entry of cfnIndexes) {
|
|
13480
|
+
const gsi = asRecord(entry);
|
|
13481
|
+
if (!gsi) {
|
|
13482
|
+
result.push(entry);
|
|
13483
|
+
continue;
|
|
13484
|
+
}
|
|
13485
|
+
const indexName = gsi["IndexName"];
|
|
13486
|
+
const localEntry = typeof indexName === "string" ? localByName.get(indexName) : void 0;
|
|
13487
|
+
const sdk = {
|
|
13488
|
+
IndexName: indexName,
|
|
13489
|
+
KeySchema: gsi["KeySchema"],
|
|
13490
|
+
Projection: gsi["Projection"]
|
|
13491
|
+
};
|
|
13492
|
+
if (gsi["WarmThroughput"] !== void 0) sdk.WarmThroughput = gsi["WarmThroughput"];
|
|
13493
|
+
const explicitProvisioned = asRecord(gsi["ProvisionedThroughput"]);
|
|
13494
|
+
const explicitOnDemand = asRecord(gsi["OnDemandThroughput"]);
|
|
13495
|
+
if (explicitProvisioned) sdk.ProvisionedThroughput = explicitProvisioned;
|
|
13496
|
+
else if (billingMode === "PROVISIONED") sdk.ProvisionedThroughput = {
|
|
13497
|
+
ReadCapacityUnits: deriveReadCapacityUnits(asRecord(localEntry?.["ReadProvisionedThroughputSettings"])) ?? deriveReadCapacityUnits(asRecord(gsi["ReadProvisionedThroughputSettings"])) ?? DEFAULT_CAPACITY_UNITS,
|
|
13498
|
+
WriteCapacityUnits: deriveWriteCapacityUnits(asRecord(gsi["WriteProvisionedThroughputSettings"])) ?? DEFAULT_CAPACITY_UNITS
|
|
13499
|
+
};
|
|
13500
|
+
if (explicitOnDemand) sdk.OnDemandThroughput = explicitOnDemand;
|
|
13501
|
+
else if (billingMode !== "PROVISIONED") {
|
|
13502
|
+
const maxWrite = toFiniteNumber(asRecord(gsi["WriteOnDemandThroughputSettings"])?.["MaxWriteRequestUnits"]);
|
|
13503
|
+
const maxRead = toFiniteNumber(asRecord(localEntry?.["ReadOnDemandThroughputSettings"])?.["MaxReadRequestUnits"]) ?? toFiniteNumber(asRecord(gsi["ReadOnDemandThroughputSettings"])?.["MaxReadRequestUnits"]);
|
|
13504
|
+
if (maxWrite !== void 0 || maxRead !== void 0) sdk.OnDemandThroughput = {
|
|
13505
|
+
...maxRead !== void 0 && { MaxReadRequestUnits: maxRead },
|
|
13506
|
+
...maxWrite !== void 0 && { MaxWriteRequestUnits: maxWrite }
|
|
13507
|
+
};
|
|
13508
|
+
}
|
|
13509
|
+
result.push(sdk);
|
|
13510
|
+
}
|
|
13511
|
+
return result;
|
|
13512
|
+
}
|
|
13513
|
+
/**
|
|
13514
|
+
* Translate a CFn `Replicas[].GlobalSecondaryIndexes[]` blob (the
|
|
13515
|
+
* `ReplicaGlobalSecondaryIndexSpecification` shape) into the SDK's
|
|
13516
|
+
* `ReplicaGlobalSecondaryIndex[]` used by `CreateReplicationGroupMemberAction`
|
|
13517
|
+
* / `UpdateReplicationGroupMemberAction` (Issue #1387).
|
|
13518
|
+
*
|
|
13519
|
+
* Verified mapping:
|
|
13520
|
+
*
|
|
13521
|
+
* | CFn | SDK |
|
|
13522
|
+
* | ---------------------------------------------------------- | ---------------------------------------------- |
|
|
13523
|
+
* | `ReadProvisionedThroughputSettings.ReadCapacityUnits` | `ProvisionedThroughputOverride.ReadCapacityUnits` |
|
|
13524
|
+
* | `ReadOnDemandThroughputSettings.MaxReadRequestUnits` | `OnDemandThroughputOverride.MaxReadRequestUnits` |
|
|
13525
|
+
*
|
|
13526
|
+
* DELIBERATELY UNMAPPED: `ContributorInsightsSpecification`. The replica-GSI
|
|
13527
|
+
* SDK shape has no member for it — per-index contributor insights are toggled
|
|
13528
|
+
* by a separate `UpdateContributorInsights(TableName, IndexName)` call, which
|
|
13529
|
+
* this provider does not issue for any index (it only reads the TABLE-level
|
|
13530
|
+
* status back in `readCurrentState`). Recorded here rather than silently
|
|
13531
|
+
* dropped; tracked with the other GlobalTable nested-key gaps.
|
|
13532
|
+
*/
|
|
13533
|
+
function toSdkReplicaGlobalSecondaryIndexes(replicaIndexes) {
|
|
13534
|
+
if (!Array.isArray(replicaIndexes) || replicaIndexes.length === 0) return void 0;
|
|
13535
|
+
return replicaIndexes.map((entry) => {
|
|
13536
|
+
const cfn = asRecord(entry);
|
|
13537
|
+
if (!cfn) return entry;
|
|
13538
|
+
const sdk = { IndexName: cfn["IndexName"] };
|
|
13539
|
+
const explicitProvisioned = asRecord(cfn["ProvisionedThroughputOverride"]);
|
|
13540
|
+
const explicitOnDemand = asRecord(cfn["OnDemandThroughputOverride"]);
|
|
13541
|
+
const readCapacity = deriveReadCapacityUnits(asRecord(cfn["ReadProvisionedThroughputSettings"]));
|
|
13542
|
+
const maxReadRequestUnits = toFiniteNumber(asRecord(cfn["ReadOnDemandThroughputSettings"])?.["MaxReadRequestUnits"]);
|
|
13543
|
+
if (explicitProvisioned) sdk.ProvisionedThroughputOverride = explicitProvisioned;
|
|
13544
|
+
else if (readCapacity !== void 0) sdk.ProvisionedThroughputOverride = { ReadCapacityUnits: readCapacity };
|
|
13545
|
+
if (explicitOnDemand) sdk.OnDemandThroughputOverride = explicitOnDemand;
|
|
13546
|
+
else if (maxReadRequestUnits !== void 0) sdk.OnDemandThroughputOverride = { MaxReadRequestUnits: maxReadRequestUnits };
|
|
13547
|
+
return sdk;
|
|
13548
|
+
});
|
|
13549
|
+
}
|
|
13240
13550
|
function diffReplicas(oldReplicas, newReplicas) {
|
|
13241
13551
|
const oldByRegion = /* @__PURE__ */ new Map();
|
|
13242
13552
|
const newByRegion = /* @__PURE__ */ new Map();
|
|
@@ -64596,7 +64906,7 @@ function createMigrateCommand() {
|
|
|
64596
64906
|
*/
|
|
64597
64907
|
function buildProgram() {
|
|
64598
64908
|
const program = new Command();
|
|
64599
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.278.
|
|
64909
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.278.13");
|
|
64600
64910
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
64601
64911
|
const { profile } = actionCommand.optsWithGlobals();
|
|
64602
64912
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|