@go-to-k/cdkd 0.158.0 → 0.158.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { _ as withSkipPrefix, a as runDockerStreaming, c as getLogger, d as getLiveRenderer, f as PATTERN_B_NAME_PROPERTIES, g as generateResourceNameWithFallback, h as generateResourceName, i as runDockerForeground, n as formatDockerLoginError, p as PATTERN_B_RESOURCE_TYPES, r as getDockerCmd, u as runStackBuffered, v as withStackName } from "./docker-cmd-iDMcWcre.js";
3
- import { $ as CdkdError, A as shouldRetainResource, B as resolveSkipPrefix, C as IntrinsicFunctionResolver, D as TemplateParser, E as DagBuilder, F as Synthesizer, G as CFN_TEMPLATE_URL_LIMIT, H as resolveStateBucketWithDefaultAndSource, I as getDefaultStateBucketName, J as uploadCfnTemplate, K as MIGRATE_TMP_PREFIX, L as getLegacyStateBucketName, M as stringifyValue, N as WorkGraph, O as LockManager, P as buildDockerImage, R as resolveApp, S as assertRegionMatch, T as DiffCalculator, U as warnDeprecatedNoPrefixCliFlag, V as resolveStateBucketWithDefault, W as CFN_TEMPLATE_BODY_LIMIT, Y as AssemblyReader, Z as resolveBucketRegion, _ as matchesCdkPath, a as withRetry, b as ProviderRegistry, bt as withErrorHandling, c as bold, ct as PartialFailureError, d as green, dt as ResourceUpdateNotSupportedError, f as red, ft as RouteDiscoveryError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, i as withResourceDeadline, it as LocalStartServiceError, j as AssetPublisher, k as S3StateBackend, l as cyan, lt as ProvisioningError, m as IAMRoleProvider, mt as StackTerminationProtectionError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as LocalInvokeBuildError, o as IMPLICIT_DELETE_DEPENDENCIES, ot as MissingCdkCliError, p as yellow, pt as StackHasActiveImportsError, q as findLargeInlineResources, r as DeployEngine, rt as LocalMigrateError, s as formatResourceLine, st as NestedStackChildDirectDestroyError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ResourceTimeoutError, v as normalizeAwsTagsToCfn, w as applyRoleArnIfSet, x as CloudControlProvider, y as resolveExplicitPhysicalId, yt as normalizeAwsError, z as resolveCaptureObservedState } from "./deploy-engine-UmoqjtWH.js";
3
+ import { $ as CdkdError, A as shouldRetainResource, B as resolveSkipPrefix, C as IntrinsicFunctionResolver, D as TemplateParser, E as DagBuilder, F as Synthesizer, G as CFN_TEMPLATE_URL_LIMIT, H as resolveStateBucketWithDefaultAndSource, I as getDefaultStateBucketName, J as uploadCfnTemplate, K as MIGRATE_TMP_PREFIX, L as getLegacyStateBucketName, M as stringifyValue, N as WorkGraph, O as LockManager, P as buildDockerImage, R as resolveApp, S as assertRegionMatch, T as DiffCalculator, U as warnDeprecatedNoPrefixCliFlag, V as resolveStateBucketWithDefault, W as CFN_TEMPLATE_BODY_LIMIT, Y as AssemblyReader, Z as resolveBucketRegion, _ as matchesCdkPath, a as withRetry, b as ProviderRegistry, bt as withErrorHandling, c as bold, ct as PartialFailureError, d as green, dt as ResourceUpdateNotSupportedError, f as red, ft as RouteDiscoveryError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, i as withResourceDeadline, it as LocalStartServiceError, j as AssetPublisher, k as S3StateBackend, l as cyan, lt as ProvisioningError, m as IAMRoleProvider, mt as StackTerminationProtectionError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as LocalInvokeBuildError, o as IMPLICIT_DELETE_DEPENDENCIES, ot as MissingCdkCliError, p as yellow, pt as StackHasActiveImportsError, q as findLargeInlineResources, r as DeployEngine, rt as LocalMigrateError, s as formatResourceLine, st as NestedStackChildDirectDestroyError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ResourceTimeoutError, v as normalizeAwsTagsToCfn, w as applyRoleArnIfSet, x as CloudControlProvider, y as resolveExplicitPhysicalId, yt as normalizeAwsError, z as resolveCaptureObservedState } from "./deploy-engine-CGmdz5WP.js";
4
4
  import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-B15NAPbL.js";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import { createHash, createHmac, createPublicKey, createVerify, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
@@ -3225,6 +3225,7 @@ var S3BucketProvider = class {
3225
3225
  "ObjectLockConfiguration",
3226
3226
  "ObjectLockEnabled"
3227
3227
  ])]]);
3228
+ unhandledByDesign = new Map([["AWS::S3::Bucket", new Map([["AccessControl", "Legacy canned ACL; AWS disables ACLs by default since 2023-04 — use BucketOwnershipControls + BucketPolicy / PublicAccessBlockConfiguration instead"]])]]);
3228
3229
  constructor() {
3229
3230
  const awsClients = getAwsClients();
3230
3231
  this.s3Client = awsClients.s3;
@@ -5997,6 +5998,7 @@ var SNSSubscriptionProvider = class {
5997
5998
  "Endpoint",
5998
5999
  "FilterPolicy"
5999
6000
  ])]]);
