alchemy 0.53.0 → 0.55.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/bin/alchemy.js +196353 -0
- package/bin/alchemy.ts +2 -2
- package/bin/commands/init.ts +1190 -0
- package/bin/constants.ts +18 -0
- package/bin/services/execute-alchemy.ts +7 -2
- package/bin/services/package-manager.ts +1 -1
- package/bin/types.ts +14 -5
- package/lib/aws/ec2/index.d.ts +10 -0
- package/lib/aws/ec2/index.d.ts.map +1 -0
- package/lib/aws/ec2/index.js +10 -0
- package/lib/aws/ec2/index.js.map +1 -0
- package/lib/aws/ec2/internet-gateway-attachment.d.ts +150 -0
- package/lib/aws/ec2/internet-gateway-attachment.d.ts.map +1 -0
- package/lib/aws/ec2/internet-gateway-attachment.js +248 -0
- package/lib/aws/ec2/internet-gateway-attachment.js.map +1 -0
- package/lib/aws/ec2/internet-gateway.d.ts +132 -0
- package/lib/aws/ec2/internet-gateway.d.ts.map +1 -0
- package/lib/aws/ec2/internet-gateway.js +311 -0
- package/lib/aws/ec2/internet-gateway.js.map +1 -0
- package/lib/aws/ec2/nat-gateway.d.ts +145 -0
- package/lib/aws/ec2/nat-gateway.d.ts.map +1 -0
- package/lib/aws/ec2/nat-gateway.js +618 -0
- package/lib/aws/ec2/nat-gateway.js.map +1 -0
- package/lib/aws/ec2/route-table-association.d.ts +134 -0
- package/lib/aws/ec2/route-table-association.d.ts.map +1 -0
- package/lib/aws/ec2/route-table-association.js +364 -0
- package/lib/aws/ec2/route-table-association.js.map +1 -0
- package/lib/aws/ec2/route-table.d.ts +94 -0
- package/lib/aws/ec2/route-table.d.ts.map +1 -0
- package/lib/aws/ec2/route-table.js +253 -0
- package/lib/aws/ec2/route-table.js.map +1 -0
- package/lib/aws/ec2/route.d.ts +130 -0
- package/lib/aws/ec2/route.d.ts.map +1 -0
- package/lib/aws/ec2/route.js +253 -0
- package/lib/aws/ec2/route.js.map +1 -0
- package/lib/aws/ec2/security-group-rule.d.ts +84 -0
- package/lib/aws/ec2/security-group-rule.d.ts.map +1 -0
- package/lib/aws/ec2/security-group-rule.js +123 -0
- package/lib/aws/ec2/security-group-rule.js.map +1 -0
- package/lib/aws/ec2/security-group.d.ts +84 -0
- package/lib/aws/ec2/security-group.d.ts.map +1 -0
- package/lib/aws/ec2/security-group.js +207 -0
- package/lib/aws/ec2/security-group.js.map +1 -0
- package/lib/aws/ec2/subnet.d.ts +110 -0
- package/lib/aws/ec2/subnet.d.ts.map +1 -0
- package/lib/aws/ec2/subnet.js +336 -0
- package/lib/aws/ec2/subnet.js.map +1 -0
- package/lib/aws/ec2/utils.d.ts +15 -0
- package/lib/aws/ec2/utils.d.ts.map +1 -0
- package/lib/aws/ec2/utils.js +79 -0
- package/lib/aws/ec2/utils.js.map +1 -0
- package/lib/aws/ec2/vpc.d.ts +160 -0
- package/lib/aws/ec2/vpc.d.ts.map +1 -0
- package/lib/aws/ec2/vpc.js +453 -0
- package/lib/aws/ec2/vpc.js.map +1 -0
- package/lib/aws/index.d.ts +7 -0
- package/lib/aws/index.d.ts.map +1 -1
- package/lib/aws/index.js +8 -0
- package/lib/aws/index.js.map +1 -1
- package/lib/aws/utils.d.ts +25 -0
- package/lib/aws/utils.d.ts.map +1 -0
- package/lib/aws/utils.js +89 -0
- package/lib/aws/utils.js.map +1 -0
- package/lib/build-date.d.ts +6 -0
- package/lib/build-date.d.ts.map +1 -0
- package/lib/build-date.js +8 -0
- package/lib/build-date.js.map +1 -0
- package/lib/cloudflare/astro.d.ts.map +1 -1
- package/lib/cloudflare/astro.js +4 -3
- package/lib/cloudflare/astro.js.map +1 -1
- package/lib/cloudflare/bundle/externals.d.ts +3 -0
- package/lib/cloudflare/bundle/externals.d.ts.map +1 -0
- package/lib/cloudflare/bundle/externals.js +35 -0
- package/lib/cloudflare/bundle/externals.js.map +1 -0
- package/lib/cloudflare/bundle/internal-worker-bundle.d.ts +8 -1
- package/lib/cloudflare/bundle/internal-worker-bundle.d.ts.map +1 -1
- package/lib/cloudflare/bundle/internal-worker-bundle.js +11 -4
- package/lib/cloudflare/bundle/internal-worker-bundle.js.map +1 -1
- package/lib/cloudflare/bundle/plugin-hot-reload.d.ts +4 -1
- package/lib/cloudflare/bundle/plugin-hot-reload.d.ts.map +1 -1
- package/lib/cloudflare/bundle/plugin-hot-reload.js +27 -11
- package/lib/cloudflare/bundle/plugin-hot-reload.js.map +1 -1
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js +5 -1
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js.map +1 -1
- package/lib/cloudflare/bundle/plugin-wasm.d.ts +6 -2
- package/lib/cloudflare/bundle/plugin-wasm.d.ts.map +1 -1
- package/lib/cloudflare/bundle/plugin-wasm.js +21 -47
- package/lib/cloudflare/bundle/plugin-wasm.js.map +1 -1
- package/lib/cloudflare/bundle/validate-node-compat.d.ts +2 -1
- package/lib/cloudflare/bundle/validate-node-compat.d.ts.map +1 -1
- package/lib/cloudflare/bundle/validate-node-compat.js +5 -4
- package/lib/cloudflare/bundle/validate-node-compat.js.map +1 -1
- package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
- package/lib/cloudflare/compatibility-date.gen.js +1 -1
- package/lib/cloudflare/d1-database.js +1 -1
- package/lib/cloudflare/d1-database.js.map +1 -1
- package/lib/cloudflare/d1-migrations.d.ts.map +1 -1
- package/lib/cloudflare/d1-migrations.js +8 -10
- package/lib/cloudflare/d1-migrations.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts +3 -3
- package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-options.js +23 -6
- package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare.js +2 -4
- package/lib/cloudflare/miniflare/miniflare.js.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.js +4 -6
- package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
- package/lib/cloudflare/react-router.d.ts +4 -0
- package/lib/cloudflare/react-router.d.ts.map +1 -1
- package/lib/cloudflare/react-router.js +8 -5
- package/lib/cloudflare/react-router.js.map +1 -1
- package/lib/cloudflare/worker-bundle.d.ts +80 -0
- package/lib/cloudflare/worker-bundle.d.ts.map +1 -0
- package/lib/cloudflare/worker-bundle.js +266 -0
- package/lib/cloudflare/worker-bundle.js.map +1 -0
- package/lib/cloudflare/worker.d.ts +1 -1
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +81 -195
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/esbuild/bundle.d.ts +1 -0
- package/lib/esbuild/bundle.d.ts.map +1 -1
- package/lib/state/cloudflare-state-store.js +1 -5
- package/lib/state/cloudflare-state-store.js.map +1 -1
- package/lib/state/dofs-state-store/store.d.ts.map +1 -1
- package/lib/state/dofs-state-store/store.js +4 -4
- package/lib/state/dofs-state-store/store.js.map +1 -1
- package/lib/util/params.d.ts +5 -0
- package/lib/util/params.d.ts.map +1 -0
- package/lib/util/params.js +30 -0
- package/lib/util/params.js.map +1 -0
- package/lib/util/timeout.d.ts +31 -0
- package/lib/util/timeout.d.ts.map +1 -0
- package/lib/util/timeout.js +109 -0
- package/lib/util/timeout.js.map +1 -0
- package/lib/util/xml.d.ts +5 -0
- package/lib/util/xml.d.ts.map +1 -0
- package/lib/util/xml.js +8 -0
- package/lib/util/xml.js.map +1 -0
- package/package.json +12 -5
- package/src/aws/ec2/index.ts +9 -0
- package/src/aws/ec2/internet-gateway-attachment.ts +468 -0
- package/src/aws/ec2/internet-gateway.ts +557 -0
- package/src/aws/ec2/nat-gateway.ts +1123 -0
- package/src/aws/ec2/route-table-association.ts +747 -0
- package/src/aws/ec2/route-table.ts +452 -0
- package/src/aws/ec2/route.ts +447 -0
- package/src/aws/ec2/security-group-rule.ts +229 -0
- package/src/aws/ec2/security-group.ts +418 -0
- package/src/aws/ec2/subnet.ts +625 -0
- package/src/aws/ec2/utils.ts +102 -0
- package/src/aws/ec2/vpc.ts +969 -0
- package/src/aws/index.ts +9 -0
- package/src/aws/utils.ts +137 -0
- package/src/build-date.ts +8 -0
- package/src/cloudflare/astro.ts +4 -3
- package/src/cloudflare/bundle/externals.ts +36 -0
- package/src/cloudflare/bundle/internal-worker-bundle.ts +12 -3
- package/src/cloudflare/bundle/plugin-hot-reload.ts +32 -12
- package/src/cloudflare/bundle/plugin-hybrid-node-compat.ts +6 -1
- package/src/cloudflare/bundle/plugin-wasm.ts +26 -54
- package/src/cloudflare/bundle/validate-node-compat.ts +6 -5
- package/src/cloudflare/compatibility-date.gen.ts +1 -1
- package/src/cloudflare/d1-database.ts +1 -1
- package/src/cloudflare/d1-migrations.ts +19 -18
- package/src/cloudflare/miniflare/miniflare-worker-options.ts +27 -13
- package/src/cloudflare/miniflare/miniflare.ts +2 -4
- package/src/cloudflare/miniflare/remote-binding-proxy.ts +5 -7
- package/src/cloudflare/react-router.ts +14 -6
- package/src/cloudflare/worker-bundle.ts +364 -0
- package/src/cloudflare/worker.ts +104 -241
- package/src/state/cloudflare-state-store.ts +1 -5
- package/src/state/dofs-state-store/store.ts +4 -4
- package/src/util/params.ts +33 -0
- package/src/util/timeout.ts +178 -0
- package/src/util/xml.ts +7 -0
- package/templates/nuxt/package.json +1 -1
- package/templates/nuxt/types/env.d.ts +11 -0
- package/templates/react-router/workers/app.ts +2 -2
- package/templates/rwsdk/.cursor/rules/alchemy_cloudflare.mdc +385 -0
- package/templates/rwsdk/wrangler.jsonc +10 -7
- package/templates/typescript/tsconfig.json +1 -2
- package/bin/alchemy.mjs +0 -51766
- package/lib/cloudflare/bundle/esbuild.d.ts +0 -16
- package/lib/cloudflare/bundle/esbuild.d.ts.map +0 -1
- package/lib/cloudflare/bundle/esbuild.js +0 -159
- package/lib/cloudflare/bundle/esbuild.js.map +0 -1
- package/lib/cloudflare/bundle/fs.d.ts +0 -18
- package/lib/cloudflare/bundle/fs.d.ts.map +0 -1
- package/lib/cloudflare/bundle/fs.js +0 -78
- package/lib/cloudflare/bundle/fs.js.map +0 -1
- package/lib/cloudflare/bundle/index.d.ts +0 -3
- package/lib/cloudflare/bundle/index.d.ts.map +0 -1
- package/lib/cloudflare/bundle/index.js +0 -2
- package/lib/cloudflare/bundle/index.js.map +0 -1
- package/lib/cloudflare/bundle/inline.d.ts +0 -12
- package/lib/cloudflare/bundle/inline.d.ts.map +0 -1
- package/lib/cloudflare/bundle/inline.js +0 -32
- package/lib/cloudflare/bundle/inline.js.map +0 -1
- package/lib/cloudflare/bundle/normalize.d.ts +0 -21
- package/lib/cloudflare/bundle/normalize.d.ts.map +0 -1
- package/lib/cloudflare/bundle/normalize.js +0 -49
- package/lib/cloudflare/bundle/normalize.js.map +0 -1
- package/lib/cloudflare/bundle/shared.d.ts +0 -30
- package/lib/cloudflare/bundle/shared.d.ts.map +0 -1
- package/lib/cloudflare/bundle/shared.js +0 -34
- package/lib/cloudflare/bundle/shared.js.map +0 -1
- package/src/cloudflare/bundle/esbuild.ts +0 -194
- package/src/cloudflare/bundle/fs.ts +0 -103
- package/src/cloudflare/bundle/index.ts +0 -6
- package/src/cloudflare/bundle/inline.ts +0 -42
- package/src/cloudflare/bundle/normalize.ts +0 -76
- package/src/cloudflare/bundle/shared.ts +0 -73
|
@@ -0,0 +1,1123 @@
|
|
|
1
|
+
import { XMLParser } from "fast-xml-parser";
|
|
2
|
+
import type { Context } from "../../context.ts";
|
|
3
|
+
import { Resource } from "../../resource.ts";
|
|
4
|
+
import { ignore } from "../../util/ignore.ts";
|
|
5
|
+
import { logger } from "../../util/logger.ts";
|
|
6
|
+
import {
|
|
7
|
+
mergeTimeoutConfig,
|
|
8
|
+
type TimeoutConfig,
|
|
9
|
+
waitForResourceState,
|
|
10
|
+
} from "../../util/timeout.ts";
|
|
11
|
+
import type { Subnet } from "./subnet.ts";
|
|
12
|
+
import { callEC2Api, createEC2Client } from "./utils.ts";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Properties for creating or updating a NAT Gateway
|
|
16
|
+
*/
|
|
17
|
+
export interface NatGatewayProps {
|
|
18
|
+
/**
|
|
19
|
+
* The subnet to create the NAT Gateway in (must be a public subnet)
|
|
20
|
+
*/
|
|
21
|
+
subnet: Subnet | string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The allocation ID of an existing Elastic IP address
|
|
25
|
+
* If not provided, a new Elastic IP will be allocated
|
|
26
|
+
*/
|
|
27
|
+
allocationId?: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The connectivity type for the NAT Gateway
|
|
31
|
+
* @default "public"
|
|
32
|
+
*/
|
|
33
|
+
connectivityType?: "public" | "private";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Tags to apply to the NAT Gateway
|
|
37
|
+
*/
|
|
38
|
+
tags?: Record<string, string>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Timeout configuration for NAT Gateway operations
|
|
42
|
+
* @default NAT Gateway-specific sensible defaults (60 attempts, 5000ms delay)
|
|
43
|
+
*/
|
|
44
|
+
timeout?: Partial<TimeoutConfig>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Output returned after NAT Gateway creation/update
|
|
49
|
+
*/
|
|
50
|
+
export interface NatGateway
|
|
51
|
+
extends Resource<"aws::NatGateway">,
|
|
52
|
+
NatGatewayProps {
|
|
53
|
+
/**
|
|
54
|
+
* The ID of the NAT Gateway
|
|
55
|
+
*/
|
|
56
|
+
natGatewayId: string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The ID of the subnet the NAT Gateway is in
|
|
60
|
+
*/
|
|
61
|
+
subnetId: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The ID of the VPC the NAT Gateway belongs to
|
|
65
|
+
*/
|
|
66
|
+
vpcId: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The current state of the NAT Gateway
|
|
70
|
+
*/
|
|
71
|
+
state: "pending" | "failed" | "available" | "deleting" | "deleted";
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The allocation ID of the Elastic IP address
|
|
75
|
+
*/
|
|
76
|
+
allocationId: string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The public IP address of the NAT Gateway
|
|
80
|
+
*/
|
|
81
|
+
publicIp?: string;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The private IP address of the NAT Gateway
|
|
85
|
+
*/
|
|
86
|
+
privateIp?: string;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Whether the Elastic IP was created by this resource
|
|
90
|
+
*/
|
|
91
|
+
createdElasticIp: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* AWS NAT Gateway Resource
|
|
96
|
+
*
|
|
97
|
+
* Creates and manages NAT Gateways that provide outbound internet access
|
|
98
|
+
* for instances in private subnets. Automatically allocates an Elastic IP
|
|
99
|
+
* if one is not provided. NAT Gateways are slow resources that can take
|
|
100
|
+
* up to 10 minutes to become available.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* // Create a NAT Gateway with automatic Elastic IP allocation
|
|
104
|
+
* const natGateway = await NatGateway("main-nat", {
|
|
105
|
+
* subnet: publicSubnet,
|
|
106
|
+
* tags: {
|
|
107
|
+
* Name: "main-nat-gateway",
|
|
108
|
+
* Environment: "production"
|
|
109
|
+
* }
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* // Create a NAT Gateway with existing Elastic IP
|
|
114
|
+
* const natGateway = await NatGateway("custom-nat", {
|
|
115
|
+
* subnet: "subnet-12345678",
|
|
116
|
+
* allocationId: "eipalloc-12345678",
|
|
117
|
+
* connectivityType: "public",
|
|
118
|
+
* tags: {
|
|
119
|
+
* Name: "custom-nat-gateway"
|
|
120
|
+
* }
|
|
121
|
+
* });
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* // Create a private NAT Gateway (for VPC-to-VPC communication)
|
|
125
|
+
* const privateNat = await NatGateway("private-nat", {
|
|
126
|
+
* subnet: privateSubnet,
|
|
127
|
+
* connectivityType: "private",
|
|
128
|
+
* tags: {
|
|
129
|
+
* Name: "private-nat-gateway",
|
|
130
|
+
* Type: "internal"
|
|
131
|
+
* }
|
|
132
|
+
* });
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Create a NAT Gateway with custom timeout configuration
|
|
136
|
+
* const slowNat = await NatGateway("slow-nat", {
|
|
137
|
+
* subnet: publicSubnet,
|
|
138
|
+
* timeout: {
|
|
139
|
+
* maxAttempts: 180, // Wait up to 15 minutes
|
|
140
|
+
* delayMs: 5000 // Check every 5 seconds
|
|
141
|
+
* },
|
|
142
|
+
* tags: {
|
|
143
|
+
* Name: "slow-nat-gateway"
|
|
144
|
+
* }
|
|
145
|
+
* });
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* // Use NAT Gateway in route table for private subnet internet access
|
|
149
|
+
* const privateRoute = await Route("private-internet", {
|
|
150
|
+
* routeTable: privateRouteTable,
|
|
151
|
+
* destinationCidrBlock: "0.0.0.0/0",
|
|
152
|
+
* natGateway: natGateway,
|
|
153
|
+
* tags: {
|
|
154
|
+
* Name: "private-to-internet"
|
|
155
|
+
* }
|
|
156
|
+
* });
|
|
157
|
+
*/
|
|
158
|
+
export const NatGateway = Resource(
|
|
159
|
+
"aws::NatGateway",
|
|
160
|
+
async function (
|
|
161
|
+
this: Context<NatGateway>,
|
|
162
|
+
_id: string,
|
|
163
|
+
props: NatGatewayProps,
|
|
164
|
+
): Promise<NatGateway> {
|
|
165
|
+
const subnetId =
|
|
166
|
+
typeof props.subnet === "string" ? props.subnet : props.subnet.subnetId;
|
|
167
|
+
const timeoutConfig = mergeTimeoutConfig(
|
|
168
|
+
NAT_GATEWAY_TIMEOUT,
|
|
169
|
+
props.timeout,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (this.phase === "delete") {
|
|
173
|
+
if (this.output?.natGatewayId) {
|
|
174
|
+
logger.log(`🗑️ Deleting NAT Gateway: ${this.output.natGatewayId}`);
|
|
175
|
+
// Delete NAT Gateway if it exists
|
|
176
|
+
await ignore("InvalidNatGatewayID.NotFound", async () => {
|
|
177
|
+
const client = await createEC2Client();
|
|
178
|
+
await callEC2Api(
|
|
179
|
+
client,
|
|
180
|
+
"DeleteNatGateway",
|
|
181
|
+
parseNatGatewayXmlResponse,
|
|
182
|
+
convertDeleteNatGatewayParamsToAwsFormat({
|
|
183
|
+
NatGatewayId: this.output!.natGatewayId,
|
|
184
|
+
}),
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Wait for NAT Gateway to be deleted AND network interfaces to be cleaned up
|
|
189
|
+
logger.log(
|
|
190
|
+
` Waiting for NAT Gateway ${this.output.natGatewayId} to be fully deleted...`,
|
|
191
|
+
);
|
|
192
|
+
await waitForNatGatewayFullyDeleted(
|
|
193
|
+
this.output.natGatewayId,
|
|
194
|
+
timeoutConfig,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
logger.log(
|
|
198
|
+
` ✅ NAT Gateway ${this.output.natGatewayId} deletion completed`,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
// Release Elastic IP if we created it and it exists
|
|
202
|
+
if (this.output.createdElasticIp && this.output.allocationId) {
|
|
203
|
+
logger.log(` Releasing Elastic IP: ${this.output.allocationId}`);
|
|
204
|
+
await ignore(
|
|
205
|
+
["InvalidAllocationID.NotFound", "InvalidAddress.NotFound"],
|
|
206
|
+
async () => {
|
|
207
|
+
const eipClient = await createEC2Client();
|
|
208
|
+
await callEC2Api(
|
|
209
|
+
eipClient,
|
|
210
|
+
"ReleaseAddress",
|
|
211
|
+
parseNatGatewayXmlResponse,
|
|
212
|
+
convertReleaseAddressParamsToAwsFormat({
|
|
213
|
+
AllocationId: this.output!.allocationId,
|
|
214
|
+
}),
|
|
215
|
+
);
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
// Wait for the EIP to be fully released
|
|
219
|
+
await waitForEipReleased(this.output.allocationId, timeoutConfig);
|
|
220
|
+
logger.log(
|
|
221
|
+
` ✅ Elastic IP ${this.output.allocationId} released successfully`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return this.destroy();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
let natGateway: AwsNatGateway;
|
|
229
|
+
let allocationId = props.allocationId;
|
|
230
|
+
let createdElasticIp = false;
|
|
231
|
+
let publicIp: string | undefined;
|
|
232
|
+
|
|
233
|
+
if (this.phase === "update" && this.output?.natGatewayId) {
|
|
234
|
+
// Get existing NAT Gateway
|
|
235
|
+
const client = await createEC2Client();
|
|
236
|
+
const response = await callEC2Api<DescribeNatGatewaysResponse>(
|
|
237
|
+
client,
|
|
238
|
+
"DescribeNatGateways",
|
|
239
|
+
parseNatGatewayXmlResponse,
|
|
240
|
+
convertDescribeNatGatewaysParamsToAwsFormat({
|
|
241
|
+
NatGatewayIds: [this.output.natGatewayId],
|
|
242
|
+
}),
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
if (!response.NatGateways?.[0]) {
|
|
246
|
+
throw new Error(`NAT Gateway ${this.output.natGatewayId} not found`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
natGateway = response.NatGateways[0];
|
|
250
|
+
allocationId = this.output.allocationId;
|
|
251
|
+
createdElasticIp = this.output.createdElasticIp;
|
|
252
|
+
publicIp = this.output.publicIp;
|
|
253
|
+
} else {
|
|
254
|
+
// Allocate Elastic IP if not provided
|
|
255
|
+
if (!allocationId) {
|
|
256
|
+
const eipParams: AllocateAddressParams = {
|
|
257
|
+
Domain: "vpc",
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// Add tags if specified
|
|
261
|
+
if (props.tags) {
|
|
262
|
+
eipParams.TagSpecifications = [
|
|
263
|
+
{
|
|
264
|
+
ResourceType: "elastic-ip",
|
|
265
|
+
Tags: Object.entries(props.tags).map(([key, value]) => ({
|
|
266
|
+
Key: `${key}-eip`,
|
|
267
|
+
Value: value,
|
|
268
|
+
})),
|
|
269
|
+
},
|
|
270
|
+
];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const client = await createEC2Client();
|
|
274
|
+
const eipResponse = await callEC2Api<AllocateAddressResponse>(
|
|
275
|
+
client,
|
|
276
|
+
"AllocateAddress",
|
|
277
|
+
parseNatGatewayXmlResponse,
|
|
278
|
+
convertAllocateAddressParamsToAwsFormat(eipParams),
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
if (!eipResponse.AllocationId) {
|
|
282
|
+
throw new Error("Failed to allocate Elastic IP");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
allocationId = eipResponse.AllocationId;
|
|
286
|
+
publicIp = eipResponse.PublicIp;
|
|
287
|
+
createdElasticIp = true;
|
|
288
|
+
} else {
|
|
289
|
+
// Get public IP of existing allocation
|
|
290
|
+
const client = await createEC2Client();
|
|
291
|
+
const addressResponse = await callEC2Api<DescribeAddressesResponse>(
|
|
292
|
+
client,
|
|
293
|
+
"DescribeAddresses",
|
|
294
|
+
parseNatGatewayXmlResponse,
|
|
295
|
+
convertDescribeAddressesParamsToAwsFormat({
|
|
296
|
+
AllocationIds: [allocationId],
|
|
297
|
+
}),
|
|
298
|
+
);
|
|
299
|
+
publicIp = addressResponse.Addresses?.[0]?.PublicIp;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Create NAT Gateway
|
|
303
|
+
const createParams: CreateNatGatewayParams = {
|
|
304
|
+
SubnetId: subnetId,
|
|
305
|
+
AllocationId: allocationId,
|
|
306
|
+
ConnectivityType: props.connectivityType || "public",
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// Add tags if specified
|
|
310
|
+
if (props.tags) {
|
|
311
|
+
createParams.TagSpecifications = [
|
|
312
|
+
{
|
|
313
|
+
ResourceType: "natgateway",
|
|
314
|
+
Tags: Object.entries(props.tags).map(([key, value]) => ({
|
|
315
|
+
Key: key,
|
|
316
|
+
Value: value,
|
|
317
|
+
})),
|
|
318
|
+
},
|
|
319
|
+
];
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const natClient = await createEC2Client();
|
|
323
|
+
const response = await callEC2Api<CreateNatGatewayResponse>(
|
|
324
|
+
natClient,
|
|
325
|
+
"CreateNatGateway",
|
|
326
|
+
parseNatGatewayXmlResponse,
|
|
327
|
+
convertCreateNatGatewayParamsToAwsFormat(createParams),
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
if (!response.NatGateway) {
|
|
331
|
+
throw new Error("Failed to create NAT Gateway");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
natGateway = response.NatGateway;
|
|
335
|
+
|
|
336
|
+
// Wait for NAT Gateway to be available
|
|
337
|
+
await waitForNatGatewayAvailable(natGateway.NatGatewayId!, timeoutConfig);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const result = this({
|
|
341
|
+
natGatewayId: natGateway.NatGatewayId!,
|
|
342
|
+
subnetId: natGateway.SubnetId!,
|
|
343
|
+
vpcId: natGateway.VpcId!,
|
|
344
|
+
state: natGateway.State,
|
|
345
|
+
allocationId: allocationId!,
|
|
346
|
+
publicIp,
|
|
347
|
+
privateIp: natGateway.NatGatewayAddresses?.[0]?.PrivateIp,
|
|
348
|
+
createdElasticIp,
|
|
349
|
+
...props,
|
|
350
|
+
subnet: subnetId,
|
|
351
|
+
});
|
|
352
|
+
return result;
|
|
353
|
+
},
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Wait for NAT Gateway to be in available state
|
|
358
|
+
*/
|
|
359
|
+
async function waitForNatGatewayAvailable(
|
|
360
|
+
natGatewayId: string,
|
|
361
|
+
timeoutConfig: TimeoutConfig,
|
|
362
|
+
): Promise<void> {
|
|
363
|
+
const checkFunction = async () => {
|
|
364
|
+
const client = await createEC2Client();
|
|
365
|
+
const response = await callEC2Api<DescribeNatGatewaysResponse>(
|
|
366
|
+
client,
|
|
367
|
+
"DescribeNatGateways",
|
|
368
|
+
parseNatGatewayXmlResponse,
|
|
369
|
+
convertDescribeNatGatewaysParamsToAwsFormat({
|
|
370
|
+
NatGatewayIds: [natGatewayId],
|
|
371
|
+
}),
|
|
372
|
+
);
|
|
373
|
+
return response.NatGateways?.[0];
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
const isReady = (natGateway: AwsNatGateway | undefined) => {
|
|
377
|
+
// Check for non-retryable failure states
|
|
378
|
+
if (natGateway?.State === "failed") {
|
|
379
|
+
throw new NatGatewayNonRetryableError(
|
|
380
|
+
`NAT Gateway ${natGatewayId} failed to create`,
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
return natGateway?.State === "available";
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
await waitForResourceState(
|
|
387
|
+
checkFunction,
|
|
388
|
+
isReady,
|
|
389
|
+
timeoutConfig,
|
|
390
|
+
natGatewayId,
|
|
391
|
+
"NAT Gateway",
|
|
392
|
+
"is now available",
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Wait for NAT Gateway to be deleted
|
|
397
|
+
*/
|
|
398
|
+
async function waitForNatGatewayDeleted(
|
|
399
|
+
natGatewayId: string,
|
|
400
|
+
timeoutConfig: TimeoutConfig,
|
|
401
|
+
): Promise<void> {
|
|
402
|
+
const checkFunction = async () => {
|
|
403
|
+
try {
|
|
404
|
+
const client = await createEC2Client();
|
|
405
|
+
const response = await callEC2Api<DescribeNatGatewaysResponse>(
|
|
406
|
+
client,
|
|
407
|
+
"DescribeNatGateways",
|
|
408
|
+
parseNatGatewayXmlResponse,
|
|
409
|
+
convertDescribeNatGatewaysParamsToAwsFormat({
|
|
410
|
+
NatGatewayIds: [natGatewayId],
|
|
411
|
+
}),
|
|
412
|
+
);
|
|
413
|
+
return response.NatGateways?.[0];
|
|
414
|
+
} catch (error: any) {
|
|
415
|
+
// If NAT Gateway is not found, it's been deleted - return undefined
|
|
416
|
+
if (
|
|
417
|
+
error.code === "InvalidNatGatewayID.NotFound" ||
|
|
418
|
+
error.code === "InvalidNatGateway.NotFound" ||
|
|
419
|
+
error.code === "NatGatewayNotFound"
|
|
420
|
+
) {
|
|
421
|
+
return undefined;
|
|
422
|
+
}
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
const isReady = (natGateway: AwsNatGateway | undefined) => {
|
|
428
|
+
// NAT Gateway is deleted if it doesn't exist or is in deleted state
|
|
429
|
+
return !natGateway || natGateway.State === "deleted";
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
await waitForResourceState(
|
|
433
|
+
checkFunction,
|
|
434
|
+
isReady,
|
|
435
|
+
timeoutConfig,
|
|
436
|
+
natGatewayId,
|
|
437
|
+
"NAT Gateway",
|
|
438
|
+
"deletion completed",
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Parse XML response for DescribeNetworkInterfaces
|
|
444
|
+
*/
|
|
445
|
+
function parseDescribeNetworkInterfacesResponse(
|
|
446
|
+
xmlText: string,
|
|
447
|
+
): DescribeNetworkInterfacesResponse {
|
|
448
|
+
const parser = new XMLParser({
|
|
449
|
+
ignoreAttributes: true,
|
|
450
|
+
parseAttributeValue: true,
|
|
451
|
+
parseTagValue: true,
|
|
452
|
+
trimValues: true,
|
|
453
|
+
});
|
|
454
|
+
const parsed = parser.parse(xmlText);
|
|
455
|
+
const result: DescribeNetworkInterfacesResponse = { NetworkInterfaces: [] };
|
|
456
|
+
if (parsed.DescribeNetworkInterfacesResponse) {
|
|
457
|
+
const networkInterfaceSet =
|
|
458
|
+
parsed.DescribeNetworkInterfacesResponse.networkInterfaceSet;
|
|
459
|
+
if (networkInterfaceSet?.item) {
|
|
460
|
+
const items: RawNetworkInterfaceXmlItem[] = Array.isArray(
|
|
461
|
+
networkInterfaceSet.item,
|
|
462
|
+
)
|
|
463
|
+
? networkInterfaceSet.item
|
|
464
|
+
: [networkInterfaceSet.item];
|
|
465
|
+
|
|
466
|
+
result.NetworkInterfaces = items.map(
|
|
467
|
+
(item): AwsNetworkInterface => ({
|
|
468
|
+
NetworkInterfaceId: item.networkInterfaceId,
|
|
469
|
+
Description: item.description,
|
|
470
|
+
Status: item.status as AwsNetworkInterface["Status"],
|
|
471
|
+
}),
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Wait for an Elastic IP to be released.
|
|
480
|
+
*/
|
|
481
|
+
async function waitForEipReleased(
|
|
482
|
+
allocationId: string,
|
|
483
|
+
timeoutConfig: TimeoutConfig,
|
|
484
|
+
): Promise<void> {
|
|
485
|
+
const checkFunction = async () => {
|
|
486
|
+
try {
|
|
487
|
+
const eipClient = await createEC2Client();
|
|
488
|
+
const addressResponse = await callEC2Api<DescribeAddressesResponse>(
|
|
489
|
+
eipClient,
|
|
490
|
+
"DescribeAddresses",
|
|
491
|
+
parseNatGatewayXmlResponse,
|
|
492
|
+
convertDescribeAddressesParamsToAwsFormat({
|
|
493
|
+
AllocationIds: [allocationId],
|
|
494
|
+
}),
|
|
495
|
+
);
|
|
496
|
+
return addressResponse.Addresses?.[0];
|
|
497
|
+
} catch (error: any) {
|
|
498
|
+
if (
|
|
499
|
+
error.code === "InvalidAllocationID.NotFound" ||
|
|
500
|
+
error.code === "InvalidAddress.NotFound"
|
|
501
|
+
) {
|
|
502
|
+
return undefined;
|
|
503
|
+
}
|
|
504
|
+
throw error;
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
const isReady = (address: AwsAddress | undefined) => {
|
|
509
|
+
return !address;
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
await waitForResourceState(
|
|
513
|
+
checkFunction,
|
|
514
|
+
isReady,
|
|
515
|
+
timeoutConfig,
|
|
516
|
+
allocationId,
|
|
517
|
+
"Elastic IP",
|
|
518
|
+
"to be released",
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Wait for NAT Gateway to be fully deleted including network interface cleanup
|
|
524
|
+
*/
|
|
525
|
+
async function waitForNatGatewayFullyDeleted(
|
|
526
|
+
natGatewayId: string,
|
|
527
|
+
timeoutConfig: TimeoutConfig,
|
|
528
|
+
): Promise<void> {
|
|
529
|
+
// First wait for the NAT Gateway itself to be deleted
|
|
530
|
+
await waitForNatGatewayDeleted(natGatewayId, timeoutConfig);
|
|
531
|
+
|
|
532
|
+
// Then wait for network interfaces to be cleaned up
|
|
533
|
+
const checkNetworkInterfaces = async () => {
|
|
534
|
+
try {
|
|
535
|
+
const client = await createEC2Client();
|
|
536
|
+
const response = await callEC2Api<DescribeNetworkInterfacesResponse>(
|
|
537
|
+
client,
|
|
538
|
+
"DescribeNetworkInterfaces",
|
|
539
|
+
parseDescribeNetworkInterfacesResponse,
|
|
540
|
+
{
|
|
541
|
+
"Filter.1.Name": "description",
|
|
542
|
+
"Filter.1.Value.1": `Interface for NAT Gateway ${natGatewayId}`,
|
|
543
|
+
},
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
return response.NetworkInterfaces || [];
|
|
547
|
+
} catch (error: any) {
|
|
548
|
+
// If we can't check network interfaces, assume cleanup is complete
|
|
549
|
+
logger.log(
|
|
550
|
+
` Could not check network interfaces for NAT Gateway ${natGatewayId}, assuming cleanup complete`,
|
|
551
|
+
error,
|
|
552
|
+
);
|
|
553
|
+
return [];
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
const isNetworkInterfacesCleanedUp = (
|
|
558
|
+
networkInterfaces: AwsNetworkInterface[],
|
|
559
|
+
) => {
|
|
560
|
+
if (networkInterfaces.length > 0) {
|
|
561
|
+
logger.log(
|
|
562
|
+
` NAT Gateway ${natGatewayId} still has ${networkInterfaces.length} network interfaces, waiting for cleanup...`,
|
|
563
|
+
);
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
return true;
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
await waitForResourceState(
|
|
570
|
+
checkNetworkInterfaces,
|
|
571
|
+
isNetworkInterfacesCleanedUp,
|
|
572
|
+
timeoutConfig,
|
|
573
|
+
natGatewayId,
|
|
574
|
+
"NAT Gateway network interfaces",
|
|
575
|
+
"cleanup completed",
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Non-retryable error for NAT Gateway operations
|
|
581
|
+
*/
|
|
582
|
+
export class NatGatewayNonRetryableError extends Error {
|
|
583
|
+
constructor(message: string) {
|
|
584
|
+
super(message);
|
|
585
|
+
this.name = "NatGatewayNonRetryableError";
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* NAT Gateway timeout constants
|
|
591
|
+
*/
|
|
592
|
+
export const NAT_GATEWAY_TIMEOUT: TimeoutConfig = {
|
|
593
|
+
maxAttempts: 120, // NAT Gateways are slow resources - can take up to 10 minutes
|
|
594
|
+
delayMs: 5000, // Check every 5 seconds
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* AWS NAT Gateway and related API response types
|
|
599
|
+
*/
|
|
600
|
+
interface AwsNatGatewayAddress {
|
|
601
|
+
AllocationId?: string;
|
|
602
|
+
NetworkInterfaceId?: string;
|
|
603
|
+
PrivateIp?: string;
|
|
604
|
+
PublicIp?: string;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
interface AwsTag {
|
|
608
|
+
Key: string;
|
|
609
|
+
Value: string;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
interface AwsNatGateway {
|
|
613
|
+
NatGatewayId: string;
|
|
614
|
+
SubnetId: string;
|
|
615
|
+
VpcId: string;
|
|
616
|
+
State: "pending" | "failed" | "available" | "deleting" | "deleted";
|
|
617
|
+
ConnectivityType?: "public" | "private";
|
|
618
|
+
NatGatewayAddresses?: AwsNatGatewayAddress[];
|
|
619
|
+
Tags?: AwsTag[];
|
|
620
|
+
CreateTime?: string;
|
|
621
|
+
DeleteTime?: string;
|
|
622
|
+
FailureCode?: string;
|
|
623
|
+
FailureMessage?: string;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
interface AwsAddress {
|
|
627
|
+
AllocationId: string;
|
|
628
|
+
PublicIp: string;
|
|
629
|
+
PrivateIpAddress?: string;
|
|
630
|
+
Domain: string;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
interface AwsNetworkInterface {
|
|
634
|
+
NetworkInterfaceId: string;
|
|
635
|
+
Description?: string;
|
|
636
|
+
Status: "available" | "attaching" | "in-use" | "detaching";
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
interface CreateNatGatewayResponse {
|
|
640
|
+
NatGateway: AwsNatGateway;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
interface DescribeNatGatewaysResponse {
|
|
644
|
+
NatGateways: AwsNatGateway[];
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
interface DescribeAddressesResponse {
|
|
648
|
+
Addresses: AwsAddress[];
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
interface DescribeNetworkInterfacesResponse {
|
|
652
|
+
NetworkInterfaces: AwsNetworkInterface[];
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Raw XML parsing interfaces for type safety
|
|
657
|
+
*/
|
|
658
|
+
interface RawNatGatewayAddressXmlItem {
|
|
659
|
+
allocationId?: string;
|
|
660
|
+
networkInterfaceId?: string;
|
|
661
|
+
privateIp?: string;
|
|
662
|
+
publicIp?: string;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
interface RawTagXmlItem {
|
|
666
|
+
key: string;
|
|
667
|
+
value: string;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
interface RawNatGatewayXmlItem {
|
|
671
|
+
natGatewayId: string;
|
|
672
|
+
subnetId: string;
|
|
673
|
+
vpcId: string;
|
|
674
|
+
state: string;
|
|
675
|
+
connectivityType?: string;
|
|
676
|
+
natGatewayAddressSet?: {
|
|
677
|
+
item?: RawNatGatewayAddressXmlItem | RawNatGatewayAddressXmlItem[];
|
|
678
|
+
};
|
|
679
|
+
tagSet?: {
|
|
680
|
+
item?: RawTagXmlItem | RawTagXmlItem[];
|
|
681
|
+
};
|
|
682
|
+
createTime?: string;
|
|
683
|
+
deleteTime?: string;
|
|
684
|
+
failureCode?: string;
|
|
685
|
+
failureMessage?: string;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
interface RawAddressXmlItem {
|
|
689
|
+
allocationId: string;
|
|
690
|
+
publicIp: string;
|
|
691
|
+
privateIpAddress?: string;
|
|
692
|
+
domain: string;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
interface RawNetworkInterfaceXmlItem {
|
|
696
|
+
networkInterfaceId: string;
|
|
697
|
+
description?: string;
|
|
698
|
+
status: string;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Parse XML responses specifically for NAT Gateway operations
|
|
703
|
+
*/
|
|
704
|
+
function parseNatGatewayXmlResponse<T>(xmlText: string): T {
|
|
705
|
+
const parser = new XMLParser({
|
|
706
|
+
ignoreAttributes: true,
|
|
707
|
+
parseAttributeValue: true,
|
|
708
|
+
parseTagValue: true,
|
|
709
|
+
trimValues: true,
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
const parsed = parser.parse(xmlText);
|
|
713
|
+
const result: Record<string, unknown> = {};
|
|
714
|
+
|
|
715
|
+
// Parse CreateNatGatewayResponse
|
|
716
|
+
if (parsed.CreateNatGatewayResponse) {
|
|
717
|
+
const natGateway = parsed.CreateNatGatewayResponse
|
|
718
|
+
.natGateway as RawNatGatewayXmlItem;
|
|
719
|
+
if (natGateway) {
|
|
720
|
+
const addresses = natGateway.natGatewayAddressSet?.item
|
|
721
|
+
? Array.isArray(natGateway.natGatewayAddressSet.item)
|
|
722
|
+
? natGateway.natGatewayAddressSet.item
|
|
723
|
+
: [natGateway.natGatewayAddressSet.item]
|
|
724
|
+
: [];
|
|
725
|
+
|
|
726
|
+
const tags = natGateway.tagSet?.item
|
|
727
|
+
? Array.isArray(natGateway.tagSet.item)
|
|
728
|
+
? natGateway.tagSet.item
|
|
729
|
+
: [natGateway.tagSet.item]
|
|
730
|
+
: [];
|
|
731
|
+
|
|
732
|
+
result.NatGateway = {
|
|
733
|
+
NatGatewayId: natGateway.natGatewayId,
|
|
734
|
+
SubnetId: natGateway.subnetId,
|
|
735
|
+
VpcId: natGateway.vpcId,
|
|
736
|
+
State: natGateway.state as AwsNatGateway["State"],
|
|
737
|
+
ConnectivityType: natGateway.connectivityType as
|
|
738
|
+
| "public"
|
|
739
|
+
| "private"
|
|
740
|
+
| undefined,
|
|
741
|
+
NatGatewayAddresses: addresses.map(
|
|
742
|
+
(address): AwsNatGatewayAddress => ({
|
|
743
|
+
AllocationId: address.allocationId,
|
|
744
|
+
NetworkInterfaceId: address.networkInterfaceId,
|
|
745
|
+
PrivateIp: address.privateIp,
|
|
746
|
+
PublicIp: address.publicIp,
|
|
747
|
+
}),
|
|
748
|
+
),
|
|
749
|
+
Tags: tags.map(
|
|
750
|
+
(tag): AwsTag => ({
|
|
751
|
+
Key: tag.key,
|
|
752
|
+
Value: tag.value,
|
|
753
|
+
}),
|
|
754
|
+
),
|
|
755
|
+
CreateTime: natGateway.createTime,
|
|
756
|
+
DeleteTime: natGateway.deleteTime,
|
|
757
|
+
FailureCode: natGateway.failureCode,
|
|
758
|
+
FailureMessage: natGateway.failureMessage,
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Parse DescribeNatGatewaysResponse
|
|
764
|
+
if (parsed.DescribeNatGatewaysResponse) {
|
|
765
|
+
const natGatewaySet = parsed.DescribeNatGatewaysResponse.natGatewaySet;
|
|
766
|
+
if (natGatewaySet?.item) {
|
|
767
|
+
const natGateways: RawNatGatewayXmlItem[] = Array.isArray(
|
|
768
|
+
natGatewaySet.item,
|
|
769
|
+
)
|
|
770
|
+
? natGatewaySet.item
|
|
771
|
+
: [natGatewaySet.item];
|
|
772
|
+
result.NatGateways = natGateways.map((natGateway): AwsNatGateway => {
|
|
773
|
+
const addresses = natGateway.natGatewayAddressSet?.item
|
|
774
|
+
? Array.isArray(natGateway.natGatewayAddressSet.item)
|
|
775
|
+
? natGateway.natGatewayAddressSet.item
|
|
776
|
+
: [natGateway.natGatewayAddressSet.item]
|
|
777
|
+
: [];
|
|
778
|
+
|
|
779
|
+
const tags = natGateway.tagSet?.item
|
|
780
|
+
? Array.isArray(natGateway.tagSet.item)
|
|
781
|
+
? natGateway.tagSet.item
|
|
782
|
+
: [natGateway.tagSet.item]
|
|
783
|
+
: [];
|
|
784
|
+
|
|
785
|
+
return {
|
|
786
|
+
NatGatewayId: natGateway.natGatewayId,
|
|
787
|
+
SubnetId: natGateway.subnetId,
|
|
788
|
+
VpcId: natGateway.vpcId,
|
|
789
|
+
State: natGateway.state as AwsNatGateway["State"],
|
|
790
|
+
ConnectivityType: natGateway.connectivityType as
|
|
791
|
+
| "public"
|
|
792
|
+
| "private"
|
|
793
|
+
| undefined,
|
|
794
|
+
NatGatewayAddresses: addresses.map(
|
|
795
|
+
(address): AwsNatGatewayAddress => ({
|
|
796
|
+
AllocationId: address.allocationId,
|
|
797
|
+
NetworkInterfaceId: address.networkInterfaceId,
|
|
798
|
+
PrivateIp: address.privateIp,
|
|
799
|
+
PublicIp: address.publicIp,
|
|
800
|
+
}),
|
|
801
|
+
),
|
|
802
|
+
Tags: tags.map(
|
|
803
|
+
(tag): AwsTag => ({
|
|
804
|
+
Key: tag.key,
|
|
805
|
+
Value: tag.value,
|
|
806
|
+
}),
|
|
807
|
+
),
|
|
808
|
+
CreateTime: natGateway.createTime,
|
|
809
|
+
DeleteTime: natGateway.deleteTime,
|
|
810
|
+
FailureCode: natGateway.failureCode,
|
|
811
|
+
FailureMessage: natGateway.failureMessage,
|
|
812
|
+
};
|
|
813
|
+
});
|
|
814
|
+
} else {
|
|
815
|
+
result.NatGateways = [];
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// Parse AllocateAddressResponse (for EIP allocation)
|
|
820
|
+
if (parsed.AllocateAddressResponse) {
|
|
821
|
+
result.AllocationId = parsed.AllocateAddressResponse.allocationId;
|
|
822
|
+
result.PublicIp = parsed.AllocateAddressResponse.publicIp;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Parse DescribeAddressesResponse (for EIP lookup)
|
|
826
|
+
if (parsed.DescribeAddressesResponse) {
|
|
827
|
+
const addressesSet = parsed.DescribeAddressesResponse.addressesSet;
|
|
828
|
+
if (addressesSet?.item) {
|
|
829
|
+
const addresses: RawAddressXmlItem[] = Array.isArray(addressesSet.item)
|
|
830
|
+
? addressesSet.item
|
|
831
|
+
: [addressesSet.item];
|
|
832
|
+
result.Addresses = addresses.map(
|
|
833
|
+
(address): AwsAddress => ({
|
|
834
|
+
AllocationId: address.allocationId,
|
|
835
|
+
PublicIp: address.publicIp,
|
|
836
|
+
PrivateIpAddress: address.privateIpAddress,
|
|
837
|
+
Domain: address.domain,
|
|
838
|
+
}),
|
|
839
|
+
);
|
|
840
|
+
} else {
|
|
841
|
+
result.Addresses = [];
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Handle success responses
|
|
846
|
+
if (parsed.DeleteNatGatewayResponse || parsed.ReleaseAddressResponse) {
|
|
847
|
+
result.success = true;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
return result as T;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
interface AllocateAddressResponse {
|
|
854
|
+
AllocationId: string;
|
|
855
|
+
PublicIp: string;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Comprehensive AWS NAT Gateway API Parameter Types
|
|
860
|
+
*/
|
|
861
|
+
|
|
862
|
+
// Common structures
|
|
863
|
+
interface TagSpecification {
|
|
864
|
+
ResourceType: string;
|
|
865
|
+
Tags: Array<{
|
|
866
|
+
Key: string;
|
|
867
|
+
Value: string;
|
|
868
|
+
}>;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
interface Filter {
|
|
872
|
+
Name: string;
|
|
873
|
+
Values: string[];
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// NAT Gateway API Request Parameters
|
|
877
|
+
interface CreateNatGatewayParams {
|
|
878
|
+
SubnetId: string;
|
|
879
|
+
AllocationId?: string;
|
|
880
|
+
ConnectivityType?: "public" | "private";
|
|
881
|
+
TagSpecifications?: TagSpecification[];
|
|
882
|
+
DryRun?: boolean;
|
|
883
|
+
ClientToken?: string;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
interface DescribeNatGatewaysParams {
|
|
887
|
+
NatGatewayIds?: string[];
|
|
888
|
+
Filters?: Filter[];
|
|
889
|
+
NextToken?: string;
|
|
890
|
+
MaxResults?: number;
|
|
891
|
+
DryRun?: boolean;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
interface DeleteNatGatewayParams {
|
|
895
|
+
NatGatewayId: string;
|
|
896
|
+
DryRun?: boolean;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Elastic IP API Request Parameters
|
|
900
|
+
interface AllocateAddressParams {
|
|
901
|
+
Domain?: "vpc" | "standard";
|
|
902
|
+
Address?: string;
|
|
903
|
+
PublicIpv4Pool?: string;
|
|
904
|
+
NetworkBorderGroup?: string;
|
|
905
|
+
CustomerOwnedIpv4Pool?: string;
|
|
906
|
+
TagSpecifications?: TagSpecification[];
|
|
907
|
+
DryRun?: boolean;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
interface DescribeAddressesParams {
|
|
911
|
+
AllocationIds?: string[];
|
|
912
|
+
PublicIps?: string[];
|
|
913
|
+
Filters?: Filter[];
|
|
914
|
+
DryRun?: boolean;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
interface ReleaseAddressParams {
|
|
918
|
+
AllocationId?: string;
|
|
919
|
+
PublicIp?: string;
|
|
920
|
+
NetworkBorderGroup?: string;
|
|
921
|
+
DryRun?: boolean;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* Helper functions to convert typed parameters to AWS API format
|
|
926
|
+
*/
|
|
927
|
+
function convertCreateNatGatewayParamsToAwsFormat(
|
|
928
|
+
params: CreateNatGatewayParams,
|
|
929
|
+
): Record<string, string> {
|
|
930
|
+
const awsParams: Record<string, string> = {
|
|
931
|
+
SubnetId: params.SubnetId,
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
if (params.AllocationId !== undefined) {
|
|
935
|
+
awsParams.AllocationId = params.AllocationId;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
if (params.ConnectivityType !== undefined) {
|
|
939
|
+
awsParams.ConnectivityType = params.ConnectivityType;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (params.DryRun !== undefined) {
|
|
943
|
+
awsParams.DryRun = params.DryRun.toString();
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
if (params.ClientToken !== undefined) {
|
|
947
|
+
awsParams.ClientToken = params.ClientToken;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// Handle TagSpecifications
|
|
951
|
+
if (params.TagSpecifications) {
|
|
952
|
+
params.TagSpecifications.forEach((tagSpec, specIndex) => {
|
|
953
|
+
const specNum = specIndex + 1;
|
|
954
|
+
awsParams[`TagSpecification.${specNum}.ResourceType`] =
|
|
955
|
+
tagSpec.ResourceType;
|
|
956
|
+
|
|
957
|
+
tagSpec.Tags.forEach((tag, tagIndex) => {
|
|
958
|
+
const tagNum = tagIndex + 1;
|
|
959
|
+
awsParams[`TagSpecification.${specNum}.Tag.${tagNum}.Key`] = tag.Key;
|
|
960
|
+
awsParams[`TagSpecification.${specNum}.Tag.${tagNum}.Value`] =
|
|
961
|
+
tag.Value;
|
|
962
|
+
});
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
return awsParams;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function convertDescribeNatGatewaysParamsToAwsFormat(
|
|
970
|
+
params: DescribeNatGatewaysParams,
|
|
971
|
+
): Record<string, string> {
|
|
972
|
+
const awsParams: Record<string, string> = {};
|
|
973
|
+
|
|
974
|
+
if (params.NatGatewayIds) {
|
|
975
|
+
params.NatGatewayIds.forEach((id, index) => {
|
|
976
|
+
awsParams[`NatGatewayId.${index + 1}`] = id;
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if (params.Filters) {
|
|
981
|
+
params.Filters.forEach((filter, filterIndex) => {
|
|
982
|
+
const filterNum = filterIndex + 1;
|
|
983
|
+
awsParams[`Filter.${filterNum}.Name`] = filter.Name;
|
|
984
|
+
filter.Values.forEach((value, valueIndex) => {
|
|
985
|
+
awsParams[`Filter.${filterNum}.Value.${valueIndex + 1}`] = value;
|
|
986
|
+
});
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
if (params.NextToken !== undefined) {
|
|
991
|
+
awsParams.NextToken = params.NextToken;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (params.MaxResults !== undefined) {
|
|
995
|
+
awsParams.MaxResults = params.MaxResults.toString();
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
if (params.DryRun !== undefined) {
|
|
999
|
+
awsParams.DryRun = params.DryRun.toString();
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
return awsParams;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
function convertDeleteNatGatewayParamsToAwsFormat(
|
|
1006
|
+
params: DeleteNatGatewayParams,
|
|
1007
|
+
): Record<string, string> {
|
|
1008
|
+
const awsParams: Record<string, string> = {
|
|
1009
|
+
NatGatewayId: params.NatGatewayId,
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
if (params.DryRun !== undefined) {
|
|
1013
|
+
awsParams.DryRun = params.DryRun.toString();
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
return awsParams;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
function convertAllocateAddressParamsToAwsFormat(
|
|
1020
|
+
params: AllocateAddressParams,
|
|
1021
|
+
): Record<string, string> {
|
|
1022
|
+
const awsParams: Record<string, string> = {};
|
|
1023
|
+
|
|
1024
|
+
if (params.Domain !== undefined) {
|
|
1025
|
+
awsParams.Domain = params.Domain;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
if (params.Address !== undefined) {
|
|
1029
|
+
awsParams.Address = params.Address;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
if (params.PublicIpv4Pool !== undefined) {
|
|
1033
|
+
awsParams.PublicIpv4Pool = params.PublicIpv4Pool;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
if (params.NetworkBorderGroup !== undefined) {
|
|
1037
|
+
awsParams.NetworkBorderGroup = params.NetworkBorderGroup;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
if (params.CustomerOwnedIpv4Pool !== undefined) {
|
|
1041
|
+
awsParams.CustomerOwnedIpv4Pool = params.CustomerOwnedIpv4Pool;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
if (params.DryRun !== undefined) {
|
|
1045
|
+
awsParams.DryRun = params.DryRun.toString();
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// Handle TagSpecifications
|
|
1049
|
+
if (params.TagSpecifications) {
|
|
1050
|
+
params.TagSpecifications.forEach((tagSpec, specIndex) => {
|
|
1051
|
+
const specNum = specIndex + 1;
|
|
1052
|
+
awsParams[`TagSpecification.${specNum}.ResourceType`] =
|
|
1053
|
+
tagSpec.ResourceType;
|
|
1054
|
+
|
|
1055
|
+
tagSpec.Tags.forEach((tag, tagIndex) => {
|
|
1056
|
+
const tagNum = tagIndex + 1;
|
|
1057
|
+
awsParams[`TagSpecification.${specNum}.Tag.${tagNum}.Key`] = tag.Key;
|
|
1058
|
+
awsParams[`TagSpecification.${specNum}.Tag.${tagNum}.Value`] =
|
|
1059
|
+
tag.Value;
|
|
1060
|
+
});
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
return awsParams;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
function convertDescribeAddressesParamsToAwsFormat(
|
|
1068
|
+
params: DescribeAddressesParams,
|
|
1069
|
+
): Record<string, string> {
|
|
1070
|
+
const awsParams: Record<string, string> = {};
|
|
1071
|
+
|
|
1072
|
+
if (params.AllocationIds) {
|
|
1073
|
+
params.AllocationIds.forEach((id, index) => {
|
|
1074
|
+
awsParams[`AllocationId.${index + 1}`] = id;
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
if (params.PublicIps) {
|
|
1079
|
+
params.PublicIps.forEach((ip, index) => {
|
|
1080
|
+
awsParams[`PublicIp.${index + 1}`] = ip;
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
if (params.Filters) {
|
|
1085
|
+
params.Filters.forEach((filter, filterIndex) => {
|
|
1086
|
+
const filterNum = filterIndex + 1;
|
|
1087
|
+
awsParams[`Filter.${filterNum}.Name`] = filter.Name;
|
|
1088
|
+
filter.Values.forEach((value, valueIndex) => {
|
|
1089
|
+
awsParams[`Filter.${filterNum}.Value.${valueIndex + 1}`] = value;
|
|
1090
|
+
});
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
if (params.DryRun !== undefined) {
|
|
1095
|
+
awsParams.DryRun = params.DryRun.toString();
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
return awsParams;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
function convertReleaseAddressParamsToAwsFormat(
|
|
1102
|
+
params: ReleaseAddressParams,
|
|
1103
|
+
): Record<string, string> {
|
|
1104
|
+
const awsParams: Record<string, string> = {};
|
|
1105
|
+
|
|
1106
|
+
if (params.AllocationId !== undefined) {
|
|
1107
|
+
awsParams.AllocationId = params.AllocationId;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
if (params.PublicIp !== undefined) {
|
|
1111
|
+
awsParams.PublicIp = params.PublicIp;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
if (params.NetworkBorderGroup !== undefined) {
|
|
1115
|
+
awsParams.NetworkBorderGroup = params.NetworkBorderGroup;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
if (params.DryRun !== undefined) {
|
|
1119
|
+
awsParams.DryRun = params.DryRun.toString();
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
return awsParams;
|
|
1123
|
+
}
|