@go-to-k/cdkd 0.9.0 → 0.11.0

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/README.md CHANGED
@@ -95,7 +95,7 @@ Reproduce with `./tests/benchmark/run-benchmark.sh all`. See [tests/benchmark/RE
95
95
  ```
96
96
  1. CLI Layer
97
97
  ├── Resolve --app (CLI > CDKD_APP env > cdk.json "app")
98
- ├── Resolve --state-bucket (CLI > env > cdk.json > auto: cdkd-state-{accountId}-{region})
98
+ ├── Resolve --state-bucket (CLI > env > cdk.json > auto: cdkd-state-{accountId}, with legacy fallback to cdkd-state-{accountId}-{region})
99
99
  └── Initialize AWS clients
100
100
 
101
101
  2. Synthesis (self-implemented, no CDK CLI dependency)
@@ -355,7 +355,7 @@ cdkd diff
355
355
  cdkd destroy
356
356
  ```
357
357
 
358
- That's it. cdkd reads `--app` from `cdk.json` and auto-resolves the state bucket from your AWS account ID (`cdkd-state-{accountId}-{region}`).
358
+ That's it. cdkd reads `--app` from `cdk.json` and auto-resolves the state bucket from your AWS account ID (`cdkd-state-{accountId}`). If you bootstrapped under a previous cdkd version, the legacy region-suffixed name (`cdkd-state-{accountId}-{region}`) is still picked up automatically with a deprecation warning.
359
359
 
360
360
  ## Usage
361
361
 
@@ -547,7 +547,7 @@ s3://{state-bucket}/
547
547
 
548
548
  | Setting | CLI | cdk.json | Env var | Default |
549
549
  |---------|-----|----------|---------|---------|
550
- | Bucket | `--state-bucket` | `context.cdkd.stateBucket` | `CDKD_STATE_BUCKET` | `cdkd-state-{accountId}-{region}` |
550
+ | Bucket | `--state-bucket` | `context.cdkd.stateBucket` | `CDKD_STATE_BUCKET` | `cdkd-state-{accountId}` (legacy `cdkd-state-{accountId}-{region}` is still read with a deprecation warning) |
551
551
  | Prefix | `--state-prefix` | - | - | `cdkd` |
552
552
 
553
553
  ### Multi-app isolation
package/dist/cli.js CHANGED
@@ -885,6 +885,40 @@ function withErrorHandling(fn) {
885
885
  }
886
886
  };
887
887
  }
888
+ function normalizeAwsError(err, context = {}) {
889
+ if (!(err instanceof Error)) {
890
+ return new Error(String(err));
891
+ }
892
+ const isUnknown = err.name === "Unknown" || err.message === "UnknownError";
893
+ if (!isUnknown)
894
+ return err;
895
+ const meta = err.$metadata;
896
+ const status = meta?.httpStatusCode;
897
+ const bucket = context.bucket ?? "<unknown bucket>";
898
+ const operation = context.operation ?? "operation";
899
+ switch (status) {
900
+ case 301: {
901
+ const responseHeaders = err.$response?.headers;
902
+ const region = responseHeaders?.["x-amz-bucket-region"] ?? responseHeaders?.["X-Amz-Bucket-Region"];
903
+ const where = region ? ` (in ${region})` : "";
904
+ return new Error(
905
+ `Bucket '${bucket}'${where} is in a different region than the client. cdkd resolves this automatically; if you see this message, please report it.`
906
+ );
907
+ }
908
+ case 403:
909
+ return new Error(
910
+ `Access denied to bucket '${bucket}'. Verify credentials and bucket policy.`
911
+ );
912
+ case 404:
913
+ return new Error(`Bucket '${bucket}' does not exist.`);
914
+ default: {
915
+ const statusStr = status !== void 0 ? `HTTP ${status}` : "unknown HTTP status";
916
+ return new Error(
917
+ `S3 error during ${operation} on '${bucket}' (${statusStr}). See CloudTrail for details.`
918
+ );
919
+ }
920
+ }
921
+ }
888
922
 
