@go-to-k/cdkd 0.30.1 → 0.31.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
@@ -24,7 +24,7 @@
24
24
  - **Diff calculation**: Self-implemented resource/property-level diff between desired template and current state
25
25
  - **S3-based state management**: No DynamoDB required, uses S3 conditional writes for locking
26
26
  - **DAG-based parallelization**: Analyze `Ref`/`Fn::GetAtt` dependencies and execute in parallel
27
- - **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache and return as soon as the create call returns (CloudFormation always blocks)
27
+ - **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache / NAT Gateway and return as soon as the create call returns (CloudFormation always blocks)
28
28
 
29
29
  > **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. If you encounter an unsupported resource type, deployment will fail with a clear error message.
30
30
 
@@ -372,11 +372,11 @@ cdkd state destroy MyStack --region us-east-1
372
372
 
373
373
  ## `--no-wait`: skip async-resource waits
374
374
 
375
- CloudFront Distributions, RDS Clusters/Instances, and ElastiCache
376
- typically take 3–15 minutes for AWS to fully propagate. By default
377
- cdkd waits for them to reach a ready state — the same behavior as
378
- CloudFormation. Pass `--no-wait` to return as soon as the create call
379
- returns:
375
+ CloudFront Distributions, RDS Clusters/Instances, ElastiCache, and
376
+ NAT Gateways typically take 1–15 minutes for AWS to fully provision.
377
+ By default cdkd waits for them to reach a ready state — the same
378
+ behavior as CloudFormation. Pass `--no-wait` to return as soon as the
379
+ create call returns:
380
380
 
381
381
  ```bash
382
382
  cdkd deploy --no-wait
@@ -386,6 +386,25 @@ The resource is fully functional once AWS finishes the async
386
386
  deployment in the background. CloudFormation has no equivalent — once
387
387
  you submit a stack, you wait for everything.
388
388
 
389
+ NAT Gateway is included as of v0.31. Provisioning typically takes
390
+ 1–2 minutes and is the dominant cost in many VPC stacks; with
391
+ `cdkd deploy --no-wait`, `CreateNatGateway` returns the `NatGatewayId`
392
+ immediately and dependent Routes that only reference the ID can
393
+ proceed against a still-`pending` gateway. AWS continues NAT
394
+ provisioning asynchronously after the deploy returns. Use this only
395
+ when nothing in the deploy flow needs actual NAT-routed egress (e.g.
396
+ no Lambda invoked during deploy that hits the internet).
397
+
398
+ `--no-wait` is **deploy-only**. `cdkd destroy` always waits for NAT
399
+ Gateway to reach `deleted` state — while the gateway is in
400
+ `deleting` AWS keeps the ENI / EIP / route-table associations
401
+ attached, so any concurrent `DeleteSubnet` / `DeleteInternetGateway`
402
+ / `DeleteVpc` returns `DependencyViolation` and the destroy enters a
403
+ retry storm. Other `--no-wait` resources (CloudFront / RDS /
404
+ ElastiCache) don't apply to destroy either — their providers are
405
+ already non-blocking on delete because they're leaves in the destroy
406
+ DAG.
407
+
389
408
  ## Other CLI flags
390
409
 
391
410
  For concurrency knobs (`--concurrency`, `--stack-concurrency`,
package/dist/cli.js CHANGED
@@ -606,6 +606,10 @@ function validateResourceTimeouts(opts) {
606
606
  }
607
607
  }
608
608
  }
609
+ var noWaitOption = new Option(
610
+ "--no-wait",
611
+ "Skip waiting for async resources to stabilize (CloudFront, RDS, ElastiCache, NAT Gateway)"
612
+ );
609
613
  var deployOptions = [
610
614
  new Option("--concurrency <number>", "Maximum concurrent resource operations").default(10).argParser((value) => parseInt(value, 10)),
611
615
  new Option("--stack-concurrency <number>", "Maximum concurrent stack deployments").default(4).argParser((value) => parseInt(value, 10)),
@@ -617,7 +621,7 @@ var deployOptions = [
617
621
  new Option("--dry-run", "Show changes without applying").default(false),
618
622
  new Option("--skip-assets", "Skip asset publishing").default(false),
619
623
  new Option("--no-rollback", "Skip rollback on deployment failure"),
620
- new Option("--no-wait", "Skip waiting for async resources (CloudFront, RDS, etc.)"),
624
+ noWaitOption,
621
625
  new Option(
622
626
  "-e, --exclusively",
623
627
  "Only deploy requested stacks, do not include dependencies"
@@ -7506,7 +7510,11 @@ Error: ${err.message || "Unknown error"}`,
7506
7510
  };
