@venturekit/infra 0.0.0-dev.20260514025219 → 0.0.0-dev.20260515022321

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 (49) hide show
  1. package/dist/cdk/app-stack.d.ts +330 -0
  2. package/dist/cdk/app-stack.d.ts.map +1 -0
  3. package/dist/cdk/app-stack.js +875 -0
  4. package/dist/cdk/app-stack.js.map +1 -0
  5. package/dist/cdk/config-stack.d.ts +104 -0
  6. package/dist/cdk/config-stack.d.ts.map +1 -0
  7. package/dist/cdk/config-stack.js +161 -0
  8. package/dist/cdk/config-stack.js.map +1 -0
  9. package/dist/cdk/data-stack.d.ts +198 -0
  10. package/dist/cdk/data-stack.d.ts.map +1 -0
  11. package/dist/cdk/data-stack.js +511 -0
  12. package/dist/cdk/data-stack.js.map +1 -0
  13. package/dist/cdk/edge-stack.d.ts +91 -0
  14. package/dist/cdk/edge-stack.d.ts.map +1 -0
  15. package/dist/cdk/edge-stack.js +364 -0
  16. package/dist/cdk/edge-stack.js.map +1 -0
  17. package/dist/cdk/identity-stack.d.ts +98 -0
  18. package/dist/cdk/identity-stack.d.ts.map +1 -0
  19. package/dist/cdk/identity-stack.js +254 -0
  20. package/dist/cdk/identity-stack.js.map +1 -0
  21. package/dist/cdk/index.d.ts +16 -0
  22. package/dist/cdk/index.d.ts.map +1 -1
  23. package/dist/cdk/index.js +17 -0
  24. package/dist/cdk/index.js.map +1 -1
  25. package/dist/cdk/messaging-stack.d.ts +109 -0
  26. package/dist/cdk/messaging-stack.d.ts.map +1 -0
  27. package/dist/cdk/messaging-stack.js +320 -0
  28. package/dist/cdk/messaging-stack.js.map +1 -0
  29. package/dist/cdk/network-stack.d.ts +87 -0
  30. package/dist/cdk/network-stack.d.ts.map +1 -0
  31. package/dist/cdk/network-stack.js +265 -0
  32. package/dist/cdk/network-stack.js.map +1 -0
  33. package/dist/cdk/shared/cross-stack-refs.d.ts +278 -0
  34. package/dist/cdk/shared/cross-stack-refs.d.ts.map +1 -0
  35. package/dist/cdk/shared/cross-stack-refs.js +326 -0
  36. package/dist/cdk/shared/cross-stack-refs.js.map +1 -0
  37. package/dist/cdk/shared/lambda-helpers.d.ts +82 -0
  38. package/dist/cdk/shared/lambda-helpers.d.ts.map +1 -0
  39. package/dist/cdk/shared/lambda-helpers.js +201 -0
  40. package/dist/cdk/shared/lambda-helpers.js.map +1 -0
  41. package/dist/cdk/shared/ssm-keys.d.ts +460 -0
  42. package/dist/cdk/shared/ssm-keys.d.ts.map +1 -0
  43. package/dist/cdk/shared/ssm-keys.js +291 -0
  44. package/dist/cdk/shared/ssm-keys.js.map +1 -0
  45. package/dist/cdk/stack.d.ts +3 -11
  46. package/dist/cdk/stack.d.ts.map +1 -1
  47. package/dist/cdk/stack.js +184 -41
  48. package/dist/cdk/stack.js.map +1 -1
  49. package/package.json +2 -2
