@aws/nx-plugin-mcp 1.0.0-rc.4 → 1.0.0-rc.41

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 (163) hide show
  1. package/bin/aws-nx-mcp.js +2240 -1030
  2. package/docs/get_started/building-with-ai.mdx +116 -0
  3. package/docs/get_started/concepts.mdx +52 -0
  4. package/docs/get_started/existing-project.mdx +176 -0
  5. package/docs/get_started/quick-start.mdx +266 -0
  6. package/docs/get_started/tutorials/contribute-generator.mdx +405 -0
  7. package/docs/get_started/tutorials/dungeon-game/1.mdx +1205 -0
  8. package/docs/get_started/tutorials/dungeon-game/2.mdx +237 -0
  9. package/docs/get_started/tutorials/dungeon-game/3.mdx +76 -0
  10. package/docs/get_started/tutorials/dungeon-game/4.mdx +162 -0
  11. package/docs/get_started/tutorials/dungeon-game/overview.mdx +144 -0
  12. package/docs/get_started/tutorials/dungeon-game/wrap-up.mdx +41 -0
  13. package/docs/get_started/tutorials/existing-project.mdx +4 -0
  14. package/docs/guides/agentcore-gateway.mdx +376 -0
  15. package/docs/guides/connection/agentcore-gateway-gateway.mdx +154 -0
  16. package/docs/guides/connection/agentcore-gateway-mcp.mdx +134 -0
  17. package/docs/guides/connection/py-agent-a2a.mdx +47 -15
  18. package/docs/guides/connection/py-agent-dynamodb.mdx +116 -0
  19. package/docs/guides/connection/py-agent-gateway.mdx +176 -0
  20. package/docs/guides/connection/py-agent-mcp.mdx +42 -13
  21. package/docs/guides/connection/py-agent-rdb.mdx +178 -0
  22. package/docs/guides/connection/py-fast-api-dynamodb.mdx +56 -0
  23. package/docs/guides/connection/py-fast-api-rdb.mdx +184 -0
  24. package/docs/guides/connection/py-mcp-server-dynamodb.mdx +116 -0
  25. package/docs/guides/connection/py-mcp-server-rdb.mdx +187 -0
  26. package/docs/guides/connection/react-agui.mdx +4 -4
  27. package/docs/guides/connection/react-fastapi.mdx +38 -2
  28. package/docs/guides/connection/react-py-agent.mdx +7 -13
  29. package/docs/guides/connection/react-smithy.mdx +3 -3
  30. package/docs/guides/connection/react-trpc.mdx +1 -1
  31. package/docs/guides/connection/react-ts-agent.mdx +8 -8
  32. package/docs/guides/connection/smithy-dynamodb.mdx +4 -4
  33. package/docs/guides/connection/smithy-rdb.mdx +5 -5
  34. package/docs/guides/connection/trpc-dynamodb.mdx +4 -4
  35. package/docs/guides/connection/trpc-rdb.mdx +5 -5
  36. package/docs/guides/connection/ts-agent-a2a.mdx +12 -9
  37. package/docs/guides/connection/ts-agent-dynamodb.mdx +3 -3
  38. package/docs/guides/connection/ts-agent-gateway.mdx +141 -0
  39. package/docs/guides/connection/ts-agent-mcp.mdx +11 -8
  40. package/docs/guides/connection/ts-agent-rdb.mdx +66 -21
  41. package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +3 -3
  42. package/docs/guides/connection/ts-mcp-server-rdb.mdx +66 -16
  43. package/docs/guides/connection.mdx +104 -5
  44. package/docs/guides/docker-bundling.mdx +68 -8
  45. package/docs/guides/fastapi.mdx +244 -4
  46. package/docs/guides/license.mdx +264 -109
  47. package/docs/guides/local-development.mdx +87 -0
  48. package/docs/guides/nx-generator.mdx +7 -2
  49. package/docs/guides/py-agent.mdx +257 -49
  50. package/docs/guides/py-dynamodb.mdx +476 -0
  51. package/docs/guides/py-mcp-server.mdx +61 -2
  52. package/docs/guides/py-rdb.mdx +254 -0
  53. package/docs/guides/react-website-auth.mdx +58 -1
  54. package/docs/guides/react-website.mdx +130 -19
  55. package/docs/guides/security.mdx +75 -0
  56. package/docs/guides/terraform-project.mdx +1 -1
  57. package/docs/guides/trpc.mdx +45 -9
  58. package/docs/guides/ts-agent.mdx +149 -9
  59. package/docs/guides/ts-dynamodb.mdx +62 -239
  60. package/docs/guides/ts-mcp-server.mdx +66 -3
  61. package/docs/guides/ts-nx-plugin.mdx +1 -1
  62. package/docs/guides/ts-rdb.mdx +117 -470
  63. package/docs/guides/ts-smithy-api.mdx +183 -4
  64. package/docs/guides/typescript-infrastructure.mdx +9 -1
  65. package/docs/guides/typescript-project.mdx +5 -10
  66. package/docs/guides/workspace.mdx +2 -2
  67. package/docs/snippets/agent/architecture.mdx +1 -1
  68. package/docs/snippets/agent/bedrock-deployment.mdx +4 -0
  69. package/docs/snippets/agent/runtime-arn.mdx +21 -0
  70. package/docs/snippets/agent/securing-your-agent.mdx +39 -0
  71. package/docs/snippets/api/access-logging.mdx +33 -0
  72. package/docs/snippets/api/type-safe-api-integrations.mdx +31 -0
  73. package/docs/snippets/api/waf-configuration.mdx +1 -1
  74. package/docs/snippets/connection/dynamodb-local-development.mdx +2 -2
  75. package/docs/snippets/connection/py-dynamodb-local-development.mdx +7 -0
  76. package/docs/snippets/connection/py-lambda-rdb-ssl-requirements.mdx +7 -0
  77. package/docs/snippets/connection/rdb-api-infrastructure.mdx +50 -18
  78. package/docs/snippets/dynamodb/deploying-table.mdx +166 -0
  79. package/docs/snippets/dynamodb/gsi-config.mdx +38 -0
  80. package/docs/snippets/dynamodb/infrastructure.mdx +33 -0
  81. package/docs/snippets/dynamodb/local-dev-start.mdx +13 -0
  82. package/docs/snippets/dynamodb/local-dev-windows.mdx +15 -0
  83. package/docs/snippets/mcp/architecture.mdx +1 -1
  84. package/docs/snippets/mcp/bedrock-deployment.mdx +4 -0
  85. package/docs/snippets/mcp/config.mdx +3 -2
  86. package/docs/snippets/rdb/architecture.mdx +38 -0
  87. package/docs/snippets/rdb/cluster-instances.mdx +31 -0
  88. package/docs/snippets/rdb/deletion-protection.mdx +34 -0
  89. package/docs/snippets/rdb/deploying.mdx +187 -0
  90. package/docs/snippets/rdb/encryption-key-rotation.mdx +30 -0
  91. package/docs/snippets/rdb/engine-version.mdx +63 -0
  92. package/docs/snippets/rdb/infrastructure.mdx +35 -0
  93. package/docs/snippets/rdb/logging.mdx +32 -0
  94. package/docs/snippets/rdb/rds-proxy.mdx +50 -0
  95. package/docs/snippets/rdb/removal-policy.mdx +57 -0
  96. package/docs/snippets/rdb/serverless-capacity.mdx +32 -0
  97. package/docs/snippets/required-prerequisites.mdx +1 -1
  98. package/docs/snippets/trivy-image-scan.mdx +27 -0
  99. package/generators.json +101 -2
  100. package/package.json +1 -1
  101. package/src/agentcore-gateway/gateway-connection/schema.json +31 -0
  102. package/src/agentcore-gateway/mcp-connection/schema.json +31 -0
  103. package/src/agentcore-gateway/schema.json +70 -0
  104. package/src/connection/schema.json +5 -0
  105. package/src/infra/app/schema.json +5 -0
  106. package/src/init/schema.json +35 -0
  107. package/src/license/schema.json +11 -0
  108. package/src/preset/schema.json +11 -5
  109. package/src/py/agent/a2a-connection/schema.json +5 -0
  110. package/src/py/agent/gateway-connection/schema.json +31 -0
  111. package/src/py/agent/mcp-connection/schema.json +5 -0
  112. package/src/py/agent/react-connection/schema.json +5 -0
  113. package/src/py/agent/schema.json +6 -1
  114. package/src/py/api/schema.json +5 -0
  115. package/src/py/dynamodb/agent-connection/schema.json +27 -0
  116. package/src/py/dynamodb/fast-api-connection/schema.json +23 -0
  117. package/src/py/dynamodb/mcp-server-connection/schema.json +27 -0
  118. package/src/py/dynamodb/schema.json +75 -0
  119. package/src/py/fast-api/react/schema.json +5 -0
  120. package/src/py/fast-api/schema.json +5 -0
  121. package/src/py/lambda-function/schema.json +5 -0
  122. package/src/py/mcp-server/schema.json +5 -0
  123. package/src/py/project/schema.json +5 -0
  124. package/src/py/rdb/agent-connection/schema.json +27 -0
  125. package/src/py/rdb/fast-api-connection/schema.json +23 -0
  126. package/src/py/rdb/mcp-server-connection/schema.json +27 -0
  127. package/src/py/rdb/schema.json +77 -0
  128. package/src/smithy/project/schema.json +5 -0
  129. package/src/smithy/react-connection/schema.json +5 -0
  130. package/src/smithy/ts/api/schema.json +5 -0
  131. package/src/terraform/project/schema.json +5 -0
  132. package/src/trpc/backend/schema.json +5 -0
  133. package/src/trpc/react/schema.json +5 -0
  134. package/src/ts/agent/a2a-connection/schema.json +5 -0
  135. package/src/ts/agent/gateway-connection/schema.json +31 -0
  136. package/src/ts/agent/mcp-connection/schema.json +5 -0
  137. package/src/ts/agent/react-connection/schema.json +5 -0
  138. package/src/ts/agent/schema.json +5 -0
  139. package/src/ts/api/schema.json +5 -0
  140. package/src/ts/astro-docs/schema.json +3 -3
  141. package/src/ts/docs/schema.json +3 -3
  142. package/src/ts/dynamodb/agent-connection/schema.json +5 -0
  143. package/src/ts/dynamodb/mcp-server-connection/schema.json +5 -0
  144. package/src/ts/dynamodb/schema.json +25 -2
  145. package/src/ts/dynamodb/smithy-connection/schema.json +5 -0
  146. package/src/ts/dynamodb/trpc-connection/schema.json +5 -0
  147. package/src/ts/lambda-function/schema.json +5 -0
  148. package/src/ts/lib/schema.json +5 -0
  149. package/src/ts/mcp-server/schema.json +5 -0
  150. package/src/ts/nx-generator/schema.json +5 -0
  151. package/src/ts/nx-plugin/schema.json +5 -0
  152. package/src/ts/rdb/agent-connection/schema.json +5 -0
  153. package/src/ts/rdb/mcp-server-connection/schema.json +5 -0
  154. package/src/ts/rdb/schema.json +6 -1
  155. package/src/ts/rdb/smithy-connection/schema.json +5 -0
  156. package/src/ts/rdb/trpc-connection/schema.json +5 -0
  157. package/src/ts/react-website/app/schema.json +11 -6
  158. package/src/ts/react-website/cognito-auth/schema.json +5 -0
  159. package/src/ts/react-website/runtime-config/schema.json +5 -0
  160. package/src/ts/website/app/schema.json +11 -6
  161. package/src/ts/website/auth/schema.json +5 -0
  162. /package/docs/snippets/connection/{lambda-rdb-ssl-requirements.mdx → ts-lambda-rdb-ssl-requirements.mdx} +0 -0
  163. /package/docs/snippets/connection/{mcp-server-rdb-ssl-requirements.mdx → ts-mcp-server-rdb-ssl-requirements.mdx} +0 -0