889
923
  // src/cli/commands/bootstrap.ts
890
924
  init_aws_clients();
@@ -937,7 +971,10 @@ function resolveStateBucket(cliBucket) {
937
971
  const bucket = cdkdContext?.["stateBucket"];
938
972
  return typeof bucket === "string" ? bucket : void 0;
939
973
  }
940
- function getDefaultStateBucketName(accountId, region) {
974
+ function getDefaultStateBucketName(accountId) {
975
+ return `cdkd-state-${accountId}`;
976
+ }
977
+ function getLegacyStateBucketName(accountId, region) {
941
978
  return `cdkd-state-${accountId}-${region}`;
942
979
  }
943
980
  async function resolveStateBucketWithDefault(cliBucket, region) {
@@ -947,13 +984,48 @@ async function resolveStateBucketWithDefault(cliBucket, region) {
947
984
  const logger = getLogger();
948
985
  logger.debug("No state bucket specified, resolving default from account...");
949
986
  const { GetCallerIdentityCommand: GetCallerIdentityCommand8 } = await import("@aws-sdk/client-sts");
987
+ const { S3Client: S3Client10 } = await import("@aws-sdk/client-s3");
950
988
  const { getAwsClients: getAwsClients2 } = await Promise.resolve().then(() => (init_aws_clients(), aws_clients_exports));
951
989
  const awsClients = getAwsClients2();
952
990
  const identity = await awsClients.sts.send(new GetCallerIdentityCommand8({}));
953
991
  const accountId = identity.Account;
954
- const bucketName = getDefaultStateBucketName(accountId, region);
955
- logger.info(`State bucket: ${bucketName}`);
956
- return bucketName;
992
+ const newName = getDefaultStateBucketName(accountId);
993
+ const legacyName = getLegacyStateBucketName(accountId, region);
994
+ const probe = new S3Client10({ region: "us-east-1" });
995
+ try {
996
+ if (await bucketExists(probe, newName)) {
997
+ logger.info(`State bucket: ${newName}`);
998
+ return newName;
999
+ }
1000
+ if (await bucketExists(probe, legacyName)) {
1001
+ logger.warn(
1002
+ `Using legacy state bucket name '${legacyName}'. The default has changed to '${newName}'. Future cdkd versions will drop legacy support; consider migrating with cdkd state migrate-bucket (coming in a future release).`
1003
+ );
1004
+ return legacyName;
1005
+ }
1006
+ throw new Error(
1007
+ `No cdkd state bucket found for account ${accountId}. Looked for '${newName}' (current default) and '${legacyName}' (legacy default). Run 'cdkd bootstrap' to create '${newName}'.`
1008
+ );
1009
+ } finally {
1010
+ probe.destroy();
1011
+ }
1012
+ }
1013
+ async function bucketExists(client, bucketName) {
1014
+ const { HeadBucketCommand: HeadBucketCommand3 } = await import("@aws-sdk/client-s3");
1015
+ try {
1016
+ await client.send(new HeadBucketCommand3({ Bucket: bucketName }));
1017
+ return true;
1018
+ } catch (error) {
1019
+ const err = error;
1020
+ const status = err.$metadata?.httpStatusCode;
1021
+ if (err.name === "NotFound" || err.name === "NoSuchBucket" || status === 404) {
1022
+ return false;
1023
+ }
1024
+ if (status === 301 || status === 403) {
1025
+ return true;
1026
+ }
1027
+ throw error;
1028
+ }
957
1029
  }
958
1030
 
959
1031
  // src/cli/commands/bootstrap.ts
@@ -981,24 +1053,24 @@ async function bootstrapCommand(options) {
981
1053
  logger.info("No --state-bucket specified, resolving default bucket name...");
982
1054
  const identity = await awsClients.sts.send(new GetCallerIdentityCommand({}));
983
1055
  accountId = identity.Account;
984
- bucketName = getDefaultStateBucketName(accountId, region);
1056
+ bucketName = getDefaultStateBucketName(accountId);
985
1057
  logger.info(`Using default state bucket: ${bucketName}`);
986
1058
  }
987
1059
  try {
988
- let bucketExists = false;
1060
+ let bucketExists2 = false;
989
1061
  try {
990
1062
  await s3Client.send(new HeadBucketCommand({ Bucket: bucketName }));
991
- bucketExists = true;
1063
+ bucketExists2 = true;
992
1064
  logger.info(`Bucket ${bucketName} already exists`);
993
1065
  } catch (error) {
994
1066
  const err = error;
995
1067
  if (err.name === "NotFound" || err.name === "NoSuchBucket") {
996
1068
  logger.debug(`Bucket ${bucketName} does not exist, will create`);
997
1069
  } else {
998
- throw error;
1070
+ throw normalizeAwsError(error, { bucket: bucketName, operation: "HeadBucket" });
999
1071
  }
1000
1072
  }
1001
- if (bucketExists) {
1073
+ if (bucketExists2) {
1002
1074
  if (!options.force) {
1003
1075
  logger.warn(
1004
1076
  `Bucket ${bucketName} already exists. Use --force to reconfigure (this will not delete existing state)`
@@ -1085,7 +1157,7 @@ State bucket: ${bucketName}`);
1085
1157
  function createBootstrapCommand() {
1086
1158
  const cmd = new Command("bootstrap").description("Bootstrap cdkd by creating required S3 bucket for state management").option(
1087
1159
  "--state-bucket <bucket>",
1088
- "Name of S3 bucket to create for state storage (default: cdkd-state-{accountId}-{region})"
1160
+ "Name of S3 bucket to create for state storage (default: cdkd-state-{accountId})"
1089
1161
  ).option("--force", "Force reconfiguration of existing bucket", false).action(withErrorHandling(bootstrapCommand));
1090
1162
  commonOptions.forEach((opt) => cmd.addOption(opt));
1091
1163
  return cmd;
@@ -3197,6 +3269,7 @@ var AssetPublisher = class {
3197
3269
 
3198
3270
  // src/state/s3-state-backend.ts
3199
3271
  import {
3272
+ S3Client as S3Client4,
3200
3273
  GetObjectCommand,
3201
3274
  PutObjectCommand as PutObjectCommand2,
3202
3275
  DeleteObjectCommand,
@@ -3210,15 +3283,44 @@ import {
3210
3283
  var STATE_SCHEMA_VERSION_LEGACY = 1;
3211
3284
  var STATE_SCHEMA_VERSION_CURRENT = 2;
3212
3285
 
3286
+ // src/utils/aws-region-resolver.ts
3287
+ import { GetBucketLocationCommand, S3Client as S3Client3 } from "@aws-sdk/client-s3";
3288
+ var cache = /* @__PURE__ */ new Map();
3289
+ async function resolveBucketRegion(bucketName, opts = {}) {
3290
+ const cached = cache.get(bucketName);
3291
+ if (cached)
3292
+ return cached;
3293
+ const promise = (async () => {
3294
+ const client = new S3Client3({
3295
+ region: "us-east-1",
3296
+ ...opts.profile && { profile: opts.profile },
3297
+ ...opts.credentials && { credentials: opts.credentials }
3298
+ });
3299
+ try {
3300
+ const response = await client.send(new GetBucketLocationCommand({ Bucket: bucketName }));
3301
+ return response.LocationConstraint || "us-east-1";
3302
+ } catch {
3303
+ return opts.fallbackRegion ?? "us-east-1";
3304
+ } finally {
3305
+ client.destroy();
3306
+ }
3307
+ })();
3308
+ cache.set(bucketName, promise);
3309
+ return promise;
3310
+ }
3311
+
3213
3312
  // src/state/s3-state-backend.ts
3214
3313
  var LEGACY_KEY_DEPTH = 2;
3215
3314
  var NEW_KEY_DEPTH = 3;
3216
3315
  var S3StateBackend = class {
3217
- constructor(s3Client, config) {
3316
+ constructor(s3Client, config, clientOpts = {}) {
3218
3317
  this.s3Client = s3Client;
3219
3318
  this.config = config;
3319
+ this.clientOpts = clientOpts;
3220
3320
  }
3221
3321
  logger = getLogger().child("S3StateBackend");
3322
+ clientResolved = false;
3323
+ resolveInFlight = null;
3222
3324
  /**
3223
3325
  * Get the new (region-scoped) S3 key for a stack's state file.
3224
3326
  */
@@ -3232,13 +3334,73 @@ var S3StateBackend = class {
3232
3334
  getLegacyStateKey(stackName) {
3233
3335
  return `${this.config.prefix}/${stackName}/state.json`;
3234
3336
  }
3337
+ /**
3338
+ * Resolve the state bucket's actual region and, if it differs from the
3339
+ * client's currently-configured region, replace the S3Client with one
3340
+ * pointed at the bucket's region.
3341
+ *
3342
+ * This is idempotent: subsequent calls return immediately. Concurrent
3343
+ * callers (e.g. when several public methods race during a parallel deploy)
3344
+ * share a single in-flight resolution promise so we never issue more than
3345
+ * one `GetBucketLocation` per backend.
3346
+ *
3347
+ * Errors from `GetBucketLocation` are deliberately swallowed by
3348
+ * `resolveBucketRegion` — the resolver returns `fallbackRegion` so the
3349
+ * caller can surface the more actionable downstream error (e.g. the
3350
+ * `HeadBucket` 404 routed via `normalizeAwsError`).
3351
+ */
3352
+ async ensureClientForBucket() {
3353
+ if (this.clientResolved)
3354
+ return;
3355
+ if (this.resolveInFlight)
3356
+ return this.resolveInFlight;
3357
+ this.resolveInFlight = (async () => {
3358
+ try {
3359
+ const currentRegion = await this.s3Client.config.region();
3360
+ const fallbackRegion = typeof currentRegion === "string" ? currentRegion : void 0;
3361
+ const bucketRegion = await resolveBucketRegion(this.config.bucket, {
3362
+ ...this.clientOpts.profile && { profile: this.clientOpts.profile },
3363
+ ...this.clientOpts.credentials && { credentials: this.clientOpts.credentials },
3364
+ ...fallbackRegion && { fallbackRegion }
3365
+ });
3366
+ if (bucketRegion !== currentRegion) {
3367
+ this.logger.debug(
3368
+ `State bucket '${this.config.bucket}' is in '${bucketRegion}' (client was '${currentRegion}'); rebuilding S3 client.`
3369
+ );
3370
+ const oldClient = this.s3Client;
3371
+ this.s3Client = new S3Client4({
3372
+ region: bucketRegion,
3373
+ ...this.clientOpts.profile && { profile: this.clientOpts.profile },
3374
+ ...this.clientOpts.credentials && { credentials: this.clientOpts.credentials },
3375
+ // Suppress "Are you using a Stream of unknown length" warning,
3376
+ // matching the suppression in AwsClients.
3377
+ logger: { debug: () => {
3378
+ }, info: () => {
3379
+ }, warn: () => {
3380
+ }, error: () => {
3381
+ } }
3382
+ });
3383
+ oldClient.destroy();
3384
+ }
3385
+ this.clientResolved = true;
3386
+ } finally {
3387
+ this.resolveInFlight = null;
3388
+ }
3389
+ })();
3390
+ return this.resolveInFlight;
3391
+ }
3235
3392
  /**
3236
3393
  * Verify that the configured state bucket exists.
3237
3394
  *
3238
3395
  * Called early in deploy/destroy to fail fast before expensive work
3239
3396
  * (asset publishing, Docker builds) runs against a missing bucket.
3397
+ *
3398
+ * Errors are routed through {@link normalizeAwsError} so the AWS SDK v3
3399
+ * synthetic `UnknownError` (e.g. cross-region HEAD) becomes a concrete
3400
+ * "Bucket does not exist" / "Access denied" / "different region" message.
3240
3401
  */
3241
3402
  async verifyBucketExists() {
3403
+ await this.ensureClientForBucket();
3242
3404
  try {
3243
3405
  await this.s3Client.send(new HeadBucketCommand2({ Bucket: this.config.bucket }));
3244
3406
  } catch (error) {
@@ -3248,9 +3410,13 @@ var S3StateBackend = class {
3248
3410
  `State bucket '${this.config.bucket}' does not exist. Run 'cdkd bootstrap' to create it, or specify an existing bucket via --state-bucket, CDKD_STATE_BUCKET, or cdk.json context.cdkd.stateBucket.`
3249
3411
  );
3250
3412
  }
3413
+ const normalized = normalizeAwsError(error, {
3414
+ bucket: this.config.bucket,
3415
+ operation: "HeadBucket"
3416
+ });
3251
3417
  throw new StateError(
3252
- `Failed to verify state bucket '${this.config.bucket}': ${error instanceof Error ? error.message : String(error)}`,
3253
- error instanceof Error ? error : void 0
3418
+ `Failed to verify state bucket '${this.config.bucket}': ${normalized.message}`,
3419
+ normalized
3254
3420
  );
3255
3421
  }
3256
3422
  }
@@ -3263,6 +3429,7 @@ var S3StateBackend = class {
3263
3429
  * state without forcing a write-through migration first.
3264
3430
  */
3265
3431
  async stateExists(stackName, region) {
3432
+ await this.ensureClientForBucket();
3266
3433
  const newKey = this.getStateKey(stackName, region);
3267
3434
  if (await this.headObject(newKey)) {
3268
3435
  return true;
@@ -3285,6 +3452,7 @@ var S3StateBackend = class {
3285
3452
  * preserve the quotes — they are required for `IfMatch` conditions.
3286
3453
  */
3287
3454
  async getState(stackName, region) {
3455
+ await this.ensureClientForBucket();
3288
3456
  const newKey = this.getStateKey(stackName, region);
3289
3457
  try {
3290
3458
  this.logger.debug(`Getting state for stack: ${stackName} (${region})`);
@@ -3344,6 +3512,7 @@ var S3StateBackend = class {
3344
3512
  * @returns New ETag (with quotes, e.g., `"abc123"`)
3345
3513
  */
3346
3514
  async saveState(stackName, region, state, options = {}) {
3515
+ await this.ensureClientForBucket();
3347
3516
  const newKey = this.getStateKey(stackName, region);
3348
3517
  const { expectedEtag, migrateLegacy } = options;
3349
3518
  const body = {
@@ -3399,9 +3568,13 @@ var S3StateBackend = class {
3399
3568
  `State has been modified by another process. Expected ETag: ${expectedEtag}, but state has changed.`
3400
3569
  );
3401
3570
  }
3571
+ const normalized = normalizeAwsError(error, {
3572
+ bucket: this.config.bucket,
3573
+ operation: "PutObject"
3574
+ });
3402
3575
  throw new StateError(
3403
- `Failed to save state for stack '${stackName}' (${region}): ${error instanceof Error ? error.message : String(error)}`,
3404
- error instanceof Error ? error : void 0
3576
+ `Failed to save state for stack '${stackName}' (${region}): ${normalized.message}`,
3577
+ normalized
3405
3578
  );
3406
3579
  }
3407
3580
  }
@@ -3413,6 +3586,7 @@ var S3StateBackend = class {
3413
3586
  * field is left alone.
3414
3587
  */
3415
3588
  async deleteState(stackName, region) {
3589
+ await this.ensureClientForBucket();
3416
3590
  try {
3417
3591
  this.logger.debug(`Deleting state: ${stackName} (${region})`);
3418
3592
  await this.s3Client.send(
@@ -3432,9 +3606,13 @@ var S3StateBackend = class {
3432
3606
  }
3433
3607
  this.logger.debug(`State deleted: ${stackName} (${region})`);
3434
3608
  } catch (error) {
3609
+ const normalized = normalizeAwsError(error, {
3610
+ bucket: this.config.bucket,
3611
+ operation: "DeleteObject"
3612
+ });
3435
3613
  throw new StateError(
3436
- `Failed to delete state for stack '${stackName}' (${region}): ${error instanceof Error ? error.message : String(error)}`,
3437
- error instanceof Error ? error : void 0
3614
+ `Failed to delete state for stack '${stackName}' (${region}): ${normalized.message}`,
3615
+ normalized
3438
3616
  );
3439
3617
  }
3440
3618
  }
@@ -3453,6 +3631,7 @@ var S3StateBackend = class {
3453
3631
  * shows up exactly once.
3454
3632
  */
3455
3633
  async listStacks() {
3634
+ await this.ensureClientForBucket();
3456
3635
  try {
3457
3636
  this.logger.debug("Listing all stacks");
3458
3637
  const prefix = `${this.config.prefix}/`;
@@ -3503,10 +3682,11 @@ var S3StateBackend = class {
3503
3682
  this.logger.debug(`Found ${refs.length} stack(s) across regions`);
3504
3683
  return refs;
3505
3684
  } catch (error) {
3506
- throw new StateError(
3507
- `Failed to list stacks: ${error instanceof Error ? error.message : String(error)}`,
3508
- error instanceof Error ? error : void 0
3509
- );
3685
+ const normalized = normalizeAwsError(error, {
3686
+ bucket: this.config.bucket,
3687
+ operation: "ListObjectsV2"
3688
+ });
3689
+ throw new StateError(`Failed to list stacks: ${normalized.message}`, normalized);
3510
3690
  }
3511
3691
  }
3512
3692
  /**
@@ -6804,7 +6984,7 @@ Error: ${err.message || "Unknown error"}`,
6804
6984
  import { InvokeCommand } from "@aws-sdk/client-lambda";
6805
6985
  import { PublishCommand } from "@aws-sdk/client-sns";
6806
6986
  import {
6807
- S3Client as S3Client5,
6987
+ S3Client as S3Client6,
6808
6988
  PutObjectCommand as PutObjectCommand4,
6809
6989
  GetObjectCommand as GetObjectCommand3,
6810
6990
  DeleteObjectCommand as DeleteObjectCommand3
@@ -6873,7 +7053,7 @@ var CustomResourceProvider = class _CustomResourceProvider {
6873
7053
  setResponseBucket(bucket, bucketRegion) {
6874
7054
  this.responseBucket = bucket;
6875
7055
  if (bucketRegion) {
6876
- this.s3Client = new S3Client5(bucketRegion ? { region: bucketRegion } : {});
7056
+ this.s3Client = new S3Client6(bucketRegion ? { region: bucketRegion } : {});
6877
7057
  }
6878
7058
  }
6879
7059
  /**
@@ -25798,7 +25978,7 @@ var CodeBuildProvider = class {
25798
25978
  const tags = properties["Tags"];
25799
25979
  const envVars = environment?.["EnvironmentVariables"];
25800
25980
  const cfnCache = properties["Cache"];
25801
- const cache = cfnCache ? {
25981
+ const cache2 = cfnCache ? {
25802
25982
  type: cfnCache["Type"],
25803
25983
  location: cfnCache["Location"],
25804
25984
  modes: cfnCache["Modes"]
@@ -25885,7 +26065,7 @@ var CodeBuildProvider = class {
25885
26065
  timeoutInMinutes: properties["TimeoutInMinutes"],
25886
26066
  queuedTimeoutInMinutes: properties["QueuedTimeoutInMinutes"],
25887
26067
  encryptionKey: properties["EncryptionKey"],
25888
- cache,
26068
+ cache: cache2,
25889
26069
  vpcConfig,
25890
26070
  logsConfig,
25891
26071
  concurrentBuildLimit: properties["ConcurrentBuildLimit"],
@@ -28429,10 +28609,17 @@ async function deployCommand(stacks, options) {
28429
28609
  ...options.profile && { profile: options.profile }
28430
28610
  });
28431
28611
  setAwsClients(awsClients);
28432
- const preflightStateBackend = new S3StateBackend(awsClients.s3, {
28433
- bucket: stateBucket,
28434
- prefix: options.statePrefix
28435
- });
28612
+ const preflightStateBackend = new S3StateBackend(
28613
+ awsClients.s3,
28614
+ {
28615
+ bucket: stateBucket,
28616
+ prefix: options.statePrefix
28617
+ },
28618
+ {
28619
+ region,
28620
+ ...options.profile && { profile: options.profile }
28621
+ }
28622
+ );
28436
28623
  await preflightStateBackend.verifyBucketExists();
28437
28624
  let deployInterrupted = false;
28438
28625
  const topLevelSigintHandler = () => {
@@ -28583,7 +28770,10 @@ Deploying stack: ${stackInfo.stackName}${stackRegion !== baseRegion ? ` (region:
28583
28770
  region: baseRegion,
28584
28771
  ...options.profile && { profile: options.profile }
28585
28772
  });
28586
- const stackStateBackend = new S3StateBackend(stateS3Client.s3, stateConfig);
28773
+ const stackStateBackend = new S3StateBackend(stateS3Client.s3, stateConfig, {
28774
+ region: baseRegion,
28775
+ ...options.profile && { profile: options.profile }
28776
+ });
28587
28777
  const stackLockManager = new LockManager(stateS3Client.s3, stateConfig);
28588
28778
  const stackProviderRegistry = new ProviderRegistry();
28589
28779
  registerAllProviders(stackProviderRegistry);
@@ -28764,7 +28954,10 @@ async function diffCommand(stacks, options) {
28764
28954
  bucket: stateBucket,
28765
28955
  prefix: options.statePrefix
28766
28956
  };
28767
- const stateBackend = new S3StateBackend(awsClients.s3, stateConfig);
28957
+ const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
28958
+ region,
28959
+ ...options.profile && { profile: options.profile }
28960
+ });
28768
28961
  const diffCalculator = new DiffCalculator();
28769
28962
  const intrinsicResolver = new IntrinsicFunctionResolver(region);
28770
28963
  for (const stackInfo of targetStacks) {
@@ -28884,7 +29077,10 @@ async function destroyCommand(stackArgs, options) {
28884
29077
  bucket: stateBucket,
28885
29078
  prefix: options.statePrefix
28886
29079
  };
28887
- const stateBackend = new S3StateBackend(awsClients.s3, stateConfig);
29080
+ const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
29081
+ ...options.region && { region: options.region },
29082
+ ...options.profile && { profile: options.profile }
29083
+ });
28888
29084
  await stateBackend.verifyBucketExists();
28889
29085
  const lockManager = new LockManager(awsClients.s3, stateConfig);
28890
29086
  const dagBuilder = new DagBuilder();
@@ -29333,7 +29529,10 @@ async function setupStateBackend(options) {
29333
29529
  const bucket = await resolveStateBucketWithDefault(options.stateBucket, region);
29334
29530
  const prefix = options.statePrefix;
29335
29531
  const stateConfig = { bucket, prefix };
29336
- const stateBackend = new S3StateBackend(awsClients.s3, stateConfig);
29532
+ const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
29533
+ region,
29534
+ ...options.profile && { profile: options.profile }
29535
+ });
29337
29536
  const lockManager = new LockManager(awsClients.s3, stateConfig);
29338
29537
  await stateBackend.verifyBucketExists();
29339
29538
  return {
@@ -29737,7 +29936,7 @@ function reorderArgs(argv) {
29737
29936
  }
29738
29937
  async function main() {
29739
29938
  const program = new Command10();
29740
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.9.0");
29939
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.11.0");
29741
29940
  program.addCommand(createBootstrapCommand());
29742
29941
  program.addCommand(createSynthCommand());
29743
29942
  program.addCommand(createListCommand());