@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.
Files changed (57) hide show
  1. package/dist/src/ast/astComputeParser.d.ts +4 -0
  2. package/dist/src/ast/astComputeParser.js +427 -0
  3. package/dist/src/ast/astInfrastructureParser.d.ts +357 -0
  4. package/dist/src/ast/astInfrastructureParser.js +1925 -0
  5. package/dist/src/ast/astSurgicalModification.d.ts +47 -0
  6. package/dist/src/ast/astSurgicalModification.js +400 -0
  7. package/dist/src/ast/index.d.ts +2 -0
  8. package/dist/src/ast/index.js +2 -0
  9. package/dist/src/aws/regions.d.ts +30 -0
  10. package/dist/src/aws/regions.js +254 -0
  11. package/dist/src/generation/common.d.ts +86 -0
  12. package/dist/src/generation/common.js +187 -0
  13. package/dist/src/generation/compute.d.ts +6 -0
  14. package/dist/src/generation/compute.js +547 -0
  15. package/dist/src/generation/database.d.ts +54 -0
  16. package/dist/src/generation/database.js +201 -0
  17. package/dist/src/generation/index.d.ts +12 -0
  18. package/dist/src/generation/index.js +18 -0
  19. package/dist/src/generation/infrastructure.d.ts +44 -0
  20. package/dist/src/generation/infrastructure.js +389 -0
  21. package/dist/src/generation/storage.d.ts +23 -0
  22. package/dist/src/generation/storage.js +174 -0
  23. package/dist/src/generation/storageConnections.d.ts +37 -0
  24. package/dist/src/generation/storageConnections.js +71 -0
  25. package/dist/src/index.d.ts +10 -0
  26. package/dist/src/index.js +19 -0
  27. package/dist/src/planning/index.d.ts +1 -0
  28. package/dist/src/planning/index.js +1 -0
  29. package/dist/src/planning/resourcePlanning.d.ts +58 -0
  30. package/dist/src/planning/resourcePlanning.js +216 -0
  31. package/dist/src/presets/index.d.ts +3 -0
  32. package/dist/src/presets/index.js +3 -0
  33. package/dist/src/presets/patternTierPresets.d.ts +93 -0
  34. package/dist/src/presets/patternTierPresets.js +131 -0
  35. package/dist/src/presets/storagePresets.d.ts +11 -0
  36. package/dist/src/presets/storagePresets.js +36 -0
  37. package/dist/src/presets/tierPresets.d.ts +59 -0
  38. package/dist/src/presets/tierPresets.js +384 -0
  39. package/dist/src/presets/tierTypes.d.ts +301 -0
  40. package/dist/src/presets/tierTypes.js +7 -0
  41. package/dist/src/schemas/constants.d.ts +74 -0
  42. package/dist/src/schemas/constants.js +208 -0
  43. package/dist/src/schemas/index.d.ts +3 -0
  44. package/dist/src/schemas/index.js +3 -0
  45. package/dist/src/schemas/instanceTypeArchitecture.d.ts +35 -0
  46. package/dist/src/schemas/instanceTypeArchitecture.js +75 -0
  47. package/dist/src/schemas/resourceSchemas.d.ts +3534 -0
  48. package/dist/src/schemas/resourceSchemas.js +2015 -0
  49. package/dist/src/types/Result.d.ts +19 -0
  50. package/dist/src/types/Result.js +31 -0
  51. package/dist/src/util/errorUtils.d.ts +2 -0
  52. package/dist/src/util/errorUtils.js +15 -0
  53. package/dist/src/validation/patterns.d.ts +300 -0
  54. package/dist/src/validation/patterns.js +360 -0
  55. package/dist/src/version.d.ts +1 -0
  56. package/dist/src/version.js +1 -0
  57. package/package.json +32 -0
