@go-to-k/cdkd 0.275.1 → 0.275.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { $ as WorkGraph, A as slowCcOperationTimeoutMs, At as warnDeprecatedNoPrefixCliFlag, B as applyRoleArnIfSet, Bt as resolveBucketRegion, C as yellow, Ct as resolveAutoAssetStorage, D as ProviderRegistry, Dt as resolveStateBucketWithDefaultAndSource, E as clearOnUpdateRemoval, Et as resolveStateBucketWithDefault, F as refStateLookupFromResource, Ft as uploadCfnTemplate, G as DagBuilder, H as describeTypeWithThrottleRetry, Ht as getAwsClients, I as WAFv2WebACLProvider, It as expectedOwnerParam, J as S3StateBackend, K as TemplateParser, Kt as CdkdError, L as normalizeAwsTagsToCfn, Lt as AssemblyReader, M as isTerminationProtectionPropagationError, Mt as CFN_TEMPLATE_URL_LIMIT, N as IntrinsicFunctionResolver, Nt as MIGRATE_TMP_PREFIX, O as findActionableSilentDrops, Ot as resolveUseCdkBootstrapAssets, P as cfnRefValueFromPhysicalId, Pt as findLargeInlineResources, Q as stringifyValue, Qt as LocalStartServiceError, R as resolveExplicitPhysicalId, Rt as processStackMessages, S as red, St as resolveApp, T as collectInlinePolicyNamesManagedBySiblings, Tt as resolveSkipPrefix, U as withRetry, Ut as resetAwsClients, V as DiffCalculator, Vt as AwsClients, W as isRetryableTransientError, Wt as setAwsClients, X as shouldRetainResource, Xt as LocalInvokeBuildError$1, Y as rebuildClientForBucketRegion, Yt as DeployCancelledError, Z as AssetPublisher, Zt as LocalMigrateError, _ as formatResourceLine, _t as getDockerImageBySourceHash, a as DeploymentEventsStore, an as ResourceUpdateNotSupportedError, at as BOOTSTRAP_MARKER_PREFIX, b as gray, bt as getDefaultStateBucketName, c as replayFailedOperations, ct as parseBootstrapMarker, d as IMPLICIT_DELETE_DEPENDENCIES, dt as buildDockerImage, en as MissingCdkCliError, et as buildAssetRedirectMap, f as computeImplicitDeleteEdges, fn as normalizeAwsError, ft as formatDockerLoginError, g as renderStatefulReason, gt as AssetManifestLoader, h as isStatefulRecreateTargetSync, ht as runDockerStreaming, i as DeploymentEventsReader, in as ResourceTimeoutError, it as AssetModeResolver, j as disableInstanceApiTermination, jt as CFN_TEMPLATE_BODY_LIMIT, k as CloudControlProvider, kt as stateBucketExistenceConfirmed, l as replayRollback, lt as validateAssetBucketName, m as MULTI_REGION_RECREATE_BLOCKED_TYPES, mt as runDockerForeground, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as PartialFailureError, nt as loadPublishableAssetManifest, o as planFailedOps, on as StackHasActiveImportsError, ot as ensureAssetStorage, p as extractDeploymentEventError, pn as withErrorHandling, pt as getDockerCmd, q as LockManager, r as DeployEngine, rn as ProvisioningError, rt as rewriteTemplateAssetReferences, s as planRollback, sn as StackTerminationProtectionError, st as getBootstrapMarkerKey, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as NestedStackChildDirectDestroyError, tt as createAssetRedirectResolver, u as withResourceDeadline, ut as validateContainerRepoName, v as bold, vt as Synthesizer, w as IAMRoleProvider, wt as resolveCaptureObservedState, x as green, xt as getLegacyStateBucketName, y as cyan, yt as synthesisStatusMessage, z as assertRegionMatch } from "./deploy-engine-C44YX-go.js";
2
+ import { $ as WorkGraph, A as slowCcOperationTimeoutMs, At as warnDeprecatedNoPrefixCliFlag, B as applyRoleArnIfSet, Bt as resolveBucketRegion, C as yellow, Ct as resolveAutoAssetStorage, D as ProviderRegistry, Dt as resolveStateBucketWithDefaultAndSource, E as clearOnUpdateRemoval, Et as resolveStateBucketWithDefault, F as refStateLookupFromResource, Ft as uploadCfnTemplate, G as DagBuilder, H as describeTypeWithThrottleRetry, Ht as getAwsClients, I as WAFv2WebACLProvider, It as expectedOwnerParam, J as S3StateBackend, K as TemplateParser, Kt as CdkdError, L as normalizeAwsTagsToCfn, Lt as AssemblyReader, M as isTerminationProtectionPropagationError, Mt as CFN_TEMPLATE_URL_LIMIT, N as IntrinsicFunctionResolver, Nt as MIGRATE_TMP_PREFIX, O as findActionableSilentDrops, Ot as resolveUseCdkBootstrapAssets, P as cfnRefValueFromPhysicalId, Pt as findLargeInlineResources, Q as stringifyValue, Qt as LocalStartServiceError, R as resolveExplicitPhysicalId, Rt as processStackMessages, S as red, St as resolveApp, T as collectInlinePolicyNamesManagedBySiblings, Tt as resolveSkipPrefix, U as withRetry, Ut as resetAwsClients, V as DiffCalculator, Vt as AwsClients, W as isRetryableTransientError, Wt as setAwsClients, X as shouldRetainResource, Xt as LocalInvokeBuildError$1, Y as rebuildClientForBucketRegion, Yt as DeployCancelledError, Z as AssetPublisher, Zt as LocalMigrateError, _ as formatResourceLine, _t as getDockerImageBySourceHash, a as DeploymentEventsStore, an as ResourceUpdateNotSupportedError, at as BOOTSTRAP_MARKER_PREFIX, b as gray, bt as getDefaultStateBucketName, c as replayFailedOperations, ct as parseBootstrapMarker, d as IMPLICIT_DELETE_DEPENDENCIES, dt as buildDockerImage, en as MissingCdkCliError, et as buildAssetRedirectMap, f as computeImplicitDeleteEdges, fn as normalizeAwsError, ft as formatDockerLoginError, g as renderStatefulReason, gt as AssetManifestLoader, h as isStatefulRecreateTargetSync, ht as runDockerStreaming, i as DeploymentEventsReader, in as ResourceTimeoutError, it as AssetModeResolver, j as disableInstanceApiTermination, jt as CFN_TEMPLATE_BODY_LIMIT, k as CloudControlProvider, kt as stateBucketExistenceConfirmed, l as replayRollback, lt as validateAssetBucketName, m as MULTI_REGION_RECREATE_BLOCKED_TYPES, mt as runDockerForeground, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as PartialFailureError, nt as loadPublishableAssetManifest, o as planFailedOps, on as StackHasActiveImportsError, ot as ensureAssetStorage, p as extractDeploymentEventError, pn as withErrorHandling, pt as getDockerCmd, q as LockManager, r as DeployEngine, rn as ProvisioningError, rt as rewriteTemplateAssetReferences, s as planRollback, sn as StackTerminationProtectionError, st as getBootstrapMarkerKey, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as NestedStackChildDirectDestroyError, tt as createAssetRedirectResolver, u as withResourceDeadline, ut as validateContainerRepoName, v as bold, vt as Synthesizer, w as IAMRoleProvider, wt as resolveCaptureObservedState, x as green, xt as getLegacyStateBucketName, y as cyan, yt as synthesisStatusMessage, z as assertRegionMatch } from "./deploy-engine-D30XI_UX.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-c0TMaGXW.js";
4
+ import { t as ASGProvider } from "./asg-provider-2hct1hkv.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";
@@ -33,7 +33,7 @@ import { AssociateVPCWithHostedZoneCommand, ChangeResourceRecordSetsCommand, Cha
33
33
  import { AddTagsCommand, CreateListenerCommand, CreateLoadBalancerCommand, CreateTargetGroupCommand, DeleteListenerCommand, DeleteLoadBalancerCommand, DeleteTargetGroupCommand, DescribeListenerAttributesCommand, DescribeListenersCommand, DescribeLoadBalancerAttributesCommand, DescribeLoadBalancersCommand, DescribeTagsCommand, DescribeTargetGroupsCommand, ElasticLoadBalancingV2Client, ModifyListenerAttributesCommand, ModifyListenerCommand, ModifyLoadBalancerAttributesCommand, ModifyTargetGroupCommand, RemoveTagsCommand, SetIpAddressTypeCommand, SetSecurityGroupsCommand, SetSubnetsCommand, waitUntilLoadBalancerAvailable } from "@aws-sdk/client-elastic-load-balancing-v2";
34
34
  import { CreateAliasCommand, CreateKeyCommand, DeleteAliasCommand, DescribeKeyCommand, DisableKeyCommand, DisableKeyRotationCommand, EnableKeyCommand, EnableKeyRotationCommand, GetKeyPolicyCommand, GetKeyRotationStatusCommand, KMSClient, ListAliasesCommand, ListResourceTagsCommand, NotFoundException as NotFoundException$2, PutKeyPolicyCommand, ScheduleKeyDeletionCommand, TagResourceCommand as TagResourceCommand$11, UntagResourceCommand as UntagResourceCommand$11, UpdateAliasCommand, UpdateKeyDescriptionCommand } from "@aws-sdk/client-kms";
35
35
  import { join as join$1 } from "path";
36
- import { BatchDeleteImageCommand, CreateRepositoryCommand, DeleteLifecyclePolicyCommand, DeleteRepositoryCommand, DeleteRepositoryPolicyCommand, DescribeImagesCommand as DescribeImagesCommand$1, DescribeRepositoriesCommand, ECRClient, GetAuthorizationTokenCommand, GetLifecyclePolicyCommand, LifecyclePolicyNotFoundException, ListTagsForResourceCommand as ListTagsForResourceCommand$8, PutImageScanningConfigurationCommand, PutImageTagMutabilityCommand, PutLifecyclePolicyCommand, RepositoryNotFoundException, SetRepositoryPolicyCommand, TagResourceCommand as TagResourceCommand$12, UntagResourceCommand as UntagResourceCommand$12 } from "@aws-sdk/client-ecr";
36
+ import { BatchDeleteImageCommand, CreateRepositoryCommand, DeleteLifecyclePolicyCommand, DeleteRepositoryCommand, DeleteRepositoryPolicyCommand, DescribeImagesCommand as DescribeImagesCommand$1, DescribeRepositoriesCommand, ECRClient, GetAuthorizationTokenCommand, GetLifecyclePolicyCommand, LifecyclePolicyNotFoundException, ListTagsForResourceCommand as ListTagsForResourceCommand$8, PutImageScanningConfigurationCommand, PutImageTagMutabilityCommand, PutLifecyclePolicyCommand, RepositoryNotEmptyException, RepositoryNotFoundException, SetRepositoryPolicyCommand, TagResourceCommand as TagResourceCommand$12, UntagResourceCommand as UntagResourceCommand$12 } from "@aws-sdk/client-ecr";
37
37
  import graphlib from "graphlib";
38
38
  import { AddTagsToResourceCommand as AddTagsToResourceCommand$1, CreateDBClusterCommand, CreateDBInstanceCommand, CreateDBProxyCommand, CreateDBProxyEndpointCommand, CreateDBSubnetGroupCommand, DBProxyEndpointNotFoundFault, DBProxyNotFoundFault, DBProxyTargetGroupNotFoundFault, DBProxyTargetNotFoundFault, DeleteDBClusterCommand, DeleteDBInstanceCommand, DeleteDBProxyCommand, DeleteDBProxyEndpointCommand, DeleteDBSubnetGroupCommand, DeregisterDBProxyTargetsCommand, DescribeDBClustersCommand, DescribeDBInstancesCommand, DescribeDBProxiesCommand, DescribeDBProxyEndpointsCommand, DescribeDBProxyTargetGroupsCommand, DescribeDBProxyTargetsCommand, DescribeDBSubnetGroupsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$9, ModifyDBClusterCommand, ModifyDBInstanceCommand, ModifyDBProxyCommand, ModifyDBProxyEndpointCommand, ModifyDBProxyTargetGroupCommand, ModifyDBSubnetGroupCommand, RDSClient, RegisterDBProxyTargetsCommand, RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand$1 } from "@aws-sdk/client-rds";
39
39
  import { AddTagsToResourceCommand as AddTagsToResourceCommand$2, CreateCacheClusterCommand, CreateCacheSubnetGroupCommand, DeleteCacheClusterCommand, DeleteCacheSubnetGroupCommand, DescribeCacheClustersCommand, DescribeCacheSubnetGroupsCommand, ElastiCacheClient, ListTagsForResourceCommand as ListTagsForResourceCommand$10, ModifyCacheClusterCommand, ModifyCacheSubnetGroupCommand, RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand$2 } from "@aws-sdk/client-elasticache";
@@ -4701,6 +4701,53 @@ var IAMUserGroupProvider = class {
4701
4701
  }
4702
4702
  };
