@maestro-js/aws-cdk-recipes 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,391 @@
1
+ ## Overview
2
+
3
+ `@maestro-js/aws-cdk-recipes` provides opinionated AWS CDK constructs that simplify deploying cloud infrastructure. Each construct wraps multiple CDK resources behind a concise props interface with sensible defaults, and exposes a `transform` escape hatch for full customization of underlying CDK props.
4
+
5
+ ## Quick Setup
6
+
7
+ ```ts
8
+ import {
9
+ Vpc,
10
+ Cluster,
11
+ Bucket,
12
+ MySqlDatabase,
13
+ AuroraDatabase,
14
+ LambdaFunction,
15
+ EcsFargateService,
16
+ StaticSite,
17
+ ReactRouterSsrSiteLambda,
18
+ ReactRouterSsrSiteEcsFargateService,
19
+ ReactRouterEcrImage
20
+ } from '@maestro-js/aws-cdk-recipes'
21
+ ```
22
+
23
+ Package dependencies:
24
+ - `constructs` (dependency)
25
+ - `aws-cdk-lib` (peer dependency, ^2.178.0)
26
+
27
+ ## Available Constructs
28
+
29
+ ### Vpc
30
+ Multi-AZ VPC with public and private subnets, configurable NAT strategy (none, single, onePerAz, ec2), optional WireGuard VPN, and VPC Flow Logs.
31
+
32
+ ```ts
33
+ const network = new Vpc(this, 'Network', {
34
+ natGateways: 'single',
35
+ wireguard: true
36
+ })
37
+ ```
38
+
39
+ Key props: `cidr`, `maxAzs`, `natGateways`, `subnetConfiguration`, `wireguard`, `flowLogs`.
40
+
41
+ Exposes: `vpc`, `publicSubnets`, `privateSubnets`, `securityGroup`, `wireguard`, `wireguardPublicKeyParam`.
42
+
43
+ ### Cluster
44
+ ECS cluster inside a VPC with optional Fargate capacity providers for Spot pricing.
45
+
46
+ ```ts
47
+ const cluster = new Cluster(this, 'Cluster', {
48
+ vpc: network.vpc,
49
+ enableFargateCapacityProviders: true
50
+ })
51
+ ```
52
+
53
+ Key props: `vpc`, `enableFargateCapacityProviders`, `transform`.
54
+
55
+ Exposes: `cluster`.
56
+
57
+ ### Bucket
58
+ S3 bucket with HTTPS enforcement, configurable CORS, lifecycle rules, and custom bucket policies.
59
+
60
+ ```ts
61
+ const uploads = new Bucket(this, 'Uploads', {
62
+ versioning: true,
63
+ lifecycle: [{ prefix: 'tmp/', expiresIn: '7 days' }]
64
+ })
65
+ ```
66
+
67
+ Key props: `access` (`'public' | 'private'`), `cors`, `versioning`, `enforceHttps`, `lifecycle`, `policy`, `transform`.
68
+
69
+ Exposes: `bucket`.
70
+
71
+ ### MySqlDatabase
72
+ RDS MySQL instance in private subnets with encrypted storage, automated backups, and optional RDS Proxy.
73
+
74
+ ```ts
75
+ const db = new MySqlDatabase(this, 'Database', {
76
+ vpc: network.vpc,
77
+ database: 'ecommerce',
78
+ multiAz: true,
79
+ proxy: true
80
+ })
81
+ ```
82
+
83
+ Key props: `vpc`, `database`, `username`, `version`, `instance`, `storage`, `multiAz`, `proxy`, `performanceInsights`, `backupRetentionDays`, `deletionProtection`, `transform`.
84
+
85
+ Exposes: `instance`, `securityGroup`, `secret`, `connections`, `rdsProxy`, `host`, `port`, `proxyEndpoint`.
86
+
87
+ ### AuroraDatabase
88
+ Aurora Serverless v2 cluster (MySQL or PostgreSQL) with auto-scaling, optional auto-pause, read replicas, and RDS Proxy.
89
+
90
+ ```ts
91
+ const db = new AuroraDatabase(this, 'Database', {
92
+ vpc: network.vpc,
93
+ engine: 'postgres',
94
+ version: rds.AuroraPostgresEngineVersion.VER_17_4,
95
+ database: 'myapp',
96
+ scaling: { min: 0, max: 4, pauseAfter: '10 minutes' }
97
+ })
98
+ ```
99
+
100
+ Key props: `vpc`, `engine` (`'postgres' | 'mysql'`), `version`, `database`, `scaling` (`min`, `max`, `pauseAfter`), `readers`, `proxy`, `dataApi`, `performanceInsights`, `backupRetentionDays`, `deletionProtection`, `transform`.
101
+
102
+ Exposes: `cluster`, `securityGroup`, `secret`, `connections`, `rdsProxy`, `host`, `port`, `readerHost`, `proxyEndpoint`.
103
+
104
+ ### LambdaFunction
105
+ Lambda function with esbuild bundling, VPC placement, function URLs, streaming responses, concurrency controls, and IAM permissions.
106
+
107
+ ```ts
108
+ const api = new LambdaFunction(this, 'Api', {
109
+ handler: 'src/api.handler',
110
+ memory: 512,
111
+ url: true
112
+ })
113
+ ```
114
+
115
+ Supports three modes:
116
+ - **Bundling mode** (default): esbuild bundles from SST-style handler path (`path/to/file.exportName`)
117
+ - **Pre-built code**: pass `code` (a `lambda.Code` asset)
118
+ - **Pre-built directory**: pass `bundle` (path string packaged via `Code.fromAsset`)
119
+
120
+ Key props: `handler`, `code`, `bundle`, `runtime`, `architecture`, `memory`, `timeout`, `storage`, `environment`, `permissions`, `policies`, `vpc`, `concurrency`, `retries`, `streaming`, `versioning`, `url`, `logging`, `tags`, `nodejs` (esbuild options), `hook`, `transform`.
121
+
122
+ Exposes: `function`, `logGroup`, `url`, `version`, `alias`.
123
+
124
+ ### EcsFargateService
125
+ Fargate service with task definition, containers, optional ALB, auto-scaling, Spot capacity, and IAM permissions. Supports multi-container sidecars and conditional ALB routing rules.
126
+
127
+ ```ts
128
+ new EcsFargateService(this, 'Api', {
129
+ cluster: cluster.cluster,
130
+ cpu: 512,
131
+ memoryLimitMiB: 1024,
132
+ containers: [{ port: 3000, environment: { NODE_ENV: 'production' } }],
133
+ loadBalancer: {
134
+ domain: { name: 'api.example.com', certificateArn: '...' }
135
+ },
136
+ scaling: { min: 2, max: 10, cpuTarget: 70 }
137
+ })
138
+ ```
139
+
140
+ Key props: `cluster`, `architecture`, `cpu`, `memoryLimitMiB`, `containers` (array with `name`, `image`, `port`, `environment`, `ssm`, `secrets`, `health`, `logging`), `loadBalancer` (with `domain`, `health`, `rules`), `scaling`, `capacity` (`'spot'` or mixed), `permissions`, `transform`.
141
+
142
+ Exposes: `service`, `taskDefinition`, `containers`, `logGroups`, `securityGroup`, `alb`, `listener`, `targetGroups`.
143
+
144
+ ### StaticSite
145
+ Static site (SPA or static HTML) deployed to S3 with CloudFront distribution, custom domain, and configurable cache control.
146
+
147
+ ```ts
148
+ new StaticSite(this, 'Website', {
149
+ path: 'dist',
150
+ domain: {
151
+ name: 'example.com',
152
+ aliases: ['www.example.com'],
153
+ certificateArn: 'arn:aws:acm:us-east-1:123456789:certificate/abc-123'
154
+ }
155
+ })
156
+ ```
157
+
158
+ Key props: `path`, `indexPage`, `errorPage`, `domain`, `assets.fileOptions`, `edge`, `invalidation`, `transform`.
159
+
160
+ Exposes: `bucket`, `distribution`.
161
+
162
+ ### ReactRouterSsrSiteLambda
163
+ Full-stack React Router SSR application on Lambda with CloudFront and S3 static assets. Auto-generates a Lambda handler that bridges React Router's `createRequestHandler` to Lambda function URL events, with streaming and buffered response support.
164
+
165
+ Run `react-router build` before deploying.
166
+
167
+ ```ts
168
+ new ReactRouterSsrSiteLambda(this, 'App', {
169
+ domain: {
170
+ name: 'app.example.com',
171
+ certificateArn: 'arn:aws:acm:us-east-1:123456789:certificate/abc-123'
172
+ },
173
+ environment: { DATABASE_URL: 'mysql://...' }
174
+ })
175
+ ```
176
+
177
+ Key props: `path`, `buildDirectory`, `environment`, `vpc`, `permissions`, `server` (`mode`, `runtime`, `memory`, `timeout`, `architecture`, `layers`, `install`, `external`), `assets`, `domain`, `edge`, `invalidation`, `transform`.
178
+
179
+ Exposes: `lambda`, `functionUrl`, `bucket`, `distribution`.
180
+
181
+ ### ReactRouterSsrSiteEcsFargateService
182
+ Full-stack React Router SSR application on ECS Fargate with ALB, CloudFront, and S3 static assets. Auto-generates a Dockerfile when none is provided.
183
+
184
+ Run `react-router build` before deploying.
185
+
186
+ ```ts
187
+ new ReactRouterSsrSiteEcsFargateService(this, 'App', {
188
+ cluster: cluster.cluster,
189
+ cpu: 512,
190
+ memoryLimitMiB: 1024,
191
+ domain: {
192
+ name: 'app.example.com',
193
+ certificateArn: 'arn:aws:acm:us-east-1:123456789:certificate/abc-123'
194
+ }
195
+ })
196
+ ```
197
+
198
+ Key props: `cluster`, `path`, `buildDirectory`, `image`, `port`, `environment`, `ssm`, `secrets`, `architecture`, `cpu`, `memoryLimitMiB`, `capacity`, `healthCheck`, `scaling`, `permissions`, `assets`, `domain`, `edge`, `invalidation`, `transform`.
199
+
200
+ Exposes: `bucket`, `distribution`, `ecsService`.
201
+
202
+ ### ReactRouterEcrImage
203
+ Builds a Docker image for a React Router app and pushes it to ECR. Auto-generates a Dockerfile when none is provided. Use to pre-build an image shared across multiple ECS services.
204
+
205
+ Run `react-router build` before deploying.
206
+
207
+ ```ts
208
+ const image = new ReactRouterEcrImage(this, 'AppImage', {
209
+ path: './packages/web',
210
+ architecture: 'ARM64'
211
+ })
212
+ ```
213
+
214
+ Key props: `path`, `buildDirectory`, `port`, `image`, `architecture`, `platform`.
215
+
216
+ Exposes: `asset` (DockerImageAsset).
217
+
218
+ ## API Reference
219
+
220
+ ### Exports (from `src/index.ts`)
221
+
222
+ ```ts
223
+ export { Bucket } from './bucket.ts'
224
+ export { Vpc } from './vpc.ts'
225
+ export { Cluster } from './cluster.ts'
226
+ export { StaticSite } from './static-site.ts'
227
+ export { ReactRouterSsrSiteLambda } from './react-router-ssr-site-lambda.ts'
228
+ export { ReactRouterSsrSiteEcsFargateService } from './react-router-ssr-site-ecs-fargate-service.ts'
229
+ export { ReactRouterEcrImage } from './react-router-ecr-image.ts'
230
+ export { MySqlDatabase } from './mysql-database.ts'
231
+ export { AuroraDatabase } from './aurora-database.ts'
232
+ export { LambdaFunction } from './lambda-function.ts'
233
+ export { EcsFargateService } from './ecs-fargate-service.ts'
234
+ ```
235
+
236
+ ### Construct Signatures
237
+
238
+ | Construct | Constructor |
239
+ |-----------|------------|
240
+ | `Vpc` | `new Vpc(scope, id, props?: Vpc.Props)` |
241
+ | `Cluster` | `new Cluster(scope, id, props: Cluster.Props)` |
242
+ | `Bucket` | `new Bucket(scope, id, props?: Bucket.Props)` |
243
+ | `MySqlDatabase` | `new MySqlDatabase(scope, id, props: MySqlDatabase.Props)` |
244
+ | `AuroraDatabase` | `new AuroraDatabase(scope, id, props: AuroraDatabase.Props)` |
245
+ | `LambdaFunction` | `new LambdaFunction(scope, id, props: LambdaFunction.Props)` |
246
+ | `EcsFargateService` | `new EcsFargateService(scope, id, props: EcsFargateService.Props)` |
247
+ | `StaticSite` | `new StaticSite(scope, id, props: StaticSite.Props)` |
248
+ | `ReactRouterSsrSiteLambda` | `new ReactRouterSsrSiteLambda(scope, id, props: ReactRouterSsrSiteLambda.Props)` |
249
+ | `ReactRouterSsrSiteEcsFargateService` | `new ReactRouterSsrSiteEcsFargateService(scope, id, props: ReactRouterSsrSiteEcsFargateService.Props)` |
250
+ | `ReactRouterEcrImage` | `new ReactRouterEcrImage(scope, id, props?: ReactRouterEcrImage.Props)` |
251
+
252
+ ## Common Patterns
253
+
254
+ ### Full-stack application with VPC, database, and API
255
+
256
+ ```ts
257
+ const network = new Vpc(this, 'Network', { natGateways: 'single' })
258
+
259
+ const cluster = new Cluster(this, 'Cluster', {
260
+ vpc: network.vpc,
261
+ enableFargateCapacityProviders: true
262
+ })
263
+
264
+ const db = new AuroraDatabase(this, 'Database', {
265
+ vpc: network.vpc,
266
+ engine: 'postgres',
267
+ version: rds.AuroraPostgresEngineVersion.VER_17_4,
268
+ database: 'myapp',
269
+ scaling: { min: 0, max: 4, pauseAfter: '10 minutes' }
270
+ })
271
+
272
+ new EcsFargateService(this, 'Api', {
273
+ cluster: cluster.cluster,
274
+ containers: [{
275
+ port: 3000,
276
+ environment: { DATABASE_HOST: db.host }
277
+ }],
278
+ loadBalancer: {
279
+ domain: { name: 'api.example.com', certificateArn: '...' }
280
+ },
281
+ scaling: { min: 2, max: 10 }
282
+ })
283
+ ```
284
+
285
+ ### React Router SSR on Lambda with custom domain
286
+
287
+ ```ts
288
+ new ReactRouterSsrSiteLambda(this, 'App', {
289
+ path: './packages/web',
290
+ server: { mode: 'streaming', memory: 1024 },
291
+ domain: {
292
+ name: 'app.example.com',
293
+ certificateArn: 'arn:aws:acm:us-east-1:123456789:certificate/abc-123'
294
+ },
295
+ environment: { DATABASE_URL: 'mysql://...' }
296
+ })
297
+ ```
298
+
299
+ ### React Router SSR on ECS Fargate with Spot pricing
300
+
301
+ ```ts
302
+ new ReactRouterSsrSiteEcsFargateService(this, 'App', {
303
+ cluster: cluster.cluster,
304
+ cpu: 512,
305
+ memoryLimitMiB: 1024,
306
+ capacity: 'spot',
307
+ domain: {
308
+ name: 'app.example.com',
309
+ certificateArn: 'arn:aws:acm:us-east-1:123456789:certificate/abc-123'
310
+ }
311
+ })
312
+ ```
313
+
314
+ ### Transform escape hatch for customizing underlying CDK props
315
+
316
+ Every construct supports a `transform` prop that receives default CDK props and returns modified versions:
317
+
318
+ ```ts
319
+ new MySqlDatabase(this, 'Database', {
320
+ vpc: network.vpc,
321
+ database: 'app',
322
+ transform: {
323
+ instance: (props) => ({ ...props, publiclyAccessible: false })
324
+ }
325
+ })
326
+
327
+ new AuroraDatabase(this, 'Database', {
328
+ vpc: network.vpc,
329
+ engine: 'postgres',
330
+ version: rds.AuroraPostgresEngineVersion.VER_17_4,
331
+ database: 'myapp',
332
+ transform: {
333
+ cluster: (props) => ({ ...props, storageType: rds.DBClusterStorageType.AURORA_IOPT1 })
334
+ }
335
+ })
336
+ ```
337
+
338
+ ### SSM secrets and environment injection in ECS
339
+
340
+ ```ts
341
+ new EcsFargateService(this, 'Api', {
342
+ cluster: cluster.cluster,
343
+ containers: [{
344
+ port: 3000,
345
+ environment: { NODE_ENV: 'production' },
346
+ ssm: {
347
+ DATABASE_URL: 'arn:aws:secretsmanager:us-east-1:123456789:secret:db-url',
348
+ API_KEY: '/my-app/api-key'
349
+ }
350
+ }]
351
+ })
352
+ ```
353
+
354
+ Values starting with `arn:aws:secretsmanager:` are resolved as Secrets Manager secrets; all others are resolved as SSM SecureString parameters.
355
+
356
+ ### Cost-effective VPC with EC2 NAT
357
+
358
+ ```ts
359
+ const network = new Vpc(this, 'Network', {
360
+ natGateways: 'ec2',
361
+ maxAzs: 2,
362
+ wireguard: true,
363
+ flowLogs: { retention: RetentionDays.ONE_WEEK }
364
+ })
365
+ ```
366
+
367
+ The `'ec2'` NAT option uses a `t4g.nano` instance running the fck-nat AMI (~$3/month vs ~$33/month for managed NAT Gateway).
368
+
369
+ ## Cross-Package Integration
370
+
371
+ `@maestro-js/aws-cdk-recipes` is a standalone infrastructure package. It has no dependencies on other Maestro packages. Use it in CDK apps to deploy infrastructure for Maestro-based applications. The React Router constructs auto-generate Dockerfiles and Lambda handlers that work with both monorepo (`pnpm deploy`) and standalone project layouts.
372
+
373
+ ## Key Source Files
374
+
375
+ - `packages/aws-cdk-recipes/src/index.ts` - Package exports
376
+ - `packages/aws-cdk-recipes/src/vpc.ts` - Vpc construct
377
+ - `packages/aws-cdk-recipes/src/cluster.ts` - Cluster construct
378
+ - `packages/aws-cdk-recipes/src/bucket.ts` - Bucket construct
379
+ - `packages/aws-cdk-recipes/src/mysql-database.ts` - MySqlDatabase construct
380
+ - `packages/aws-cdk-recipes/src/aurora-database.ts` - AuroraDatabase construct
381
+ - `packages/aws-cdk-recipes/src/lambda-function.ts` - LambdaFunction construct
382
+ - `packages/aws-cdk-recipes/src/ecs-fargate-service.ts` - EcsFargateService construct
383
+ - `packages/aws-cdk-recipes/src/static-site.ts` - StaticSite construct
384
+ - `packages/aws-cdk-recipes/src/react-router-ssr-site-lambda.ts` - ReactRouterSsrSiteLambda construct
385
+ - `packages/aws-cdk-recipes/src/react-router-ssr-site-ecs-fargate-service.ts` - ReactRouterSsrSiteEcsFargateService construct
386
+ - `packages/aws-cdk-recipes/src/react-router-ecr-image.ts` - ReactRouterEcrImage construct
387
+ - `packages/aws-cdk-recipes/src/helpers/cloudfront.ts` - Shared CloudFront/S3 deployment helpers
388
+ - `packages/aws-cdk-recipes/src/helpers/ecs.ts` - Shared ECS helpers (log retention, secrets)
389
+ - `packages/aws-cdk-recipes/src/helpers/docker.ts` - React Router Dockerfile generation
390
+ - `packages/aws-cdk-recipes/src/helpers/ssr-site-lambda.ts` - SSR site Lambda orchestration
391
+ - `packages/aws-cdk-recipes/src/helpers/ssr-site-ecs-service.ts` - SSR site ECS orchestration