6001
+ unhandledByDesign = new Map([["AWS::SNS::Subscription", new Map([["Region", "CFn-only cross-region subscription hint; cdkd uses the SDK client region directly and has no per-resource region override"]])]]);
6000
6002
  constructor() {
6001
6003
  const awsClients = getAwsClients();
6002
6004
  this.snsClient = awsClients.sns;
@@ -11700,9 +11702,11 @@ var EC2Provider = class {
11700
11702
  "FromPort",
11701
11703
  "ToPort",
11702
11704
  "CidrIp",
11705
+ "CidrIpv6",
11703
11706
  "Description",
11704
11707
  "SourceSecurityGroupId",
11705
- "SourceSecurityGroupOwnerId"
11708
+ "SourceSecurityGroupOwnerId",
11709
+ "SourcePrefixListId"
11706
11710
  ])],
11707
11711
  ["AWS::EC2::Instance", new Set([
11708
11712
  "ImageId",
@@ -11726,10 +11730,15 @@ var EC2Provider = class {
11726
11730
  "CidrBlock",
11727
11731
  "Ipv6CidrBlock",
11728
11732
  "PortRange",
11729
- "IcmpTypeCode"
11733
+ "Icmp"
11730
11734
  ])],
11731
11735
  ["AWS::EC2::SubnetNetworkAclAssociation", new Set(["SubnetId", "NetworkAclId"])]
11732
11736
  ]);
11737
+ unhandledByDesign = new Map([
11738
+ ["AWS::EC2::Instance", new Map([["ElasticGpuSpecifications", "AWS Elastic GPU end-of-life (announced 2023-11); no replacement API"], ["ElasticInferenceAccelerators", "AWS Elastic Inference end-of-life 2024-04; use AWS Inferentia / Trainium accelerator instance families instead"]])],
11739
+ ["AWS::EC2::SecurityGroupIngress", new Map([["GroupName", "EC2-Classic-only — use GroupId for VPC security groups (EC2-Classic retired 2022-08-15)"], ["SourceSecurityGroupName", "EC2-Classic-only — use SourceSecurityGroupId for VPC peer security groups (EC2-Classic retired 2022-08-15)"]])],
11740
+ ["AWS::EC2::NatGateway", new Map([["VpcId", "AWS derives the VPC from SubnetId; the ec2:CreateNatGateway API has no VpcId parameter"]])]
11741
+ ]);
11733
11742
  constructor() {
11734
11743
  const awsClients = getAwsClients();
11735
11744
  this.ec2Client = awsClients.ec2;
@@ -12864,7 +12873,7 @@ var EC2Provider = class {
12864
12873
  const cidrBlock = properties["CidrBlock"];
12865
12874
  const ipv6CidrBlock = properties["Ipv6CidrBlock"];
12866
12875
  const portRange = properties["PortRange"];
12867
- const icmpTypeCode = properties["IcmpTypeCode"];
12876
+ const icmpTypeCode = properties["Icmp"] ?? properties["IcmpTypeCode"];
12868
12877
  await this.ec2Client.send(new CreateNetworkAclEntryCommand({
12869
12878
  NetworkAclId: networkAclId,
12870
12879
  RuleNumber: ruleNumber,
@@ -13614,7 +13623,10 @@ var EC2Provider = class {
13614
13623
  const icmp = {};
13615
13624
  if (entry.IcmpTypeCode.Type !== void 0) icmp["Type"] = entry.IcmpTypeCode.Type;
13616
13625
  if (entry.IcmpTypeCode.Code !== void 0) icmp["Code"] = entry.IcmpTypeCode.Code;
13617
- if (Object.keys(icmp).length > 0) result["IcmpTypeCode"] = icmp;
13626
+ if (Object.keys(icmp).length > 0) {
13627
+ result["Icmp"] = icmp;
13628
+ result["IcmpTypeCode"] = icmp;
13629
+ }
13618
13630
  }
13619
13631
  return result;
13620
13632
  }
@@ -13861,6 +13873,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
13861
13873
  "MethodResponses"
13862
13874
  ])]
13863
13875
  ]);
13876
+ unhandledByDesign = new Map([["AWS::ApiGateway::Deployment", new Map([["StageName", "CFn-only convenience for inline-creating a Stage from a Deployment; declare AWS::ApiGateway::Stage explicitly to attach to this Deployment"], ["StageDescription", "CFn-only convenience for inline-creating a Stage; declare AWS::ApiGateway::Stage with the Description property instead"]])]]);
13864
13877
  /** Maximum number of retries for IAM propagation delays */
13865
13878
  static MAX_IAM_RETRIES = 3;
13866
13879
  /** Delay between IAM propagation retries (ms) - exponential backoff */
@@ -17003,7 +17016,7 @@ var ECSProvider = class {
17003
17016
  "CapacityProviderStrategy",
17004
17017
  "DeploymentConfiguration",
17005
17018
  "PlacementConstraints",
17006
- "PlacementStrategy",
17019
+ "PlacementStrategies",
17007
17020
  "PlatformVersion",
17008
17021
  "HealthCheckGracePeriodSeconds",
17009
17022
  "SchedulingStrategy",
@@ -17014,6 +17027,7 @@ var ECSProvider = class {
17014
17027
  "Tags"
17015
17028
  ])]
17016
17029
  ]);
