alchemy 0.61.0 → 0.62.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 +1 -2
- package/bin/alchemy.js +1406 -1464
- package/bin/commands/init.ts +29 -2
- package/bin/services/execute-alchemy.ts +1 -2
- package/lib/alchemy.d.ts +2 -2
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js.map +1 -1
- package/lib/aws/client-props.d.ts +149 -0
- package/lib/aws/client-props.d.ts.map +1 -0
- package/lib/aws/client-props.js +1 -0
- package/lib/aws/client-props.js.map +1 -0
- package/lib/aws/credentials.d.ts +68 -5
- package/lib/aws/credentials.d.ts.map +1 -1
- package/lib/aws/credentials.js +148 -0
- package/lib/aws/credentials.js.map +1 -1
- package/lib/aws/ec2/internet-gateway-attachment.d.ts +57 -3
- package/lib/aws/ec2/internet-gateway-attachment.d.ts.map +1 -1
- package/lib/aws/ec2/internet-gateway-attachment.js +57 -3
- package/lib/aws/ec2/internet-gateway-attachment.js.map +1 -1
- package/lib/aws/ec2/internet-gateway.d.ts +68 -40
- package/lib/aws/ec2/internet-gateway.d.ts.map +1 -1
- package/lib/aws/ec2/internet-gateway.js +68 -40
- package/lib/aws/ec2/internet-gateway.js.map +1 -1
- package/lib/aws/ec2/nat-gateway.d.ts +99 -18
- package/lib/aws/ec2/nat-gateway.d.ts.map +1 -1
- package/lib/aws/ec2/nat-gateway.js +113 -37
- package/lib/aws/ec2/nat-gateway.js.map +1 -1
- package/lib/aws/ec2/route-table-association.d.ts +1 -1
- package/lib/aws/ec2/route-table-association.js +1 -1
- package/lib/aws/ec2/route-table.d.ts +64 -1
- package/lib/aws/ec2/route-table.d.ts.map +1 -1
- package/lib/aws/ec2/route-table.js +64 -1
- package/lib/aws/ec2/route-table.js.map +1 -1
- package/lib/aws/ec2/route.d.ts +60 -1
- package/lib/aws/ec2/route.d.ts.map +1 -1
- package/lib/aws/ec2/route.js +60 -1
- package/lib/aws/ec2/route.js.map +1 -1
- package/lib/aws/ec2/security-group.d.ts +96 -3
- package/lib/aws/ec2/security-group.d.ts.map +1 -1
- package/lib/aws/ec2/security-group.js +96 -3
- package/lib/aws/ec2/security-group.js.map +1 -1
- package/lib/aws/ec2/subnet.d.ts +61 -3
- package/lib/aws/ec2/subnet.d.ts.map +1 -1
- package/lib/aws/ec2/subnet.js +61 -3
- package/lib/aws/ec2/subnet.js.map +1 -1
- package/lib/aws/ec2/utils.d.ts +10 -2
- package/lib/aws/ec2/utils.d.ts.map +1 -1
- package/lib/aws/ec2/utils.js +68 -7
- package/lib/aws/ec2/utils.js.map +1 -1
- package/lib/aws/ec2/vpc.d.ts +50 -2
- package/lib/aws/ec2/vpc.d.ts.map +1 -1
- package/lib/aws/ec2/vpc.js +50 -2
- package/lib/aws/ec2/vpc.js.map +1 -1
- package/lib/aws/index.d.ts +2 -0
- package/lib/aws/index.d.ts.map +1 -1
- package/lib/aws/index.js +2 -0
- package/lib/aws/index.js.map +1 -1
- package/lib/cloudflare/api-response.js +2 -2
- package/lib/cloudflare/api-response.js.map +1 -1
- package/lib/cloudflare/api.d.ts +19 -0
- package/lib/cloudflare/api.d.ts.map +1 -1
- package/lib/cloudflare/api.js +4 -0
- package/lib/cloudflare/api.js.map +1 -1
- package/lib/cloudflare/assets.d.ts.map +1 -1
- package/lib/cloudflare/assets.js +3 -4
- package/lib/cloudflare/assets.js.map +1 -1
- package/lib/cloudflare/bucket.d.ts +5 -3
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +22 -18
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/bundle/plugin-compat-warning.js +7 -7
- package/lib/cloudflare/bundle/plugin-compat-warning.js.map +1 -1
- package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -1
- package/lib/cloudflare/kv-namespace.d.ts +2 -2
- package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
- package/lib/cloudflare/kv-namespace.js.map +1 -1
- package/lib/cloudflare/oauth.js +3 -3
- package/lib/cloudflare/oauth.js.map +1 -1
- package/lib/cloudflare/quick-tunnel.d.ts +1 -1
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +26 -97
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
- package/lib/cloudflare/worker-bundle.js +9 -8
- package/lib/cloudflare/worker-bundle.js.map +1 -1
- package/lib/cloudflare/worker-tail.d.ts.map +1 -1
- package/lib/cloudflare/worker-tail.js +6 -6
- package/lib/cloudflare/worker-tail.js.map +1 -1
- package/lib/resource.d.ts +1 -0
- package/lib/resource.d.ts.map +1 -1
- package/lib/resource.js +13 -2
- package/lib/resource.js.map +1 -1
- package/lib/scope.d.ts +24 -23
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +25 -20
- package/lib/scope.js.map +1 -1
- package/lib/state/cloudflare-state-store.d.ts.map +1 -1
- package/lib/state/cloudflare-state-store.js +2 -1
- package/lib/state/cloudflare-state-store.js.map +1 -1
- package/lib/util/idempotent-spawn.d.ts +10 -8
- package/lib/util/idempotent-spawn.d.ts.map +1 -1
- package/lib/util/idempotent-spawn.js +97 -78
- package/lib/util/idempotent-spawn.js.map +1 -1
- package/lib/util/index.d.ts +2 -0
- package/lib/util/index.d.ts.map +1 -0
- package/lib/util/index.js +2 -0
- package/lib/util/index.js.map +1 -0
- package/lib/util/safe-fetch.d.ts +24 -0
- package/lib/util/safe-fetch.d.ts.map +1 -1
- package/lib/util/safe-fetch.js +72 -0
- package/lib/util/safe-fetch.js.map +1 -1
- package/package.json +8 -5
- package/src/alchemy.ts +2 -2
- package/src/aws/client-props.ts +156 -0
- package/src/aws/credentials.ts +165 -4
- package/src/aws/ec2/internet-gateway-attachment.ts +59 -4
- package/src/aws/ec2/internet-gateway.ts +70 -41
- package/src/aws/ec2/nat-gateway.ts +123 -33
- package/src/aws/ec2/route-table-association.ts +1 -1
- package/src/aws/ec2/route-table.ts +66 -2
- package/src/aws/ec2/route.ts +62 -2
- package/src/aws/ec2/security-group.ts +98 -4
- package/src/aws/ec2/subnet.ts +63 -4
- package/src/aws/ec2/utils.ts +73 -7
- package/src/aws/ec2/vpc.ts +52 -3
- package/src/aws/index.ts +2 -0
- package/src/cloudflare/api-response.ts +2 -2
- package/src/cloudflare/api.ts +23 -0
- package/src/cloudflare/assets.ts +3 -4
- package/src/cloudflare/bucket.ts +27 -25
- package/src/cloudflare/bundle/plugin-compat-warning.ts +7 -7
- package/src/cloudflare/cloudflare-env-proxy.ts +2 -2
- package/src/cloudflare/kv-namespace.ts +26 -27
- package/src/cloudflare/oauth.ts +3 -3
- package/src/cloudflare/website.ts +30 -111
- package/src/cloudflare/worker-bundle.ts +9 -8
- package/src/cloudflare/worker-tail.ts +6 -8
- package/src/resource.ts +19 -2
- package/src/scope.ts +73 -43
- package/src/state/cloudflare-state-store.ts +2 -1
- package/src/util/idempotent-spawn.ts +117 -100
- package/src/util/index.ts +1 -0
- package/src/util/safe-fetch.ts +114 -0
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
type TimeoutConfig,
|
|
9
9
|
waitForResourceState,
|
|
10
10
|
} from "../../util/timeout.ts";
|
|
11
|
+
import type { AwsClientProps } from "../client-props.ts";
|
|
11
12
|
import type { Subnet } from "./subnet.ts";
|
|
12
13
|
import { callEC2Api, createEC2Client } from "./utils.ts";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Properties for creating or updating a NAT Gateway
|
|
16
17
|
*/
|
|
17
|
-
export interface NatGatewayProps {
|
|
18
|
+
export interface NatGatewayProps extends AwsClientProps {
|
|
18
19
|
/**
|
|
19
20
|
* The subnet to create the NAT Gateway in (must be a public subnet)
|
|
20
21
|
*/
|
|
@@ -99,39 +100,94 @@ export interface NatGateway
|
|
|
99
100
|
* if one is not provided. NAT Gateways are slow resources that can take
|
|
100
101
|
* up to 10 minutes to become available.
|
|
101
102
|
*
|
|
103
|
+
* Supports AWS credential overrides at the resource level, allowing you to deploy NAT Gateways
|
|
104
|
+
* to different AWS accounts or regions than the default scope configuration.
|
|
105
|
+
*
|
|
102
106
|
* @example
|
|
107
|
+
* ```typescript
|
|
103
108
|
* // Create a NAT Gateway with automatic Elastic IP allocation
|
|
104
109
|
* const natGateway = await NatGateway("main-nat", {
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
+
* subnet: publicSubnet,
|
|
111
|
+
* tags: {
|
|
112
|
+
* Name: "main-nat-gateway",
|
|
113
|
+
* Environment: "production"
|
|
114
|
+
* }
|
|
115
|
+
* });
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* // Create NAT Gateway with AWS credential overrides
|
|
121
|
+
* const crossAccountNat = await NatGateway("cross-account-nat", {
|
|
122
|
+
* subnet: publicSubnet,
|
|
123
|
+
* // Override AWS credentials for this specific resource
|
|
124
|
+
* region: "us-east-1",
|
|
125
|
+
* profile: "production-account",
|
|
126
|
+
* tags: {
|
|
127
|
+
* Name: "cross-account-nat-gateway",
|
|
128
|
+
* Environment: "production"
|
|
129
|
+
* }
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* // Create NAT Gateway in different region with role assumption
|
|
136
|
+
* const multiRegionNat = await NatGateway("multi-region-nat", {
|
|
137
|
+
* subnet: euPublicSubnet,
|
|
138
|
+
* region: "eu-west-1",
|
|
139
|
+
* roleArn: "arn:aws:iam::123456789012:role/CrossRegionRole",
|
|
140
|
+
* roleSessionName: "nat-gateway-deployment",
|
|
141
|
+
* tags: {
|
|
142
|
+
* Name: "eu-nat-gateway",
|
|
143
|
+
* Region: "europe"
|
|
144
|
+
* }
|
|
110
145
|
* });
|
|
146
|
+
* ```
|
|
111
147
|
*
|
|
112
148
|
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* // Create NAT Gateway with explicit credentials
|
|
151
|
+
* const explicitCredsNat = await NatGateway("explicit-creds-nat", {
|
|
152
|
+
* subnet: testPublicSubnet,
|
|
153
|
+
* accessKeyId: alchemy.secret("AKIAIOSFODNN7EXAMPLE"),
|
|
154
|
+
* secretAccessKey: alchemy.secret("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"),
|
|
155
|
+
* region: "us-west-2",
|
|
156
|
+
* tags: {
|
|
157
|
+
* Name: "explicit-credentials-nat",
|
|
158
|
+
* Purpose: "testing"
|
|
159
|
+
* }
|
|
160
|
+
* });
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
113
165
|
* // Create a NAT Gateway with existing Elastic IP
|
|
114
166
|
* const natGateway = await NatGateway("custom-nat", {
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
167
|
+
* subnet: "subnet-12345678",
|
|
168
|
+
* allocationId: "eipalloc-12345678",
|
|
169
|
+
* connectivityType: "public",
|
|
170
|
+
* tags: {
|
|
171
|
+
* Name: "custom-nat-gateway"
|
|
172
|
+
* }
|
|
121
173
|
* });
|
|
174
|
+
* ```
|
|
122
175
|
*
|
|
123
176
|
* @example
|
|
177
|
+
* ```typescript
|
|
124
178
|
* // Create a private NAT Gateway (for VPC-to-VPC communication)
|
|
125
179
|
* const privateNat = await NatGateway("private-nat", {
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
180
|
+
* subnet: privateSubnet,
|
|
181
|
+
* connectivityType: "private",
|
|
182
|
+
* tags: {
|
|
183
|
+
* Name: "private-nat-gateway",
|
|
184
|
+
* Type: "internal"
|
|
185
|
+
* }
|
|
132
186
|
* });
|
|
187
|
+
* ```
|
|
133
188
|
*
|
|
134
189
|
* @example
|
|
190
|
+
* ```typescript
|
|
135
191
|
* // Create a NAT Gateway with custom timeout configuration
|
|
136
192
|
* const slowNat = await NatGateway("slow-nat", {
|
|
137
193
|
* subnet: publicSubnet,
|
|
@@ -143,8 +199,32 @@ export interface NatGateway
|
|
|
143
199
|
* Name: "slow-nat-gateway"
|
|
144
200
|
* }
|
|
145
201
|
* });
|
|
202
|
+
* ```
|
|
146
203
|
*
|
|
147
204
|
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* // Multi-account deployment with scope-level and resource-level overrides
|
|
207
|
+
* await alchemy.run("production", {
|
|
208
|
+
* aws: { region: "us-west-2", profile: "main-account" }
|
|
209
|
+
* }, async () => {
|
|
210
|
+
* // This NAT Gateway uses scope credentials (main-account, us-west-2)
|
|
211
|
+
* const mainNat = await NatGateway("main-nat", {
|
|
212
|
+
* subnet: mainPublicSubnet,
|
|
213
|
+
* tags: { Name: "main-account-nat" }
|
|
214
|
+
* });
|
|
215
|
+
*
|
|
216
|
+
* // This NAT Gateway overrides to use different account
|
|
217
|
+
* const crossAccountNat = await NatGateway("cross-account-nat", {
|
|
218
|
+
* subnet: crossPublicSubnet,
|
|
219
|
+
* profile: "secondary-account",
|
|
220
|
+
* region: "us-east-1", // Also override region
|
|
221
|
+
* tags: { Name: "secondary-account-nat" }
|
|
222
|
+
* });
|
|
223
|
+
* });
|
|
224
|
+
* ```
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
148
228
|
* // Use NAT Gateway in route table for private subnet internet access
|
|
149
229
|
* const privateRoute = await Route("private-internet", {
|
|
150
230
|
* routeTable: privateRouteTable,
|
|
@@ -154,6 +234,7 @@ export interface NatGateway
|
|
|
154
234
|
* Name: "private-to-internet"
|
|
155
235
|
* }
|
|
156
236
|
* });
|
|
237
|
+
* ```
|
|
157
238
|
*/
|
|
158
239
|
export const NatGateway = Resource(
|
|
159
240
|
"aws::NatGateway",
|
|
@@ -162,6 +243,8 @@ export const NatGateway = Resource(
|
|
|
162
243
|
_id: string,
|
|
163
244
|
props: NatGatewayProps,
|
|
164
245
|
): Promise<NatGateway> {
|
|
246
|
+
// Create EC2 client with credential resolution handled internally
|
|
247
|
+
const client = await createEC2Client(props);
|
|
165
248
|
const subnetId =
|
|
166
249
|
typeof props.subnet === "string" ? props.subnet : props.subnet.subnetId;
|
|
167
250
|
const timeoutConfig = mergeTimeoutConfig(
|
|
@@ -174,7 +257,6 @@ export const NatGateway = Resource(
|
|
|
174
257
|
logger.log(`🗑️ Deleting NAT Gateway: ${this.output.natGatewayId}`);
|
|
175
258
|
// Delete NAT Gateway if it exists
|
|
176
259
|
await ignore("InvalidNatGatewayID.NotFound", async () => {
|
|
177
|
-
const client = await createEC2Client();
|
|
178
260
|
await callEC2Api(
|
|
179
261
|
client,
|
|
180
262
|
"DeleteNatGateway",
|
|
@@ -192,6 +274,7 @@ export const NatGateway = Resource(
|
|
|
192
274
|
await waitForNatGatewayFullyDeleted(
|
|
193
275
|
this.output.natGatewayId,
|
|
194
276
|
timeoutConfig,
|
|
277
|
+
props,
|
|
195
278
|
);
|
|
196
279
|
|
|
197
280
|
logger.log(
|
|
@@ -204,9 +287,8 @@ export const NatGateway = Resource(
|
|
|
204
287
|
await ignore(
|
|
205
288
|
["InvalidAllocationID.NotFound", "InvalidAddress.NotFound"],
|
|
206
289
|
async () => {
|
|
207
|
-
const eipClient = await createEC2Client();
|
|
208
290
|
await callEC2Api(
|
|
209
|
-
|
|
291
|
+
client,
|
|
210
292
|
"ReleaseAddress",
|
|
211
293
|
parseNatGatewayXmlResponse,
|
|
212
294
|
convertReleaseAddressParamsToAwsFormat({
|
|
@@ -216,7 +298,11 @@ export const NatGateway = Resource(
|
|
|
216
298
|
},
|
|
217
299
|
);
|
|
218
300
|
// Wait for the EIP to be fully released
|
|
219
|
-
await waitForEipReleased(
|
|
301
|
+
await waitForEipReleased(
|
|
302
|
+
this.output.allocationId,
|
|
303
|
+
timeoutConfig,
|
|
304
|
+
props,
|
|
305
|
+
);
|
|
220
306
|
logger.log(
|
|
221
307
|
` ✅ Elastic IP ${this.output.allocationId} released successfully`,
|
|
222
308
|
);
|
|
@@ -232,7 +318,6 @@ export const NatGateway = Resource(
|
|
|
232
318
|
|
|
233
319
|
if (this.phase === "update" && this.output?.natGatewayId) {
|
|
234
320
|
// Get existing NAT Gateway
|
|
235
|
-
const client = await createEC2Client();
|
|
236
321
|
const response = await callEC2Api<DescribeNatGatewaysResponse>(
|
|
237
322
|
client,
|
|
238
323
|
"DescribeNatGateways",
|
|
@@ -270,7 +355,6 @@ export const NatGateway = Resource(
|
|
|
270
355
|
];
|
|
271
356
|
}
|
|
272
357
|
|
|
273
|
-
const client = await createEC2Client();
|
|
274
358
|
const eipResponse = await callEC2Api<AllocateAddressResponse>(
|
|
275
359
|
client,
|
|
276
360
|
"AllocateAddress",
|
|
@@ -287,7 +371,6 @@ export const NatGateway = Resource(
|
|
|
287
371
|
createdElasticIp = true;
|
|
288
372
|
} else {
|
|
289
373
|
// Get public IP of existing allocation
|
|
290
|
-
const client = await createEC2Client();
|
|
291
374
|
const addressResponse = await callEC2Api<DescribeAddressesResponse>(
|
|
292
375
|
client,
|
|
293
376
|
"DescribeAddresses",
|
|
@@ -319,9 +402,8 @@ export const NatGateway = Resource(
|
|
|
319
402
|
];
|
|
320
403
|
}
|
|
321
404
|
|
|
322
|
-
const natClient = await createEC2Client();
|
|
323
405
|
const response = await callEC2Api<CreateNatGatewayResponse>(
|
|
324
|
-
|
|
406
|
+
client,
|
|
325
407
|
"CreateNatGateway",
|
|
326
408
|
parseNatGatewayXmlResponse,
|
|
327
409
|
convertCreateNatGatewayParamsToAwsFormat(createParams),
|
|
@@ -334,7 +416,11 @@ export const NatGateway = Resource(
|
|
|
334
416
|
natGateway = response.NatGateway;
|
|
335
417
|
|
|
336
418
|
// Wait for NAT Gateway to be available
|
|
337
|
-
await waitForNatGatewayAvailable(
|
|
419
|
+
await waitForNatGatewayAvailable(
|
|
420
|
+
natGateway.NatGatewayId!,
|
|
421
|
+
timeoutConfig,
|
|
422
|
+
props,
|
|
423
|
+
);
|
|
338
424
|
}
|
|
339
425
|
|
|
340
426
|
const result = this({
|
|
@@ -359,9 +445,10 @@ export const NatGateway = Resource(
|
|
|
359
445
|
async function waitForNatGatewayAvailable(
|
|
360
446
|
natGatewayId: string,
|
|
361
447
|
timeoutConfig: TimeoutConfig,
|
|
448
|
+
credentials?: AwsClientProps,
|
|
362
449
|
): Promise<void> {
|
|
363
450
|
const checkFunction = async () => {
|
|
364
|
-
const client = await createEC2Client();
|
|
451
|
+
const client = await createEC2Client(credentials);
|
|
365
452
|
const response = await callEC2Api<DescribeNatGatewaysResponse>(
|
|
366
453
|
client,
|
|
367
454
|
"DescribeNatGateways",
|
|
@@ -398,10 +485,11 @@ async function waitForNatGatewayAvailable(
|
|
|
398
485
|
async function waitForNatGatewayDeleted(
|
|
399
486
|
natGatewayId: string,
|
|
400
487
|
timeoutConfig: TimeoutConfig,
|
|
488
|
+
credentials?: AwsClientProps,
|
|
401
489
|
): Promise<void> {
|
|
402
490
|
const checkFunction = async () => {
|
|
403
491
|
try {
|
|
404
|
-
const client = await createEC2Client();
|
|
492
|
+
const client = await createEC2Client(credentials);
|
|
405
493
|
const response = await callEC2Api<DescribeNatGatewaysResponse>(
|
|
406
494
|
client,
|
|
407
495
|
"DescribeNatGateways",
|
|
@@ -481,10 +569,11 @@ function parseDescribeNetworkInterfacesResponse(
|
|
|
481
569
|
async function waitForEipReleased(
|
|
482
570
|
allocationId: string,
|
|
483
571
|
timeoutConfig: TimeoutConfig,
|
|
572
|
+
credentials?: AwsClientProps,
|
|
484
573
|
): Promise<void> {
|
|
485
574
|
const checkFunction = async () => {
|
|
486
575
|
try {
|
|
487
|
-
const eipClient = await createEC2Client();
|
|
576
|
+
const eipClient = await createEC2Client(credentials);
|
|
488
577
|
const addressResponse = await callEC2Api<DescribeAddressesResponse>(
|
|
489
578
|
eipClient,
|
|
490
579
|
"DescribeAddresses",
|
|
@@ -525,14 +614,15 @@ async function waitForEipReleased(
|
|
|
525
614
|
async function waitForNatGatewayFullyDeleted(
|
|
526
615
|
natGatewayId: string,
|
|
527
616
|
timeoutConfig: TimeoutConfig,
|
|
617
|
+
credentials?: AwsClientProps,
|
|
528
618
|
): Promise<void> {
|
|
529
619
|
// First wait for the NAT Gateway itself to be deleted
|
|
530
|
-
await waitForNatGatewayDeleted(natGatewayId, timeoutConfig);
|
|
620
|
+
await waitForNatGatewayDeleted(natGatewayId, timeoutConfig, credentials);
|
|
531
621
|
|
|
532
622
|
// Then wait for network interfaces to be cleaned up
|
|
533
623
|
const checkNetworkInterfaces = async () => {
|
|
534
624
|
try {
|
|
535
|
-
const client = await createEC2Client();
|
|
625
|
+
const client = await createEC2Client(credentials);
|
|
536
626
|
const response = await callEC2Api<DescribeNetworkInterfacesResponse>(
|
|
537
627
|
client,
|
|
538
628
|
"DescribeNetworkInterfaces",
|
|
@@ -9,13 +9,14 @@ import {
|
|
|
9
9
|
type TimeoutConfig,
|
|
10
10
|
waitForResourceState,
|
|
11
11
|
} from "../../util/timeout.ts";
|
|
12
|
+
import type { AwsClientProps } from "../client-props.ts";
|
|
12
13
|
import { callEC2Api, createEC2Client } from "./utils.ts";
|
|
13
14
|
import type { Vpc } from "./vpc.ts";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Properties for creating or updating a Route Table
|
|
17
18
|
*/
|
|
18
|
-
export interface RouteTableProps {
|
|
19
|
+
export interface RouteTableProps extends AwsClientProps {
|
|
19
20
|
/**
|
|
20
21
|
* The VPC to create the route table in
|
|
21
22
|
*/
|
|
@@ -58,6 +59,9 @@ export interface RouteTable
|
|
|
58
59
|
* traffic is directed. Subnet associations are managed separately using the
|
|
59
60
|
* RouteTableAssociation resource.
|
|
60
61
|
*
|
|
62
|
+
* Supports AWS credential overrides at the resource level, allowing you to deploy Route Tables
|
|
63
|
+
* to different AWS accounts or regions than the default scope configuration.
|
|
64
|
+
*
|
|
61
65
|
* @example
|
|
62
66
|
* // Create a basic route table
|
|
63
67
|
* const routeTable = await RouteTable("main-route-table", {
|
|
@@ -80,6 +84,45 @@ export interface RouteTable
|
|
|
80
84
|
* });
|
|
81
85
|
*
|
|
82
86
|
* @example
|
|
87
|
+
* // Create Route Table with AWS credential overrides
|
|
88
|
+
* const crossAccountRouteTable = await RouteTable("cross-account-rt", {
|
|
89
|
+
* vpc: mainVpc,
|
|
90
|
+
* // Override AWS credentials for this specific resource
|
|
91
|
+
* region: "us-east-1",
|
|
92
|
+
* profile: "production-account",
|
|
93
|
+
* tags: {
|
|
94
|
+
* Name: "cross-account-route-table",
|
|
95
|
+
* Environment: "production"
|
|
96
|
+
* }
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* // Create Route Table in different region with role assumption
|
|
101
|
+
* const multiRegionRouteTable = await RouteTable("multi-region-rt", {
|
|
102
|
+
* vpc: euVpc,
|
|
103
|
+
* region: "eu-west-1",
|
|
104
|
+
* roleArn: "arn:aws:iam::123456789012:role/CrossRegionRole",
|
|
105
|
+
* roleSessionName: "route-table-deployment",
|
|
106
|
+
* tags: {
|
|
107
|
+
* Name: "eu-route-table",
|
|
108
|
+
* Region: "europe"
|
|
109
|
+
* }
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* // Create Route Table with explicit credentials
|
|
114
|
+
* const explicitCredsRouteTable = await RouteTable("explicit-creds-rt", {
|
|
115
|
+
* vpc: testVpc,
|
|
116
|
+
* accessKeyId: alchemy.secret("AKIAIOSFODNN7EXAMPLE"),
|
|
117
|
+
* secretAccessKey: alchemy.secret("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"),
|
|
118
|
+
* region: "us-west-2",
|
|
119
|
+
* tags: {
|
|
120
|
+
* Name: "explicit-credentials-rt",
|
|
121
|
+
* Purpose: "testing"
|
|
122
|
+
* }
|
|
123
|
+
* });
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
83
126
|
* // Create a private route table for internal traffic
|
|
84
127
|
* const privateRouteTable = await RouteTable("private-routes", {
|
|
85
128
|
* vpc: myVpc,
|
|
@@ -102,6 +145,26 @@ export interface RouteTable
|
|
|
102
145
|
* Name: "custom-timeout-route-table"
|
|
103
146
|
* }
|
|
104
147
|
* });
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* // Multi-account deployment with scope-level and resource-level overrides
|
|
151
|
+
* await alchemy.run("production", {
|
|
152
|
+
* aws: { region: "us-west-2", profile: "main-account" }
|
|
153
|
+
* }, async () => {
|
|
154
|
+
* // This Route Table uses scope credentials (main-account, us-west-2)
|
|
155
|
+
* const mainRouteTable = await RouteTable("main-rt", {
|
|
156
|
+
* vpc: mainVpc,
|
|
157
|
+
* tags: { Name: "main-account-rt" }
|
|
158
|
+
* });
|
|
159
|
+
*
|
|
160
|
+
* // This Route Table overrides to use different account
|
|
161
|
+
* const crossAccountRouteTable = await RouteTable("cross-account-rt", {
|
|
162
|
+
* vpc: crossVpc,
|
|
163
|
+
* profile: "secondary-account",
|
|
164
|
+
* region: "us-east-1", // Also override region
|
|
165
|
+
* tags: { Name: "secondary-account-rt" }
|
|
166
|
+
* });
|
|
167
|
+
* });
|
|
105
168
|
*/
|
|
106
169
|
export const RouteTable = Resource(
|
|
107
170
|
"aws::RouteTable",
|
|
@@ -110,7 +173,8 @@ export const RouteTable = Resource(
|
|
|
110
173
|
_id: string,
|
|
111
174
|
props: RouteTableProps,
|
|
112
175
|
): Promise<RouteTable> {
|
|
113
|
-
|
|
176
|
+
// Create EC2 client with credential resolution handled internally
|
|
177
|
+
const client = await createEC2Client(props);
|
|
114
178
|
const timeoutConfig = mergeTimeoutConfig(
|
|
115
179
|
ROUTE_TABLE_TIMEOUT,
|
|
116
180
|
props.timeout,
|
package/src/aws/ec2/route.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type TimeoutConfig,
|
|
10
10
|
waitForResourceState,
|
|
11
11
|
} from "../../util/timeout.ts";
|
|
12
|
+
import type { AwsClientProps } from "../client-props.ts";
|
|
12
13
|
import { retry } from "../retry.ts";
|
|
13
14
|
import type { InternetGateway } from "./internet-gateway.ts";
|
|
14
15
|
import type { NatGateway } from "./nat-gateway.ts";
|
|
@@ -18,7 +19,7 @@ import { callEC2Api, createEC2Client } from "./utils.ts";
|
|
|
18
19
|
/**
|
|
19
20
|
* Properties for creating or updating a Route
|
|
20
21
|
*/
|
|
21
|
-
export interface RouteProps {
|
|
22
|
+
export interface RouteProps extends AwsClientProps {
|
|
22
23
|
/**
|
|
23
24
|
* The route table to add the route to
|
|
24
25
|
*/
|
|
@@ -74,6 +75,9 @@ export interface Route extends Resource<"aws::Route">, RouteProps {
|
|
|
74
75
|
* Creates and manages individual routes within route tables, directing traffic
|
|
75
76
|
* to various targets like Internet Gateways, NAT Gateways, or instances.
|
|
76
77
|
*
|
|
78
|
+
* Supports AWS credential overrides at the resource level, allowing you to deploy Routes
|
|
79
|
+
* to different AWS accounts or regions than the default scope configuration.
|
|
80
|
+
*
|
|
77
81
|
* @example
|
|
78
82
|
* // Create a default route to Internet Gateway
|
|
79
83
|
* const publicRoute = await Route("public-default-route", {
|
|
@@ -91,6 +95,39 @@ export interface Route extends Resource<"aws::Route">, RouteProps {
|
|
|
91
95
|
* });
|
|
92
96
|
*
|
|
93
97
|
* @example
|
|
98
|
+
* // Create Route with AWS credential overrides
|
|
99
|
+
* const crossAccountRoute = await Route("cross-account-route", {
|
|
100
|
+
* routeTable: mainRouteTable,
|
|
101
|
+
* destinationCidrBlock: "0.0.0.0/0",
|
|
102
|
+
* target: { internetGateway: mainIgw },
|
|
103
|
+
* // Override AWS credentials for this specific resource
|
|
104
|
+
* region: "us-east-1",
|
|
105
|
+
* profile: "production-account",
|
|
106
|
+
* });
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* // Create Route in different region with role assumption
|
|
110
|
+
* const multiRegionRoute = await Route("multi-region-route", {
|
|
111
|
+
* routeTable: euRouteTable,
|
|
112
|
+
* destinationCidrBlock: "0.0.0.0/0",
|
|
113
|
+
* target: { internetGateway: euIgw },
|
|
114
|
+
* region: "eu-west-1",
|
|
115
|
+
* roleArn: "arn:aws:iam::123456789012:role/CrossRegionRole",
|
|
116
|
+
* roleSessionName: "route-deployment",
|
|
117
|
+
* });
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* // Create Route with explicit credentials
|
|
121
|
+
* const explicitCredsRoute = await Route("explicit-creds-route", {
|
|
122
|
+
* routeTable: testRouteTable,
|
|
123
|
+
* destinationCidrBlock: "0.0.0.0/0",
|
|
124
|
+
* target: { internetGateway: testIgw },
|
|
125
|
+
* accessKeyId: alchemy.secret("AKIAIOSFODNN7EXAMPLE"),
|
|
126
|
+
* secretAccessKey: alchemy.secret("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"),
|
|
127
|
+
* region: "us-west-2",
|
|
128
|
+
* });
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
94
131
|
* // Create a route to a specific instance
|
|
95
132
|
* const instanceRoute = await Route("instance-route", {
|
|
96
133
|
* routeTable: "rtb-12345678",
|
|
@@ -133,6 +170,28 @@ export interface Route extends Resource<"aws::Route">, RouteProps {
|
|
|
133
170
|
* delayMs: 2000
|
|
134
171
|
* }
|
|
135
172
|
* });
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* // Multi-account deployment with scope-level and resource-level overrides
|
|
176
|
+
* await alchemy.run("production", {
|
|
177
|
+
* aws: { region: "us-west-2", profile: "main-account" }
|
|
178
|
+
* }, async () => {
|
|
179
|
+
* // This Route uses scope credentials (main-account, us-west-2)
|
|
180
|
+
* const mainRoute = await Route("main-route", {
|
|
181
|
+
* routeTable: mainRouteTable,
|
|
182
|
+
* destinationCidrBlock: "0.0.0.0/0",
|
|
183
|
+
* target: { internetGateway: mainIgw }
|
|
184
|
+
* });
|
|
185
|
+
*
|
|
186
|
+
* // This Route overrides to use different account
|
|
187
|
+
* const crossAccountRoute = await Route("cross-account-route", {
|
|
188
|
+
* routeTable: crossRouteTable,
|
|
189
|
+
* destinationCidrBlock: "0.0.0.0/0",
|
|
190
|
+
* target: { internetGateway: crossIgw },
|
|
191
|
+
* profile: "secondary-account",
|
|
192
|
+
* region: "us-east-1", // Also override region
|
|
193
|
+
* });
|
|
194
|
+
* });
|
|
136
195
|
*/
|
|
137
196
|
export const Route = Resource(
|
|
138
197
|
"aws::Route",
|
|
@@ -141,7 +200,8 @@ export const Route = Resource(
|
|
|
141
200
|
_id: string,
|
|
142
201
|
props: RouteProps,
|
|
143
202
|
): Promise<Route> {
|
|
144
|
-
|
|
203
|
+
// Create EC2 client with credential resolution handled internally
|
|
204
|
+
const client = await createEC2Client(props);
|
|
145
205
|
const _timeoutConfig = mergeTimeoutConfig(ROUTE_TIMEOUT, props.timeout);
|
|
146
206
|
const routeTableId =
|
|
147
207
|
typeof props.routeTable === "string"
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type TimeoutConfig,
|
|
9
9
|
waitForResourceState,
|
|
10
10
|
} from "../../util/timeout.ts";
|
|
11
|
+
import type { AwsClientProps } from "../client-props.ts";
|
|
11
12
|
import { callEC2Api, createEC2Client } from "./utils.ts";
|
|
12
13
|
import type { Vpc } from "./vpc.ts";
|
|
13
14
|
|
|
@@ -22,7 +23,7 @@ export const SECURITY_GROUP_TIMEOUT: TimeoutConfig = {
|
|
|
22
23
|
/**
|
|
23
24
|
* Properties for creating or updating a Security Group
|
|
24
25
|
*/
|
|
25
|
-
export interface SecurityGroupProps {
|
|
26
|
+
export interface SecurityGroupProps extends AwsClientProps {
|
|
26
27
|
/**
|
|
27
28
|
* The VPC to create the security group in.
|
|
28
29
|
*/
|
|
@@ -79,8 +80,12 @@ export interface SecurityGroup
|
|
|
79
80
|
* instances and other AWS resources. Rules are managed separately using the
|
|
80
81
|
* `SecurityGroupRule` resource.
|
|
81
82
|
*
|
|
83
|
+
* Supports AWS credential overrides at the resource level, allowing you to deploy Security Groups
|
|
84
|
+
* to different AWS accounts or regions than the default scope configuration.
|
|
85
|
+
*
|
|
82
86
|
* @example
|
|
83
|
-
*
|
|
87
|
+
* ```typescript
|
|
88
|
+
* // Create a basic web server security group
|
|
84
89
|
* const webSecurityGroup = await SecurityGroup("web-sg", {
|
|
85
90
|
* vpc: mainVpc,
|
|
86
91
|
* groupName: "web-server-sg",
|
|
@@ -90,11 +95,72 @@ export interface SecurityGroup
|
|
|
90
95
|
* Environment: "production"
|
|
91
96
|
* }
|
|
92
97
|
* });
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* // Create Security Group with AWS credential overrides
|
|
103
|
+
* const crossAccountSg = await SecurityGroup("cross-account-sg", {
|
|
104
|
+
* vpc: mainVpc,
|
|
105
|
+
* groupName: "cross-account-security-group",
|
|
106
|
+
* description: "Security group in different account",
|
|
107
|
+
* // Override AWS credentials for this specific resource
|
|
108
|
+
* region: "us-east-1",
|
|
109
|
+
* profile: "production-account",
|
|
110
|
+
* tags: {
|
|
111
|
+
* Name: "cross-account-sg",
|
|
112
|
+
* Environment: "production"
|
|
113
|
+
* }
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
93
116
|
*
|
|
94
117
|
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* // Create Security Group in different region with role assumption
|
|
120
|
+
* const multiRegionSg = await SecurityGroup("multi-region-sg", {
|
|
121
|
+
* vpc: euVpc,
|
|
122
|
+
* groupName: "eu-security-group",
|
|
123
|
+
* description: "Security group in EU region",
|
|
124
|
+
* region: "eu-west-1",
|
|
125
|
+
* roleArn: "arn:aws:iam::123456789012:role/CrossRegionRole",
|
|
126
|
+
* roleSessionName: "security-group-deployment",
|
|
127
|
+
* tags: {
|
|
128
|
+
* Name: "eu-security-group",
|
|
129
|
+
* Region: "europe"
|
|
130
|
+
* }
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* // Create Security Group with explicit credentials
|
|
137
|
+
* const explicitCredsSg = await SecurityGroup("explicit-creds-sg", {
|
|
138
|
+
* vpc: testVpc,
|
|
139
|
+
* groupName: "test-security-group",
|
|
140
|
+
* description: "Security group with explicit credentials",
|
|
141
|
+
* accessKeyId: alchemy.secret("AKIAIOSFODNN7EXAMPLE"),
|
|
142
|
+
* secretAccessKey: alchemy.secret("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"),
|
|
143
|
+
* region: "us-west-2",
|
|
144
|
+
* tags: {
|
|
145
|
+
* Name: "explicit-credentials-sg",
|
|
146
|
+
* Purpose: "testing"
|
|
147
|
+
* }
|
|
148
|
+
* });
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* // Create Security Group with rules (rules managed separately)
|
|
154
|
+
* const webSg = await SecurityGroup("web-sg", {
|
|
155
|
+
* vpc: mainVpc,
|
|
156
|
+
* groupName: "web-server-sg",
|
|
157
|
+
* description: "Security group for web servers",
|
|
158
|
+
* tags: { Name: "web-server-security-group" }
|
|
159
|
+
* });
|
|
160
|
+
*
|
|
95
161
|
* // Separately, define a rule to allow HTTP traffic
|
|
96
162
|
* const httpRule = await SecurityGroupRule("web-sg-http-rule", {
|
|
97
|
-
* securityGroup:
|
|
163
|
+
* securityGroup: webSg,
|
|
98
164
|
* type: "ingress",
|
|
99
165
|
* protocol: "tcp",
|
|
100
166
|
* fromPort: 80,
|
|
@@ -102,6 +168,33 @@ export interface SecurityGroup
|
|
|
102
168
|
* cidrBlocks: ["0.0.0.0/0"],
|
|
103
169
|
* description: "Allow HTTP access from anywhere"
|
|
104
170
|
* });
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* // Multi-account deployment with scope-level and resource-level overrides
|
|
176
|
+
* await alchemy.run("production", {
|
|
177
|
+
* aws: { region: "us-west-2", profile: "main-account" }
|
|
178
|
+
* }, async () => {
|
|
179
|
+
* // This SG uses scope credentials (main-account, us-west-2)
|
|
180
|
+
* const mainSg = await SecurityGroup("main-sg", {
|
|
181
|
+
* vpc: mainVpc,
|
|
182
|
+
* groupName: "main-account-sg",
|
|
183
|
+
* description: "Security group in main account",
|
|
184
|
+
* tags: { Name: "main-account-sg" }
|
|
185
|
+
* });
|
|
186
|
+
*
|
|
187
|
+
* // This SG overrides to use different account
|
|
188
|
+
* const crossAccountSg = await SecurityGroup("cross-account-sg", {
|
|
189
|
+
* vpc: crossVpc,
|
|
190
|
+
* groupName: "secondary-account-sg",
|
|
191
|
+
* description: "Security group in secondary account",
|
|
192
|
+
* profile: "secondary-account",
|
|
193
|
+
* region: "us-east-1", // Also override region
|
|
194
|
+
* tags: { Name: "secondary-account-sg" }
|
|
195
|
+
* });
|
|
196
|
+
* });
|
|
197
|
+
* ```
|
|
105
198
|
*/
|
|
106
199
|
export const SecurityGroup = Resource(
|
|
107
200
|
"aws::SecurityGroup",
|
|
@@ -110,7 +203,8 @@ export const SecurityGroup = Resource(
|
|
|
110
203
|
_id: string,
|
|
111
204
|
props: SecurityGroupProps,
|
|
112
205
|
): Promise<SecurityGroup> {
|
|
113
|
-
|
|
206
|
+
// Create EC2 client with credential resolution handled internally
|
|
207
|
+
const client = await createEC2Client(props);
|
|
114
208
|
const vpcId = typeof props.vpc === "string" ? props.vpc : props.vpc.vpcId;
|
|
115
209
|
const timeoutConfig = mergeTimeoutConfig(
|
|
116
210
|
SECURITY_GROUP_TIMEOUT,
|