@@ -0,0 +1,547 @@
1
+ import { formatValue, getVariableName, emitExtraProperties } from "./common.js";
2
+ import { DATABASE_ENV_VARS, getConnectedDatabases, generateDatabaseEnvVarEntries, buildDatabaseEnvVars, } from "./database.js";
3
+ import { STORAGE_ENV_VARS, getConnectedStorage, generateStorageEnvVarEntries, buildStorageEnvVars, formatAllConnectionsCode, } from "./storageConnections.js";
4
+ import { COMPUTE_TYPE, DEPLOYMENT_TYPE, DEFAULT_COMPUTE_ARCHITECTURE, } from "../schemas/constants.js";
5
+ /** Check if a compute resource has database connections */
6
+ function computeHasDatabaseConnections(compute) {
7
+ return Boolean(compute.needsConnection && compute.connectedDatabase?.length);
8
+ }
9
+ /** Check if a compute resource has storage connections */
10
+ function computeHasStorageConnections(compute) {
11
+ return Boolean(compute.connectedStorage?.length);
12
+ }
13
+ /** Check if a compute resource has any connections (database or storage) */
14
+ function computeHasConnections(compute) {
15
+ return (computeHasDatabaseConnections(compute) ||
16
+ computeHasStorageConnections(compute));
17
+ }
18
+ const BASE_ENVIRONMENT_VARS = {
19
+ ENVIRONMENT: { __expression: "getConfig().environment" },
20
+ };
21
+ function formatEnvBlock(vars, indent) {
22
+ return Object.entries(vars)
23
+ .map(([key, value]) => `${indent}${key}: ${formatValue(value)},`)
24
+ .join("\n");
25
+ }
26
+ export function generateLambdaCode(compute, _plan) {
27
+ let code = "";
28
+ if (compute.deployment === DEPLOYMENT_TYPE.CODE && compute.codePath) {
29
+ code += `
30
+ deployment: "${DEPLOYMENT_TYPE.CODE}",
31
+ code: Code.fromAsset("${compute.codePath}"),`;
32
+ if (compute.handler) {
33
+ code += `
34
+ handler: "${compute.handler}",`;
35
+ }
36
+ if (compute.runtime) {
37
+ code += `
38
+ runtime: Runtime.${compute.runtime},`;
39
+ }
40
+ }
41
+ else {
42
+ code += `
43
+ deployment: "${DEPLOYMENT_TYPE.CONTAINER}",
44
+ ecrRepository: app.getDefaultContainerRegistry(),`;
45
+ }
46
+ if (compute.timeout !== undefined) {
47
+ code += `
48
+ timeout: ${compute.timeout},`;
49
+ }
50
+ if (compute.memory !== undefined) {
51
+ code += `
52
+ memorySize: ${compute.memory},`;
53
+ }
54
+ if (compute.functionUrl) {
55
+ code += `
56
+ functionUrl: { authType: FunctionUrlAuthType.${compute.functionUrl.authType} },`;
57
+ }
58
+ if (compute.description) {
59
+ code += `
60
+ lambdaDescription: "${compute.description}",`;
61
+ }
62
+ if (compute.scheduleExpression) {
63
+ code += `
64
+ scheduleExpression: "${compute.scheduleExpression}",`;
65
+ }
66
+ if (compute.architecture ||
67
+ compute.deployment === DEPLOYMENT_TYPE.CONTAINER) {
68
+ const arch = compute.architecture ?? DEFAULT_COMPUTE_ARCHITECTURE;
69
+ code += `
70
+ architecture: Architecture.${arch},`;
71
+ }
72
+ if (compute.ephemeralStorageSize !== undefined) {
73
+ code += `
74
+ ephemeralStorageSize: ${compute.ephemeralStorageSize},`;
75
+ }
76
+ if (compute.functionName) {
77
+ code += `
78
+ functionName: "${compute.functionName}",`;
79
+ }
80
+ if (compute.ssmSecretsPath) {
81
+ code += `
82
+ ssmSecretsPath: "${compute.ssmSecretsPath}",`;
83
+ }
84
+ if (compute.ssmSecrets && compute.ssmSecrets.length > 0) {
85
+ const secretsList = compute.ssmSecrets.map((s) => `"${s}"`).join(", ");
86
+ code += `
87
+ secrets: [${secretsList}],`;
88
+ }
89
+ // When there are connections, generateLambdaConnectionsCode handles env vars.
90
+ // Otherwise, emit environment block here with base + user env vars.
91
+ if (!computeHasConnections(compute)) {
92
+ const allEnv = {
93
+ ...BASE_ENVIRONMENT_VARS,
94
+ ...compute.environment,
95
+ };
96
+ code += `
97
+ environment: {
98
+ ${formatEnvBlock(allEnv, " ")}
99
+ },`;
100
+ }
101
+ code += emitExtraProperties(compute.extraProperties);
102
+ return code;
103
+ }
104
+ export function generateLambdaConnectionsCode(compute, plan) {
105
+ if (compute.type !== COMPUTE_TYPE.LAMBDA)
106
+ return "";
107
+ const hasDatabaseConnections = computeHasDatabaseConnections(compute);
108
+ const hasStorageConns = computeHasStorageConnections(compute);
109
+ if (!hasDatabaseConnections && !hasStorageConns)
110
+ return "";
111
+ const connectedDatabases = hasDatabaseConnections
112
+ ? getConnectedDatabases(plan, compute)
113
+ : [];
114
+ const connectedStorage = hasStorageConns
115
+ ? getConnectedStorage(plan, compute)
116
+ : [];
117
+ if (connectedDatabases.length === 0 && connectedStorage.length === 0) {
118
+ return "";
119
+ }
120
+ // All env/secret values are stored as typed objects so formatValue handles
121
+ // them uniformly: __expression objects emit raw code, strings get JSON-quoted.
122
+ const envVars = {
123
+ ...BASE_ENVIRONMENT_VARS,
124
+ };
125
+ const secretVars = {};
126
+ // Database env vars
127
+ if (connectedDatabases.length > 0) {
128
+ const entries = generateDatabaseEnvVarEntries(connectedDatabases);
129
+ for (const entry of entries) {
130
+ // "true" is a literal string value (DATABASE_SSL); expressions are code refs
131
+ const value = entry.expression === `"true"`
132
+ ? "true"
133
+ : { __expression: entry.expression };
134
+ if (entry.isSecret) {
135
+ secretVars[entry.key] = { __expression: entry.expression };
136
+ }
137
+ else {
138
+ envVars[entry.key] = value;
139
+ }
140
+ }
141
+ }
142
+ // Storage env vars (no secrets — S3 uses IAM)
143
+ if (connectedStorage.length > 0) {
144
+ const entries = generateStorageEnvVarEntries(connectedStorage);
145
+ for (const entry of entries) {
146
+ envVars[entry.key] = { __expression: entry.expression };
147
+ }
148
+ }
149
+ // Merge compute.environment values directly — formatValue handles all types
150
+ if (compute.environment) {
151
+ for (const [key, value] of Object.entries(compute.environment)) {
152
+ envVars[key] = value;
153
+ }
154
+ }
155
+ let code = "";
156
+ // containerSecretsImport for database credentials (resolved at deploy time)
157
+ if (Object.keys(secretVars).length > 0) {
158
+ code += `
159
+ containerSecretsImport: {`;
160
+ for (const [key, value] of Object.entries(secretVars)) {
161
+ code += `
162
+ ${key}: ${formatValue(value)},`;
163
+ }
164
+ code += `
165
+ },`;
166
+ }
167
+ if (Object.keys(envVars).length > 0) {
168
+ code += `
169
+ environment: {`;
170
+ for (const [key, value] of Object.entries(envVars)) {
171
+ code += `
172
+ ${key}: ${formatValue(value)},`;
173
+ }
174
+ code += `
175
+ },`;
176
+ }
177
+ code += `
178
+ ${formatAllConnectionsCode(connectedDatabases, connectedStorage)}`;
179
+ return code;
180
+ }
181
+ export function generateEc2Code(compute) {
182
+ let code = "";
183
+ if (compute.instanceType) {
184
+ code += `
185
+ instanceType: "${compute.instanceType}",`;
186
+ }
187
+ if (compute.enableSSH !== undefined) {
188
+ code += compute.enableSSH
189
+ ? `
190
+ ssh: {},`
191
+ : `
192
+ ssh: false,`;
193
+ }
194
+ code += emitExtraProperties(compute.extraProperties);
195
+ return code;
196
+ }
197
+ function generateEcsClusterCode(compute) {
198
+ if (!compute.cluster)
199
+ return "";
200
+ const parts = [];
201
+ if (compute.cluster.directAccess) {
202
+ parts.push(`directAccess: true`);
203
+ }
204
+ if (compute.cluster.domain) {
205
+ parts.push(`domain: "${compute.cluster.domain}"`);
206
+ }
207
+ if (compute.cluster.loadBalancer !== undefined) {
208
+ parts.push(compute.cluster.loadBalancer === false
209
+ ? `loadBalancer: false`
210
+ : `loadBalancer: "${compute.cluster.loadBalancer}"`);
211
+ }
212
+ if (parts.length <= 1) {
213
+ return `
214
+ cluster: { ${parts[0] || ""} },`;
215
+ }
216
+ const inner = parts.map((p) => `\n ${p},`).join("");
217
+ return `
218
+ cluster: {${inner}
219
+ },`;
220
+ }
221
+ function generateEcsContainerCode(containerConfig, shouldAddConnectionEnv, dbEnvVars, storageEnvVars, baseEnvVars) {
222
+ let code = "";
223
+ if (containerConfig.name) {
224
+ code += `
225
+ name: "${containerConfig.name}",`;
226
+ }
227
+ if (containerConfig.image) {
228
+ code += `
229
+ image: "${containerConfig.image}",`;
230
+ }
231
+ if (containerConfig.port !== undefined) {
232
+ code += `
233
+ port: ${containerConfig.port},`;
234
+ }
235
+ if (containerConfig.essential !== undefined) {
236
+ code += `
237
+ essential: ${containerConfig.essential},`;
238
+ }
239
+ if (containerConfig.command?.length) {
240
+ code += `
241
+ command: ${JSON.stringify(containerConfig.command)},`;
242
+ }
243
+ if (containerConfig.entryPoint?.length) {
244
+ code += `
245
+ entryPoint: ${JSON.stringify(containerConfig.entryPoint)},`;
246
+ }
247
+ const connectionEnvKeys = [
248
+ DATABASE_ENV_VARS.HOST,
249
+ DATABASE_ENV_VARS.PORT,
250
+ DATABASE_ENV_VARS.NAME,
251
+ DATABASE_ENV_VARS.SSL,
252
+ DATABASE_ENV_VARS.USERNAME,
253
+ DATABASE_ENV_VARS.PASSWORD,
254
+ STORAGE_ENV_VARS.NAME,
255
+ ];
256
+ const stripConnectionEnv = (env) => {
257
+ if (!env)
258
+ return env;
259
+ const filtered = {};
260
+ for (const [key, value] of Object.entries(env)) {
261
+ const isConnectionKey = connectionEnvKeys.some((connKey) => key === connKey || key.startsWith(`${connKey}_`));
262
+ if (!isConnectionKey) {
263
+ filtered[key] = value;
264
+ }
265
+ }
266
+ return Object.keys(filtered).length > 0 ? filtered : undefined;
267
+ };
268
+ // Base env vars (e.g. ENVIRONMENT) are always injected into every container.
269
+ // Connection env vars are only added to the first container of the service that needs them.
270
+ const containerEnv = shouldAddConnectionEnv
271
+ ? {
272
+ ...baseEnvVars,
273
+ ...dbEnvVars.env,
274
+ ...storageEnvVars.env,
275
+ ...containerConfig.environment,
276
+ }
277
+ : { ...baseEnvVars, ...stripConnectionEnv(containerConfig.environment) };
278
+ const containerSecrets = shouldAddConnectionEnv
279
+ ? { ...dbEnvVars.secrets, ...containerConfig.secretsImport }
280
+ : stripConnectionEnv(containerConfig.secretsImport);
281
+ if (containerEnv && Object.keys(containerEnv).length > 0) {
282
+ code += `
283
+ environment: {
284
+ ${formatEnvBlock(containerEnv, " ")}
285
+ },`;
286
+ }
287
+ if (containerSecrets && Object.keys(containerSecrets).length > 0) {
288
+ code += `
289
+ secretsImport: {
290
+ ${formatEnvBlock(containerSecrets, " ")}
291
+ },`;
292
+ }
293
+ if (containerConfig.ssmSecrets && containerConfig.ssmSecrets.length > 0) {
294
+ const secretsList = containerConfig.ssmSecrets
295
+ .map((s) => `"${s}"`)
296
+ .join(", ");
297
+ code += `
298
+ secrets: [${secretsList}],`;
299
+ }
300
+ if (containerConfig.healthCheck) {
301
+ code += `
302
+ healthCheck: ${formatValue(containerConfig.healthCheck, " ")},`;
303
+ }
304
+ code += emitExtraProperties(containerConfig.extraProperties, " ");
305
+ return code;
306
+ }
307
+ function formatRoutingRule(rule, indent) {
308
+ const parts = [];
309
+ if (rule.path)
310
+ parts.push(`path: "${rule.path}"`);
311
+ if (rule.host)
312
+ parts.push(`host: "${rule.host}"`);
313
+ if (rule.priority !== undefined)
314
+ parts.push(`priority: ${rule.priority}`);
315
+ if (rule.healthCheckPath)
316
+ parts.push(`healthCheckPath: "${rule.healthCheckPath}"`);
317
+ if (parts.length <= 1) {
318
+ return `{ ${parts[0] || ""} }`;
319
+ }
320
+ const inner = parts.map((p) => `\n${indent} ${p},`).join("");
321
+ return `{${inner}\n${indent}}`;
322
+ }
323
+ function generateEcsServiceRoutingCode(routing) {
324
+ const rules = Array.isArray(routing) ? routing : [routing];
325
+ if (rules.length === 1) {
326
+ const formatted = formatRoutingRule(rules[0], " ");
327
+ return `
328
+ routing: ${formatted},`;
329
+ }
330
+ const entries = rules.map((r) => formatRoutingRule(r, " "));
331
+ return `
332
+ routing: [
333
+ ${entries.join(",\n ")},
334
+ ],`;
335
+ }
336
+ function generateEcsServiceScalingCode(scaling) {
337
+ if (scaling === false) {
338
+ return `
339
+ scaling: false,`;
340
+ }
341
+ if (typeof scaling !== "object")
342
+ return "";
343
+ const hasScalingConfig = scaling.minCapacity !== undefined ||
344
+ scaling.maxCapacity !== undefined ||
345
+ scaling.desiredCount !== undefined ||
346
+ scaling.scalingType !== undefined;
347
+ if (!hasScalingConfig)
348
+ return "";
349
+ const scalingParts = [];
350
+ if (scaling.minCapacity !== undefined)
351
+ scalingParts.push(`minCapacity: ${scaling.minCapacity}`);
352
+ if (scaling.maxCapacity !== undefined)
353
+ scalingParts.push(`maxCapacity: ${scaling.maxCapacity}`);
354
+ if (scaling.desiredCount !== undefined)
355
+ scalingParts.push(`desiredCount: ${scaling.desiredCount}`);
356
+ if (scaling.scalingType)
357
+ scalingParts.push(`scalingType: "${scaling.scalingType}"`);
358
+ if (scalingParts.length <= 1) {
359
+ return `
360
+ scaling: { ${scalingParts[0] || ""} },`;
361
+ }
362
+ const inner = scalingParts.map((p) => `\n ${p},`).join("");
363
+ return `
364
+ scaling: {${inner}
365
+ },`;
366
+ }
367
+ function generateEcsServiceCode(options) {
368
+ const { service, isFirstService, hasConnections, dbEnvVars, storageEnvVars, baseEnvVars, plan, compute, } = options;
369
+ let code = `
370
+ name: "${service.name}",`;
371
+ code += `
372
+ capacityProvider: "${service.capacityProvider}",`;
373
+ if (service.ec2Config) {
374
+ code += `
375
+ ec2Config: ${formatValue(service.ec2Config, " ")},`;
376
+ }
377
+ if (service.dockerfilePath) {
378
+ code += `
379
+ dockerfilePath: "${service.dockerfilePath}",`;
380
+ }
381
+ if (service.dockerTarget) {
382
+ code += `
383
+ dockerTarget: "${service.dockerTarget}",`;
384
+ }
385
+ if (service.image) {
386
+ code += `
387
+ image: "${service.image}",`;
388
+ }
389
+ if (service.ssmSecretsPath) {
390
+ code += `
391
+ ssmSecretsPath: "${service.ssmSecretsPath}",`;
392
+ }
393
+ if (service.containers?.length) {
394
+ code += `
395
+ containers: [{`;
396
+ for (let i = 0; i < service.containers.length; i++) {
397
+ const container = service.containers[i];
398
+ if (!container)
399
+ continue;
400
+ const serviceNeedsDb = service.needsDatabaseConnection !== undefined
401
+ ? service.needsDatabaseConnection
402
+ : isFirstService && computeHasDatabaseConnections(compute);
403
+ const serviceNeedsStorage = service.needsStorageConnection !== undefined
404
+ ? service.needsStorageConnection
405
+ : isFirstService && computeHasStorageConnections(compute);
406
+ const shouldAddConnectionEnv = i === 0 && (serviceNeedsDb || serviceNeedsStorage) && hasConnections;
407
+ // Build per-container env vars: only include the connection types this service needs
408
+ const containerDbEnvVars = serviceNeedsDb
409
+ ? dbEnvVars
410
+ : { env: {}, secrets: {} };
411
+ const containerStorageEnvVars = serviceNeedsStorage
412
+ ? storageEnvVars
413
+ : { env: {}, secrets: {} };
414
+ if (i > 0) {
415
+ code += `
416
+ }, {`;
417
+ }
418
+ code += generateEcsContainerCode(container, shouldAddConnectionEnv, containerDbEnvVars, containerStorageEnvVars, baseEnvVars);
419
+ }
420
+ code += `
421
+ }],`;
422
+ }
423
+ if (service.routing) {
424
+ code += generateEcsServiceRoutingCode(service.routing);
425
+ }
426
+ if (service.cpu !== undefined) {
427
+ code += `
428
+ cpu: ${service.cpu},`;
429
+ }
430
+ if (service.memoryLimitMiB !== undefined) {
431
+ code += `
432
+ memoryLimitMiB: ${service.memoryLimitMiB},`;
433
+ }
434
+ if (service.desiredCount !== undefined) {
435
+ code += `
436
+ desiredCount: ${service.desiredCount},`;
437
+ }
438
+ if (service.scaling !== undefined) {
439
+ code += generateEcsServiceScalingCode(service.scaling);
440
+ }
441
+ code += emitExtraProperties(service.extraProperties, " ");
442
+ const serviceNeedsDbConnection = service.needsDatabaseConnection !== undefined
443
+ ? service.needsDatabaseConnection
444
+ : isFirstService && computeHasDatabaseConnections(compute);
445
+ const serviceNeedsStorageConnection = service.needsStorageConnection !== undefined
446
+ ? service.needsStorageConnection
447
+ : isFirstService && computeHasStorageConnections(compute);
448
+ if (serviceNeedsDbConnection || serviceNeedsStorageConnection) {
449
+ const connectedDatabases = serviceNeedsDbConnection
450
+ ? getConnectedDatabases(plan, compute)
451
+ : [];
452
+ const connectedStorage = serviceNeedsStorageConnection
453
+ ? getConnectedStorage(plan, compute)
454
+ : [];
455
+ if (connectedDatabases.length > 0 || connectedStorage.length > 0) {
456
+ code += `
457
+ ${formatAllConnectionsCode(connectedDatabases, connectedStorage)}`;
458
+ }
459
+ }
460
+ return code;
461
+ }
462
+ export function generateEcsCode(compute, plan) {
463
+ const hasConnections = computeHasConnections(compute);
464
+ const baseEnvVars = {
465
+ ...BASE_ENVIRONMENT_VARS,
466
+ };
467
+ // Database env vars only injected into containers with database connections
468
+ const dbEnvVars = {
469
+ env: {},
470
+ secrets: {},
471
+ };
472
+ if (computeHasDatabaseConnections(compute)) {
473
+ const builtEnvVars = buildDatabaseEnvVars(plan, compute);
474
+ Object.assign(dbEnvVars.env, builtEnvVars.env);
475
+ Object.assign(dbEnvVars.secrets, builtEnvVars.secrets);
476
+ }
477
+ // Storage env vars (no secrets — S3 uses IAM)
478
+ const storageEnvVars = {
479
+ env: {},
480
+ secrets: {},
481
+ };
482
+ if (computeHasStorageConnections(compute)) {
483
+ const builtStorageEnvVars = buildStorageEnvVars(plan, compute);
484
+ Object.assign(storageEnvVars.env, builtStorageEnvVars.env);
485
+ }
486
+ let code = `
487
+ ecrRepository: app.getDefaultContainerRegistry(),`;
488
+ code += generateEcsClusterCode(compute);
489
+ if (compute.services?.length) {
490
+ code += `
491
+ services: [{`;
492
+ for (let serviceIndex = 0; serviceIndex < compute.services.length; serviceIndex++) {
493
+ const service = compute.services[serviceIndex];
494
+ if (!service)
495
+ continue;
496
+ if (serviceIndex > 0) {
497
+ code += `
498
+ }, {`;
499
+ }
500
+ code += generateEcsServiceCode({
501
+ service,
502
+ isFirstService: serviceIndex === 0,
503
+ hasConnections: !!hasConnections,
504
+ dbEnvVars,
505
+ storageEnvVars,
506
+ baseEnvVars,
507
+ plan,
508
+ compute,
509
+ });
510
+ }
511
+ code += `
512
+ }],`;
513
+ }
514
+ code += emitExtraProperties(compute.extraProperties);
515
+ return code;
516
+ }
517
+ export function generateComputeCode(plan, cdnReferencedResources) {
518
+ if (plan.compute.length === 0)
519
+ return "";
520
+ let code = "";
521
+ for (let computeIndex = 0; computeIndex < plan.compute.length; computeIndex++) {
522
+ const compute = plan.compute[computeIndex];
523
+ const needsVariable = cdnReferencedResources.has(compute.name);
524
+ const computeVariable = getVariableName(compute);
525
+ const needsLeadingNewline = plan.database.length > 0 || plan.s3.length > 0 || computeIndex > 0;
526
+ const prefix = needsVariable ? `const ${computeVariable} = ` : "";
527
+ const leadingNewline = needsLeadingNewline ? "\n" : "";
528
+ code += `${leadingNewline}${prefix}app.addCompute(
529
+ ComputeFactory.build("${compute.name}", {
530
+ type: "${compute.type}",`;
531
+ if (compute.type === COMPUTE_TYPE.LAMBDA) {
532
+ code += generateLambdaCode(compute, plan);
533
+ }
534
+ else if (compute.type === COMPUTE_TYPE.EC2) {
535
+ code += generateEc2Code(compute);
536
+ }
537
+ else if (compute.type === COMPUTE_TYPE.ECS) {
538
+ code += generateEcsCode(compute, plan);
539
+ }
540
+ code += generateLambdaConnectionsCode(compute, plan);
541
+ code += `
542
+ })
543
+ );
544
+ `;
545
+ }
546
+ return code;
547
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Database Code Generation
3
+ *
4
+ * Functions for generating database infrastructure code including
5
+ * RDS Instance, Aurora, and GlobalAurora configurations.
6
+ */
7
+ import type { DatabaseResourcePlan, ApplicationResourcePlan, ComputeResourcePlan } from "../schemas/resourceSchemas.js";
8
+ export declare const DATABASE_ENV_VARS: Readonly<{
9
+ readonly HOST: "DATABASE_HOST";
10
+ readonly PORT: "DATABASE_PORT";
11
+ readonly NAME: "DATABASE_NAME";
12
+ readonly SSL: "DATABASE_SSL";
13
+ readonly USERNAME: "DATABASE_USERNAME";
14
+ readonly PASSWORD: "DATABASE_PASSWORD";
15
+ }>;
16
+ export declare const CREDENTIAL_KEYS: Readonly<{
17
+ readonly USERNAME: "username";
18
+ readonly PASSWORD: "password";
19
+ }>;
20
+ export type DatabaseEnvVarEntry = {
21
+ key: string;
22
+ expression: string;
23
+ isSecret: boolean;
24
+ };
25
+ export interface DatabaseEnvVars {
26
+ env: Record<string, unknown>;
27
+ secrets: Record<string, unknown>;
28
+ }
29
+ /**
30
+ * Get databases connected to a compute resource
31
+ */
32
+ export declare function getConnectedDatabases(plan: ApplicationResourcePlan, compute: ComputeResourcePlan): DatabaseResourcePlan[];
33
+ /**
34
+ * Generate database environment variable entries for a list of connected databases.
35
+ * Both ECS and Lambda use containerSecretsImport with getImport() for credentials.
36
+ * Credential entries are always marked as secrets (isSecret: true).
37
+ */
38
+ export declare function generateDatabaseEnvVarEntries(connectedDatabases: DatabaseResourcePlan[]): DatabaseEnvVarEntry[];
39
+ /**
40
+ * Format database connections array for generated infrastructure code
41
+ */
42
+ export declare function formatConnectionsCode(connectedDatabases: DatabaseResourcePlan[]): string;
43
+ /**
44
+ * Build database environment variables for a compute resource
45
+ */
46
+ export declare function buildDatabaseEnvVars(plan: ApplicationResourcePlan, compute: ComputeResourcePlan): DatabaseEnvVars;
47
+ /**
48
+ * Check if a database needs a variable assignment (referenced by compute)
49
+ */
50
+ export declare function databaseNeedsVariable(database: DatabaseResourcePlan, plan: ApplicationResourcePlan): boolean;
51
+ /**
52
+ * Generate database infrastructure code
53
+ */
54
+ export declare function generateDatabaseCode(plan: ApplicationResourcePlan): string;