@aws/nx-plugin-mcp 1.0.0-rc.2 → 1.0.0-rc.21
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 +5919 -4776
- package/docs/guides/agentcore-gateway.mdx +240 -0
- package/docs/guides/connection/agentcore-gateway-gateway.mdx +154 -0
- package/docs/guides/connection/agentcore-gateway-mcp.mdx +134 -0
- package/docs/guides/connection/py-agent-a2a.mdx +8 -5
- package/docs/guides/connection/py-agent-dynamodb.mdx +116 -0
- package/docs/guides/connection/py-agent-gateway.mdx +161 -0
- package/docs/guides/connection/py-agent-mcp.mdx +7 -4
- package/docs/guides/connection/py-fast-api-dynamodb.mdx +56 -0
- package/docs/guides/connection/py-mcp-server-dynamodb.mdx +116 -0
- package/docs/guides/connection/react-smithy.mdx +1 -1
- package/docs/guides/connection/react-trpc.mdx +1 -1
- package/docs/guides/connection/smithy-dynamodb.mdx +68 -0
- package/docs/guides/connection/smithy-rdb.mdx +1 -1
- package/docs/guides/connection/trpc-dynamodb.mdx +62 -0
- package/docs/guides/connection/trpc-rdb.mdx +1 -1
- package/docs/guides/connection/ts-agent-a2a.mdx +8 -5
- package/docs/guides/connection/ts-agent-dynamodb.mdx +128 -0
- package/docs/guides/connection/ts-agent-gateway.mdx +152 -0
- package/docs/guides/connection/ts-agent-mcp.mdx +7 -4
- package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +125 -0
- package/docs/guides/connection.mdx +89 -0
- package/docs/guides/docker-bundling.mdx +13 -7
- package/docs/guides/fastapi.mdx +213 -3
- package/docs/guides/license.mdx +264 -109
- package/docs/guides/local-development.mdx +76 -0
- package/docs/guides/nx-generator.mdx +5 -0
- package/docs/guides/py-agent.mdx +42 -3
- package/docs/guides/py-dynamodb.mdx +449 -0
- package/docs/guides/py-mcp-server.mdx +5 -1
- package/docs/guides/react-website-auth.mdx +15 -0
- package/docs/guides/react-website.mdx +12 -4
- package/docs/guides/trpc.mdx +8 -8
- package/docs/guides/ts-agent.mdx +40 -2
- package/docs/guides/ts-dynamodb.mdx +158 -0
- package/docs/guides/ts-mcp-server.mdx +5 -1
- package/docs/guides/ts-rdb.mdx +58 -10
- package/docs/guides/ts-smithy-api.mdx +148 -3
- package/docs/guides/typescript-project.mdx +5 -10
- package/docs/guides/workspace.mdx +8 -2
- package/docs/snippets/api/type-safe-api-integrations.mdx +31 -0
- package/docs/snippets/api/waf-configuration.mdx +1 -1
- package/docs/snippets/connection/dynamodb-local-development.mdx +7 -0
- package/docs/snippets/connection/lambda-dynamodb-access.mdx +80 -0
- package/docs/snippets/connection/py-dynamodb-local-development.mdx +7 -0
- package/docs/snippets/dynamodb/deploying-table.mdx +171 -0
- package/docs/snippets/dynamodb/gsi-config.mdx +38 -0
- package/docs/snippets/dynamodb/infrastructure.mdx +33 -0
- package/docs/snippets/dynamodb/serve-local-start.mdx +13 -0
- package/docs/snippets/dynamodb/serve-local-windows.mdx +15 -0
- package/docs/snippets/mcp/config.mdx +1 -1
- package/docs/snippets/required-prerequisites.mdx +1 -1
- package/generators.json +100 -1
- package/package.json +1 -1
- package/src/agentcore-gateway/gateway-connection/schema.json +26 -0
- package/src/agentcore-gateway/mcp-connection/schema.json +26 -0
- package/src/agentcore-gateway/schema.json +65 -0
- package/src/license/schema.json +6 -0
- package/src/preset/schema.json +5 -0
- package/src/py/agent/gateway-connection/schema.json +26 -0
- package/src/py/dynamodb/agent-connection/schema.json +22 -0
- package/src/py/dynamodb/fast-api-connection/schema.json +18 -0
- package/src/py/dynamodb/mcp-server-connection/schema.json +22 -0
- package/src/py/dynamodb/schema.json +70 -0
- package/src/ts/agent/gateway-connection/schema.json +26 -0
- package/src/ts/dynamodb/agent-connection/schema.json +22 -0
- package/src/ts/dynamodb/mcp-server-connection/schema.json +22 -0
- package/src/ts/dynamodb/schema.json +70 -0
- package/src/ts/dynamodb/smithy-connection/schema.json +18 -0
- package/src/ts/dynamodb/trpc-connection/schema.json +18 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TypeScript DynamoDB
|
|
3
|
+
description: Create a TypeScript DynamoDB project
|
|
4
|
+
generator: ts#dynamodb
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
import { FileTree } from '@astrojs/starlight/components';
|
|
8
|
+
import Link from '@components/link.astro';
|
|
9
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
10
|
+
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
11
|
+
import Snippet from '@components/snippet.astro';
|
|
12
|
+
|
|
13
|
+
This generator creates a new TypeScript DynamoDB project backed by [Amazon DynamoDB](https://aws.amazon.com/dynamodb/), using [ElectroDB](https://electrodb.dev/) for type-safe entity modelling. It generates the application code and infrastructure needed to provision and manage a DynamoDB table using AWS CDK or Terraform, with single-table design support and built-in local development via DynamoDB Local.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Generate a TypeScript DynamoDB Project
|
|
18
|
+
|
|
19
|
+
<RunGenerator generator="ts#dynamodb" />
|
|
20
|
+
|
|
21
|
+
### Options
|
|
22
|
+
|
|
23
|
+
<GeneratorParameters generator="ts#dynamodb" />
|
|
24
|
+
|
|
25
|
+
## Generator Output
|
|
26
|
+
|
|
27
|
+
The generator creates the following project structure in the `<directory>/<name>` directory:
|
|
28
|
+
|
|
29
|
+
<FileTree>
|
|
30
|
+
- src
|
|
31
|
+
- index.ts Project entry point and exports
|
|
32
|
+
- client.ts DynamoDB client singleton and table name resolution
|
|
33
|
+
- entities
|
|
34
|
+
- example.ts Example ElectroDB entity definition
|
|
35
|
+
- index.ts Entity exports
|
|
36
|
+
- config.json Table configuration including GSI definitions and local development settings
|
|
37
|
+
- project.json Project configuration and build targets
|
|
38
|
+
</FileTree>
|
|
39
|
+
|
|
40
|
+
The local development scripts are shared across all DynamoDB projects (both TypeScript and Python) and generated once into:
|
|
41
|
+
|
|
42
|
+
<FileTree>
|
|
43
|
+
- packages/common/scripts/src/dynamodb
|
|
44
|
+
- create-local-table.ts Creates the DynamoDB table in the local DynamoDB Local instance
|
|
45
|
+
- pull-image.ts Pulls the DynamoDB Local image
|
|
46
|
+
- start-container.ts Starts the DynamoDB Local container
|
|
47
|
+
</FileTree>
|
|
48
|
+
|
|
49
|
+
### Infrastructure
|
|
50
|
+
|
|
51
|
+
<Snippet name="dynamodb/infrastructure" />
|
|
52
|
+
|
|
53
|
+
## Local Development
|
|
54
|
+
|
|
55
|
+
### Starting Local DynamoDB
|
|
56
|
+
|
|
57
|
+
<Snippet name="dynamodb/serve-local-start" />
|
|
58
|
+
|
|
59
|
+
### Data Modelling
|
|
60
|
+
|
|
61
|
+
The generated project uses [ElectroDB](https://electrodb.dev/) for type-safe entity modelling on a single DynamoDB table, following [DynamoDB's single-table design](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/data-modeling-foundations.html). Add or update entity files under `src/entities/`, using the generated example entity as a starting point.
|
|
62
|
+
|
|
63
|
+
Example entity definition:
|
|
64
|
+
|
|
65
|
+
```ts title="packages/my-table/src/entities/example.ts"
|
|
66
|
+
import { Entity } from 'electrodb';
|
|
67
|
+
import { getDynamoDBClient, resolveTableName } from '../client.js';
|
|
68
|
+
|
|
69
|
+
export const createExampleEntity = async () =>
|
|
70
|
+
new Entity(
|
|
71
|
+
{
|
|
72
|
+
model: {
|
|
73
|
+
entity: 'example',
|
|
74
|
+
version: '1',
|
|
75
|
+
service: 'MyTable',
|
|
76
|
+
},
|
|
77
|
+
attributes: {
|
|
78
|
+
id: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
required: true,
|
|
81
|
+
},
|
|
82
|
+
createdAt: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
required: true,
|
|
85
|
+
default: () => new Date().toISOString(),
|
|
86
|
+
readOnly: true,
|
|
87
|
+
},
|
|
88
|
+
updatedAt: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
required: true,
|
|
91
|
+
default: () => new Date().toISOString(),
|
|
92
|
+
watch: '*',
|
|
93
|
+
set: () => new Date().toISOString(),
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
indexes: {
|
|
97
|
+
primary: {
|
|
98
|
+
pk: {
|
|
99
|
+
field: 'pk',
|
|
100
|
+
composite: ['id'],
|
|
101
|
+
},
|
|
102
|
+
sk: {
|
|
103
|
+
field: 'sk',
|
|
104
|
+
composite: [],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{ client: getDynamoDBClient(), table: await resolveTableName() },
|
|
110
|
+
);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For more details, see the [ElectroDB entity documentation](https://electrodb.dev/en/modeling/entities/).
|
|
114
|
+
|
|
115
|
+
### Using the DynamoDB Client
|
|
116
|
+
|
|
117
|
+
The generated `src/client.ts` exports two key utilities:
|
|
118
|
+
|
|
119
|
+
- `getDynamoDBClient()` — returns a cached singleton `DynamoDBClient`. When `SERVE_LOCAL=true`, connects to the local DynamoDB Local instance; otherwise creates an AWS client using the default credential chain.
|
|
120
|
+
- `resolveTableName()` — returns the DynamoDB table name. When `SERVE_LOCAL=true`, returns the local table name constant; otherwise fetches the name from AWS AppConfig using the `RUNTIME_CONFIG_APP_ID` environment variable and caches it for subsequent calls.
|
|
121
|
+
|
|
122
|
+
### Stopping Local DynamoDB
|
|
123
|
+
|
|
124
|
+
<Snippet name="dynamodb/serve-local-windows" />
|
|
125
|
+
|
|
126
|
+
## Adding/Removing Global Secondary Indexes
|
|
127
|
+
|
|
128
|
+
GSIs are defined in `config.json` at the project root under the `tableConfig.globalSecondaryIndexes` key. Add an entry for each GSI, following the [single-table design](https://electrodb.dev/en/core-concepts/single-table-relationships/) naming convention for GSI keys:
|
|
129
|
+
|
|
130
|
+
<Snippet name="dynamodb/gsi-config" parentHeading="Adding/Removing Global Secondary Indexes" />
|
|
131
|
+
|
|
132
|
+
## Connecting to the Table
|
|
133
|
+
|
|
134
|
+
In any TypeScript project, import entity factories from your DynamoDB package and use them directly:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { createExampleEntity } from ':my-scope/my-table';
|
|
138
|
+
|
|
139
|
+
const entity = await createExampleEntity();
|
|
140
|
+
const result = await entity.query.primary({ id: '123' }).go();
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
:::note[Runtime config]
|
|
144
|
+
When running in AWS, `resolveTableName()` fetches the table name from AWS AppConfig using the `RUNTIME_CONFIG_APP_ID` environment variable. Projects built with this plugin (tRPC APIs, Smithy APIs, agents, MCP servers) already have this variable configured automatically. For other TypeScript projects, ensure `RUNTIME_CONFIG_APP_ID` is set in the runtime environment with the AppConfig application ID provisioned by your infrastructure. For more information, see the <Link path="guides/runtime-config">Runtime Configuration guide</Link>.
|
|
145
|
+
:::
|
|
146
|
+
|
|
147
|
+
### Connection Generators
|
|
148
|
+
|
|
149
|
+
For specific project types, use the `connection` generator to automatically wire up local development dependencies so DynamoDB Local starts automatically alongside your project:
|
|
150
|
+
|
|
151
|
+
- <Link path="guides/connection/trpc-dynamodb">tRPC API → DynamoDB</Link>
|
|
152
|
+
- <Link path="guides/connection/smithy-dynamodb">Smithy API → DynamoDB</Link>
|
|
153
|
+
- <Link path="guides/connection/ts-agent-dynamodb">TypeScript Agent → DynamoDB</Link>
|
|
154
|
+
- <Link path="guides/connection/ts-mcp-server-dynamodb">MCP Server → DynamoDB</Link>
|
|
155
|
+
|
|
156
|
+
## Deploying your Table
|
|
157
|
+
|
|
158
|
+
<Snippet name="dynamodb/deploying-table" parentHeading="Deploying your Table" />
|
|
@@ -122,12 +122,16 @@ server.registerResource('dynamic-resource', 'dynamic://resource', {}, async (uri
|
|
|
122
122
|
|
|
123
123
|
### Inspector
|
|
124
124
|
|
|
125
|
-
The generator configures a target named `<your-server-name>-inspect`, which starts the [MCP Inspector](https://github.com/modelcontextprotocol/inspector)
|
|
125
|
+
The generator configures a target named `<your-server-name>-inspect`, which starts your MCP server locally (via the `<your-server-name>-serve-local` target, including any connected dependencies such as a local database) and launches the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) pre-configured to connect to it over Streamable HTTP transport.
|
|
126
126
|
|
|
127
127
|
<NxCommands commands={['your-server-name-inspect your-project']} />
|
|
128
128
|
|
|
129
129
|
This will start the inspector at `http://localhost:6274`. Get started by clicking on the "Connect" button.
|
|
130
130
|
|
|
131
|
+
:::tip
|
|
132
|
+
To inspect the server using STDIO transport instead, use the `<your-server-name>-inspect-stdio` target, which launches the inspector against a STDIO instance of your server.
|
|
133
|
+
:::
|
|
134
|
+
|
|
131
135
|
### STDIO
|
|
132
136
|
|
|
133
137
|
The easiest way to test and use an MCP server is by using the inspector or configuring it with an AI assistant (as above).
|
package/docs/guides/ts-rdb.mdx
CHANGED
|
@@ -37,23 +37,28 @@ The generator will create the following project structure in the `<directory>/<n
|
|
|
37
37
|
- models
|
|
38
38
|
- example.prisma Example model definition
|
|
39
39
|
- schema.prisma Main Prisma schema (references models)
|
|
40
|
-
- scripts
|
|
41
|
-
- docker-pull.ts Pulls the database Docker image for local development
|
|
42
|
-
- docker-start.ts Starts a local database container
|
|
43
|
-
- wait-for-db.ts Waits for the local database to be ready
|
|
44
40
|
- src
|
|
45
41
|
- index.ts Project entry point
|
|
46
|
-
- constants.ts Local development connection details and runtime config key
|
|
47
42
|
- prisma.ts Prisma runtime client wrapper
|
|
48
43
|
- utils.ts Runtime config and secret helpers
|
|
49
44
|
- create-db-user-handler.ts Lambda handler used to create the application database user during deployment
|
|
50
45
|
- migration-handler.ts Lambda handler used to run database migrations during deployment
|
|
51
46
|
- .gitignore Git ignore entries including generated Prisma client output
|
|
47
|
+
- config.json Local development connection details and runtime config key
|
|
52
48
|
- Dockerfile Container image definition for the migration handler
|
|
53
49
|
- project.json Project configuration and build targets
|
|
54
50
|
- prisma.config.ts Configuration for Prisma CLI
|
|
55
51
|
</FileTree>
|
|
56
52
|
|
|
53
|
+
Local development scripts are shared across all database projects and generated into `packages/common/scripts/`:
|
|
54
|
+
|
|
55
|
+
<FileTree>
|
|
56
|
+
- packages/common/scripts/src/rdb
|
|
57
|
+
- pull-image.ts Pulls the database container image
|
|
58
|
+
- start-container.ts Starts a local database container
|
|
59
|
+
- wait-for-db.ts Waits for the local database to be ready
|
|
60
|
+
</FileTree>
|
|
61
|
+
|
|
57
62
|
### Infrastructure
|
|
58
63
|
|
|
59
64
|
<Snippet name="shared-constructs" />
|
|
@@ -156,7 +161,6 @@ Use the `prisma` target to run Prisma CLI commands from the workspace root:
|
|
|
156
161
|
|
|
157
162
|
The runtime wrapper in `src/prisma.ts` exports:
|
|
158
163
|
|
|
159
|
-
- `DB_PACKAGE_NAME` - the key used under the `database` runtime config namespace in AWS AppConfig
|
|
160
164
|
- `getPrisma()` - loads database connection settings from AWS AppConfig and creates a Prisma client using IAM authentication
|
|
161
165
|
|
|
162
166
|
The client automatically:
|
|
@@ -169,7 +173,7 @@ The client automatically:
|
|
|
169
173
|
|
|
170
174
|
After adding or updating models under `prisma/models/`, use `migrate dev` to generate migration files and apply them to your local database at the same time.
|
|
171
175
|
|
|
172
|
-
The generated `prisma` target automatically starts a local database
|
|
176
|
+
The generated `prisma` target automatically starts a local database container before running:
|
|
173
177
|
|
|
174
178
|
<NxCommands commands={['run <project>:prisma migrate dev']} />
|
|
175
179
|
|
|
@@ -204,12 +208,26 @@ The generated `prisma` target exposes the Prisma CLI, so you can use it to run a
|
|
|
204
208
|
|
|
205
209
|
<NxCommands commands={['run <project>:prisma <prisma-command>']} />
|
|
206
210
|
|
|
207
|
-
### Prisma Studio
|
|
211
|
+
### Using Prisma Studio
|
|
208
212
|
|
|
209
213
|
[Prisma Studio](https://www.prisma.io/studio) is a visual editor for your local database. Use it to browse tables, inspect and edit records, filter data, follow relations, and run raw SQL via the built-in SQL console. It is useful for verifying migrations and seeding test data during development. Launch it with:
|
|
210
214
|
|
|
211
215
|
<NxCommands commands={['run <project>:prisma studio']} />
|
|
212
216
|
|
|
217
|
+
### Stopping the Local Database
|
|
218
|
+
|
|
219
|
+
Stopping `serve-local` (e.g. with `Ctrl+C`) automatically removes the local database container, but preserves the named volume so your data persists across restarts.
|
|
220
|
+
|
|
221
|
+
:::caution[Windows]
|
|
222
|
+
Due to limitations with signal handling on Windows, the container is not automatically removed when `serve-local` is stopped. You will need to remove it manually:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
<engine> rm -f <scope>-<db-name>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Replace `<engine>` with your container engine (`docker` or `finch`), `<scope>` with your Nx workspace scope (e.g. `proj`), and `<db-name>` with your database project name (e.g. `my-db`).
|
|
229
|
+
:::
|
|
230
|
+
|
|
213
231
|
## Connecting to the Database
|
|
214
232
|
|
|
215
233
|
In any TypeScript project, import `getPrisma` from your database package and call it to get a type-safe Prisma client:
|
|
@@ -524,9 +542,9 @@ module "my_database" {
|
|
|
524
542
|
|
|
525
543
|
Pin a specific Aurora engine version.
|
|
526
544
|
|
|
527
|
-
By default, the generated local
|
|
545
|
+
By default, the generated local database container image matches the default Aurora engine version. If you change the Aurora engine version, it's recommended to also use a matching local container image version for maximum compatibility. See the AWS release notes for [Aurora PostgreSQL versions](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/aurorapostgresql-release-calendar.html) and [Aurora MySQL versions](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraMySQLReleaseNotes/AuroraMySQL.Updates.30Updates.html) to identify the corresponding community database version.
|
|
528
546
|
|
|
529
|
-
The local database image is configured in the
|
|
547
|
+
The local database image is configured in the `serveLocal.image` field of the generated `config.json` file in your database project root. Update that value when you change engine versions.
|
|
530
548
|
|
|
531
549
|
<OptionFilter when={{ engine: 'postgres' }}>
|
|
532
550
|
<Infrastructure>
|
|
@@ -659,6 +677,36 @@ module "my_database" {
|
|
|
659
677
|
</Fragment>
|
|
660
678
|
</Infrastructure>
|
|
661
679
|
|
|
680
|
+
### Logging and Monitoring
|
|
681
|
+
|
|
682
|
+
Performance Insights is enabled on the Aurora writer instance by default (encrypted with the cluster's KMS key). You can also export the Aurora engine logs to [CloudWatch Logs](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_LogAccess.html) (`postgresql` for [Aurora PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.CloudWatch.html); `audit`, `error`, `general` and `slowquery` for [Aurora MySQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.CloudWatch.html)). Enable log export per database:
|
|
683
|
+
|
|
684
|
+
<Infrastructure>
|
|
685
|
+
<Fragment slot="cdk">
|
|
686
|
+
|
|
687
|
+
```ts title="packages/infra/src/stacks/application-stack.ts"
|
|
688
|
+
import { MyDatabase } from ':my-scope/common-constructs';
|
|
689
|
+
|
|
690
|
+
const db = new MyDatabase(this, 'Db', {
|
|
691
|
+
...
|
|
692
|
+
enableCloudwatchLogs: true,
|
|
693
|
+
enablePerformanceInsights: false, // disable if not required
|
|
694
|
+
});
|
|
695
|
+
```
|
|
696
|
+
</Fragment>
|
|
697
|
+
<Fragment slot="terraform">
|
|
698
|
+
|
|
699
|
+
```hcl title="packages/infra/src/main.tf"
|
|
700
|
+
module "my_database" {
|
|
701
|
+
source = "../../common/terraform/src/app/dbs/my-database"
|
|
702
|
+
...
|
|
703
|
+
enable_cloudwatch_logs = true
|
|
704
|
+
enable_performance_insights = false # disable if not required
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
</Fragment>
|
|
708
|
+
</Infrastructure>
|
|
709
|
+
|
|
662
710
|
### Encryption Key Rotation
|
|
663
711
|
|
|
664
712
|
The KMS key used to encrypt the Aurora cluster and its credentials secret has automatic key rotation enabled by default. Disable it if your security policy manages rotation externally.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Smithy TypeScript API
|
|
3
3
|
description: Reference documentation for Smithy TypeScript API
|
|
4
|
-
generator: ts#
|
|
4
|
+
generator: ts#api
|
|
5
5
|
when:
|
|
6
6
|
framework: [smithy]
|
|
7
7
|
infra: [rest-lambda]
|
|
@@ -27,11 +27,11 @@ The Smithy TypeScript API generator creates a new API using Smithy for service d
|
|
|
27
27
|
|
|
28
28
|
You can generate a new Smithy TypeScript API in two ways:
|
|
29
29
|
|
|
30
|
-
<RunGenerator generator="ts#
|
|
30
|
+
<RunGenerator generator="ts#api" requiredParameters={{ framework: 'smithy' }} />
|
|
31
31
|
|
|
32
32
|
### Options
|
|
33
33
|
|
|
34
|
-
<GeneratorParameters generator="ts#
|
|
34
|
+
<GeneratorParameters generator="ts#api" />
|
|
35
35
|
|
|
36
36
|
:::tip[Integration Pattern]
|
|
37
37
|
The `integrationPattern` option defaults to `isolated`, which creates one Lambda per Smithy operation. Select `shared` if you would prefer a single shared Lambda handler for the whole API, with optional per-operation overrides.
|
|
@@ -401,6 +401,151 @@ export const MyOperation: MyOperationHandler<ServiceContext> = async (input) =>
|
|
|
401
401
|
};
|
|
402
402
|
```
|
|
403
403
|
|
|
404
|
+
### Accessing the Calling User
|
|
405
|
+
|
|
406
|
+
When your API is protected by authentication, your operations often need to know who is calling. The recommended approach is to resolve the caller's identity once in the handler and pass it through the [service context](#service-context) for consumption by specific operations.
|
|
407
|
+
|
|
408
|
+
We'll model the unauthorized case as a Smithy error so it serializes to a proper `403` response. Add it to your model, for example in `model/src/operations/errors.smithy`, and reference it on any operation that requires identity:
|
|
409
|
+
|
|
410
|
+
```smithy
|
|
411
|
+
$version: "2.0"
|
|
412
|
+
|
|
413
|
+
namespace your.namespace
|
|
414
|
+
|
|
415
|
+
/// Thrown when the calling user cannot be determined
|
|
416
|
+
@error("client")
|
|
417
|
+
@httpError(403)
|
|
418
|
+
structure UnauthorizedError {
|
|
419
|
+
@required
|
|
420
|
+
message: String
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
First, expose the resolved identity on the service context in `src/context.ts`. We provide it as a function so that the `UnauthorizedError` is thrown from within an operation (where the Server SDK serializes it to a `403`), rather than from the handler:
|
|
425
|
+
|
|
426
|
+
```ts {4-7,15} ins={4-7,15}
|
|
427
|
+
import { Logger } from '@aws-lambda-powertools/logger';
|
|
428
|
+
import { Metrics } from '@aws-lambda-powertools/metrics';
|
|
429
|
+
import { Tracer } from '@aws-lambda-powertools/tracer';
|
|
430
|
+
|
|
431
|
+
export interface Identity {
|
|
432
|
+
sub: string;
|
|
433
|
+
username: string;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Context provided to all operations.
|
|
438
|
+
*/
|
|
439
|
+
export interface ServiceContext {
|
|
440
|
+
tracer: Tracer;
|
|
441
|
+
logger: Logger;
|
|
442
|
+
metrics: Metrics;
|
|
443
|
+
getIdentity: () => Promise<Identity>;
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Next, write the resolver in `src/identity.ts`. It throws `UnauthorizedError` when the caller cannot be determined. The implementation depends on your selected `auth` method:
|
|
448
|
+
|
|
449
|
+
<OptionFilter when={{ auth: 'iam' }} description="Identity resolution for IAM-authenticated APIs">
|
|
450
|
+
For `IAM` authentication, we look up the caller in Cognito using the sub extracted from the API Gateway event:
|
|
451
|
+
|
|
452
|
+
```ts
|
|
453
|
+
import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider';
|
|
454
|
+
import type { APIGatewayProxyEvent } from 'aws-lambda';
|
|
455
|
+
import { Identity } from './context.js';
|
|
456
|
+
import { UnauthorizedError } from './generated/ssdk/index.js';
|
|
457
|
+
|
|
458
|
+
const cognito = new CognitoIdentityProvider();
|
|
459
|
+
|
|
460
|
+
export const getIdentity = async (
|
|
461
|
+
event: APIGatewayProxyEvent,
|
|
462
|
+
): Promise<Identity> => {
|
|
463
|
+
const cognitoAuthenticationProvider =
|
|
464
|
+
event.requestContext?.identity?.cognitoAuthenticationProvider;
|
|
465
|
+
|
|
466
|
+
let sub: string | undefined = undefined;
|
|
467
|
+
if (cognitoAuthenticationProvider) {
|
|
468
|
+
const providerParts = cognitoAuthenticationProvider.split(':');
|
|
469
|
+
sub = providerParts[providerParts.length - 1];
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (!sub) {
|
|
473
|
+
throw new UnauthorizedError({ message: 'Unable to determine calling user' });
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const { Users } = await cognito.listUsers({
|
|
477
|
+
// Assumes user pool id is configured in lambda environment
|
|
478
|
+
UserPoolId: process.env.USER_POOL_ID!,
|
|
479
|
+
Limit: 1,
|
|
480
|
+
Filter: `sub="${sub}"`,
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
if (!Users || Users.length !== 1) {
|
|
484
|
+
throw new UnauthorizedError({ message: `No user found with subjectId ${sub}` });
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return { sub, username: Users[0].Username! };
|
|
488
|
+
};
|
|
489
|
+
```
|
|
490
|
+
</OptionFilter>
|
|
491
|
+
|
|
492
|
+
<OptionFilter when={{ auth: 'cognito' }} description="Identity resolution for Cognito-authenticated APIs">
|
|
493
|
+
With `auth: 'cognito'`, the API Gateway Cognito User Pools authorizer verifies the JWT that the caller supplies in the `Authorization` header and places the verified claims on the event at `event.requestContext.authorizer.claims`:
|
|
494
|
+
|
|
495
|
+
```ts
|
|
496
|
+
import type { APIGatewayProxyEvent } from 'aws-lambda';
|
|
497
|
+
import { Identity } from './context.js';
|
|
498
|
+
import { UnauthorizedError } from './generated/ssdk/index.js';
|
|
499
|
+
|
|
500
|
+
export const getIdentity = async (
|
|
501
|
+
event: APIGatewayProxyEvent,
|
|
502
|
+
): Promise<Identity> => {
|
|
503
|
+
const claims = event.requestContext?.authorizer?.claims as
|
|
504
|
+
| Record<string, string>
|
|
505
|
+
| undefined;
|
|
506
|
+
|
|
507
|
+
const sub = claims?.sub;
|
|
508
|
+
const username = claims?.username;
|
|
509
|
+
|
|
510
|
+
if (!sub || !username) {
|
|
511
|
+
throw new UnauthorizedError({ message: 'Unable to determine calling user' });
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return { sub, username };
|
|
515
|
+
};
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
:::tip[No token verification required]
|
|
519
|
+
You don't need `aws-jwt-verify` or any other JWT-verification library here — the API Gateway Cognito User Pools authorizer has already verified the signature, issuer, scopes, and expiry by the time your Lambda runs. If any of those checks fail, API Gateway returns `401 Unauthorized` and your handler is never invoked.
|
|
520
|
+
:::
|
|
521
|
+
</OptionFilter>
|
|
522
|
+
|
|
523
|
+
Then wire the resolver into the context in `src/handler.ts`:
|
|
524
|
+
|
|
525
|
+
```ts {2,8} ins={2,8}
|
|
526
|
+
import { Service } from './service.js';
|
|
527
|
+
import { getIdentity } from './identity.js';
|
|
528
|
+
// ...
|
|
529
|
+
const httpResponse = await serviceHandler.handle(httpRequest, {
|
|
530
|
+
tracer,
|
|
531
|
+
logger,
|
|
532
|
+
metrics,
|
|
533
|
+
getIdentity: () => getIdentity(event),
|
|
534
|
+
});
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
We can now use the resolved identity in an operation, for example in `src/operations/echo.ts`:
|
|
538
|
+
|
|
539
|
+
```ts
|
|
540
|
+
import { ServiceContext } from '../context.js';
|
|
541
|
+
import { Echo as EchoOperation } from '../generated/ssdk/index.js';
|
|
542
|
+
|
|
543
|
+
export const Echo: EchoOperation<ServiceContext> = async (input, ctx) => {
|
|
544
|
+
const identity = await ctx.getIdentity();
|
|
545
|
+
return { message: `${identity.username} says ${input.message}` };
|
|
546
|
+
};
|
|
547
|
+
```
|
|
548
|
+
|
|
404
549
|
## Building and Code Generation
|
|
405
550
|
|
|
406
551
|
The Smithy model project uses [Docker](https://www.docker.com/) to build the Smithy artifacts and generate the TypeScript Server SDK:
|
|
@@ -11,7 +11,7 @@ import NxCommands from '@components/nx-commands.astro';
|
|
|
11
11
|
import PackageManagerShortCommand from '@components/package-manager-short-command.astro';
|
|
12
12
|
import Link from '@components/link.astro';
|
|
13
13
|
|
|
14
|
-
The TypeScript project generator can be used to create a modern [TypeScript](https://www.typescriptlang.org/) library or application configured with best practices such as [ECMAScript Modules (ESM)](https://www.typescriptlang.org/docs/handbook/modules/reference.html), TypeScript [project references](https://www.typescriptlang.org/docs/handbook/project-references.html), [Vitest](https://vitest.dev/) for running tests and [
|
|
14
|
+
The TypeScript project generator can be used to create a modern [TypeScript](https://www.typescriptlang.org/) library or application configured with best practices such as [ECMAScript Modules (ESM)](https://www.typescriptlang.org/docs/handbook/modules/reference.html), TypeScript [project references](https://www.typescriptlang.org/docs/handbook/project-references.html), [Vitest](https://vitest.dev/) for running tests and [Biome](https://biomejs.dev/) for linting and formatting.
|
|
15
15
|
|
|
16
16
|
## Usage
|
|
17
17
|
|
|
@@ -38,7 +38,6 @@ The generator will create the following project structure in the `<directory>/<n
|
|
|
38
38
|
- tsconfig.lib.json TypeScript configuration for your library (your runtime or packaged source)
|
|
39
39
|
- tsconfig.spec.json TypeScript configuration for your tests
|
|
40
40
|
- vitest.config.mts Configuration for Vitest
|
|
41
|
-
- eslint.config.mjs Configuration for ESLint
|
|
42
41
|
|
|
43
42
|
</FileTree>
|
|
44
43
|
|
|
@@ -198,7 +197,7 @@ If you're building an AWS Lambda function, check out the <Link path="/guides/ts-
|
|
|
198
197
|
|
|
199
198
|
If you are publishing your TypeScript project to NPM, you must create a `package.json` file for it.
|
|
200
199
|
|
|
201
|
-
This must declare the dependencies that your project references. Since at build time your project will resolve dependencies installed via the workspace root `package.json`,
|
|
200
|
+
This must declare the dependencies that your project references. Since at build time your project will resolve dependencies installed via the workspace root `package.json`, Biome's `noUndeclaredDependencies` rule will warn you if your project imports a package that isn't listed in its `package.json`.
|
|
202
201
|
|
|
203
202
|
### Building
|
|
204
203
|
|
|
@@ -269,11 +268,7 @@ If you are a VSCode user, we recommend installing the [Vitest Runner for VSCode
|
|
|
269
268
|
|
|
270
269
|
## Linting
|
|
271
270
|
|
|
272
|
-
TypeScript projects use [
|
|
273
|
-
|
|
274
|
-
We recommend configuring ESLint in the workspace root `eslint.config.mjs` file, as changes to this will apply to all TypeScript projects in your workspace and ensure consistency.
|
|
275
|
-
|
|
276
|
-
Likewise, you can configure Prettier in the root `.prettierrc` file.
|
|
271
|
+
TypeScript projects use [Biome](https://biomejs.dev/) for linting and formatting. Biome is configured in the workspace root `biome.json` file — changes to this apply to all TypeScript projects in your workspace and ensure consistency.
|
|
277
272
|
|
|
278
273
|
### Running the Linter
|
|
279
274
|
|
|
@@ -283,7 +278,7 @@ To invoke the linter to check your project, you can run the `lint` target.
|
|
|
283
278
|
|
|
284
279
|
### Fixing Lint Issues
|
|
285
280
|
|
|
286
|
-
The majority of linting or formatting issues can be fixed automatically
|
|
281
|
+
The majority of linting or formatting issues can be fixed automatically by running with the `--configuration=fix` argument.
|
|
287
282
|
|
|
288
283
|
<NxCommands commands={["lint <project-name> --configuration=fix"]} />
|
|
289
284
|
|
|
@@ -303,7 +298,7 @@ To avoid linting issues slowing you down during development (particularly if you
|
|
|
303
298
|
|
|
304
299
|
<NxCommands commands={["run-many --target build --configuration=skip-lint"]} />
|
|
305
300
|
|
|
306
|
-
This
|
|
301
|
+
This skips the lint target entirely during build.
|
|
307
302
|
|
|
308
303
|
:::tip[Shorthand Command]
|
|
309
304
|
This has a shorthand command from the root of your workspace:
|
|
@@ -29,6 +29,12 @@ When you create a new workspace with `@aws/nx-plugin`, the preset generator sets
|
|
|
29
29
|
- aws-nx-plugin.config.mts Nx Plugin for AWS configuration
|
|
30
30
|
- .git-secrets/ Vendored git-secrets bash script for credential scanning
|
|
31
31
|
- .husky/ Git hooks
|
|
32
|
+
- .mcp.json Nx Plugin for AWS MCP server configuration for Claude Code
|
|
33
|
+
- .cursor/mcp.json ...and for Cursor
|
|
34
|
+
- .kiro/settings/mcp.json ...and for Kiro
|
|
35
|
+
- .gemini/settings.json ...and for Gemini CLI
|
|
36
|
+
- .vscode/mcp.json ...and for GitHub Copilot
|
|
37
|
+
- .codex/config.toml ...and for OpenAI Codex
|
|
32
38
|
</FileTree>
|
|
33
39
|
|
|
34
40
|
## Nx
|
|
@@ -128,7 +134,7 @@ This will run the chosen target as well as the targets it depends on.
|
|
|
128
134
|
|
|
129
135
|
### Linting
|
|
130
136
|
|
|
131
|
-
New workspaces are configured with [
|
|
137
|
+
New workspaces are configured with [Biome](https://biomejs.dev/) for static analysis and code formatting. Running `lint` checks all projects for issues, and `lint --configuration=fix` auto-fixes them.
|
|
132
138
|
|
|
133
139
|
### Git Secrets
|
|
134
140
|
|
|
@@ -175,7 +181,7 @@ export default {
|
|
|
175
181
|
} satisfies AwsNxPluginConfig;
|
|
176
182
|
```
|
|
177
183
|
|
|
178
|
-
- **`iac.provider`** — the default infrastructure-as-code provider (`cdk` or `terraform`) used by generators that emit infrastructure (e.g. `ts#infra`, `ts#
|
|
184
|
+
- **`iac.provider`** — the default infrastructure-as-code provider (`cdk` or `terraform`) used by generators that emit infrastructure (e.g. `ts#infra`, `ts#api`, `py#api`). Generators that accept an `--iac` flag default to `inherit`, which reads this value.
|
|
179
185
|
- **`containers.engine`** — the container CLI (`docker` or `finch`) baked into generated build/push/login commands. CDK image-asset builds also pick this up via the `CDK_DOCKER` environment variable. See the <Link path="guides/docker-bundling">Docker bundling guide</Link> for details.
|
|
180
186
|
|
|
181
187
|
You can edit either setting at any time — subsequent generator runs will pick up the new value.
|
|
@@ -172,6 +172,37 @@ module "my_api" {
|
|
|
172
172
|
</Fragment>
|
|
173
173
|
</Infrastructure>
|
|
174
174
|
|
|
175
|
+
#### Customising Options Per-Operation
|
|
176
|
+
|
|
177
|
+
<Infrastructure>
|
|
178
|
+
<Fragment slot="cdk">
|
|
179
|
+
To customise the options used to create the default integration for _specific_ operations (without affecting the others), you can use the `withOperationOptions` method. For example, if you would like to increase the Lambda function timeout for just one operation:
|
|
180
|
+
|
|
181
|
+
```ts {4-6}
|
|
182
|
+
const api = new MyApi(this, 'MyApi', {
|
|
183
|
+
integrations: MyApi.defaultIntegrations(this)
|
|
184
|
+
.withOperationOptions({
|
|
185
|
+
sayHello: {
|
|
186
|
+
timeout: Duration.seconds(60),
|
|
187
|
+
},
|
|
188
|
+
})
|
|
189
|
+
.build(),
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// The selected operations remain default integrations, so they're still typed accordingly:
|
|
193
|
+
api.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({ ... }));
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The options you specify are merged with the default integration options (and any options set via `withDefaultOptions`). Note that you cannot specify options for operations which you have replaced via `withOverrides`, since these no longer use the default integration.
|
|
197
|
+
|
|
198
|
+
You will encounter a type error if the same operation is targeted by both `withOperationOptions` and `withOverrides`, regardless of the order in which you call them.
|
|
199
|
+
|
|
200
|
+
</Fragment>
|
|
201
|
+
<Fragment slot="terraform">
|
|
202
|
+
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).
|
|
203
|
+
</Fragment>
|
|
204
|
+
</Infrastructure>
|
|
205
|
+
|
|
175
206
|
#### Overriding Integrations
|
|
176
207
|
|
|
177
208
|
<Infrastructure>
|
|
@@ -6,7 +6,7 @@ import Infrastructure from '@components/infrastructure.astro';
|
|
|
6
6
|
For REST APIs, the generated construct associates an [AWS WAFv2](https://docs.aws.amazon.com/waf/latest/developerguide/waf-chapter.html) Web ACL with the API Gateway stage by default. The Web ACL uses the AWS managed default ruleset ([`AWSManagedRulesCommonRuleSet`](https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-baseline.html#aws-managed-rule-groups-baseline-crs) and [`AWSManagedRulesKnownBadInputsRuleSet`](https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-baseline.html#aws-managed-rule-groups-baseline-known-bad-inputs)), providing protection against common web exploits including the OWASP Top 10. WAF request logs are written to a CloudWatch Logs group.
|
|
7
7
|
|
|
8
8
|
:::caution[SizeRestrictions_BODY deviation from defaults]
|
|
9
|
-
The `SizeRestrictions_BODY` rule from `AWSManagedRulesCommonRuleSet` is overridden to `Count` rather than `Block`, since the rule's 8 KB limit is too restrictive for most APIs. Oversized requests will still be recorded as metrics so you can monitor them. See the [AWS WAF body size limits](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-oversize-handling.html) guide for more details.
|
|
9
|
+
The `SizeRestrictions_BODY` rule from `AWSManagedRulesCommonRuleSet` is overridden to `Count` rather than `Block`, since the rule's 8 KB limit is too restrictive for most APIs. Oversized requests will still be recorded as metrics so you can monitor them. See the [AWS WAF body size limits](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-oversize-handling.html) guide for more details. API Gateway natively enforces its [maximum payload size of 10 MB](https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html), returning a `413` for larger requests.
|
|
10
10
|
:::
|
|
11
11
|
|
|
12
12
|
You can edit the generated rest-api construct to add, remove, or adjust rules (for example, to add [rate-based rules](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-rate-based.html) or additional managed rule groups).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: DynamoDB Local Development
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The `connection` generator configures your project's `serve-local` target to depend on the DynamoDB project's `serve-local` target. DynamoDB Local will start automatically alongside your project when running `serve-local`.
|
|
6
|
+
|
|
7
|
+
The `SERVE_LOCAL=true` environment variable is set automatically, so `getDynamoDBClient()` and `resolveTableName()` connect to the local DynamoDB Local instance instead of AWS.
|