@go-to-k/cdkd 0.200.0 → 0.201.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-DWUnLza1.js";
|
|
3
|
-
import { $ as uploadCfnTemplate, A as S3StateBackend, At as PATTERN_B_NAME_PROPERTIES, B as Synthesizer, C as assertRegionMatch, Ct as normalizeAwsError, D as DagBuilder, E as DiffCalculator, Et as getLogger, F as buildDockerImage, Ft as withStackName, G as resolveSkipPrefix, H as getLegacyStateBucketName, I as formatDockerLoginError, J as warnDeprecatedNoPrefixCliFlag, K as resolveStateBucketWithDefault, L as getDockerCmd, M as AssetPublisher, Mt as generateResourceName, N as stringifyValue, Nt as generateResourceNameWithFallback, O as TemplateParser, Ot as runStackBuffered, P as WorkGraph, Pt as withSkipPrefix, Q as findLargeInlineResources, R as runDockerForeground, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveApp, V as getDefaultStateBucketName, W as resolveCaptureObservedState, X as CFN_TEMPLATE_URL_LIMIT, Y as CFN_TEMPLATE_BODY_LIMIT, Z as MIGRATE_TMP_PREFIX, _ as matchesCdkPath, _t as StackHasActiveImportsError, a as withRetry, b as ProviderRegistry, c as bold, ct as LocalMigrateError, d as green, dt as MissingCdkCliError, et as AssemblyReader, f as red, ft as NestedStackChildDirectDestroyError, g as CDK_PATH_TAG, gt as ResourceUpdateNotSupportedError, h as collectInlinePolicyNamesManagedBySiblings, ht as ResourceTimeoutError, i as withResourceDeadline, it as CdkdError, j as shouldRetainResource, jt as PATTERN_B_RESOURCE_TYPES, k as LockManager, kt as getLiveRenderer, l as cyan, lt as LocalStartServiceError, m as IAMRoleProvider, mt as ProvisioningError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as resolveBucketRegion, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as PartialFailureError, q as resolveStateBucketWithDefaultAndSource, r as DeployEngine, s as formatResourceLine, st as LocalInvokeBuildError$1, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, v as normalizeAwsTagsToCfn, vt as StackTerminationProtectionError, w as IntrinsicFunctionResolver, wt as withErrorHandling, x as findActionableSilentDrops, y as resolveExplicitPhysicalId, z as runDockerStreaming } from "./deploy-engine-
|
|
3
|
+
import { $ as uploadCfnTemplate, A as S3StateBackend, At as PATTERN_B_NAME_PROPERTIES, B as Synthesizer, C as assertRegionMatch, Ct as normalizeAwsError, D as DagBuilder, E as DiffCalculator, Et as getLogger, F as buildDockerImage, Ft as withStackName, G as resolveSkipPrefix, H as getLegacyStateBucketName, I as formatDockerLoginError, J as warnDeprecatedNoPrefixCliFlag, K as resolveStateBucketWithDefault, L as getDockerCmd, M as AssetPublisher, Mt as generateResourceName, N as stringifyValue, Nt as generateResourceNameWithFallback, O as TemplateParser, Ot as runStackBuffered, P as WorkGraph, Pt as withSkipPrefix, Q as findLargeInlineResources, R as runDockerForeground, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveApp, V as getDefaultStateBucketName, W as resolveCaptureObservedState, X as CFN_TEMPLATE_URL_LIMIT, Y as CFN_TEMPLATE_BODY_LIMIT, Z as MIGRATE_TMP_PREFIX, _ as matchesCdkPath, _t as StackHasActiveImportsError, a as withRetry, b as ProviderRegistry, c as bold, ct as LocalMigrateError, d as green, dt as MissingCdkCliError, et as AssemblyReader, f as red, ft as NestedStackChildDirectDestroyError, g as CDK_PATH_TAG, gt as ResourceUpdateNotSupportedError, h as collectInlinePolicyNamesManagedBySiblings, ht as ResourceTimeoutError, i as withResourceDeadline, it as CdkdError, j as shouldRetainResource, jt as PATTERN_B_RESOURCE_TYPES, k as LockManager, kt as getLiveRenderer, l as cyan, lt as LocalStartServiceError, m as IAMRoleProvider, mt as ProvisioningError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as resolveBucketRegion, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as PartialFailureError, q as resolveStateBucketWithDefaultAndSource, r as DeployEngine, s as formatResourceLine, st as LocalInvokeBuildError$1, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, v as normalizeAwsTagsToCfn, vt as StackTerminationProtectionError, w as IntrinsicFunctionResolver, wt as withErrorHandling, x as findActionableSilentDrops, y as resolveExplicitPhysicalId, z as runDockerStreaming } from "./deploy-engine-5CVA5VWR.js";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
6
6
|
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, ListBucketsCommand, ListDirectoryBucketsCommand, 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";
|
|
@@ -58,7 +58,7 @@ import { CreateDeliveryStreamCommand, DeleteDeliveryStreamCommand, DescribeDeliv
|
|
|
58
58
|
import { AddTagsCommand as AddTagsCommand$1, CloudTrailClient, CreateTrailCommand, DeleteTrailCommand, GetEventSelectorsCommand, GetInsightSelectorsCommand, GetTrailCommand, GetTrailStatusCommand, ListTagsCommand as ListTagsCommand$1, ListTrailsCommand, PutEventSelectorsCommand, PutInsightSelectorsCommand, RemoveTagsCommand as RemoveTagsCommand$1, StartLoggingCommand, StopLoggingCommand, TrailNotFoundException, UpdateTrailCommand } from "@aws-sdk/client-cloudtrail";
|
|
59
59
|
import { BatchGetProjectsCommand, CodeBuildClient, CreateProjectCommand, DeleteProjectCommand, ListProjectsCommand, ResourceNotFoundException as ResourceNotFoundException$10, UpdateProjectCommand } from "@aws-sdk/client-codebuild";
|
|
60
60
|
import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketCommand, GetVectorBucketCommand, ListIndexesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$18, ListVectorBucketsCommand, S3VectorsClient } from "@aws-sdk/client-s3vectors";
|
|
61
|
-
import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand as ListTablesCommand$1, ListTagsForResourceCommand as ListTagsForResourceCommand$19, NotFoundException as NotFoundException$5, S3TablesClient } from "@aws-sdk/client-s3tables";
|
|
61
|
+
import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand as ListTablesCommand$1, ListTagsForResourceCommand as ListTagsForResourceCommand$19, NotFoundException as NotFoundException$5, S3TablesClient, TagResourceCommand as TagResourceCommand$16, UntagResourceCommand as UntagResourceCommand$15 } from "@aws-sdk/client-s3tables";
|
|
62
62
|
import { AttachLoadBalancerTargetGroupsCommand, AttachLoadBalancersCommand, AttachTrafficSourcesCommand, AutoScalingClient, CreateAutoScalingGroupCommand, CreateOrUpdateTagsCommand, DeleteAutoScalingGroupCommand, DeleteLifecycleHookCommand, DeleteNotificationConfigurationCommand, DeleteTagsCommand as DeleteTagsCommand$1, DescribeAutoScalingGroupsCommand, DescribeLifecycleHooksCommand, DescribeNotificationConfigurationsCommand, DescribeTrafficSourcesCommand, DetachLoadBalancerTargetGroupsCommand, DetachLoadBalancersCommand, DetachTrafficSourcesCommand, DisableMetricsCollectionCommand, EnableMetricsCollectionCommand, PutLifecycleHookCommand, PutNotificationConfigurationCommand, UpdateAutoScalingGroupCommand } from "@aws-sdk/client-auto-scaling";
|
|
63
63
|
import { Document, Pair, Scalar, YAMLMap, YAMLSeq, parse as parse$1, stringify } from "yaml";
|
|
64
64
|
import { createLocalStateProvider, getEmbedConfig, isCfnFlagPresent, listTargets, rejectExplicitCfnStackWithMultipleStacks, resolveCfnFallbackRegion, setEmbedConfig, substituteAgainstState, substituteAgainstStateAsync, substituteEnvVarsFromState, substituteEnvVarsFromStateAsync } from "cdk-local";
|
|
@@ -17236,7 +17236,7 @@ var CloudFrontDistributionProvider = class {
|
|
|
17236
17236
|
const getResponse = await this.cloudFrontClient.send(new GetDistributionCommand({ Id: physicalId }));
|
|
17237
17237
|
const domainName = getResponse.Distribution?.DomainName ?? "";
|
|
17238
17238
|
const arn = getResponse.Distribution?.ARN;
|
|
17239
|
-
await this.
|
|
17239
|
+
await this.applyTagDiff(arn, previousProperties["Tags"], properties["Tags"], physicalId, logicalId, resourceType);
|
|
17240
17240
|
this.logger.debug(`Updated CloudFront Distribution ${physicalId}`);
|
|
17241
17241
|
return {
|
|
17242
17242
|
physicalId,
|
|
@@ -17489,32 +17489,44 @@ var CloudFrontDistributionProvider = class {
|
|
|
17489
17489
|
};
|
|
17490
17490
|
}
|
|
17491
17491
|
/**
|
|
17492
|
-
* Apply a tag diff to a distribution
|
|
17492
|
+
* Apply a tag diff to a distribution.
|
|
17493
17493
|
*
|
|
17494
17494
|
* CloudFront has no atomic overlay API for tags — `TagResource` adds /
|
|
17495
17495
|
* overwrites and `UntagResource` removes. Run the removal first, then
|
|
17496
17496
|
* the upsert, so a same-key value rewrite (which lands in `upserts`)
|
|
17497
17497
|
* is not accidentally cleared by a stale Untag.
|
|
17498
17498
|
*
|
|
17499
|
-
* Errors are
|
|
17500
|
-
*
|
|
17501
|
-
*
|
|
17502
|
-
*
|
|
17503
|
-
*
|
|
17499
|
+
* Errors are RETHROWN as `ProvisioningError` (issue #740 fix) so the
|
|
17500
|
+
* deploy engine sees a failed update() and (a) does NOT write the new
|
|
17501
|
+
* properties.Tags into state — the next deploy retries the tag-diff
|
|
17502
|
+
* against the still-old state, (b) surfaces the failure to the user
|
|
17503
|
+
* via the standard error path. The deploy engine's `withRetry` MAY
|
|
17504
|
+
* pick up some transient AWS errors via the cause-message-pattern
|
|
17505
|
+
* match (`retryable-errors.ts`'s `RETRYABLE_ERROR_MESSAGE_PATTERNS`),
|
|
17506
|
+
* but bare HTTP 429 throttles wrapped by update()'s outer catch reach
|
|
17507
|
+
* the classifier two levels deep and slip past its single-level
|
|
17508
|
+
* `.cause` walk — so the **load-bearing retry guarantee is the
|
|
17509
|
+
* next-deploy retry**, not in-deploy retry. This is acceptable: the
|
|
17510
|
+
* user sees the failure, can react, and the next `cdkd deploy`
|
|
17511
|
+
* re-fires the tag-diff against the still-old state cleanly.
|
|
17512
|
+
*
|
|
17513
|
+
* Trade-off: a tag-side failure flips an otherwise-successful
|
|
17514
|
+
* `UpdateDistribution` into a deploy failure, and the retry will
|
|
17515
|
+
* re-issue UpdateDistribution against the (now-current) config —
|
|
17516
|
+
* AWS accepts the no-op idempotently. The cost of that secondary
|
|
17517
|
+
* noise is much lower than the cost of silent tag drift the pre-#740
|
|
17518
|
+
* swallow caused.
|
|
17504
17519
|
*
|
|
17505
17520
|
* The ARN is unexpectedly absent only on a hypothetical SDK regression
|
|
17506
17521
|
* (`GetDistribution` returns ARN as a required string in every SDK
|
|
17507
17522
|
* shape verified so far). When that happens AND a tag delta exists,
|
|
17508
|
-
*
|
|
17509
|
-
*
|
|
17523
|
+
* THROW so the silent-drop does not silently resurface; when no delta
|
|
17524
|
+
* exists, return without needing ARN.
|
|
17510
17525
|
*/
|
|
17511
|
-
async
|
|
17526
|
+
async applyTagDiff(arn, previousTags, newTags, physicalId, logicalId, resourceType) {
|
|
17512
17527
|
const { removed, upserts } = this.computeTagDiff(previousTags, newTags);
|
|
17513
17528
|
if (removed.length === 0 && upserts.length === 0) return;
|
|
17514
|
-
if (!arn) {
|
|
17515
|
-
this.logger.warn(`CloudFront Distribution ${physicalId}: GetDistribution returned no ARN; skipping tag diff (removed=${removed.length}, upserts=${upserts.length}). Tags on AWS may drift from the template.`);
|
|
17516
|
-
return;
|
|
17517
|
-
}
|
|
17529
|
+
if (!arn) throw new ProvisioningError(`CloudFront Distribution ${physicalId}: GetDistribution returned no ARN; cannot apply tag diff (removed=${removed.length}, upserts=${upserts.length}). Refusing to silently drop the tag update — retry on next deploy or check SDK version.`, resourceType, logicalId, physicalId);
|
|
17518
17530
|
try {
|
|
17519
17531
|
if (removed.length > 0) {
|
|
17520
17532
|
this.logger.debug(`Untagging CloudFront Distribution ${arn}: ${removed.join(", ")}`);
|
|
@@ -17531,7 +17543,8 @@ var CloudFrontDistributionProvider = class {
|
|
|
17531
17543
|
}));
|
|
17532
17544
|
}
|
|
17533
17545
|
} catch (err) {
|
|
17534
|
-
|
|
17546
|
+
const cause = err instanceof Error ? err : void 0;
|
|
17547
|
+
throw new ProvisioningError(`CloudFront Distribution ${physicalId}: tag diff failed (removed=${removed.length}, upserts=${upserts.length}): ${err instanceof Error ? err.message : String(err)}. UpdateDistribution succeeded but TagResource/UntagResource did not — state has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause);
|
|
17535
17548
|
}
|
|
17536
17549
|
}
|
|
17537
17550
|
/**
|
|
@@ -32005,7 +32018,9 @@ var S3TablesProvider = class {
|
|
|
32005
32018
|
"Namespace",
|
|
32006
32019
|
"TableName",
|
|
32007
32020
|
"Name",
|
|
32008
|
-
"
|
|
32021
|
+
"OpenTableFormat",
|
|
32022
|
+
"Format",
|
|
32023
|
+
"Tags"
|
|
32009
32024
|
])]
|
|
32010
32025
|
]);
|
|
32011
32026
|
getClient() {
|
|
@@ -32020,12 +32035,13 @@ var S3TablesProvider = class {
|
|
|
32020
32035
|
default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId);
|
|
32021
32036
|
}
|
|
32022
32037
|
}
|
|
32023
|
-
update(logicalId, physicalId, resourceType,
|
|
32024
|
-
this.
|
|
32025
|
-
|
|
32038
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
32039
|
+
if (resourceType === "AWS::S3Tables::Table") await this.applyTableTagsDiff(logicalId, physicalId, resourceType, previousProperties["Tags"], properties["Tags"]);
|
|
32040
|
+
else this.logger.debug(`Update is no-op for ${resourceType} ${logicalId}`);
|
|
32041
|
+
return {
|
|
32026
32042
|
physicalId,
|
|
32027
32043
|
wasReplaced: false
|
|
32028
|
-
}
|
|
32044
|
+
};
|
|
32029
32045
|
}
|
|
32030
32046
|
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
32031
32047
|
switch (resourceType) {
|
|
@@ -32121,9 +32137,11 @@ var S3TablesProvider = class {
|
|
|
32121
32137
|
this.logger.debug(`Creating S3 Tables Namespace ${logicalId}`);
|
|
32122
32138
|
const tableBucketARN = properties["TableBucketARN"];
|
|
32123
32139
|
if (!tableBucketARN) throw new ProvisioningError(`TableBucketARN is required for S3 Tables Namespace ${logicalId}`, resourceType, logicalId);
|
|
32124
|
-
const
|
|
32125
|
-
|
|
32126
|
-
|
|
32140
|
+
const rawNs = properties["Namespace"];
|
|
32141
|
+
let namespaceName;
|
|
32142
|
+
if (Array.isArray(rawNs) && rawNs.length > 0 && typeof rawNs[0] === "string") namespaceName = rawNs[0];
|
|
32143
|
+
else if (typeof rawNs === "string" && rawNs.length > 0) namespaceName = rawNs;
|
|
32144
|
+
if (!namespaceName) throw new ProvisioningError(`Namespace is required for S3 Tables Namespace ${logicalId}`, resourceType, logicalId);
|
|
32127
32145
|
try {
|
|
32128
32146
|
await this.getClient().send(new CreateNamespaceCommand({
|
|
32129
32147
|
tableBucketARN,
|
|
@@ -32168,20 +32186,24 @@ var S3TablesProvider = class {
|
|
|
32168
32186
|
if (!namespace) throw new ProvisioningError(`Namespace is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
|
|
32169
32187
|
const name = properties["TableName"] ?? properties["Name"];
|
|
32170
32188
|
if (!name) throw new ProvisioningError(`TableName is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
|
|
32171
|
-
const format = properties["Format"];
|
|
32172
|
-
if (!format) throw new ProvisioningError(`
|
|
32189
|
+
const format = properties["OpenTableFormat"] ?? properties["Format"];
|
|
32190
|
+
if (!format) throw new ProvisioningError(`OpenTableFormat is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
|
|
32191
|
+
const tags = this.cfnTagsToSdkMap(properties["Tags"]);
|
|
32173
32192
|
try {
|
|
32174
|
-
await this.getClient().send(new CreateTableCommand$2({
|
|
32193
|
+
const response = await this.getClient().send(new CreateTableCommand$2({
|
|
32175
32194
|
tableBucketARN,
|
|
32176
32195
|
namespace,
|
|
32177
32196
|
name,
|
|
32178
|
-
format
|
|
32197
|
+
format,
|
|
32198
|
+
...tags !== void 0 && { tags }
|
|
32179
32199
|
}));
|
|
32180
32200
|
const physicalId = `${tableBucketARN}|${namespace}|${name}`;
|
|
32201
|
+
if (!response.tableARN) throw new ProvisioningError(`CreateTable did not return a tableARN for ${logicalId} (${physicalId}) — refusing to record an empty TableARN attribute`, resourceType, logicalId, physicalId);
|
|
32202
|
+
const tableARN = response.tableARN;
|
|
32181
32203
|
this.logger.debug(`Successfully created S3 Tables Table ${logicalId}: ${physicalId}`);
|
|
32182
32204
|
return {
|
|
32183
32205
|
physicalId,
|
|
32184
|
-
attributes: {}
|
|
32206
|
+
attributes: { TableARN: tableARN }
|
|
32185
32207
|
};
|
|
32186
32208
|
} catch (error) {
|
|
32187
32209
|
const cause = error instanceof Error ? error : void 0;
|
|
@@ -32233,7 +32255,7 @@ var S3TablesProvider = class {
|
|
|
32233
32255
|
if (!tableBucketARN || !namespaceName) return void 0;
|
|
32234
32256
|
return {
|
|
32235
32257
|
TableBucketARN: tableBucketARN,
|
|
32236
|
-
Namespace:
|
|
32258
|
+
Namespace: namespaceName
|
|
32237
32259
|
};
|
|
32238
32260
|
}
|
|
32239
32261
|
async readTableCurrentState(physicalId) {
|
|
@@ -32259,7 +32281,11 @@ var S3TablesProvider = class {
|
|
|
32259
32281
|
Name: tableNameValue,
|
|
32260
32282
|
TableName: tableNameValue
|
|
32261
32283
|
};
|
|
32262
|
-
if (resp.format !== void 0)
|
|
32284
|
+
if (resp.format !== void 0) {
|
|
32285
|
+
result["OpenTableFormat"] = resp.format;
|
|
32286
|
+
result["Format"] = resp.format;
|
|
32287
|
+
}
|
|
32288
|
+
result["Tags"] = resp.tableARN ? await this.readTagsBestEffort(resp.tableARN) : [];
|
|
32263
32289
|
return result;
|
|
32264
32290
|
}
|
|
32265
32291
|
/**
|
|
@@ -32416,6 +32442,131 @@ var S3TablesProvider = class {
|
|
|
32416
32442
|
throw new ProvisioningError(`Failed to delete S3 Tables Table ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
|
|
32417
32443
|
}
|
|
32418
32444
|
}
|
|
32445
|
+
/**
|
|
32446
|
+
* Convert CFn `Tags: [{ Key, Value }]` to the S3Tables SDK's
|
|
32447
|
+
* `Record<string, string>` shape. Returns `undefined` when the input
|
|
32448
|
+
* is absent, empty, or invalid (so the caller can omit the field
|
|
32449
|
+
* from CreateTableCommand — the SDK rejects an empty `tags: {}` map
|
|
32450
|
+
* with InvalidRequestException). Entries missing a `Key` are skipped;
|
|
32451
|
+
* a missing `Value` is normalized to `''` (matches the on-AWS
|
|
32452
|
+
* representation — empty-string tag values are legal).
|
|
32453
|
+
*/
|
|
32454
|
+
cfnTagsToSdkMap(value) {
|
|
32455
|
+
if (!Array.isArray(value) || value.length === 0) return void 0;
|
|
32456
|
+
const map = {};
|
|
32457
|
+
for (const entry of value) {
|
|
32458
|
+
if (!entry || typeof entry !== "object") continue;
|
|
32459
|
+
const key = entry.Key;
|
|
32460
|
+
if (typeof key !== "string" || key.length === 0) continue;
|
|
32461
|
+
const raw = entry.Value;
|
|
32462
|
+
if (typeof raw === "string") map[key] = raw;
|
|
32463
|
+
else if (raw === void 0 || raw === null) map[key] = "";
|
|
32464
|
+
else if (typeof raw === "number" || typeof raw === "boolean") map[key] = String(raw);
|
|
32465
|
+
else continue;
|
|
32466
|
+
}
|
|
32467
|
+
return Object.keys(map).length > 0 ? map : void 0;
|
|
32468
|
+
}
|
|
32469
|
+
/**
|
|
32470
|
+
* Look up a table's real AWS ARN given its cdkd-compound physical
|
|
32471
|
+
* id parts. The real ARN is opaque (NOT `<bucketArn>/table/<ns>/<name>`
|
|
32472
|
+
* — that shape returns BadRequestException) and only AWS knows it,
|
|
32473
|
+
* so we call `GetTable` and pull `tableARN` from the response. Used
|
|
32474
|
+
* by the tag-diff path in update() and the readback's tag-fetch leg.
|
|
32475
|
+
* Returns null if the table is gone (NotFoundException → caller can
|
|
32476
|
+
* skip the tag op gracefully).
|
|
32477
|
+
*/
|
|
32478
|
+
async lookupTableArn(tableBucketARN, namespace, name) {
|
|
32479
|
+
try {
|
|
32480
|
+
return (await this.getClient().send(new GetTableCommand$1({
|
|
32481
|
+
tableBucketARN,
|
|
32482
|
+
namespace,
|
|
32483
|
+
name
|
|
32484
|
+
}))).tableARN ?? null;
|
|
32485
|
+
} catch (err) {
|
|
32486
|
+
if (err instanceof NotFoundException$5) return null;
|
|
32487
|
+
throw err;
|
|
32488
|
+
}
|
|
32489
|
+
}
|
|
32490
|
+
/**
|
|
32491
|
+
* Best-effort tag readback. ListTagsForResource against a freshly-
|
|
32492
|
+
* created table can briefly 404 due to eventual consistency; emit
|
|
32493
|
+
* `[]` on any failure rather than propagate (matches the S3Vectors /
|
|
32494
|
+
* CloudFront patterns and keeps the drift comparator happy).
|
|
32495
|
+
*/
|
|
32496
|
+
async readTagsBestEffort(resourceArn) {
|
|
32497
|
+
try {
|
|
32498
|
+
const tags = (await this.getClient().send(new ListTagsForResourceCommand$19({ resourceArn }))).tags ?? {};
|
|
32499
|
+
const out = [];
|
|
32500
|
+
for (const [Key, Value] of Object.entries(tags)) out.push({
|
|
32501
|
+
Key,
|
|
32502
|
+
Value
|
|
32503
|
+
});
|
|
32504
|
+
return out;
|
|
32505
|
+
} catch (err) {
|
|
32506
|
+
this.logger.debug(`readTagsBestEffort: ListTagsForResource failed for ${resourceArn}: ${err instanceof Error ? err.message : String(err)} — emitting Tags: []`);
|
|
32507
|
+
return [];
|
|
32508
|
+
}
|
|
32509
|
+
}
|
|
32510
|
+
/**
|
|
32511
|
+
* Apply a tag-diff against a Table resource ARN: keys present in
|
|
32512
|
+
* `previousTags` but absent / value-changed in `newTags` go through
|
|
32513
|
+
* `UntagResource`, then the full upsert set (additions + value
|
|
32514
|
+
* rewrites) goes through `TagResource`. Removal runs FIRST so a
|
|
32515
|
+
* value-only rewrite on key K isn't accidentally cleared by a stale
|
|
32516
|
+
* UntagResource pass (matches the CloudFront / S3Vectors pattern).
|
|
32517
|
+
*
|
|
32518
|
+
* Tag-side failures THROW `ProvisioningError` (issue #740 fix): a
|
|
32519
|
+
* silent swallow would let the deploy engine write the new properties.Tags
|
|
32520
|
+
* to state as if applied, and the next deploy's diff (template Tags
|
|
32521
|
+
* vs new state Tags) sees no change → tag-diff never re-fires → AWS
|
|
32522
|
+
* tags stay stale forever. Throwing means: (a) state is NOT written,
|
|
32523
|
+
* (b) the next deploy retries the tag-diff against the still-old
|
|
32524
|
+
* state. The deploy engine's `withRetry` MAY pick up transient AWS
|
|
32525
|
+
* errors via the cause-message-pattern match in `retryable-errors.ts`,
|
|
32526
|
+
* but bare HTTP 429 throttles can slip past the classifier's
|
|
32527
|
+
* single-level `.cause` walk depending on wrapping — so the
|
|
32528
|
+
* **load-bearing retry guarantee is the next-deploy retry**, not
|
|
32529
|
+
* in-deploy retry. For the S3Tables Table case `update()` is
|
|
32530
|
+
* otherwise a no-op (the Table itself is immutable), so a tag-side
|
|
32531
|
+
* throw cleanly turns the whole update into a retry without
|
|
32532
|
+
* side-effects.
|
|
32533
|
+
*
|
|
32534
|
+
* The malformed-physicalId / GetTable-NotFound branches throw too
|
|
32535
|
+
* — both indicate a state-vs-AWS divergence the user needs to see,
|
|
32536
|
+
* not silently skip past.
|
|
32537
|
+
*/
|
|
32538
|
+
async applyTableTagsDiff(logicalId, physicalId, resourceType, previousTags, newTags) {
|
|
32539
|
+
const prev = this.cfnTagsToSdkMap(previousTags) ?? {};
|
|
32540
|
+
const next = this.cfnTagsToSdkMap(newTags) ?? {};
|
|
32541
|
+
const removedKeys = Object.keys(prev).filter((k) => !(k in next));
|
|
32542
|
+
const upserts = {};
|
|
32543
|
+
for (const [k, v] of Object.entries(next)) if (prev[k] !== v) upserts[k] = v;
|
|
32544
|
+
if (removedKeys.length === 0 && Object.keys(upserts).length === 0) return;
|
|
32545
|
+
const parts = physicalId.split("|");
|
|
32546
|
+
if (parts.length < 3) throw new ProvisioningError(`applyTableTagsDiff: cannot derive table ARN from physicalId '${physicalId}' (expected '<bucketArn>|<namespace>|<name>') — refusing to silently drop the tag update`, resourceType, logicalId, physicalId);
|
|
32547
|
+
const [tableBucketARN, namespace, name] = parts;
|
|
32548
|
+
if (!tableBucketARN || !namespace || !name) throw new ProvisioningError(`applyTableTagsDiff: cannot derive table ARN from malformed physicalId '${physicalId}' (empty part after split) — refusing to silently drop the tag update`, resourceType, logicalId, physicalId);
|
|
32549
|
+
const resourceArn = await this.lookupTableArn(tableBucketARN, namespace, name);
|
|
32550
|
+
if (!resourceArn) throw new ProvisioningError(`applyTableTagsDiff: GetTable returned no tableARN for ${physicalId} — table is gone or state is out-of-sync. Refusing to silently drop the tag update (run 'cdkd state orphan ${logicalId}' to clean up if the table was deleted out-of-band).`, resourceType, logicalId, physicalId);
|
|
32551
|
+
if (removedKeys.length > 0) try {
|
|
32552
|
+
await this.getClient().send(new UntagResourceCommand$15({
|
|
32553
|
+
resourceArn,
|
|
32554
|
+
tagKeys: removedKeys
|
|
32555
|
+
}));
|
|
32556
|
+
} catch (err) {
|
|
32557
|
+
const cause = err instanceof Error ? err : void 0;
|
|
32558
|
+
throw new ProvisioningError(`applyTableTagsDiff: UntagResource failed for ${resourceArn} (keys: ${removedKeys.join(", ")}): ${err instanceof Error ? err.message : String(err)}. State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause);
|
|
32559
|
+
}
|
|
32560
|
+
if (Object.keys(upserts).length > 0) try {
|
|
32561
|
+
await this.getClient().send(new TagResourceCommand$16({
|
|
32562
|
+
resourceArn,
|
|
32563
|
+
tags: upserts
|
|
32564
|
+
}));
|
|
32565
|
+
} catch (err) {
|
|
32566
|
+
const cause = err instanceof Error ? err : void 0;
|
|
32567
|
+
throw new ProvisioningError(`applyTableTagsDiff: TagResource failed for ${resourceArn} (keys: ${Object.keys(upserts).join(", ")}): ${err instanceof Error ? err.message : String(err)}. State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause);
|
|
32568
|
+
}
|
|
32569
|
+
}
|
|
32419
32570
|
};
|
|
32420
32571
|
|
|
32421
32572
|
//#endregion
|
|
@@ -51726,7 +51877,7 @@ function reorderArgs(argv) {
|
|
|
51726
51877
|
*/
|
|
51727
51878
|
async function main() {
|
|
51728
51879
|
const program = new Command();
|
|
51729
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
51880
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.201.1");
|
|
51730
51881
|
program.addCommand(createBootstrapCommand());
|
|
51731
51882
|
program.addCommand(createSynthCommand());
|
|
51732
51883
|
program.addCommand(createListCommand());
|