@go-to-k/cdkd 0.13.0 → 0.14.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
@@ -628,7 +628,7 @@ After deployment, outputs are resolved and saved to the S3 state file:
628
628
  **Key differences from CloudFormation**:
629
629
 
630
630
  - CloudFormation: Outputs accessible via `aws cloudformation describe-stacks`
631
- - cdkd: Outputs saved in S3 state file (e.g., `s3://bucket/cdkd/MyStack/state.json`)
631
+ - cdkd: Outputs saved in S3 state file (e.g., `s3://bucket/cdkd/MyStack/us-east-1/state.json`)
632
632
  - Both resolve intrinsic functions (Ref, Fn::GetAtt, etc.) to actual values
633
633
 
634
634
  ## Testing
package/dist/cli.js CHANGED
@@ -447,7 +447,7 @@ var init_aws_clients = __esm({
447
447
  });
448
448
 
449
449
  // src/cli/index.ts
450
- import { Command as Command10 } from "commander";
450
+ import { Command as Command11 } from "commander";
451
451
 
452
452
  // src/cli/commands/bootstrap.ts
453
453
  import { Command, Option as Option2 } from "commander";
@@ -998,15 +998,15 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
998
998
  return syncResult;
999
999
  const logger = getLogger();
1000
1000
  logger.debug("No state bucket specified, resolving default from account...");
1001
- const { GetCallerIdentityCommand: GetCallerIdentityCommand8 } = await import("@aws-sdk/client-sts");
1002
- const { S3Client: S3Client10 } = await import("@aws-sdk/client-s3");
1001
+ const { GetCallerIdentityCommand: GetCallerIdentityCommand9 } = await import("@aws-sdk/client-sts");
1002
+ const { S3Client: S3Client11 } = await import("@aws-sdk/client-s3");
1003
1003
  const { getAwsClients: getAwsClients2 } = await Promise.resolve().then(() => (init_aws_clients(), aws_clients_exports));
1004
1004
  const awsClients = getAwsClients2();
1005
- const identity = await awsClients.sts.send(new GetCallerIdentityCommand8({}));
1005
+ const identity = await awsClients.sts.send(new GetCallerIdentityCommand9({}));
1006
1006
  const accountId = identity.Account;
1007
1007
  const newName = getDefaultStateBucketName(accountId);
1008
1008
  const legacyName = getLegacyStateBucketName(accountId, region);
1009
- const probe = new S3Client10({ region: "us-east-1" });
1009
+ const probe = new S3Client11({ region: "us-east-1" });
1010
1010
  try {
1011
1011
  if (await bucketExists(probe, newName)) {
1012
1012
  logger.debug(`State bucket: ${newName}`);
@@ -1014,7 +1014,11 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
1014
1014
  }
1015
1015
  if (await bucketExists(probe, legacyName)) {
1016
1016
  logger.warn(
1017
- `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).`
1017
+ `Using legacy state bucket name '${legacyName}'. The default has changed to '${newName}'. To migrate, run:
1018
+
1019
+ cdkd state migrate-bucket --region ${region}
1020
+
1021
+ (add --remove-legacy to delete the legacy bucket after a successful copy; legacy support will be dropped in a future release.)`
1018
1022
  );
1019
1023
  return { bucket: legacyName, source: "default-legacy" };
1020
1024
  }
@@ -1026,9 +1030,9 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
1026
1030
  }
1027
1031
  }
