@aws/nx-plugin-mcp 1.0.0-rc.83 → 1.0.0-rc.85

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/aws-nx-mcp.js CHANGED
@@ -54266,6 +54266,13 @@ var generators$1 = {
54266
54266
  "metric": "g19",
54267
54267
  "hidden": true
54268
54268
  },
54269
+ "open-api#json-metadata": {
54270
+ "factory": "./src/open-api/json-metadata/generator",
54271
+ "schema": "./src/open-api/json-metadata/schema.json",
54272
+ "description": "Generate a JSON metadata file describing an OpenAPI specification's operations",
54273
+ "metric": "g72",
54274
+ "hidden": true
54275
+ },
54269
54276
  "preset": {
54270
54277
  "factory": "./src/preset/generator",
54271
54278
  "schema": "./src/preset/schema.json",
@@ -94,7 +94,7 @@ const harness = new MyHarness(this, 'MyHarness', {
94
94
 
95
95
  The construct also accepts:
96
96
 
97
- - `allowedTools` — the tools the Harness may use. The Harness deploys with none unless you supply them, see <a href="#configuring-tools">Configuring tools</a>.
97
+ - `allowedTools` — the tools the Harness may use. Defaults to none, see <a href="#configuring-tools">Configuring tools</a>.
98
98
  - `executionRole` — an existing IAM role to use instead of the generated role. A supplied role is used as-is: the baseline permissions are not added to it, and its ARN always feeds the Harness (the raw `executionRoleArn` string cannot be overridden).
99
99
  - `modelResourceArns` — the Bedrock model and inference-profile ARNs the generated execution role may invoke, replacing the default list.
100
100
  - `vpc`, `vpcSubnets` and `securityGroups` — run the Harness in a VPC so it can reach private resources, see <a href="#running-in-a-vpc">Running in a VPC</a>.
@@ -112,15 +112,21 @@ module "my_harness" {
112
112
  }
113
113
  ```
114
114
 
115
- The module exposes three variables:
115
+ The module exposes the following variables:
116
116
 
117
117
  - `model_id` — the Bedrock model or inference profile the Harness uses by default.
118
- - `model_resource_arns` — the Bedrock model and inference-profile ARNs the execution role may invoke, replacing the default list.
119
- - `additional_execution_role_policy_statements` — a list of IAM statement objects (`Effect`, `Action`, `Resource`, optional `Sid` and `Condition`) appended to the execution role policy.
118
+ - `allowed_tools` — the tools the Harness may use. Defaults to none, see <a href="#configuring-tools">Configuring tools</a>.
119
+ - `memory` — the Harness memory configuration, see <a href="#configuring-memory">Configuring memory</a>.
120
+ - `environment_variables`, `max_iterations`, `timeout_seconds` — the corresponding native Harness fields.
121
+ - `execution_role_arn` — an existing IAM role to use instead of the generated role. A supplied role is used as-is: neither the role nor its baseline policy is created, so `model_resource_arns` and `additional_execution_role_policy_statements` cannot be combined with it.
122
+ - `model_resource_arns` — the Bedrock model and inference-profile ARNs the generated execution role may invoke, replacing the default list.
123
+ - `additional_execution_role_policy_statements` — a list of IAM statement objects (`Effect`, `Action`, `Resource`, optional `Sid` and `Condition`) appended to the generated execution role policy.
124
+ - `enable_vpc`, `vpc_id`, `subnet_ids` — run the Harness in a VPC so it can reach private resources, see <a href="#running-in-a-vpc">Running in a VPC</a>.
125
+ - `tags` — tags applied to the resources the module creates.
120
126
 
121
- Everything else is configured on the generated `aws_bedrockagentcore_harness` resource in the module itself.
127
+ Other provider-native fields are configured by editing the generated `aws_bedrockagentcore_harness` resource in the module itself, see <a href="#customizing-your-harness">Customizing your Harness</a>.
122
128
 
123
- The module outputs `harness_id`, `harness_arn`, and `execution_role_arn`.
129
+ The module outputs `harness_id`, `harness_arn`, `execution_role_arn` and `security_group_id`.
124
130
 
125
131
  Deploy with your Terraform project's plan/apply workflow as usual — see the <Link path="guides/terraform-project">Terraform project guide</Link>.
126
132
  </Fragment>
@@ -196,7 +202,7 @@ With neither set, the script fails with an error naming both options.
196
202
  Every native Harness property of the pinned `aws-cdk-lib/aws-bedrockagentcore` module is available through the construct's props — alternate model providers, tool definitions, memory, skills, environment configuration, truncation, custom JWT authorization, and execution limits — and explicit props take precedence over the generated defaults. Alternatively, edit the generated construct in `packages/common/constructs/src/app/harnesses/<name>/<name>.ts`.
197
203
  </Fragment>
198
204
  <Fragment slot="terraform">
199
- The generated module keeps the native `aws_bedrockagentcore_harness` resource directly editable, so provider-native fields alternate model providers (`gemini_model_config`, `openai_model_config`), `tool` blocks, `memory`, `skill` blocks, environments (`environment`, `environment_variables`, `environment_artifact`), `truncation`, and `authorizer_configuration` with a `custom_jwt_authorizer` — are configured by editing `packages/common/terraform/src/app/harnesses/<name>/<name>.tf`.
205
+ The module's variables cover the fields most deployments configure — `model_id`, `allowed_tools`, `memory`, `environment_variables`, `max_iterations`, `timeout_seconds` — plus the execution role and VPC placement. Terraform has no equivalent of the CDK construct's prop spread, so the remaining provider-native fields are configured by editing the `aws_bedrockagentcore_harness` resource in `packages/common/terraform/src/app/harnesses/<name>/<name>.tf`: alternate model providers (`gemini_model_config`, `openai_model_config`), `tool` blocks, `skill` blocks, `environment_artifact`, filesystem and lifecycle configuration under `environment`, `truncation`, and `authorizer_configuration` with a `custom_jwt_authorizer`.
200
206
  </Fragment>
201
207
  </Infrastructure>
202
208
 
@@ -213,19 +219,47 @@ new MyHarness(this, 'Harness', { allowedTools: ['@builtin'] });
213
219
  ```
214
220
  </Fragment>
215
221
  <Fragment slot="terraform">
216
- ```hcl title="packages/common/terraform/src/app/harnesses/my-harness/my-harness.tf"
217
- resource "aws_bedrockagentcore_harness" "this" {
218
- # ...
222
+ ```hcl title="packages/infra/src/main.tf"
223
+ module "my_harness" {
224
+ source = "../../common/terraform/src/app/harnesses/my-harness"
219
225
  allowed_tools = ["@builtin"]
220
226
  }
221
227
  ```
222
-
223
- Add an `allowed_tools` variable to the module if you would rather set it as a module argument where you reference the module.
224
228
  </Fragment>
225
229
  </Infrastructure>
226
230
 
227
231
  Narrow `@builtin` to specific patterns such as `@builtin/file_operations` to restrict what the agent loop can do. See [Harness tools](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/harness-tools.html) for the built-in tools you can add.
228
232
 
233
+ ### Configuring memory
234
+
235
+ The service provisions managed memory for the Harness by default, and the generated execution role is granted access to it — scoped to the memory ARN the service assigns, and only granted while the Harness uses managed memory the infrastructure created. Configure memory explicitly to tune that managed memory, point the Harness at a memory resource you own, or turn memory off:
236
+
237
+ <Infrastructure>
238
+ <Fragment slot="cdk">
239
+ ```ts
240
+ new MyHarness(this, 'MyHarness', {
241
+ memory: { managedMemoryConfiguration: { strategies: ['SUMMARIZATION'] } },
242
+ });
243
+ ```
244
+
245
+ Supplying `memory` at all replaces the default managed memory, so the construct leaves the memory grant off the execution role: add whatever the configuration needs with `addToRolePolicy`.
246
+ </Fragment>
247
+ <Fragment slot="terraform">
248
+ ```hcl
249
+ module "my_harness" {
250
+ source = "../../common/terraform/src/app/harnesses/my-harness"
251
+ memory = {
252
+ managed_memory_configuration = {
253
+ strategies = ["SUMMARIZATION"]
254
+ }
255
+ }
256
+ }
257
+ ```
258
+
259
+ Set exactly one of `managed_memory_configuration` (tune the service's managed memory), `agentcore_memory_configuration` (use a memory resource you own, by ARN) or `disabled` (no memory). Choosing `agentcore_memory_configuration` or `disabled` drops the managed-memory grant from the execution role; for your own memory resource, grant access through `additional_execution_role_policy_statements`.
260
+ </Fragment>
261
+ </Infrastructure>
262
+
229
263
  ### Running in a VPC
230
264
 
231
265
  <Infrastructure>
@@ -241,28 +275,31 @@ database.connections.allowDefaultPortFrom(harness, 'Harness to database');
241
275
  The Harness is placed in the VPC's private subnets with egress, in a security group created for it. Override either with `vpcSubnets` and `securityGroups`. Both require `vpc`, and `connections` is only available when the Harness runs in a VPC.
242
276
  </Fragment>
243
277
  <Fragment slot="terraform">
244
- Add a `network_configuration` block to the generated `aws_bedrockagentcore_harness` resource's `environment.agent_core_runtime_environment`, then reference the security group you place it in from your other resources' rules:
278
+ Set `enable_vpc` alongside `vpc_id` and `subnet_ids` to run the Harness inside a VPC, so it can reach private resources such as a database:
245
279
 
246
- ```hcl title="packages/common/terraform/src/app/harnesses/my-harness/my-harness.tf"
247
- resource "aws_security_group" "harness" {
248
- vpc_id = var.vpc_id
280
+ ```hcl
281
+ module "my_harness" {
282
+ source = "../../common/terraform/src/app/harnesses/my-harness"
283
+ enable_vpc = true
284
+ vpc_id = var.vpc_id
285
+ subnet_ids = var.private_subnet_ids
249
286
  }
287
+ ```
250
288
 
251
- resource "aws_bedrockagentcore_harness" "this" {
252
- # ...
253
- environment {
254
- agent_core_runtime_environment {
255
- network_configuration {
256
- network_mode = "VPC"
257
- network_mode_config {
258
- security_groups = [aws_security_group.harness.id]
259
- subnets = var.subnet_ids
260
- }
261
- }
262
- }
263
- }
289
+ The module creates a security group for the Harness, allowing outbound HTTPS only. Its `security_group_id` output is what resources the Harness must reach reference in their own ingress rules:
290
+
291
+ ```hcl
292
+ resource "aws_vpc_security_group_ingress_rule" "harness_to_database" {
293
+ security_group_id = aws_security_group.database.id
294
+ referenced_security_group_id = module.my_harness.security_group_id
295
+ from_port = 5432
296
+ to_port = 5432
297
+ ip_protocol = "tcp"
298
+ description = "Harness to database"
264
299
  }
265
300
  ```
301
+
302
+ `security_group_id` is null unless `enable_vpc` is true, and `vpc_id` and `subnet_ids` are both required when it is.
266
303
  </Fragment>
267
304
  </Infrastructure>
268
305
 
@@ -491,6 +491,8 @@ The `UserIdentity` construct can be generated using the <Link path="/guides/reac
491
491
  <OptionFilter when={{ auth: 'custom' }} description="Custom Lambda Authorizer CDK usage">
492
492
  :::caution[Custom Lambda Authorizer]
493
493
  When using `Custom` auth, the construct creates a Lambda Authorizer internally from the generated `authorizer.py` file, which **denies all requests by default**. You must implement your authorization logic in that file before your API will accept any traffic.
494
+
495
+ Authorizer results are cached for 5 minutes, keyed on the `Authorization` header, so a revoked token may be accepted until its cached result expires. Reduce the cache duration in the generated infrastructure if you need faster revocation.
494
496
  :::
495
497
  </OptionFilter>
496
498
  </Fragment>
@@ -604,6 +606,8 @@ module "my_api" {
604
606
  <OptionFilter when={{ auth: 'custom' }} description="Custom Lambda Authorizer usage with Terraform">
605
607
  :::caution[Custom Lambda Authorizer]
606
608
  When using `Custom` auth, your API is protected by a Lambda Authorizer that **denies all requests by default**. You must implement your authorization logic in the generated `authorizer.py` file before your API will accept any traffic.
609
+
610
+ Authorizer results are cached for 5 minutes, keyed on the `Authorization` header, so a revoked token may be accepted until its cached result expires. Reduce the cache duration in the generated infrastructure if you need faster revocation.
607
611
  :::
608
612
  </OptionFilter>
609
613
  </Fragment>
@@ -48,10 +48,12 @@ For application projects (`--type=application`), the generator creates a complet
48
48
  - main.tf S3 bucket and policies for state storage
49
49
  - providers.tf AWS provider configuration
50
50
  - variables.tf Bootstrap variable definitions
51
- - scripts Node helpers run by the nx `bootstrap` and `init` targets
51
+ - scripts Node helpers run by the nx `bootstrap`, `bootstrap-destroy` and `init` targets
52
52
  - aws-config.ts Resolves account + region via the AWS SDK credential chain
53
53
  - bootstrap.ts Pulls/pushes the bootstrap tfstate and runs `terraform apply`
54
+ - bootstrap-destroy.ts Empties the state bucket and runs `terraform destroy`
54
55
  - init.ts Runs `terraform init` with the S3 backend config
56
+ - checkov.yml Checkov configuration, including the checks to skip
55
57
  - project.json Project configuration and build targets
56
58
 
57
59
  </FileTree>
@@ -71,6 +73,7 @@ For library projects (`--type=library`), the generator creates a simpler structu
71
73
 
72
74
  - src
73
75
  - main.tf Main Terraform module file
76
+ - checkov.yml Checkov configuration, including the checks to skip
74
77
  - project.json Project configuration and build targets
75
78
 
76
79
  </FileTree>
@@ -250,12 +253,66 @@ Format your Terraform code using the `fmt` target:
250
253
 
251
254
  #### Security Testing
252
255
 
253
- Run security checks on your infrastructure using Checkov with the `test` target:
256
+ Run security checks on your infrastructure using Checkov with the `checkov` target:
254
257
 
255
- <NxCommands commands={['test tf-infra']} />
258
+ <NxCommands commands={['checkov tf-infra']} />
256
259
 
257
260
  You will find your security test results in the root `dist` folder, under `dist/packages/<my-terraform-project>/checkov`.
258
261
 
262
+ Checks are configured in the project's `checkov.yml`. Add a check id to `skip-check` to suppress it across the whole project:
263
+
264
+ ```yaml title="checkov.yml"
265
+ skip-check:
266
+ - CKV_AWS_115 # Concurrent execution limit
267
+ - CKV_AWS_116 # Dead Letter Queue
268
+ ```
269
+
270
+ To suppress a check for a single resource instead, add a `#checkov:skip=<id>:<reason>` comment inside the resource block:
271
+
272
+ ```hcl
273
+ resource "aws_s3_bucket" "example" {
274
+ #checkov:skip=CKV_AWS_18:Access logging not required for this bucket
275
+ bucket = "example"
276
+ }
277
+ ```
278
+
279
+ #### Running Terraform Tests
280
+
281
+ The `test` target runs [Terraform's native test framework](https://developer.hashicorp.com/terraform/language/tests) over any `.tftest.hcl` files in your project:
282
+
283
+ <NxCommands commands={['test tf-infra']} />
284
+
285
+ A project with no test files is a no-op success, so you can add tests when you need them. `build` runs this target, so your tests run as part of a normal build.
286
+
287
+ Each `run` block evaluates your configuration. Use `command = plan` to check what Terraform _would_ do (this expands the whole module graph, so it catches plan-time errors that `validate` cannot), or `command = apply` to create real resources and assert on their outputs. Declaring `mock_provider` means no API calls are made and no AWS credentials are needed, which keeps `plan` tests fast and safe to run in CI:
288
+
289
+ ```hcl title="src/main.tftest.hcl"
290
+ mock_provider "aws" {
291
+ mock_data "aws_caller_identity" {
292
+ defaults = { account_id = "123456789012" }
293
+ }
294
+ mock_data "aws_region" {
295
+ defaults = { region = "us-east-1" }
296
+ }
297
+ }
298
+
299
+ variables {
300
+ aws_region = "us-east-1"
301
+ environment = "dev"
302
+ }
303
+
304
+ run "plan_is_valid" {
305
+ command = plan
306
+
307
+ assert {
308
+ condition = data.aws_caller_identity.current.account_id == "123456789012"
309
+ error_message = "Unexpected account id"
310
+ }
311
+ }
312
+ ```
313
+
314
+ Set every variable your configuration requires in the `variables` block, otherwise the run fails with "has a required variable ... with no set value".
315
+
259
316
  <OptionFilter when={{ type: 'application' }} description="Application-only targets: plan / apply / destroy / etc.">
260
317
  ### Application-Only Targets
261
318
 
@@ -310,6 +367,12 @@ This will permanently delete all resources managed by this Terraform configurati
310
367
  To clean up the bootstrap resources (S3 bucket for state storage):
311
368
 
312
369
  <NxCommands commands={['bootstrap-destroy tf-infra']} />
370
+
371
+ This empties the state bucket before destroying it, and resolves the region from the AWS SDK credential chain, so it runs unattended in CI.
372
+
373
+ :::caution[Destroy your infrastructure first]
374
+ The state bucket holds the state for every environment, so run `destroy` for each environment before this. Once the bucket is gone, Terraform no longer knows about the resources it created.
375
+ :::
313
376
  </OptionFilter>
314
377
 
315
378
  ## More Information
@@ -573,6 +573,8 @@ export class ExampleStack extends Stack {
573
573
 
574
574
  :::caution[Custom Lambda Authorizer]
575
575
  When using `Custom` auth, the construct creates a Lambda Authorizer internally from the generated `src/authorizer.ts` file, which **denies all requests by default**. You must implement your authorization logic in that file before your API will accept any traffic.
576
+
577
+ Authorizer results are cached for 5 minutes, keyed on the `Authorization` header, so a revoked token may be accepted until its cached result expires. Reduce the cache duration in the generated infrastructure if you need faster revocation.
576
578
  :::
577
579
  </OptionFilter>
578
580
 
@@ -718,6 +720,8 @@ module "my_api" {
718
720
  <OptionFilter when={{ auth: 'custom' }} description="Custom Lambda Authorizer usage with Terraform">
719
721
  :::caution[Custom Lambda Authorizer]
720
722
  When using `Custom` auth, your API is protected by a Lambda Authorizer that **denies all requests by default**. You must implement your authorization logic in the generated `src/authorizer.ts` file before your API will accept any traffic.
723
+
724
+ Authorizer results are cached for 5 minutes, keyed on the `Authorization` header, so a revoked token may be accepted until its cached result expires. Reduce the cache duration in the generated infrastructure if you need faster revocation.
721
725
  :::
722
726
  </OptionFilter>
723
727
  </Fragment>
@@ -697,6 +697,8 @@ The `UserIdentity` construct can be generated using the <Link path="/guides/reac
697
697
  <OptionFilter when={{ auth: 'custom' }} description="Custom Lambda Authorizer CDK usage">
698
698
  :::caution[Custom Lambda Authorizer]
699
699
  When using `Custom` auth, the construct creates a Lambda Authorizer internally from the generated `src/authorizer.ts` file, which **denies all requests by default**. You must implement your authorization logic in that file before your API will accept any traffic.
700
+
701
+ Authorizer results are cached for 5 minutes, keyed on the `Authorization` header, so a revoked token may be accepted until its cached result expires. Reduce the cache duration in the generated infrastructure if you need faster revocation.
700
702
  :::
701
703
  </OptionFilter>
702
704
  </Fragment>
@@ -768,6 +770,8 @@ module "my_api" {
768
770
  <OptionFilter when={{ auth: 'custom' }} description="Custom Lambda Authorizer usage with Terraform">
769
771
  :::caution[Custom Lambda Authorizer]
770
772
  When using `Custom` auth, your API is protected by a Lambda Authorizer that **denies all requests by default**. You must implement your authorization logic in the generated `src/authorizer.ts` file before your API will accept any traffic.
773
+
774
+ Authorizer results are cached for 5 minutes, keyed on the `Authorization` header, so a revoked token may be accepted until its cached result expires. Reduce the cache duration in the generated infrastructure if you need faster revocation.
771
775
  :::
772
776
  </OptionFilter>
773
777
 
@@ -1,24 +1,14 @@
1
1
  ---
2
2
  title: Type-Safe API Integrations
3
3
  ---
4
- import { Tabs, TabItem } from '@astrojs/starlight/components';
4
+ import { Steps } from '@astrojs/starlight/components';
5
5
  import Infrastructure from '@components/infrastructure.astro';
6
+ import Drawer from '@components/drawer.astro';
7
+ import OptionFilter from '@components/option-filter.astro';
8
+ import RunGenerator from '@components/run-generator.astro';
6
9
 
7
10
  The REST/HTTP API CDK constructs are configured to provide a type-safe interface for defining integrations for each of your operations.
8
11
 
9
- <Infrastructure>
10
- <Fragment slot="cdk">
11
- The CDK constructs provide full type-safe integration support as described below.
12
- </Fragment>
13
- <Fragment slot="terraform">
14
- :::note[Router Pattern]
15
- Terraform modules use the "router pattern" with a single Lambda function serving all operations. Type-safe integrations are not supported - the module creates one Lambda function that handles all API requests.
16
-
17
- For explicit per-operation integrations with Terraform, you would need to manually create individual Lambda functions and API Gateway routes. See the [Explicit Integrations](#explicit-integrations) section for examples.
18
- :::
19
- </Fragment>
20
- </Infrastructure>
21
-
22
12
  #### Default Integrations
23
13
 
24
14
  <Infrastructure>
@@ -32,7 +22,7 @@ new MyApi(this, 'MyApi', {
32
22
  ```
33
23
  </Fragment>
34
24
  <Fragment slot="terraform">
35
- Terraform modules automatically use the router pattern with a single Lambda function. No additional configuration is needed:
25
+ The generated module already defines the default integrations for the pattern the API was generated with, so no additional configuration is needed:
36
26
 
37
27
  ```hcl
38
28
  module "my_api" {
@@ -40,11 +30,11 @@ module "my_api" {
40
30
 
41
31
  asset_bucket_name = module.asset_bucket.bucket_name
42
32
 
43
- # The module automatically creates a single Lambda function
44
- # that handles all API operations
45
33
  tags = local.common_tags
46
34
  }
47
35
  ```
36
+
37
+ With the default `isolated` pattern, this creates one Lambda function per operation.
48
38
  </Fragment>
49
39
  </Infrastructure>
50
40
 
@@ -78,13 +68,13 @@ api.integrations.$router.handler.addEnvironment('LOG_LEVEL', 'DEBUG');
78
68
  ```
79
69
  </Fragment>
80
70
  <Fragment slot="terraform">
81
- With Terraform's router pattern, there's only one Lambda function. You can access it via the module outputs:
71
+ With the `isolated` pattern, the module's outputs are maps keyed by operation name, so you can reach a single operation's resources. For example, to grant one operation's Lambda function extra permissions:
82
72
 
83
73
  ```hcl
84
- # Grant additional permissions to the single Lambda function
85
- resource "aws_iam_role_policy" "additional_permissions" {
86
- name = "additional-api-permissions"
87
- role = module.my_api.lambda_execution_role_name
74
+ # Grant additional permissions to just the sayHello operation's function
75
+ resource "aws_iam_role_policy" "say_hello_permissions" {
76
+ name = "say-hello-additional-permissions"
77
+ role = module.my_api.lambda_execution_role_names["sayHello"]
88
78
 
89
79
  policy = jsonencode({
90
80
  Version = "2012-10-17"
@@ -101,6 +91,48 @@ resource "aws_iam_role_policy" "additional_permissions" {
101
91
  })
102
92
  }
103
93
  ```
94
+
95
+ To grant the same permissions to every operation, iterate the `operations` output:
96
+
97
+ ```hcl
98
+ resource "aws_iam_role_policy" "additional_permissions" {
99
+ for_each = toset(module.my_api.operations)
100
+
101
+ name = "additional-api-permissions"
102
+ role = module.my_api.lambda_execution_role_names[each.key]
103
+
104
+ policy = jsonencode({
105
+ Version = "2012-10-17"
106
+ Statement = [
107
+ {
108
+ Effect = "Allow"
109
+ Action = ["s3:GetObject"]
110
+ Resource = "arn:aws:s3:::my-bucket/*"
111
+ }
112
+ ]
113
+ })
114
+ }
115
+ ```
116
+
117
+ The module also exposes `lambda_function_names`, `lambda_function_arns`, `lambda_invoke_arns`, `integration_ids` and `lambda_log_group_names` as maps keyed by operation name. With the `shared` pattern the equivalent singular outputs (`lambda_execution_role_name`, `lambda_function_name`, …) are exposed instead, since there is only one function.
118
+
119
+ Permissions every operation needs are better passed to the module, which applies them to each function's role:
120
+
121
+ ```hcl
122
+ module "my_api" {
123
+ source = "../../common/terraform/src/app/apis/my-api"
124
+
125
+ asset_bucket_name = module.asset_bucket.bucket_name
126
+
127
+ additional_iam_policy_statements = [
128
+ {
129
+ Effect = "Allow"
130
+ Action = ["s3:GetObject"]
131
+ Resource = ["arn:aws:s3:::my-bucket/*"]
132
+ }
133
+ ]
134
+ }
135
+ ```
104
136
  </Fragment>
105
137
  </Infrastructure>
106
138
 
@@ -125,7 +157,7 @@ new MyApi(this, 'MyApi', {
125
157
 
126
158
  </Fragment>
127
159
  <Fragment slot="terraform">
128
- VPC configuration is already supported by the generated module — set `enable_vpc` along with `vpc_id` and `subnet_ids`, and the module deploys the Lambda function into your VPC behind a security group it creates for you:
160
+ VPC configuration is already supported by the generated module — set `enable_vpc` along with `vpc_id` and `subnet_ids`, and the module deploys every Lambda function into your VPC behind a shared security group it creates for you:
129
161
 
130
162
  ```hcl
131
163
  module "my_api" {
@@ -142,7 +174,7 @@ module "my_api" {
142
174
  }
143
175
  ```
144
176
 
145
- For options the module does not expose, edit the `aws_lambda_function` resource in the generated Terraform module directly.
177
+ For options the module does not expose, edit the `aws_lambda_function` resource in the generated Terraform module directly. With the `isolated` pattern that single resource is declared `for_each = local.operations`, so an edit there applies to every operation.
146
178
  </Fragment>
147
179
  </Infrastructure>
148
180
 
@@ -173,7 +205,21 @@ You will encounter a type error if the same operation is targeted by both `withO
173
205
 
174
206
  </Fragment>
175
207
  <Fragment slot="terraform">
176
- To customise options for specific operations with Terraform, you need to edit the generated Terraform module to configure individual Lambda functions per operation (see the [Explicit Integrations](#explicit-integrations) section below).
208
+ With the `isolated` pattern the Lambda function resource is already per-operation, so options can be varied by operation name. For example, to give one operation a longer timeout, edit the `aws_lambda_function` resource in the generated module:
209
+
210
+ ```hcl
211
+ # packages/common/terraform/src/app/apis/my-api/my-api.tf
212
+ resource "aws_lambda_function" "api_lambda" {
213
+ for_each = local.operations
214
+
215
+ # Default to 30 seconds, but allow longer for specific operations
216
+ timeout = lookup({
217
+ sayHello = 60
218
+ }, each.key, 30)
219
+
220
+ # ... rest of configuration
221
+ }
222
+ ```
177
223
  </Fragment>
178
224
  </Infrastructure>
179
225
 
@@ -244,11 +290,36 @@ api.integrations.getFile.bucket.grantRead(...);
244
290
  ```
245
291
  </Fragment>
246
292
  <Fragment slot="terraform">
247
- :::note[Integration Overrides]
248
- Overriding specific integrations is not supported with Terraform modules since they use the router pattern. All operations are handled by the single Lambda function.
293
+ To point a specific operation at a different integration type, exclude it from the default `for_each` and declare its integration separately. For example, to serve `getDocumentation` from an external website:
249
294
 
250
- For different integration types per operation, you would need to implement explicit integrations manually (see the [Explicit Integrations](#explicit-integrations) section below).
251
- :::
295
+ ```hcl
296
+ # packages/common/terraform/src/app/apis/my-api/my-api.tf
297
+
298
+ # Exclude the overridden operation from the default per-operation resources
299
+ locals {
300
+ overridden_operations = ["getDocumentation"]
301
+ default_operations = {
302
+ for op, details in local.operations : op => details
303
+ if !contains(local.overridden_operations, op)
304
+ }
305
+ }
306
+
307
+ # Then use local.default_operations in place of local.operations for the
308
+ # aws_lambda_function, aws_iam_role, aws_apigatewayv2_integration and
309
+ # aws_lambda_permission resources, and add the override:
310
+ resource "aws_apigatewayv2_integration" "get_documentation" {
311
+ api_id = module.http_api.api_id
312
+ integration_type = "HTTP_PROXY"
313
+ integration_uri = "https://example.com/documentation"
314
+ integration_method = "GET"
315
+ }
316
+
317
+ resource "aws_apigatewayv2_route" "get_documentation" {
318
+ api_id = module.http_api.api_id
319
+ route_key = local.route_key["getDocumentation"]
320
+ target = "integrations/${aws_apigatewayv2_integration.get_documentation.id}"
321
+ }
322
+ ```
252
323
  </Fragment>
253
324
  </Infrastructure>
254
325
 
@@ -274,11 +345,20 @@ new MyApi(this, 'MyApi', {
274
345
  ```
275
346
  </Fragment>
276
347
  <Fragment slot="terraform">
277
- :::note[Authorizer Overrides]
278
- Per-operation authorizer overrides are not supported with Terraform modules. The entire API uses the authentication method specified when generating the API (IAM, Cognito, or Custom).
348
+ Authorization is set on the route (HTTP API) or method (REST API) for each operation, so it can be varied by operation name. For example, to leave one operation unauthenticated on an HTTP API:
279
349
 
280
- For per-operation authorization, you would need to implement explicit integrations manually as below.
281
- :::
350
+ ```hcl
351
+ # packages/common/terraform/src/app/apis/my-api/my-api.tf
352
+ resource "aws_apigatewayv2_route" "operation_routes" {
353
+ for_each = local.operations
354
+
355
+ # ... rest of configuration
356
+
357
+ authorization_type = each.key == "getDocumentation" ? "NONE" : "AWS_IAM"
358
+ }
359
+ ```
360
+
361
+ For an IAM-authenticated REST API, also add a resource policy statement allowing unauthenticated access to that operation's path.
282
362
  </Fragment>
283
363
  </Infrastructure>
284
364
 
@@ -302,331 +382,26 @@ new MyApi(this, 'MyApi', {
302
382
  ```
303
383
  </Fragment>
304
384
  <Fragment slot="terraform">
305
- For explicit per-operation integrations with Terraform, you should modify the generated app-specific module to replace the default proxy integration with specific integrations for each operation.
306
-
307
- Edit `packages/common/terraform/src/app/apis/my-api/my-api.tf`:
308
-
309
- 1. **Remove the default proxy routes** (e.g., `resource "aws_apigatewayv2_route" "proxy_routes"`)
310
- 2. **Replace the single Lambda function** with individual functions for each operation
311
- 3. **Create specific integrations and routes** for each operation, reusing the same ZIP bundle:
312
-
313
- <Tabs syncKey="http-rest">
314
- <TabItem label="HTTP API" _filter={{ infra: 'http-lambda' }}>
315
-
316
- ```diff
317
- # packages/common/terraform/src/app/apis/my-api/my-api.tf
318
-
319
- # Remove the default single Lambda function
320
- - resource "aws_lambda_function" "api_lambda" {
321
- - s3_bucket = aws_s3_object.lambda_zip.bucket
322
- - s3_key = aws_s3_object.lambda_zip.key
323
- - s3_object_version = aws_s3_object.lambda_zip.version_id
324
- - function_name = "MyApiHandler"
325
- - role = aws_iam_role.lambda_execution_role.arn
326
- - handler = "index.handler"
327
- - runtime = "nodejs22.x"
328
- - timeout = 30
329
- - # ... rest of configuration
330
- - }
331
-
332
- # Remove the default proxy integration
333
- - resource "aws_apigatewayv2_integration" "lambda_integration" {
334
- - api_id = module.http_api.api_id
335
- - integration_type = "AWS_PROXY"
336
- - integration_uri = aws_lambda_function.api_lambda.invoke_arn
337
- - # ... rest of configuration
338
- - }
339
-
340
- # Remove the default proxy routes
341
- - resource "aws_apigatewayv2_route" "proxy_routes" {
342
- - for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
343
- - api_id = module.http_api.api_id
344
- - route_key = "${each.key} /{proxy+}"
345
- - target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}"
346
- - # ... rest of configuration
347
- - }
348
-
349
- # Add individual Lambda functions for each operation using the same bundle
350
- + resource "aws_lambda_function" "say_hello_handler" {
351
- + s3_bucket = aws_s3_object.lambda_zip.bucket
352
- + s3_key = aws_s3_object.lambda_zip.key
353
- + s3_object_version = aws_s3_object.lambda_zip.version_id
354
- + function_name = "MyApi-SayHello"
355
- + role = aws_iam_role.lambda_execution_role.arn
356
- + handler = "sayHello.handler" # Specific handler for this operation
357
- + runtime = "nodejs22.x"
358
- + timeout = 30
359
- + source_code_hash = data.archive_file.lambda_zip.output_base64sha256
360
- +
361
- + tracing_config {
362
- + mode = "Active"
363
- + }
364
- +
365
- + environment {
366
- + variables = var.env
367
- + }
368
- +
369
- + tags = var.tags
370
- + }
371
-
372
- + resource "aws_lambda_function" "get_documentation_handler" {
373
- + s3_bucket = aws_s3_object.lambda_zip.bucket
374
- + s3_key = aws_s3_object.lambda_zip.key
375
- + s3_object_version = aws_s3_object.lambda_zip.version_id
376
- + function_name = "MyApi-GetDocumentation"
377
- + role = aws_iam_role.lambda_execution_role.arn
378
- + handler = "getDocumentation.handler" # Specific handler for this operation
379
- + runtime = "nodejs22.x"
380
- + timeout = 30
381
- + source_code_hash = data.archive_file.lambda_zip.output_base64sha256
382
- +
383
- + tracing_config {
384
- + mode = "Active"
385
- + }
386
- +
387
- + environment {
388
- + variables = var.env
389
- + }
390
- +
391
- + tags = var.tags
392
- + }
393
-
394
- # Add specific integrations for each operation
395
- + resource "aws_apigatewayv2_integration" "say_hello_integration" {
396
- + api_id = module.http_api.api_id
397
- + integration_type = "AWS_PROXY"
398
- + integration_uri = aws_lambda_function.say_hello_handler.invoke_arn
399
- + payload_format_version = "2.0"
400
- + timeout_milliseconds = 30000
401
- + }
402
-
403
- + resource "aws_apigatewayv2_integration" "get_documentation_integration" {
404
- + api_id = module.http_api.api_id
405
- + integration_type = "HTTP_PROXY"
406
- + integration_uri = "https://example.com/documentation"
407
- + integration_method = "GET"
408
- + }
409
-
410
- # Add specific routes for each operation
411
- + resource "aws_apigatewayv2_route" "say_hello_route" {
412
- + api_id = module.http_api.api_id
413
- + route_key = "POST /sayHello"
414
- + target = "integrations/${aws_apigatewayv2_integration.say_hello_integration.id}"
415
- + authorization_type = "AWS_IAM"
416
- + }
417
-
418
- + resource "aws_apigatewayv2_route" "get_documentation_route" {
419
- + api_id = module.http_api.api_id
420
- + route_key = "GET /documentation"
421
- + target = "integrations/${aws_apigatewayv2_integration.get_documentation_integration.id}"
422
- + authorization_type = "NONE"
423
- + }
424
-
425
- # Add Lambda permissions for each function
426
- + resource "aws_lambda_permission" "say_hello_permission" {
427
- + statement_id = "AllowExecutionFromAPIGateway-SayHello"
428
- + action = "lambda:InvokeFunction"
429
- + function_name = aws_lambda_function.say_hello_handler.function_name
430
- + principal = "apigateway.amazonaws.com"
431
- + source_arn = "${module.http_api.api_execution_arn}/*/*"
432
- + }
433
-
434
- + resource "aws_lambda_permission" "get_documentation_permission" {
435
- + statement_id = "AllowExecutionFromAPIGateway-GetDocumentation"
436
- + action = "lambda:InvokeFunction"
437
- + function_name = aws_lambda_function.get_documentation_handler.function_name
438
- + principal = "apigateway.amazonaws.com"
439
- + source_arn = "${module.http_api.api_execution_arn}/*/*"
440
- + }
441
- ```
442
- </TabItem>
443
- <TabItem label="REST API" _filter={{ infra: 'rest-lambda' }}>
444
-
445
- ```diff
446
- # packages/common/terraform/src/app/apis/my-api/my-api.tf
447
-
448
- # Remove the default single Lambda function
449
- - resource "aws_lambda_function" "api_lambda" {
450
- - s3_bucket = aws_s3_object.lambda_zip.bucket
451
- - s3_key = aws_s3_object.lambda_zip.key
452
- - s3_object_version = aws_s3_object.lambda_zip.version_id
453
- - function_name = "MyApiHandler-${random_string.suffix.result}"
454
- - role = aws_iam_role.lambda_execution_role.arn
455
- - handler = "index.handler"
456
- - runtime = "nodejs22.x"
457
- - timeout = 30
458
- - # ... rest of configuration
459
- - }
460
-
461
- # Remove the default proxy integration
462
- - resource "aws_api_gateway_integration" "lambda_integration" {
463
- - rest_api_id = module.rest_api.api_id
464
- - resource_id = aws_api_gateway_resource.proxy_resource.id
465
- - http_method = aws_api_gateway_method.proxy_method.http_method
466
- - integration_http_method = "POST"
467
- - type = "AWS_PROXY"
468
- - uri = aws_lambda_function.api_lambda.invoke_arn
469
- - # ... rest of configuration
470
- - }
471
-
472
- # Remove the default catch-all proxy method
473
- - resource "aws_api_gateway_method" "proxy_method" {
474
- - rest_api_id = module.rest_api.api_id
475
- - resource_id = aws_api_gateway_resource.proxy_resource.id
476
- - http_method = "ANY"
477
- - # ... rest of configuration
478
- - }
479
-
480
- # Add individual Lambda functions for each operation using the same bundle
481
- + resource "aws_lambda_function" "say_hello_handler" {
482
- + s3_bucket = aws_s3_object.lambda_zip.bucket
483
- + s3_key = aws_s3_object.lambda_zip.key
484
- + s3_object_version = aws_s3_object.lambda_zip.version_id
485
- + function_name = "MyApi-SayHello"
486
- + role = aws_iam_role.lambda_execution_role.arn
487
- + handler = "sayHello.handler" # Specific handler for this operation
488
- + runtime = "nodejs22.x"
489
- + timeout = 30
490
- + source_code_hash = data.archive_file.lambda_zip.output_base64sha256
491
- +
492
- + tracing_config {
493
- + mode = "Active"
494
- + }
495
- +
496
- + environment {
497
- + variables = var.env
498
- + }
499
- +
500
- + tags = var.tags
501
- + }
502
-
503
- + resource "aws_lambda_function" "get_documentation_handler" {
504
- + s3_bucket = aws_s3_object.lambda_zip.bucket
505
- + s3_key = aws_s3_object.lambda_zip.key
506
- + s3_object_version = aws_s3_object.lambda_zip.version_id
507
- + function_name = "MyApi-GetDocumentation"
508
- + role = aws_iam_role.lambda_execution_role.arn
509
- + handler = "getDocumentation.handler" # Specific handler for this operation
510
- + runtime = "nodejs22.x"
511
- + timeout = 30
512
- + source_code_hash = data.archive_file.lambda_zip.output_base64sha256
513
- +
514
- + tracing_config {
515
- + mode = "Active"
516
- + }
517
- +
518
- + environment {
519
- + variables = var.env
520
- + }
521
- +
522
- + tags = var.tags
523
- + }
524
-
525
- # Add specific resources and methods for each operation
526
- + resource "aws_api_gateway_resource" "say_hello_resource" {
527
- + rest_api_id = module.rest_api.api_id
528
- + parent_id = module.rest_api.api_root_resource_id
529
- + path_part = "sayHello"
530
- + }
531
-
532
- + resource "aws_api_gateway_method" "say_hello_method" {
533
- + rest_api_id = module.rest_api.api_id
534
- + resource_id = aws_api_gateway_resource.say_hello_resource.id
535
- + http_method = "POST"
536
- + authorization = "AWS_IAM"
537
- + }
538
-
539
- + resource "aws_api_gateway_integration" "say_hello_integration" {
540
- + rest_api_id = module.rest_api.api_id
541
- + resource_id = aws_api_gateway_resource.say_hello_resource.id
542
- + http_method = aws_api_gateway_method.say_hello_method.http_method
543
- +
544
- + integration_http_method = "POST"
545
- + type = "AWS_PROXY"
546
- + uri = aws_lambda_function.say_hello_handler.invoke_arn
547
- + }
548
-
549
- + resource "aws_api_gateway_resource" "get_documentation_resource" {
550
- + rest_api_id = module.rest_api.api_id
551
- + parent_id = module.rest_api.api_root_resource_id
552
- + path_part = "documentation"
553
- + }
554
-
555
- + resource "aws_api_gateway_method" "get_documentation_method" {
556
- + rest_api_id = module.rest_api.api_id
557
- + resource_id = aws_api_gateway_resource.get_documentation_resource.id
558
- + http_method = "GET"
559
- + authorization = "NONE"
560
- + }
561
-
562
- + resource "aws_api_gateway_integration" "get_documentation_integration" {
563
- + rest_api_id = module.rest_api.api_id
564
- + resource_id = aws_api_gateway_resource.get_documentation_resource.id
565
- + http_method = aws_api_gateway_method.get_documentation_method.http_method
566
- +
567
- + integration_http_method = "GET"
568
- + type = "HTTP"
569
- + uri = "https://example.com/documentation"
570
- + }
571
-
572
- # Update deployment to depend on new integrations
573
- ~ resource "aws_api_gateway_deployment" "api_deployment" {
574
- rest_api_id = module.rest_api.api_id
575
-
576
- depends_on = [
577
- - aws_api_gateway_integration.lambda_integration,
578
- + aws_api_gateway_integration.say_hello_integration,
579
- + aws_api_gateway_integration.get_documentation_integration,
580
- ]
581
-
582
- lifecycle {
583
- create_before_destroy = true
584
- }
585
-
586
- + triggers = {
587
- + redeployment = sha1(jsonencode([
588
- + aws_api_gateway_integration.say_hello_integration,
589
- + aws_api_gateway_integration.get_documentation_integration,
590
- + ]))
591
- + }
592
- }
593
-
594
- # Add Lambda permissions for each function
595
- + resource "aws_lambda_permission" "say_hello_permission" {
596
- + statement_id = "AllowExecutionFromAPIGateway-SayHello"
597
- + action = "lambda:InvokeFunction"
598
- + function_name = aws_lambda_function.say_hello_handler.function_name
599
- + principal = "apigateway.amazonaws.com"
600
- + source_arn = "${module.rest_api.api_execution_arn}/*/*"
601
- + }
602
-
603
- + resource "aws_lambda_permission" "get_documentation_permission" {
604
- + statement_id = "AllowExecutionFromAPIGateway-GetDocumentation"
605
- + action = "lambda:InvokeFunction"
606
- + function_name = aws_lambda_function.get_documentation_handler.function_name
607
- + principal = "apigateway.amazonaws.com"
608
- + source_arn = "${module.rest_api.api_execution_arn}/*/*"
609
- + }
610
- ```
611
- </TabItem>
612
- </Tabs>
385
+ Replace the `for_each` used by the `isolated` pattern with explicit instantiations of the Lambda functions, integrations and permissions for each operation.
613
386
 
387
+ :::caution
388
+ Unlike CDK, there is no type-safety in Terraform which will give you a type error if you add a new operation in your application code but forget to declare it in your infrastructure.
389
+ :::
614
390
  </Fragment>
615
391
  </Infrastructure>
616
392
 
617
393
  #### Integration Pattern
618
394
 
619
- <Infrastructure>
620
- <Fragment slot="cdk">
395
+ Generated APIs support two integration patterns:
621
396
 
622
- Generated CDK API constructs support two integration patterns:
623
-
624
- - `isolated` creates one Lambda function per operation. This is the default for generated APIs.
397
+ - `isolated` creates one Lambda function per operation. This is the default and recommended option for APIs.
625
398
  - `shared` creates a single default router Lambda and reuses it for every operation unless you override specific integrations.
626
399
 
627
- `isolated` gives you finer-grained permissions and configuration per operation. `shared` reduces Lambda and API Gateway integration sprawl while still allowing selective overrides.
400
+ `isolated` gives you finer-grained permissions and configuration per operation, as well as better separation for logs and traces. `shared` reduces the likelihood of encountering cold-starts for low-usage APIs.
628
401
 
629
- For example, setting `pattern` to `'shared'` creates a single function instead of one per integration:
402
+ <Infrastructure>
403
+ <Fragment slot="cdk">
404
+ The integration pattern can be changed at any time in CDK by updating your API construct. For example, setting `pattern` to `'shared'` creates a single function instead of one per integration:
630
405
 
631
406
  ```ts {6}
632
407
  // packages/common/constructs/src/app/apis/my-api.ts
@@ -643,20 +418,71 @@ export class MyApi<...> extends ... {
643
418
  ```
644
419
  </Fragment>
645
420
  <Fragment slot="terraform">
646
- Terraform modules automatically use the router pattern - this is the default and only supported approach. The generated module creates a single Lambda function that handles all API operations.
647
-
648
- You can simply instantiate the default module to get the router pattern:
421
+ Unlike CDK, the integration pattern is baked into the generated module. To change the integration pattern:
649
422
 
650
- ```hcl
651
- # Default router pattern - single Lambda function for all operations
652
- module "my_api" {
653
- source = "../../common/terraform/src/app/apis/my-api"
423
+ <Steps>
424
+ 1. Delete the previously generated API module in `packages/common/terraform/src/app/apis`
425
+ 2. Re-run the API generator with the other integration pattern:
426
+ <RunGenerator generator="ts#api" requiredParameters={{ integrationPattern: 'shared' }} />
427
+ </Steps>
654
428
 
655
- asset_bucket_name = module.asset_bucket.bucket_name
429
+ With the `isolated` pattern, the module reads the operations from a generated file:
656
430
 
657
- # Single Lambda function handles all operations automatically
658
- tags = local.common_tags
431
+ ```hcl
432
+ # packages/common/terraform/src/app/apis/my-api/my-api.tf
433
+ locals {
434
+ operations_file = "${path.module}/../../../generated/my-api/operations.json"
435
+ operations = fileexists(local.operations_file) ? jsondecode(file(local.operations_file)) : {}
659
436
  }
660
437
  ```
438
+
439
+ This file is generated from your API, so you do not need to edit this by hand. Adding an operation to your API application code adds the route and lambda function on the next deploy. It is `.gitignore`d by default; remove the entry if you prefer to check it in.
661
440
  </Fragment>
662
441
  </Infrastructure>
442
+
443
+ <OptionFilter when={{ iac: 'terraform', infra: 'rest-lambda' }} description="Raising the REST API path depth limit in Terraform">
444
+ ##### Terraform REST API Path Depth Limit
445
+
446
+ :::caution
447
+ Due to a limitation with Terraform where instances of resources can't reference one another (see [hashicorp/terraform#26697](https://github.com/hashicorp/terraform/issues/26697)), the API Gateway resource tree is built one level at a time rather than recursively, supporting operation paths of up to 16 segments. If an operation's path exceeds this, the plan fails with a message naming the paths that are too deep.
448
+
449
+ <Drawer title="Supporting deeper paths" trigger="Click here for instructions to support deeper paths should your API require it">
450
+
451
+ Edit `packages/common/terraform/src/app/apis/<my-api>/<my-api>.tf`:
452
+
453
+ <Steps>
454
+ 1. Increment `max_path_depth` in `locals`:
455
+
456
+ ```hcl
457
+ locals {
458
+ max_path_depth = 17
459
+ }
460
+ ```
461
+
462
+ 2. Copy the last `aws_api_gateway_resource` block, incrementing both the resource name and its parent:
463
+
464
+ ```hcl
465
+ resource "aws_api_gateway_resource" "path_depth_16" {
466
+ for_each = local.path_nodes_by_depth[16]
467
+
468
+ rest_api_id = module.rest_api.api_id
469
+ parent_id = aws_api_gateway_resource.path_depth_15[each.value.parent].id
470
+ path_part = each.value.part
471
+ }
472
+ ```
473
+
474
+ 3. Add the new level to the `resource_ids` local:
475
+
476
+ ```hcl
477
+ locals {
478
+ resource_ids = merge(
479
+ ...
480
+ { for path, resource in aws_api_gateway_resource.path_depth_16 : path => resource.id },
481
+ )
482
+ }
483
+ ```
484
+ </Steps>
485
+
486
+ </Drawer>
487
+ :::
488
+ </OptionFilter>
@@ -5,6 +5,8 @@ import Infrastructure from '@components/infrastructure.astro';
5
5
 
6
6
  Performance Insights is enabled on the Aurora writer instance by default (encrypted with the cluster's KMS key). Aurora engine logs are also exported to [CloudWatch Logs](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_LogAccess.html) by default, configured to surface schema-level activity without leaking row data.
7
7
 
8
+ Exported log volume — and so [CloudWatch Logs ingestion cost](https://aws.amazon.com/cloudwatch/pricing/) — scales with schema changes and connections rather than query traffic, since the log types that carry full statement text are excluded. On Aurora MySQL the `CONNECT` audit event is emitted per connection, so workloads that open a connection per request produce more than ones that pool.
9
+
8
10
  Disable log export per database if not required:
9
11
 
10
12
  <Infrastructure>
@@ -3,7 +3,7 @@ title: Serverless Capacity
3
3
  ---
4
4
  import Infrastructure from '@components/infrastructure.astro';
5
5
 
6
- Control Aurora Serverless v2 scaling limits to match your workload.
6
+ Control Aurora Serverless v2 scaling limits to match your workload. Both providers default to a minimum of 0.5 ACUs and a maximum of 4.
7
7
 
8
8
  <Infrastructure>
9
9
  <Fragment slot="cdk">
package/generators.json CHANGED
@@ -124,6 +124,13 @@
124
124
  "metric": "g19",
125
125
  "hidden": true
126
126
  },
127
+ "open-api#json-metadata": {
128
+ "factory": "./src/open-api/json-metadata/generator",
129
+ "schema": "./src/open-api/json-metadata/schema.json",
130
+ "description": "Generate a JSON metadata file describing an OpenAPI specification's operations",
131
+ "metric": "g72",
132
+ "hidden": true
133
+ },
127
134
  "preset": {
128
135
  "factory": "./src/preset/generator",
129
136
  "schema": "./src/preset/schema.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws/nx-plugin-mcp",
3
- "version": "1.0.0-rc.83",
3
+ "version": "1.0.0-rc.85",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/awslabs/nx-plugin-for-aws.git",
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "OpenApiJsonMetadata",
4
+ "title": "OpenAPI JSON Metadata",
5
+ "description": "Generate a JSON metadata file describing an OpenAPI specification's operations",
6
+ "type": "object",
7
+ "properties": {
8
+ "openApiSpecPath": {
9
+ "type": "string",
10
+ "description": "Path to the OpenAPI specification relative to the monorepo root",
11
+ "x-priority": "important"
12
+ },
13
+ "outputPath": {
14
+ "type": "string",
15
+ "description": "Path to the directory in which to generate the metadata relative to the monorepo root",
16
+ "x-priority": "important"
17
+ }
18
+ },
19
+ "required": ["openApiSpecPath", "outputPath"]
20
+ }