17030
+ unhandledByDesign = new Map([["AWS::ECS::Service", new Map([["Role", "Legacy classic-ELB service-linked-role override; AWS uses the AWSServiceRoleForECS service-linked role automatically since 2017"]])], ["AWS::ECS::TaskDefinition", new Map([["InferenceAccelerators", "AWS Elastic Inference end-of-life 2024-04; use AWS Inferentia / Trainium accelerator instance families instead"]])]]);
17017
17031
  getClient() {
17018
17032
  if (!this.ecsClient) this.ecsClient = new ECSClient(this.providerRegion ? { region: this.providerRegion } : {});
17019
17033
  return this.ecsClient;
@@ -17215,7 +17229,7 @@ var ECSProvider = class {
17215
17229
  capacityProviderStrategy: properties["CapacityProviderStrategy"],
17216
17230
  deploymentConfiguration: properties["DeploymentConfiguration"],
17217
17231
  placementConstraints: properties["PlacementConstraints"],
17218
- placementStrategy: properties["PlacementStrategy"],
17232
+ placementStrategy: properties["PlacementStrategies"] ?? properties["PlacementStrategy"],
17219
17233
  platformVersion: properties["PlatformVersion"],
17220
17234
  healthCheckGracePeriodSeconds: properties["HealthCheckGracePeriodSeconds"],
17221
17235
  schedulingStrategy: properties["SchedulingStrategy"],
@@ -17255,7 +17269,7 @@ var ECSProvider = class {
17255
17269
  capacityProviderStrategy: properties["CapacityProviderStrategy"],
17256
17270
  deploymentConfiguration: properties["DeploymentConfiguration"],
17257
17271
  placementConstraints: properties["PlacementConstraints"],
17258
- placementStrategy: properties["PlacementStrategy"],
17272
+ placementStrategy: properties["PlacementStrategies"] ?? properties["PlacementStrategy"],
17259
17273
  platformVersion: properties["PlatformVersion"],
17260
17274
  healthCheckGracePeriodSeconds: properties["HealthCheckGracePeriodSeconds"],
17261
17275
  enableExecuteCommand: properties["EnableExecuteCommand"]
@@ -17664,8 +17678,14 @@ var ECSProvider = class {
17664
17678
  else if (!s.launchType) result["CapacityProviderStrategy"] = [];
17665
17679
  if (s.deploymentConfiguration) result["DeploymentConfiguration"] = s.deploymentConfiguration;
17666
17680
  result["PlacementConstraints"] = s.placementConstraints ?? [];
17667
- if (s.launchType === "EC2" || s.launchType === "EXTERNAL") result["PlacementStrategy"] = s.placementStrategy ?? [];
17668
- else if (s.placementStrategy && s.placementStrategy.length > 0) result["PlacementStrategy"] = s.placementStrategy;
17681
+ if (s.launchType === "EC2" || s.launchType === "EXTERNAL") {
17682
+ const strategy = s.placementStrategy ?? [];
17683
+ result["PlacementStrategy"] = strategy;
17684
+ result["PlacementStrategies"] = strategy;
17685
+ } else if (s.placementStrategy && s.placementStrategy.length > 0) {
17686
+ result["PlacementStrategy"] = s.placementStrategy;
17687
+ result["PlacementStrategies"] = s.placementStrategy;
17688
+ }
17669
17689
  result["ServiceRegistries"] = s.serviceRegistries ?? [];
17670
17690
  result["Tags"] = normalizeAwsTagsToCfn(s.tags);
17671
17691
  return result;
@@ -18530,6 +18550,11 @@ var RDSProvider = class {
18530
18550
  "Tags"
18531
18551
  ])]
18532
18552
  ]);