7507
7511
 
7508
7512
  // src/provisioning/providers/custom-resource-provider.ts
7509
- import { InvokeCommand } from "@aws-sdk/client-lambda";
7513
+ import {
7514
+ InvokeCommand,
7515
+ waitUntilFunctionActiveV2,
7516
+ waitUntilFunctionUpdatedV2
7517
+ } from "@aws-sdk/client-lambda";
7510
7518
  import { PublishCommand } from "@aws-sdk/client-sns";
7511
7519
  import {
7512
7520
  S3Client as S3Client6,
@@ -7790,9 +7798,54 @@ var CustomResourceProvider = class _CustomResourceProvider {
7790
7798
  await this.publishToSns(serviceToken, request);
7791
7799
  return await this.pollS3Response(responseKey, logicalId, operation);
7792
7800
  }
7801
+ await this.waitForBackingLambdaReady(serviceToken, logicalId);
7793
7802
  const response = await this.invokeLambda(serviceToken, request);
7794
7803
  return await this.getCustomResourceResponse(response, responseKey, logicalId, operation);
7795
7804
  }
7805
+ /**
7806
+ * Block until the backing Lambda function for a Custom Resource is in a
7807
+ * state that accepts a synchronous Invoke.
7808
+ *
7809
+ * Two sequential waiters:
7810
+ * 1. `waitUntilFunctionActiveV2` — handles the post-CreateFunction
7811
+ * `Pending` window (image pull, VPC ENI attachment, layer init).
7812
+ * 2. `waitUntilFunctionUpdatedV2` — handles the post-Update
7813
+ * `InProgress` window (configuration / code swap settling).
7814
+ * Together they cover the only two transient states that reject
7815
+ * synchronous Invokes.
7816
+ *
7817
+ * In the common case (Lambda has been Active for a while, no in-flight
7818
+ * Update), both waiters return on first poll → ~2 GetFunction calls →
7819
+ * ~200ms overhead. That's the price for correctness; the alternative
7820
+ * (whole-stack Active wait at Lambda CREATE) is ~5–10 minutes per
7821
+ * VPC-attached function.
7822
+ *
7823
+ * `serviceToken` is the Lambda function ARN; the Lambda SDK accepts
7824
+ * both name and ARN as `FunctionName`, so we pass the ARN through
7825
+ * unchanged.
7826
+ *
7827
+ * `maxWaitTime` is set generously (10 min) because VPC ENI attachment
7828
+ * has been observed to take 8+ minutes in pathological cases. The
7829
+ * deploy engine's per-resource `--resource-timeout` (default 30 min)
7830
+ * still bounds the outer Custom Resource provisioning attempt, so
7831
+ * this waiter cap is layered defense, not the only timeout.
7832
+ */
7833
+ async waitForBackingLambdaReady(serviceToken, logicalId) {
7834
+ try {
7835
+ await waitUntilFunctionActiveV2(
7836
+ { client: this.lambdaClient, maxWaitTime: 600 },
7837
+ { FunctionName: serviceToken }
7838
+ );
7839
+ await waitUntilFunctionUpdatedV2(
7840
+ { client: this.lambdaClient, maxWaitTime: 600 },
7841
+ { FunctionName: serviceToken }
7842
+ );
7843
+ } catch (error) {
7844
+ throw new Error(
7845
+ `Lambda backing custom resource ${logicalId} (${serviceToken}) did not reach a ready state for Invoke: ${error instanceof Error ? error.message : String(error)}`
7846
+ );
7847
+ }
7848
+ }
7796
7849
  /**
7797
7850
  * Publish custom resource request to an SNS topic
7798
7851
  */
