@fjall/generator 0.88.4 → 0.89.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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/ast/astCdnParser.d.ts +15 -0
  3. package/dist/src/ast/astCdnParser.js +114 -0
  4. package/dist/src/ast/astCommonParser.d.ts +90 -0
  5. package/dist/src/ast/astCommonParser.js +351 -0
  6. package/dist/src/ast/astComputeParser.d.ts +14 -2
  7. package/dist/src/ast/astComputeParser.js +55 -9
  8. package/dist/src/ast/astDatabaseParser.d.ts +104 -0
  9. package/dist/src/ast/astDatabaseParser.js +275 -0
  10. package/dist/src/ast/astInfrastructureParser.d.ts +23 -277
  11. package/dist/src/ast/astInfrastructureParser.js +83 -1456
  12. package/dist/src/ast/astMessagingParser.d.ts +25 -0
  13. package/dist/src/ast/astMessagingParser.js +78 -0
  14. package/dist/src/ast/astNetworkParser.d.ts +70 -0
  15. package/dist/src/ast/astNetworkParser.js +219 -0
  16. package/dist/src/ast/astPatternParser.d.ts +80 -0
  17. package/dist/src/ast/astPatternParser.js +155 -0
  18. package/dist/src/ast/astStorageParser.d.ts +18 -0
  19. package/dist/src/ast/astStorageParser.js +164 -0
  20. package/dist/src/ast/index.d.ts +1 -0
  21. package/dist/src/ast/index.js +4 -0
  22. package/dist/src/dns/bindParser.d.ts +13 -0
  23. package/dist/src/dns/bindParser.js +224 -0
  24. package/dist/src/dns/bindWriter.d.ts +2 -0
  25. package/dist/src/dns/bindWriter.js +52 -0
  26. package/dist/src/dns/index.d.ts +4 -0
  27. package/dist/src/dns/index.js +4 -0
  28. package/dist/src/dns/infrastructureWriter.d.ts +2 -0
  29. package/dist/src/dns/infrastructureWriter.js +58 -0
  30. package/dist/src/dns/types.d.ts +82 -0
  31. package/dist/src/dns/types.js +52 -0
  32. package/dist/src/generation/common.d.ts +1 -16
  33. package/dist/src/generation/common.js +2 -28
  34. package/dist/src/generation/compute.js +77 -28
  35. package/dist/src/generation/index.d.ts +2 -1
  36. package/dist/src/generation/index.js +3 -1
  37. package/dist/src/generation/messagingConnections.d.ts +33 -0
  38. package/dist/src/generation/messagingConnections.js +73 -0
  39. package/dist/src/generation/storage.d.ts +5 -1
  40. package/dist/src/generation/storage.js +9 -1
  41. package/dist/src/generation/storageConnections.d.ts +3 -3
  42. package/dist/src/generation/storageConnections.js +8 -4
  43. package/dist/src/index.d.ts +1 -0
  44. package/dist/src/index.js +2 -0
  45. package/dist/src/planning/resourcePlanning.js +0 -2
  46. package/dist/src/presets/tierTypes.d.ts +4 -1
  47. package/dist/src/schemas/applicationSchemas.d.ts +854 -0
  48. package/dist/src/schemas/applicationSchemas.js +80 -0
  49. package/dist/src/schemas/baseSchemas.d.ts +206 -0
  50. package/dist/src/schemas/baseSchemas.js +248 -0
  51. package/dist/src/schemas/cdnSchemas.d.ts +61 -0
  52. package/dist/src/schemas/cdnSchemas.js +62 -0
  53. package/dist/src/schemas/computeSchemas.d.ts +723 -0
  54. package/dist/src/schemas/computeSchemas.js +727 -0
  55. package/dist/src/schemas/constants.d.ts +12 -8
  56. package/dist/src/schemas/constants.js +14 -4
  57. package/dist/src/schemas/databaseSchemas.d.ts +638 -0
  58. package/dist/src/schemas/databaseSchemas.js +366 -0
  59. package/dist/src/schemas/messagingSchemas.d.ts +20 -0
  60. package/dist/src/schemas/messagingSchemas.js +29 -0
  61. package/dist/src/schemas/networkSchemas.d.ts +246 -0
  62. package/dist/src/schemas/networkSchemas.js +125 -0
  63. package/dist/src/schemas/patternSchemas.d.ts +708 -0
  64. package/dist/src/schemas/patternSchemas.js +294 -0
  65. package/dist/src/schemas/resourceSchemas.d.ts +24 -3530
  66. package/dist/src/schemas/resourceSchemas.js +24 -2011
  67. package/dist/src/schemas/storageSchemas.d.ts +93 -0
  68. package/dist/src/schemas/storageSchemas.js +119 -0
  69. package/dist/src/util/errorUtils.d.ts +1 -2
  70. package/dist/src/util/errorUtils.js +1 -15
  71. package/dist/src/validation/patterns.d.ts +9 -0
  72. package/dist/src/validation/patterns.js +9 -0
  73. package/dist/src/version.d.ts +1 -1
  74. package/dist/src/version.js +1 -1
  75. package/package.json +5 -3