@@ -1,13 +1,15 @@
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]
8
8
  ---
9
9
 
10
- import { FileTree } from '@astrojs/starlight/components';
10
+ import { FileTree, CardGrid } from '@astrojs/starlight/components';
11
+ import Astro from '@astrojs/react';
12
+ import ConnectionCard from '@components/connection-card.astro';
11
13
  import Link from '@components/link.astro';
12
14
  import RunGenerator from '@components/run-generator.astro';
13
15
  import GeneratorParameters from '@components/generator-parameters.astro';
@@ -27,11 +29,11 @@ The Smithy TypeScript API generator creates a new API using Smithy for service d
27
29
 
28
30
  You can generate a new Smithy TypeScript API in two ways:
29
31
 
30
- <RunGenerator generator="ts#smithy-api" />
32
+ <RunGenerator generator="ts#api" requiredParameters={{ framework: 'smithy' }} />
31
33
 
32
34
  ### Options
33
35
 
34
- <GeneratorParameters generator="ts#smithy-api" />
36
+ <GeneratorParameters generator="ts#api" />
35
37
 
36
38
  :::tip[Integration Pattern]
37
39
  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 +403,151 @@ export const MyOperation: MyOperationHandler<ServiceContext> = async (input) =>
401
403
  };
402
404
  ```
403
405
 
406
+ ### Accessing the Calling User
407
+
408
+ 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.
409
+
410
+ 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:
411
+
412
+ ```smithy
413
+ $version: "2.0"
414
+
415
+ namespace your.namespace
416
+
417
+ /// Thrown when the calling user cannot be determined
418
+ @error("client")
419
+ @httpError(403)
420
+ structure UnauthorizedError {
421
+ @required
422
+ message: String
423
+ }
424
+ ```
425
+
426
+ 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:
427
+
428
+ ```ts {4-7,15} ins={4-7,15}
429
+ import { Logger } from '@aws-lambda-powertools/logger';
430
+ import { Metrics } from '@aws-lambda-powertools/metrics';
431
+ import { Tracer } from '@aws-lambda-powertools/tracer';
432
+
433
+ export interface Identity {
434
+ sub: string;
435
+ username: string;
436
+ }
437
+
438
+ /**
439
+ * Context provided to all operations.
440
+ */
441
+ export interface ServiceContext {
442
+ tracer: Tracer;
443
+ logger: Logger;
444
+ metrics: Metrics;
445
+ getIdentity: () => Promise<Identity>;
446
+ }
447
+ ```
448
+
449
+ 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:
450
+
451
+ <OptionFilter when={{ auth: 'iam' }} description="Identity resolution for IAM-authenticated APIs">
452
+ For `IAM` authentication, we look up the caller in Cognito using the sub extracted from the API Gateway event:
453
+
454
+ ```ts
455
+ import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider';
456
+ import type { APIGatewayProxyEvent } from 'aws-lambda';
457
+ import { Identity } from './context.js';
458
+ import { UnauthorizedError } from './generated/ssdk/index.js';
459
+
460
+ const cognito = new CognitoIdentityProvider();
461
+
462
+ export const getIdentity = async (
463
+ event: APIGatewayProxyEvent,
464
+ ): Promise<Identity> => {
465
+ const cognitoAuthenticationProvider =
466
+ event.requestContext?.identity?.cognitoAuthenticationProvider;
467
+
468
+ let sub: string | undefined = undefined;
469
+ if (cognitoAuthenticationProvider) {
470
+ const providerParts = cognitoAuthenticationProvider.split(':');
471
+ sub = providerParts[providerParts.length - 1];
472
+ }
473
+
474
+ if (!sub) {
475
+ throw new UnauthorizedError({ message: 'Unable to determine calling user' });
476
+ }
477
+
478
+ const { Users } = await cognito.listUsers({
479
+ // Assumes user pool id is configured in lambda environment
480
+ UserPoolId: process.env.USER_POOL_ID!,
481
+ Limit: 1,
482
+ Filter: `sub="${sub}"`,
483
+ });
484
+
485
+ if (!Users || Users.length !== 1) {
486
+ throw new UnauthorizedError({ message: `No user found with subjectId ${sub}` });
487
+ }
488
+
489
+ return { sub, username: Users[0].Username! };
490
+ };
491
+ ```
492
+ </OptionFilter>
493
+
494
+ <OptionFilter when={{ auth: 'cognito' }} description="Identity resolution for Cognito-authenticated APIs">
495
+ 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`:
496
+
497
+ ```ts
498
+ import type { APIGatewayProxyEvent } from 'aws-lambda';
499
+ import { Identity } from './context.js';
500
+ import { UnauthorizedError } from './generated/ssdk/index.js';
501
+
502
+ export const getIdentity = async (
503
+ event: APIGatewayProxyEvent,
504
+ ): Promise<Identity> => {
505
+ const claims = event.requestContext?.authorizer?.claims as
506
+ | Record<string, string>
507
+ | undefined;
508
+
509
+ const sub = claims?.sub;
510
+ const username = claims?.username;
511
+
512
+ if (!sub || !username) {
513
+ throw new UnauthorizedError({ message: 'Unable to determine calling user' });
514
+ }
515
+
516
+ return { sub, username };
517
+ };
518
+ ```
519
+
520
+ :::tip[No token verification required]
521
+ 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.
522
+ :::
523
+ </OptionFilter>
524
+
525
+ Then wire the resolver into the context in `src/handler.ts`:
526
+
527
+ ```ts {2,8} ins={2,8}
528
+ import { Service } from './service.js';
529
+ import { getIdentity } from './identity.js';
530
+ // ...
531
+ const httpResponse = await serviceHandler.handle(httpRequest, {
532
+ tracer,
533
+ logger,
534
+ metrics,
535
+ getIdentity: () => getIdentity(event),
536
+ });
537
+ ```
538
+
539
+ We can now use the resolved identity in an operation, for example in `src/operations/echo.ts`:
540
+
541
+ ```ts
542
+ import { ServiceContext } from '../context.js';
543
+ import { Echo as EchoOperation } from '../generated/ssdk/index.js';
544
+
545
+ export const Echo: EchoOperation<ServiceContext> = async (input, ctx) => {
546
+ const identity = await ctx.getIdentity();
547
+ return { message: `${identity.username} says ${input.message}` };
548
+ };
549
+ ```
550
+
404
551
  ## Building and Code Generation