1028
1032
  async function bucketExists(client, bucketName) {
1029
- const { HeadBucketCommand: HeadBucketCommand3 } = await import("@aws-sdk/client-s3");
1033
+ const { HeadBucketCommand: HeadBucketCommand4 } = await import("@aws-sdk/client-s3");
1030
1034
  try {
1031
- await client.send(new HeadBucketCommand3({ Bucket: bucketName }));
1035
+ await client.send(new HeadBucketCommand4({ Bucket: bucketName }));
1032
1036
  return true;
1033
1037
  } catch (error) {
1034
1038
  const err = error;
@@ -1072,10 +1076,10 @@ async function bootstrapCommand(options) {
1072
1076
  logger.info(`Using default state bucket: ${bucketName}`);
1073
1077
  }
1074
1078
  try {
1075
- let bucketExists2 = false;
1079
+ let bucketExists3 = false;
1076
1080
  try {
1077
1081
  await s3Client.send(new HeadBucketCommand({ Bucket: bucketName }));
1078
- bucketExists2 = true;
1082
+ bucketExists3 = true;
1079
1083
  logger.info(`Bucket ${bucketName} already exists`);
1080
1084
  } catch (error) {
1081
1085
  const err = error;
@@ -1085,7 +1089,7 @@ async function bootstrapCommand(options) {
1085
1089
  throw normalizeAwsError(error, { bucket: bucketName, operation: "HeadBucket" });
1086
1090
  }
1087
1091
  }
1088
- if (bucketExists2) {
1092
+ if (bucketExists3) {
1089
1093
  if (!options.force) {
1090
1094
  logger.warn(
1091
1095
  `Bucket ${bucketName} already exists. Use --force to reconfigure (this will not delete existing state)`
@@ -3239,9 +3243,9 @@ var AssetPublisher = class {
3239
3243
  const region = options.region || process.env["AWS_REGION"] || "us-east-1";
3240
3244
  let accountId = options.accountId;
3241
3245
  if (!accountId) {
3242
- const { STSClient: STSClient7, GetCallerIdentityCommand: GetCallerIdentityCommand8 } = await import("@aws-sdk/client-sts");
3246
+ const { STSClient: STSClient7, GetCallerIdentityCommand: GetCallerIdentityCommand9 } = await import("@aws-sdk/client-sts");
3243
3247
  const stsClient = new STSClient7({ region });
3244
- const identity = await stsClient.send(new GetCallerIdentityCommand8({}));
3248
+ const identity = await stsClient.send(new GetCallerIdentityCommand9({}));
3245
3249
  accountId = identity.Account;
3246
3250
  stsClient.destroy();
3247
3251
  }
@@ -28716,11 +28720,11 @@ async function deployCommand(stacks, options) {
28716
28720
  addDependencies(stack.stackName);
28717
28721
  }
28718
28722
  }
28719
- const { STSClient: STSClient7, GetCallerIdentityCommand: GetCallerIdentityCommand8 } = await import("@aws-sdk/client-sts");
28723
+ const { STSClient: STSClient7, GetCallerIdentityCommand: GetCallerIdentityCommand9 } = await import("@aws-sdk/client-sts");
28720
28724
  const stsClient = new STSClient7({
28721
28725
  region: options.region || process.env["AWS_REGION"] || "us-east-1"
28722
28726
  });
28723
- const callerIdentity = await stsClient.send(new GetCallerIdentityCommand8({}));
28727
+ const callerIdentity = await stsClient.send(new GetCallerIdentityCommand9({}));
28724
28728
  const accountId = callerIdentity.Account;
28725
28729
  stsClient.destroy();
28726
28730
  const assetPublisher = new AssetPublisher();
@@ -29551,14 +29555,321 @@ function createForceUnlockCommand() {
29551
29555
  }
29552
29556
 
29553
29557
  // src/cli/commands/state.ts
29554
- import * as readline2 from "node:readline/promises";
29555
- import { Command as Command9, Option as Option5 } from "commander";
29558
+ import * as readline3 from "node:readline/promises";
29559
+ import { Command as Command10, Option as Option5 } from "commander";
29556
29560
  import {
29557
29561
  GetBucketLocationCommand as GetBucketLocationCommand2,
29558
29562
  GetObjectCommand as GetObjectCommand4,
29559
- ListObjectsV2Command as ListObjectsV2Command3
29563
+ ListObjectsV2Command as ListObjectsV2Command4
29564
+ } from "@aws-sdk/client-s3";
29565
+ init_aws_clients();
29566
+
29567
+ // src/cli/commands/state-migrate-bucket.ts
29568
+ import * as readline2 from "node:readline/promises";
29569
+ import { Command as Command9 } from "commander";
29570
+ import {
29571
+ CopyObjectCommand,
29572
+ CreateBucketCommand as CreateBucketCommand4,
29573
+ DeleteBucketCommand as DeleteBucketCommand3,
29574
+ DeleteObjectsCommand as DeleteObjectsCommand3,
29575
+ HeadBucketCommand as HeadBucketCommand3,
29576
+ ListObjectVersionsCommand as ListObjectVersionsCommand2,
29577
+ ListObjectsV2Command as ListObjectsV2Command3,
29578
+ PutBucketEncryptionCommand as PutBucketEncryptionCommand3,
29579
+ PutBucketPolicyCommand as PutBucketPolicyCommand3,
29580
+ PutBucketVersioningCommand as PutBucketVersioningCommand3,
29581
+ S3Client as S3Client10
29560
29582
  } from "@aws-sdk/client-s3";
29583
+ import { GetCallerIdentityCommand as GetCallerIdentityCommand8 } from "@aws-sdk/client-sts";
29561
29584
  init_aws_clients();
29585
+ async function stateMigrateBucketCommand(options) {
29586
+ const logger = getLogger();
29587
+ if (options.verbose)
29588
+ logger.setLevel("debug");
29589
+ const region = options.region || process.env["AWS_REGION"] || "us-east-1";
29590
+ const awsClients = new AwsClients({
29591
+ region,
29592
+ ...options.profile && { profile: options.profile }
29593
+ });
29594
+ setAwsClients(awsClients);
29595
+ try {
29596
+ const identity = await awsClients.sts.send(new GetCallerIdentityCommand8({}));
29597
+ const accountId = identity.Account;
29598
+ if (!accountId) {
29599
+ throw new Error("STS GetCallerIdentity returned no Account id.");
29600
+ }
29601
+ const legacyBucket = options.legacyBucket ?? getLegacyStateBucketName(accountId, region);
29602
+ const newBucket = options.newBucket ?? getDefaultStateBucketName(accountId);
29603
+ if (legacyBucket === newBucket) {
29604
+ logger.warn(
29605
+ `Source and destination resolve to the same bucket (${legacyBucket}); nothing to do.`
29606
+ );
29607
+ return;
29608
+ }
29609
+ logger.info("Migrating state bucket:");
29610
+ logger.info(` source: ${legacyBucket} (resolved for --region ${region})`);
29611
+ logger.info(` destination: ${newBucket}`);
29612
+ const probeRegion = "us-east-1";
29613
+ const probe = new S3Client10({ region: probeRegion });
29614
+ let sourceExists;
29615
+ try {
29616
+ sourceExists = await bucketExists2(probe, legacyBucket);
29617
+ } finally {
29618
+ probe.destroy();
29619
+ }
29620
+ if (!sourceExists) {
29621
+ throw new Error(
29622
+ `Source bucket '${legacyBucket}' does not exist. Nothing to migrate. (Tip: run \`cdkd state info\` to confirm which bucket cdkd is reading from.)`
29623
+ );
29624
+ }
29625
+ const legacyRegion = await resolveBucketRegion(legacyBucket);
29626
+ logger.info(` source bucket actual region: ${legacyRegion}`);
29627
+ const legacyS3 = new S3Client10({ region: legacyRegion });
29628
+ try {
29629
+ await assertNoActiveLocks(legacyS3, legacyBucket);
29630
+ const sourceObjects = await listAllObjects(legacyS3, legacyBucket);
29631
+ logger.info(` source object count: ${sourceObjects.length}`);
29632
+ if (sourceObjects.length === 0) {
29633
+ logger.info("Source bucket is empty \u2014 no objects to copy.");
29634
+ }
29635
+ if (!options.yes) {
29636
+ const action = options.removeLegacy ? "and DELETE the source bucket" : "(source bucket will be kept)";
29637
+ const ok = await confirmPrompt(
29638
+ `Copy ${sourceObjects.length} object(s) from ${legacyBucket} -> ${newBucket} ${action}?`
29639
+ );
29640
+ if (!ok) {
29641
+ logger.info("Migration cancelled.");
29642
+ return;
29643
+ }
29644
+ }
29645
+ if (options.dryRun) {
29646
+ logger.info("--dry-run: no changes will be made. Stopping here.");
29647
+ return;
29648
+ }
29649
+ const newS3 = await ensureDestinationBucket(newBucket, legacyRegion, accountId, logger);
29650
+ try {
29651
+ let copied = 0;
29652
+ for (const obj of sourceObjects) {
29653
+ if (!obj.Key)
29654
+ continue;
29655
+ await newS3.send(
29656
+ new CopyObjectCommand({
29657
+ Bucket: newBucket,
29658
+ Key: obj.Key,
29659
+ // CopySource needs encoding for slashes inside the key path.
29660
+ CopySource: encodeURIComponent(`${legacyBucket}/${obj.Key}`)
29661
+ })
29662
+ );
29663
+ copied++;
29664
+ logger.debug(` copied ${obj.Key}`);
29665
+ }
29666
+ logger.info(`\u2713 Copied ${copied} object(s) to ${newBucket}`);
29667
+ const destObjects = await listAllObjects(newS3, newBucket);
29668
+ if (destObjects.length < sourceObjects.length) {
29669
+ throw new Error(
29670
+ `Migration verification failed: source has ${sourceObjects.length} object(s), destination has ${destObjects.length}. Aborting before any source-bucket cleanup.`
29671
+ );
29672
+ }
29673
+ logger.info("\u2713 Object count verified at destination");
29674
+ if (options.removeLegacy) {
29675
+ logger.info(`Emptying source bucket ${legacyBucket} (all versions + delete markers)...`);
29676
+ await emptyBucketAllVersions(legacyS3, legacyBucket);
29677
+ logger.info(`Deleting source bucket ${legacyBucket}...`);
29678
+ await legacyS3.send(new DeleteBucketCommand3({ Bucket: legacyBucket }));
29679
+ logger.info(`\u2713 Deleted source bucket: ${legacyBucket}`);
29680
+ } else {
29681
+ logger.info(
29682
+ `Source bucket ${legacyBucket} kept. Pass --remove-legacy on a future run to delete it.`
29683
+ );
29684
+ }
29685
+ logger.info(`\u2713 Migration complete: ${legacyBucket} -> ${newBucket}`);
29686
+ } finally {
29687
+ newS3.destroy();
29688
+ }
29689
+ } finally {
29690
+ legacyS3.destroy();
29691
+ }
29692
+ } finally {
29693
+ awsClients.destroy();
29694
+ }
29695
+ }
29696
+ async function bucketExists2(s3, bucketName) {
29697
+ try {
29698
+ await s3.send(new HeadBucketCommand3({ Bucket: bucketName }));
29699
+ return true;
29700
+ } catch (error) {
29701
+ const err = error;
29702
+ const status = err.$metadata?.httpStatusCode;
29703
+ if (err.name === "NotFound" || err.name === "NoSuchBucket" || status === 404) {
29704
+ return false;
29705
+ }
29706
+ if (status === 301 || status === 403)
29707
+ return true;
29708
+ throw error;
29709
+ }
29710
+ }
29711
+ async function listAllObjects(s3, bucket) {
29712
+ const all = [];
29713
+ let continuationToken;
29714
+ do {
29715
+ const resp = await s3.send(
29716
+ new ListObjectsV2Command3({
29717
+ Bucket: bucket,
29718
+ ...continuationToken && { ContinuationToken: continuationToken }
29719
+ })
29720
+ );
29721
+ if (resp.Contents)
29722
+ all.push(...resp.Contents);
29723
+ continuationToken = resp.NextContinuationToken;
29724
+ } while (continuationToken);
29725
+ return all;
29726
+ }
29727
+ async function assertNoActiveLocks(s3, bucket) {
29728
+ const all = await listAllObjects(s3, bucket);
29729
+ const locks = all.map((o) => o.Key).filter((k) => typeof k === "string" && k.endsWith("/lock.json"));
29730
+ if (locks.length > 0) {
29731
+ const sample = locks.slice(0, 3).join(", ");
29732
+ const more = locks.length > 3 ? ` (+${locks.length - 3} more)` : "";
29733
+ throw new Error(
29734
+ `Refusing to migrate: ${locks.length} active lock file(s) found in '${bucket}': ${sample}${more}. Wait for in-flight cdkd operations to complete, or run 'cdkd force-unlock <stack>' if a lock is stale.`
29735
+ );
29736
+ }
29737
+ }
29738
+ async function ensureDestinationBucket(bucketName, region, accountId, logger) {
29739
+ const probe = new S3Client10({ region });
29740
+ let exists;
29741
+ try {
29742
+ exists = await bucketExists2(probe, bucketName);
29743
+ } finally {
29744
+ probe.destroy();
29745
+ }
29746
+ if (exists) {
29747
+ logger.info(`Destination bucket ${bucketName} already exists; reusing it.`);
29748
+ const actual = await resolveBucketRegion(bucketName);
29749
+ if (actual !== region) {
29750
+ logger.warn(
29751
+ `Destination bucket lives in ${actual}, but source is in ${region}. Cross-region copy is supported but slower; objects will be replicated to ${actual}.`
29752
+ );
29753
+ }
29754
+ return new S3Client10({ region: actual });
29755
+ }
29756
+ logger.info(`Creating destination bucket ${bucketName} in ${region}...`);
29757
+ const s3 = new S3Client10({ region });
29758
+ const createParams = { Bucket: bucketName };
29759
+ if (region !== "us-east-1") {
29760
+ createParams.CreateBucketConfiguration = {
29761
+ LocationConstraint: region
29762
+ };
29763
+ }
29764
+ await s3.send(new CreateBucketCommand4(createParams));
29765
+ logger.info(`\u2713 Created destination bucket: ${bucketName}`);
29766
+ await s3.send(
29767
+ new PutBucketVersioningCommand3({
29768
+ Bucket: bucketName,
29769
+ VersioningConfiguration: { Status: "Enabled" }
29770
+ })
29771
+ );
29772
+ await s3.send(
29773
+ new PutBucketEncryptionCommand3({
29774
+ Bucket: bucketName,
29775
+ ServerSideEncryptionConfiguration: {
29776
+ Rules: [
29777
+ {
29778
+ ApplyServerSideEncryptionByDefault: { SSEAlgorithm: "AES256" },
29779
+ BucketKeyEnabled: true
29780
+ }
29781
+ ]
29782
+ }
29783
+ })
29784
+ );
29785
+ await s3.send(
29786
+ new PutBucketPolicyCommand3({
29787
+ Bucket: bucketName,
29788
+ Policy: JSON.stringify({
29789
+ Version: "2012-10-17",
29790
+ Statement: [
29791
+ {
29792
+ Sid: "DenyExternalAccess",
29793
+ Effect: "Deny",
29794
+ Principal: "*",
29795
+ Action: "s3:*",
29796
+ Resource: [`arn:aws:s3:::${bucketName}`, `arn:aws:s3:::${bucketName}/*`],
29797
+ Condition: { StringNotEquals: { "aws:PrincipalAccount": accountId } }
29798
+ }
29799
+ ]
29800
+ })
29801
+ })
29802
+ );
29803
+ logger.info("\u2713 Applied versioning, encryption, and account-only access policy");
29804
+ return s3;
29805
+ }
29806
+ async function emptyBucketAllVersions(s3, bucket) {
29807
+ let keyMarker;
29808
+ let versionIdMarker;
29809
+ do {
29810
+ const resp = await s3.send(
29811
+ new ListObjectVersionsCommand2({
29812
+ Bucket: bucket,
29813
+ ...keyMarker && { KeyMarker: keyMarker },
29814
+ ...versionIdMarker && { VersionIdMarker: versionIdMarker }
29815
+ })
29816
+ );
29817
+ const ids = [];
29818
+ for (const v of resp.Versions ?? []) {
29819
+ if (v.Key && v.VersionId)
29820
+ ids.push({ Key: v.Key, VersionId: v.VersionId });
29821
+ }
29822
+ for (const dm of resp.DeleteMarkers ?? []) {
29823
+ if (dm.Key && dm.VersionId)
29824
+ ids.push({ Key: dm.Key, VersionId: dm.VersionId });
29825
+ }
29826
+ for (let i = 0; i < ids.length; i += 1e3) {
29827
+ const batch = ids.slice(i, i + 1e3);
29828
+ await s3.send(
29829
+ new DeleteObjectsCommand3({
29830
+ Bucket: bucket,
29831
+ Delete: {
29832
+ Objects: batch,
29833
+ Quiet: true
29834
+ }
29835
+ })
29836
+ );
29837
+ }
29838
+ keyMarker = resp.NextKeyMarker;
29839
+ versionIdMarker = resp.NextVersionIdMarker;
29840
+ } while (keyMarker || versionIdMarker);
29841
+ }
29842
+ async function confirmPrompt(prompt) {
29843
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
29844
+ try {
29845
+ const ans = await rl.question(`${prompt} [y/N] `);
29846
+ return /^y(es)?$/i.test(ans.trim());
29847
+ } finally {
29848
+ rl.close();
29849
+ }
29850
+ }
29851
+ function createStateMigrateBucketCommand() {
29852
+ const cmd = new Command9("migrate-bucket").description(
29853
+ "Migrate state from the legacy region-suffixed bucket (cdkd-state-{account}-{region}) to the new region-free default (cdkd-state-{account}). Source bucket is kept by default; pass --remove-legacy to delete it after a successful migration."
29854
+ ).option(
29855
+ "--region <region>",
29856
+ "Region of the legacy bucket to migrate. Defaults to AWS_REGION or us-east-1. Run once per region for multi-region setups."
29857
+ ).option(
29858
+ "--legacy-bucket <name>",
29859
+ "Override the legacy (source) bucket name (default: derived from STS account + --region)."
29860
+ ).option(
29861
+ "--new-bucket <name>",
29862
+ "Override the new (destination) bucket name (default: cdkd-state-{accountId})."
29863
+ ).option("--dry-run", "Show planned actions without making changes", false).option(
29864
+ "--remove-legacy",
29865
+ "Delete the source bucket after successful migration. Default: keep it.",
29866
+ false
29867
+ ).action(withErrorHandling(stateMigrateBucketCommand));
29868
+ commonOptions.forEach((o) => cmd.addOption(o));
29869
+ return cmd;
29870
+ }
29871
+
29872
+ // src/cli/commands/state.ts
29562
29873
  function formatStackRef(ref) {
29563
29874
  return ref.region ? `${ref.stackName} (${ref.region})` : ref.stackName;
29564
29875
  }
@@ -29696,7 +30007,7 @@ async function stateListCommand(options) {
29696
30007
  }
29697
30008
  }
29698
30009
  function createStateListCommand() {
29699
- const cmd = new Command9("list").alias("ls").description("List stacks registered in the cdkd state bucket").option("-l, --long", "Show resource count, last-modified time, and lock status", false).option("--json", "Output as JSON", false).action(withErrorHandling(stateListCommand));
30010
+ const cmd = new Command10("list").alias("ls").description("List stacks registered in the cdkd state bucket").option("-l, --long", "Show resource count, last-modified time, and lock status", false).option("--json", "Output as JSON", false).action(withErrorHandling(stateListCommand));
29700
30011
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
29701
30012
  cmd.addOption(deprecatedRegionOption);
29702
30013
  return cmd;
@@ -29800,7 +30111,7 @@ function formatLockSummary(lockInfo) {
29800
30111
  return `locked by ${lockInfo.owner}${opStr}, ${expiresStr}`;
29801
30112
  }
29802
30113
  function createStateResourcesCommand() {
29803
- const cmd = new Command9("resources").description("List resources recorded in a stack's state").argument("<stack>", "Stack name (physical CloudFormation name)").option("-l, --long", "Include dependencies and attributes per resource", false).option("--json", "Output as JSON", false).addOption(stackRegionOption()).action(withErrorHandling(stateResourcesCommand));
30114
+ const cmd = new Command10("resources").description("List resources recorded in a stack's state").argument("<stack>", "Stack name (physical CloudFormation name)").option("-l, --long", "Include dependencies and attributes per resource", false).option("--json", "Output as JSON", false).addOption(stackRegionOption()).action(withErrorHandling(stateResourcesCommand));
29804
30115
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
29805
30116
  cmd.addOption(deprecatedRegionOption);
29806
30117
  return cmd;
@@ -29888,7 +30199,7 @@ async function stateShowCommand(stackName, options) {
29888
30199
  }
29889
30200
  }
29890
30201
  function createStateShowCommand() {
29891
- const cmd = new Command9("show").description("Show the full cdkd state record for a stack (metadata, outputs, resources)").argument("<stack>", "Stack name (physical CloudFormation name)").option("--json", "Output the raw state and lock as JSON", false).addOption(stackRegionOption()).action(withErrorHandling(stateShowCommand));
30202
+ const cmd = new Command10("show").description("Show the full cdkd state record for a stack (metadata, outputs, resources)").argument("<stack>", "Stack name (physical CloudFormation name)").option("--json", "Output the raw state and lock as JSON", false).addOption(stackRegionOption()).action(withErrorHandling(stateShowCommand));
29892
30203
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
29893
30204
  cmd.addOption(deprecatedRegionOption);
29894
30205
  return cmd;
@@ -29936,7 +30247,7 @@ Use 'cdkd destroy ${stackName}' if you want to delete the actual resources.
29936
30247
 
29937
30248
  `
29938
30249
  );
29939
- const rl = readline2.createInterface({
30250
+ const rl = readline3.createInterface({
29940
30251
  input: process.stdin,
29941
30252
  output: process.stdout
29942
30253
  });
@@ -29971,7 +30282,7 @@ function stackRegionOption() {
29971
30282
  );
29972
30283
  }
29973
30284
  function createStateRmCommand() {
29974
- const cmd = new Command9("rm").description("Remove cdkd state for one or more stacks (does NOT delete AWS resources)").argument("<stacks...>", "Stack name(s) to remove from state").option("-f, --force", "Skip confirmation and remove even if the stack is locked", false).addOption(stackRegionOption()).action(withErrorHandling(stateRmCommand));
30285
+ const cmd = new Command10("rm").description("Remove cdkd state for one or more stacks (does NOT delete AWS resources)").argument("<stacks...>", "Stack name(s) to remove from state").option("-f, --force", "Skip confirmation and remove even if the stack is locked", false).addOption(stackRegionOption()).action(withErrorHandling(stateRmCommand));
29975
30286
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
29976
30287
  cmd.addOption(deprecatedRegionOption);
29977
30288
  return cmd;
@@ -30021,7 +30332,7 @@ WARNING: This destroys ${stackNames.length} stack(s) and removes their state rec
30021
30332
  `);
30022
30333
  }
30023
30334
  process.stdout.write("\n");
30024
- const rl = readline2.createInterface({
30335
+ const rl = readline3.createInterface({
30025
30336
  input: process.stdin,
30026
30337
  output: process.stdout
30027
30338
  });
@@ -30096,7 +30407,7 @@ Preparing to destroy stack: ${stackName}${ref.region ? ` (${ref.region})` : ""}`
30096
30407
  }
30097
30408
  }
30098
30409
  function createStateDestroyCommand() {
30099
- const cmd = new Command9("destroy").description(
30410
+ const cmd = new Command10("destroy").description(
30100
30411
  "Destroy a stack's AWS resources and remove its state record without requiring the CDK app. For removing only the state record (keeping AWS resources intact), use 'cdkd state rm'."
30101
30412
  ).argument("[stacks...]", "Stack name(s) to destroy (physical CloudFormation names)").option("--all", "Destroy every stack in the state bucket", false).addOption(stackRegionOption()).addHelpText(
30102
30413
  "after",
@@ -30149,7 +30460,7 @@ async function listStateFileKeys(awsClients, bucket, prefix) {
30149
30460
  const searchPrefix = `${prefix}/`;
30150
30461
  do {
30151
30462
  const resp = await awsClients.s3.send(
30152
- new ListObjectsV2Command3({
30463
+ new ListObjectsV2Command4({
30153
30464
  Bucket: bucket,
30154
30465
  Prefix: searchPrefix,
30155
30466
  ...continuationToken && { ContinuationToken: continuationToken }
@@ -30228,20 +30539,21 @@ async function stateInfoCommand(options) {
30228
30539
  }
30229
30540
  }
30230
30541
  function createStateInfoCommand() {
30231
- const cmd = new Command9("info").description(
30542
+ const cmd = new Command10("info").description(
30232
30543
  "Show cdkd state bucket info (bucket name, region, source, schema version, stack count)"
30233
30544
  ).option("--json", "Output as JSON", false).action(withErrorHandling(stateInfoCommand));
30234
30545
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
30235
30546
  return cmd;
30236
30547
  }
30237
30548
  function createStateCommand() {
30238
- const cmd = new Command9("state").description("Manage cdkd state stored in S3");
30549
+ const cmd = new Command10("state").description("Manage cdkd state stored in S3");
30239
30550
  cmd.addCommand(createStateInfoCommand());
30240
30551
  cmd.addCommand(createStateListCommand());
30241
30552
  cmd.addCommand(createStateResourcesCommand());
30242
30553
  cmd.addCommand(createStateShowCommand());
30243
30554
  cmd.addCommand(createStateRmCommand());
30244
30555
  cmd.addCommand(createStateDestroyCommand());
30556
+ cmd.addCommand(createStateMigrateBucketCommand());
30245
30557
  return cmd;
30246
30558
  }
30247
30559
 
@@ -30269,8 +30581,8 @@ function reorderArgs(argv) {
30269
30581
  return [...prefix, ...cmdAndAfter, ...beforeCmd];
30270
30582
  }
30271
30583
  async function main() {
30272
- const program = new Command10();
30273
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.13.0");
30584
+ const program = new Command11();
30585
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.14.0");
30274
30586
  program.addCommand(createBootstrapCommand());
30275
30587
  program.addCommand(createSynthCommand());
30276
30588
  program.addCommand(createListCommand());