@@ -0,0 +1,25 @@
1
+ import * as ts from "typescript";
2
+ import type { ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
3
+ import { type ParsedValue } from "./astCommonParser.js";
4
+ /** Parsed SQS queue resource from app.addMessaging(MessagingFactory.build(...)) */
5
+ export interface ParsedSQSResource {
6
+ variableName?: string;
7
+ resourceName: string;
8
+ queueType: string;
9
+ visibilityTimeout?: number;
10
+ retentionPeriod?: number;
11
+ contentBasedDeduplication?: boolean;
12
+ extraProperties?: Array<{
13
+ key: string;
14
+ sourceText: string;
15
+ }>;
16
+ node: ts.Node;
17
+ }
18
+ export declare function parseDeadLetterQueueConfig(value: ParsedValue): {
19
+ enabled?: boolean;
20
+ maxReceiveCount?: number;
21
+ } | false | undefined;
22
+ /** Find all SQS resources from addMessaging calls */
23
+ export declare function findSQSResources(sourceFile: ts.SourceFile): ParsedSQSResource[];
24
+ /** Convert parsed SQS resources to plan format */
25
+ export declare function convertSQSResources(sqsResources: ParsedSQSResource[]): ApplicationResourcePlan["sqs"];
@@ -0,0 +1,78 @@
1
+ import * as ts from "typescript";
2
+ import { asBoolean, asNumber, asString, captureExtraProperties, collectFromAst, extractVariableName, isFactoryBuildCall, isFactoryMethodCall, isParsedObject, omitUndefined, parseObjectLiteral, } from "./astCommonParser.js";
3
+ // ---- Extraction helpers ----
4
+ function extractSQSResource(addMessagingCall, buildCall) {
5
+ if (buildCall.arguments.length < 2)
6
+ return null;
7
+ const nameArg = buildCall.arguments[0];
8
+ const configArg = buildCall.arguments[1];
9
+ if (!ts.isStringLiteral(nameArg) ||
10
+ !ts.isObjectLiteralExpression(configArg)) {
11
+ return null;
12
+ }
13
+ const config = parseObjectLiteral(configArg);
14
+ const resource = {
15
+ resourceName: nameArg.text,
16
+ queueType: asString(config.queueType) ?? "standard",
17
+ visibilityTimeout: asNumber(config.visibilityTimeout),
18
+ retentionPeriod: asNumber(config.messageRetentionPeriod),
19
+ contentBasedDeduplication: asBoolean(config.contentBasedDeduplication),
20
+ node: addMessagingCall,
21
+ };
22
+ const varName = extractVariableName(addMessagingCall);
23
+ if (varName)
24
+ resource.variableName = varName;
25
+ const SQS_KNOWN_KEYS = new Set([
26
+ "type",
27
+ "queueType",
28
+ "visibilityTimeout",
29
+ "messageRetentionPeriod",
30
+ "contentBasedDeduplication",
31
+ ]);
32
+ const extras = captureExtraProperties(config, SQS_KNOWN_KEYS);
33
+ if (extras.length > 0)
34
+ resource.extraProperties = extras;
35
+ return resource;
36
+ }
37
+ // ---- Parsing for dead letter queue config (used by pattern parser) ----
38
+ export function parseDeadLetterQueueConfig(value) {
39
+ if (value === undefined || value === null)
40
+ return undefined;
41
+ if (value === false)
42
+ return false;
43
+ if (!isParsedObject(value))
44
+ return undefined;
45
+ return omitUndefined({
46
+ enabled: asBoolean(value.enabled),
47
+ maxReceiveCount: asNumber(value.maxReceiveCount),
48
+ });
49
+ }
50
+ // ---- Public API ----
51
+ /** Find all SQS resources from addMessaging calls */
52
+ export function findSQSResources(sourceFile) {
53
+ return collectFromAst(sourceFile, (node) => {
54
+ if (!ts.isCallExpression(node) ||
55
+ !isFactoryMethodCall(node, "addMessaging"))
56
+ return null;
57
+ const messagingArg = node.arguments[0];
58
+ if (!isFactoryBuildCall(messagingArg, "MessagingFactory"))
59
+ return null;
60
+ return extractSQSResource(node, messagingArg);
61
+ });
62
+ }
63
+ /** Convert parsed SQS resources to plan format */
64
+ export function convertSQSResources(sqsResources) {
65
+ if (sqsResources.length === 0)
66
+ return undefined;
67
+ return sqsResources.map((queue) => ({
68
+ name: queue.resourceName,
69
+ queueType: queue.queueType === "fifo" ? "fifo" : "standard",
70
+ ...omitUndefined({
71
+ visibilityTimeout: queue.visibilityTimeout,
72
+ retentionPeriod: queue.retentionPeriod,
73
+ contentBasedDeduplication: queue.contentBasedDeduplication,
74
+ variableName: queue.variableName,
75
+ extraProperties: queue.extraProperties,
76
+ }),
77
+ }));
78
+ }
@@ -0,0 +1,70 @@
1
+ import * as ts from "typescript";
2
+ import type { ApplicationResourcePlan, NetworkResourcePlan } from "../schemas/resourceSchemas.js";
3
+ import { type ParsedObject } from "./astCommonParser.js";
4
+ /** Parsed network configuration from App.getApp() options */
5
+ export interface ParsedNetworkConfig {
6
+ maxAzs?: number;
7
+ natGateways?: {
8
+ count?: number;
9
+ } | false;
10
+ flowLogs?: {
11
+ destination?: string;
12
+ retentionDays?: number;
13
+ } | false;
14
+ vpcEndpoints?: ParsedObject;
15
+ }
16
+ /** Parsed additional network resource from app.addNetwork() */
17
+ export interface ParsedNetworkResource {
18
+ variableName?: string;
19
+ name: string;
20
+ config: {
21
+ maxAzs?: number;
22
+ natGateways?: {
23
+ count?: number;
24
+ } | false;
25
+ flowLogs?: {
26
+ destination?: string;
27
+ retentionDays?: number;
28
+ } | false;
29
+ vpcEndpoints?: ParsedObject;
30
+ };
31
+ node: ts.Node;
32
+ }
33
+ /** Find VPC ID from App.getApp() network.useExisting option */
34
+ export declare function findVpcId(sourceFile: ts.SourceFile): string | undefined;
35
+ /** Extract the network configuration from App.getApp() options */
36
+ export declare function findNetworkConfig(sourceFile: ts.SourceFile): ParsedNetworkConfig | undefined;
37
+ /** Extract the backup configuration from App.getApp() options */
38
+ export declare function findBackupConfig(sourceFile: ts.SourceFile): {
39
+ tier: string;
40
+ } | false | undefined;
41
+ /** Extract the tunnel configuration from App.getApp() options */
42
+ export declare function findTunnelConfig(sourceFile: ts.SourceFile): {
43
+ instanceType?: string;
44
+ } | boolean | undefined;
45
+ /** Find all app.addNetwork() calls and extract their configuration */
46
+ export declare function findNetworkResources(sourceFile: ts.SourceFile): ParsedNetworkResource[];
47
+ /** Builds the conditional spread fields shared by primary and additional network configs */
48
+ export declare function buildNetworkFields(config: {
49
+ maxAzs?: number;
50
+ natGateways?: {
51
+ count?: number;
52
+ } | false;
53
+ flowLogs?: {
54
+ destination?: string;
55
+ retentionDays?: number;
56
+ } | false;
57
+ vpcEndpoints?: ParsedObject | Record<string, unknown>;
58
+ }): NetworkResourcePlan;
59
+ /** Convert network config to plan format */
60
+ export declare function convertNetworkConfig(network: ParsedNetworkConfig | undefined): ApplicationResourcePlan["network"];
61
+ /** Convert backup config to plan format */
62
+ export declare function convertBackupConfig(backup: {
63
+ tier: string;
64
+ } | false | undefined): ApplicationResourcePlan["backup"];
65
+ /** Convert tunnel config to plan format */
66
+ export declare function convertTunnelConfig(tunnel: {
67
+ instanceType?: string;
68
+ } | boolean | undefined): ApplicationResourcePlan["tunnel"];
69
+ /** Convert additional network resources to plan format */
70
+ export declare function convertAdditionalNetworks(networkResources: ParsedNetworkResource[]): ApplicationResourcePlan["additionalNetworks"];
@@ -0,0 +1,219 @@
1
+ import * as ts from "typescript";
2
+ import { constIncludes, BACKUP_VAULT_TIERS } from "../schemas/constants.js";
3
+ import { asNumber, asString, collectFromAst, extractVariableName, findFirstInAst, isAppGetAppCall, isFactoryBuildCall, isFactoryMethodCall, isNamedProperty, isParsedObject, omitUndefined, parseObjectLiteral, parseBooleanOrConfig, } from "./astCommonParser.js";
4
+ // ---- Flow log destination ----
5
+ const FLOW_LOG_DESTINATIONS = ["cloudwatch", "s3"];
6
+ function asFlowLogDestination(value) {
7
+ if (value === undefined)
8
+ return undefined;
9
+ return FLOW_LOG_DESTINATIONS.includes(value)
10
+ ? value
11
+ : undefined;
12
+ }
13
+ // ---- Network config parsing ----
14
+ function parseNetworkConfigFields(parsed) {
15
+ return {
16
+ maxAzs: asNumber(parsed.maxAzs),
17
+ natGateways: parseBooleanOrConfig(parsed.natGateways, (v) => ({
18
+ count: asNumber(v.count),
19
+ })),
20
+ flowLogs: parseBooleanOrConfig(parsed.flowLogs, (v) => ({
21
+ destination: asString(v.destination),
22
+ retentionDays: asNumber(v.retentionDays),
23
+ })),
24
+ vpcEndpoints: isParsedObject(parsed.vpcEndpoints)
25
+ ? parsed.vpcEndpoints
26
+ : undefined,
27
+ };
28
+ }
29
+ // ---- Extraction helpers ----
30
+ function extractNetworkResource(addNetworkCall, buildCall) {
31
+ if (buildCall.arguments.length < 2)
32
+ return null;
33
+ const nameArg = buildCall.arguments[0];
34
+ const configArg = buildCall.arguments[1];
35
+ if (!ts.isStringLiteral(nameArg))
36
+ return null;
37
+ const name = nameArg.text;
38
+ const parsed = ts.isObjectLiteralExpression(configArg)
39
+ ? parseObjectLiteral(configArg)
40
+ : {};
41
+ const networkFields = parseNetworkConfigFields(parsed);
42
+ const resource = {
43
+ name,
44
+ config: omitUndefined({ ...networkFields }),
45
+ node: addNetworkCall,
46
+ };
47
+ const varName = extractVariableName(addNetworkCall);
48
+ if (varName)
49
+ resource.variableName = varName;
50
+ return resource;
51
+ }
52
+ // ---- Public API ----
53
+ /** Find VPC ID from App.getApp() network.useExisting option */
54
+ export function findVpcId(sourceFile) {
55
+ return findFirstInAst(sourceFile, (node) => {
56
+ if (!isAppGetAppCall(node) || node.arguments.length <= 1)
57
+ return undefined;
58
+ const optionsArg = node.arguments[1];
59
+ if (!ts.isObjectLiteralExpression(optionsArg))
60
+ return undefined;
61
+ for (const prop of optionsArg.properties) {
62
+ if (isNamedProperty(prop, "network") &&
63
+ ts.isObjectLiteralExpression(prop.initializer)) {
64
+ for (const networkProp of prop.initializer.properties) {
65
+ if (isNamedProperty(networkProp, "useExisting") &&
66
+ ts.isStringLiteral(networkProp.initializer)) {
67
+ return networkProp.initializer.text;
68
+ }
69
+ }
70
+ }
71
+ }
72
+ return undefined;
73
+ });
74
+ }
75
+ /** Extract the network configuration from App.getApp() options */
76
+ export function findNetworkConfig(sourceFile) {
77
+ return findFirstInAst(sourceFile, (node) => {
78
+ if (!isAppGetAppCall(node) || node.arguments.length <= 1)
79
+ return undefined;
80
+ const optionsArg = node.arguments[1];
81
+ if (!ts.isObjectLiteralExpression(optionsArg))
82
+ return undefined;
83
+ for (const prop of optionsArg.properties) {
84
+ if (isNamedProperty(prop, "network")) {
85
+ if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword)
86
+ return undefined;
87
+ if (ts.isObjectLiteralExpression(prop.initializer)) {
88
+ const hasUseExisting = prop.initializer.properties.some((p) => isNamedProperty(p, "useExisting"));
89
+ if (!hasUseExisting) {
90
+ const parsed = parseObjectLiteral(prop.initializer);
91
+ return parseNetworkConfigFields(parsed);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ return undefined;
97
+ });
98
+ }
99
+ /** Extract the backup configuration from App.getApp() options */
100
+ export function findBackupConfig(sourceFile) {
101
+ return findFirstInAst(sourceFile, (node) => {
102
+ if (!isAppGetAppCall(node) || node.arguments.length <= 1)
103
+ return undefined;
104
+ const optionsArg = node.arguments[1];
105
+ if (!ts.isObjectLiteralExpression(optionsArg))
106
+ return undefined;
107
+ for (const prop of optionsArg.properties) {
108
+ if (isNamedProperty(prop, "backup")) {
109
+ if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword)
110
+ return false;
111
+ if (ts.isObjectLiteralExpression(prop.initializer)) {
112
+ const parsed = parseObjectLiteral(prop.initializer);
113
+ const tier = asString(parsed.tier);
114
+ if (tier)
115
+ return { tier };
116
+ }
117
+ }
118
+ }
119
+ return undefined;
120
+ });
121
+ }
122
+ /** Extract the tunnel configuration from App.getApp() options */
123
+ export function findTunnelConfig(sourceFile) {
124
+ return findFirstInAst(sourceFile, (node) => {
125
+ if (!isAppGetAppCall(node) || node.arguments.length <= 1)
126
+ return undefined;
127
+ const optionsArg = node.arguments[1];
128
+ if (!ts.isObjectLiteralExpression(optionsArg))
129
+ return undefined;
130
+ for (const prop of optionsArg.properties) {
131
+ if (isNamedProperty(prop, "tunnel")) {
132
+ if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword)
133
+ return false;
134
+ if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword)
135
+ return true;
136
+ if (ts.isObjectLiteralExpression(prop.initializer)) {
137
+ const parsed = parseObjectLiteral(prop.initializer);
138
+ const instanceType = asString(parsed.instanceType);
139
+ if (instanceType)
140
+ return { instanceType };
141
+ return {};
142
+ }
143
+ }
144
+ }
145
+ return undefined;
146
+ });
147
+ }
148
+ /** Find all app.addNetwork() calls and extract their configuration */
149
+ export function findNetworkResources(sourceFile) {
150
+ return collectFromAst(sourceFile, (node) => {
151
+ if (!ts.isCallExpression(node) || !isFactoryMethodCall(node, "addNetwork"))
152
+ return null;
153
+ const networkArg = node.arguments[0];
154
+ if (!isFactoryBuildCall(networkArg, "NetworkFactory"))
155
+ return null;
156
+ return extractNetworkResource(node, networkArg);
157
+ });
158
+ }
159
+ // ---- Plan conversion ----
160
+ /** Builds the conditional spread fields shared by primary and additional network configs */
161
+ export function buildNetworkFields(config) {
162
+ const flowLogs = config.flowLogs;
163
+ return {
164
+ ...omitUndefined({
165
+ maxAzs: config.maxAzs,
166
+ natGateways: config.natGateways,
167
+ vpcEndpoints: config.vpcEndpoints,
168
+ }),
169
+ ...(flowLogs !== undefined && {
170
+ flowLogs: flowLogs === false
171
+ ? false
172
+ : omitUndefined({
173
+ destination: asFlowLogDestination(flowLogs.destination),
174
+ retentionDays: flowLogs.retentionDays,
175
+ }),
176
+ }),
177
+ };
178
+ }
179
+ /** Convert network config to plan format */
180
+ export function convertNetworkConfig(network) {
181
+ if (!network)
182
+ return undefined;
183
+ return buildNetworkFields(network);
184
+ }
185
+ /** Convert backup config to plan format */
186
+ export function convertBackupConfig(backup) {
187
+ if (backup === undefined)
188
+ return undefined;
189
+ if (backup === false)
190
+ return false;
191
+ const tier = backup.tier;
192
+ if (constIncludes(BACKUP_VAULT_TIERS, tier)) {
193
+ return { tier: tier };
194
+ }
195
+ return undefined;
196
+ }
197
+ /** Convert tunnel config to plan format */
198
+ export function convertTunnelConfig(tunnel) {
199
+ if (tunnel === undefined)
200
+ return undefined;
201
+ if (tunnel === false)
202
+ return false;
203
+ if (tunnel === true)
204
+ return {};
205
+ const result = {};
206
+ if (tunnel.instanceType) {
207
+ result.instanceType = tunnel.instanceType;
208
+ }
209
+ return result;
210
+ }
211
+ /** Convert additional network resources to plan format */
212
+ export function convertAdditionalNetworks(networkResources) {
213
+ if (!networkResources || networkResources.length === 0)
214
+ return undefined;
215
+ return networkResources.map((network) => ({
216
+ name: network.name,
217
+ ...buildNetworkFields(network.config),
218
+ }));
219
+ }
@@ -0,0 +1,80 @@
1
+ import * as ts from "typescript";
2
+ import type { ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
3
+ /** Parsed Lambda function configuration */
4
+ export interface ParsedLambdaConfig {
5
+ memorySize?: number;
6
+ timeout?: number;
7
+ ephemeralStorageSize?: number;
8
+ }
9
+ /** Parsed pattern resource from app.addPattern(PatternFactory.build(...)) */
10
+ export interface ParsedPatternResource {
11
+ variableName?: string;
12
+ constructId: string;
13
+ type: "payload" | "nextjs";
14
+ config: {
15
+ name: string;
16
+ domain?: string;
17
+ database?: {
18
+ type?: "Instance" | "Aurora";
19
+ databaseName?: string;
20
+ databaseEngine?: "postgresql" | "mysql";
21
+ deletionProtection?: boolean;
22
+ backupRetention?: number;
23
+ port?: number;
24
+ publiclyAccessible?: boolean;
25
+ allowedIpCidr?: string;
26
+ instanceType?: string;
27
+ allocatedStorage?: number;
28
+ multiAz?: boolean;
29
+ allowVpcAccess?: boolean;
30
+ monitoringInterval?: number;
31
+ preferredMaintenanceWindow?: string;
32
+ snapshotIdentifier?: string;
33
+ snapshotUsername?: string;
34
+ readReplica?: object | false;
35
+ writer?: object;
36
+ readers?: object | false;
37
+ databaseInsights?: object | false;
38
+ proxy?: object | false;
39
+ credentials?: object;
40
+ encryption?: object;
41
+ };
42
+ compute?: {
43
+ server?: ParsedLambdaConfig;
44
+ imageOptimisation?: ParsedLambdaConfig;
45
+ revalidation?: ParsedLambdaConfig;
46
+ };
47
+ storage?: {
48
+ assets?: {
49
+ versioned?: boolean;
50
+ };
51
+ cache?: {
52
+ versioned?: boolean;
53
+ };
54
+ media?: {
55
+ versioned?: boolean;
56
+ };
57
+ };
58
+ messaging?: {
59
+ revalidationQueue?: {
60
+ visibilityTimeout?: number;
61
+ messageRetentionPeriod?: number;
62
+ maxMessageSize?: number;
63
+ deadLetterQueue?: {
64
+ enabled?: boolean;
65
+ maxReceiveCount?: number;
66
+ } | false;
67
+ };
68
+ };
69
+ cdn?: {
70
+ domainNames?: string[];
71
+ certificateArn?: string;
72
+ };
73
+ environment?: Record<string, string>;
74
+ };
75
+ node: ts.Node;
76
+ }
77
+ /** Find pattern resources from app.addPattern(PatternFactory.build(...)) calls */
78
+ export declare function findPatternResources(sourceFile: ts.SourceFile): ParsedPatternResource[];
79
+ /** Apply pattern config to plan */
80
+ export declare function applyPatternConfig(plan: ApplicationResourcePlan, patternResources: ParsedPatternResource[]): void;
@@ -0,0 +1,155 @@
1
+ import * as ts from "typescript";
2
+ import { asBoolean, asNumber, asString, asStringArray, asStringUnion, asObjectOrFalse, collectFromAst, extractSubConfig, extractVariableName, isFactoryBuildCall, isFactoryMethodCall, isParsedObject, parseObjectLiteral, parseOptionalConfig, typed, } from "./astCommonParser.js";
3
+ import { parseDeadLetterQueueConfig } from "./astMessagingParser.js";
4
+ // ---- Internal helpers ----
5
+ const VALID_NON_GLOBAL_DB_TYPES = ["Instance", "Aurora"];
6
+ const VALID_DB_ENGINES = ["postgresql", "mysql"];
7
+ function parseLambdaConfig(obj) {
8
+ if (!isParsedObject(obj))
9
+ return undefined;
10
+ const config = {
11
+ ...(obj.memorySize !== undefined && {
12
+ memorySize: asNumber(obj.memorySize),
13
+ }),
14
+ ...(obj.timeout !== undefined && { timeout: asNumber(obj.timeout) }),
15
+ ...(obj.ephemeralStorageSize !== undefined && {
16
+ ephemeralStorageSize: asNumber(obj.ephemeralStorageSize),
17
+ }),
18
+ };
19
+ return Object.keys(config).length > 0 ? config : undefined;
20
+ }
21
+ function extractPatternDatabaseConfig(rawConfig) {
22
+ return extractSubConfig(rawConfig, "database", (db) => ({
23
+ type: asStringUnion(db.type, VALID_NON_GLOBAL_DB_TYPES),
24
+ databaseName: asString(db.databaseName),
25
+ databaseEngine: asStringUnion(db.databaseEngine, VALID_DB_ENGINES),
26
+ deletionProtection: asBoolean(db.deletionProtection),
27
+ backupRetention: asNumber(db.backupRetention),
28
+ port: asNumber(db.port),
29
+ publiclyAccessible: asBoolean(db.publiclyAccessible),
30
+ allowedIpCidr: asString(db.allowedIpCidr),
31
+ instanceType: asString(db.instanceType),
32
+ allocatedStorage: asNumber(db.allocatedStorage),
33
+ multiAz: asBoolean(db.multiAz),
34
+ allowVpcAccess: asBoolean(db.allowVpcAccess),
35
+ monitoringInterval: asNumber(db.monitoringInterval),
36
+ preferredMaintenanceWindow: asString(db.preferredMaintenanceWindow),
37
+ snapshotIdentifier: asString(db.snapshotIdentifier),
38
+ snapshotUsername: asString(db.snapshotUsername),
39
+ readReplica: asObjectOrFalse(db.readReplica),
40
+ writer: parseOptionalConfig(db.writer, typed()),
41
+ readers: asObjectOrFalse(db.readers),
42
+ databaseInsights: asObjectOrFalse(db.databaseInsights),
43
+ proxy: asObjectOrFalse(db.proxy),
44
+ credentials: parseOptionalConfig(db.credentials, typed()),
45
+ encryption: parseOptionalConfig(db.encryption, typed()),
46
+ }));
47
+ }
48
+ function extractPatternComputeConfig(rawConfig) {
49
+ return extractSubConfig(rawConfig, "compute", (compute) => ({
50
+ server: parseOptionalConfig(compute.server, parseLambdaConfig),
51
+ imageOptimisation: parseOptionalConfig(compute.imageOptimisation, parseLambdaConfig),
52
+ revalidation: parseOptionalConfig(compute.revalidation, parseLambdaConfig),
53
+ }));
54
+ }
55
+ function extractPatternStorageConfig(rawConfig) {
56
+ const parseVersionedConfig = (obj) => ({
57
+ versioned: asBoolean(obj.versioned),
58
+ });
59
+ return extractSubConfig(rawConfig, "storage", (storage) => ({
60
+ assets: parseOptionalConfig(storage.assets, parseVersionedConfig),
61
+ cache: parseOptionalConfig(storage.cache, parseVersionedConfig),
62
+ media: parseOptionalConfig(storage.media, parseVersionedConfig),
63
+ }));
64
+ }
65
+ function extractPatternMessagingConfig(rawConfig) {
66
+ return extractSubConfig(rawConfig, "messaging", (messaging) => ({
67
+ revalidationQueue: parseOptionalConfig(messaging.revalidationQueue, (queue) => ({
68
+ visibilityTimeout: asNumber(queue.visibilityTimeout),
69
+ messageRetentionPeriod: asNumber(queue.messageRetentionPeriod),
70
+ maxMessageSize: asNumber(queue.maxMessageSize),
71
+ deadLetterQueue: parseDeadLetterQueueConfig(queue.deadLetterQueue),
72
+ })),
73
+ }));
74
+ }
75
+ function extractPatternCdnConfig(rawConfig) {
76
+ return extractSubConfig(rawConfig, "cdn", (cdn) => ({
77
+ domainNames: asStringArray(cdn.domainNames),
78
+ certificateArn: asString(cdn.certificateArn),
79
+ }));
80
+ }
81
+ function extractPatternEnvironmentConfig(rawConfig) {
82
+ return extractSubConfig(rawConfig, "environment", (env) => {
83
+ const environment = Object.fromEntries(Object.entries(env).filter((entry) => typeof entry[1] === "string"));
84
+ return Object.keys(environment).length > 0 ? environment : undefined;
85
+ });
86
+ }
87
+ function extractPatternResource(buildCall, addPatternCall) {
88
+ if (buildCall.arguments.length < 2)
89
+ return null;
90
+ const constructIdArg = buildCall.arguments[0];
91
+ const configArg = buildCall.arguments[1];
92
+ if (!ts.isStringLiteral(constructIdArg) ||
93
+ !ts.isObjectLiteralExpression(configArg)) {
94
+ return null;
95
+ }
96
+ const constructId = constructIdArg.text;
97
+ const rawConfig = parseObjectLiteral(configArg);
98
+ const patternType = rawConfig.type;
99
+ if (patternType !== "payload" && patternType !== "nextjs") {
100
+ return null;
101
+ }
102
+ const variableName = extractVariableName(addPatternCall);
103
+ const name = asString(rawConfig.name);
104
+ if (!name) {
105
+ return null;
106
+ }
107
+ return {
108
+ variableName,
109
+ constructId,
110
+ type: patternType,
111
+ config: {
112
+ name,
113
+ domain: asString(rawConfig.domain),
114
+ database: extractPatternDatabaseConfig(rawConfig),
115
+ compute: extractPatternComputeConfig(rawConfig),
116
+ storage: extractPatternStorageConfig(rawConfig),
117
+ messaging: extractPatternMessagingConfig(rawConfig),
118
+ cdn: extractPatternCdnConfig(rawConfig),
119
+ environment: extractPatternEnvironmentConfig(rawConfig),
120
+ },
121
+ node: buildCall,
122
+ };
123
+ }
124
+ // ---- Public API ----
125
+ /** Find pattern resources from app.addPattern(PatternFactory.build(...)) calls */
126
+ export function findPatternResources(sourceFile) {
127
+ return collectFromAst(sourceFile, (node) => {
128
+ if (!ts.isCallExpression(node) || !isFactoryMethodCall(node, "addPattern"))
129
+ return null;
130
+ const patternArg = node.arguments[0];
131
+ if (!isFactoryBuildCall(patternArg, "PatternFactory"))
132
+ return null;
133
+ return extractPatternResource(patternArg, node);
134
+ });
135
+ }
136
+ /** Apply pattern config to plan */
137
+ export function applyPatternConfig(plan, patternResources) {
138
+ if (!patternResources || patternResources.length === 0)
139
+ return;
140
+ const patternResource = patternResources[0];
141
+ if (patternResource.type !== "payload" && patternResource.type !== "nextjs")
142
+ return;
143
+ plan.pattern = patternResource.type;
144
+ plan.patternConfig = {
145
+ type: patternResource.type,
146
+ name: patternResource.config.name,
147
+ domain: patternResource.config.domain,
148
+ database: patternResource.config.database,
149
+ compute: patternResource.config.compute,
150
+ storage: patternResource.config.storage,
151
+ messaging: patternResource.config.messaging,
152
+ cdn: patternResource.config.cdn,
153
+ environment: patternResource.config.environment,
154
+ };
155
+ }
@@ -0,0 +1,18 @@
1
+ import * as ts from "typescript";
2
+ import { type ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
3
+ import { type ParsedObject } from "./astCommonParser.js";
4
+ declare const S3_BUCKET_CLASSES: Set<string>;
5
+ export { S3_BUCKET_CLASSES };
6
+ export interface ParsedS3Resource {
7
+ variableName: string;
8
+ resourceName: string;
9
+ bucketClass: string;
10
+ config: ParsedObject;
11
+ node: ts.Node;
12
+ }
13
+ /** Find S3 resources created via new S3Bucket() constructor pattern */
14
+ export declare function findS3Resources(sourceFile: ts.SourceFile): ParsedS3Resource[];
15
+ /** Find S3 resources created via app.addStorage(StorageFactory.build(...)) factory pattern */
16
+ export declare function findS3FactoryResources(sourceFile: ts.SourceFile): ParsedS3Resource[];
17
+ /** Convert parsed S3 resources to plan format */
18
+ export declare function convertS3Resources(s3Resources: ParsedS3Resource[]): ApplicationResourcePlan["s3"];