405
552
 
406
553
  The Smithy model project uses [Docker](https://www.docker.com/) to build the Smithy artifacts and generate the TypeScript Server SDK:
@@ -583,6 +730,10 @@ output "lambda_function_name" {
583
730
 
584
731
  <Snippet name="api/waf-configuration" parentHeading="WAF" />
585
732
 
733
+ ### Access logging
734
+
735
+ <Snippet name="api/access-logging" parentHeading="Access logging" />
736
+
586
737
  ### Integrations
587
738
 
588
739
  <Snippet name="api/type-safe-api-integrations" parentHeading="Integrations" />
@@ -662,3 +813,31 @@ resource "aws_iam_role_policy_attachment" "api_invoke_access" {
662
813
  ## Invoking your Smithy API
663
814
 
664
815
  To invoke your API from a React website, you can use the <Link path="guides/connection/react-smithy">`connection`</Link> generator, which provides type-safe client generation from your Smithy model.
816
+
817
+ ## Connections
818
+
819
+ Use the <Link path="guides/connection">`connection`</Link> generator to integrate this project with others in your workspace. The following connections involve this project:
820
+
821
+ <CardGrid>
822
+ <ConnectionCard
823
+ title="React to Smithy API"
824
+ description="Call a Smithy API from a React website"
825
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/react-smithy`}
826
+ source="react"
827
+ target="smithy"
828
+ />
829
+ <ConnectionCard
830
+ title="Smithy API to Relational Database"
831
+ description="Connect a Smithy API to an Aurora relational database"
832
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/smithy-rdb`}
833
+ source="smithy"
834
+ target="aurora"
835
+ />
836
+ <ConnectionCard
837
+ title="Smithy API to TypeScript DynamoDB"
838
+ description="Connect a Smithy API to a DynamoDB table"
839
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/smithy-dynamodb`}
840
+ source="smithy"
841
+ target="dynamodb"
842
+ />
843
+ </CardGrid>
@@ -286,7 +286,7 @@ export class ApplicationStack extends Stack {
286
286
 
287
287
  ### Website Infrastructure
288
288
 
289
- If you have used the <Link path="guides/react-website">CloudScape website</Link> generator, you will notice you already have a construct in `packages/common/constructs` to deploy it. For example:
289
+ If you have used the <Link path="guides/react-website">React Website</Link> generator, you will notice you already have a construct in `packages/common/constructs` to deploy it. For example:
290
290
 
291
291
  ```ts title="src/stacks/application-stack.ts" {3, 9-10}
292
292
  import { Stack, StackProps } from 'aws-cdk-lib';
@@ -381,6 +381,14 @@ Then run the deploy target:
381
381
 
382
382
  <NxCommands commands={['deploy <my-infra> <my-infra>-sandbox/*']} />
383
383
 
384
+ :::tip[Express Mode for Faster Deployments]
385
+ The `deploy` target waits for full resource stabilization by default, favouring consistency over speed. To speed up iteration during development, opt into [CloudFormation express mode](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-express-mode.html) by passing CDK's `--express` flag:
386
+
387
+ <NxCommands commands={['deploy <my-infra> <my-infra>-sandbox/* --express']} />
388
+
389
+ Express mode finishes once resource configuration is confirmed applied rather than waiting for full stabilization, with propagation continuing in the background, for significantly faster iteration cycles. It is intended for development and iteration.
390
+ :::
391
+
384
392
  :::tip[Selective Stack Deployment]
385
393
  The above command deploys _all_ stacks for the `<my-infra>-sandbox` stage. You can specify other stages so long as they are defined in `main.ts`.
386
394
 
@@ -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:
@@ -134,7 +134,7 @@ This will run the chosen target as well as the targets it depends on.
134
134
 
135
135
  ### Linting
136
136
 
137
- 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.
138
138
 
139
139
  ### Git Secrets
140
140
 
@@ -181,7 +181,7 @@ export default {
181
181
  } satisfies AwsNxPluginConfig;
182
182
  ```
183
183
 
184
- - **`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.
185
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.
186
186
 
187
187
  You can edit either setting at any time — subsequent generator runs will pick up the new value.
@@ -23,7 +23,7 @@ ecr: ECR {
23
23
 
24
24
  agentcore: Strands Agent\n(AgentCore Runtime) {
25
25
  shape: image
26
- icon: /nx-plugin-for-aws/icons/aws/bedrock-agentcore.svg
26
+ icon: /nx-plugin-for-aws/icons/aws/bedrock-agentcore-runtime.svg
27
27
  }
28
28
 
29
29
  bedrock: Bedrock\n(Model Inference) {
@@ -169,4 +169,8 @@ module "my_project_agent" {
169
169
 
170
170
  :::note[Custom OIDC Providers]
171
171
  If you require custom JWT authentication with a non-Cognito OIDC provider, you can modify the generated CDK construct or Terraform module for your agent directly. Note that the connection generator will only support `IAM` or `Cognito` authentication.
172
+ :::
173
+
174
+ :::caution[Security Best Practices]
175
+ When implementing your agent's business logic, review the [Bedrock AgentCore Runtime security best practices](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-security-best-practices.html).
172
176
  :::
@@ -61,4 +61,25 @@ The Bedrock AgentCore Runtime dataplane URL for invoking the agent is as follows
61
61
  https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<url-encoded-arn>/invocations
62
62
  ```
63
63
 
64
+ :::tip[Invocation URL]
65
+ Your infrastructure can also output the full invocation URL directly, with the ARN encoding handled for you:
66
+
67
+ <Infrastructure>
68
+ <Fragment slot="cdk">
69
+ ```ts
70
+ new CfnOutput(this, 'AgentUrl', {
71
+ value: agent.invocationUrl,
72
+ });
73
+ ```
74
+ </Fragment>
75
+ <Fragment slot="terraform">
76
+ ```terraform
77
+ output "agent_url" {
78
+ value = module.my_project_agent.invocation_url
79
+ }
80
+ ```
81
+ </Fragment>
82
+ </Infrastructure>
83
+ :::
84
+
64
85
  The exact way to invoke this URL depends upon the authentication method used.
@@ -0,0 +1,39 @@
1
+ ---
2
+ title: Securing your Agent
3
+ ---
4
+
5
+ Agents act on untrusted input and can drive real actions through their tools, so it's worth considering security from the start. The following practices apply to the generated agent.
6
+
7
+ ### Treat model input and output as untrusted
8
+
9
+ Prompts can contain adversarial instructions (prompt injection), and model output is non-deterministic — neither should be trusted in security-sensitive logic:
10
+
11
+ - Define strict input schemas for your tools, as in the generated example tool. Constrain values to what the tool actually needs (enums, length limits, numeric ranges) rather than accepting free-form strings.
12
+ - Never pass model output directly into shell commands, SQL queries, code evaluation, or rendered HTML without validation or encoding.
13
+ - Apply authorization checks in your tools and downstream services — don't rely on the system prompt to prevent the model from misusing a tool it has access to.
14
+
15
+ Strands' [Prompt Engineering](https://strandsagents.com/docs/user-guide/safety-security/prompt-engineering/) and [Responsible AI](https://strandsagents.com/docs/user-guide/safety-security/responsible-ai/) guides cover writing robust, safety-conscious system prompts.
16
+
17
+ ### Scope tool permissions tightly
18
+
19
+ Grant the agent's IAM role only the permissions its tools need. The vended CDK constructs and Terraform modules expose `grant*` methods and scoped policies for this purpose — for example granting an agent access to invoke a specific API rather than attaching broad managed policies. Where a tool acts on behalf of a user, prefer authorizing the action using the calling user's identity (passed through via the request context) over the agent's own ambient permissions.
20
+
21
+ ### Provide a kill switch
22
+
23
+ Because model behaviour can change in unexpected ways, plan for quickly disabling or swapping the model without a code change:
24
+
25
+ - Read the model ID from configuration (for example a `MODEL_ID` environment variable) so operators can switch or roll back to a different model by updating configuration.
26
+ - Gate the agent behind a feature flag so its AI functionality can be disabled entirely. When disabled, return a generic message rather than an error, and ensure the rest of your application degrades gracefully.
27
+
28
+ Document how to flip these controls in your operational runbook.
29
+
30
+ ### Protect sensitive data
31
+
32
+ - Avoid logging prompts and completions, which may contain user data. The generated agent's model error logging hook logs error metadata only, not conversation content — keep this property when adding your own logging.
33
+ - Return generic error messages to users; log detailed errors server-side.
34
+ - Isolate conversation state between users and sessions, and authorize access to any persisted session data.
35
+ - Redact personally identifiable information (PII) from prompts and outputs — either with a Bedrock Guardrail sensitive information filter (below) or, for Strands agents, the approaches in the [PII Redaction](https://strandsagents.com/docs/user-guide/safety-security/pii-redaction/) guide.
36
+
37
+ ### Amazon Bedrock Guardrails
38
+
39
+ [Amazon Bedrock Guardrails](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html) provide configurable content filters, denied topics, and sensitive information (PII) filters which are evaluated on model input and output. You can attach a guardrail to the model used by the generated agent:
@@ -0,0 +1,33 @@
1
+ ---
2
+ title: Access logging
3
+ ---
4
+ import Infrastructure from '@components/infrastructure.astro';
5
+
6
+ For REST APIs, the generated infrastructure enables [access logging](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html) by default, writing one structured JSON line per request to a dedicated CloudWatch Logs group. The log group is encrypted with a customer-managed KMS key and retained for one year.
7
+
8
+ API Gateway writes access logs using an account-level CloudWatch Logs role. This role is configured on the `AWS::ApiGateway::Account` setting, which is a **singleton per region per account** — there is only one role for every REST API in the region. To manage this safely across multiple independently-deployed stacks, the generated infrastructure:
9
+
10
+ - Creates a shared CloudWatch Logs role and configures it on the account only when no working role is already set, so deployments never overwrite a role another stack owns.
11
+ - Leaves the account setting untouched on teardown, so destroying one stack never disables logging for other REST APIs in the region.
12
+
13
+ <Infrastructure>
14
+ <Fragment slot="cdk">
15
+ The account role is managed by the `ApiGatewayAccount` construct, a stack-scoped singleton resolved via `ApiGatewayAccount.ensure(scope)`. Each REST API's stage depends on it, and the role is configured by a Lambda-backed custom resource.
16
+
17
+ You can customise the access log format by passing `deployOptions` when constructing your API:
18
+
19
+ ```ts {3-5}
20
+ const api = new MyApi(this, 'MyApi', {
21
+ integrations: MyApi.defaultIntegrations(this).build(),
22
+ deployOptions: {
23
+ accessLogFormat: AccessLogFormat.clf(),
24
+ },
25
+ });
26
+ ```
27
+ </Fragment>
28
+ <Fragment slot="terraform">
29
+ The account role is managed by the `core/api/api-gateway-account` module, which is instantiated by the generated API module. It configures the account idempotently and is never reset on `terraform destroy`.
30
+
31
+ You can customise the access log format by editing the `access_log_settings` block on the `aws_api_gateway_stage` resource in the generated API module.
32
+ </Fragment>
33
+ </Infrastructure>
@@ -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).
@@ -2,6 +2,6 @@
2
2
  title: DynamoDB Local Development
3
3
  ---
4
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`.
5
+ The `connection` generator configures your project's `dev` target to depend on the DynamoDB project's `dev` target. DynamoDB Local will start automatically alongside your project when running `dev`.
6
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.
7
+ The `LOCAL_DEV=true` environment variable is set automatically, so `getDynamoDBClient()` and `resolveTableName()` connect to the local DynamoDB Local instance instead of AWS.
@@ -0,0 +1,7 @@
1
+ ---
2
+ title: Python DynamoDB Local Development
3
+ ---
4
+
5
+ The `connection` generator configures your project's `dev` target to depend on the DynamoDB project's `dev` target. DynamoDB Local will start automatically alongside your project when running `dev`.
6
+
7
+ The `LOCAL_DEV=true` environment variable is set automatically, so `is_local()` returns `True` and your PynamoDB entities connect to the local DynamoDB instance instead of AWS.
@@ -0,0 +1,7 @@
1
+ ---
2
+ title: SSL Requirements when Connecting without RDS Proxy
3
+ ---
4
+
5
+ The Amazon Linux 2023 Lambda execution environment's built-in CA trust store includes the Amazon Root CAs used by RDS, so no additional configuration is needed.
6
+
7
+ When using RDS Proxy, you do not need to configure the RDS CA bundle in your Lambda function.
@@ -2,6 +2,7 @@
2
2
  title: RDB API Infrastructure
3
3
  ---
4
4
  import Infrastructure from '@components/infrastructure.astro';
5
+ import Link from '@components/link.astro';
5
6
 
6
7
  To allow your API to connect to the database at runtime, the API Lambda functions must be deployed into the same VPC as the database and granted network and IAM access.
7
8
 
@@ -39,34 +40,65 @@ This example grants every handler in your API access, but if only some handlers
39
40
  </Fragment>
40
41
  <Fragment slot="terraform">
41
42
 
42
- Pass the database module outputs into your API module so it can reach the database and read its runtime configuration:
43
+ Deploy the API into the same VPC as the database, grant it `rds-db:connect` via `additional_iam_policy_statements`, and open the network path with a pair of security group rules. The `aws_vpc.main` and `aws_subnet` resources are defined in the database deployment guide:
43
44
 
44
45
  ```hcl title="packages/infra/src/main.tf"
45
46
  module "my_database" {
46
47
  source = "../../common/terraform/src/app/dbs/my-database"
47
- vpc_id = module.vpc.vpc_id
48
- database_subnet_ids = module.vpc.private_isolated_subnet_ids
49
- lambda_subnet_ids = module.vpc.private_subnet_ids
48
+ vpc_id = aws_vpc.main.id
49
+ database_subnet_ids = aws_subnet.database[*].id
50
+ lambda_subnet_ids = aws_subnet.private[*].id
50
51
  }
51
52
 
52
53
  module "api" {
53
- source = "..."
54
- vpc_id = module.vpc.vpc_id
55
- private_subnet_ids = module.vpc.private_subnet_ids
56
-
57
- appconfig_application_id = module.my_database.appconfig_application_id
58
- database_cluster_resource_id = module.my_database.cluster_resource_id
59
- database_runtime_user = module.my_database.database_runtime_user
60
- database_security_group_id = module.my_database.security_group_id
61
- database_port = module.my_database.cluster_port
62
-
63
- environment_variables = {
64
- RUNTIME_CONFIG_APP_ID = module.my_database.appconfig_application_id
65
- }
54
+ source = "../../common/terraform/src/app/apis/my-api"
55
+ enable_vpc = true
56
+ vpc_id = aws_vpc.main.id
57
+ subnet_ids = aws_subnet.private[*].id
58
+
59
+ appconfig_application_id = module.runtime_config_appconfig.application_id
60
+ appconfig_application_arn = module.runtime_config_appconfig.application_arn
61
+
62
+ additional_iam_policy_statements = [
63
+ {
64
+ Effect = "Allow"
65
+ Action = ["rds-db:connect"]
66
+ Resource = [
67
+ "arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.my_database.connect_resource_id}/${module.my_database.database_runtime_user}"
68
+ ]
69
+ }
70
+ ]
71
+ }
72
+
73
+ resource "aws_vpc_security_group_ingress_rule" "api_to_database" {
74
+ description = "Allow the API Lambda functions to connect to the database"
75
+ security_group_id = module.my_database.security_group_id
76
+ referenced_security_group_id = module.api.security_group_id
77
+ from_port = module.my_database.cluster_port
78
+ to_port = module.my_database.cluster_port
79
+ ip_protocol = "tcp"
80
+ }
81
+
82
+ resource "aws_vpc_security_group_egress_rule" "api_to_database" {
83
+ description = "Allow outbound traffic from the API Lambda functions to the database"
84
+ security_group_id = module.api.security_group_id
85
+ referenced_security_group_id = module.my_database.security_group_id
86
+ from_port = module.my_database.cluster_port
87
+ to_port = module.my_database.cluster_port
88
+ ip_protocol = "tcp"
66
89
  }
67
90
  ```
68
91
 
69
- Deploy the API Lambda functions into **private subnets with egress**, not private isolated subnets. Ensure the API Lambda role has `rds-db:connect` permission and that its security group can reach the database security group on the database port.
92
+ Deploy the API Lambda functions into **private subnets with egress**, not private isolated subnets. `appconfig_application_id`/`appconfig_application_arn` come from the shared <Link path="guides/runtime-config">runtime configuration</Link> AppConfig application declared once in your root module, not from the database module — passing them sets `RUNTIME_CONFIG_APP_ID` on the Lambda functions and grants them read access to the application. Include the `database` namespace when instantiating it so the database module's runtime configuration entry is deployed:
93
+
94
+ ```hcl title="packages/infra/src/main.tf"
95
+ module "runtime_config_appconfig" {
96
+ source = "../../common/terraform/src/core/runtime-config/appconfig"
97
+
98
+ application_name = "my-app-runtime-config"
99
+ namespaces = ["connection", "agentcore", "database"]
100
+ }
101
+ ```
70
102
 
71
103
  </Fragment>
72
104
  </Infrastructure>