@@ -12967,8 +13020,7 @@ import {
12967
13020
  ListFunctionsCommand,
12968
13021
  ListTagsCommand,
12969
13022
  ResourceNotFoundException,
12970
- waitUntilFunctionActiveV2,
12971
- waitUntilFunctionUpdatedV2
13023
+ waitUntilFunctionUpdatedV2 as waitUntilFunctionUpdatedV22
12972
13024
  } from "@aws-sdk/client-lambda";
12973
13025
  import {
12974
13026
  DescribeNetworkInterfacesCommand,
@@ -13011,14 +13063,20 @@ var LambdaFunctionProvider = class {
13011
13063
  eniWaitTimeoutMs = 10 * 60 * 1e3;
13012
13064
  eniWaitInitialDelayMs = 1e4;
13013
13065
  eniWaitMaxDelayMs = 3e4;
13014
- // Budget for the post-CreateFunction / post-Update wait that blocks until
13015
- // Configuration.State === 'Active' and LastUpdateStatus === 'Successful'.
13016
- // Must NOT be skipped by --no-wait: downstream resources (Custom Resource
13017
- // Invokes, EventSourceMappings, etc.) cannot operate against a function
13018
- // still in Pending / InProgress, so this is required for correctness, not
13019
- // a "convenience wait" like CloudFront / RDS readiness.
13066
+ // Budget for the post-Update wait that blocks until LastUpdateStatus
13067
+ // === 'Successful'. Required to prevent the SECOND in-flight call (e.g.
13068
+ // UpdateFunctionCode immediately after UpdateFunctionConfiguration)
13069
+ // from racing the first with "function is currently in the following
13070
+ // state: InProgress". Update typically settles in seconds; the 10-min
13071
+ // cap is generous slack for layer-update / VPC-detach edge cases.
13020
13072
  // Seconds (the SDK waiter contract is seconds, not ms).
13021
- functionReadyMaxWaitSeconds = 10 * 60;
13073
+ //
13074
+ // The post-CreateFunction `State=Active` wait used to live here too
13075
+ // (PR #121) but doubled deploy time on benchmark stacks because every
13076
+ // Lambda paid the cost regardless of whether anything synchronously
13077
+ // invoked it. The Active wait now lives in `CustomResourceProvider`
13078
+ // (the only deploy-time consumer that breaks against Pending).
13079
+ functionUpdateMaxWaitSeconds = 10 * 60;
13022
13080
  // delstack-style ENI cleanup tunables.
13023
13081
  // - initial sleep: gives AWS time to publish post-detach ENI state via
13024
13082
  // DescribeNetworkInterfaces (right after the update, the API can return
@@ -13087,7 +13145,6 @@ var LambdaFunctionProvider = class {
13087
13145
  Tags: tags
13088
13146
  };
13089
13147
  const response = await this.lambdaClient.send(new CreateFunctionCommand(createParams));
13090
- await this.waitForFunctionActive(logicalId, resourceType, functionName);
13091
13148
  this.logger.debug(`Successfully created Lambda function ${logicalId}: ${functionName}`);
13092
13149
  return {
13093
13150
  physicalId: response.FunctionName || functionName,
@@ -13097,9 +13154,6 @@ var LambdaFunctionProvider = class {
13097
13154
  }
13098
13155
  };
13099
13156
  } catch (error) {
13100
- if (error instanceof ProvisioningError) {
13101
- throw error;
13102
- }
13103
13157
  const cause = error instanceof Error ? error : void 0;
13104
13158
  throw new ProvisioningError(
13105
13159
  `Failed to create Lambda function ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
@@ -13355,45 +13409,28 @@ var LambdaFunctionProvider = class {
13355
13409
  * Timeout is a soft warning — downstream Subnet/SG deletion has its own
13356
13410
  * retries.
13357
13411
  */
13358
- /**
13359
- * Block until the function's State === 'Active'.
13360
- *
13361
- * Used after CreateFunction. Wraps the SDK's built-in
13362
- * `waitUntilFunctionActiveV2` (acceptors: SUCCESS=Active, FAILURE=Failed,
13363
- * RETRY=Pending). The waiter throws on FAILURE / TIMEOUT — both surface
13364
- * as `ProvisioningError` with the function-name as physicalId so the
13365
- * deploy engine's per-resource error handling treats them identically to
13366
- * a CreateFunction failure.
13367
- */
13368
- async waitForFunctionActive(logicalId, resourceType, functionName) {
13369
- try {
13370
- await waitUntilFunctionActiveV2(
13371
- { client: this.lambdaClient, maxWaitTime: this.functionReadyMaxWaitSeconds },
13372
- { FunctionName: functionName }
13373
- );
13374
- } catch (error) {
13375
- const cause = error instanceof Error ? error : void 0;
13376
- throw new ProvisioningError(
13377
- `Lambda function ${logicalId} did not reach Active state: ${error instanceof Error ? error.message : String(error)}`,
13378
- resourceType,
13379
- logicalId,
13380
- functionName,
13381
- cause
13382
- );
13383
- }
13384
- }
13385
13412
  /**
13386
13413
  * Block until the function's LastUpdateStatus === 'Successful'.
13387
13414
  *
13388
13415
  * Used after UpdateFunctionConfiguration / UpdateFunctionCode. Wraps the
13389
13416
  * SDK's `waitUntilFunctionUpdatedV2` (acceptors: SUCCESS=Successful,
13390
- * FAILURE=Failed, RETRY=InProgress). Same error-wrapping contract as
13391
- * `waitForFunctionActive`.
13417
+ * FAILURE=Failed, RETRY=InProgress). Errors are surfaced as
13418
+ * `ProvisioningError` so the deploy engine's per-resource error
13419
+ * handling treats them identically to an Update API failure.
13420
+ *
13421
+ * NOTE: post-CreateFunction `State=Active` wait was deliberately moved
13422
+ * out of this provider in favor of an on-demand wait inside
13423
+ * `CustomResourceProvider.sendRequest` (the only deploy-time consumer
13424
+ * that breaks against a Pending Lambda). Blocking the entire deploy
13425
+ * DAG behind every Lambda's Active transition more than doubled
13426
+ * deploy time on benchmark stacks; the on-demand wait scoped to the
13427
+ * one resource type that actually needs it preserves the bug fix
13428
+ * without paying the whole-stack tax.
13392
13429
  */
13393
13430
  async waitForFunctionUpdated(logicalId, resourceType, functionName) {
13394
13431
  try {
13395
- await waitUntilFunctionUpdatedV2(
13396
- { client: this.lambdaClient, maxWaitTime: this.functionReadyMaxWaitSeconds },
13432
+ await waitUntilFunctionUpdatedV22(
13433
+ { client: this.lambdaClient, maxWaitTime: this.functionUpdateMaxWaitSeconds },
13397
13434
  { FunctionName: functionName }
13398
13435
  );
13399
13436
  } catch (error) {
@@ -16757,6 +16794,11 @@ import {
16757
16794
  DeleteInternetGatewayCommand,
16758
16795
  AttachInternetGatewayCommand,
16759
16796
  DetachInternetGatewayCommand,
16797
+ CreateNatGatewayCommand,
16798
+ DeleteNatGatewayCommand,
16799
+ DescribeNatGatewaysCommand,
16800
+ waitUntilNatGatewayAvailable,
16801
+ waitUntilNatGatewayDeleted,
16760
16802
  CreateRouteTableCommand,
16761
16803
  DeleteRouteTableCommand,
16762
16804
  CreateRouteCommand,
@@ -16802,6 +16844,20 @@ var EC2Provider = class {
16802
16844
  ],
16803
16845
  ["AWS::EC2::InternetGateway", /* @__PURE__ */ new Set(["Tags"])],
16804
16846
  ["AWS::EC2::VPCGatewayAttachment", /* @__PURE__ */ new Set(["VpcId", "InternetGatewayId"])],
16847
+ [
16848
+ "AWS::EC2::NatGateway",
16849
+ /* @__PURE__ */ new Set([
16850
+ "AllocationId",
16851
+ "SubnetId",
16852
+ "ConnectivityType",
16853
+ "PrivateIpAddress",
16854
+ "SecondaryAllocationIds",
16855
+ "SecondaryPrivateIpAddresses",
16856
+ "SecondaryPrivateIpAddressCount",
16857
+ "MaxDrainDurationSeconds",
16858
+ "Tags"
16859
+ ])
16860
+ ],
16805
16861
  ["AWS::EC2::RouteTable", /* @__PURE__ */ new Set(["VpcId", "Tags"])],
16806
16862
  [
16807
16863
  "AWS::EC2::Route",
@@ -16889,6 +16945,8 @@ var EC2Provider = class {
16889
16945
  return this.createInternetGateway(logicalId, resourceType, properties);
16890
16946
  case "AWS::EC2::VPCGatewayAttachment":
16891
16947
  return this.createVpcGatewayAttachment(logicalId, resourceType, properties);
16948
+ case "AWS::EC2::NatGateway":
16949
+ return this.createNatGateway(logicalId, resourceType, properties);
16892
16950
  case "AWS::EC2::RouteTable":
16893
16951
  return this.createRouteTable(logicalId, resourceType, properties);
16894
16952
  case "AWS::EC2::Route":
@@ -16925,6 +16983,8 @@ var EC2Provider = class {
16925
16983
  return this.updateInternetGateway(logicalId, physicalId);
16926
16984
  case "AWS::EC2::VPCGatewayAttachment":
16927
16985
  return this.updateVpcGatewayAttachment(logicalId, physicalId);
16986
+ case "AWS::EC2::NatGateway":
16987
+ return this.updateNatGateway(logicalId, physicalId);
16928
16988
  case "AWS::EC2::RouteTable":
16929
16989
  return this.updateRouteTable(logicalId, physicalId);
16930
16990
  case "AWS::EC2::Route":
@@ -16978,6 +17038,8 @@ var EC2Provider = class {
16978
17038
  return this.deleteInternetGateway(logicalId, physicalId, resourceType, context);
16979
17039
  case "AWS::EC2::VPCGatewayAttachment":
16980
17040
  return this.deleteVpcGatewayAttachment(logicalId, physicalId, resourceType, context);
17041
+ case "AWS::EC2::NatGateway":
17042
+ return this.deleteNatGateway(logicalId, physicalId, resourceType, context);
16981
17043
  case "AWS::EC2::RouteTable":
16982
17044
  return this.deleteRouteTable(logicalId, physicalId, resourceType, context);
16983
17045
  case "AWS::EC2::Route":
@@ -17546,6 +17608,118 @@ var EC2Provider = class {
17546
17608
  );
17547
17609
  }
17548
17610
  }
17611
+ // ─── AWS::EC2::NatGateway ─────────────────────────────────────────
17612
+ //
17613
+ // CloudFormation parity: by default we wait for the new NAT gateway to
17614
+ // reach `available` state before marking the resource created. NAT
17615
+ // provisioning takes ~1–2 minutes (often the longest single step in a
17616
+ // VPC stack). Pass `--no-wait` to skip the wait — `CreateNatGateway`
17617
+ // returns the `NatGatewayId` immediately so dependent Routes /
17618
+ // Subnets that only need the ID can proceed against a still-`pending`
17619
+ // gateway. Anything that requires actual NAT-routed egress (e.g. a
17620
+ // Lambda invocation that hits the internet during deploy) must not
17621
+ // rely on the gateway being live; with `--no-wait`, AWS continues
17622
+ // provisioning asynchronously after the deploy returns.
17623
+ async createNatGateway(logicalId, resourceType, properties) {
17624
+ this.logger.debug(`Creating NatGateway ${logicalId}`);
17625
+ const subnetId = properties["SubnetId"];
17626
+ if (!subnetId) {
17627
+ throw new ProvisioningError(
17628
+ `SubnetId is required for NatGateway ${logicalId}`,
17629
+ resourceType,
17630
+ logicalId
17631
+ );
17632
+ }
17633
+ try {
17634
+ const response = await this.ec2Client.send(
17635
+ new CreateNatGatewayCommand({
17636
+ SubnetId: subnetId,
17637
+ AllocationId: properties["AllocationId"],
17638
+ ConnectivityType: properties["ConnectivityType"] ?? void 0,
17639
+ PrivateIpAddress: properties["PrivateIpAddress"],
17640
+ SecondaryAllocationIds: properties["SecondaryAllocationIds"],
17641
+ SecondaryPrivateIpAddresses: properties["SecondaryPrivateIpAddresses"],
17642
+ SecondaryPrivateIpAddressCount: properties["SecondaryPrivateIpAddressCount"]
17643
+ })
17644
+ );
17645
+ const natGatewayId = response.NatGateway.NatGatewayId;
17646
+ await this.applyTags(natGatewayId, properties, logicalId);
17647
+ if (process.env["CDKD_NO_WAIT"] !== "true") {
17648
+ this.logger.debug(`Waiting for NatGateway ${natGatewayId} to reach available state...`);
17649
+ await waitUntilNatGatewayAvailable(
17650
+ // 15-min cap matches AWS's documented worst case for NAT
17651
+ // provisioning. Per-resource `--resource-timeout` (default
17652
+ // 30 min) still bounds the outer call as a backstop.
17653
+ { client: this.ec2Client, maxWaitTime: 15 * 60 },
17654
+ { NatGatewayIds: [natGatewayId] }
17655
+ );
17656
+ this.logger.debug(`NatGateway ${natGatewayId} is available`);
17657
+ } else {
17658
+ this.logger.debug(
17659
+ `NatGateway ${natGatewayId} created (skipping available-state wait per --no-wait)`
17660
+ );
17661
+ }
17662
+ this.logger.debug(`Successfully created NatGateway ${logicalId}: ${natGatewayId}`);
17663
+ return {
17664
+ physicalId: natGatewayId,
17665
+ attributes: {
17666
+ NatGatewayId: natGatewayId
17667
+ }
17668
+ };
17669
+ } catch (error) {
17670
+ const cause = error instanceof Error ? error : void 0;
17671
+ throw new ProvisioningError(
17672
+ `Failed to create NatGateway ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
17673
+ resourceType,
17674
+ logicalId,
17675
+ void 0,
17676
+ cause
17677
+ );
17678
+ }
17679
+ }
17680
+ updateNatGateway(logicalId, physicalId) {
17681
+ this.logger.debug(`Updating NatGateway ${logicalId}: ${physicalId} (no-op)`);
17682
+ return Promise.resolve({ physicalId, wasReplaced: false });
17683
+ }
17684
+ async deleteNatGateway(logicalId, physicalId, resourceType, context) {
17685
+ this.logger.debug(`Deleting NatGateway ${logicalId}: ${physicalId}`);
17686
+ try {
17687
+ await this.ec2Client.send(new DeleteNatGatewayCommand({ NatGatewayId: physicalId }));
17688
+ } catch (error) {
17689
+ if (this.isNotFoundError(error)) {
17690
+ const clientRegion = await this.ec2Client.config.region();
17691
+ assertRegionMatch(
17692
+ clientRegion,
17693
+ context?.expectedRegion,
17694
+ resourceType,
17695
+ logicalId,
17696
+ physicalId
17697
+ );
17698
+ this.logger.debug(`NatGateway ${physicalId} does not exist, skipping deletion`);
17699
+ return;
17700
+ }
17701
+ const cause = error instanceof Error ? error : void 0;
17702
+ throw new ProvisioningError(
17703
+ `Failed to delete NatGateway ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
17704
+ resourceType,
17705
+ logicalId,
17706
+ physicalId,
17707
+ cause
17708
+ );
17709
+ }
17710
+ this.logger.debug(`Waiting for NatGateway ${physicalId} to reach deleted state...`);
17711
+ try {
17712
+ await waitUntilNatGatewayDeleted(
17713
+ { client: this.ec2Client, maxWaitTime: 15 * 60 },
17714
+ { NatGatewayIds: [physicalId] }
17715
+ );
17716
+ } catch (error) {
17717
+ this.logger.warn(
17718
+ `Wait for NatGateway ${physicalId} deletion did not complete cleanly: ${error instanceof Error ? error.message : String(error)} \u2014 proceeding with downstream delete steps`
17719
+ );
17720
+ }
17721
+ this.logger.debug(`Successfully deleted NatGateway ${logicalId}`);
17722
+ }
17549
17723
  // ─── AWS::EC2::RouteTable ─────────────────────────────────────────
17550
17724
  async createRouteTable(logicalId, resourceType, properties) {
17551
17725
  this.logger.debug(`Creating RouteTable ${logicalId}`);
@@ -18755,6 +18929,15 @@ var EC2Provider = class {
18755
18929
  const sg = resp.SecurityGroups?.[0];
18756
18930
  return sg?.GroupId ? { physicalId: sg.GroupId, attributes: {} } : null;
18757
18931
  }
18932
+ case "AWS::EC2::NatGateway": {
18933
+ const resp = await this.ec2Client.send(
18934
+ new DescribeNatGatewaysCommand({
18935
+ Filter: [{ Name: `tag:${CDK_PATH_TAG}`, Values: [input.cdkPath] }]
18936
+ })
18937
+ );
18938
+ const gw = resp.NatGateways?.find((g) => g.State !== "deleted" && g.State !== "deleting");
18939
+ return gw?.NatGatewayId ? { physicalId: gw.NatGatewayId, attributes: {} } : null;
18940
+ }
18758
18941
  default:
18759
18942
  return null;
18760
18943
  }
@@ -18783,6 +18966,13 @@ var EC2Provider = class {
18783
18966
  );
18784
18967
  return resp.SecurityGroups?.[0] ? { physicalId, attributes: {} } : null;
18785
18968
  }
18969
+ case "AWS::EC2::NatGateway": {
18970
+ const resp = await this.ec2Client.send(
18971
+ new DescribeNatGatewaysCommand({ NatGatewayIds: [physicalId] })
18972
+ );
18973
+ const gw = resp.NatGateways?.find((g) => g.State !== "deleted" && g.State !== "deleting");
18974
+ return gw ? { physicalId, attributes: {} } : null;
18975
+ }
18786
18976
  default:
18787
18977
  return null;
18788
18978
  }
@@ -31106,6 +31296,7 @@ function registerAllProviders(registry) {
31106
31296
  registry.register("AWS::EC2::Subnet", ec2Provider);
31107
31297
  registry.register("AWS::EC2::InternetGateway", ec2Provider);
31108
31298
  registry.register("AWS::EC2::VPCGatewayAttachment", ec2Provider);
31299
+ registry.register("AWS::EC2::NatGateway", ec2Provider);
31109
31300
  registry.register("AWS::EC2::RouteTable", ec2Provider);
31110
31301
  registry.register("AWS::EC2::Route", ec2Provider);
31111
31302
  registry.register("AWS::EC2::SubnetRouteTableAssociation", ec2Provider);
@@ -36139,7 +36330,7 @@ function reorderArgs(argv) {
36139
36330
  }
36140
36331
  async function main() {
36141
36332
  const program = new Command13();
36142
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.30.1");
36333
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.31.0");
36143
36334
  program.addCommand(createBootstrapCommand());
36144
36335
  program.addCommand(createSynthCommand());
36145
36336
  program.addCommand(createListCommand());