4703
4703
 
4704
+ //#endregion
4705
+ //#region src/provisioning/data-delete-intent.ts
4706
+ /**
4707
+ * Shared helpers for detecting a template-borne "destroy my data" opt-in on
4708
+ * resources whose delete API fails by default while they still hold data
4709
+ * (issue #1340).
4710
+ *
4711
+ * CloudFormation fails the delete of a non-empty S3 bucket / image-carrying
4712
+ * ECR repository and the user opts into force-cleanup explicitly (CDK's
4713
+ * `autoDeleteObjects` custom resource + tag, `emptyOnDelete` /
4714
+ * `EmptyOnDelete: true`). cdkd honors exactly those signals — plus the
4715
+ * deploy engine's `--force-stateful-recreation` consent, threaded via
4716
+ * `DeleteContext.forceDataDelete` — instead of force-cleaning every
4717
+ * resource unconditionally.
4718
+ */
4719
+ /**
4720
+ * Tag key CDK's `aws-s3.Bucket` sets when `autoDeleteObjects: true`.
4721
+ * The tag is what the AutoDeleteObjects custom-resource handler itself
4722
+ * checks before emptying, so it is the canonical opt-in marker.
4723
+ */
4724
+ const S3_AUTO_DELETE_OBJECTS_TAG = "aws-cdk:auto-delete-objects";
4725
+ /**
4726
+ * Tag key CDK's `aws-ecr.Repository` sets when `autoDeleteImages: true`
4727
+ * (the pre-`emptyOnDelete` opt-in; both signals are honored).
4728
+ */
4729
+ const ECR_AUTO_DELETE_IMAGES_TAG = "aws-cdk:auto-delete-images";
4730
+ /**
4731
+ * True when the resource's CFn `Tags` list carries `tagKey` with a truthy
4732
+ * value. Tolerates the CFn boolean-as-string shape (`"true"`).
4733
+ */
4734
+ function hasCdkAutoDeleteTag(properties, tagKey) {
4735
+ const tags = properties?.["Tags"];
4736
+ if (!Array.isArray(tags)) return false;
4737
+ return tags.some((tag) => {
4738
+ if (typeof tag !== "object" || tag === null) return false;
4739
+ const entry = tag;
4740
+ return entry.Key === tagKey && isTruthyCfnBoolean(entry.Value);
4741
+ });
4742
+ }
4743
+ /**
4744
+ * CFn booleans arrive as `true` or the string `"true"` depending on how the
4745
+ * template was authored / resolved; treat both as true.
4746
+ */
4747
+ function isTruthyCfnBoolean(value) {
4748
+ return value === true || value === "true";
4749
+ }
4750
+
4704
4751
  //#endregion
