@go-to-k/cdkd 0.280.3 → 0.280.5
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-C-Mym0XH.js → asg-provider-DINOy61N.js} +2 -2
- package/dist/{asg-provider-C-Mym0XH.js.map → asg-provider-DINOy61N.js.map} +1 -1
- package/dist/cli.js +355 -22
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-Ca5ywZ1L.js → deploy-engine-C5xOvZbg.js} +14 -16
- package/dist/{deploy-engine-Ca5ywZ1L.js.map → deploy-engine-C5xOvZbg.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 DiffCalculator, $t as resolveBucketRegion, A as red, At as getDockerImageBySourceHash, B as isTerminationProtectionPropagationError, Bt as resolveStateBucketWithDefaultAndSource, C as isStatefulRecreateTargetSync, Ct as validateContainerRepoName, D as cyan, Dt as runDockerForeground, E as bold, En as withErrorHandling, Et as getDockerCmd, F as ProviderRegistry, Ft as resolveApp, G as normalizeAwsTagsToCfn, Gt as CFN_TEMPLATE_URL_LIMIT, H as cfnRefValueFromPhysicalId, Ht as stateBucketExistenceConfirmed, I as findActionableSilentDrops, It as resolveAutoAssetStorage, J as readConfigString, Jt as uploadCfnTemplate, K as resolveExplicitPhysicalId, Kt as MIGRATE_TMP_PREFIX, L as CloudControlProvider, Lt as resolveCaptureObservedState, M as IAMRoleProvider, Mt as synthesisStatusMessage, N as collectInlinePolicyNamesManagedBySiblings, Nt as getDefaultStateBucketName, O as gray, Ot as runDockerStreaming, P as clearOnUpdateRemoval, Pt as getLegacyStateBucketName, Q as applyRoleArnIfSet, R as slowCcOperationTimeoutMs, Rt as resolveSkipPrefix, S as MULTI_REGION_RECREATE_BLOCKED_TYPES, St as validateAssetBucketName, T as formatResourceLine, Tn as normalizeAwsError, Tt as formatDockerLoginError, U as refStateLookupFromResource, Ut as warnDeprecatedNoPrefixCliFlag, V as IntrinsicFunctionResolver, Vt as resolveUseCdkBootstrapAssets, W as WAFv2WebACLProvider, Wt as CFN_TEMPLATE_BODY_LIMIT, X as requireConfigArray, Xt as AssemblyReader, Y as replayWarn, Yt as expectedOwnerParam, Z as requireConfigString, Zt as processStackMessages, _ as createPreDeleteFinalSnapshot, _n as ResourceTimeoutError, _t as AssetModeResolver, a as DeploymentEventsStore, an as CdkdError, at as TemplateParser, b as unsupportedFinalSnapshotError, bn as StackTerminationProtectionError, bt as getBootstrapMarkerKey, c as replayFailedOperations, cn as DeployCancelledError, ct as rebuildClientForBucketRegion, d as IMPLICIT_DELETE_DEPENDENCIES, dn as LocalStartServiceError, dt as stringifyValue, en as AwsClients, et as describeTypeWithThrottleRetry, f as computeImplicitDeleteEdges, ft as WorkGraph, g as ccRoutedFinalSnapshotError, gn as ProvisioningError, gt as rewriteTemplateAssetReferences, h as buildFinalSnapshotIdentifier, hn as PartialFailureError, ht as loadPublishableAssetManifest, i as DeploymentEventsReader, it as DagBuilder, j as yellow, jt as Synthesizer, k as green, kt as AssetManifestLoader, l as replayRollback, ln as LocalInvokeBuildError$1, lt as shouldRetainResource, m as PRE_DELETE_SNAPSHOT_TYPES, mn as NestedStackChildDirectDestroyError, mt as createAssetRedirectResolver, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as resetAwsClients, nt as isRetryableTransientError, o as planFailedOps, ot as LockManager, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as MissingCdkCliError, pt as buildAssetRedirectMap, q as assertRegionMatch, qt as findLargeInlineResources, r as DeployEngine, rn as setAwsClients, rt as isThrottlingError, s as planRollback, st as S3StateBackend, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as getAwsClients, tt as withRetry, u as withResourceDeadline, un as LocalMigrateError, ut as AssetPublisher, v as isFinalSnapshotError, vn as ResourceUpdateNotSupportedError, vt as BOOTSTRAP_MARKER_PREFIX, w as renderStatefulReason, wt as buildDockerImage, x as extractDeploymentEventError, xt as parseBootstrapMarker, y as refusesFinalSnapshot, yn as StackHasActiveImportsError, yt as ensureAssetStorage, z as disableInstanceApiTermination, zt as resolveStateBucketWithDefault } from "./deploy-engine-
|
|
2
|
+
import { $ as DiffCalculator, $t as resolveBucketRegion, A as red, At as getDockerImageBySourceHash, B as isTerminationProtectionPropagationError, Bt as resolveStateBucketWithDefaultAndSource, C as isStatefulRecreateTargetSync, Ct as validateContainerRepoName, D as cyan, Dt as runDockerForeground, E as bold, En as withErrorHandling, Et as getDockerCmd, F as ProviderRegistry, Ft as resolveApp, G as normalizeAwsTagsToCfn, Gt as CFN_TEMPLATE_URL_LIMIT, H as cfnRefValueFromPhysicalId, Ht as stateBucketExistenceConfirmed, I as findActionableSilentDrops, It as resolveAutoAssetStorage, J as readConfigString, Jt as uploadCfnTemplate, K as resolveExplicitPhysicalId, Kt as MIGRATE_TMP_PREFIX, L as CloudControlProvider, Lt as resolveCaptureObservedState, M as IAMRoleProvider, Mt as synthesisStatusMessage, N as collectInlinePolicyNamesManagedBySiblings, Nt as getDefaultStateBucketName, O as gray, Ot as runDockerStreaming, P as clearOnUpdateRemoval, Pt as getLegacyStateBucketName, Q as applyRoleArnIfSet, R as slowCcOperationTimeoutMs, Rt as resolveSkipPrefix, S as MULTI_REGION_RECREATE_BLOCKED_TYPES, St as validateAssetBucketName, T as formatResourceLine, Tn as normalizeAwsError, Tt as formatDockerLoginError, U as refStateLookupFromResource, Ut as warnDeprecatedNoPrefixCliFlag, V as IntrinsicFunctionResolver, Vt as resolveUseCdkBootstrapAssets, W as WAFv2WebACLProvider, Wt as CFN_TEMPLATE_BODY_LIMIT, X as requireConfigArray, Xt as AssemblyReader, Y as replayWarn, Yt as expectedOwnerParam, Z as requireConfigString, Zt as processStackMessages, _ as createPreDeleteFinalSnapshot, _n as ResourceTimeoutError, _t as AssetModeResolver, a as DeploymentEventsStore, an as CdkdError, at as TemplateParser, b as unsupportedFinalSnapshotError, bn as StackTerminationProtectionError, bt as getBootstrapMarkerKey, c as replayFailedOperations, cn as DeployCancelledError, ct as rebuildClientForBucketRegion, d as IMPLICIT_DELETE_DEPENDENCIES, dn as LocalStartServiceError, dt as stringifyValue, en as AwsClients, et as describeTypeWithThrottleRetry, f as computeImplicitDeleteEdges, ft as WorkGraph, g as ccRoutedFinalSnapshotError, gn as ProvisioningError, gt as rewriteTemplateAssetReferences, h as buildFinalSnapshotIdentifier, hn as PartialFailureError, ht as loadPublishableAssetManifest, i as DeploymentEventsReader, it as DagBuilder, j as yellow, jt as Synthesizer, k as green, kt as AssetManifestLoader, l as replayRollback, ln as LocalInvokeBuildError$1, lt as shouldRetainResource, m as PRE_DELETE_SNAPSHOT_TYPES, mn as NestedStackChildDirectDestroyError, mt as createAssetRedirectResolver, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as resetAwsClients, nt as isRetryableTransientError, o as planFailedOps, ot as LockManager, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as MissingCdkCliError, pt as buildAssetRedirectMap, q as assertRegionMatch, qt as findLargeInlineResources, r as DeployEngine, rn as setAwsClients, rt as isThrottlingError, s as planRollback, st as S3StateBackend, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as getAwsClients, tt as withRetry, u as withResourceDeadline, un as LocalMigrateError, ut as AssetPublisher, v as isFinalSnapshotError, vn as ResourceUpdateNotSupportedError, vt as BOOTSTRAP_MARKER_PREFIX, w as renderStatefulReason, wt as buildDockerImage, x as extractDeploymentEventError, xt as parseBootstrapMarker, y as refusesFinalSnapshot, yn as StackHasActiveImportsError, yt as ensureAssetStorage, z as disableInstanceApiTermination, zt as resolveStateBucketWithDefault } from "./deploy-engine-C5xOvZbg.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-DINOy61N.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";
|
|
@@ -43,7 +43,7 @@ import readline from "node:readline/promises";
|
|
|
43
43
|
import { writeFileSync as writeFileSync$1 } from "fs";
|
|
44
44
|
import * as zlib from "node:zlib";
|
|
45
45
|
import { ApplicationAutoScalingClient, DeleteScalingPolicyCommand, DeregisterScalableTargetCommand, DescribeScalableTargetsCommand, DescribeScalingPoliciesCommand, PutScalingPolicyCommand, RegisterScalableTargetCommand } from "@aws-sdk/client-application-auto-scaling";
|
|
46
|
-
import { ApiGatewayV2Client, CreateApiCommand, CreateAuthorizerCommand as CreateAuthorizerCommand$1, CreateIntegrationCommand, CreateRouteCommand as CreateRouteCommand$1, CreateStageCommand as CreateStageCommand$1, DeleteApiCommand, DeleteAuthorizerCommand as DeleteAuthorizerCommand$1, DeleteCorsConfigurationCommand, DeleteIntegrationCommand, DeleteRouteCommand as DeleteRouteCommand$1, DeleteStageCommand as DeleteStageCommand$1, GetApiCommand, GetAuthorizerCommand as GetAuthorizerCommand$1, GetIntegrationCommand, GetRouteCommand, GetStageCommand as GetStageCommand$1, NotFoundException as NotFoundException$3, UpdateApiCommand, UpdateAuthorizerCommand as UpdateAuthorizerCommand$1, UpdateIntegrationCommand, UpdateRouteCommand, UpdateStageCommand as UpdateStageCommand$1 } from "@aws-sdk/client-apigatewayv2";
|
|
46
|
+
import { ApiGatewayV2Client, CreateApiCommand, CreateAuthorizerCommand as CreateAuthorizerCommand$1, CreateIntegrationCommand, CreateRouteCommand as CreateRouteCommand$1, CreateStageCommand as CreateStageCommand$1, DeleteAccessLogSettingsCommand, DeleteApiCommand, DeleteAuthorizerCommand as DeleteAuthorizerCommand$1, DeleteCorsConfigurationCommand, DeleteIntegrationCommand, DeleteRouteCommand as DeleteRouteCommand$1, DeleteRouteRequestParameterCommand, DeleteRouteSettingsCommand, DeleteStageCommand as DeleteStageCommand$1, GetApiCommand, GetAuthorizerCommand as GetAuthorizerCommand$1, GetIntegrationCommand, GetRouteCommand, GetStageCommand as GetStageCommand$1, NotFoundException as NotFoundException$3, UpdateApiCommand, UpdateAuthorizerCommand as UpdateAuthorizerCommand$1, UpdateIntegrationCommand, UpdateRouteCommand, UpdateStageCommand as UpdateStageCommand$1 } from "@aws-sdk/client-apigatewayv2";
|
|
47
47
|
import { CreateStateMachineCommand, DeleteStateMachineCommand, DescribeStateMachineCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$11, SFNClient, StateMachineDoesNotExist, TagResourceCommand as TagResourceCommand$13, UntagResourceCommand as UntagResourceCommand$13, UpdateStateMachineCommand } from "@aws-sdk/client-sfn";
|
|
48
48
|
import { CreateClusterCommand, CreateServiceCommand, DeleteClusterCommand, DeleteServiceCommand, DeregisterTaskDefinitionCommand, DescribeClustersCommand, DescribeServicesCommand, DescribeTaskDefinitionCommand, ECSClient, PutClusterCapacityProvidersCommand, RegisterTaskDefinitionCommand, TagResourceCommand as TagResourceCommand$14, UntagResourceCommand as UntagResourceCommand$14, UpdateClusterCommand, UpdateServiceCommand, waitUntilServicesStable } from "@aws-sdk/client-ecs";
|
|
49
49
|
import { AddTagsToResourceCommand as AddTagsToResourceCommand$3, CreateDBClusterCommand as CreateDBClusterCommand$1, CreateDBInstanceCommand as CreateDBInstanceCommand$1, CreateDBSubnetGroupCommand as CreateDBSubnetGroupCommand$1, DeleteDBClusterCommand as DeleteDBClusterCommand$1, DeleteDBInstanceCommand as DeleteDBInstanceCommand$1, DeleteDBSubnetGroupCommand as DeleteDBSubnetGroupCommand$1, DescribeDBClustersCommand as DescribeDBClustersCommand$1, DescribeDBInstancesCommand as DescribeDBInstancesCommand$1, DescribeDBSubnetGroupsCommand as DescribeDBSubnetGroupsCommand$1, DocDBClient, ListTagsForResourceCommand as ListTagsForResourceCommand$12, ModifyDBClusterCommand as ModifyDBClusterCommand$1, ModifyDBInstanceCommand as ModifyDBInstanceCommand$1, ModifyDBSubnetGroupCommand as ModifyDBSubnetGroupCommand$1, RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand$3 } from "@aws-sdk/client-docdb";
|
|
@@ -12954,7 +12954,8 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12954
12954
|
if (tableArn) await this.applyTagDiff(tableArn, extractLocalTags(previousProperties), extractLocalTags(properties));
|
|
12955
12955
|
const recordedOldBilling = previousProperties["BillingMode"];
|
|
12956
12956
|
const recordedOldBillingUsable = recordedOldBilling === void 0 || typeof recordedOldBilling === "string" && recordedOldBilling.trim() !== "";
|
|
12957
|
-
const
|
|
12957
|
+
const liveBillingMode = describeResp.Table?.BillingModeSummary?.BillingMode ?? "PROVISIONED";
|
|
12958
|
+
const oldBilling = recordedOldBillingUsable ? recordedOldBilling ?? "PAY_PER_REQUEST" : liveBillingMode;
|
|
12958
12959
|
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.`);
|
|
12959
12960
|
let billingUnusable = false;
|
|
12960
12961
|
const requestedBilling = requireConfigString(properties["BillingMode"], "PAY_PER_REQUEST", "AWS::DynamoDB::GlobalTable BillingMode", { onUnusable: (message) => {
|
|
@@ -12970,12 +12971,12 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
12970
12971
|
let desiredGsiUnusable = false;
|
|
12971
12972
|
const onUnusableGsiBlock = (message) => {
|
|
12972
12973
|
desiredGsiUnusable = true;
|
|
12973
|
-
this.logger.warn(
|
|
12974
|
+
this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: ${message} No GlobalSecondaryIndexes change is applied by this update; the table's existing indexes are left untouched.`);
|
|
12974
12975
|
};
|
|
12975
12976
|
let previousGsiUnusable = false;
|
|
12976
12977
|
const onUnusablePreviousGsiBlock = (message) => {
|
|
12977
12978
|
previousGsiUnusable = true;
|
|
12978
|
-
this.logger.warn(
|
|
12979
|
+
this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: ${message} (recorded in cdkd state, not in the template) — using the table's LIVE indexes as the comparison baseline for this update, so a corrected template still applies.`);
|
|
12979
12980
|
};
|
|
12980
12981
|
const liveIndexNames = new Set((describeResp.Table?.GlobalSecondaryIndexes ?? []).map((live) => live.IndexName).filter((name) => typeof name === "string"));
|
|
12981
12982
|
const desiredSdkIndexes = toSdkGlobalSecondaryIndexes(properties, currentRegion, newBilling, "min", flippingToProvisioned ? void 0 : diagnostics, onUnusableGsiBlock);
|
|
@@ -13182,11 +13183,15 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
13182
13183
|
await this.waitForReplicaActive(physicalId, region, logicalId);
|
|
13183
13184
|
}
|
|
13184
13185
|
const previousTranslatedIndexes = toSdkGlobalSecondaryIndexes(previousProperties, currentRegion, oldBilling, "min", void 0, onUnusablePreviousGsiBlock);
|
|
13185
|
-
const previousSdkIndexes = previousGsiUnusable ? desiredSdkIndexes
|
|
13186
|
+
const previousSdkIndexes = previousGsiUnusable ? buildLiveRecoveryGsiBaseline(desiredSdkIndexes, describeResp.Table?.GlobalSecondaryIndexes, {
|
|
13187
|
+
carryLiveValues: oldBilling === newBilling && liveBillingMode === newBilling,
|
|
13188
|
+
liveBillingMode,
|
|
13189
|
+
uncomparableCapacityIndexNames: collectUncomparableCapacityGsiNames(properties, currentRegion)
|
|
13190
|
+
}) : previousTranslatedIndexes;
|
|
13186
13191
|
if (previousGsiUnusable) {
|
|
13187
13192
|
const desiredNames = new Set(desiredSdkIndexes.map((gsi) => gsi.IndexName).filter((name) => typeof name === "string"));
|
|
13188
13193
|
const liveOnly = [...liveIndexNames].filter((name) => !desiredNames.has(name));
|
|
13189
|
-
if (liveOnly.length > 0) this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: ${liveOnly.join(", ")} exist(s) on the table but not in the template. No Delete is issued while the recorded GlobalSecondaryIndexes are unusable — a junk state record cannot prove cdkd created them.
|
|
13194
|
+
if (liveOnly.length > 0) this.logger.warn(`AWS::DynamoDB::GlobalTable ${logicalId}: ${liveOnly.join(", ")} exist(s) on the table but not in the template. No Delete is issued while the recorded GlobalSecondaryIndexes are unusable — a junk state record cannot prove cdkd created them, and an index delete is irreversible. This does NOT self-heal, and no later cdkd deploy will remove them: delete the index directly, e.g. aws dynamodb update-table --table-name ${physicalId} --global-secondary-index-updates '[{"Delete":{"IndexName":"<name>"}}]'.`);
|
|
13190
13195
|
}
|
|
13191
13196
|
const gsiDiff = desiredGsiUnusable ? {
|
|
13192
13197
|
added: [],
|
|
@@ -14941,6 +14946,159 @@ function collectRawOnDemandDeclarations(properties, region) {
|
|
|
14941
14946
|
return out;
|
|
14942
14947
|
}
|
|
14943
14948
|
/**
|
|
14949
|
+
* Names of the GSIs whose PROVISIONED capacity must NOT be compared against
|
|
14950
|
+
* the live table (issue #1571). Two disjoint reasons, and both are about the
|
|
14951
|
+
* DESIRED side being a number the template did not actually choose:
|
|
14952
|
+
*
|
|
14953
|
+
* - **auto-scaled** — the live number is owned by Application Auto Scaling
|
|
14954
|
+
* while the translation takes `MinCapacity` (see {@link CapacitySource}), so
|
|
14955
|
+
* a live 10 against a template min of 1 reads as a scale-down NOBODY ASKED
|
|
14956
|
+
* FOR. This was one of the three measured failure modes of the first
|
|
14957
|
+
* value-carrying baseline (#1551), and the only one that cannot be resolved
|
|
14958
|
+
* by reading the live side more carefully — both numbers are correct, they
|
|
14959
|
+
* answer different questions.
|
|
14960
|
+
* - **not template-determined** — no capacity resolves to a finite number, so
|
|
14961
|
+
* `toSdkGlobalSecondaryIndexes` substitutes `DEFAULT_CAPACITY_UNITS` (5/5,
|
|
14962
|
+
* the issue #1511 class). Comparing that invented default against the live
|
|
14963
|
+
* value turns it into a WRITE. Found by review, not by the first cut.
|
|
14964
|
+
*
|
|
14965
|
+
* Walks the same two sources as {@link toSdkGlobalSecondaryIndexes} and
|
|
14966
|
+
* {@link collectRawOnDemandDeclarations} — the LOCAL replica's index entry
|
|
14967
|
+
* first (the canonical CDK spelling), the GSI-level block as the
|
|
14968
|
+
* hand-authored fallback for read, the top-level GSI for write. A divergence
|
|
14969
|
+
* between the three is what would re-open the bug, so they are kept adjacent.
|
|
14970
|
+
*
|
|
14971
|
+
* The auto-scaling arm tests PRESENCE of the `*CapacityAutoScalingSettings`
|
|
14972
|
+
* key, not whether its members coerce: a block that is itself an unresolved
|
|
14973
|
+
* intrinsic still means "this index is autoscaled", and "might be" must read
|
|
14974
|
+
* as "is" — a false negative issues an unrequested scale-down.
|
|
14975
|
+
*
|
|
14976
|
+
* KNOWN BOUND: detection is TEMPLATE-side only. An index autoscaled OUT OF
|
|
14977
|
+
* BAND (no `*CapacityAutoScalingSettings` in the template) has a
|
|
14978
|
+
* template-determined capacity, so its live value IS compared and the recovery
|
|
14979
|
+
* deploy re-asserts the template's number — which is what a clean previous
|
|
14980
|
+
* side would also have done, so this matches ordinary cdkd semantics rather
|
|
14981
|
+
* than being a recovery-path defect.
|
|
14982
|
+
*
|
|
14983
|
+
* And the cost of a false positive is a PERMANENT divergence, not "one deploy
|
|
14984
|
+
* of lag": the deploy records the template value as state, so the next diff
|
|
14985
|
+
* sees previous == desired and never revisits it. That is the same self-heal
|
|
14986
|
+
* fallacy this PR corrects in the live-only warning; it is accepted here
|
|
14987
|
+
* because the alternative is writing a number the user never asked for.
|
|
14988
|
+
*/
|
|
14989
|
+
function collectUncomparableCapacityGsiNames(properties, region) {
|
|
14990
|
+
const out = /* @__PURE__ */ new Set();
|
|
14991
|
+
const rawIndexes = properties["GlobalSecondaryIndexes"];
|
|
14992
|
+
if (!Array.isArray(rawIndexes)) return out;
|
|
14993
|
+
const replicas = properties["Replicas"];
|
|
14994
|
+
const localReplicaIndexes = asRecord$1(Array.isArray(replicas) ? replicas.find((r) => asRecord$1(r)?.["Region"] === region) : void 0)?.["GlobalSecondaryIndexes"];
|
|
14995
|
+
const localByName = /* @__PURE__ */ new Map();
|
|
14996
|
+
if (Array.isArray(localReplicaIndexes)) for (const entry of localReplicaIndexes) {
|
|
14997
|
+
const record = asRecord$1(entry);
|
|
14998
|
+
const name = record?.["IndexName"];
|
|
14999
|
+
if (record && typeof name === "string") localByName.set(name, record);
|
|
15000
|
+
}
|
|
15001
|
+
for (const entry of rawIndexes) {
|
|
15002
|
+
const gsi = asRecord$1(entry);
|
|
15003
|
+
const name = gsi?.["IndexName"];
|
|
15004
|
+
if (!gsi || typeof name !== "string") continue;
|
|
15005
|
+
const readBlocks = [localByName.get(name)?.["ReadProvisionedThroughputSettings"], gsi["ReadProvisionedThroughputSettings"]];
|
|
15006
|
+
const writeBlock = gsi["WriteProvisionedThroughputSettings"];
|
|
15007
|
+
if (readBlocks.some((block) => asRecord$1(block)?.["ReadCapacityAutoScalingSettings"] !== void 0 || isUnresolvedIntrinsicBlock(block)) || asRecord$1(writeBlock)?.["WriteCapacityAutoScalingSettings"] !== void 0 || isUnresolvedIntrinsicBlock(writeBlock)) {
|
|
15008
|
+
out.add(name);
|
|
15009
|
+
continue;
|
|
15010
|
+
}
|
|
15011
|
+
const explicitProvisioned = asRecord$1(gsi["ProvisionedThroughput"]);
|
|
15012
|
+
const derivedRead = toFiniteNumber(explicitProvisioned?.["ReadCapacityUnits"]) ?? deriveReadCapacityUnits(asRecord$1(readBlocks[0])) ?? deriveReadCapacityUnits(asRecord$1(readBlocks[1]));
|
|
15013
|
+
const derivedWrite = toFiniteNumber(explicitProvisioned?.["WriteCapacityUnits"]) ?? deriveWriteCapacityUnits(asRecord$1(writeBlock));
|
|
15014
|
+
if (derivedRead === void 0 || derivedWrite === void 0) out.add(name);
|
|
15015
|
+
}
|
|
15016
|
+
return out;
|
|
15017
|
+
}
|
|
15018
|
+
/**
|
|
15019
|
+
* Build the GSI diff baseline used when the cdkd STATE record's
|
|
15020
|
+
* `GlobalSecondaryIndexes` is present-but-unusable (issue #1571, closing the
|
|
15021
|
+
* residual #1551 / PR #1562 measured and deliberately left open).
|
|
15022
|
+
*
|
|
15023
|
+
* The entries are the DESIRED indexes filtered to the names that EXIST live —
|
|
15024
|
+
* the live table is the only side that can answer "does this index exist",
|
|
15025
|
+
* which is what stops the permanent index loss #1562 was about. What #1562
|
|
15026
|
+
* could not settle was the VALUES: it copied the desired entry verbatim, so
|
|
15027
|
+
* the diff could only ever produce ADDs and every capacity / ceiling edit
|
|
15028
|
+
* silently lagged one deploy.
|
|
15029
|
+
*
|
|
15030
|
+
* This carries live VALUES, but only the ones that are safe to compare, and
|
|
15031
|
+
* the exclusions are the three measured failure modes of the first attempt
|
|
15032
|
+
* (recorded at the `liveIndexNames` call site) rather than a guess:
|
|
15033
|
+
*
|
|
15034
|
+
* - **`ProvisionedThroughput` is gated on the LIVE billing mode.**
|
|
15035
|
+
* `DescribeTable` reports `{ReadCapacityUnits: 0, WriteCapacityUnits: 0}`
|
|
15036
|
+
* for every index of a PAY_PER_REQUEST table, so an ungated read produced a
|
|
15037
|
+
* "modified" on every index and re-sent `{0, 0}`, which AWS rejects.
|
|
15038
|
+
* - **An AUTOSCALED index keeps identity-only capacity.** The live number
|
|
15039
|
+
* belongs to Application Auto Scaling; the desired side is `MinCapacity`.
|
|
15040
|
+
* Comparing them reads as a scale-down the user never asked for.
|
|
15041
|
+
* - **`KeySchema` / `Projection` / `WarmThroughput` are always the desired
|
|
15042
|
+
* side.** All three are copied from `desired`, so they can never DIFFER —
|
|
15043
|
+
* deliberately. `KeySchema` and `Projection` are immutable on an existing
|
|
15044
|
+
* index (a difference produces only a "recreate the index" warning, and
|
|
15045
|
+
* AWS's `Projection.NonKeyAttributes` READBACK ORDER is not guaranteed, so
|
|
15046
|
+
* the comparison would be a coin flip); `WarmThroughput` reads back with a
|
|
15047
|
+
* `Status` member the translated shape does not carry, and DynamoDB warm
|
|
15048
|
+
* throughput is increase-only, so a manufactured difference is a real
|
|
15049
|
+
* AWS-side risk.
|
|
15050
|
+
*
|
|
15051
|
+
* `OnDemandThroughput` IS carried from live on an on-demand table, and that is
|
|
15052
|
+
* the second thing this fixes: the `modified` loop derives the `-1` ceiling
|
|
15053
|
+
* RESET (the #1160 absent-field-removal class) from the PREVIOUS side, so with
|
|
15054
|
+
* a desired-copy baseline a template that dropped `MaxReadRequestUnits` left
|
|
15055
|
+
* the old ceiling live in AWS forever while cdkd reported success.
|
|
15056
|
+
*
|
|
15057
|
+
* REMOVES are still not derivable here and are deliberately absent: an index
|
|
15058
|
+
* live but not in the template is in NEITHER side, so no `Delete` is issued.
|
|
15059
|
+
* A junk state record cannot distinguish "cdkd created this and the template
|
|
15060
|
+
* dropped it" from "somebody added it out of band", the delete is irreversible
|
|
15061
|
+
* and a re-create costs a full backfill. The caller names the live-only
|
|
15062
|
+
* indexes and points at the remedy.
|
|
15063
|
+
*/
|
|
15064
|
+
function buildLiveRecoveryGsiBaseline(desiredSdkIndexes, liveIndexes, options) {
|
|
15065
|
+
const liveByName = /* @__PURE__ */ new Map();
|
|
15066
|
+
for (const live of liveIndexes ?? []) if (typeof live.IndexName === "string") liveByName.set(live.IndexName, live);
|
|
15067
|
+
const baseline = [];
|
|
15068
|
+
for (const desired of desiredSdkIndexes) {
|
|
15069
|
+
if (typeof desired.IndexName !== "string") continue;
|
|
15070
|
+
const live = liveByName.get(desired.IndexName);
|
|
15071
|
+
if (!live) continue;
|
|
15072
|
+
const entry = { ...desired };
|
|
15073
|
+
if (!options.carryLiveValues) {
|
|
15074
|
+
baseline.push(entry);
|
|
15075
|
+
continue;
|
|
15076
|
+
}
|
|
15077
|
+
if (options.liveBillingMode === "PROVISIONED") {
|
|
15078
|
+
if (options.uncomparableCapacityIndexNames.has(desired.IndexName)) {
|
|
15079
|
+
baseline.push(entry);
|
|
15080
|
+
continue;
|
|
15081
|
+
}
|
|
15082
|
+
const liveRead = toFiniteNumber(live.ProvisionedThroughput?.ReadCapacityUnits);
|
|
15083
|
+
const liveWrite = toFiniteNumber(live.ProvisionedThroughput?.WriteCapacityUnits);
|
|
15084
|
+
if (desired.ProvisionedThroughput && liveRead !== void 0 && liveWrite !== void 0) entry.ProvisionedThroughput = {
|
|
15085
|
+
ReadCapacityUnits: liveRead,
|
|
15086
|
+
WriteCapacityUnits: liveWrite
|
|
15087
|
+
};
|
|
15088
|
+
} else {
|
|
15089
|
+
const liveRead = toFiniteNumber(live.OnDemandThroughput?.MaxReadRequestUnits);
|
|
15090
|
+
const liveWrite = toFiniteNumber(live.OnDemandThroughput?.MaxWriteRequestUnits);
|
|
15091
|
+
if (liveRead === void 0 && liveWrite === void 0) delete entry.OnDemandThroughput;
|
|
15092
|
+
else entry.OnDemandThroughput = {
|
|
15093
|
+
...liveRead !== void 0 && { MaxReadRequestUnits: liveRead },
|
|
15094
|
+
...liveWrite !== void 0 && { MaxWriteRequestUnits: liveWrite }
|
|
15095
|
+
};
|
|
15096
|
+
}
|
|
15097
|
+
baseline.push(entry);
|
|
15098
|
+
}
|
|
15099
|
+
return baseline;
|
|
15100
|
+
}
|
|
15101
|
+
/**
|
|
14944
15102
|
* Translate a CFn `Replicas[].GlobalSecondaryIndexes[]` blob (the
|
|
14945
15103
|
* `ReplicaGlobalSecondaryIndexSpecification` shape) into the SDK's
|
|
14946
15104
|
* `ReplicaGlobalSecondaryIndex[]` used by `CreateReplicationGroupMemberAction`
|
|
@@ -21781,7 +21939,11 @@ var ApiGatewayV2Provider = class {
|
|
|
21781
21939
|
"Description",
|
|
21782
21940
|
"Tags",
|
|
21783
21941
|
"StageVariables",
|
|
21784
|
-
"DefaultRouteSettings"
|
|
21942
|
+
"DefaultRouteSettings",
|
|
21943
|
+
"AccessLogSettings",
|
|
21944
|
+
"ClientCertificateId",
|
|
21945
|
+
"DeploymentId",
|
|
21946
|
+
"RouteSettings"
|
|
21785
21947
|
])],
|
|
21786
21948
|
["AWS::ApiGatewayV2::Integration", /* @__PURE__ */ new Set([
|
|
21787
21949
|
"ApiId",
|
|
@@ -21800,7 +21962,12 @@ var ApiGatewayV2Provider = class {
|
|
|
21800
21962
|
"AuthorizationType",
|
|
21801
21963
|
"AuthorizerId",
|
|
21802
21964
|
"AuthorizationScopes",
|
|
21803
|
-
"OperationName"
|
|
21965
|
+
"OperationName",
|
|
21966
|
+
"ApiKeyRequired",
|
|
21967
|
+
"ModelSelectionExpression",
|
|
21968
|
+
"RequestModels",
|
|
21969
|
+
"RequestParameters",
|
|
21970
|
+
"RouteResponseSelectionExpression"
|
|
21804
21971
|
])],
|
|
21805
21972
|
["AWS::ApiGatewayV2::Authorizer", /* @__PURE__ */ new Set([
|
|
21806
21973
|
"ApiId",
|
|
@@ -21959,6 +22126,10 @@ var ApiGatewayV2Provider = class {
|
|
|
21959
22126
|
Description: properties["Description"],
|
|
21960
22127
|
StageVariables: properties["StageVariables"],
|
|
21961
22128
|
DefaultRouteSettings: properties["DefaultRouteSettings"],
|
|
22129
|
+
AccessLogSettings: properties["AccessLogSettings"],
|
|
22130
|
+
ClientCertificateId: properties["ClientCertificateId"],
|
|
22131
|
+
DeploymentId: properties["DeploymentId"],
|
|
22132
|
+
RouteSettings: properties["RouteSettings"],
|
|
21962
22133
|
Tags: this.cfnTagsToRecord(properties["Tags"])
|
|
21963
22134
|
}));
|
|
21964
22135
|
this.logger.debug(`Successfully created API Gateway V2 Stage ${logicalId}: ${stageName}`);
|
|
@@ -22056,7 +22227,12 @@ var ApiGatewayV2Provider = class {
|
|
|
22056
22227
|
AuthorizationType: properties["AuthorizationType"],
|
|
22057
22228
|
AuthorizerId: properties["AuthorizerId"],
|
|
22058
22229
|
AuthorizationScopes: properties["AuthorizationScopes"],
|
|
22059
|
-
OperationName: properties["OperationName"]
|
|
22230
|
+
OperationName: properties["OperationName"],
|
|
22231
|
+
ApiKeyRequired: properties["ApiKeyRequired"],
|
|
22232
|
+
ModelSelectionExpression: properties["ModelSelectionExpression"],
|
|
22233
|
+
RequestModels: properties["RequestModels"],
|
|
22234
|
+
RequestParameters: properties["RequestParameters"],
|
|
22235
|
+
RouteResponseSelectionExpression: properties["RouteResponseSelectionExpression"]
|
|
22060
22236
|
}))).RouteId;
|
|
22061
22237
|
this.logger.debug(`Successfully created API Gateway V2 Route ${logicalId}: ${routeId}`);
|
|
22062
22238
|
return {
|
|
@@ -22196,6 +22372,10 @@ var ApiGatewayV2Provider = class {
|
|
|
22196
22372
|
result["Description"] = resp.Description ?? "";
|
|
22197
22373
|
if (resp.StageVariables !== void 0) result["StageVariables"] = resp.StageVariables;
|
|
22198
22374
|
if (resp.DefaultRouteSettings !== void 0) result["DefaultRouteSettings"] = resp.DefaultRouteSettings;
|
|
22375
|
+
if (resp.AccessLogSettings !== void 0) result["AccessLogSettings"] = resp.AccessLogSettings;
|
|
22376
|
+
if (resp.ClientCertificateId !== void 0) result["ClientCertificateId"] = resp.ClientCertificateId;
|
|
22377
|
+
if (properties?.["DeploymentId"] !== void 0 && resp.DeploymentId !== void 0) result["DeploymentId"] = resp.DeploymentId;
|
|
22378
|
+
if (resp.RouteSettings !== void 0) result["RouteSettings"] = resp.RouteSettings;
|
|
22199
22379
|
return result;
|
|
22200
22380
|
} catch (err) {
|
|
22201
22381
|
if (err instanceof NotFoundException$3) return void 0;
|
|
@@ -22241,6 +22421,11 @@ var ApiGatewayV2Provider = class {
|
|
|
22241
22421
|
result["AuthorizationScopes"] = resp.AuthorizationScopes ? [...resp.AuthorizationScopes] : [];
|
|
22242
22422
|
}
|
|
22243
22423
|
if (resp.OperationName !== void 0) result["OperationName"] = resp.OperationName;
|
|
22424
|
+
result["ApiKeyRequired"] = resp.ApiKeyRequired ?? false;
|
|
22425
|
+
if (resp.ModelSelectionExpression !== void 0) result["ModelSelectionExpression"] = resp.ModelSelectionExpression;
|
|
22426
|
+
if (resp.RequestModels !== void 0) result["RequestModels"] = resp.RequestModels;
|
|
22427
|
+
if (resp.RequestParameters !== void 0) result["RequestParameters"] = resp.RequestParameters;
|
|
22428
|
+
if (resp.RouteResponseSelectionExpression !== void 0) result["RouteResponseSelectionExpression"] = resp.RouteResponseSelectionExpression;
|
|
22244
22429
|
return result;
|
|
22245
22430
|
} catch (err) {
|
|
22246
22431
|
if (err instanceof NotFoundException$3) return void 0;
|
|
@@ -22400,8 +22585,11 @@ var ApiGatewayV2Provider = class {
|
|
|
22400
22585
|
* `UpdateStage` keys on `(ApiId, StageName)` — `StageName` is the
|
|
22401
22586
|
* physicalId and immutable. Mutable fields cdkd manages:
|
|
22402
22587
|
* `AutoDeploy` / `Description` / `StageVariables` /
|
|
22403
|
-
* `DefaultRouteSettings
|
|
22404
|
-
*
|
|
22588
|
+
* `DefaultRouteSettings` / `AccessLogSettings` / `ClientCertificateId` /
|
|
22589
|
+
* `DeploymentId` / `RouteSettings`. `ApiId` is also immutable (a stage
|
|
22590
|
+
* cannot be moved between APIs). `AccessLogSettings` and per-key
|
|
22591
|
+
* `RouteSettings` can only be CLEARED through their dedicated delete APIs —
|
|
22592
|
+
* see {@link applyStageRemovals}.
|
|
22405
22593
|
*/
|
|
22406
22594
|
async updateStage(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
22407
22595
|
const apiId = properties["ApiId"] ?? previousProperties["ApiId"];
|
|
@@ -22435,7 +22623,40 @@ var ApiGatewayV2Provider = class {
|
|
|
22435
22623
|
input.DefaultRouteSettings = properties["DefaultRouteSettings"];
|
|
22436
22624
|
changed = true;
|
|
22437
22625
|
}
|
|
22626
|
+
if (properties["AccessLogSettings"] !== void 0 && !this.deepEqual(properties["AccessLogSettings"], previousProperties["AccessLogSettings"])) {
|
|
22627
|
+
input.AccessLogSettings = properties["AccessLogSettings"];
|
|
22628
|
+
changed = true;
|
|
22629
|
+
}
|
|
22630
|
+
const accessLogRemoved = properties["AccessLogSettings"] === void 0 && previousProperties["AccessLogSettings"] !== void 0;
|
|
22631
|
+
if (properties["RouteSettings"] !== void 0 && !this.deepEqual(properties["RouteSettings"], previousProperties["RouteSettings"])) {
|
|
22632
|
+
input.RouteSettings = properties["RouteSettings"];
|
|
22633
|
+
changed = true;
|
|
22634
|
+
}
|
|
22635
|
+
const droppedRouteSettingKeys = this.droppedKeys(properties["RouteSettings"], previousProperties["RouteSettings"]);
|
|
22636
|
+
{
|
|
22637
|
+
const r = this.clearableUpdate(properties["ClientCertificateId"], previousProperties["ClientCertificateId"], "");
|
|
22638
|
+
if (r.changed) {
|
|
22639
|
+
input.ClientCertificateId = r.value;
|
|
22640
|
+
changed = true;
|
|
22641
|
+
}
|
|
22642
|
+
}
|
|
22643
|
+
if (properties["DeploymentId"] !== void 0 && properties["DeploymentId"] !== previousProperties["DeploymentId"]) {
|
|
22644
|
+
input.DeploymentId = properties["DeploymentId"];
|
|
22645
|
+
changed = true;
|
|
22646
|
+
}
|
|
22438
22647
|
if (!changed) {
|
|
22648
|
+
if (accessLogRemoved || droppedRouteSettingKeys.length > 0) {
|
|
22649
|
+
try {
|
|
22650
|
+
await this.applyStageRemovals(apiId, physicalId, accessLogRemoved, droppedRouteSettingKeys);
|
|
22651
|
+
} catch (error) {
|
|
22652
|
+
const cause = error instanceof Error ? error : void 0;
|
|
22653
|
+
throw new ProvisioningError(`Failed to update API Gateway V2 Stage ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
|
|
22654
|
+
}
|
|
22655
|
+
return {
|
|
22656
|
+
physicalId,
|
|
22657
|
+
wasReplaced: false
|
|
22658
|
+
};
|
|
22659
|
+
}
|
|
22439
22660
|
this.logger.debug(`No mutable Stage fields changed for ${logicalId}; skipping UpdateStage`);
|
|
22440
22661
|
return {
|
|
22441
22662
|
physicalId,
|
|
@@ -22445,6 +22666,7 @@ var ApiGatewayV2Provider = class {
|
|
|
22445
22666
|
this.logger.debug(`Updating API Gateway V2 Stage ${logicalId}: ${physicalId}`);
|
|
22446
22667
|
try {
|
|
22447
22668
|
await this.getClient().send(new UpdateStageCommand$1(input));
|
|
22669
|
+
await this.applyStageRemovals(apiId, physicalId, accessLogRemoved, droppedRouteSettingKeys);
|
|
22448
22670
|
return {
|
|
22449
22671
|
physicalId,
|
|
22450
22672
|
wasReplaced: false
|
|
@@ -22525,7 +22747,9 @@ var ApiGatewayV2Provider = class {
|
|
|
22525
22747
|
/**
|
|
22526
22748
|
* `UpdateRoute` keys on `(ApiId, RouteId)`. Mutable fields cdkd
|
|
22527
22749
|
* manages: `RouteKey` / `Target` / `AuthorizationType` /
|
|
22528
|
-
* `AuthorizerId` / `AuthorizationScopes` / `OperationName
|
|
22750
|
+
* `AuthorizerId` / `AuthorizationScopes` / `OperationName` /
|
|
22751
|
+
* `ApiKeyRequired` / `RequestModels` / `RequestParameters` /
|
|
22752
|
+
* `ModelSelectionExpression` / `RouteResponseSelectionExpression`.
|
|
22529
22753
|
*/
|
|
22530
22754
|
async updateRoute(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
22531
22755
|
const apiId = properties["ApiId"] ?? previousProperties["ApiId"];
|
|
@@ -22572,7 +22796,46 @@ var ApiGatewayV2Provider = class {
|
|
|
22572
22796
|
changed = true;
|
|
22573
22797
|
}
|
|
22574
22798
|
}
|
|
22799
|
+
{
|
|
22800
|
+
const r = this.clearableUpdate(properties["ApiKeyRequired"], previousProperties["ApiKeyRequired"], false);
|
|
22801
|
+
if (r.changed) {
|
|
22802
|
+
input.ApiKeyRequired = r.value;
|
|
22803
|
+
changed = true;
|
|
22804
|
+
}
|
|
22805
|
+
}
|
|
22806
|
+
{
|
|
22807
|
+
const merged = this.mapWithRemovals(properties["RequestModels"], previousProperties["RequestModels"]);
|
|
22808
|
+
if (merged !== void 0) {
|
|
22809
|
+
input.RequestModels = merged;
|
|
22810
|
+
changed = true;
|
|
22811
|
+
}
|
|
22812
|
+
}
|
|
22813
|
+
if (properties["RequestParameters"] !== void 0 && !this.deepEqual(properties["RequestParameters"], previousProperties["RequestParameters"])) {
|
|
22814
|
+
input.RequestParameters = properties["RequestParameters"];
|
|
22815
|
+
changed = true;
|
|
22816
|
+
}
|
|
22817
|
+
const droppedRequestParameterKeys = this.droppedKeys(properties["RequestParameters"], previousProperties["RequestParameters"]);
|
|
22818
|
+
if (properties["ModelSelectionExpression"] !== void 0 && properties["ModelSelectionExpression"] !== previousProperties["ModelSelectionExpression"]) {
|
|
22819
|
+
input.ModelSelectionExpression = properties["ModelSelectionExpression"];
|
|
22820
|
+
changed = true;
|
|
22821
|
+
}
|
|
22822
|
+
if (properties["RouteResponseSelectionExpression"] !== void 0 && properties["RouteResponseSelectionExpression"] !== previousProperties["RouteResponseSelectionExpression"]) {
|
|
22823
|
+
input.RouteResponseSelectionExpression = properties["RouteResponseSelectionExpression"];
|
|
22824
|
+
changed = true;
|
|
22825
|
+
}
|
|
22575
22826
|
if (!changed) {
|
|
22827
|
+
if (droppedRequestParameterKeys.length > 0) {
|
|
22828
|
+
try {
|
|
22829
|
+
await this.deleteRouteRequestParameters(apiId, physicalId, droppedRequestParameterKeys);
|
|
22830
|
+
} catch (error) {
|
|
22831
|
+
const cause = error instanceof Error ? error : void 0;
|
|
22832
|
+
throw new ProvisioningError(`Failed to update API Gateway V2 Route ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
|
|
22833
|
+
}
|
|
22834
|
+
return {
|
|
22835
|
+
physicalId,
|
|
22836
|
+
wasReplaced: false
|
|
22837
|
+
};
|
|
22838
|
+
}
|
|
22576
22839
|
this.logger.debug(`No mutable Route fields changed for ${logicalId}; skipping UpdateRoute`);
|
|
22577
22840
|
return {
|
|
22578
22841
|
physicalId,
|
|
@@ -22582,6 +22845,7 @@ var ApiGatewayV2Provider = class {
|
|
|
22582
22845
|
this.logger.debug(`Updating API Gateway V2 Route ${logicalId}: ${physicalId}`);
|
|
22583
22846
|
try {
|
|
22584
22847
|
await this.getClient().send(new UpdateRouteCommand(input));
|
|
22848
|
+
await this.deleteRouteRequestParameters(apiId, physicalId, droppedRequestParameterKeys);
|
|
22585
22849
|
return {
|
|
22586
22850
|
physicalId,
|
|
22587
22851
|
wasReplaced: false
|
|
@@ -22722,16 +22986,85 @@ var ApiGatewayV2Provider = class {
|
|
|
22722
22986
|
};
|
|
22723
22987
|
}
|
|
22724
22988
|
/**
|
|
22725
|
-
*
|
|
22726
|
-
*
|
|
22989
|
+
* Keys present in `previous` but absent from `next` — the set a
|
|
22990
|
+
* merge-semantics map silently keeps unless each is deleted BY NAME. A
|
|
22991
|
+
* whole-block removal (`next` undefined) therefore yields every previous key.
|
|
22992
|
+
*/
|
|
22993
|
+
droppedKeys(next, previous) {
|
|
22994
|
+
if (previous == null || typeof previous !== "object" || Array.isArray(previous)) return [];
|
|
22995
|
+
const prevMap = previous;
|
|
22996
|
+
const nextMap = next != null && typeof next === "object" && !Array.isArray(next) ? next : {};
|
|
22997
|
+
return Object.keys(prevMap).filter((key) => !Object.prototype.hasOwnProperty.call(nextMap, key));
|
|
22998
|
+
}
|
|
22999
|
+
/**
|
|
23000
|
+
* Send a delete that is idempotent by intent.
|
|
23001
|
+
*
|
|
23002
|
+
* These removal deletes run AFTER the merge-Update in the same update, so a
|
|
23003
|
+
* partial failure (throttle on the second of two) leaves state unsaved and
|
|
23004
|
+
* the next deploy recomputes the SAME dropped-key set and re-issues an
|
|
23005
|
+
* already-applied delete. A console-side removal produces the same shape.
|
|
23006
|
+
* Treating NotFound as success is what keeps that from becoming a permanent
|
|
23007
|
+
* failure loop.
|
|
23008
|
+
*/
|
|
23009
|
+
async sendTolerantOfNotFound(send) {
|
|
23010
|
+
try {
|
|
23011
|
+
await send();
|
|
23012
|
+
} catch (error) {
|
|
23013
|
+
if (error instanceof NotFoundException$3) return;
|
|
23014
|
+
throw error;
|
|
23015
|
+
}
|
|
23016
|
+
}
|
|
23017
|
+
/**
|
|
23018
|
+
* The two Stage members `UpdateStage` cannot clear.
|
|
23019
|
+
*
|
|
23020
|
+
* Both MERGE server-side — live-probed 2026-08-11: a stage keeps its
|
|
23021
|
+
* `AccessLogSettings` verbatim through an `UpdateStage` that omits the
|
|
23022
|
+
* member — so a removal that only omits the field is the silent no-op issue
|
|
23023
|
+
* #1160 tracks (access logging, and its billing, keep running). AWS ships
|
|
23024
|
+
* dedicated delete APIs for both; this mirrors the `DeleteCorsConfiguration`
|
|
23025
|
+
* path on `::Api`.
|
|
23026
|
+
*
|
|
23027
|
+
* KNOWN BOUND: `DeleteRouteSettings` removes a whole ROUTE KEY, so dropping
|
|
23028
|
+
* one member INSIDE a kept entry (`LoggingLevel` while `ThrottlingRateLimit`
|
|
23029
|
+
* stays) still merges and survives — the #1225 sub-field class, one level
|
|
23030
|
+
* below what this closes. Same for a partial `AccessLogSettings`.
|
|
23031
|
+
*/
|
|
23032
|
+
async applyStageRemovals(apiId, stageName, accessLogRemoved, droppedRouteSettingKeys) {
|
|
23033
|
+
if (accessLogRemoved) await this.sendTolerantOfNotFound(() => this.getClient().send(new DeleteAccessLogSettingsCommand({
|
|
23034
|
+
ApiId: apiId,
|
|
23035
|
+
StageName: stageName
|
|
23036
|
+
})));
|
|
23037
|
+
for (const routeKey of droppedRouteSettingKeys) await this.sendTolerantOfNotFound(() => this.getClient().send(new DeleteRouteSettingsCommand({
|
|
23038
|
+
ApiId: apiId,
|
|
23039
|
+
StageName: stageName,
|
|
23040
|
+
RouteKey: routeKey
|
|
23041
|
+
})));
|
|
23042
|
+
}
|
|
23043
|
+
/**
|
|
23044
|
+
* `RequestParameters` on a Route is an OBJECT-valued merge map, so a dropped
|
|
23045
|
+
* key needs the per-key delete API (live-probed 2026-08-11:
|
|
23046
|
+
* `DeleteRouteRequestParameter` clears exactly one parameter).
|
|
23047
|
+
*/
|
|
23048
|
+
async deleteRouteRequestParameters(apiId, routeId, droppedKeys) {
|
|
23049
|
+
for (const key of droppedKeys) await this.sendTolerantOfNotFound(() => this.getClient().send(new DeleteRouteRequestParameterCommand({
|
|
23050
|
+
ApiId: apiId,
|
|
23051
|
+
RouteId: routeId,
|
|
23052
|
+
RequestParameterKey: key
|
|
23053
|
+
})));
|
|
23054
|
+
}
|
|
23055
|
+
/**
|
|
23056
|
+
* Resolve a `Record<string, string>` update field (`StageVariables`, Route
|
|
23057
|
+
* `RequestModels`, Integration `RequestParameters`) with per-key removal
|
|
23058
|
+
* awareness.
|
|
22727
23059
|
*
|
|
22728
23060
|
* These maps also merge on the AWS side: sending `{}` (or a map missing
|
|
22729
23061
|
* a previously-present key) does NOT delete the dropped key — it is kept
|
|
22730
|
-
* live. Live-probed 2026-07-22
|
|
22731
|
-
* an empty-string value. So the
|
|
22732
|
-
*
|
|
22733
|
-
* removal (next `undefined`, previous
|
|
22734
|
-
* old key as `''`. Returns `undefined` when
|
|
23062
|
+
* live. Live-probed 2026-07-22 (and again 2026-08-11 for `RequestModels`):
|
|
23063
|
+
* a key is cleared only by sending it with an empty-string value. So the
|
|
23064
|
+
* resolved map is `next` plus every key present in `previous` but absent
|
|
23065
|
+
* from `next`, set to `''`. Whole-block removal (next `undefined`, previous
|
|
23066
|
+
* populated) therefore sends every old key as `''`. Returns `undefined` when
|
|
23067
|
+
* nothing changed.
|
|
22735
23068
|
*/
|
|
22736
23069
|
mapWithRemovals(next, previous) {
|
|
22737
23070
|
if (this.deepEqual(next, previous)) return void 0;
|
|
@@ -68374,7 +68707,7 @@ function createMigrateCommand() {
|
|
|
68374
68707
|
*/
|
|
68375
68708
|
function buildProgram() {
|
|
68376
68709
|
const program = new Command();
|
|
68377
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.280.
|
|
68710
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.280.5");
|
|
68378
68711
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
68379
68712
|
const { profile } = actionCommand.optsWithGlobals();
|
|
68380
68713
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|