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.
Files changed (143) hide show
  1. package/README.md +1 -2
  2. package/bin/alchemy.js +1406 -1464
  3. package/bin/commands/init.ts +29 -2
  4. package/bin/services/execute-alchemy.ts +1 -2
  5. package/lib/alchemy.d.ts +2 -2
  6. package/lib/alchemy.d.ts.map +1 -1
  7. package/lib/alchemy.js.map +1 -1
  8. package/lib/aws/client-props.d.ts +149 -0
  9. package/lib/aws/client-props.d.ts.map +1 -0
  10. package/lib/aws/client-props.js +1 -0
  11. package/lib/aws/client-props.js.map +1 -0
  12. package/lib/aws/credentials.d.ts +68 -5
  13. package/lib/aws/credentials.d.ts.map +1 -1
  14. package/lib/aws/credentials.js +148 -0
  15. package/lib/aws/credentials.js.map +1 -1
  16. package/lib/aws/ec2/internet-gateway-attachment.d.ts +57 -3
  17. package/lib/aws/ec2/internet-gateway-attachment.d.ts.map +1 -1
  18. package/lib/aws/ec2/internet-gateway-attachment.js +57 -3
  19. package/lib/aws/ec2/internet-gateway-attachment.js.map +1 -1
  20. package/lib/aws/ec2/internet-gateway.d.ts +68 -40
  21. package/lib/aws/ec2/internet-gateway.d.ts.map +1 -1
  22. package/lib/aws/ec2/internet-gateway.js +68 -40
  23. package/lib/aws/ec2/internet-gateway.js.map +1 -1
  24. package/lib/aws/ec2/nat-gateway.d.ts +99 -18
  25. package/lib/aws/ec2/nat-gateway.d.ts.map +1 -1
  26. package/lib/aws/ec2/nat-gateway.js +113 -37
  27. package/lib/aws/ec2/nat-gateway.js.map +1 -1
  28. package/lib/aws/ec2/route-table-association.d.ts +1 -1
  29. package/lib/aws/ec2/route-table-association.js +1 -1
  30. package/lib/aws/ec2/route-table.d.ts +64 -1
  31. package/lib/aws/ec2/route-table.d.ts.map +1 -1
  32. package/lib/aws/ec2/route-table.js +64 -1
  33. package/lib/aws/ec2/route-table.js.map +1 -1
  34. package/lib/aws/ec2/route.d.ts +60 -1
  35. package/lib/aws/ec2/route.d.ts.map +1 -1
  36. package/lib/aws/ec2/route.js +60 -1
  37. package/lib/aws/ec2/route.js.map +1 -1
  38. package/lib/aws/ec2/security-group.d.ts +96 -3
  39. package/lib/aws/ec2/security-group.d.ts.map +1 -1
  40. package/lib/aws/ec2/security-group.js +96 -3
  41. package/lib/aws/ec2/security-group.js.map +1 -1
  42. package/lib/aws/ec2/subnet.d.ts +61 -3
  43. package/lib/aws/ec2/subnet.d.ts.map +1 -1
  44. package/lib/aws/ec2/subnet.js +61 -3
  45. package/lib/aws/ec2/subnet.js.map +1 -1
  46. package/lib/aws/ec2/utils.d.ts +10 -2
  47. package/lib/aws/ec2/utils.d.ts.map +1 -1
  48. package/lib/aws/ec2/utils.js +68 -7
  49. package/lib/aws/ec2/utils.js.map +1 -1
  50. package/lib/aws/ec2/vpc.d.ts +50 -2
  51. package/lib/aws/ec2/vpc.d.ts.map +1 -1
  52. package/lib/aws/ec2/vpc.js +50 -2
  53. package/lib/aws/ec2/vpc.js.map +1 -1
  54. package/lib/aws/index.d.ts +2 -0
  55. package/lib/aws/index.d.ts.map +1 -1
  56. package/lib/aws/index.js +2 -0
  57. package/lib/aws/index.js.map +1 -1
  58. package/lib/cloudflare/api-response.js +2 -2
  59. package/lib/cloudflare/api-response.js.map +1 -1
  60. package/lib/cloudflare/api.d.ts +19 -0
  61. package/lib/cloudflare/api.d.ts.map +1 -1
  62. package/lib/cloudflare/api.js +4 -0
  63. package/lib/cloudflare/api.js.map +1 -1
  64. package/lib/cloudflare/assets.d.ts.map +1 -1
  65. package/lib/cloudflare/assets.js +3 -4
  66. package/lib/cloudflare/assets.js.map +1 -1
  67. package/lib/cloudflare/bucket.d.ts +5 -3
  68. package/lib/cloudflare/bucket.d.ts.map +1 -1
  69. package/lib/cloudflare/bucket.js +22 -18
  70. package/lib/cloudflare/bucket.js.map +1 -1
  71. package/lib/cloudflare/bundle/plugin-compat-warning.js +7 -7
  72. package/lib/cloudflare/bundle/plugin-compat-warning.js.map +1 -1
  73. package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -1
  74. package/lib/cloudflare/kv-namespace.d.ts +2 -2
  75. package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
  76. package/lib/cloudflare/kv-namespace.js.map +1 -1
  77. package/lib/cloudflare/oauth.js +3 -3
  78. package/lib/cloudflare/oauth.js.map +1 -1
  79. package/lib/cloudflare/quick-tunnel.d.ts +1 -1
  80. package/lib/cloudflare/website.d.ts.map +1 -1
  81. package/lib/cloudflare/website.js +26 -97
  82. package/lib/cloudflare/website.js.map +1 -1
  83. package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
  84. package/lib/cloudflare/worker-bundle.js +9 -8
  85. package/lib/cloudflare/worker-bundle.js.map +1 -1
  86. package/lib/cloudflare/worker-tail.d.ts.map +1 -1
  87. package/lib/cloudflare/worker-tail.js +6 -6
  88. package/lib/cloudflare/worker-tail.js.map +1 -1
  89. package/lib/resource.d.ts +1 -0
  90. package/lib/resource.d.ts.map +1 -1
  91. package/lib/resource.js +13 -2
  92. package/lib/resource.js.map +1 -1
  93. package/lib/scope.d.ts +24 -23
  94. package/lib/scope.d.ts.map +1 -1
  95. package/lib/scope.js +25 -20
  96. package/lib/scope.js.map +1 -1
  97. package/lib/state/cloudflare-state-store.d.ts.map +1 -1
  98. package/lib/state/cloudflare-state-store.js +2 -1
  99. package/lib/state/cloudflare-state-store.js.map +1 -1
  100. package/lib/util/idempotent-spawn.d.ts +10 -8
  101. package/lib/util/idempotent-spawn.d.ts.map +1 -1
  102. package/lib/util/idempotent-spawn.js +97 -78
  103. package/lib/util/idempotent-spawn.js.map +1 -1
  104. package/lib/util/index.d.ts +2 -0
  105. package/lib/util/index.d.ts.map +1 -0
  106. package/lib/util/index.js +2 -0
  107. package/lib/util/index.js.map +1 -0
  108. package/lib/util/safe-fetch.d.ts +24 -0
  109. package/lib/util/safe-fetch.d.ts.map +1 -1
  110. package/lib/util/safe-fetch.js +72 -0
  111. package/lib/util/safe-fetch.js.map +1 -1
  112. package/package.json +8 -5
  113. package/src/alchemy.ts +2 -2
  114. package/src/aws/client-props.ts +156 -0
  115. package/src/aws/credentials.ts +165 -4
  116. package/src/aws/ec2/internet-gateway-attachment.ts +59 -4
  117. package/src/aws/ec2/internet-gateway.ts +70 -41
  118. package/src/aws/ec2/nat-gateway.ts +123 -33
  119. package/src/aws/ec2/route-table-association.ts +1 -1
  120. package/src/aws/ec2/route-table.ts +66 -2
  121. package/src/aws/ec2/route.ts +62 -2
  122. package/src/aws/ec2/security-group.ts +98 -4
  123. package/src/aws/ec2/subnet.ts +63 -4
  124. package/src/aws/ec2/utils.ts +73 -7
  125. package/src/aws/ec2/vpc.ts +52 -3
  126. package/src/aws/index.ts +2 -0
  127. package/src/cloudflare/api-response.ts +2 -2
  128. package/src/cloudflare/api.ts +23 -0
  129. package/src/cloudflare/assets.ts +3 -4
  130. package/src/cloudflare/bucket.ts +27 -25
  131. package/src/cloudflare/bundle/plugin-compat-warning.ts +7 -7
  132. package/src/cloudflare/cloudflare-env-proxy.ts +2 -2
  133. package/src/cloudflare/kv-namespace.ts +26 -27
  134. package/src/cloudflare/oauth.ts +3 -3
  135. package/src/cloudflare/website.ts +30 -111
  136. package/src/cloudflare/worker-bundle.ts +9 -8
  137. package/src/cloudflare/worker-tail.ts +6 -8
  138. package/src/resource.ts +19 -2
  139. package/src/scope.ts +73 -43
  140. package/src/state/cloudflare-state-store.ts +2 -1
  141. package/src/util/idempotent-spawn.ts +117 -100
  142. package/src/util/index.ts +1 -0
  143. 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
- * subnet: publicSubnet,
106
- * tags: {
107
- * Name: "main-nat-gateway",
108
- * Environment: "production"
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
- * subnet: "subnet-12345678",
116
- * allocationId: "eipalloc-12345678",
117
- * connectivityType: "public",
118
- * tags: {
119
- * Name: "custom-nat-gateway"
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
- * subnet: privateSubnet,
127
- * connectivityType: "private",
128
- * tags: {
129
- * Name: "private-nat-gateway",
130
- * Type: "internal"
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
- eipClient,
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(this.output.allocationId, timeoutConfig);
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
- natClient,
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(natGateway.NatGatewayId!, timeoutConfig);
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",
@@ -236,7 +236,7 @@ async function waitForRouteTableAssociationDeleted(
236
236
  * publicSubnets.map((subnet, index) =>
237
237
  * RouteTableAssociation(`public-association-${index}`, {
238
238
  * routeTable: publicRouteTable,
239
- * subnet
239
+ * subnet: subnet
240
240
  * })
241
241
  * )
242
242
  * );
@@ -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
- const client = await createEC2Client();
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,
@@ -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
- const client = await createEC2Client();
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
- * // Create a web server security group
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: webSecurityGroup,
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
- const client = await createEC2Client();
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,