4705
4752
  //#region src/provisioning/providers/s3-bucket-provider.ts
4706
4753
  /**
@@ -5599,10 +5646,11 @@ var S3BucketProvider = class {
5599
5646
  *
5600
5647
  * Note: The bucket must be empty before deletion.
5601
5648
  */
5602
- async delete(logicalId, physicalId, resourceType, _properties, context) {
5649
+ async delete(logicalId, physicalId, resourceType, properties, context) {
5603
5650
  this.logger.debug(`Deleting S3 bucket ${logicalId}: ${physicalId}`);
5651
+ const allowAutoEmpty = context?.forceDataDelete === true || hasCdkAutoDeleteTag(properties, "aws-cdk:auto-delete-objects");
5604
5652
  try {
5605
- await this.deleteBucketWithEmptyRetry(logicalId, physicalId);
5653
+ await this.deleteBucketWithEmptyRetry(logicalId, physicalId, allowAutoEmpty);
5606
5654
  } catch (error) {
5607
5655
  if (error instanceof NoSuchBucket) {
5608
5656
  assertRegionMatch(await this.s3Client.config.region(), context?.expectedRegion, resourceType, logicalId, physicalId);
@@ -6134,11 +6182,21 @@ var S3BucketProvider = class {
6134
6182
  return null;
6135
6183
  }
6136
6184
  /**
6137
- * Delete a bucket, emptying it first if not empty.
6138
- * Handles the race condition where objects (e.g., ALB logs) are written
6139
- * after CustomResource cleanup but before bucket deletion.
6185
+ * Delete a bucket, emptying it first if not empty — but ONLY when
6186
+ * `allowAutoEmpty` is set (issue #1340).
6187
+ *
6188
+ * With `allowAutoEmpty` (CDK `autoDeleteObjects` tag present, or
6189
+ * `--force-stateful-recreation` consent via
6190
+ * {@link DeleteContext.forceDataDelete}), the retry loop handles the race
6191
+ * condition where objects (e.g., ALB logs) are written after
6192
+ * CustomResource cleanup but before bucket deletion.
6193
+ *
6194
+ * Without it, a not-empty bucket refuses deletion with an actionable
6195
+ * error — matching CloudFormation's DELETE_FAILED, which is the safety
6196
+ * net users rely on to keep `cdkd destroy` from silently destroying data
6197
+ * they never opted into losing.
6140
6198
  */
6141
- async deleteBucketWithEmptyRetry(logicalId, bucketName) {
6199
+ async deleteBucketWithEmptyRetry(logicalId, bucketName, allowAutoEmpty) {
6142
6200
  const maxAttempts = 3;
6143
6201
  for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
6144
6202
  await this.s3Client.send(new DeleteBucketCommand({ Bucket: bucketName }));
@@ -6147,7 +6205,8 @@ var S3BucketProvider = class {
6147
6205
  } catch (error) {
6148
6206
  const msg = error instanceof Error ? error.message : String(error);
6149
6207
  if (msg.includes("not empty") || msg.includes("BucketNotEmpty")) {
6150
- this.logger.debug(`Bucket ${bucketName} not empty (attempt ${attempt}/${maxAttempts}), emptying...`);
6208
+ if (!allowAutoEmpty) throw new Error(`bucket ${bucketName} is not empty. Matching CloudFormation, cdkd does not delete a non-empty bucket unless it opted into automatic emptying (CDK's autoDeleteObjects: true, i.e. the '${S3_AUTO_DELETE_OBJECTS_TAG}' tag). Either empty the bucket first (delete all objects — and for versioned buckets all object versions and delete markers), or redeploy with autoDeleteObjects: true and destroy again.`);
6209
+ this.logger.info(`Bucket ${bucketName} not empty (attempt ${attempt}/${maxAttempts}), emptying (auto-delete opt-in present)...`);
6151
6210
  await this.emptyBucket(bucketName);
6152
6211
  continue;
6153
6212
  }
@@ -42015,8 +42074,11 @@ var S3TablesProvider = class {
42015
42074
  *
42016
42075
  * Implements resource provisioning for AWS::ECR::Repository using the ECR SDK.
42017
42076
  * WHY: The CC API cannot force-delete repositories that contain images.
42018
- * This SDK provider uses DeleteRepositoryCommand with `force: true` to delete
42019
- * repositories along with all their images, supporting CDK's `emptyOnDelete: true`.
42077
+ * This SDK provider implements CDK's `emptyOnDelete: true` by passing
42078
+ * `force: true` to DeleteRepositoryCommand gated on the user's opt-in
42079
+ * (`EmptyOnDelete: true`, the `aws-cdk:auto-delete-images` tag, or
42080
+ * `--force-stateful-recreation` on a replacement), never unconditionally
42081
+ * (issue #1340; CloudFormation parity for repositories without the opt-in).
42020
42082
  */
42021
42083
  var ECRProvider = class {
42022
42084
  client;
@@ -42208,18 +42270,27 @@ var ECRProvider = class {
42208
42270
  /**
42209
42271
  * Delete an ECR Repository
42210
42272
  *
42211
- * Uses `force: true` to delete the repository even if it contains images.
42212
- * This supports CDK's `emptyOnDelete: true` / `removalPolicy: DESTROY` pattern.
42273
+ * `force: true` (delete the repository along with any images it still
42274
+ * contains) is applied ONLY when the user opted in (issue #1340):
42275
+ * `EmptyOnDelete: true` (CDK `emptyOnDelete`), CDK's legacy
42276
+ * `autoDeleteImages` tag, or the deploy engine's
42277
+ * `--force-stateful-recreation` consent on a replacement delete.
42278
+ * Without an opt-in, a repository that still contains images refuses
42279
+ * deletion with an actionable error — matching CloudFormation's
42280
+ * DELETE_FAILED (`RepositoryNotEmptyException`).
42213
42281
  */
42214
- async delete(logicalId, physicalId, resourceType, _properties, context) {
42282
+ async delete(logicalId, physicalId, resourceType, properties, context) {
42215
42283
  this.logger.debug(`Deleting ECR Repository ${logicalId}: ${physicalId}`);
42284
+ const force = context?.forceDataDelete === true || isTruthyCfnBoolean(properties?.["EmptyOnDelete"]) || hasCdkAutoDeleteTag(properties, "aws-cdk:auto-delete-images");
42216
42285
  try {
42286
+ if (force) this.logger.debug(`Force-deleting ECR Repository ${logicalId} (empty-on-delete opt-in present)`);
42217
42287
  await this.getClient().send(new DeleteRepositoryCommand({
42218
42288
  repositoryName: physicalId,
42219
- force: true
42289
+ force
42220
42290
  }));
42221
42291
  this.logger.debug(`Successfully deleted ECR Repository ${logicalId}`);
42222
42292
  } catch (error) {
42293
+ if (error instanceof RepositoryNotEmptyException) throw new ProvisioningError(`Failed to delete ECR Repository ${logicalId}: repository ${physicalId} still contains images. Matching CloudFormation, cdkd does not force-delete an image-carrying repository unless it opted in via EmptyOnDelete: true (CDK's emptyOnDelete) or the '${ECR_AUTO_DELETE_IMAGES_TAG}' tag (CDK's autoDeleteImages). Either delete the images first (aws ecr batch-delete-image), or redeploy with emptyOnDelete: true and destroy again.`, resourceType, logicalId, physicalId, error);
42223
42294
  if (error instanceof RepositoryNotFoundException) {
42224
42295
  assertRegionMatch(await this.getClient().config.region(), context?.expectedRegion, resourceType, logicalId, physicalId);
42225
42296
  this.logger.debug(`ECR Repository ${physicalId} does not exist, skipping deletion`);
@@ -63483,7 +63554,7 @@ function createMigrateCommand() {
63483
63554
  */
63484
63555
  function buildProgram() {
63485
63556
  const program = new Command();
63486
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.275.1");
63557
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.275.2");
63487
63558
  program.hook("preAction", (_thisCommand, actionCommand) => {
63488
63559
  const { profile } = actionCommand.optsWithGlobals();
63489
63560
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;