@fjall/generator 0.88.4
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/src/ast/astComputeParser.d.ts +4 -0
- package/dist/src/ast/astComputeParser.js +427 -0
- package/dist/src/ast/astInfrastructureParser.d.ts +357 -0
- package/dist/src/ast/astInfrastructureParser.js +1925 -0
- package/dist/src/ast/astSurgicalModification.d.ts +47 -0
- package/dist/src/ast/astSurgicalModification.js +400 -0
- package/dist/src/ast/index.d.ts +2 -0
- package/dist/src/ast/index.js +2 -0
- package/dist/src/aws/regions.d.ts +30 -0
- package/dist/src/aws/regions.js +254 -0
- package/dist/src/generation/common.d.ts +86 -0
- package/dist/src/generation/common.js +187 -0
- package/dist/src/generation/compute.d.ts +6 -0
- package/dist/src/generation/compute.js +547 -0
- package/dist/src/generation/database.d.ts +54 -0
- package/dist/src/generation/database.js +201 -0
- package/dist/src/generation/index.d.ts +12 -0
- package/dist/src/generation/index.js +18 -0
- package/dist/src/generation/infrastructure.d.ts +44 -0
- package/dist/src/generation/infrastructure.js +389 -0
- package/dist/src/generation/storage.d.ts +23 -0
- package/dist/src/generation/storage.js +174 -0
- package/dist/src/generation/storageConnections.d.ts +37 -0
- package/dist/src/generation/storageConnections.js +71 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +19 -0
- package/dist/src/planning/index.d.ts +1 -0
- package/dist/src/planning/index.js +1 -0
- package/dist/src/planning/resourcePlanning.d.ts +58 -0
- package/dist/src/planning/resourcePlanning.js +216 -0
- package/dist/src/presets/index.d.ts +3 -0
- package/dist/src/presets/index.js +3 -0
- package/dist/src/presets/patternTierPresets.d.ts +93 -0
- package/dist/src/presets/patternTierPresets.js +131 -0
- package/dist/src/presets/storagePresets.d.ts +11 -0
- package/dist/src/presets/storagePresets.js +36 -0
- package/dist/src/presets/tierPresets.d.ts +59 -0
- package/dist/src/presets/tierPresets.js +384 -0
- package/dist/src/presets/tierTypes.d.ts +301 -0
- package/dist/src/presets/tierTypes.js +7 -0
- package/dist/src/schemas/constants.d.ts +74 -0
- package/dist/src/schemas/constants.js +208 -0
- package/dist/src/schemas/index.d.ts +3 -0
- package/dist/src/schemas/index.js +3 -0
- package/dist/src/schemas/instanceTypeArchitecture.d.ts +35 -0
- package/dist/src/schemas/instanceTypeArchitecture.js +75 -0
- package/dist/src/schemas/resourceSchemas.d.ts +3534 -0
- package/dist/src/schemas/resourceSchemas.js +2015 -0
- package/dist/src/types/Result.d.ts +19 -0
- package/dist/src/types/Result.js +31 -0
- package/dist/src/util/errorUtils.d.ts +2 -0
- package/dist/src/util/errorUtils.js +15 -0
- package/dist/src/validation/patterns.d.ts +300 -0
- package/dist/src/validation/patterns.js +360 -0
- package/dist/src/version.d.ts +1 -0
- package/dist/src/version.js +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ParsedInfrastructure } from "./astInfrastructureParser.js";
|
|
2
|
+
import { type ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
|
|
3
|
+
/** Convert parsed compute resources to plan format */
|
|
4
|
+
export declare function convertComputeResources(parsed: ParsedInfrastructure, plan: ApplicationResourcePlan): ApplicationResourcePlan["compute"];
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { isPlainObject, isParsedObject, isIdentifierRef, isExpressionRef, isCallRef, asString, asNumber, asBoolean, asStringArray, asStringUnion, captureExtraProperties, } from "./astInfrastructureParser.js";
|
|
2
|
+
import { COMPUTE_TYPES, DEPLOYMENT_TYPES, EC2_INSTANCE_TYPES, ECS_CAPACITY_PROVIDERS, } from "../schemas/constants.js";
|
|
3
|
+
const MAX_DATABASE_CONNECTION_INDICES = 10;
|
|
4
|
+
const LOAD_BALANCER_TYPES = ["public", "internal"];
|
|
5
|
+
function isEnvironmentRecord(value) {
|
|
6
|
+
return value !== undefined && isPlainObject(value);
|
|
7
|
+
}
|
|
8
|
+
function parseContainerSecretsImport(secretsImportValue) {
|
|
9
|
+
if (!isParsedObject(secretsImportValue))
|
|
10
|
+
return undefined;
|
|
11
|
+
const result = {};
|
|
12
|
+
for (const [key, val] of Object.entries(secretsImportValue)) {
|
|
13
|
+
if (isParsedObject(val)) {
|
|
14
|
+
const id = asString(val.id);
|
|
15
|
+
const name = asString(val.name);
|
|
16
|
+
if (id && name) {
|
|
17
|
+
result[key] = { id, name, field: asString(val.field) };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
22
|
+
}
|
|
23
|
+
function parseContainerHealthCheck(healthCheckValue) {
|
|
24
|
+
if (!isParsedObject(healthCheckValue))
|
|
25
|
+
return undefined;
|
|
26
|
+
const cmd = asStringArray(healthCheckValue.command);
|
|
27
|
+
if (!cmd || cmd.length === 0)
|
|
28
|
+
return undefined;
|
|
29
|
+
return {
|
|
30
|
+
command: cmd,
|
|
31
|
+
interval: asNumber(healthCheckValue.interval),
|
|
32
|
+
timeout: asNumber(healthCheckValue.timeout),
|
|
33
|
+
retries: asNumber(healthCheckValue.retries),
|
|
34
|
+
startPeriod: asNumber(healthCheckValue.startPeriod),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function parseServiceContainer(c) {
|
|
38
|
+
const CONTAINER_KNOWN_KEYS = new Set([
|
|
39
|
+
"name",
|
|
40
|
+
"image",
|
|
41
|
+
"port",
|
|
42
|
+
"environment",
|
|
43
|
+
"essential",
|
|
44
|
+
"command",
|
|
45
|
+
"entryPoint",
|
|
46
|
+
"secretsImport",
|
|
47
|
+
"secrets",
|
|
48
|
+
"healthCheck",
|
|
49
|
+
]);
|
|
50
|
+
const extras = captureExtraProperties(c, CONTAINER_KNOWN_KEYS);
|
|
51
|
+
return {
|
|
52
|
+
name: asString(c.name),
|
|
53
|
+
image: asString(c.image),
|
|
54
|
+
port: asNumber(c.port),
|
|
55
|
+
environment: isEnvironmentRecord(c.environment) ? c.environment : undefined,
|
|
56
|
+
essential: asBoolean(c.essential),
|
|
57
|
+
command: asStringArray(c.command),
|
|
58
|
+
entryPoint: asStringArray(c.entryPoint),
|
|
59
|
+
secretsImport: parseContainerSecretsImport(c.secretsImport),
|
|
60
|
+
ssmSecrets: asStringArray(c.secrets),
|
|
61
|
+
healthCheck: parseContainerHealthCheck(c.healthCheck),
|
|
62
|
+
extraProperties: extras.length > 0 ? extras : undefined,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function parseServiceRouting(routingVal) {
|
|
66
|
+
if (Array.isArray(routingVal)) {
|
|
67
|
+
return routingVal.filter(isParsedObject).map((rule) => ({
|
|
68
|
+
path: asString(rule.path),
|
|
69
|
+
host: asString(rule.host),
|
|
70
|
+
priority: asNumber(rule.priority),
|
|
71
|
+
healthCheckPath: asString(rule.healthCheckPath),
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
if (!isParsedObject(routingVal))
|
|
75
|
+
return undefined;
|
|
76
|
+
return {
|
|
77
|
+
path: asString(routingVal.path),
|
|
78
|
+
host: asString(routingVal.host),
|
|
79
|
+
priority: asNumber(routingVal.priority),
|
|
80
|
+
healthCheckPath: asString(routingVal.healthCheckPath),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const SCALING_TYPES = ["CPU", "MEMORY"];
|
|
84
|
+
const AMI_HARDWARE_TYPES = ["ARM", "STANDARD"];
|
|
85
|
+
function parseServiceScaling(scalingVal) {
|
|
86
|
+
if (scalingVal === false)
|
|
87
|
+
return false;
|
|
88
|
+
if (!isParsedObject(scalingVal))
|
|
89
|
+
return undefined;
|
|
90
|
+
return {
|
|
91
|
+
minCapacity: asNumber(scalingVal.minCapacity),
|
|
92
|
+
maxCapacity: asNumber(scalingVal.maxCapacity),
|
|
93
|
+
desiredCount: asNumber(scalingVal.desiredCount),
|
|
94
|
+
scalingType: asStringUnion(scalingVal.scalingType, SCALING_TYPES),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function parseServiceEc2Config(ec2ConfigVal) {
|
|
98
|
+
if (!isParsedObject(ec2ConfigVal))
|
|
99
|
+
return undefined;
|
|
100
|
+
return {
|
|
101
|
+
instanceType: asString(ec2ConfigVal.instanceType),
|
|
102
|
+
amiHardwareType: asStringUnion(ec2ConfigVal.amiHardwareType, AMI_HARDWARE_TYPES),
|
|
103
|
+
minCapacity: asNumber(ec2ConfigVal.minCapacity),
|
|
104
|
+
maxCapacity: asNumber(ec2ConfigVal.maxCapacity),
|
|
105
|
+
memoryLimitMiB: asNumber(ec2ConfigVal.memoryLimitMiB),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** Resolve connected database names from AST connection references */
|
|
109
|
+
function resolveConnectedDatabaseNames(connections, databaseResources) {
|
|
110
|
+
if (!Array.isArray(connections))
|
|
111
|
+
return [];
|
|
112
|
+
return connections
|
|
113
|
+
.filter(isIdentifierRef)
|
|
114
|
+
.map((conn) => databaseResources.find((db) => db.variableName === conn.__identifier))
|
|
115
|
+
.filter((db) => db !== undefined)
|
|
116
|
+
.map((db) => db.resourceName);
|
|
117
|
+
}
|
|
118
|
+
/** Resolve connected storage names from AST connection references */
|
|
119
|
+
function resolveConnectedStorageNames(connections, s3Resources) {
|
|
120
|
+
if (!Array.isArray(connections))
|
|
121
|
+
return [];
|
|
122
|
+
return connections
|
|
123
|
+
.filter(isIdentifierRef)
|
|
124
|
+
.map((conn) => s3Resources.find((s3) => s3.variableName === conn.__identifier))
|
|
125
|
+
.filter((s3) => s3 !== undefined)
|
|
126
|
+
.map((s3) => s3.resourceName);
|
|
127
|
+
}
|
|
128
|
+
/** Infer database connections from environment variables in ECS containers */
|
|
129
|
+
function inferDatabaseConnectionsFromEnv(computePlan, servicesVal, databasePlans) {
|
|
130
|
+
if (!Array.isArray(servicesVal) || servicesVal.length === 0)
|
|
131
|
+
return;
|
|
132
|
+
const firstService = servicesVal[0];
|
|
133
|
+
if (!isParsedObject(firstService))
|
|
134
|
+
return;
|
|
135
|
+
const containersVal = firstService.containers;
|
|
136
|
+
if (!Array.isArray(containersVal) || containersVal.length === 0)
|
|
137
|
+
return;
|
|
138
|
+
const firstContainer = containersVal[0];
|
|
139
|
+
if (!isParsedObject(firstContainer) ||
|
|
140
|
+
!isParsedObject(firstContainer.environment)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const env = firstContainer.environment;
|
|
144
|
+
if (env.DATABASE_HOST || env.DATABASE_PORT || env.DATABASE_NAME) {
|
|
145
|
+
computePlan.needsConnection = true;
|
|
146
|
+
if (databasePlans.length > 0 &&
|
|
147
|
+
(computePlan.connectedDatabase ?? []).length === 0) {
|
|
148
|
+
computePlan.connectedDatabase = [databasePlans[0].name];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
for (let i = 1; i <= MAX_DATABASE_CONNECTION_INDICES; i++) {
|
|
152
|
+
if (env[`DATABASE_HOST_${i}`] ||
|
|
153
|
+
env[`DATABASE_PORT_${i}`] ||
|
|
154
|
+
env[`DATABASE_NAME_${i}`]) {
|
|
155
|
+
computePlan.needsConnection = true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Infer storage connections from environment variables in ECS containers */
|
|
160
|
+
function inferStorageConnectionsFromEnv(computePlan, servicesVal, s3Plans) {
|
|
161
|
+
if (!Array.isArray(servicesVal) || servicesVal.length === 0)
|
|
162
|
+
return;
|
|
163
|
+
const firstService = servicesVal[0];
|
|
164
|
+
if (!isParsedObject(firstService))
|
|
165
|
+
return;
|
|
166
|
+
const containersVal = firstService.containers;
|
|
167
|
+
if (!Array.isArray(containersVal) || containersVal.length === 0)
|
|
168
|
+
return;
|
|
169
|
+
const firstContainer = containersVal[0];
|
|
170
|
+
if (!isParsedObject(firstContainer) ||
|
|
171
|
+
!isParsedObject(firstContainer.environment)) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const env = firstContainer.environment;
|
|
175
|
+
if (env.BUCKET_NAME) {
|
|
176
|
+
if (s3Plans.length > 0 &&
|
|
177
|
+
(computePlan.connectedStorage ?? []).length === 0) {
|
|
178
|
+
computePlan.connectedStorage = [s3Plans[0].name];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function extractClusterConfig(cluster) {
|
|
183
|
+
if (!isParsedObject(cluster))
|
|
184
|
+
return undefined;
|
|
185
|
+
const loadBalancerVal = cluster.loadBalancer;
|
|
186
|
+
return {
|
|
187
|
+
domain: asString(cluster.domain),
|
|
188
|
+
loadBalancer: loadBalancerVal === false
|
|
189
|
+
? false
|
|
190
|
+
: asStringUnion(loadBalancerVal, LOAD_BALANCER_TYPES),
|
|
191
|
+
directAccess: asBoolean(cluster.directAccess),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function parseEcsService(service) {
|
|
195
|
+
const containersVal = service.containers;
|
|
196
|
+
const containers = Array.isArray(containersVal)
|
|
197
|
+
? containersVal.filter(isParsedObject).map(parseServiceContainer)
|
|
198
|
+
: undefined;
|
|
199
|
+
const ECS_SERVICE_KNOWN_KEYS = new Set([
|
|
200
|
+
"name",
|
|
201
|
+
"image",
|
|
202
|
+
"dockerfilePath",
|
|
203
|
+
"dockerTarget",
|
|
204
|
+
"ssmSecretsPath",
|
|
205
|
+
"containers",
|
|
206
|
+
"routing",
|
|
207
|
+
"connections",
|
|
208
|
+
"cpu",
|
|
209
|
+
"memoryLimitMiB",
|
|
210
|
+
"desiredCount",
|
|
211
|
+
"scaling",
|
|
212
|
+
"capacityProvider",
|
|
213
|
+
"ec2Config",
|
|
214
|
+
]);
|
|
215
|
+
const extras = captureExtraProperties(service, ECS_SERVICE_KNOWN_KEYS);
|
|
216
|
+
return {
|
|
217
|
+
name: asString(service.name) ?? "",
|
|
218
|
+
image: asString(service.image),
|
|
219
|
+
dockerfilePath: asString(service.dockerfilePath),
|
|
220
|
+
dockerTarget: asString(service.dockerTarget),
|
|
221
|
+
ssmSecretsPath: asString(service.ssmSecretsPath),
|
|
222
|
+
containers,
|
|
223
|
+
routing: parseServiceRouting(service.routing),
|
|
224
|
+
cpu: asNumber(service.cpu),
|
|
225
|
+
memoryLimitMiB: asNumber(service.memoryLimitMiB),
|
|
226
|
+
desiredCount: asNumber(service.desiredCount),
|
|
227
|
+
scaling: parseServiceScaling(service.scaling),
|
|
228
|
+
capacityProvider: asStringUnion(service.capacityProvider, ECS_CAPACITY_PROVIDERS) ??
|
|
229
|
+
"FARGATE",
|
|
230
|
+
ec2Config: parseServiceEc2Config(service.ec2Config),
|
|
231
|
+
...(extras.length > 0 && { extraProperties: extras }),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function assignIfDefined(target, key, value) {
|
|
235
|
+
if (value !== undefined)
|
|
236
|
+
target[key] = value;
|
|
237
|
+
}
|
|
238
|
+
function convertEcsCompute(compute, computePlan) {
|
|
239
|
+
assignIfDefined(computePlan, "dockerfilePath", asString(compute.config.dockerfilePath));
|
|
240
|
+
const cluster = compute.config.cluster;
|
|
241
|
+
if (cluster !== undefined) {
|
|
242
|
+
computePlan.cluster = extractClusterConfig(cluster);
|
|
243
|
+
}
|
|
244
|
+
const services = compute.config.services;
|
|
245
|
+
if (services !== undefined && Array.isArray(services)) {
|
|
246
|
+
computePlan.services = services
|
|
247
|
+
.filter((s) => isParsedObject(s))
|
|
248
|
+
.map(parseEcsService);
|
|
249
|
+
}
|
|
250
|
+
const ECS_KNOWN_KEYS = new Set([
|
|
251
|
+
"type",
|
|
252
|
+
"ecrRepository",
|
|
253
|
+
"dockerfilePath",
|
|
254
|
+
"cluster",
|
|
255
|
+
"services",
|
|
256
|
+
"connections",
|
|
257
|
+
]);
|
|
258
|
+
const extras = captureExtraProperties(compute.config, ECS_KNOWN_KEYS);
|
|
259
|
+
if (extras.length > 0)
|
|
260
|
+
computePlan.extraProperties = extras;
|
|
261
|
+
}
|
|
262
|
+
/** Extract a string from a literal or an expression like `Prefix.VALUE` → "VALUE" */
|
|
263
|
+
function extractEnumString(value, prefix) {
|
|
264
|
+
const str = asString(value);
|
|
265
|
+
if (str)
|
|
266
|
+
return str;
|
|
267
|
+
if (isExpressionRef(value) && value.__expression.startsWith(prefix + ".")) {
|
|
268
|
+
return value.__expression.slice(prefix.length + 1);
|
|
269
|
+
}
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
/** Extract a string argument from a call expression like `Code.fromAsset("./path")` */
|
|
273
|
+
function extractCallStringArg(value) {
|
|
274
|
+
if (!isCallRef(value))
|
|
275
|
+
return undefined;
|
|
276
|
+
const match = value.__call.match(/\(\s*"([^"]+)"\s*\)/);
|
|
277
|
+
return match?.[1];
|
|
278
|
+
}
|
|
279
|
+
function convertLambdaCompute(compute, computePlan) {
|
|
280
|
+
assignIfDefined(computePlan, "deployment", asStringUnion(compute.config.deployment, DEPLOYMENT_TYPES));
|
|
281
|
+
assignIfDefined(computePlan, "timeout", asNumber(compute.config.timeout));
|
|
282
|
+
// Code gen emits `memorySize` but plan field is `memory` — handle both keys
|
|
283
|
+
assignIfDefined(computePlan, "memory", asNumber(compute.config.memorySize) ?? asNumber(compute.config.memory));
|
|
284
|
+
assignIfDefined(computePlan, "handler", asString(compute.config.handler));
|
|
285
|
+
// Code gen emits `runtime: Runtime.NODEJS_20_X` — extract enum value from expression
|
|
286
|
+
assignIfDefined(computePlan, "runtime", extractEnumString(compute.config.runtime, "Runtime"));
|
|
287
|
+
if (isEnvironmentRecord(compute.config.environment)) {
|
|
288
|
+
computePlan.environment = compute.config.environment;
|
|
289
|
+
}
|
|
290
|
+
// secrets can be EnvironmentRecord (Secrets Manager) or string[] (SSM secrets)
|
|
291
|
+
if (isEnvironmentRecord(compute.config.secrets)) {
|
|
292
|
+
computePlan.secrets = compute.config.secrets;
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
const ssmSecrets = asStringArray(compute.config.secrets);
|
|
296
|
+
if (ssmSecrets)
|
|
297
|
+
computePlan.ssmSecrets = ssmSecrets;
|
|
298
|
+
}
|
|
299
|
+
// Extract functionUrl: { authType: FunctionUrlAuthType.NONE }
|
|
300
|
+
const functionUrlVal = compute.config.functionUrl;
|
|
301
|
+
if (isParsedObject(functionUrlVal)) {
|
|
302
|
+
const authType = extractEnumString(functionUrlVal.authType, "FunctionUrlAuthType");
|
|
303
|
+
if (authType === "NONE" || authType === "AWS_IAM") {
|
|
304
|
+
computePlan.functionUrl = { authType };
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// Extract codePath from `code: Code.fromAsset("./path")`
|
|
308
|
+
const codeVal = compute.config.code;
|
|
309
|
+
if (codeVal !== undefined) {
|
|
310
|
+
const codePath = extractCallStringArg(codeVal);
|
|
311
|
+
if (codePath) {
|
|
312
|
+
computePlan.codePath = codePath;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// CDK prop is `lambdaDescription` — plan stores as `description`
|
|
316
|
+
assignIfDefined(computePlan, "description", asString(compute.config.lambdaDescription));
|
|
317
|
+
assignIfDefined(computePlan, "scheduleExpression", asString(compute.config.scheduleExpression));
|
|
318
|
+
assignIfDefined(computePlan, "architecture", extractEnumString(compute.config.architecture, "Architecture"));
|
|
319
|
+
assignIfDefined(computePlan, "ephemeralStorageSize", asNumber(compute.config.ephemeralStorageSize));
|
|
320
|
+
assignIfDefined(computePlan, "functionName", asString(compute.config.functionName));
|
|
321
|
+
assignIfDefined(computePlan, "ssmSecretsPath", asString(compute.config.ssmSecretsPath));
|
|
322
|
+
const LAMBDA_KNOWN_KEYS = new Set([
|
|
323
|
+
"type",
|
|
324
|
+
"deployment",
|
|
325
|
+
"timeout",
|
|
326
|
+
"memorySize",
|
|
327
|
+
"memory",
|
|
328
|
+
"handler",
|
|
329
|
+
"runtime",
|
|
330
|
+
"environment",
|
|
331
|
+
"secrets",
|
|
332
|
+
"functionUrl",
|
|
333
|
+
"code",
|
|
334
|
+
"connections",
|
|
335
|
+
"ecrRepository",
|
|
336
|
+
"containerSecretsImport",
|
|
337
|
+
"lambdaDescription",
|
|
338
|
+
"scheduleExpression",
|
|
339
|
+
"architecture",
|
|
340
|
+
"ephemeralStorageSize",
|
|
341
|
+
"functionName",
|
|
342
|
+
"ssmSecretsPath",
|
|
343
|
+
]);
|
|
344
|
+
const extras = captureExtraProperties(compute.config, LAMBDA_KNOWN_KEYS);
|
|
345
|
+
if (extras.length > 0)
|
|
346
|
+
computePlan.extraProperties = extras;
|
|
347
|
+
}
|
|
348
|
+
function convertEc2Compute(compute, computePlan) {
|
|
349
|
+
assignIfDefined(computePlan, "instanceType", asStringUnion(compute.config.instanceType, EC2_INSTANCE_TYPES));
|
|
350
|
+
// Code gen emits `ssh: {}` or `ssh: false` — map to enableSSH boolean.
|
|
351
|
+
// Also accept `enableSSH: true/false` for manually-written code.
|
|
352
|
+
const sshVal = compute.config.ssh;
|
|
353
|
+
if (sshVal === false) {
|
|
354
|
+
computePlan.enableSSH = false;
|
|
355
|
+
}
|
|
356
|
+
else if (sshVal !== undefined && isParsedObject(sshVal)) {
|
|
357
|
+
computePlan.enableSSH = true;
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
assignIfDefined(computePlan, "enableSSH", asBoolean(compute.config.enableSSH));
|
|
361
|
+
}
|
|
362
|
+
assignIfDefined(computePlan, "keyName", asString(compute.config.keyName));
|
|
363
|
+
assignIfDefined(computePlan, "userData", asString(compute.config.userData));
|
|
364
|
+
if (compute.config.securityGroups !== undefined) {
|
|
365
|
+
computePlan.securityGroups = asStringArray(compute.config.securityGroups);
|
|
366
|
+
}
|
|
367
|
+
const EC2_KNOWN_KEYS = new Set([
|
|
368
|
+
"type",
|
|
369
|
+
"instanceType",
|
|
370
|
+
"ssh",
|
|
371
|
+
"enableSSH",
|
|
372
|
+
"keyName",
|
|
373
|
+
"userData",
|
|
374
|
+
"securityGroups",
|
|
375
|
+
"connections",
|
|
376
|
+
]);
|
|
377
|
+
const extras = captureExtraProperties(compute.config, EC2_KNOWN_KEYS);
|
|
378
|
+
if (extras.length > 0)
|
|
379
|
+
computePlan.extraProperties = extras;
|
|
380
|
+
}
|
|
381
|
+
function applyConnectionConfig(computePlan, compute, databaseResources, s3Resources) {
|
|
382
|
+
// Check top-level connections first, then service-level (ECS generated format)
|
|
383
|
+
let connections = compute.config.connections;
|
|
384
|
+
if (!connections && Array.isArray(compute.config.services)) {
|
|
385
|
+
const firstService = compute.config.services[0];
|
|
386
|
+
if (isParsedObject(firstService)) {
|
|
387
|
+
connections = firstService.connections;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (!connections)
|
|
391
|
+
return;
|
|
392
|
+
const connectedDbNames = resolveConnectedDatabaseNames(connections, databaseResources);
|
|
393
|
+
if (connectedDbNames.length > 0) {
|
|
394
|
+
computePlan.needsConnection = true;
|
|
395
|
+
computePlan.connectedDatabase = connectedDbNames;
|
|
396
|
+
}
|
|
397
|
+
const connectedStorageNames = resolveConnectedStorageNames(connections, s3Resources);
|
|
398
|
+
if (connectedStorageNames.length > 0) {
|
|
399
|
+
computePlan.connectedStorage = connectedStorageNames;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function applyTypeSpecificConfig(computePlan, compute) {
|
|
403
|
+
const TYPE_CONVERTERS = {
|
|
404
|
+
ecs: convertEcsCompute,
|
|
405
|
+
lambda: convertLambdaCompute,
|
|
406
|
+
ec2: convertEc2Compute,
|
|
407
|
+
};
|
|
408
|
+
TYPE_CONVERTERS[computePlan.type]?.(compute, computePlan);
|
|
409
|
+
}
|
|
410
|
+
/** Convert parsed compute resources to plan format */
|
|
411
|
+
export function convertComputeResources(parsed, plan) {
|
|
412
|
+
return parsed.computeResources.map((compute) => {
|
|
413
|
+
const computeType = asStringUnion(compute.config.type, COMPUTE_TYPES) ?? "ecs";
|
|
414
|
+
const computePlan = {
|
|
415
|
+
name: compute.resourceName,
|
|
416
|
+
type: computeType,
|
|
417
|
+
needsConnection: false,
|
|
418
|
+
connectedDatabase: [],
|
|
419
|
+
...(compute.variableName && { variableName: compute.variableName }),
|
|
420
|
+
};
|
|
421
|
+
applyConnectionConfig(computePlan, compute, parsed.databaseResources, parsed.s3Resources);
|
|
422
|
+
applyTypeSpecificConfig(computePlan, compute);
|
|
423
|
+
inferDatabaseConnectionsFromEnv(computePlan, compute.config.services, plan.database);
|
|
424
|
+
inferStorageConnectionsFromEnv(computePlan, compute.config.services, plan.s3);
|
|
425
|
+
return computePlan;
|
|
426
|
+
});
|
|
427
|
+
}
|