@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.
- package/dist/cdk/app-stack.d.ts +330 -0
- package/dist/cdk/app-stack.d.ts.map +1 -0
- package/dist/cdk/app-stack.js +875 -0
- package/dist/cdk/app-stack.js.map +1 -0
- package/dist/cdk/config-stack.d.ts +104 -0
- package/dist/cdk/config-stack.d.ts.map +1 -0
- package/dist/cdk/config-stack.js +161 -0
- package/dist/cdk/config-stack.js.map +1 -0
- package/dist/cdk/data-stack.d.ts +198 -0
- package/dist/cdk/data-stack.d.ts.map +1 -0
- package/dist/cdk/data-stack.js +511 -0
- package/dist/cdk/data-stack.js.map +1 -0
- package/dist/cdk/edge-stack.d.ts +91 -0
- package/dist/cdk/edge-stack.d.ts.map +1 -0
- package/dist/cdk/edge-stack.js +364 -0
- package/dist/cdk/edge-stack.js.map +1 -0
- package/dist/cdk/identity-stack.d.ts +98 -0
- package/dist/cdk/identity-stack.d.ts.map +1 -0
- package/dist/cdk/identity-stack.js +254 -0
- package/dist/cdk/identity-stack.js.map +1 -0
- package/dist/cdk/index.d.ts +16 -0
- package/dist/cdk/index.d.ts.map +1 -1
- package/dist/cdk/index.js +17 -0
- package/dist/cdk/index.js.map +1 -1
- package/dist/cdk/messaging-stack.d.ts +109 -0
- package/dist/cdk/messaging-stack.d.ts.map +1 -0
- package/dist/cdk/messaging-stack.js +320 -0
- package/dist/cdk/messaging-stack.js.map +1 -0
- package/dist/cdk/network-stack.d.ts +87 -0
- package/dist/cdk/network-stack.d.ts.map +1 -0
- package/dist/cdk/network-stack.js +265 -0
- package/dist/cdk/network-stack.js.map +1 -0
- package/dist/cdk/shared/cross-stack-refs.d.ts +278 -0
- package/dist/cdk/shared/cross-stack-refs.d.ts.map +1 -0
- package/dist/cdk/shared/cross-stack-refs.js +326 -0
- package/dist/cdk/shared/cross-stack-refs.js.map +1 -0
- package/dist/cdk/shared/lambda-helpers.d.ts +82 -0
- package/dist/cdk/shared/lambda-helpers.d.ts.map +1 -0
- package/dist/cdk/shared/lambda-helpers.js +201 -0
- package/dist/cdk/shared/lambda-helpers.js.map +1 -0
- package/dist/cdk/shared/ssm-keys.d.ts +460 -0
- package/dist/cdk/shared/ssm-keys.d.ts.map +1 -0
- package/dist/cdk/shared/ssm-keys.js +291 -0
- package/dist/cdk/shared/ssm-keys.js.map +1 -0
- package/dist/cdk/stack.d.ts +3 -11
- package/dist/cdk/stack.d.ts.map +1 -1
- package/dist/cdk/stack.js +184 -41
- package/dist/cdk/stack.js.map +1 -1
- 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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"}
|