@@ -0,0 +1,511 @@
1
+ /**
2
+ * Tier 1 — Data stack.
3
+ *
4
+ * Owns every long-lived stateful resource in the deploy:
5
+ *
6
+ * - RDS instance(s) (Postgres / MySQL) + master credentials
7
+ * Secret + the database-side SecurityGroup
8
+ * - ElastiCache cluster(s) + ElastiCache SG
9
+ * - DynamoDB table(s): user-declared (free-tier) and the
10
+ * auto-provisioned rate-limits table (always provisioned —
11
+ * `createDefaultRateLimiter()` from `@venturekit/runtime` reads
12
+ * `VENTURE_RATE_LIMIT_TABLE` and the rate limiter must "just
13
+ * work" on first deploy regardless of preset)
14
+ * - S3 bucket(s) — bucket only; CloudFront distribution lives in
15
+ * the edge tier and imports the bucket via SSM
16
+ * - Internal HMAC Secret used by `@venturekit/auth` for state-
17
+ * token signing across Lambda-to-Lambda calls
18
+ *
19
+ * # Lifecycle position
20
+ *
21
+ * Updated quarterly-ish — RDS minor version, instance-size bumps,
22
+ * occasional new bucket. Survives stack delete because every
23
+ * stateful resource has both `DeletionPolicy: Retain` AND
24
+ * (where AWS supports it) the resource-native deletion-protection
25
+ * flag (RDS, DynamoDB).
26
+ *
27
+ * # Public surface (via SSM)
28
+ *
29
+ * - `dataKeys.rdsEndpoint` / `rdsPort` / `rdsDatabaseName` /
30
+ * `rdsSecretArn` / `rdsSecurityGroupId` per declared db id
31
+ * - `dataKeys.bucketName` / `bucketArn` per declared bucket id
32
+ * - `dataKeys.dynamoTableName` / `dynamoTableArn` per
33
+ * user-declared table (free tier) AND for the rate-limits table
34
+ * (id `'rate-limits'`)
35
+ * - `dataKeys.cacheEndpoint` / `cachePort` / `cacheSecurityGroupId`
36
+ * per cache id
37
+ * - `dataKeys.internalHmacSecretArn`
38
+ *
39
+ * Outputs (`cdk.CfnOutput`) are deliberately NOT used — see plan §3.
40
+ *
41
+ * # What this stack does NOT do
42
+ *
43
+ * - **No CloudFront distribution.** Edge stack (step 8) imports the
44
+ * bucket and creates the distribution with `S3BucketOrigin.with
45
+ * OriginAccessControl(bucket)`. The OAC's `aws:SourceArn`-scoped
46
+ * bucket policy lands in the edge stack via
47
+ * `bucket.addToResourcePolicy()` on the imported `IBucket`.
48
+ *
49
+ * - **No migration runner.** The CodeBuild-based migration runner is
50
+ * ephemeral wiring (delete-on-redeploy is fine; migrations are
51
+ * already applied to the persistent DB). It moves to the app stack
52
+ * in step 9, where it imports the RDS endpoint + secret via SSM.
53
+ *
54
+ * - **No Lambda permissions wiring.** Every IAM grant
55
+ * (`bucket.grantReadWrite(role)`, `secret.grantRead(role)`, etc.)
56
+ * produces an `AWS::IAM::Policy` resource attached to the role.
57
+ * The role lives in the app stack; therefore so does every grant.
58
+ * This is critical: putting grants here would create a circular
59
+ * stack dependency (data → app for the role; app → data for the
60
+ * bucket).
61
+ */
62
+ import * as cdk from 'aws-cdk-lib';
63
+ import * as ec2 from 'aws-cdk-lib/aws-ec2';
64
+ import * as rds from 'aws-cdk-lib/aws-rds';
65
+ import * as s3 from 'aws-cdk-lib/aws-s3';
66
+ import * as elasticache from 'aws-cdk-lib/aws-elasticache';
67
+ import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
68
+ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
69
+ import * as iam from 'aws-cdk-lib/aws-iam';
70
+ import { DATA_SAFETY_CONFIG } from '@venturekit/core';
71
+ import * as path from 'path';
72
+ import { writeSsm } from './shared/cross-stack-refs.js';
73
+ import { dataKeys } from './shared/ssm-keys.js';
74
+ import { MigrationRunner, hasMigrations } from './migration-runner.js';
75
+ /**
76
+ * Map a database `intent.size` to an RDS instance type. Graviton
77
+ * (T4G / R6G) for cost. Mirrors `VentureStack.sizeToInstanceType`.
78
+ */
79
+ function sizeToInstanceType(size) {
80
+ switch (size) {
81
+ case 'xlarge':
82
+ return ec2.InstanceType.of(ec2.InstanceClass.R6G, ec2.InstanceSize.LARGE);
83
+ case 'large':
84
+ return ec2.InstanceType.of(ec2.InstanceClass.R6G, ec2.InstanceSize.MEDIUM);
85
+ case 'medium':
86
+ return ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.SMALL);
87
+ default: // 'small'
88
+ return ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.MICRO);
89
+ }
90
+ }
91
+ function sizeToCacheNodeType(size) {
92
+ switch (size) {
93
+ case 'xlarge':
94
+ return 'cache.r6g.large';
95
+ case 'large':
96
+ return 'cache.r6g.medium';
97
+ case 'medium':
98
+ return 'cache.t4g.small';
99
+ default: // 'small'
100
+ return 'cache.t4g.micro';
101
+ }
102
+ }
103
+ export class VentureDataStack extends cdk.Stack {
104
+ /**
105
+ * In-process accessors for sibling stacks (app stack mostly) that
106
+ * are deployed in the same `cdk.App`. Same rationale as
107
+ * `VentureNetworkStack.vpc`: direct CDK references give the
108
+ * consumer fully-typed access; cross-deploy consumers go through
109
+ * SSM + `import…` helpers.
110
+ */
111
+ databases = new Map();
112
+ buckets = new Map();
113
+ dynamoTables = new Map();
114
+ /**
115
+ * The auto-provisioned rate-limits table. Always populated, even
116
+ * when no `databases` intent is declared.
117
+ */
118
+ rateLimitTable;
119
+ /** Internal HMAC secret used by `@venturekit/auth/runtime`. */
120
+ internalHmacSecret;
121
+ /**
122
+ * Captured once in the constructor and reused by every private
123
+ * `create…` method. Avoids re-deriving from `envConfig.dataSafety`
124
+ * at five separate call sites and keeps the retention semantics
125
+ * consistent across all data-tier resources within a single stack.
126
+ */
127
+ isStrictRetain;
128
+ /**
129
+ * Native deletion-protection flag for resources that expose one
130
+ * (RDS, DynamoDB). Mirrors `dataSafetyConfig.deletionProtection`.
131
+ */
132
+ nativeDeletionProtection;
133
+ /**
134
+ * Migration runner config captured from props for use by
135
+ * `createDatabase`. `undefined` skips runner provisioning;
136
+ * the runner is also skipped per-DB when `hasMigrations` is
137
+ * false or the engine isn't Postgres.
138
+ */
139
+ migrationsConfig;
140
+ /** Captured for migration runner log retention. */
141
+ logRetentionDays;
142
+ /** Captured for migration runner NAT-availability gating. */
143
+ natType;
144
+ constructor(scope, id, props) {
145
+ super(scope, id, props);
146
+ const { projectName, stage, envConfig, infrastructure, vpc, isFreeTier } = props;
147
+ const dataSafetyConfig = DATA_SAFETY_CONFIG[envConfig.dataSafety];
148
+ this.isStrictRetain = dataSafetyConfig.removalPolicy === 'retain';
149
+ this.nativeDeletionProtection = dataSafetyConfig.deletionProtection;
150
+ this.migrationsConfig = props.migrations;
151
+ this.logRetentionDays = envConfig.observability.logs.retentionDays;
152
+ this.natType = envConfig.vpc.natType;
153
+ const isStrictRetain = this.isStrictRetain;
154
+ // ─── Internal HMAC secret ────────────────────────────────────
155
+ // CloudFormation auto-generates a 64-char alphanumeric value on
156
+ // first deploy and preserves it across stack updates. The value
157
+ // is consumed by `@venturekit/auth/runtime` for signing internal
158
+ // Lambda-to-Lambda state tokens; the app stack reads the secret's
159
+ // ARN via SSM and either fetches the value at cold start (default)
160
+ // or — for stages where the SM round-trip latency matters —
161
+ // injects the value as a Lambda env var directly.
162
+ this.internalHmacSecret = new secretsmanager.Secret(this, 'internalHmacSecret', {
163
+ secretName: `venturekit/${projectName}/${stage}/internal-hmac`,
164
+ description: 'VentureKit internal Lambda-to-Lambda HMAC signing key. Auto-generated.',
165
+ generateSecretString: {
166
+ passwordLength: 64,
167
+ excludePunctuation: true,
168
+ excludeCharacters: '"\'\\/',
169
+ requireEachIncludedType: false,
170
+ includeSpace: false,
171
+ },
172
+ removalPolicy: isStrictRetain ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
173
+ });
174
+ writeSsm(this, dataKeys.internalHmacSecretArn(projectName, stage), this.internalHmacSecret.secretArn, { description: 'Internal HMAC secret ARN' });
175
+ // ─── Databases ───────────────────────────────────────────────
176
+ if (infrastructure.databases) {
177
+ for (const intent of infrastructure.databases) {
178
+ if (isFreeTier) {
179
+ // Free tier swaps RDS for DynamoDB. Cheaper, fully
180
+ // serverless, no VPC required. The `databases` intent
181
+ // surface stays the same so vk.config.ts is unchanged.
182
+ this.createDynamoDBTable(intent, projectName, stage);
183
+ }
184
+ else {
185
+ if (!vpc) {
186
+ throw new Error(`VentureDataStack: database '${intent.id}' requires a VPC. ` +
187
+ `Pass the VentureNetworkStack's vpc to VentureDataStackProps.vpc, ` +
188
+ `or use the free preset which routes databases through DynamoDB.`);
189
+ }
190
+ this.createDatabase(intent, projectName, stage, vpc);
191
+ }
192
+ }
193
+ }
194
+ // ─── Built-in rate-limits DDB ────────────────────────────────
195
+ // Always created — the runtime rate limiter expects the table
196
+ // to exist regardless of preset. Per-stack name avoids cross-
197
+ // project collisions in shared accounts. See plan §5: this was
198
+ // historically hardcoded `RemovalPolicy.DESTROY` and now respects
199
+ // dataSafety.
200
+ this.rateLimitTable = this.createRateLimitTable(projectName, stage);
201
+ // ─── Storage buckets ─────────────────────────────────────────
202
+ if (infrastructure.storage) {
203
+ for (const intent of infrastructure.storage) {
204
+ this.createStorage(intent, projectName, stage);
205
+ }
206
+ }
207
+ // ─── Caches ──────────────────────────────────────────────────
208
+ if (infrastructure.caches) {
209
+ for (const intent of infrastructure.caches) {
210
+ if (!vpc) {
211
+ throw new Error(`VentureDataStack: cache '${intent.id}' requires a VPC. ` +
212
+ `Pass the VentureNetworkStack's vpc to VentureDataStackProps.vpc.`);
213
+ }
214
+ this.createCache(intent, projectName, stage, vpc);
215
+ }
216
+ }
217
+ }
218
+ // ─── RDS ───────────────────────────────────────────────────────
219
+ createDatabase(intent, projectName, stage, vpc) {
220
+ const isStrictRetain = this.isStrictRetain;
221
+ // Stable logical ID — never changes when preset changes.
222
+ const logicalId = `db-${intent.id}`;
223
+ const instanceType = sizeToInstanceType(intent.size || 'small');
224
+ const engine = intent.type === 'mysql'
225
+ ? rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0 })
226
+ : rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_16 });
227
+ // Place DB in isolated subnets when the preset ships them
228
+ // (medium+); otherwise fall back to private-with-egress.
229
+ const subnetType = vpc.isolatedSubnets?.length
230
+ ? ec2.SubnetType.PRIVATE_ISOLATED
231
+ : ec2.SubnetType.PRIVATE_WITH_EGRESS;
232
+ const commonDbProps = {
233
+ engine,
234
+ instanceType,
235
+ vpc,
236
+ vpcSubnets: { subnetType },
237
+ removalPolicy: isStrictRetain ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
238
+ // Native RDS deletion protection — CFN-level RETAIN doesn't
239
+ // block console / CLI deletes; this flag does.
240
+ deletionProtection: this.nativeDeletionProtection,
241
+ multiAz: intent.highAvailability ?? false,
242
+ storageEncrypted: intent.encrypted ?? true,
243
+ backupRetention: intent.backups !== false
244
+ ? cdk.Duration.days(intent.backupRetentionDays ?? 7)
245
+ : cdk.Duration.days(0),
246
+ autoMinorVersionUpgrade: true,
247
+ enablePerformanceInsights: intent.performanceInsights ?? false,
248
+ };
249
+ const instance = intent.restoreFromSnapshot
250
+ ? new rds.DatabaseInstanceFromSnapshot(this, logicalId, {
251
+ ...commonDbProps,
252
+ snapshotIdentifier: intent.restoreFromSnapshot,
253
+ credentials: rds.SnapshotCredentials.fromGeneratedSecret('postgres'),
254
+ })
255
+ : new rds.DatabaseInstance(this, logicalId, {
256
+ ...commonDbProps,
257
+ databaseName: intent.name || intent.id,
258
+ credentials: rds.Credentials.fromGeneratedSecret('postgres'),
259
+ });
260
+ // UpdateReplacePolicy=Retain on the DB instance so a property
261
+ // change that requires REPLACE doesn't drop the underlying
262
+ // storage. Mirrors the §5 retention model.
263
+ if (isStrictRetain) {
264
+ const cfnInstance = instance.node.defaultChild;
265
+ cfnInstance.cfnOptions.updateReplacePolicy = cdk.CfnDeletionPolicy.RETAIN;
266
+ }
267
+ // RETAIN the master credentials Secret. `instance.secret`
268
+ // returns a `SecretTargetAttachment` (CDK metadata, not the
269
+ // actual Secret); the underlying `AWS::SecretsManager::Secret`
270
+ // resource is a sibling child of the DB construct under the
271
+ // well-known id `'Secret'`. Walking to it directly is the only
272
+ // way to apply RemovalPolicy to the secret itself.
273
+ if (isStrictRetain) {
274
+ const dbSecret = instance.node.tryFindChild('Secret');
275
+ if (dbSecret) {
276
+ dbSecret.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN);
277
+ const cfnSecret = dbSecret.node.defaultChild;
278
+ if (cfnSecret) {
279
+ cfnSecret.cfnOptions.updateReplacePolicy = cdk.CfnDeletionPolicy.RETAIN;
280
+ }
281
+ }
282
+ }
283
+ this.databases.set(intent.id, { instance, intent });
284
+ // ─── Migration runner (CodeBuild in-VPC) ────────────────────
285
+ // Provisioned only for Postgres + when the project has a
286
+ // `db/migrations/` dir + when the VPC has outbound egress.
287
+ // Skipping silently is OK because the operator can run
288
+ // `vk migrate` manually via an SSM tunnel.
289
+ if (this.migrationsConfig &&
290
+ intent.type === 'postgres' &&
291
+ instance.secret) {
292
+ const dbDir = path.join(this.migrationsConfig.projectDir, 'db');
293
+ if (hasMigrations(dbDir)) {
294
+ if (this.natType === 'none') {
295
+ console.warn(`[venturekit] Skipping auto-migrations for db "${intent.id}": ` +
296
+ `natType is 'none', so the in-VPC migration runner can't ` +
297
+ `reach npmjs.com to install @venturekit/cli. Fix: set ` +
298
+ `'infrastructure.vpc.natType: "instance"' (or "gateway") in ` +
299
+ `vk.config.ts. Until then, run \`vk migrate -e ${stage}\` ` +
300
+ `manually once the DB is reachable (e.g. via SSM tunnel).`);
301
+ }
302
+ else {
303
+ new MigrationRunner(this, `migration-runner-${intent.id}`, {
304
+ projectName,
305
+ stage,
306
+ dbId: intent.id,
307
+ vpc,
308
+ dbInstance: instance,
309
+ dbSecret: instance.secret,
310
+ dbName: intent.name || intent.id,
311
+ dbDir,
312
+ extraMigrationsDirs: this.migrationsConfig.packageMigrationsDirs ?? [],
313
+ vkCliVersion: this.migrationsConfig.vkCliVersion,
314
+ logRetentionDays: this.logRetentionDays,
315
+ });
316
+ }
317
+ }
318
+ }
319
+ else if (this.migrationsConfig && intent.type === 'mysql') {
320
+ console.warn(`[venturekit] No auto-migration runner for MySQL db "${intent.id}". ` +
321
+ `Run migrations manually via tunnel.`);
322
+ }
323
+ // Publish to SSM for the app stack's connection wiring.
324
+ writeSsm(this, dataKeys.rdsEndpoint(projectName, stage, intent.id), instance.dbInstanceEndpointAddress, { description: `Postgres/MySQL endpoint for db '${intent.id}'` });
325
+ writeSsm(this, dataKeys.rdsPort(projectName, stage, intent.id), instance.dbInstanceEndpointPort, { description: `RDS port for db '${intent.id}'` });
326
+ writeSsm(this, dataKeys.rdsDatabaseName(projectName, stage, intent.id), intent.name || intent.id, { description: `Database name for db '${intent.id}'` });
327
+ if (instance.secret) {
328
+ writeSsm(this, dataKeys.rdsSecretArn(projectName, stage, intent.id), instance.secret.secretArn, { description: `Master credentials secret ARN for db '${intent.id}'` });
329
+ }
330
+ writeSsm(this, dataKeys.rdsSecurityGroupId(projectName, stage, intent.id), instance.connections.securityGroups[0].securityGroupId, { description: `Database SG ID — app stack imports + adds Lambda ingress` });
331
+ }
332
+ // ─── DynamoDB (free-tier `databases` substitute + user tables) ─
333
+ createDynamoDBTable(intent, projectName, stage) {
334
+ const isStrictRetain = this.isStrictRetain;
335
+ const logicalId = `dynamo-${intent.id}`;
336
+ const table = new dynamodb.Table(this, logicalId, {
337
+ tableName: `${projectName}-${intent.id}-${stage}`,
338
+ partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING },
339
+ sortKey: { name: 'sk', type: dynamodb.AttributeType.STRING },
340
+ billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
341
+ removalPolicy: isStrictRetain ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
342
+ pointInTimeRecovery: isStrictRetain,
343
+ encryption: dynamodb.TableEncryption.AWS_MANAGED,
344
+ timeToLiveAttribute: 'ttl',
345
+ // Native DDB deletion protection — second layer beyond RETAIN.
346
+ deletionProtection: isStrictRetain,
347
+ });
348
+ if (isStrictRetain) {
349
+ const cfnTable = table.node.defaultChild;
350
+ cfnTable.cfnOptions.updateReplacePolicy = cdk.CfnDeletionPolicy.RETAIN;
351
+ }
352
+ table.addGlobalSecondaryIndex({
353
+ indexName: 'gsi1',
354
+ partitionKey: { name: 'gsi1pk', type: dynamodb.AttributeType.STRING },
355
+ sortKey: { name: 'gsi1sk', type: dynamodb.AttributeType.STRING },
356
+ projectionType: dynamodb.ProjectionType.ALL,
357
+ });
358
+ this.dynamoTables.set(intent.id, table);
359
+ writeSsm(this, dataKeys.dynamoTableName(projectName, stage, intent.id), table.tableName, { description: `DynamoDB table name '${intent.id}'` });
360
+ writeSsm(this, dataKeys.dynamoTableArn(projectName, stage, intent.id), table.tableArn, { description: `DynamoDB table ARN '${intent.id}'` });
361
+ }
362
+ createRateLimitTable(projectName, stage) {
363
+ const isStrictRetain = this.isStrictRetain;
364
+ // Per-stack name to avoid collisions across multiple projects in
365
+ // the same AWS account.
366
+ const tableName = `${projectName}-rate-limits-${stage}`;
367
+ const table = new dynamodb.Table(this, 'RateLimitTable', {
368
+ tableName,
369
+ partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING },
370
+ billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
371
+ removalPolicy: isStrictRetain ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
372
+ timeToLiveAttribute: 'ttl',
373
+ encryption: dynamodb.TableEncryption.AWS_MANAGED,
374
+ deletionProtection: isStrictRetain,
375
+ });
376
+ if (isStrictRetain) {
377
+ const cfn = table.node.defaultChild;
378
+ cfn.cfnOptions.updateReplacePolicy = cdk.CfnDeletionPolicy.RETAIN;
379
+ }
380
+ // Publish under the stable id `'rate-limits'` so app-stack code
381
+ // reads through `dataKeys.dynamoTableName(project, stage, 'rate-limits')`.
382
+ writeSsm(this, dataKeys.dynamoTableName(projectName, stage, 'rate-limits'), table.tableName, { description: 'Rate-limits DDB table name (consumed by @venturekit/runtime)' });
383
+ writeSsm(this, dataKeys.dynamoTableArn(projectName, stage, 'rate-limits'), table.tableArn, { description: 'Rate-limits DDB table ARN — for IAM grants in app stack' });
384
+ return table;
385
+ }
386
+ // ─── S3 ────────────────────────────────────────────────────────
387
+ createStorage(intent, projectName, stage) {
388
+ const isStrictRetain = this.isStrictRetain;
389
+ const logicalId = `storage-${intent.id}`;
390
+ const bucket = new s3.Bucket(this, logicalId, {
391
+ bucketName: `${projectName}-${intent.id}-${stage}`,
392
+ versioned: intent.versioned ?? intent.purpose === 'backups',
393
+ removalPolicy: isStrictRetain ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
394
+ autoDeleteObjects: !isStrictRetain,
395
+ encryption: s3.BucketEncryption.S3_MANAGED,
396
+ // BLOCK_ALL even when CDN is in use; the edge-tier CloudFront
397
+ // distribution accesses the bucket through an Origin Access
398
+ // Control with `aws:SourceArn` scoping, not via direct
399
+ // anonymous reads.
400
+ blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
401
+ enforceSSL: true,
402
+ cors: intent.corsOrigins
403
+ ? [
404
+ {
405
+ allowedOrigins: intent.corsOrigins,
406
+ allowedMethods: [
407
+ s3.HttpMethods.GET,
408
+ s3.HttpMethods.PUT,
409
+ s3.HttpMethods.POST,
410
+ s3.HttpMethods.DELETE,
411
+ ],
412
+ allowedHeaders: ['*'],
413
+ },
414
+ ]
415
+ : undefined,
416
+ lifecycleRules: intent.purpose === 'logs'
417
+ ? [{ expiration: cdk.Duration.days(intent.retentionDays ?? 90), id: 'log-expiry' }]
418
+ : intent.purpose === 'backups'
419
+ ? [
420
+ {
421
+ transitions: [
422
+ { storageClass: s3.StorageClass.INFREQUENT_ACCESS, transitionAfter: cdk.Duration.days(30) },
423
+ ],
424
+ id: 'backup-ia',
425
+ },
426
+ {
427
+ transitions: [
428
+ { storageClass: s3.StorageClass.GLACIER, transitionAfter: cdk.Duration.days(90) },
429
+ ],
430
+ id: 'backup-glacier',
431
+ },
432
+ ]
433
+ : [],
434
+ });
435
+ if (isStrictRetain) {
436
+ const cfnBucket = bucket.node.defaultChild;
437
+ cfnBucket.cfnOptions.updateReplacePolicy = cdk.CfnDeletionPolicy.RETAIN;
438
+ }
439
+ this.buckets.set(intent.id, { bucket, intent });
440
+ // ── OAC bucket policy (CDN-fronted buckets) ───────────────────
441
+ // The edge stack creates the CloudFront distribution with an
442
+ // OriginAccessControl pointing at this bucket. The bucket policy
443
+ // that authorizes CloudFront's signed S3 GET must live here (the
444
+ // bucket's home stack); creating it in the edge stack would force
445
+ // CDK to add a `data → edge` dependency for the distribution ARN
446
+ // *and* an `edge → data` dependency for the bucket's regional
447
+ // domain — a synth-time cycle.
448
+ //
449
+ // We scope the statement with `aws:SourceAccount` instead of
450
+ // `aws:SourceArn`. Pinning to a specific distribution ARN would
451
+ // require a cross-stack reference; the SourceAccount condition
452
+ // is the AWS-recommended fallback when the distribution lives in
453
+ // another stack and gives equivalent protection at the account
454
+ // boundary (the only CloudFront distribution with this OAC will
455
+ // be the one in the edge stack — anyone else attempting to use
456
+ // the same OAC must already be inside the same AWS account).
457
+ if (intent.cdn === true) {
458
+ bucket.addToResourcePolicy(new iam.PolicyStatement({
459
+ sid: 'AllowCloudFrontOacRead',
460
+ effect: iam.Effect.ALLOW,
461
+ principals: [new iam.ServicePrincipal('cloudfront.amazonaws.com')],
462
+ actions: ['s3:GetObject'],
463
+ resources: [bucket.arnForObjects('*')],
464
+ conditions: {
465
+ StringEquals: { 'aws:SourceAccount': cdk.Aws.ACCOUNT_ID },
466
+ },
467
+ }));
468
+ }
469
+ writeSsm(this, dataKeys.bucketName(projectName, stage, intent.id), bucket.bucketName, { description: `S3 bucket name for storage '${intent.id}'` });
470
+ writeSsm(this, dataKeys.bucketArn(projectName, stage, intent.id), bucket.bucketArn, { description: `S3 bucket ARN — IAM scoping target` });
471
+ }
472
+ // ─── ElastiCache ───────────────────────────────────────────────
473
+ createCache(intent, projectName, stage, vpc) {
474
+ const logicalId = `cache-${intent.id}`;
475
+ const securityGroup = new ec2.SecurityGroup(this, `${logicalId}-sg`, {
476
+ vpc,
477
+ description: `Security group for ${projectName}-${intent.id} Redis`,
478
+ allowAllOutbound: false,
479
+ });
480
+ // Allow Redis-port ingress from anywhere in the VPC. Tighter
481
+ // scoping (Lambda SG → cache SG) isn't possible from this
482
+ // stack — the Lambda SG lives in the app stack. The CIDR-scoped
483
+ // rule is still secure (no internet exposure) and sufficient.
484
+ securityGroup.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(6379), 'Allow Redis access from VPC');
485
+ const subnetIds = vpc.isolatedSubnets?.length
486
+ ? vpc.isolatedSubnets.map((s) => s.subnetId)
487
+ : vpc.privateSubnets.map((s) => s.subnetId);
488
+ const subnetGroup = new elasticache.CfnSubnetGroup(this, `${logicalId}-subnet-group`, {
489
+ description: `Subnet group for ${projectName}-${intent.id}`,
490
+ subnetIds,
491
+ });
492
+ const cacheNodeType = sizeToCacheNodeType(intent.size || 'small');
493
+ const redis = new elasticache.CfnCacheCluster(this, logicalId, {
494
+ engine: 'redis',
495
+ cacheNodeType,
496
+ numCacheNodes: 1,
497
+ vpcSecurityGroupIds: [securityGroup.securityGroupId],
498
+ cacheSubnetGroupName: subnetGroup.ref,
499
+ transitEncryptionEnabled: true,
500
+ // Snapshot retention for strict (preserves the cache contents
501
+ // for ad-hoc forensic restore — not as durable as RDS but
502
+ // better than nothing for stateful Redis use cases).
503
+ snapshotRetentionLimit: this.isStrictRetain ? 7 : 0,
504
+ autoMinorVersionUpgrade: true,
505
+ });
506
+ writeSsm(this, dataKeys.cacheEndpoint(projectName, stage, intent.id), redis.attrRedisEndpointAddress, { description: `Redis endpoint for cache '${intent.id}'` });
507
+ writeSsm(this, dataKeys.cachePort(projectName, stage, intent.id), redis.attrRedisEndpointPort, { description: `Redis port for cache '${intent.id}'` });
508
+ writeSsm(this, dataKeys.cacheSecurityGroupId(projectName, stage, intent.id), securityGroup.securityGroupId, { description: `Cache SG ID — app stack imports + adds Lambda ingress` });
509
+ }
510
+ }
511
+ //# sourceMappingURL=data-stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-stack.js","sourceRoot":"","sources":["../../src/cdk/data-stack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Tier 5 — Edge stack.
3
+ *
4
+ * Owns the public-facing entry surface:
5
+ *
6
+ * - The `AWS::ApiGatewayV2::Api` (HttpApi) shell with stable
7
+ * ID + access logging configured. Routes (which target Lambdas)
8
+ * are added in the app stack via `HttpApi.fromHttpApiAttributes`
9
+ * + `addRoutes()`.
10
+ * - Custom domain(s) per `domains[]` intent: ACM certificate
11
+ * (existing ARN, Route53-validated, or DNS-validation-pending),
12
+ * `AWS::ApiGatewayV2::DomainName`, `ApiMapping` to the API's
13
+ * default stage, optional Route53 alias.
14
+ * - CloudFront distribution(s) over imported S3 buckets per
15
+ * `storage[]` intent that has `cdn: true`. Bucket lives in the
16
+ * data stack; distribution + Origin Access Control + alias DNS
17
+ * live here. The OAC's `aws:SourceArn`-scoped bucket policy
18
+ * statement is added to the imported `IBucket` automatically by
19
+ * `S3BucketOrigin.withOriginAccessControl(...)`.
20
+ *
21
+ * # Lifecycle position
22
+ *
23
+ * Updated occasionally (~quarterly): a new domain, a new CDN, an
24
+ * ACM cert rotation. The HttpApi ID itself is the most fragile:
25
+ * the `*.execute-api.{region}.amazonaws.com` URL embeds it, and
26
+ * mobile apps shipped with that URL baked in cannot be patched
27
+ * without a full update cycle. RETAIN under strict is therefore
28
+ * not just durability — it's external-contract preservation.
29
+ *
30
+ * # Public surface (via SSM)
31
+ *
32
+ * - `edgeKeys.apiId / apiEndpoint / apiCustomDomain /
33
+ * apiDefaultStageName` — the app stack reads these to import
34
+ * the API and add its discovered routes.
35
+ * - `edgeKeys.storageCdnDomain(storageId) /
36
+ * storageCdnDistributionId(storageId)` per CDN-fronted bucket.
37
+ *
38
+ * # What this stack does NOT do
39
+ *
40
+ * - **No routes / integrations.** `HttpApi.addRoutes(...)` runs
41
+ * in the app stack. CDK's `HttpApi.fromHttpApiAttributes` returns
42
+ * an `IHttpApi` that supports `addRoutes`, so the cross-stack
43
+ * pattern is the same as the in-stack one.
44
+ *
45
+ * - **No Lambda permissions.** API Gateway invoking a Lambda
46
+ * requires a `lambda:InvokeFunction` resource policy on the
47
+ * Lambda granted to `apigateway.amazonaws.com` with `aws:SourceArn`
48
+ * scoping. CDK's `HttpLambdaIntegration` adds that grant
49
+ * automatically when the route is created — which happens in the
50
+ * app stack.
51
+ *
52
+ * - **No CloudFront-Lambda@Edge wiring.** Edge Lambdas (request /
53
+ * response viewer functions) are extreme-rare in the VentureKit
54
+ * surface. If they're added later, they'd live here because their
55
+ * lifecycle is tied to the distribution, not to a single regional
56
+ * handler.
57
+ */
58
+ import * as cdk from 'aws-cdk-lib';
59
+ import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';
60
+ import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
61
+ import * as s3 from 'aws-cdk-lib/aws-s3';
62
+ import { Construct } from 'constructs';
63
+ import { type EnvConfig, type VentureIntent } from '@venturekit/core';
64
+ export interface VentureEdgeStackProps extends cdk.StackProps {
65
+ projectName: string;
66
+ stage: string;
67
+ envConfig: EnvConfig;
68
+ /** Reads `domains[]` and `storage[]` (CDN flag only). */
69
+ infrastructure: VentureIntent;
70
+ /**
71
+ * Imported `IBucket` per storage intent that has `cdn: true`.
72
+ * The CLI generator wires these up: data stack creates the bucket
73
+ * → generator captures `dataStack.buckets.get(id).bucket` → passes
74
+ * the map here. Edge stack imports each one and creates the
75
+ * CloudFront distribution + OAC bucket policy.
76
+ *
77
+ * Cross-deploy consumers can reconstruct via `s3.Bucket.fromBucketAttributes`
78
+ * + the data stack's published `bucketArn` SSM key, but the
79
+ * common case is in-process refs.
80
+ */
81
+ storageBuckets?: Map<string, s3.IBucket>;
82
+ }
83
+ export declare class VentureEdgeStack extends cdk.Stack {
84
+ readonly api: apigatewayv2.HttpApi;
85
+ readonly distributions: Map<string, cloudfront.Distribution>;
86
+ private readonly isStrictRetain;
87
+ constructor(scope: Construct, id: string, props: VentureEdgeStackProps);
88
+ private createDomain;
89
+ private createStorageCdn;
90
+ }
91
+ //# sourceMappingURL=edge-stack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-stack.d.ts","sourceRoot":"","sources":["../../src/cdk/edge-stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,YAAY,MAAM,8BAA8B,CAAC;AAI7D,OAAO,KAAK,UAAU,MAAM,4BAA4B,CAAC;AAEzD,OAAO,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAsB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAI1F,MAAM,WAAW,qBAAsB,SAAQ,GAAG,CAAC,UAAU;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,SAAS,CAAC;IAErB,yDAAyD;IACzD,cAAc,EAAE,aAAa,CAAC;IAE9B;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;CAC1C;AAaD,qBAAa,gBAAiB,SAAQ,GAAG,CAAC,KAAK;IAC7C,SAAgB,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC;IAE1C,SAAgB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,YAAY,CAAC,CAAa;IAEhF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;gBAE7B,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB;IAqJtE,OAAO,CAAC,YAAY;IA8FpB,OAAO,CAAC,gBAAgB;CAoHzB"}