18553
+ unhandledByDesign = new Map([["AWS::RDS::DBCluster", new Map([["DeleteAutomatedBackups", "cdkd hardcodes SkipFinalSnapshot=true on destroy; this CFn lifecycle flag has no equivalent on the runtime path"]])], ["AWS::RDS::DBInstance", new Map([
18554
+ ["DBSecurityGroups", "EC2-Classic-only feature retired by AWS (2022-08-15); new accounts cannot use this — use VPCSecurityGroups instead"],
18555
+ ["ApplyImmediately", "cdkd always applies modifications immediately (rds:ModifyDBInstance.ApplyImmediately=true is hardcoded); users wanting maintenance-window deferral should run aws rds modify-db-instance directly"],
18556
+ ["DeleteAutomatedBackups", "cdkd hardcodes SkipFinalSnapshot=true on destroy; this CFn lifecycle flag has no equivalent on the runtime path"]
18557
+ ])]]);
18533
18558
  getClient() {
18534
18559
  if (!this.rdsClient) this.rdsClient = new RDSClient(this.providerRegion ? { region: this.providerRegion } : {});
18535
18560
  return this.rdsClient;
@@ -20868,6 +20893,7 @@ var NeptuneProvider = class {
20868
20893
  ["AWS::Neptune::DBCluster", new Set([
20869
20894
  "DBClusterIdentifier",
20870
20895
  "EngineVersion",
20896
+ "DBPort",
20871
20897
  "Port",
20872
20898
  "VpcSecurityGroupIds",
20873
20899
  "DBSubnetGroupName",
@@ -20997,7 +21023,7 @@ var NeptuneProvider = class {
20997
21023
  DBClusterIdentifier: dbClusterIdentifier,
20998
21024
  Engine: "neptune",
20999
21025
  EngineVersion: properties["EngineVersion"],
21000
- Port: properties["Port"] != null ? Number(properties["Port"]) : void 0,
21026
+ Port: properties["DBPort"] != null ? Number(properties["DBPort"]) : properties["Port"] != null ? Number(properties["Port"]) : void 0,
21001
21027
  VpcSecurityGroupIds: properties["VpcSecurityGroupIds"],
21002
21028
  DBSubnetGroupName: properties["DBSubnetGroupName"],
21003
21029
  StorageEncrypted: properties["StorageEncrypted"],
@@ -21043,7 +21069,7 @@ var NeptuneProvider = class {
21043
21069
  DBClusterParameterGroupName: properties["DBClusterParameterGroupName"],
21044
21070
  EnableIAMDatabaseAuthentication: properties["IamAuthEnabled"],
21045
21071
  ...sendVpcSgIds && { VpcSecurityGroupIds: vpcSgIds },
21046
- Port: properties["Port"] != null ? Number(properties["Port"]) : void 0,
21072
+ Port: properties["DBPort"] != null ? Number(properties["DBPort"]) : properties["Port"] != null ? Number(properties["Port"]) : void 0,
21047
21073
  ApplyImmediately: true
21048
21074
  }));
21049
21075
  this.logger.debug(`Successfully updated Neptune DBCluster ${logicalId}`);
@@ -21370,7 +21396,10 @@ var NeptuneProvider = class {
21370
21396
  const result = {};
21371
21397
  if (cluster.DBClusterIdentifier !== void 0) result["DBClusterIdentifier"] = cluster.DBClusterIdentifier;
21372
21398
  if (cluster.EngineVersion !== void 0) result["EngineVersion"] = cluster.EngineVersion;
21373
- if (cluster.Port !== void 0) result["Port"] = cluster.Port;
21399
+ if (cluster.Port !== void 0) {
21400
+ result["Port"] = cluster.Port;
21401
+ result["DBPort"] = cluster.Port;
21402
+ }
21374
21403
  result["VpcSecurityGroupIds"] = (cluster.VpcSecurityGroups ?? []).map((sg) => sg.VpcSecurityGroupId).filter((id) => !!id);
21375
21404
  if (cluster.DBSubnetGroup !== void 0) result["DBSubnetGroupName"] = cluster.DBSubnetGroup;
21376
21405
  if (cluster.StorageEncrypted !== void 0) result["StorageEncrypted"] = cluster.StorageEncrypted;
@@ -22810,6 +22839,7 @@ var ElastiCacheProvider = class {
22810
22839
  handledProperties = new Map([["AWS::ElastiCache::SubnetGroup", new Set([
22811
22840
  "CacheSubnetGroupName",
22812
22841
  "CacheSubnetGroupDescription",
22842
+ "Description",
22813
22843
  "SubnetIds",
22814
22844
  "Tags"
22815
22845
  ])], ["AWS::ElastiCache::CacheCluster", new Set([
@@ -22837,6 +22867,7 @@ var ElastiCacheProvider = class {
22837
22867
  "IpDiscovery",
22838
22868
  "TransitEncryptionEnabled"
22839
22869
  ])]]);
22870
+ unhandledByDesign = new Map([["AWS::ElastiCache::CacheCluster", new Map([["CacheSecurityGroupNames", "EC2-Classic-only — use VpcSecurityGroupIds for VPC-deployed clusters (EC2-Classic retired 2022-08-15)"]])]]);
22840
22871
  getClient() {
22841
22872
  if (!this.client) this.client = new ElastiCacheClient(this.providerRegion ? { region: this.providerRegion } : {});
22842
22873
  return this.client;
@@ -22871,7 +22902,7 @@ var ElastiCacheProvider = class {
22871
22902
  try {
22872
22903
  await this.getClient().send(new CreateCacheSubnetGroupCommand({
22873
22904
  CacheSubnetGroupName: cacheSubnetGroupName,
22874
- CacheSubnetGroupDescription: properties["CacheSubnetGroupDescription"] || `Subnet group for ${logicalId}`,
22905
+ CacheSubnetGroupDescription: properties["Description"] ?? properties["CacheSubnetGroupDescription"] ?? `Subnet group for ${logicalId}`,
22875
22906
  SubnetIds: properties["SubnetIds"]
22876
22907
  }));
22877
22908
  this.logger.debug(`Successfully created CacheSubnetGroup ${logicalId}: ${cacheSubnetGroupName}`);
@@ -22889,7 +22920,7 @@ var ElastiCacheProvider = class {
22889
22920
  try {
22890
22921
  await this.getClient().send(new ModifyCacheSubnetGroupCommand({
22891
22922
  CacheSubnetGroupName: physicalId,
22892
- CacheSubnetGroupDescription: properties["CacheSubnetGroupDescription"],
22923
+ CacheSubnetGroupDescription: properties["Description"] ?? properties["CacheSubnetGroupDescription"],
22893
22924
  SubnetIds: properties["SubnetIds"]
22894
22925
  }));
22895
22926
  this.logger.debug(`Successfully updated CacheSubnetGroup ${logicalId}`);
@@ -23199,7 +23230,10 @@ var ElastiCacheProvider = class {
23199
23230
  if (!group) return void 0;
23200
23231
  const result = {};
23201
23232
  if (group.CacheSubnetGroupName !== void 0) result["CacheSubnetGroupName"] = group.CacheSubnetGroupName;
23202
- if (group.CacheSubnetGroupDescription !== void 0) result["CacheSubnetGroupDescription"] = group.CacheSubnetGroupDescription;
23233
+ if (group.CacheSubnetGroupDescription !== void 0) {
23234
+ result["CacheSubnetGroupDescription"] = group.CacheSubnetGroupDescription;
23235
+ result["Description"] = group.CacheSubnetGroupDescription;
23236
+ }
23203
23237
  result["SubnetIds"] = (group.Subnets ?? []).map((s) => s.SubnetIdentifier).filter((id) => !!id);
23204
23238
  if (group.ARN) await this.attachTags(result, group.ARN);
23205
23239
  return result;
@@ -23853,6 +23887,7 @@ var AppSyncProvider = class {
23853
23887
  "Expires"
23854
23888
  ])]
23855
23889
  ]);
23890
+ unhandledByDesign = new Map([["AWS::AppSync::DataSource", new Map([["ElasticsearchConfig", "Legacy Elasticsearch alias; use OpenSearchServiceConfig (AppSync deprecated the Elasticsearch DataSource type in favor of OpenSearch)"]])]]);
23856
23891
  getClient() {
23857
23892
  if (!this.client) this.client = new AppSyncClient(this.providerRegion ? { region: this.providerRegion } : {});
23858
23893
  return this.client;
@@ -24718,9 +24753,14 @@ var GlueProvider = class {
24718
24753
  cachedAccountId;
24719
24754
  providerRegion = process.env["AWS_REGION"];
24720
24755
  logger = getLogger().child("GlueProvider");
24721
- handledProperties = new Map([["AWS::Glue::Database", new Set(["DatabaseInput", "CatalogId"])], ["AWS::Glue::Table", new Set([
24756
+ handledProperties = new Map([["AWS::Glue::Database", new Set([
24757
+ "DatabaseInput",
24758
+ "DatabaseName",
24759
+ "CatalogId"
24760
+ ])], ["AWS::Glue::Table", new Set([
24722
24761
  "DatabaseName",
24723
24762
  "TableInput",
24763
+ "Name",
24724
24764
  "CatalogId"
24725
24765
  ])]]);
24726
24766
  getClient() {
@@ -24752,8 +24792,8 @@ var GlueProvider = class {
24752
24792
  this.logger.debug(`Creating Glue Database ${logicalId}`);
24753
24793
  const databaseInput = properties["DatabaseInput"];
24754
24794
  if (!databaseInput) throw new ProvisioningError(`DatabaseInput is required for Glue Database ${logicalId}`, resourceType, logicalId);
24755
- const databaseName = databaseInput["Name"];
24756
- if (!databaseName) throw new ProvisioningError(`DatabaseInput.Name is required for Glue Database ${logicalId}`, resourceType, logicalId);
24795
+ const databaseName = databaseInput["Name"] ?? properties["DatabaseName"];
24796
+ if (!databaseName) throw new ProvisioningError(`DatabaseInput.Name or top-level DatabaseName is required for Glue Database ${logicalId}`, resourceType, logicalId);
24757
24797
  const catalogId = properties["CatalogId"];
24758
24798
  try {
24759
24799
  await this.getClient().send(new CreateDatabaseCommand({
@@ -24816,14 +24856,14 @@ var GlueProvider = class {
24816
24856
  if (!databaseName) throw new ProvisioningError(`DatabaseName is required for Glue Table ${logicalId}`, resourceType, logicalId);
24817
24857
  const tableInput = properties["TableInput"];
24818
24858
  if (!tableInput) throw new ProvisioningError(`TableInput is required for Glue Table ${logicalId}`, resourceType, logicalId);
24819
- const tableName = tableInput["Name"];
24820
- if (!tableName) throw new ProvisioningError(`TableInput.Name is required for Glue Table ${logicalId}`, resourceType, logicalId);
24859
+ const tableName = tableInput["Name"] ?? properties["Name"];
24860
+ if (!tableName) throw new ProvisioningError(`TableInput.Name or top-level Name is required for Glue Table ${logicalId}`, resourceType, logicalId);
24821
24861
  const catalogId = properties["CatalogId"];
24822
24862
  try {
24823
24863
  await this.getClient().send(new CreateTableCommand$1({
24824
24864
  CatalogId: catalogId,
24825
24865
  DatabaseName: databaseName,
24826
- TableInput: this.buildTableInput(tableInput)
24866
+ TableInput: this.buildTableInput(tableInput, tableName)
24827
24867
  }));
24828
24868
  const physicalId = `${databaseName}|${tableName}`;
24829
24869
  this.logger.debug(`Successfully created Glue Table ${logicalId}: ${physicalId}`);
@@ -24838,8 +24878,8 @@ var GlueProvider = class {
24838
24878
  }
24839
24879
  async updateTable(logicalId, physicalId, resourceType, properties) {
24840
24880
  this.logger.debug(`Updating Glue Table ${logicalId}: ${physicalId}`);
24841
- const [databaseName] = physicalId.split("|");
24842
- if (!databaseName) throw new ProvisioningError(`Invalid Glue Table physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
24881
+ const [databaseName, tableName] = physicalId.split("|");
24882
+ if (!databaseName || !tableName) throw new ProvisioningError(`Invalid Glue Table physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
24843
24883
  const tableInput = properties["TableInput"];
24844
24884
  if (!tableInput) throw new ProvisioningError(`TableInput is required for Glue Table update ${logicalId}`, resourceType, logicalId, physicalId);
24845
24885
  const catalogId = properties["CatalogId"];
@@ -24847,7 +24887,7 @@ var GlueProvider = class {
24847
24887
  await this.getClient().send(new UpdateTableCommand$1({
24848
24888
  CatalogId: catalogId,
24849
24889
  DatabaseName: databaseName,
24850
- TableInput: this.buildTableInput(tableInput)
24890
+ TableInput: this.buildTableInput(tableInput, tableName)
24851
24891
  }));
24852
24892
  this.logger.debug(`Successfully updated Glue Table ${logicalId}`);
24853
24893
  return {
@@ -24902,8 +24942,8 @@ var GlueProvider = class {
24902
24942
  /**
24903
24943
  * Build TableInput for Glue API from CFn template properties
24904
24944
  */
24905
- buildTableInput(tableInput) {
24906
- const result = { Name: tableInput["Name"] };
24945
+ buildTableInput(tableInput, fallbackName) {
24946
+ const result = { Name: tableInput["Name"] ?? fallbackName };
24907
24947
  if (tableInput["Description"] !== void 0) result.Description = tableInput["Description"];
24908
24948
  if (tableInput["TableType"] !== void 0) result.TableType = tableInput["TableType"];
24909
24949
  if (tableInput["Parameters"] !== void 0) {
@@ -25009,7 +25049,9 @@ var GlueProvider = class {
25009
25049
  dbInput["Description"] = db.Description ?? "";
25010
25050
  if (db.LocationUri !== void 0) dbInput["LocationUri"] = db.LocationUri;
25011
25051
  dbInput["Parameters"] = db.Parameters ?? {};
25012
- return { DatabaseInput: dbInput };
25052
+ const result = { DatabaseInput: dbInput };
25053
+ if (db.Name !== void 0) result["DatabaseName"] = db.Name;
25054
+ return result;
25013
25055
  }
25014
25056
  async readTable(physicalId) {
25015
25057
  const [databaseName, tableName] = physicalId.split("|");
@@ -25037,10 +25079,12 @@ var GlueProvider = class {
25037
25079
  if (table.ViewOriginalText !== void 0) tableInput["ViewOriginalText"] = table.ViewOriginalText;
25038
25080
  if (table.ViewExpandedText !== void 0) tableInput["ViewExpandedText"] = table.ViewExpandedText;
25039
25081
  if (table.TargetTable) tableInput["TargetTable"] = table.TargetTable;
25040
- return {
25082
+ const result = {
25041
25083
  DatabaseName: databaseName,
25042
25084
  TableInput: tableInput
25043
25085
  };
25086
+ if (table.Name !== void 0) result["Name"] = table.Name;
25087
+ return result;
25044
25088
  }
25045
25089
  async import(input) {
25046
25090
  switch (input.resourceType) {
@@ -27455,6 +27499,7 @@ var EFSProvider = class {
27455
27499
  "AccessPointTags"
27456
27500
  ])]
27457
27501
  ]);
27502
+ unhandledByDesign = new Map([["AWS::EFS::AccessPoint", new Map([["ClientToken", "AWS SDK manages this idempotency token internally on CreateAccessPoint; no user-supplied value is honored"]])]]);
27458
27503
  getClient() {
27459
27504
  if (!this.client) this.client = new EFSClient(this.providerRegion ? { region: this.providerRegion } : {});
27460
27505
  return this.client;
@@ -30466,6 +30511,7 @@ var S3TablesProvider = class {
30466
30511
  ["AWS::S3Tables::Table", new Set([
30467
30512
  "TableBucketARN",
30468
30513
  "Namespace",
30514
+ "TableName",
30469
30515
  "Name",
30470
30516
  "Format"
30471
30517
  ])]
@@ -30628,8 +30674,8 @@ var S3TablesProvider = class {
30628
30674
  if (!tableBucketARN) throw new ProvisioningError(`TableBucketARN is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
30629
30675
  const namespace = properties["Namespace"];
30630
30676
  if (!namespace) throw new ProvisioningError(`Namespace is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
30631
- const name = properties["Name"];
30632
- if (!name) throw new ProvisioningError(`Name is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
30677
+ const name = properties["TableName"] ?? properties["Name"];
30678
+ if (!name) throw new ProvisioningError(`TableName is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
30633
30679
  const format = properties["Format"];
30634
30680
  if (!format) throw new ProvisioningError(`Format is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
30635
30681
  try {
@@ -30714,10 +30760,12 @@ var S3TablesProvider = class {
30714
30760
  if (err instanceof NotFoundException$5) return void 0;
30715
30761
  throw err;
30716
30762
  }
30763
+ const tableNameValue = resp.name ?? name;
30717
30764
  const result = {
30718
30765
  TableBucketARN: tableBucketARN,
30719
30766
  Namespace: namespace,
30720
- Name: resp.name ?? name
30767
+ Name: tableNameValue,
30768
+ TableName: tableNameValue
30721
30769
  };
30722
30770
  if (resp.format !== void 0) result["Format"] = resp.format;
30723
30771
  return result;
@@ -31258,6 +31306,7 @@ var ASGProvider = class ASGProvider {
31258
31306
  "InstanceMaintenancePolicy",
31259
31307
  "DeletionProtection"
31260
31308
  ])]]);
31309
+ unhandledByDesign = new Map([["AWS::AutoScaling::AutoScalingGroup", new Map([["LaunchConfigurationName", "AWS Launch Configurations end-of-life 2024-10; use LaunchTemplate instead"], ["NotificationConfiguration", "Legacy singular form; use NotificationConfigurations (plural) which cdkd already wires"]])]]);
31261
31310
  getClient() {
31262
31311
  if (!this.asgClient) this.asgClient = new AutoScalingClient(this.providerRegion ? { region: this.providerRegion } : {});
31263
31312
  return this.asgClient;
@@ -41608,6 +41657,7 @@ var CfnLocalStateProvider = class {
41608
41657
  region;
41609
41658
  client;
41610
41659
  clientOptions;
41660
+ disposed = false;
41611
41661
  constructor(opts) {
41612
41662
  this.cfnStackName = opts.cfnStackName;
41613
41663
  this.region = opts.region;
@@ -41615,6 +41665,7 @@ var CfnLocalStateProvider = class {
41615
41665
  if (opts.profile !== void 0) this.clientOptions.profile = opts.profile;
41616
41666
  }
41617
41667
  getClient() {
41668
+ if (this.disposed) throw new Error("CfnLocalStateProvider used after dispose()");
41618
41669
  if (!this.client) this.client = new CloudFormationClient({ region: this.region });
41619
41670
  return this.client;
41620
41671
  }
@@ -41631,13 +41682,14 @@ var CfnLocalStateProvider = class {
41631
41682
  * behavior on every intrinsic-valued env var.
41632
41683
  */
41633
41684
  async load(_stackName, _synthRegion) {
41685
+ if (this.disposed) throw new Error("CfnLocalStateProvider used after dispose()");
41634
41686
  const logger = getLogger();
41635
41687
  const client = this.getClient();
41636
41688
  let resourceMap;
41637
41689
  try {
41638
41690
  resourceMap = buildResourceStateMap((await client.send(new DescribeStackResourcesCommand({ StackName: this.cfnStackName }))).StackResources ?? []);
41639
41691
  } catch (err) {
41640
- logger.warn(`${this.label}: DescribeStackResources(${this.cfnStackName}) failed: ${err instanceof Error ? err.message : String(err)}. Was the stack deployed in region '${this.region}'? Falling back.`);
41692
+ logger.warn(`${this.label}: DescribeStackResources(${this.cfnStackName}) failed: ${formatAwsErrorForWarn(err)}. Was the stack deployed in region '${this.region}'? Falling back.`);
41641
41693
  return;
41642
41694
  }
41643
41695
  let outputs;
@@ -41648,7 +41700,7 @@ var CfnLocalStateProvider = class {
41648
41700
  outputs = {};
41649
41701
  } else outputs = buildOutputsMap(stack.Outputs ?? []);
41650
41702
  } catch (err) {
41651
- logger.warn(`${this.label}: DescribeStacks(${this.cfnStackName}) failed: ${err instanceof Error ? err.message : String(err)}. Outputs will be empty (Fn::GetStackOutput cannot resolve).`);
41703
+ logger.warn(`${this.label}: DescribeStacks(${this.cfnStackName}) failed: ${formatAwsErrorForWarn(err)}. Outputs will be empty (Fn::GetStackOutput cannot resolve).`);
41652
41704
  outputs = {};
41653
41705
  }
41654
41706
  return {
@@ -41672,18 +41724,18 @@ var CfnLocalStateProvider = class {
41672
41724
  * partition-aware region list.
41673
41725
  */
41674
41726
  async buildCrossStackResolver(_consumerRegion) {
41727
+ if (this.disposed) throw new Error("CfnLocalStateProvider used after dispose()");
41675
41728
  const logger = getLogger();
41676
41729
  const client = this.getClient();
41677
41730
  const label = this.label;
41678
41731
  const region = this.region;
41679
- let cachedExports;
41680
- const ensureExports = async () => {
41681
- if (cachedExports) return cachedExports;
41682
- const result = await fetchAllExports(client).catch((err) => {
41683
- logger.warn(`${label}: ListExports (${region}) failed: ${err instanceof Error ? err.message : String(err)}. Fn::ImportValue intrinsics will warn-and-drop.`);
41732
+ let exportsPromise;
41733
+ const ensureExports = () => {
41734
+ if (exportsPromise) return exportsPromise;
41735
+ exportsPromise = fetchAllExports(client).catch((err) => {
41736
+ logger.warn(`${label}: ListExports (${region}) failed: ${formatAwsErrorForWarn(err)}. Fn::ImportValue intrinsics will warn-and-drop.`);
41684
41737
  });
41685
- if (result) cachedExports = result;
41686
- return result;
41738
+ return exportsPromise;
41687
41739
  };
41688
41740
  return {
41689
41741
  async resolveImport(exportName) {
@@ -41697,6 +41749,7 @@ var CfnLocalStateProvider = class {
41697
41749
  };
41698
41750
  }
41699
41751
  dispose() {
41752
+ this.disposed = true;
41700
41753
  if (this.client) {
41701
41754
  this.client.destroy();
41702
41755
  this.client = void 0;
@@ -41764,9 +41817,32 @@ async function fetchAllExports(client) {
41764
41817
  nextToken = resp.NextToken;
41765
41818
  pages += 1;
41766
41819
  if (pages > 50) throw new Error("ListExports pagination exceeded 50 pages — likely a malformed NextToken loop.");
41767
- } while (nextToken !== void 0);
41820
+ } while (nextToken !== void 0 && nextToken !== "");
41768
41821
  return out;
41769
41822
  }
41823
+ /**
41824
+ * Format an AWS SDK error as `<name> (HTTP <status>): <message>` so the
41825
+ * surfaced warn name the error class (e.g. `ThrottlingException`,
41826
+ * `AccessDeniedException`, `ValidationError`) and HTTP status alongside
41827
+ * the human-readable message. Falls back to the bare message for
41828
+ * non-SDK errors (the existing pre-issue-#611 behavior) so non-AWS
41829
+ * thrown values still surface meaningfully. Exported for unit testing.
41830
+ *
41831
+ * Issue #611 NIT 4 — `normalizeAwsError` in `utils/error-handler.ts` is
41832
+ * S3-bucket-specific (it rewrites the synthetic `Unknown`/`UnknownError`
41833
+ * with bucket / region context), so the CFn provider extracts the
41834
+ * pieces directly here.
41835
+ */
41836
+ function formatAwsErrorForWarn(err) {
41837
+ if (!(err instanceof Error)) return String(err);
41838
+ const name = err.name && err.name !== "Error" ? err.name : void 0;
41839
+ const status = err.$metadata?.httpStatusCode;
41840
+ const prefixParts = [];
41841
+ if (name !== void 0) prefixParts.push(name);
41842
+ if (status !== void 0) prefixParts.push(`HTTP ${status}`);
41843
+ if (prefixParts.length === 0) return err.message;
41844
+ return `${prefixParts.join(" ")}: ${err.message}`;
41845
+ }
41770
41846
 
41771
41847
  //#endregion
41772
41848
  //#region src/cli/commands/local-state-source.ts
@@ -41811,6 +41887,22 @@ function resolveCfnStackName(fromCfnStack, cdkdStackName) {
41811
41887
  return cdkdStackName;
41812
41888
  }
41813
41889
  /**
41890
+ * Single source of truth for "is the user asking for `--from-cfn-stack`?".
41891
+ * Commander maps the flag to one of `undefined` (absent) / `true` (bare) /
41892
+ * `'<name>'` (explicit). Everything except `undefined` / `false` means the
41893
+ * flag is present. Extracted so the `local-start-api` "state source
41894
+ * active" check (the parent call site that decides whether to load any
41895
+ * state at all) and `createLocalStateProvider`'s own branch logic stay
41896
+ * in lock-step — a previous duplication of this predicate motivated the
41897
+ * extraction (issue #611 NIT 5).
41898
+ *
41899
+ * Exported for use by `local-start-api` and unit testing.
41900
+ */
41901
+ function isCfnFlagPresent(opts) {
41902
+ const v = opts.fromCfnStack;
41903
+ return v !== void 0 && v !== false;
41904
+ }
41905
+ /**
41814
41906
  * Resolve the region used for the CFn client. The CFn provider is
41815
41907
  * region-bound at construction time; we apply the precedence chain
41816
41908
  * `--stack-region` > `--region` > `AWS_REGION` > `AWS_DEFAULT_REGION`
@@ -41881,8 +41973,9 @@ function rejectExplicitCfnStackWithMultipleStacks(options, routedStackCount) {
41881
41973
  */
41882
41974
  function createLocalStateProvider(options, cdkdStackName, synthRegion) {
41883
41975
  const cfnStackOpt = options.fromCfnStack;
41884
- const cfnFlagPresent = cfnStackOpt !== void 0 && cfnStackOpt !== false;
41976
+ const cfnFlagPresent = isCfnFlagPresent(options);
41885
41977
  if (options.fromState && cfnFlagPresent) throw new LocalStateSourceError("--from-state and --from-cfn-stack are mutually exclusive. Use --from-state for stacks deployed via `cdkd deploy`; use --from-cfn-stack for stacks deployed via `cdk deploy` (CloudFormation).");
41978
+ if (cfnStackOpt === "") throw new LocalStateSourceError("--from-cfn-stack requires a non-empty stack name when an explicit value is provided. Drop the value to use the cdkd stack name, or pass --from-cfn-stack <name>.");
41886
41979
  if (options.fromState) return new S3LocalStateProvider({
41887
41980
  statePrefix: options.statePrefix,
41888
41981
  ...options.stateBucket !== void 0 && { stateBucket: options.stateBucket },
@@ -53827,7 +53920,7 @@ async function localStartApiCommand(target, options) {
53827
53920
  const m = buildCorsConfigByApiId(stack.template);
53828
53921
  for (const [k, v] of m) corsConfigByApiId.set(k, v);
53829
53922
  }
53830
- const stateByStack = options.fromState || options.fromCfnStack !== void 0 && options.fromCfnStack !== false ? await loadStateForRoutedStacks(targetStacks, routes, routesWithAuth, options) : /* @__PURE__ */ new Map();
53923
+ const stateByStack = options.fromState || isCfnFlagPresent(options) ? await loadStateForRoutedStacks(targetStacks, routes, routesWithAuth, options) : /* @__PURE__ */ new Map();
53831
53924
  const lambdaIds = uniqueLambdaIds(routes, routesWithAuth, webSocketApis);
53832
53925
  const specs = /* @__PURE__ */ new Map();
53833
53926
  for (let i = 0; i < lambdaIds.length; i++) {
@@ -59343,7 +59436,7 @@ function reorderArgs(argv) {
59343
59436
  */
59344
59437
  async function main() {
59345
59438
  const program = new Command();
59346
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.158.0");
59439
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.158.1");
59347
59440
  program.addCommand(createBootstrapCommand());
59348
59441
  program.addCommand(createSynthCommand());
59349
59442
  program.addCommand(createListCommand());