@go-to-k/cdkd 0.284.20 → 0.284.21

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 isTerminationProtectionPropagationError, $n as PartialFailureError, $t as getBootstrapMarkerKey, A as renderStatefulReason, An as expectedOwnerParam, At as applyRoleArnIfSet, B as exportAliasCollisionScrubWarning, Bn as resetAwsClients, Bt as shouldRetainResource, C as isFinalSnapshotError, Cn as stateBucketExistenceConfirmed, Ct as redactSecretsForState, D as extractDeploymentEventError, Dn as MIGRATE_TMP_PREFIX, Dt as s3BucketDualStackDomainName, E as makeCanonicalizePropertiesFn, En as CFN_TEMPLATE_URL_LIMIT, Et as s3BucketDomainName, F as green, Fn as processStackMessages, Ft as DagBuilder, G as collectInlinePolicyNamesManagedBySiblings, Gt as createAssetRedirectResolver, H as secretBearingStateKeyWarning, Ht as stringifyValue, I as red, It as TemplateParser, J as findActionableSilentDrops, Jn as LocalMigrateError, Jt as escapeRegExp, K as clearOnUpdateRemoval, Kn as DeployCancelledError, Kt as loadPublishableAssetManifest, L as yellow, Ln as resolveBucketRegion, Lt as LockManager, M as bold, Mn as canonicalizeRegion, Mt as INTRINSIC_KEYS, N as cyan, Nn as derivePartitionAndUrlSuffix, Nt as describeTypeWithThrottleRetry, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as findLargeInlineResources, Ot as s3BucketRegionalDomainName, P as gray, Pn as AssemblyReader, Pt as withRetry, Q as disableInstanceApiTermination, Qn as NestedStackChildDirectDestroyError, Qt as ensureAssetStorage, R as collectDeclaredOutputNames, Rn as AwsClients, Rt as S3StateBackend, S as createPreDeleteFinalSnapshot, Sn as resolveUseCdkBootstrapAssets, St as maskSecretsInText, T as unsupportedFinalSnapshotError, Tn as CFN_TEMPLATE_BODY_LIMIT, Tt as s3BucketArn, U as stateKeySecretExposure, Un as CdkdError, Ut as WorkGraph, V as isExportAliasCollision, Vn as setAwsClients, Vt as AssetPublisher, W as IAMRoleProvider, Wt as buildAssetRedirectMap, X as CloudControlProvider, Xt as AssetModeResolver, Y as findSilentDropProperties, Yn as LocalStartServiceError, Yt as stripControlChars, Z as slowCcOperationTimeoutMs, Zn as MissingCdkCliError, Zt as BOOTSTRAP_MARKER_PREFIX, _ as computeImplicitDeleteEdges, _n as resolveAutoAssetStorage, _t as STATE_SOURCED_READBACK_RULES, a as DeploymentEventsStore, an as buildDockerImage, at as normalizeAwsTagsToCfn, b as buildFinalSnapshotIdentifier, bn as resolveStateBucketWithDefault, bt as dynamicReferenceTokens, c as replayFailedOperations, cn as runDockerForeground, ct as coerceCfnBoolean, d as updatePartialReason, dn as getDockerImageBySourceHash, dr as isMarkedNonRetryable, dt as readConfigString, en as parseBootstrapMarker, er as ProvisioningError, et as IntrinsicFunctionResolver, f as UNSPECIFIED_SKIP_REASON, fn as Synthesizer, fr as isRetryableTransientError, ft as replayWarn, g as IMPLICIT_DELETE_DEPENDENCIES, gn as resolveApp, gt as STATE_SOURCED_CROSS_GENERATION_RULES, h as maskingRetryLogger, hn as getLegacyStateBucketName, ht as requireConfigString, i as DeploymentEventsReader, in as buildDenyExternalAccessPolicy, ir as StackTerminationProtectionError, it as WAFv2WebACLProvider, j as formatResourceLine, jn as PARTITION_TABLE, jt as DiffCalculator, k as isStatefulRecreateTargetSync, kn as uploadCfnTemplate, kt as s3BucketWebsiteUrl, l as replayRollback, ln as runDockerStreaming, lr as normalizeAwsError, lt as configBooleanRefusal, m as withResourceDeadline, mn as getDefaultStateBucketName, mr as markNonRetryable, mt as requireConfigObject, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as validateAssetBucketName, nr as ResourceUpdateNotSupportedError, nt as getAccountInfo, o as planFailedOps, on as formatDockerLoginError, ot as resolveExplicitPhysicalId, p as deleteSkipReason, pn as synthesisStatusMessage, pr as isThrottlingError, pt as requireConfigArray, q as ProviderRegistry, qn as LocalInvokeBuildError$1, qt as rewriteTemplateAssetReferences, r as DeployEngine, rn as validateContainerRepoName, rr as StackHasActiveImportsError, rt as refStateLookupFromResource, s as planRollback, sn as getDockerCmd, st as assertRegionMatch, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as readBootstrapMarkerBody, tr as ResourceTimeoutError, tt as cfnRefValueFromPhysicalId, u as updatePartialMessage, un as AssetManifestLoader, ur as withErrorHandling, ut as configStringRefusal, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as resolveCaptureObservedState, vt as TEMPLATE_SOURCED_RULES, w as refusesFinalSnapshot, wn as warnDeprecatedNoPrefixCliFlag, wt as scrubResourceRecord, x as ccRoutedFinalSnapshotError, xn as resolveStateBucketWithDefaultAndSource, xt as isSingleDynamicReferenceToken, y as PRE_DELETE_SNAPSHOT_TYPES, yn as resolveSkipPrefix, yt as createSecretMasker, z as collectPublishedOutputNames, zn as getAwsClients, zt as rebuildClientForBucketRegion } from "./deploy-engine-C6gt7NcL.js";
2
+ import { $ as isTerminationProtectionPropagationError, $n as PartialFailureError, $t as getBootstrapMarkerKey, A as renderStatefulReason, An as expectedOwnerParam, At as applyRoleArnIfSet, B as exportAliasCollisionScrubWarning, Bn as resetAwsClients, Bt as shouldRetainResource, C as isFinalSnapshotError, Cn as stateBucketExistenceConfirmed, Ct as redactSecretsForState, D as extractDeploymentEventError, Dn as MIGRATE_TMP_PREFIX, Dt as s3BucketDualStackDomainName, E as makeCanonicalizePropertiesFn, En as CFN_TEMPLATE_URL_LIMIT, Et as s3BucketDomainName, F as green, Fn as processStackMessages, Ft as DagBuilder, G as collectInlinePolicyNamesManagedBySiblings, Gt as createAssetRedirectResolver, H as secretBearingStateKeyWarning, Ht as stringifyValue, I as red, It as TemplateParser, J as findActionableSilentDrops, Jn as LocalMigrateError, Jt as escapeRegExp, K as clearOnUpdateRemoval, Kn as DeployCancelledError, Kt as loadPublishableAssetManifest, L as yellow, Ln as resolveBucketRegion, Lt as LockManager, M as bold, Mn as canonicalizeRegion, Mt as INTRINSIC_KEYS, N as cyan, Nn as derivePartitionAndUrlSuffix, Nt as describeTypeWithThrottleRetry, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as findLargeInlineResources, Ot as s3BucketRegionalDomainName, P as gray, Pn as AssemblyReader, Pt as withRetry, Q as disableInstanceApiTermination, Qn as NestedStackChildDirectDestroyError, Qt as ensureAssetStorage, R as collectDeclaredOutputNames, Rn as AwsClients, Rt as S3StateBackend, S as createPreDeleteFinalSnapshot, Sn as resolveUseCdkBootstrapAssets, St as maskSecretsInText, T as unsupportedFinalSnapshotError, Tn as CFN_TEMPLATE_BODY_LIMIT, Tt as s3BucketArn, U as stateKeySecretExposure, Un as CdkdError, Ut as WorkGraph, V as isExportAliasCollision, Vn as setAwsClients, Vt as AssetPublisher, W as IAMRoleProvider, Wt as buildAssetRedirectMap, X as CloudControlProvider, Xt as AssetModeResolver, Y as findSilentDropProperties, Yn as LocalStartServiceError, Yt as stripControlChars, Z as slowCcOperationTimeoutMs, Zn as MissingCdkCliError, Zt as BOOTSTRAP_MARKER_PREFIX, _ as computeImplicitDeleteEdges, _n as resolveAutoAssetStorage, _t as STATE_SOURCED_READBACK_RULES, a as DeploymentEventsStore, an as buildDockerImage, at as normalizeAwsTagsToCfn, b as buildFinalSnapshotIdentifier, bn as resolveStateBucketWithDefault, bt as dynamicReferenceTokens, c as replayFailedOperations, cn as runDockerForeground, ct as coerceCfnBoolean, d as updatePartialReason, dn as getDockerImageBySourceHash, dr as isMarkedNonRetryable, dt as readConfigString, en as parseBootstrapMarker, er as ProvisioningError, et as IntrinsicFunctionResolver, f as UNSPECIFIED_SKIP_REASON, fn as Synthesizer, fr as isRetryableTransientError, ft as replayWarn, g as IMPLICIT_DELETE_DEPENDENCIES, gn as resolveApp, gt as STATE_SOURCED_CROSS_GENERATION_RULES, h as maskingRetryLogger, hn as getLegacyStateBucketName, ht as requireConfigString, i as DeploymentEventsReader, in as buildDenyExternalAccessPolicy, ir as StackTerminationProtectionError, it as WAFv2WebACLProvider, j as formatResourceLine, jn as PARTITION_TABLE, jt as DiffCalculator, k as isStatefulRecreateTargetSync, kn as uploadCfnTemplate, kt as s3BucketWebsiteUrl, l as replayRollback, ln as runDockerStreaming, lr as normalizeAwsError, lt as configBooleanRefusal, m as withResourceDeadline, mn as getDefaultStateBucketName, mr as markNonRetryable, mt as requireConfigObject, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as validateAssetBucketName, nr as ResourceUpdateNotSupportedError, nt as getAccountInfo, o as planFailedOps, on as formatDockerLoginError, ot as resolveExplicitPhysicalId, p as deleteSkipReason, pn as synthesisStatusMessage, pr as isThrottlingError, pt as requireConfigArray, q as ProviderRegistry, qn as LocalInvokeBuildError$1, qt as rewriteTemplateAssetReferences, r as DeployEngine, rn as validateContainerRepoName, rr as StackHasActiveImportsError, rt as refStateLookupFromResource, s as planRollback, sn as getDockerCmd, st as assertRegionMatch, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as readBootstrapMarkerBody, tr as ResourceTimeoutError, tt as cfnRefValueFromPhysicalId, u as updatePartialMessage, un as AssetManifestLoader, ur as withErrorHandling, ut as configStringRefusal, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as resolveCaptureObservedState, vt as TEMPLATE_SOURCED_RULES, w as refusesFinalSnapshot, wn as warnDeprecatedNoPrefixCliFlag, wt as scrubResourceRecord, x as ccRoutedFinalSnapshotError, xn as resolveStateBucketWithDefaultAndSource, xt as isSingleDynamicReferenceToken, y as PRE_DELETE_SNAPSHOT_TYPES, yn as resolveSkipPrefix, yt as createSecretMasker, z as collectPublishedOutputNames, zn as getAwsClients, zt as rebuildClientForBucketRegion } from "./deploy-engine--N_xnvjI.js";
3
3
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
4
- import { t as ASGProvider } from "./asg-provider-Cq-oDB62.js";
4
+ import { t as ASGProvider } from "./asg-provider-D5G53CUp.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";
@@ -112,7 +112,11 @@ const commonOptions = [
112
112
  * Kept (rather than fully removed) so that scripts or muscle memory passing
113
113
  * `--region` do not break. The value IS still honored — every non-bootstrap
114
114
  * command consumes `options.region` as the highest-precedence region source
115
- * (`options.region || AWS_REGION || 'us-east-1'`): it sets the region of the
115
+ * (`--region` -> `AWS_REGION` -> `us-east-1`, except `cdkd gc` and `cdkd
116
+ * bootstrap --destroy`, which resolve the profile region and REFUSE rather
117
+ * than falling back to a literal, because they delete — issue #2029; the
118
+ * value is folded to its canonical spelling at each handler's entry, issue
119
+ * #2065): it sets the region of the
116
120
  * provisioning / state-bucket SDK clients, the `applyRoleArnIfSet` STS hop,
117
121
  * and (for `deploy` / `destroy` / `import` / `export` / `orphan`) the
118
122
  * `AWS_REGION` env var inherited by the CDK synth subprocess. The flag is
@@ -776,6 +780,92 @@ const destroyOptions = [
776
780
  */
777
781
  const skipFinalSnapshotOption = new Option("--skip-final-snapshot", "Delete resources whose DeletionPolicy (or, on replacements, UpdateReplacePolicy) is 'Snapshot' WITHOUT creating the final snapshot the policy promises (DATA LOSS — explicit opt-out of CloudFormation parity). By default cdkd creates the final snapshot for every CloudFormation-supported type (RDS DBInstance / DBCluster, Neptune / DocDB clusters, ElastiCache CacheCluster / ReplicationGroup, Redshift Cluster, EC2 Volume) and refuses the delete when it cannot — e.g. a resource managed via the Cloud Control API route, whose delete has no final-snapshot parameter. On 'cdkd rollback' the flag governs the rolled-back CREATE's DeletionPolicy; a reverse-replacement delete of the NEW resource keeps its own bounded UpdateReplacePolicy behavior and is unaffected.").default(false);
778
782
 
783
+ //#endregion
784
+ //#region src/cli/region-options.ts
785
+ /**
786
+ * ONE region-normalization point for the CLI's command handlers.
787
+ *
788
+ * Issue [#1795](https://github.com/go-to-k/cdkd/issues/1795) folded `--region`
789
+ * at the boundary of the four `cdkd local *` commands, for a reason that was
790
+ * never specific to them: AWS SDK endpoint resolution, SigV4's credential
791
+ * scope, this repo's own `PARTITION_TABLE` prefix walk and every ARN segment
792
+ * built from the value are ALL case-sensitive, so a raw spelling is wrong at
793
+ * each of them. Issue
794
+ * [#2065](https://github.com/go-to-k/cdkd/issues/2065) measured what that costs
795
+ * the commands the fix skipped — `cdkd deploy --region US-EAST-1` dies at the
796
+ * state-bucket preflight before it does anything:
797
+ *
798
+ * ```text
799
+ * FAIL S3 ListObjectsV2 region=US-EAST-1 AuthorizationHeaderMalformed:
800
+ * the region 'US-EAST-1' is wrong; expecting 'us-east-1'
801
+ * ```
802
+ *
803
+ * The fold lives here rather than at each consumer because a command reads
804
+ * `options.region` in many places — `applyRoleArnIfSet`, the
805
+ * `process.env.AWS_REGION` copy, several `new AwsClients({ region })` spreads —
806
+ * and folding per consumer is the shape that has needed a follow-up every time
807
+ * a new consumer was added. Double-folding is a no-op, which is what makes a
808
+ * second fold further down (`derivePartitionAndUrlSuffix`, `AwsClients`) safe
809
+ * rather than redundant.
810
+ */
811
+ /**
812
+ * Fold `--region` to its canonical spelling in place, at the handler's entry.
813
+ *
814
+ * Call this BEFORE the first consumer of `options.region` — in practice before
815
+ * `applyRoleArnIfSet`, which is the first AWS-touching call in most handlers.
816
+ *
817
+ * A handler that ALSO needs the user's exact spelling must capture it first.
818
+ * The one consumer with that need is the bootstrap-marker read, whose second
819
+ * probe exists precisely to find a key an unfolded `cdkd bootstrap` wrote
820
+ * (see `readBootstrapMarkerBody` in `src/assets/asset-storage.ts`); the
821
+ * `--stack-region` fold in `local-invoke.ts` keeps a `rawStackRegion` for the
822
+ * same class of reason.
823
+ */
824
+ function foldRegionOption(options) {
825
+ if (options.region !== void 0) options.region = canonicalizeRegion(options.region);
826
+ for (const key of ["AWS_REGION", "AWS_DEFAULT_REGION"]) {
827
+ const value = process.env[key];
828
+ if (value) process.env[key] = canonicalizeRegion(value);
829
+ }
830
+ }
831
+ /**
832
+ * The region the user NAMED — `--region` first, then `AWS_REGION` — canonical,
833
+ * or `undefined` when they named NEITHER.
834
+ *
835
+ * `undefined` is a distinct answer from any region string, and the distinction
836
+ * is the whole point of this helper. Issue
837
+ * [#2029](https://github.com/go-to-k/cdkd/issues/2029): materializing a
838
+ * `|| 'us-east-1'` literal collapses "the user named no region" into "the user
839
+ * named us-east-1", and the literal then wins over the profile region the AWS
840
+ * SDK's own chain would have resolved from `~/.aws/config`. For `cdkd gc` that
841
+ * meant evaluating — and deleting in — a region the user never mentioned, with
842
+ * no error, because `us-east-1` is a perfectly valid region.
843
+ *
844
+ * So a caller that builds an SDK client spreads this CONDITIONALLY
845
+ * (`...(named !== undefined && { region: named })`) and lets an absent region
846
+ * stay absent. A caller that needs a region as a VALUE — a state key, a bucket
847
+ * name, a marker key — must resolve one rather than pin a literal, and must
848
+ * resolve the SAME one its clients use or the two silently disagree.
849
+ *
850
+ * Deliberately reads `AWS_REGION` only, not `AWS_DEFAULT_REGION`: that is the
851
+ * precedence every one of these handlers already had, and widening it is a
852
+ * behavior change with no defect behind it.
853
+ */
854
+ function namedCliRegion(optionRegion) {
855
+ return canonicalizeRegion(optionRegion || process.env["AWS_REGION"]) || void 0;
856
+ }
857
+ /**
858
+ * The user's EXACT `--region` / `AWS_REGION` spelling, unfolded.
859
+ *
860
+ * Only the bootstrap-marker read wants this — it probes the canonical key
861
+ * first and this spelling second, so that a marker written by a pre-fold
862
+ * `cdkd bootstrap` is still found. Every other consumer wants
863
+ * {@link namedCliRegion}.
864
+ */
865
+ function rawCliRegion(optionRegion) {
866
+ return optionRegion || process.env["AWS_REGION"] || void 0;
867
+ }
868
+
779
869
  //#endregion
780
870
  //#region src/cli/commands/state-file-keys.ts
781
871
  /**
@@ -1067,13 +1157,12 @@ async function bootstrapDestroyCommand(options) {
1067
1157
  logger.debug("Options:", options);
1068
1158
  await applyRoleArnIfSet({
1069
1159
  roleArn: options.roleArn,
1070
- region: canonicalizeRegion(options.region)
1160
+ region: namedCliRegion(options.region)
1071
1161
  });
1072
- const rawRegion = options.region || process.env["AWS_REGION"] || "us-east-1";
1073
- const region = canonicalizeRegion(rawRegion);
1074
- const clientRegion = canonicalizeRegion(options.region || process.env["AWS_REGION"]) || void 0;
1162
+ const region = namedCliRegion(options.region) ?? "us-east-1";
1163
+ const rawRegion = rawCliRegion(options.region) ?? region;
1075
1164
  const awsClients = new AwsClients({
1076
- ...clientRegion !== void 0 && { region: clientRegion },
1165
+ region,
1077
1166
  ...options.profile && { profile: options.profile }
1078
1167
  });
1079
1168
  setAwsClients(awsClients);
@@ -1202,6 +1291,8 @@ async function bootstrapCommand(options) {
1202
1291
  if (options.verbose) logger.setLevel("debug");
1203
1292
  logger.info("Starting cdkd bootstrap...");
1204
1293
  logger.debug("Options:", options);
1294
+ const rawRegion = rawCliRegion(options.region) ?? "us-east-1";
1295
+ foldRegionOption(options);
1205
1296
  await applyRoleArnIfSet({
1206
1297
  roleArn: options.roleArn,
1207
1298
  region: options.region
@@ -1212,7 +1303,7 @@ async function bootstrapCommand(options) {
1212
1303
  });
1213
1304
  setAwsClients(awsClients);
1214
1305
  const s3Client = awsClients.s3;
1215
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
1306
+ const region = namedCliRegion(options.region) ?? "us-east-1";
1216
1307
  let bucketName;
1217
1308
  let accountId;
1218
1309
  if (options.stateBucket) {
@@ -1310,7 +1401,7 @@ async function bootstrapCommand(options) {
1310
1401
  ecrClient,
1311
1402
  stateBackend,
1312
1403
  accountId,
1313
- region,
1404
+ region: rawRegion,
1314
1405
  force: options.force,
1315
1406
  ...options.assetBucket && { assetBucketName: options.assetBucket },
1316
1407
  ...options.containerRepo && { containerRepoName: options.containerRepo }
@@ -1340,7 +1431,7 @@ async function bootstrapCommand(options) {
1340
1431
  * Create bootstrap command
1341
1432
  */
1342
1433
  function createBootstrapCommand() {
1343
- const cmd = new Command("bootstrap").description("Bootstrap cdkd by creating the S3 state bucket plus cdkd-owned asset storage (asset bucket + container-asset ECR repo) for the region. With --destroy, tear down the region's asset storage instead (issue #1010).").option("--state-bucket <bucket>", "Name of S3 bucket to create for state storage (default: cdkd-state-{accountId})").option("--force", "Create: force reconfiguration of an existing bucket. Destroy: delete the asset storage even when deployed stacks still reference it", false).option("--no-assets", "Skip cdkd asset storage (asset bucket / ECR repo / marker) — deploys keep publishing assets to the CDK bootstrap bucket/repo").option("--asset-bucket <name>", "Custom name for the cdkd asset bucket (default: cdkd-assets-{accountId}-{region}). Written into the bootstrap marker; re-bootstrapping a region with a different name is refused").option("--container-repo <name>", "Custom name for the container-asset ECR repository (default: cdkd-container-assets-{accountId}-{region}). Written into the bootstrap marker; re-bootstrapping a region with a different name is refused").option("--destroy", "Tear down the region's cdkd asset storage (empty + delete the asset bucket, force-delete the container-asset ECR repo, then delete the bootstrap marker last). The state bucket is kept unless --include-state-bucket is also passed", false).option("--include-state-bucket", "With --destroy: also delete the S3 state bucket. Refused while any stack state exists or any other region is still opted in to asset storage", false).addOption(new Option("--region <region>", "AWS region in which to create the state bucket (defaults to AWS_REGION env or us-east-1)")).action(withErrorHandling(async (options) => {
1434
+ const cmd = new Command("bootstrap").description("Bootstrap cdkd by creating the S3 state bucket plus cdkd-owned asset storage (asset bucket + container-asset ECR repo) for the region. With --destroy, tear down the region's asset storage instead (issue #1010).").option("--state-bucket <bucket>", "Name of S3 bucket to create for state storage (default: cdkd-state-{accountId})").option("--force", "Create: force reconfiguration of an existing bucket. Destroy: delete the asset storage even when deployed stacks still reference it", false).option("--no-assets", "Skip cdkd asset storage (asset bucket / ECR repo / marker) — deploys keep publishing assets to the CDK bootstrap bucket/repo").option("--asset-bucket <name>", "Custom name for the cdkd asset bucket (default: cdkd-assets-{accountId}-{region}). Written into the bootstrap marker; re-bootstrapping a region with a different name is refused").option("--container-repo <name>", "Custom name for the container-asset ECR repository (default: cdkd-container-assets-{accountId}-{region}). Written into the bootstrap marker; re-bootstrapping a region with a different name is refused").option("--destroy", "Tear down the region's cdkd asset storage (empty + delete the asset bucket, force-delete the container-asset ECR repo, then delete the bootstrap marker last). The state bucket is kept unless --include-state-bucket is also passed", false).option("--include-state-bucket", "With --destroy: also delete the S3 state bucket. Refused while any stack state exists or any other region is still opted in to asset storage", false).addOption(new Option("--region <region>", "AWS region to bootstrap, or to tear down with --destroy (defaults to AWS_REGION env, else us-east-1)")).action(withErrorHandling(async (options) => {
1344
1435
  if (options.destroy) {
1345
1436
  if (options.assetBucket !== void 0 || options.containerRepo !== void 0) throw new CdkdError("--asset-bucket / --container-repo cannot be combined with --destroy. The teardown reads the region's asset storage names from the bootstrap marker.", "INVALID_OPTIONS");
1346
1437
  if (!options.assets) throw new CdkdError("--no-assets cannot be combined with --destroy. The teardown scope is the asset storage itself; use --include-state-bucket to also delete the state bucket.", "INVALID_OPTIONS");
@@ -1431,6 +1522,7 @@ async function synthCommand(options) {
1431
1522
  const logger = getLogger();
1432
1523
  if (options.verbose) logger.setLevel("debug");
1433
1524
  warnIfDeprecatedRegion(options);
1525
+ foldRegionOption(options);
1434
1526
  await applyRoleArnIfSet({
1435
1527
  roleArn: options.roleArn,
1436
1528
  region: options.region
@@ -1568,6 +1660,7 @@ async function listCommand(patterns, options) {
1568
1660
  const logger = getLogger();
1569
1661
  if (options.verbose) logger.setLevel("debug");
1570
1662
  warnIfDeprecatedRegion(options);
1663
+ foldRegionOption(options);
1571
1664
  await applyRoleArnIfSet({
1572
1665
  roleArn: options.roleArn,
1573
1666
  region: options.region
@@ -59271,6 +59364,8 @@ async function deployCommand(stacks, options) {
59271
59364
  validateResourceTimeouts(options);
59272
59365
  setResolvedResourceTimeouts(options.resourceTimeout);
59273
59366
  applyWaitFlagEnv(options);
59367
+ const rawBaseRegion = rawCliRegion(options.region) ?? "us-east-1";
59368
+ foldRegionOption(options);
59274
59369
  await applyRoleArnIfSet({
59275
59370
  roleArn: options.roleArn,
59276
59371
  region: options.region
@@ -59282,7 +59377,7 @@ async function deployCommand(stacks, options) {
59282
59377
  const app = resolveApp(options.app);
59283
59378
  if (!app) throw new Error("No app command specified. Use --app, set CDKD_APP env var, or add \"app\" to cdk.json");
59284
59379
  options.app = app;
59285
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
59380
+ const region = namedCliRegion(options.region) ?? "us-east-1";
59286
59381
  logger.debug("Starting deployment...");
59287
59382
  logger.debug("Options:", options);
59288
59383
  if (options.region) {
@@ -59383,7 +59478,7 @@ async function deployCommand(stacks, options) {
59383
59478
  });
59384
59479
  await synthesizer.expandMacrosForStacks(targetStacks, synthOptions);
59385
59480
  const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
59386
- const stsClient = new STSClient({ region: options.region || process.env["AWS_REGION"] || "us-east-1" });
59481
+ const stsClient = new STSClient({ region: namedCliRegion(options.region) ?? "us-east-1" });
59387
59482
  const accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
59388
59483
  stsClient.destroy();
59389
59484
  const assetPublisher = new AssetPublisher();
@@ -59407,7 +59502,7 @@ async function deployCommand(stacks, options) {
59407
59502
  };
59408
59503
  const dagBuilder = new DagBuilder({ relaxCdkVpcDefensiveDeps: !!options.aggressiveVpcParallel });
59409
59504
  const diffCalculator = new DiffCalculator();
59410
- const baseRegion = options.region || process.env["AWS_REGION"] || "us-east-1";
59505
+ const baseRegion = namedCliRegion(options.region) ?? "us-east-1";
59411
59506
  const switchRegion = (region) => {
59412
59507
  process.env["AWS_REGION"] = region;
59413
59508
  process.env["AWS_DEFAULT_REGION"] = region;
@@ -59422,7 +59517,7 @@ async function deployCommand(stacks, options) {
59422
59517
  const assetRegion = stack.region || baseRegion;
59423
59518
  const manifest = loadPublishableAssetManifest(stack.assetManifestPath);
59424
59519
  if (manifest) {
59425
- const assetMode = await assetModeResolver.resolve(assetRegion);
59520
+ const assetMode = await assetModeResolver.resolve(stack.region || rawBaseRegion);
59426
59521
  logger.debug(`Asset mode for region ${assetRegion}: ${assetMode.mode} (stack ${stack.stackName})`);
59427
59522
  let redirect;
59428
59523
  if (assetMode.mode === "cdkd-assets") {
@@ -61582,6 +61677,7 @@ async function diffCommand(stacks, options) {
61582
61677
  if (options.json) logger.setLevel("warn");
61583
61678
  else if (options.verbose) logger.setLevel("debug");
61584
61679
  warnIfDeprecatedRegion(options);
61680
+ foldRegionOption(options);
61585
61681
  await applyRoleArnIfSet({
61586
61682
  roleArn: options.roleArn,
61587
61683
  region: options.region
@@ -61589,7 +61685,7 @@ async function diffCommand(stacks, options) {
61589
61685
  const app = resolveApp(options.app);
61590
61686
  if (!app) throw new Error("No app command specified. Use --app, set CDKD_APP env var, or add \"app\" to cdk.json");
61591
61687
  options.app = app;
61592
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
61688
+ const region = namedCliRegion(options.region) ?? "us-east-1";
61593
61689
  const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
61594
61690
  logger.info("Calculating diff...");
61595
61691
  logger.debug("Options:", options);
@@ -61783,13 +61879,14 @@ async function scrubCommand(stacks, options) {
61783
61879
  const logger = getLogger();
61784
61880
  if (options.verbose) logger.setLevel("debug");
61785
61881
  warnIfDeprecatedRegion(options);
61882
+ foldRegionOption(options);
61786
61883
  await applyRoleArnIfSet({
61787
61884
  roleArn: options.roleArn,
61788
61885
  region: options.region
61789
61886
  });
61790
61887
  const app = resolveApp(options.app);
61791
61888
  if (!app) throw new Error("CDK app is required (scrub needs the template to identify secret references). Pass --app, set CDKD_APP, or add \"app\" to cdk.json.");
61792
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
61889
+ const region = namedCliRegion(options.region) ?? "us-east-1";
61793
61890
  const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
61794
61891
  setAwsClients(new AwsClients({
61795
61892
  ...options.region && { region: options.region },
@@ -63178,6 +63275,7 @@ async function driftCommand(stacks, options) {
63178
63275
  if (options.verbose) logger.setLevel("debug");
63179
63276
  warnIfDeprecatedRegion(options);
63180
63277
  if (options.accept && options.revert) throw new Error("--accept and --revert are mutually exclusive. Use --accept to update cdkd state from AWS, or --revert to push cdkd state values back into AWS.");
63278
+ foldRegionOption(options);
63181
63279
  await applyRoleArnIfSet({
63182
63280
  roleArn: options.roleArn,
63183
63281
  region: options.region
@@ -63188,7 +63286,7 @@ async function driftCommand(stacks, options) {
63188
63286
  });
63189
63287
  setAwsClients(awsClients);
63190
63288
  try {
63191
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
63289
+ const region = namedCliRegion(options.region) ?? "us-east-1";
63192
63290
  const bucket = await resolveStateBucketWithDefault(options.stateBucket, region);
63193
63291
  const stateConfig = {
63194
63292
  bucket,
@@ -64858,11 +64956,12 @@ async function destroyCommand(stackArgs, options) {
64858
64956
  warnIfDeprecatedRegion(options);
64859
64957
  validateResourceTimeouts(options);
64860
64958
  setResolvedResourceTimeouts(options.resourceTimeout);
64959
+ foldRegionOption(options);
64861
64960
  await applyRoleArnIfSet({
64862
64961
  roleArn: options.roleArn,
64863
64962
  region: options.region
64864
64963
  });
64865
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
64964
+ const region = namedCliRegion(options.region) ?? "us-east-1";
64866
64965
  const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
64867
64966
  logger.info("Starting stack destruction...");
64868
64967
  logger.debug("Options:", options);
@@ -65137,11 +65236,12 @@ function createDestroyCommand() {
65137
65236
  async function stateMigrateCommand(options) {
65138
65237
  const logger = getLogger();
65139
65238
  if (options.verbose) logger.setLevel("debug");
65239
+ foldRegionOption(options);
65140
65240
  await applyRoleArnIfSet({
65141
65241
  roleArn: options.roleArn,
65142
65242
  region: options.region
65143
65243
  });
65144
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
65244
+ const region = namedCliRegion(options.region) ?? "us-east-1";
65145
65245
  const awsClients = new AwsClients({
65146
65246
  region,
65147
65247
  ...options.profile && { profile: options.profile }
@@ -66597,11 +66697,12 @@ async function exportCommand(stackArg, options) {
66597
66697
  }
66598
66698
  warnIfDeprecatedRegion(options);
66599
66699
  refuseTransientContextIfUnsafe(options);
66700
+ foldRegionOption(options);
66600
66701
  await applyRoleArnIfSet({
66601
66702
  roleArn: options.roleArn,
66602
66703
  region: options.region
66603
66704
  });
66604
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
66705
+ const region = namedCliRegion(options.region) ?? "us-east-1";
66605
66706
  const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
66606
66707
  if (options.region) {
66607
66708
  process.env["AWS_REGION"] = options.region;
@@ -69017,6 +69118,7 @@ function resolveSingleRegion(stackName, refs, requestedRegion) {
69017
69118
  */
69018
69119
  async function setupStateBackend(options) {
69019
69120
  warnIfDeprecatedRegion(options);
69121
+ foldRegionOption(options);
69020
69122
  await applyRoleArnIfSet({
69021
69123
  roleArn: options.roleArn,
69022
69124
  region: options.region
@@ -69026,7 +69128,7 @@ async function setupStateBackend(options) {
69026
69128
  ...options.profile && { profile: options.profile }
69027
69129
  });
69028
69130
  setAwsClients(awsClients);
69029
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
69131
+ const region = namedCliRegion(options.region) ?? "us-east-1";
69030
69132
  const bucket = await resolveStateBucketWithDefault(options.stateBucket, region);
69031
69133
  const prefix = options.statePrefix;
69032
69134
  const stateConfig = {
@@ -69917,6 +70019,7 @@ async function listAssetStorageMarkers(s3, bucket) {
69917
70019
  async function stateInfoCommand(options) {
69918
70020
  const logger = getLogger();
69919
70021
  if (options.verbose) logger.setLevel("debug");
70022
+ foldRegionOption(options);
69920
70023
  await applyRoleArnIfSet({
69921
70024
  roleArn: options.roleArn,
69922
70025
  region: options.region
@@ -69928,7 +70031,7 @@ async function stateInfoCommand(options) {
69928
70031
  setAwsClients(awsClients);
69929
70032
  let regionCorrectedS3 = null;
69930
70033
  try {
69931
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
70034
+ const region = namedCliRegion(options.region) ?? "us-east-1";
69932
70035
  const resolved = await resolveStateBucketWithDefaultAndSource(options.stateBucket, region);
69933
70036
  const bucket = resolved.bucket;
69934
70037
  const prefix = options.statePrefix;
@@ -70663,6 +70766,7 @@ async function eventsCommand(stackName, options) {
70663
70766
  const logger = getLogger();
70664
70767
  if (options.verbose) logger.setLevel("debug");
70665
70768
  warnIfDeprecatedRegion(options);
70769
+ foldRegionOption(options);
70666
70770
  const asJson = options.json === true;
70667
70771
  const awsClients = new AwsClients({
70668
70772
  ...options.region && { region: options.region },
@@ -70670,7 +70774,7 @@ async function eventsCommand(stackName, options) {
70670
70774
  });
70671
70775
  setAwsClients(awsClients);
70672
70776
  try {
70673
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
70777
+ const region = namedCliRegion(options.region) ?? "us-east-1";
70674
70778
  const bucket = await resolveStateBucketWithDefault(options.stateBucket, region);
70675
70779
  const prefix = options.statePrefix ?? "cdkd";
70676
70780
  const stateBackend = new S3StateBackend(awsClients.s3, {
@@ -70740,6 +70844,7 @@ async function eventsPruneCommand(stackName, options) {
70740
70844
  const logger = getLogger();
70741
70845
  if (options.verbose) logger.setLevel("debug");
70742
70846
  warnIfDeprecatedRegion(options);
70847
+ foldRegionOption(options);
70743
70848
  if (options.all === true && (options.keep !== void 0 || options.olderThan !== void 0)) throw new CdkdError("'--all' purges every run and cannot be combined with '--keep' / '--older-than'.", "EVENTS_PRUNE_BAD_FLAGS");
70744
70849
  const olderThanMs = options.olderThan !== void 0 ? parseDuration(options.olderThan) : void 0;
70745
70850
  const awsClients = new AwsClients({
@@ -70748,7 +70853,7 @@ async function eventsPruneCommand(stackName, options) {
70748
70853
  });
70749
70854
  setAwsClients(awsClients);
70750
70855
  try {
70751
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
70856
+ const region = namedCliRegion(options.region) ?? "us-east-1";
70752
70857
  const bucket = await resolveStateBucketWithDefault(options.stateBucket, region);
70753
70858
  const prefix = options.statePrefix ?? "cdkd";
70754
70859
  const stateBackend = new S3StateBackend(awsClients.s3, {
@@ -71800,7 +71905,7 @@ function formatAge(date) {
71800
71905
  async function promptGcConfirm(input) {
71801
71906
  const logger = getLogger();
71802
71907
  logger.warn("");
71803
- logger.warn("cdkd gc will delete the following unreferenced assets:");
71908
+ logger.warn(`cdkd gc will delete the following unreferenced assets in ${input.region}:`);
71804
71909
  for (const line of input.planLines) logger.warn(` - ${line}`);
71805
71910
  if (input.yes) return true;
71806
71911
  if (process.stdin.isTTY !== true) throw new CdkdError("The gc confirmation prompt cannot run in a non-interactive environment. Pass --yes / -y to confirm the deletion, or run the command from a real terminal.", "NON_INTERACTIVE_CONFIRM");
@@ -71863,10 +71968,10 @@ async function gcCommand(options) {
71863
71968
  logger.debug("Options:", options);
71864
71969
  await applyRoleArnIfSet({
71865
71970
  roleArn: options.roleArn,
71866
- region: canonicalizeRegion(options.region)
71971
+ region: namedCliRegion(options.region)
71867
71972
  });
71868
- const rawRegion = options.region || process.env["AWS_REGION"] || "us-east-1";
71869
- const region = canonicalizeRegion(rawRegion);
71973
+ const region = namedCliRegion(options.region) ?? "us-east-1";
71974
+ const rawRegion = rawCliRegion(options.region) ?? region;
71870
71975
  const awsClients = new AwsClients({
71871
71976
  region,
71872
71977
  ...options.profile && { profile: options.profile }
@@ -71930,7 +72035,7 @@ async function gcCommand(options) {
71930
72035
  const totals = `Total: ${s3Candidates.length} S3 object(s) (${formatBytes(s3Bytes)}) + ${ecrCandidates.length} ECR image(s) (${formatBytes(ecrBytes)}) = ${formatBytes(s3Bytes + ecrBytes)} reclaimable`;
71931
72036
  if (options.dryRun) {
71932
72037
  logger.info("");
71933
- logger.info("Dry run — the following unreferenced assets would be deleted:");
72038
+ logger.info(`Dry run — the following unreferenced assets in ${region} would be deleted:`);
71934
72039
  for (const line of planLines) logger.info(` - ${line}`);
71935
72040
  logger.info(totals);
71936
72041
  logger.info("Dry run: nothing deleted. Re-run without --dry-run to delete.");
@@ -71938,7 +72043,8 @@ async function gcCommand(options) {
71938
72043
  }
71939
72044
  if (!await promptGcConfirm({
71940
72045
  planLines: [...planLines, totals],
71941
- yes: options.yes
72046
+ yes: options.yes,
72047
+ region
71942
72048
  })) {
71943
72049
  logger.info("gc cancelled — nothing deleted.");
71944
72050
  return;
@@ -71962,7 +72068,7 @@ async function gcCommand(options) {
71962
72068
  * Create the `cdkd gc` command (upstream `cdk gc` parity naming).
71963
72069
  */
71964
72070
  function createGcCommand() {
71965
- const cmd = new Command("gc").description("Garbage-collect unreferenced objects / images from ONE region's cdkd-owned asset storage (asset bucket + container-asset ECR repo). References are collected from every cdkd state file; CDK bootstrap storage is never touched (use cdk gc for that).").option("--state-bucket <bucket>", "S3 bucket holding cdkd state (default: cdkd-state-{accountId})").addOption(new Option("--older-than <duration>", "Never delete an object / image newer than this age, even when unreferenced (protects in-flight publishes and recent rollback targets). Accepts <n>d / <n>h.").default(DEFAULT_OLDER_THAN_MS, "30d").argParser(parseOlderThan)).option("--dry-run", "Print the reclaim plan (per-item list + totals) without deleting", false).addOption(new Option("--region <region>", "Region whose cdkd asset storage to garbage-collect (defaults to AWS_REGION env or us-east-1)")).action(withErrorHandling(async (options) => {
72071
+ const cmd = new Command("gc").description("Garbage-collect unreferenced objects / images from ONE region's cdkd-owned asset storage (asset bucket + container-asset ECR repo). References are collected from every cdkd state file; CDK bootstrap storage is never touched (use cdk gc for that).").option("--state-bucket <bucket>", "S3 bucket holding cdkd state (default: cdkd-state-{accountId})").addOption(new Option("--older-than <duration>", "Never delete an object / image newer than this age, even when unreferenced (protects in-flight publishes and recent rollback targets). Accepts <n>d / <n>h.").default(DEFAULT_OLDER_THAN_MS, "30d").argParser(parseOlderThan)).option("--dry-run", "Print the reclaim plan (per-item list + totals) without deleting", false).addOption(new Option("--region <region>", "Region whose cdkd asset storage to garbage-collect (defaults to AWS_REGION / AWS_DEFAULT_REGION, else the profile region; refuses if none is configured)")).action(withErrorHandling(async (options) => {
71966
72072
  await gcCommand(options);
71967
72073
  }));
71968
72074
  commonOptions.forEach((opt) => cmd.addOption(opt));
@@ -72462,13 +72568,14 @@ async function orphanCommand(pathArgs, options) {
72462
72568
  const logger = getLogger();
72463
72569
  if (options.verbose) logger.setLevel("debug");
72464
72570
  warnIfDeprecatedRegion(options);
72571
+ foldRegionOption(options);
72465
72572
  await applyRoleArnIfSet({
72466
72573
  roleArn: options.roleArn,
72467
72574
  region: options.region
72468
72575
  });
72469
72576
  if (pathArgs.length === 0) throw new Error("'cdkd orphan' requires at least one construct path, e.g. 'cdkd orphan MyStack/MyTable'.\n To remove a stack's state record (the previous behavior), use:\n cdkd state orphan MyStack");
72470
72577
  for (const p of pathArgs) if (!p.includes("/")) throw new Error(`'cdkd orphan' now expects a construct path like 'MyStack/MyTable'.\n Got: '${p}'\n To remove a stack's state record (the previous behavior), use:\n cdkd state orphan ${p}`);
72471
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
72578
+ const region = namedCliRegion(options.region) ?? "us-east-1";
72472
72579
  const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
72473
72580
  if (options.region) {
72474
72581
  process.env["AWS_REGION"] = options.region;
@@ -72705,6 +72812,8 @@ async function publishAssetsCommand(stacks, options) {
72705
72812
  const logger = getLogger();
72706
72813
  if (options.verbose) logger.setLevel("debug");
72707
72814
  warnIfDeprecatedRegion(options);
72815
+ const rawBaseRegion = rawCliRegion(options.region) ?? "us-east-1";
72816
+ foldRegionOption(options);
72708
72817
  await applyRoleArnIfSet({
72709
72818
  roleArn: options.roleArn,
72710
72819
  region: options.region
@@ -72730,7 +72839,7 @@ async function publishAssetsCommand(stacks, options) {
72730
72839
  else if (allStacks.length === 1) targetStacks = allStacks;
72731
72840
  else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all`);
72732
72841
  if (targetStacks.length === 0) throw new Error(stackPatterns.length > 0 ? `No stacks matching ${stackPatterns.join(", ")} found in assembly. Available: ${allStacks.map(describeStack).join(", ")}` : "No stacks found in assembly");
72733
- const baseRegion = options.region || process.env["AWS_REGION"] || "us-east-1";
72842
+ const baseRegion = namedCliRegion(options.region) ?? "us-east-1";
72734
72843
  const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
72735
72844
  const stsClient = new STSClient({ region: baseRegion });
72736
72845
  const accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
@@ -72790,7 +72899,7 @@ async function publishAssetsCommand(stacks, options) {
72790
72899
  const modeResolver = await getModeResolver();
72791
72900
  if (modeResolver) {
72792
72901
  const stackRegion = stack.region || baseRegion;
72793
- const assetMode = await modeResolver.resolve(stackRegion);
72902
+ const assetMode = await modeResolver.resolve(stack.region || rawBaseRegion);
72794
72903
  if (assetMode.mode === "cdkd-assets") {
72795
72904
  const map = buildAssetRedirectMap(manifest, assetMode.marker, accountId, stackRegion);
72796
72905
  if (map.entries.length > 0) redirect = map;
@@ -72898,6 +73007,7 @@ async function forceUnlockCommand(stackArgs, options) {
72898
73007
  const logger = getLogger();
72899
73008
  if (options.verbose) logger.setLevel("debug");
72900
73009
  warnIfDeprecatedRegion(options);
73010
+ foldRegionOption(options);
72901
73011
  await applyRoleArnIfSet({
72902
73012
  roleArn: options.roleArn,
72903
73013
  region: options.region
@@ -72909,7 +73019,7 @@ async function forceUnlockCommand(stackArgs, options) {
72909
73019
  ...options.profile && { profile: options.profile }
72910
73020
  });
72911
73021
  setAwsClients(awsClients);
72912
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
73022
+ const region = namedCliRegion(options.region) ?? "us-east-1";
72913
73023
  const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
72914
73024
  try {
72915
73025
  const stateConfig = {
@@ -72968,11 +73078,12 @@ async function importCommand(stackArg, options) {
72968
73078
  logger.setLevel("debug");
72969
73079
  process.env["CDKD_NO_LIVE"] = "1";
72970
73080
  }
73081
+ foldRegionOption(options);
72971
73082
  await applyRoleArnIfSet({
72972
73083
  roleArn: options.roleArn,
72973
73084
  region: options.region
72974
73085
  });
72975
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
73086
+ const region = namedCliRegion(options.region) ?? "us-east-1";
72976
73087
  const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
72977
73088
  if (options.region) {
72978
73089
  process.env["AWS_REGION"] = options.region;
@@ -83562,11 +83673,12 @@ async function migrateCommandAction(positionalStack, options) {
83562
83673
  if (options.retireCfnStack && options.skipSynth) throw new LocalMigrateError("--retire-cfn-stack is incompatible with --skip-synth: the post-state-write retirement (UpdateStack + DeleteStack) cannot run without a synthesized template + cdkd state.");
83563
83674
  if (options.retireCfnStack && options.dryRun) throw new LocalMigrateError("--retire-cfn-stack is incompatible with --dry-run: retirement issues real AWS calls (UpdateStack injects Retain policies, then DeleteStack).");
83564
83675
  if (options.retireCfnStack && options.filter && options.filter.length > 0) throw new LocalMigrateError("--retire-cfn-stack is incompatible with --filter: a partial migration that retires the whole source CFn stack would strand the un-migrated resources. Drop one of the flags or migrate the rest of the stack first.");
83676
+ foldRegionOption(options);
83565
83677
  await applyRoleArnIfSet({
83566
83678
  roleArn: options.roleArn,
83567
83679
  region: options.region
83568
83680
  });
83569
- const region = options.region || process.env["AWS_REGION"] || "us-east-1";
83681
+ const region = namedCliRegion(options.region) ?? "us-east-1";
83570
83682
  const outputDir = resolve(options.outputDir ?? sourceCfnStackName);
83571
83683
  logger.info(`[migrate] Source CFn stack: ${sourceCfnStackName}`);
83572
83684
  logger.info(`[migrate] Output directory: ${outputDir}`);
@@ -83731,7 +83843,7 @@ function createMigrateCommand() {
83731
83843
  */
83732
83844
  function buildProgram() {
83733
83845
  const program = new Command();
83734
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.20");
83846
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.21");
83735
83847
  program.hook("preAction", (_thisCommand, actionCommand) => {
83736
83848
  const { profile } = actionCommand.optsWithGlobals();
83737
83849
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;