@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.
Files changed (70) hide show
  1. package/bin/aws-nx-mcp.js +5919 -4776
  2. package/docs/guides/agentcore-gateway.mdx +240 -0
  3. package/docs/guides/connection/agentcore-gateway-gateway.mdx +154 -0
  4. package/docs/guides/connection/agentcore-gateway-mcp.mdx +134 -0
  5. package/docs/guides/connection/py-agent-a2a.mdx +8 -5
  6. package/docs/guides/connection/py-agent-dynamodb.mdx +116 -0
  7. package/docs/guides/connection/py-agent-gateway.mdx +161 -0
  8. package/docs/guides/connection/py-agent-mcp.mdx +7 -4
  9. package/docs/guides/connection/py-fast-api-dynamodb.mdx +56 -0
  10. package/docs/guides/connection/py-mcp-server-dynamodb.mdx +116 -0
  11. package/docs/guides/connection/react-smithy.mdx +1 -1
  12. package/docs/guides/connection/react-trpc.mdx +1 -1
  13. package/docs/guides/connection/smithy-dynamodb.mdx +68 -0
  14. package/docs/guides/connection/smithy-rdb.mdx +1 -1
  15. package/docs/guides/connection/trpc-dynamodb.mdx +62 -0
  16. package/docs/guides/connection/trpc-rdb.mdx +1 -1
  17. package/docs/guides/connection/ts-agent-a2a.mdx +8 -5
  18. package/docs/guides/connection/ts-agent-dynamodb.mdx +128 -0
  19. package/docs/guides/connection/ts-agent-gateway.mdx +152 -0
  20. package/docs/guides/connection/ts-agent-mcp.mdx +7 -4
  21. package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +125 -0
  22. package/docs/guides/connection.mdx +89 -0
  23. package/docs/guides/docker-bundling.mdx +13 -7
  24. package/docs/guides/fastapi.mdx +213 -3
  25. package/docs/guides/license.mdx +264 -109
  26. package/docs/guides/local-development.mdx +76 -0
  27. package/docs/guides/nx-generator.mdx +5 -0
  28. package/docs/guides/py-agent.mdx +42 -3
  29. package/docs/guides/py-dynamodb.mdx +449 -0
  30. package/docs/guides/py-mcp-server.mdx +5 -1
  31. package/docs/guides/react-website-auth.mdx +15 -0
  32. package/docs/guides/react-website.mdx +12 -4
  33. package/docs/guides/trpc.mdx +8 -8
  34. package/docs/guides/ts-agent.mdx +40 -2
  35. package/docs/guides/ts-dynamodb.mdx +158 -0
  36. package/docs/guides/ts-mcp-server.mdx +5 -1
  37. package/docs/guides/ts-rdb.mdx +58 -10
  38. package/docs/guides/ts-smithy-api.mdx +148 -3
  39. package/docs/guides/typescript-project.mdx +5 -10
  40. package/docs/guides/workspace.mdx +8 -2
  41. package/docs/snippets/api/type-safe-api-integrations.mdx +31 -0
  42. package/docs/snippets/api/waf-configuration.mdx +1 -1
  43. package/docs/snippets/connection/dynamodb-local-development.mdx +7 -0
  44. package/docs/snippets/connection/lambda-dynamodb-access.mdx +80 -0
  45. package/docs/snippets/connection/py-dynamodb-local-development.mdx +7 -0
  46. package/docs/snippets/dynamodb/deploying-table.mdx +171 -0
  47. package/docs/snippets/dynamodb/gsi-config.mdx +38 -0
  48. package/docs/snippets/dynamodb/infrastructure.mdx +33 -0
  49. package/docs/snippets/dynamodb/serve-local-start.mdx +13 -0
  50. package/docs/snippets/dynamodb/serve-local-windows.mdx +15 -0
  51. package/docs/snippets/mcp/config.mdx +1 -1
  52. package/docs/snippets/required-prerequisites.mdx +1 -1
  53. package/generators.json +100 -1
  54. package/package.json +1 -1
  55. package/src/agentcore-gateway/gateway-connection/schema.json +26 -0
  56. package/src/agentcore-gateway/mcp-connection/schema.json +26 -0
  57. package/src/agentcore-gateway/schema.json +65 -0
  58. package/src/license/schema.json +6 -0
  59. package/src/preset/schema.json +5 -0
  60. package/src/py/agent/gateway-connection/schema.json +26 -0
  61. package/src/py/dynamodb/agent-connection/schema.json +22 -0
  62. package/src/py/dynamodb/fast-api-connection/schema.json +18 -0
  63. package/src/py/dynamodb/mcp-server-connection/schema.json +22 -0
  64. package/src/py/dynamodb/schema.json +70 -0
  65. package/src/ts/agent/gateway-connection/schema.json +26 -0
  66. package/src/ts/dynamodb/agent-connection/schema.json +22 -0
  67. package/src/ts/dynamodb/mcp-server-connection/schema.json +22 -0
  68. package/src/ts/dynamodb/schema.json +70 -0
  69. package/src/ts/dynamodb/smithy-connection/schema.json +18 -0
  70. 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) with the configuration to connect to your MCP server using STDIO transport.
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).
@@ -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 via Docker before running:
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 Docker database image matches the default Aurora engine version. If you change the Aurora engine version, it's recommended to also use a matching local Docker database 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.
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 generated database project's `serve-local` target in `project.json`. Update the image argument passed to `scripts/docker-start.ts` when you change engine versions.
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#smithy-api
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#smithy-api" />
30
+ <RunGenerator generator="ts#api" requiredParameters={{ framework: 'smithy' }} />
31
31
 
32
32
  ### Options
33
33
 
34
- <GeneratorParameters generator="ts#smithy-api" />
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 [ESLint](https://eslint.org/) for static analysis.
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`, it's recommended to configure the [Nx Dependency Checks ESLint Plugin](https://nx.dev/nx-api/eslint-plugin/documents/dependency-checks) to ensure that your published project's `package.json` includes all dependencies you use in your project.
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 [ESLint](https://eslint.org/) for linting, along with [Prettier](https://prettier.io/) for formatting.
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. You can tell ESLint to fix lint issues by running with the `--configuration=fix` argument.
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 will still run ESLint as part of the build, but the lint target will always be considered successful.
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 [ESLint](https://eslint.org/) for static analysis and [Prettier](https://prettier.io/) for code formatting. Running `lint` applies both to all projects.
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#trpc-api`, `py#fast-api`). Generators that accept an `--iac` flag default to `inherit`, which reads this value.
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.