@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,326 @@
1
+ /**
2
+ * Cross-stack reference helpers for the lifecycle-aligned multi-stack
3
+ * layout. Producers write SSM `String` parameters; consumers read via
4
+ * CFN dynamic references (`{{resolve:ssm:…}}`) which AWS resolves at
5
+ * deploy time without forming a CFN stack-graph dependency.
6
+ *
7
+ * # Producer side: `writeSsm` / `writeSsmStringList`
8
+ *
9
+ * Producer stacks (network, data, identity, config, messaging, edge)
10
+ * publish their public surface by calling these helpers. The actual
11
+ * CDK construct is `ssm.StringParameter` — we wrap it for two
12
+ * reasons:
13
+ *
14
+ * 1. Stable logical IDs. CDK's default ID derives from the
15
+ * construct path; we want IDs that don't churn across refactors
16
+ * so a producer-side rename (e.g. moving from
17
+ * `VentureDataStack.createRds` to `…createDatabase`) doesn't
18
+ * orphan the parameter and force a redeploy of every consumer.
19
+ * We derive the logical ID from a slug of the parameter name
20
+ * (`/venturekit/p/s/data/rds/main/endpoint` →
21
+ * `SsmVenturekitPSDataRdsMainEndpoint`), which is stable
22
+ * regardless of where in the stack tree the call site lives.
23
+ *
24
+ * 2. Single audit point. Every cross-stack value flowing out of a
25
+ * producer goes through `writeSsm`, so security review can grep
26
+ * one symbol to enumerate the public surface.
27
+ *
28
+ * # Consumer side: `readSsm…` + `import…`
29
+ *
30
+ * Consumers never instantiate AWS resources from raw construct props;
31
+ * they call the typed `import…` helpers below which encapsulate the
32
+ * full `Foo.fromXAttributes({...})` rehydration. That keeps the
33
+ * cross-stack contract narrow: the producer publishes exactly the
34
+ * fields the importer expects, the importer fails loudly at synth if
35
+ * any are missing, and any change to the contract shape forces a
36
+ * coordinated edit at both ends.
37
+ *
38
+ * # Why not `Stack.exportValue` / `Fn::ImportValue`?
39
+ *
40
+ * See the long-form rationale in `ssm-keys.ts`. tl;dr: CFN exports
41
+ * carry a hard "cannot modify a consumed export" lock that makes the
42
+ * stable lower tiers unable to evolve. SSM dynamic references have
43
+ * no such lock.
44
+ *
45
+ * # Why not StringList parameters?
46
+ *
47
+ * SSM `StringList` parameters cannot be referenced by the
48
+ * `{{resolve:ssm:...}}` dynamic-reference syntax — only `String` and
49
+ * `SecureString`. We work around it by storing comma-joined strings
50
+ * via `writeSsmStringList` and splitting on read via
51
+ * `readSsmStringList`. The split happens at deploy time inside CDK
52
+ * after the dynamic reference resolves, so it works transparently.
53
+ */
54
+ import * as cdk from 'aws-cdk-lib';
55
+ import * as ec2 from 'aws-cdk-lib/aws-ec2';
56
+ import * as s3 from 'aws-cdk-lib/aws-s3';
57
+ import * as cognito from 'aws-cdk-lib/aws-cognito';
58
+ import * as sqs from 'aws-cdk-lib/aws-sqs';
59
+ import * as sns from 'aws-cdk-lib/aws-sns';
60
+ import * as ssm from 'aws-cdk-lib/aws-ssm';
61
+ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
62
+ import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';
63
+ import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
64
+ // ─── Logical-ID derivation ────────────────────────────────────────────
65
+ /**
66
+ * Convert an SSM parameter name to a stable CDK logical ID.
67
+ *
68
+ * Rules:
69
+ * - Drop the leading slash.
70
+ * - Replace every non-alphanumeric character with a single space.
71
+ * - Title-case each word, drop spaces.
72
+ * - Prefix `Ssm` so logical IDs are namespaced.
73
+ *
74
+ * `/venturekit/myapp/prod/data/rds/main/endpoint` →
75
+ * `SsmVenturekitMyappProdDataRdsMainEndpoint`
76
+ *
77
+ * The output is deterministic, contains only alphanumerics, fits well
78
+ * within CFN's 255-char logical-ID limit (a maximally long key like
79
+ * `/venturekit/<32-char-project>/<8-char-stage>/messaging/queues/<32-char-id>/visibility-timeout-seconds`
80
+ * yields a ~120-char logical ID), and is stable across producer
81
+ * refactors.
82
+ */
83
+ export function logicalIdForParameter(parameterName) {
84
+ const cleaned = parameterName
85
+ .replace(/^\/+/, '')
86
+ .replace(/[^a-zA-Z0-9]+/g, ' ')
87
+ .trim()
88
+ .split(/\s+/)
89
+ .map((segment) => segment.length === 0
90
+ ? ''
91
+ : segment[0].toUpperCase() + segment.slice(1).toLowerCase())
92
+ .join('');
93
+ return `Ssm${cleaned}`;
94
+ }
95
+ /**
96
+ * Publish a single string value to SSM at `name`. Returns the
97
+ * underlying `ssm.StringParameter` so the caller can grant additional
98
+ * IAM permissions (rare; the default SSM-read IAM is sufficient for
99
+ * the dynamic-reference path).
100
+ *
101
+ * Idempotent within one synth: calling `writeSsm` twice with the same
102
+ * name in the same stack throws CDK's standard
103
+ * "Construct with id 'X' already exists" — that's a producer bug
104
+ * (two producers claiming the same key).
105
+ */
106
+ export function writeSsm(scope, name, value, opts = {}) {
107
+ const logicalId = logicalIdForParameter(name);
108
+ const param = new ssm.StringParameter(scope, logicalId, {
109
+ parameterName: name,
110
+ stringValue: value,
111
+ description: opts.description,
112
+ // Standard tier — free, 4 KB max value. None of our cross-stack
113
+ // values come anywhere near that ceiling (the largest is the
114
+ // comma-joined subnet IDs, ~150 bytes for 6 subnet IDs). Going
115
+ // Advanced would just cost money for no benefit.
116
+ tier: ssm.ParameterTier.STANDARD,
117
+ });
118
+ // Pin the CFN logical ID to exactly the slug we derived from the
119
+ // parameter name. CDK's default allocator appends an 8-char hash
120
+ // suffix to disambiguate L2 children that wrap an L1 `Resource`,
121
+ // which would make the logical ID unstable across CDK upgrades and
122
+ // less greppable. The slug already encodes the parameter name, so
123
+ // collisions inside one stack are impossible by construction.
124
+ param.node.defaultChild.overrideLogicalId(logicalId);
125
+ return param;
126
+ }
127
+ /**
128
+ * Publish a list as a single comma-joined `String` parameter. Use
129
+ * this for things like subnet ID lists where the consumer needs the
130
+ * individual values back. SSM `StringList` parameters are rejected
131
+ * by the `{{resolve:ssm:…}}` dynamic reference, so we round-trip via
132
+ * comma-joined strings.
133
+ *
134
+ * Throws if any element contains a comma — that would silently
135
+ * corrupt the list on read. AWS resource IDs (subnet IDs, AZ names,
136
+ * security group IDs) are guaranteed comma-free, so this should
137
+ * never fire in practice; the assertion just locks the assumption.
138
+ */
139
+ export function writeSsmStringList(scope, name, values, opts = {}) {
140
+ for (const v of values) {
141
+ if (v.includes(',')) {
142
+ throw new Error(`writeSsmStringList: value '${v}' for parameter '${name}' contains a comma. ` +
143
+ `Comma-joined storage in SSM is the cross-stack workaround for the lack of ` +
144
+ `StringList support in CFN dynamic references; commas inside values would ` +
145
+ `silently corrupt the round-trip on the consumer side.`);
146
+ }
147
+ }
148
+ return writeSsm(scope, name, values.join(','), opts);
149
+ }
150
+ // ─── Consumer helpers ────────────────────────────────────────────────
151
+ /**
152
+ * Read a single SSM string parameter as a CFN dynamic reference.
153
+ * The returned token resolves to the parameter's current value at
154
+ * deploy time — there is NO build-time / synth-time AWS API call,
155
+ * so this works in hermetic CI without AWS credentials.
156
+ *
157
+ * The token can be passed anywhere CDK accepts a string property
158
+ * (resource ARNs, IDs, env vars). It cannot be inspected at synth
159
+ * time — `console.log(value)` will print `${Token[TOKEN.123]}`,
160
+ * not the actual value.
161
+ */
162
+ export function readSsmString(scope, name) {
163
+ return ssm.StringParameter.valueForStringParameter(scope, name);
164
+ }
165
+ /**
166
+ * Read a comma-joined `String` parameter and split it back into a
167
+ * list. Used as the symmetric counterpart to `writeSsmStringList`.
168
+ *
169
+ * Implementation note: because the parameter value is a CFN token
170
+ * resolved at deploy time, we cannot call `.split(',')` directly —
171
+ * the token is opaque to JS. CDK's `Fn.split` produces a CFN
172
+ * `Fn::Split` intrinsic that runs at deploy time; we then use
173
+ * `Fn.select` to access individual elements OR pass the whole
174
+ * `cdk.Token`-wrapped array into a context that accepts arrays.
175
+ *
176
+ * `count` is the **expected** number of elements — required because
177
+ * `Fn::Split` returns a length-unknown list and CDK refuses to
178
+ * iterate it without a hint. Callers who don't know the count up
179
+ * front (rare) should pass it through SSM as a separate parameter.
180
+ */
181
+ export function readSsmStringList(scope, name, count) {
182
+ if (!Number.isInteger(count) || count <= 0) {
183
+ throw new Error(`readSsmStringList: 'count' must be a positive integer (got ${count}). ` +
184
+ `CFN's Fn::Split returns a length-unknown list; CDK can't iterate it ` +
185
+ `without an expected length.`);
186
+ }
187
+ const joined = readSsmString(scope, name);
188
+ // Fn.split returns a Token-wrapped array of strings. Fn.select picks
189
+ // a specific index. We unroll the list synchronously based on
190
+ // `count` so callers can pass the result anywhere a `string[]` is
191
+ // expected.
192
+ const tokens = cdk.Fn.split(',', joined, count);
193
+ // `cdk.Fn.split` already returns a string[]-typed token list of
194
+ // exactly `count` elements; surface it directly.
195
+ return tokens;
196
+ }
197
+ /**
198
+ * Reconstruct a VPC abstraction from its public attributes (read out
199
+ * of SSM by the consumer). This deliberately uses
200
+ * `Vpc.fromVpcAttributes` rather than `Vpc.fromLookup` because:
201
+ *
202
+ * 1. `fromLookup` makes a real `ec2:DescribeVpcs` API call at synth
203
+ * time, breaking hermetic CI (the runner needs IAM creds).
204
+ * 2. `fromLookup` writes results into `cdk.context.json`, which
205
+ * then needs to be checked in or regenerated; that's another
206
+ * moving part for no benefit when the consumer already has
207
+ * every needed attribute via SSM.
208
+ *
209
+ * AZ + subnet-ID lists must be the same length and same ordering —
210
+ * CDK uses the index to pair each subnet with its AZ. Lists shorter
211
+ * than the AZ list mean "no subnet in that AZ"; CDK handles that fine.
212
+ */
213
+ export function importVpc(scope, id, params) {
214
+ return ec2.Vpc.fromVpcAttributes(scope, id, {
215
+ vpcId: params.vpcId,
216
+ availabilityZones: params.availabilityZones,
217
+ privateSubnetIds: params.privateSubnetIds,
218
+ publicSubnetIds: params.publicSubnetIds,
219
+ isolatedSubnetIds: params.isolatedSubnetIds,
220
+ });
221
+ }
222
+ /**
223
+ * Import the RDS connection surface (endpoint + port + SG) without
224
+ * actually instantiating an `IDatabaseInstance` — we don't need the
225
+ * full DB abstraction in the app stack, just enough to point Lambdas
226
+ * at it and open the SG.
227
+ */
228
+ export function importRdsConnection(scope, id, params) {
229
+ const port = typeof params.port === 'number'
230
+ ? params.port
231
+ : Number.parseInt(params.port, 10);
232
+ if (!Number.isFinite(port)) {
233
+ throw new Error(`importRdsConnection: failed to parse RDS port from value '${params.port}'. ` +
234
+ `The producer (data stack) writes port as a numeric string via the SSM ` +
235
+ `parameter at ${id}.`);
236
+ }
237
+ const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(scope, `${id}-sg`, params.securityGroupId,
238
+ // `mutable: true` lets the consumer add ingress rules locally
239
+ // (the rule lands in the consumer stack; the imported SG itself
240
+ // is unchanged in the producer stack).
241
+ { mutable: true });
242
+ return { endpoint: params.endpoint, port, securityGroup };
243
+ }
244
+ /**
245
+ * Import an S3 bucket by ARN. Returns an `IBucket` so the consumer
246
+ * can call `bucket.grantReadWrite(lambdaRole)` etc. — those grants
247
+ * land in the consumer stack's IAM policy, leaving the bucket
248
+ * itself untouched.
249
+ *
250
+ * `Bucket.fromBucketArn` returns a less-typed view (no
251
+ * encryption/versioning info) than `fromBucketAttributes`, but for
252
+ * IAM grants and env-var injection that's all the app stack needs.
253
+ */
254
+ export function importBucket(scope, id, bucketArn) {
255
+ return s3.Bucket.fromBucketArn(scope, id, bucketArn);
256
+ }
257
+ /**
258
+ * Import a DynamoDB table by ARN. Returns an `ITable` for IAM
259
+ * grants. Note: `Table.fromTableArn` does NOT include the GSI
260
+ * indexes — for `Query` against a GSI, the consumer must call
261
+ * `Table.fromTableAttributes({ tableArn, globalIndexes: ['gsi1'] })`
262
+ * instead. Since most app-stack code paths only read/write the
263
+ * primary key, ARN-only is the common case; we wrap it here for
264
+ * convenience and document the GSI exception.
265
+ */
266
+ export function importDynamoTable(scope, id, tableArn) {
267
+ return dynamodb.Table.fromTableArn(scope, id, tableArn);
268
+ }
269
+ /**
270
+ * Import a Cognito User Pool. The pool ID is what `AdminInitiateAuth`
271
+ * etc. need at runtime; the ARN is what IAM policies scope to. Both
272
+ * are published by the identity stack via `identityKeys`.
273
+ */
274
+ export function importUserPool(scope, id, params) {
275
+ // `fromUserPoolArn` is sufficient: CDK extracts the pool ID from
276
+ // the ARN, and the resulting IUserPool exposes `userPoolId`.
277
+ // Passing both fields explicitly via `fromUserPoolAttributes`
278
+ // would be redundant.
279
+ return cognito.UserPool.fromUserPoolArn(scope, id, params.userPoolArn);
280
+ }
281
+ /**
282
+ * Import an SQS queue by ARN. The CDK helper extracts the URL from
283
+ * the ARN under the standard naming convention, which is what
284
+ * Lambda's `addEventSource(new SqsEventSource(queue))` wants.
285
+ *
286
+ * On consumer-stack delete, the resulting `EventSourceMapping` is
287
+ * removed; the queue + DLQ + buffered messages live on in the
288
+ * messaging stack (plan §6.2).
289
+ */
290
+ export function importQueue(scope, id, queueArn) {
291
+ return sqs.Queue.fromQueueArn(scope, id, queueArn);
292
+ }
293
+ /**
294
+ * Import an SNS topic by ARN. Used by the app stack to subscribe
295
+ * the bounce-handler Lambda to the notify events topic created in
296
+ * the config tier.
297
+ */
298
+ export function importTopic(scope, id, topicArn) {
299
+ return sns.Topic.fromTopicArn(scope, id, topicArn);
300
+ }
301
+ /**
302
+ * Import a Secrets Manager secret by ARN. Used for every
303
+ * cross-stack secret reference (RDS master credentials, federated
304
+ * provider OAuth credentials, WhatsApp tokens, operator-declared
305
+ * `secrets` intents).
306
+ */
307
+ export function importSecret(scope, id, secretArn) {
308
+ return secretsmanager.Secret.fromSecretCompleteArn(scope, id, secretArn);
309
+ }
310
+ /**
311
+ * Import an API Gateway HttpApi. The app stack needs this to add
312
+ * routes that target Lambdas in the app stack itself — the route
313
+ * `AWS::ApiGatewayV2::Route` resource lives in the consumer (app)
314
+ * stack and references the imported API by ID.
315
+ *
316
+ * IMPORTANT: `HttpApi.fromHttpApiAttributes` does NOT carry the
317
+ * `defaultStage` in its returned `IHttpApi`; consumers that need
318
+ * to attach access logs or stage variables must manage that
319
+ * separately on the producer (edge) side.
320
+ */
321
+ export function importHttpApi(scope, id, params) {
322
+ return apigatewayv2.HttpApi.fromHttpApiAttributes(scope, id, {
323
+ httpApiId: params.apiId,
324
+ });
325
+ }
326
+ //# sourceMappingURL=cross-stack-refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-stack-refs.js","sourceRoot":"","sources":["../../../src/cdk/shared/cross-stack-refs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Lambda-bundling + runtime-mapping helpers shared between the legacy
3
+ * `VentureStack` and the new per-tier `VentureAppStack`. Pure
4
+ * functions only — no class state, no hidden globals beyond the
5
+ * lazily-loaded esbuild module.
6
+ *
7
+ * # Why a shared module
8
+ *
9
+ * During the §11 multi-stack migration both `stack.ts` (legacy) and
10
+ * `app-stack.ts` need to bundle handlers, map preset config to the
11
+ * `lambda.Runtime` / `lambda.Architecture` enums, and compute log-
12
+ * retention. Duplicating ~80 lines of bundling logic between two
13
+ * files would diverge over time. Step §11.10 deletes the legacy
14
+ * stack and this module becomes the single home.
15
+ */
16
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
17
+ import * as logs from 'aws-cdk-lib/aws-logs';
18
+ import type { EnvConfig } from '@venturekit/core';
19
+ /**
20
+ * Bundle a Lambda handler in-process via esbuild's synchronous API.
21
+ *
22
+ * Replaces an earlier Docker-based bundling pipeline that spun up a
23
+ * SAM Node 20 image, ran `npm install -g esbuild`, and bundled the
24
+ * handler — taking ~30 s per Lambda. With 100+ handlers in a project
25
+ * that meant over an hour of synth time and a long tail of Docker-
26
+ * related failure modes (UID/HOME/permission edge cases on GitHub-
27
+ * hosted runners). In-process bundling collapses the entire sequence
28
+ * to a single `esbuild.buildSync` call: sub-second per handler,
29
+ * native Node module resolution against the consumer's `node_modules`,
30
+ * no Docker daemon dependency.
31
+ *
32
+ * The asset is the temp directory holding the bundled `index.js`, so
33
+ * CDK uploads only the bundled output to S3 — never the source tree.
34
+ *
35
+ * Modules baked into the Lambda runtime (`@aws-sdk/*`) are kept
36
+ * external so they aren't redundantly included in the bundle.
37
+ */
38
+ export declare function bundleHandlerCodeWithEsbuild(handlerFile: string, projectDir: string): lambda.Code;
39
+ /**
40
+ * Inline Lambda stub used in unit tests when `skipBundling: true`.
41
+ * Satisfies API Gateway's contract; tests assert on resource shape,
42
+ * not on Lambda execution.
43
+ */
44
+ export declare function inlineStubLambdaCode(): lambda.Code;
45
+ export declare function toLambdaRuntime(envConfig: EnvConfig): lambda.Runtime;
46
+ export declare function toLambdaArchitecture(envConfig: EnvConfig): lambda.Architecture;
47
+ export declare function toLogRetention(days: number): logs.RetentionDays;
48
+ /**
49
+ * Tiny non-cryptographic 6-char hex hash. Used only to disambiguate
50
+ * Lambda function names that would otherwise overflow the 64-char
51
+ * limit; collision risk is acceptable because the truncated prefix
52
+ * already encodes most of the route path.
53
+ */
54
+ export declare function shortHash(input: string): string;
55
+ /**
56
+ * Cap a Lambda function name at the AWS hard limit (64 chars). When
57
+ * the natural name overflows, replace the trailing portion with a
58
+ * 6-char hash of the original — preserving the first 56 chars so
59
+ * operators can still recognize the resource by prefix.
60
+ */
61
+ export declare function clampLambdaFunctionName(rawName: string): string;
62
+ /**
63
+ * Recursively discover Lambda handler files under a directory. Used
64
+ * for `src/queues/`, `src/crons/`, `src/functions/` — all of which
65
+ * follow the same convention: every `.ts` / `.js` file (excluding
66
+ * `.d.ts` declarations) is one Lambda. The handler name is the
67
+ * dash-delimited relative path:
68
+ *
69
+ * src/queues/order/create-order.ts → 'order-create-order'
70
+ * src/crons/cleanup.ts → 'cleanup'
71
+ *
72
+ * Test files (`*.test.ts`, `*.spec.ts`) are excluded so colocated
73
+ * tests don't accidentally become production Lambdas.
74
+ *
75
+ * Exported pure function so app-stack tests can build fixtures
76
+ * without spinning up a CDK stack.
77
+ */
78
+ export declare function discoverFunctionFiles(dir: string, baseDir?: string): Array<{
79
+ name: string;
80
+ handlerFile: string;
81
+ }>;
82
+ //# sourceMappingURL=lambda-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lambda-helpers.d.ts","sourceRoot":"","sources":["../../../src/cdk/shared/lambda-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,MAAM,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,IAAI,MAAM,sBAAsB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAuBlD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,IAAI,CAgBb;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,IAAI,CAIlD;AAID,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAAC,OAAO,CAWpE;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAAC,YAAY,CAI9E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,aAAa,CAiB/D;AAID;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI/D;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,GACf,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAwB9C"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Lambda-bundling + runtime-mapping helpers shared between the legacy
3
+ * `VentureStack` and the new per-tier `VentureAppStack`. Pure
4
+ * functions only — no class state, no hidden globals beyond the
5
+ * lazily-loaded esbuild module.
6
+ *
7
+ * # Why a shared module
8
+ *
9
+ * During the §11 multi-stack migration both `stack.ts` (legacy) and
10
+ * `app-stack.ts` need to bundle handlers, map preset config to the
11
+ * `lambda.Runtime` / `lambda.Architecture` enums, and compute log-
12
+ * retention. Duplicating ~80 lines of bundling logic between two
13
+ * files would diverge over time. Step §11.10 deletes the legacy
14
+ * stack and this module becomes the single home.
15
+ */
16
+ import * as fs from 'fs';
17
+ import * as os from 'os';
18
+ import * as path from 'path';
19
+ import { createRequire } from 'module';
20
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
21
+ import * as logs from 'aws-cdk-lib/aws-logs';
22
+ // ─── esbuild lazy-load ──────────────────────────────────────────────
23
+ /**
24
+ * Lazily-loaded esbuild module. Top-level import is avoided so unit
25
+ * tests that set `skipBundling: true` (which short-circuits before any
26
+ * bundling happens) don't pay the import cost or require esbuild to
27
+ * be installed in their sandbox. `createRequire` works around the
28
+ * fact that this file is ESM while esbuild's package exports are
29
+ * CJS-shaped.
30
+ */
31
+ let esbuildModule;
32
+ function loadEsbuild() {
33
+ if (!esbuildModule) {
34
+ const requireFromHere = createRequire(import.meta.url);
35
+ esbuildModule = requireFromHere('esbuild');
36
+ }
37
+ return esbuildModule;
38
+ }
39
+ // ─── Bundling ───────────────────────────────────────────────────────
40
+ /**
41
+ * Bundle a Lambda handler in-process via esbuild's synchronous API.
42
+ *
43
+ * Replaces an earlier Docker-based bundling pipeline that spun up a
44
+ * SAM Node 20 image, ran `npm install -g esbuild`, and bundled the
45
+ * handler — taking ~30 s per Lambda. With 100+ handlers in a project
46
+ * that meant over an hour of synth time and a long tail of Docker-
47
+ * related failure modes (UID/HOME/permission edge cases on GitHub-
48
+ * hosted runners). In-process bundling collapses the entire sequence
49
+ * to a single `esbuild.buildSync` call: sub-second per handler,
50
+ * native Node module resolution against the consumer's `node_modules`,
51
+ * no Docker daemon dependency.
52
+ *
53
+ * The asset is the temp directory holding the bundled `index.js`, so
54
+ * CDK uploads only the bundled output to S3 — never the source tree.
55
+ *
56
+ * Modules baked into the Lambda runtime (`@aws-sdk/*`) are kept
57
+ * external so they aren't redundantly included in the bundle.
58
+ */
59
+ export function bundleHandlerCodeWithEsbuild(handlerFile, projectDir) {
60
+ const outDir = fs.mkdtempSync(path.join(os.tmpdir(), 'venturekit-bundle-'));
61
+ const outfile = path.join(outDir, 'index.js');
62
+ loadEsbuild().buildSync({
63
+ entryPoints: [handlerFile],
64
+ bundle: true,
65
+ platform: 'node',
66
+ target: 'node20',
67
+ outfile,
68
+ external: ['@aws-sdk/*'],
69
+ absWorkingDir: projectDir,
70
+ logLevel: 'error',
71
+ });
72
+ return lambda.Code.fromAsset(outDir);
73
+ }
74
+ /**
75
+ * Inline Lambda stub used in unit tests when `skipBundling: true`.
76
+ * Satisfies API Gateway's contract; tests assert on resource shape,
77
+ * not on Lambda execution.
78
+ */
79
+ export function inlineStubLambdaCode() {
80
+ return lambda.Code.fromInline("exports.main = async () => ({ statusCode: 200, body: '{\"stub\":true}' });");
81
+ }
82
+ // ─── Runtime / architecture / log-retention mapping ────────────────
83
+ export function toLambdaRuntime(envConfig) {
84
+ switch (envConfig.lambda.runtime) {
85
+ case 'nodejs22.x':
86
+ return lambda.Runtime.NODEJS_22_X;
87
+ case 'nodejs20.x':
88
+ return lambda.Runtime.NODEJS_20_X;
89
+ case 'nodejs18.x':
90
+ return lambda.Runtime.NODEJS_18_X;
91
+ default:
92
+ return lambda.Runtime.NODEJS_20_X;
93
+ }
94
+ }
95
+ export function toLambdaArchitecture(envConfig) {
96
+ return envConfig.lambda.architecture === 'x86_64'
97
+ ? lambda.Architecture.X86_64
98
+ : lambda.Architecture.ARM_64;
99
+ }
100
+ export function toLogRetention(days) {
101
+ if (days <= 1)
102
+ return logs.RetentionDays.ONE_DAY;
103
+ if (days <= 3)
104
+ return logs.RetentionDays.THREE_DAYS;
105
+ if (days <= 5)
106
+ return logs.RetentionDays.FIVE_DAYS;
107
+ if (days <= 7)
108
+ return logs.RetentionDays.ONE_WEEK;
109
+ if (days <= 14)
110
+ return logs.RetentionDays.TWO_WEEKS;
111
+ if (days <= 30)
112
+ return logs.RetentionDays.ONE_MONTH;
113
+ if (days <= 60)
114
+ return logs.RetentionDays.TWO_MONTHS;
115
+ if (days <= 90)
116
+ return logs.RetentionDays.THREE_MONTHS;
117
+ if (days <= 120)
118
+ return logs.RetentionDays.FOUR_MONTHS;
119
+ if (days <= 150)
120
+ return logs.RetentionDays.FIVE_MONTHS;
121
+ if (days <= 180)
122
+ return logs.RetentionDays.SIX_MONTHS;
123
+ if (days <= 365)
124
+ return logs.RetentionDays.ONE_YEAR;
125
+ if (days <= 400)
126
+ return logs.RetentionDays.THIRTEEN_MONTHS;
127
+ if (days <= 545)
128
+ return logs.RetentionDays.EIGHTEEN_MONTHS;
129
+ if (days <= 731)
130
+ return logs.RetentionDays.TWO_YEARS;
131
+ return logs.RetentionDays.INFINITE;
132
+ }
133
+ // ─── Naming helpers ─────────────────────────────────────────────────
134
+ /**
135
+ * Tiny non-cryptographic 6-char hex hash. Used only to disambiguate
136
+ * Lambda function names that would otherwise overflow the 64-char
137
+ * limit; collision risk is acceptable because the truncated prefix
138
+ * already encodes most of the route path.
139
+ */
140
+ export function shortHash(input) {
141
+ let h = 5381;
142
+ for (let i = 0; i < input.length; i++) {
143
+ h = ((h << 5) + h + input.charCodeAt(i)) | 0;
144
+ }
145
+ return (h >>> 0).toString(16).padStart(6, '0').slice(0, 6);
146
+ }
147
+ /**
148
+ * Cap a Lambda function name at the AWS hard limit (64 chars). When
149
+ * the natural name overflows, replace the trailing portion with a
150
+ * 6-char hash of the original — preserving the first 56 chars so
151
+ * operators can still recognize the resource by prefix.
152
+ */
153
+ export function clampLambdaFunctionName(rawName) {
154
+ return rawName.length <= 64
155
+ ? rawName
156
+ : `${rawName.slice(0, 56)}-${shortHash(rawName)}`;
157
+ }
158
+ // ─── Function-file discovery ────────────────────────────────────────
159
+ /**
160
+ * Recursively discover Lambda handler files under a directory. Used
161
+ * for `src/queues/`, `src/crons/`, `src/functions/` — all of which
162
+ * follow the same convention: every `.ts` / `.js` file (excluding
163
+ * `.d.ts` declarations) is one Lambda. The handler name is the
164
+ * dash-delimited relative path:
165
+ *
166
+ * src/queues/order/create-order.ts → 'order-create-order'
167
+ * src/crons/cleanup.ts → 'cleanup'
168
+ *
169
+ * Test files (`*.test.ts`, `*.spec.ts`) are excluded so colocated
170
+ * tests don't accidentally become production Lambdas.
171
+ *
172
+ * Exported pure function so app-stack tests can build fixtures
173
+ * without spinning up a CDK stack.
174
+ */
175
+ export function discoverFunctionFiles(dir, baseDir) {
176
+ const root = baseDir ?? dir;
177
+ const results = [];
178
+ if (!fs.existsSync(dir))
179
+ return results;
180
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
181
+ for (const entry of entries) {
182
+ const fullPath = path.join(dir, entry.name);
183
+ if (entry.isDirectory()) {
184
+ results.push(...discoverFunctionFiles(fullPath, root));
185
+ continue;
186
+ }
187
+ if (!/\.(ts|js)$/.test(entry.name))
188
+ continue;
189
+ if (entry.name.endsWith('.d.ts'))
190
+ continue;
191
+ if (/\.(test|spec)\.(ts|js)$/.test(entry.name))
192
+ continue;
193
+ const relativePath = path.relative(root, fullPath);
194
+ const name = relativePath
195
+ .replace(/\.(ts|js)$/, '')
196
+ .replace(/[\\/]/g, '-');
197
+ results.push({ name, handlerFile: fullPath });
198
+ }
199
+ return results;
200
+ }
201
+ //# sourceMappingURL=lambda-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lambda-helpers.js","sourceRoot":"","sources":["../../../src/cdk/shared/lambda-helpers.ts"],"names":[],"mappings":"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"}