@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,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Code Generation
|
|
3
|
+
*
|
|
4
|
+
* Functions for generating storage infrastructure code including
|
|
5
|
+
* S3 buckets, DynamoDB tables, and SQS queues.
|
|
6
|
+
*/
|
|
7
|
+
import { buildProperty, getVariableName, emitExtraProperties, } from "./common.js";
|
|
8
|
+
/**
|
|
9
|
+
* Generate S3 bucket configuration properties using buildProperty for consistent formatting
|
|
10
|
+
*/
|
|
11
|
+
function generateS3BucketProps(bucket) {
|
|
12
|
+
let code = "";
|
|
13
|
+
code += buildProperty(bucket.bucketName !== undefined, "bucketName", bucket.bucketName, "string");
|
|
14
|
+
code += buildProperty(bucket.stackPlacement !== undefined && bucket.stackPlacement !== "storage", "stackPlacement", bucket.stackPlacement, "string");
|
|
15
|
+
code += buildProperty(bucket.publicReadAccess === true, "publicReadAccess", true);
|
|
16
|
+
code += buildProperty(bucket.websiteHosting !== undefined, "websiteHosting", bucket.websiteHosting, "object");
|
|
17
|
+
code += buildProperty(bucket.backupVaultTier !== undefined, "backupVaultTier", bucket.backupVaultTier, "string");
|
|
18
|
+
code += buildProperty(bucket.versioned !== undefined, "versioned", bucket.versioned);
|
|
19
|
+
code += buildProperty(bucket.encryption !== undefined, "encryption", bucket.encryption, "string");
|
|
20
|
+
code += buildProperty(bucket.kmsKeyArn !== undefined, "kmsKeyArn", bucket.kmsKeyArn, "string");
|
|
21
|
+
code += buildProperty(bucket.cors !== undefined && bucket.cors.length > 0, "cors", bucket.cors, "object");
|
|
22
|
+
code += buildProperty(bucket.deployment !== undefined, "deployment", bucket.deployment, "object");
|
|
23
|
+
return code;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if an S3 bucket needs a variable assignment (referenced by compute or CDN)
|
|
27
|
+
*/
|
|
28
|
+
export function s3NeedsVariable(bucket, plan) {
|
|
29
|
+
// Referenced by compute via connectedStorage
|
|
30
|
+
const computeRef = plan.compute.some((compute) => compute.connectedStorage?.includes(bucket.name));
|
|
31
|
+
if (computeRef)
|
|
32
|
+
return true;
|
|
33
|
+
// Referenced by CDN as an origin
|
|
34
|
+
if (plan.cdn) {
|
|
35
|
+
if (plan.cdn.defaultOriginRef === bucket.name)
|
|
36
|
+
return true;
|
|
37
|
+
if (plan.cdn.behaviours?.some((b) => b.originRef === bucket.name))
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Generate S3 bucket infrastructure code
|
|
44
|
+
*/
|
|
45
|
+
export function generateS3Code(plan) {
|
|
46
|
+
if (plan.s3.length === 0)
|
|
47
|
+
return "";
|
|
48
|
+
let code = "";
|
|
49
|
+
for (let i = 0; i < plan.s3.length; i++) {
|
|
50
|
+
const bucket = plan.s3[i];
|
|
51
|
+
const bucketVariable = getVariableName(bucket);
|
|
52
|
+
const hasReferences = s3NeedsVariable(bucket, plan);
|
|
53
|
+
const needsLeadingNewline = plan.database.length > 0 || i > 0;
|
|
54
|
+
const leadingNewline = needsLeadingNewline ? "\n" : "";
|
|
55
|
+
const props = generateS3BucketProps(bucket);
|
|
56
|
+
const prefix = hasReferences ? `const ${bucketVariable} = ` : "";
|
|
57
|
+
const extraPropsStr = emitExtraProperties(bucket.extraProperties);
|
|
58
|
+
if (props || extraPropsStr) {
|
|
59
|
+
code += `${leadingNewline}${prefix}app.addStorage(
|
|
60
|
+
StorageFactory.build("${bucket.name}", {${props}${extraPropsStr}
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
code += `${leadingNewline}${prefix}app.addStorage(
|
|
67
|
+
StorageFactory.build("${bucket.name}", {})
|
|
68
|
+
);
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return code;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Generate DynamoDB table infrastructure code
|
|
76
|
+
*/
|
|
77
|
+
export function generateDynamoDBCode(plan) {
|
|
78
|
+
if (!plan.dynamodb || plan.dynamodb.length === 0)
|
|
79
|
+
return "";
|
|
80
|
+
let code = "";
|
|
81
|
+
for (const table of plan.dynamodb) {
|
|
82
|
+
const tableVariable = getVariableName(table);
|
|
83
|
+
code += `
|
|
84
|
+
const ${tableVariable} = app.addDatabase(
|
|
85
|
+
DatabaseFactory.build("${table.name}", {
|
|
86
|
+
type: "DynamoDB",
|
|
87
|
+
partitionKey: {
|
|
88
|
+
name: "${table.partitionKey.name}",
|
|
89
|
+
type: "${table.partitionKey.type}",
|
|
90
|
+
}`;
|
|
91
|
+
if (table.sortKey) {
|
|
92
|
+
code += `,
|
|
93
|
+
sortKey: {
|
|
94
|
+
name: "${table.sortKey.name}",
|
|
95
|
+
type: "${table.sortKey.type}",
|
|
96
|
+
}`;
|
|
97
|
+
}
|
|
98
|
+
if (table.globalSecondaryIndexes &&
|
|
99
|
+
table.globalSecondaryIndexes.length > 0) {
|
|
100
|
+
const gsiStr = table.globalSecondaryIndexes
|
|
101
|
+
.map((gsi) => {
|
|
102
|
+
let gsiCode = `{
|
|
103
|
+
indexName: "${gsi.indexName}",
|
|
104
|
+
partitionKey: {
|
|
105
|
+
name: "${gsi.partitionKey.name}",
|
|
106
|
+
type: "${gsi.partitionKey.type}",
|
|
107
|
+
},`;
|
|
108
|
+
if (gsi.sortKey) {
|
|
109
|
+
gsiCode += `
|
|
110
|
+
sortKey: {
|
|
111
|
+
name: "${gsi.sortKey.name}",
|
|
112
|
+
type: "${gsi.sortKey.type}",
|
|
113
|
+
},`;
|
|
114
|
+
}
|
|
115
|
+
gsiCode += `
|
|
116
|
+
}`;
|
|
117
|
+
return gsiCode;
|
|
118
|
+
})
|
|
119
|
+
.join(",\n ");
|
|
120
|
+
code += `,
|
|
121
|
+
globalSecondaryIndexes: [
|
|
122
|
+
${gsiStr}
|
|
123
|
+
]`;
|
|
124
|
+
}
|
|
125
|
+
if (table.ttlAttribute) {
|
|
126
|
+
code += `,
|
|
127
|
+
ttlAttribute: "${table.ttlAttribute}"`;
|
|
128
|
+
}
|
|
129
|
+
if (table.stream) {
|
|
130
|
+
code += `,
|
|
131
|
+
stream: true`;
|
|
132
|
+
}
|
|
133
|
+
code += emitExtraProperties(table.extraProperties);
|
|
134
|
+
code += `
|
|
135
|
+
})
|
|
136
|
+
);
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
return code;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Generate SQS queue infrastructure code
|
|
143
|
+
*/
|
|
144
|
+
export function generateSQSCode(plan) {
|
|
145
|
+
if (!plan.sqs || plan.sqs.length === 0)
|
|
146
|
+
return "";
|
|
147
|
+
let code = "";
|
|
148
|
+
for (const queue of plan.sqs) {
|
|
149
|
+
const queueVariable = getVariableName(queue);
|
|
150
|
+
code += `
|
|
151
|
+
const ${queueVariable} = app.addMessaging(
|
|
152
|
+
MessagingFactory.build("${queue.name}", {
|
|
153
|
+
type: "queue",
|
|
154
|
+
queueType: "${queue.queueType}"`;
|
|
155
|
+
if (queue.visibilityTimeout !== undefined) {
|
|
156
|
+
code += `,
|
|
157
|
+
visibilityTimeout: ${queue.visibilityTimeout}`;
|
|
158
|
+
}
|
|
159
|
+
if (queue.retentionPeriod !== undefined) {
|
|
160
|
+
code += `,
|
|
161
|
+
messageRetentionPeriod: ${queue.retentionPeriod}`;
|
|
162
|
+
}
|
|
163
|
+
if (queue.contentBasedDeduplication) {
|
|
164
|
+
code += `,
|
|
165
|
+
contentBasedDeduplication: true`;
|
|
166
|
+
}
|
|
167
|
+
code += emitExtraProperties(queue.extraProperties);
|
|
168
|
+
code += `
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
return code;
|
|
174
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Connection Code Generation
|
|
3
|
+
*
|
|
4
|
+
* Functions for generating storage connection code (env vars, connections array)
|
|
5
|
+
* following the same pattern as database connections.
|
|
6
|
+
*/
|
|
7
|
+
import type { S3ResourcePlan, ApplicationResourcePlan, ComputeResourcePlan, DatabaseResourcePlan } from "../schemas/resourceSchemas.js";
|
|
8
|
+
export declare const STORAGE_ENV_VARS: Readonly<{
|
|
9
|
+
readonly NAME: "BUCKET_NAME";
|
|
10
|
+
}>;
|
|
11
|
+
export type StorageEnvVarEntry = {
|
|
12
|
+
key: string;
|
|
13
|
+
expression: string;
|
|
14
|
+
};
|
|
15
|
+
export interface StorageEnvVars {
|
|
16
|
+
env: Record<string, unknown>;
|
|
17
|
+
secrets: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get S3 buckets connected to a compute resource
|
|
21
|
+
*/
|
|
22
|
+
export declare function getConnectedStorage(plan: ApplicationResourcePlan, compute: ComputeResourcePlan): S3ResourcePlan[];
|
|
23
|
+
/**
|
|
24
|
+
* Generate storage environment variable entries for a list of connected buckets.
|
|
25
|
+
* S3 uses IAM-based access, so there are no secrets — only BUCKET_NAME env vars.
|
|
26
|
+
*/
|
|
27
|
+
export declare function generateStorageEnvVarEntries(connectedStorage: S3ResourcePlan[]): StorageEnvVarEntry[];
|
|
28
|
+
/**
|
|
29
|
+
* Build storage environment variables for a compute resource.
|
|
30
|
+
* S3 always uses IAM — secrets is always empty.
|
|
31
|
+
*/
|
|
32
|
+
export declare function buildStorageEnvVars(plan: ApplicationResourcePlan, compute: ComputeResourcePlan): StorageEnvVars;
|
|
33
|
+
/**
|
|
34
|
+
* Format combined connections array for generated infrastructure code.
|
|
35
|
+
* Merges both database and storage variable names into a single connections line.
|
|
36
|
+
*/
|
|
37
|
+
export declare function formatAllConnectionsCode(connectedDatabases: DatabaseResourcePlan[], connectedStorage: S3ResourcePlan[]): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Connection Code Generation
|
|
3
|
+
*
|
|
4
|
+
* Functions for generating storage connection code (env vars, connections array)
|
|
5
|
+
* following the same pattern as database connections.
|
|
6
|
+
*/
|
|
7
|
+
import { getVariableName } from "./common.js";
|
|
8
|
+
export const STORAGE_ENV_VARS = Object.freeze({
|
|
9
|
+
NAME: "BUCKET_NAME",
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Get S3 buckets connected to a compute resource
|
|
13
|
+
*/
|
|
14
|
+
export function getConnectedStorage(plan, compute) {
|
|
15
|
+
const { connectedStorage } = compute;
|
|
16
|
+
if (!connectedStorage?.length)
|
|
17
|
+
return [];
|
|
18
|
+
return plan.s3.filter((bucket) => connectedStorage.includes(bucket.name));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generate storage environment variable entries for a list of connected buckets.
|
|
22
|
+
* S3 uses IAM-based access, so there are no secrets — only BUCKET_NAME env vars.
|
|
23
|
+
*/
|
|
24
|
+
export function generateStorageEnvVarEntries(connectedStorage) {
|
|
25
|
+
const entries = [];
|
|
26
|
+
if (connectedStorage.length === 1) {
|
|
27
|
+
const bucketVar = getVariableName(connectedStorage[0]);
|
|
28
|
+
entries.push({
|
|
29
|
+
key: STORAGE_ENV_VARS.NAME,
|
|
30
|
+
expression: `${bucketVar}.getBucketName()`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
for (const [index, bucket] of connectedStorage.entries()) {
|
|
35
|
+
const bucketVar = getVariableName(bucket);
|
|
36
|
+
const suffix = index === 0 ? "" : `_${index + 1}`;
|
|
37
|
+
entries.push({
|
|
38
|
+
key: `${STORAGE_ENV_VARS.NAME}${suffix}`,
|
|
39
|
+
expression: `${bucketVar}.getBucketName()`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return entries;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build storage environment variables for a compute resource.
|
|
47
|
+
* S3 always uses IAM — secrets is always empty.
|
|
48
|
+
*/
|
|
49
|
+
export function buildStorageEnvVars(plan, compute) {
|
|
50
|
+
const env = {};
|
|
51
|
+
const secrets = {};
|
|
52
|
+
if (!compute.connectedStorage?.length) {
|
|
53
|
+
return { env, secrets };
|
|
54
|
+
}
|
|
55
|
+
const connectedStorage = getConnectedStorage(plan, compute);
|
|
56
|
+
const entries = generateStorageEnvVarEntries(connectedStorage);
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
env[entry.key] = { __expression: entry.expression };
|
|
59
|
+
}
|
|
60
|
+
return { env, secrets };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Format combined connections array for generated infrastructure code.
|
|
64
|
+
* Merges both database and storage variable names into a single connections line.
|
|
65
|
+
*/
|
|
66
|
+
export function formatAllConnectionsCode(connectedDatabases, connectedStorage) {
|
|
67
|
+
const dbVars = connectedDatabases.map((db) => getVariableName(db));
|
|
68
|
+
const storageVars = connectedStorage.map((b) => getVariableName(b));
|
|
69
|
+
const allVars = [...dbVars, ...storageVars].join(", ");
|
|
70
|
+
return `connections: [${allVars}],`;
|
|
71
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { normaliseError, getErrorMessage } from "./util/errorUtils.js";
|
|
2
|
+
export { type Result, isSuccess, isFailure, success, failure, tryAsync, trySync, } from "./types/Result.js";
|
|
3
|
+
export { VALIDATION_PATTERNS, VALIDATION_MESSAGES, type ValidationPatternKey, type ValidationMessageKey, } from "./validation/patterns.js";
|
|
4
|
+
export { type RegionInfo, DEFAULT_REGION, regions, AWS_REGIONS_METADATA, topRegions, commonRegions, parseRegionList, isValidRegion, isValidRegionFormat, getSuggestions, validateRegion, validateRegionList, filterDuplicateRegions, getRegionOptions, getRegionOptionsExcluding, getRegionName, createRegionFormatter, } from "./aws/regions.js";
|
|
5
|
+
export { GENERATOR_VERSION } from "./version.js";
|
|
6
|
+
export * from "./schemas/index.js";
|
|
7
|
+
export * from "./generation/index.js";
|
|
8
|
+
export * from "./presets/index.js";
|
|
9
|
+
export * from "./ast/index.js";
|
|
10
|
+
export * from "./planning/index.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Utility foundation
|
|
2
|
+
export { normaliseError, getErrorMessage } from "./util/errorUtils.js";
|
|
3
|
+
export { isSuccess, isFailure, success, failure, tryAsync, trySync, } from "./types/Result.js";
|
|
4
|
+
// Validation
|
|
5
|
+
export { VALIDATION_PATTERNS, VALIDATION_MESSAGES, } from "./validation/patterns.js";
|
|
6
|
+
// AWS
|
|
7
|
+
export { DEFAULT_REGION, regions, AWS_REGIONS_METADATA, topRegions, commonRegions, parseRegionList, isValidRegion, isValidRegionFormat, getSuggestions, validateRegion, validateRegionList, filterDuplicateRegions, getRegionOptions, getRegionOptionsExcluding, getRegionName, createRegionFormatter, } from "./aws/regions.js";
|
|
8
|
+
// Version
|
|
9
|
+
export { GENERATOR_VERSION } from "./version.js";
|
|
10
|
+
// Schemas, plan types, constants
|
|
11
|
+
export * from "./schemas/index.js";
|
|
12
|
+
// Code generation
|
|
13
|
+
export * from "./generation/index.js";
|
|
14
|
+
// Tier, pattern, and storage presets
|
|
15
|
+
export * from "./presets/index.js";
|
|
16
|
+
// AST parsing & surgical modification
|
|
17
|
+
export * from "./ast/index.js";
|
|
18
|
+
// Resource planning
|
|
19
|
+
export * from "./planning/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { planApplicationResources, type OpenNextResourceOptions, planOpenNextResources, type GenerationOptions, generateInfrastructureFromPlan, } from "./resourcePlanning.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { planApplicationResources, planOpenNextResources, generateInfrastructureFromPlan, } from "./resourcePlanning.js";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type UserServiceConfig, type AppType } from "../presets/tierPresets.js";
|
|
2
|
+
import { type PatternTypeWithCustom } from "../presets/patternTierPresets.js";
|
|
3
|
+
import { type PatternType } from "../schemas/constants.js";
|
|
4
|
+
import { type Result } from "../types/Result.js";
|
|
5
|
+
import type { ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
|
|
6
|
+
export declare function planApplicationResources(appName: string, appType: AppType, includeDatabase?: boolean, services?: UserServiceConfig[], snapshotOptions?: {
|
|
7
|
+
snapshotIdentifier?: string;
|
|
8
|
+
snapshotUsername?: string;
|
|
9
|
+
}): ApplicationResourcePlan;
|
|
10
|
+
export interface OpenNextResourceOptions {
|
|
11
|
+
/** Pattern tier: lightweight, standard, resilient, or custom */
|
|
12
|
+
tier?: PatternTypeWithCustom;
|
|
13
|
+
/** Custom domain (auto-creates certificate + DNS) */
|
|
14
|
+
domain?: string;
|
|
15
|
+
/** Database configuration (uses tier defaults if not specified) */
|
|
16
|
+
database?: {
|
|
17
|
+
type?: "Instance" | "Aurora";
|
|
18
|
+
instanceType?: string;
|
|
19
|
+
databaseName?: string;
|
|
20
|
+
publiclyAccessible?: boolean;
|
|
21
|
+
allowedIpCidr?: string;
|
|
22
|
+
backupRetention?: number;
|
|
23
|
+
deletionProtection?: boolean;
|
|
24
|
+
encryption?: {
|
|
25
|
+
useCMK: true;
|
|
26
|
+
} | false;
|
|
27
|
+
};
|
|
28
|
+
/** Compute (Lambda) configuration (uses tier defaults if not specified) */
|
|
29
|
+
compute?: {
|
|
30
|
+
memorySize?: number;
|
|
31
|
+
timeout?: number;
|
|
32
|
+
};
|
|
33
|
+
/** CDN configuration (advanced - prefer `domain` for simple setup) */
|
|
34
|
+
cdn?: {
|
|
35
|
+
domainNames?: string[];
|
|
36
|
+
certificateArn?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Additional environment variables */
|
|
39
|
+
environment?: Record<string, string>;
|
|
40
|
+
/** Resource tags */
|
|
41
|
+
tags?: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Plan resources for OpenNext patterns (Next.js/Payload).
|
|
45
|
+
*
|
|
46
|
+
* All OpenNext patterns use the PatternFactory approach, generating a single
|
|
47
|
+
* `PatternFactory.build()` call. The pattern class internally handles all
|
|
48
|
+
* infrastructure (database, S3, DynamoDB, SQS, Lambdas, CDN).
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const plan = planOpenNextResources("my-cms", "payload", { tier: "standard" });
|
|
52
|
+
*/
|
|
53
|
+
export declare function planOpenNextResources(appName: string, pattern: PatternType, options?: OpenNextResourceOptions): Result<ApplicationResourcePlan, Error>;
|
|
54
|
+
export interface GenerationOptions {
|
|
55
|
+
/** Resource name mapping from old names to new names (for custom code repositioning) */
|
|
56
|
+
resourceMapping?: Map<string, string>;
|
|
57
|
+
}
|
|
58
|
+
export declare function generateInfrastructureFromPlan(plan: ApplicationResourcePlan, options?: GenerationOptions): Result<string, Error>;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { TIER_PRESETS, getDefaultDatabaseTypeForTier, getNetworkPreset, applyTierDefaultsToServices, } from "../presets/tierPresets.js";
|
|
2
|
+
import { getPatternTierPreset, isPatternTierName, } from "../presets/patternTierPresets.js";
|
|
3
|
+
import { COMPUTE_TYPE } from "../schemas/constants.js";
|
|
4
|
+
import { success, failure } from "../types/Result.js";
|
|
5
|
+
import { PatternConfigSchema } from "../schemas/resourceSchemas.js";
|
|
6
|
+
import { injectCustomCodeBlocks } from "../ast/astSurgicalModification.js";
|
|
7
|
+
import { toVariableName, toValidDatabaseName, generateImports, generateAppInit, generateTags, generateNetworkCode, generateDatabaseCode, generateS3Code, generateDynamoDBCode, generateSQSCode, generateComputeCode, generateCDNCode, collectCdnReferencedResources, usesPatternApproach, generatePatternCodeWithComments, } from "../generation/index.js";
|
|
8
|
+
const DEFAULT_NETWORK = getNetworkPreset("standard");
|
|
9
|
+
/** Type guard that narrows a pattern string to a supported PatternConfig type via Zod schema. */
|
|
10
|
+
function isPatternConfigType(value) {
|
|
11
|
+
return PatternConfigSchema.options.some((schema) => schema.shape?.type?.value === value);
|
|
12
|
+
}
|
|
13
|
+
export function planApplicationResources(appName, appType, includeDatabase = true, services, snapshotOptions) {
|
|
14
|
+
const basePlan = {
|
|
15
|
+
appName,
|
|
16
|
+
type: appType,
|
|
17
|
+
database: [],
|
|
18
|
+
s3: [],
|
|
19
|
+
compute: [],
|
|
20
|
+
importedResources: [],
|
|
21
|
+
};
|
|
22
|
+
if (appType === "custom") {
|
|
23
|
+
return basePlan;
|
|
24
|
+
}
|
|
25
|
+
const tier = appType;
|
|
26
|
+
const tierPreset = TIER_PRESETS[tier];
|
|
27
|
+
return {
|
|
28
|
+
...basePlan,
|
|
29
|
+
database: buildDatabasePlan(appName, tierPreset, tier, includeDatabase, snapshotOptions),
|
|
30
|
+
compute: buildComputePlan(appName, tierPreset, tier, includeDatabase, services),
|
|
31
|
+
network: tierPreset.network,
|
|
32
|
+
backup: tierPreset.backup,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function buildDatabasePlan(appName, tierPreset, tier, includeDatabase, snapshotOptions) {
|
|
36
|
+
const databaseType = getDefaultDatabaseTypeForTier(tier);
|
|
37
|
+
const databasePreset = tierPreset.database[databaseType];
|
|
38
|
+
if (!includeDatabase || databasePreset === null)
|
|
39
|
+
return [];
|
|
40
|
+
return [
|
|
41
|
+
{
|
|
42
|
+
name: appName,
|
|
43
|
+
type: databaseType,
|
|
44
|
+
databaseName: toValidDatabaseName(appName),
|
|
45
|
+
variableName: `${toVariableName(appName)}Database`,
|
|
46
|
+
...databasePreset,
|
|
47
|
+
...(snapshotOptions?.snapshotIdentifier !== undefined && {
|
|
48
|
+
snapshotIdentifier: snapshotOptions.snapshotIdentifier,
|
|
49
|
+
}),
|
|
50
|
+
...(snapshotOptions?.snapshotUsername !== undefined && {
|
|
51
|
+
snapshotUsername: snapshotOptions.snapshotUsername,
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
function buildScalingConfig(minCapacity, maxCapacity) {
|
|
57
|
+
if (minCapacity === undefined && maxCapacity === undefined)
|
|
58
|
+
return undefined;
|
|
59
|
+
return {
|
|
60
|
+
scaling: {
|
|
61
|
+
...(minCapacity !== undefined && { minCapacity }),
|
|
62
|
+
...(maxCapacity !== undefined && { maxCapacity }),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function buildServiceEntry(tierService, userService) {
|
|
67
|
+
const { minCapacity, maxCapacity, ...rest } = tierService;
|
|
68
|
+
const containerPort = userService?.containerPort ?? 3000;
|
|
69
|
+
return {
|
|
70
|
+
...rest,
|
|
71
|
+
dockerfilePath: userService?.dockerfilePath,
|
|
72
|
+
needsDatabaseConnection: userService?.needsDatabaseConnection,
|
|
73
|
+
containers: [{ port: containerPort }],
|
|
74
|
+
...buildScalingConfig(minCapacity, maxCapacity),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function buildComputePlan(appName, tierPreset, tier, includeDatabase, services) {
|
|
78
|
+
const ecsPreset = tierPreset.compute.ecs;
|
|
79
|
+
const tierServices = services && services.length > 0
|
|
80
|
+
? applyTierDefaultsToServices(tier, services)
|
|
81
|
+
: ecsPreset.services.map((s, i) => ({
|
|
82
|
+
...s,
|
|
83
|
+
name: i === 0 ? "api" : `service-${i + 1}`,
|
|
84
|
+
}));
|
|
85
|
+
return [
|
|
86
|
+
{
|
|
87
|
+
name: appName,
|
|
88
|
+
type: COMPUTE_TYPE.ECS,
|
|
89
|
+
needsConnection: includeDatabase,
|
|
90
|
+
connectedDatabase: includeDatabase ? [appName] : undefined,
|
|
91
|
+
variableName: `${toVariableName(appName)}Compute`,
|
|
92
|
+
cluster: ecsPreset.cluster,
|
|
93
|
+
services: tierServices.map((tierService, index) => buildServiceEntry(tierService, services?.[index])),
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Plan resources for OpenNext patterns (Next.js/Payload).
|
|
99
|
+
*
|
|
100
|
+
* All OpenNext patterns use the PatternFactory approach, generating a single
|
|
101
|
+
* `PatternFactory.build()` call. The pattern class internally handles all
|
|
102
|
+
* infrastructure (database, S3, DynamoDB, SQS, Lambdas, CDN).
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const plan = planOpenNextResources("my-cms", "payload", { tier: "standard" });
|
|
106
|
+
*/
|
|
107
|
+
export function planOpenNextResources(appName, pattern, options) {
|
|
108
|
+
const { tier = "standard", domain, database, compute, cdn, environment, tags, } = options ?? {};
|
|
109
|
+
const validTier = isPatternTierName(tier);
|
|
110
|
+
if (!validTier && tier !== "custom") {
|
|
111
|
+
return failure(new Error(`Invalid pattern tier: "${tier}". Valid tiers are: lightweight, standard, resilient, custom`));
|
|
112
|
+
}
|
|
113
|
+
if (!isPatternConfigType(pattern)) {
|
|
114
|
+
return failure(new Error(`Unsupported pattern type: ${pattern}`));
|
|
115
|
+
}
|
|
116
|
+
const tierPreset = validTier ? getPatternTierPreset(tier) : null;
|
|
117
|
+
const patternConfig = buildPatternConfig(pattern, appName, {
|
|
118
|
+
domain,
|
|
119
|
+
database,
|
|
120
|
+
compute,
|
|
121
|
+
cdn,
|
|
122
|
+
environment,
|
|
123
|
+
tierPreset,
|
|
124
|
+
});
|
|
125
|
+
if (patternConfig instanceof Error) {
|
|
126
|
+
return failure(patternConfig);
|
|
127
|
+
}
|
|
128
|
+
return success({
|
|
129
|
+
appName,
|
|
130
|
+
type: "standard",
|
|
131
|
+
pattern,
|
|
132
|
+
network: tierPreset ? tierPreset.network : DEFAULT_NETWORK,
|
|
133
|
+
backup: tierPreset ? tierPreset.backup : false,
|
|
134
|
+
patternConfig,
|
|
135
|
+
database: [],
|
|
136
|
+
s3: [],
|
|
137
|
+
compute: [],
|
|
138
|
+
tags: tags ?? {},
|
|
139
|
+
importedResources: [],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function mergeDatabaseConfig(database, tierPreset) {
|
|
143
|
+
return {
|
|
144
|
+
type: database?.type ?? tierPreset.database.type,
|
|
145
|
+
instanceType: database?.instanceType ?? tierPreset.database.instanceType,
|
|
146
|
+
databaseName: database?.databaseName,
|
|
147
|
+
publiclyAccessible: database?.publiclyAccessible,
|
|
148
|
+
allowedIpCidr: database?.allowedIpCidr,
|
|
149
|
+
backupRetention: database?.backupRetention ?? tierPreset.database.backupRetention,
|
|
150
|
+
deletionProtection: database?.deletionProtection ?? tierPreset.database.deletionProtection,
|
|
151
|
+
encryption: database?.encryption,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function mergeComputeConfig(compute, tierPreset) {
|
|
155
|
+
return {
|
|
156
|
+
memorySize: compute?.memorySize ?? tierPreset.compute.memorySize,
|
|
157
|
+
timeout: compute?.timeout ?? tierPreset.compute.timeout,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function toPatternDatabaseConfig(db) {
|
|
161
|
+
const { encryption, ...rest } = db;
|
|
162
|
+
return {
|
|
163
|
+
...rest,
|
|
164
|
+
...(encryption && { encryption: { storageKey: encryption } }),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function buildPatternConfig(type, appName, opts) {
|
|
168
|
+
const { domain, database, compute, cdn, environment, tierPreset } = opts;
|
|
169
|
+
const mergedDatabase = tierPreset
|
|
170
|
+
? mergeDatabaseConfig(database, tierPreset)
|
|
171
|
+
: database;
|
|
172
|
+
const mergedCompute = tierPreset
|
|
173
|
+
? mergeComputeConfig(compute, tierPreset)
|
|
174
|
+
: compute;
|
|
175
|
+
const config = {
|
|
176
|
+
type,
|
|
177
|
+
name: appName,
|
|
178
|
+
domain,
|
|
179
|
+
database: mergedDatabase
|
|
180
|
+
? toPatternDatabaseConfig(mergedDatabase)
|
|
181
|
+
: undefined,
|
|
182
|
+
compute: mergedCompute ? { server: mergedCompute } : undefined,
|
|
183
|
+
cdn: cdn
|
|
184
|
+
? { domainNames: cdn.domainNames, certificateArn: cdn.certificateArn }
|
|
185
|
+
: undefined,
|
|
186
|
+
environment,
|
|
187
|
+
};
|
|
188
|
+
const result = PatternConfigSchema.safeParse(config);
|
|
189
|
+
if (!result.success) {
|
|
190
|
+
return new Error(`Invalid pattern config: ${result.error.message}`);
|
|
191
|
+
}
|
|
192
|
+
return result.data;
|
|
193
|
+
}
|
|
194
|
+
export function generateInfrastructureFromPlan(plan, options) {
|
|
195
|
+
const parts = [
|
|
196
|
+
generateImports(plan),
|
|
197
|
+
generateAppInit(plan),
|
|
198
|
+
generateTags(plan),
|
|
199
|
+
];
|
|
200
|
+
if (usesPatternApproach(plan)) {
|
|
201
|
+
parts.push(generatePatternCodeWithComments(plan), generateNetworkCode(plan));
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const cdnReferencedResources = collectCdnReferencedResources(plan);
|
|
205
|
+
parts.push(generateNetworkCode(plan), generateDatabaseCode(plan), generateS3Code(plan), generateDynamoDBCode(plan), generateSQSCode(plan), generateComputeCode(plan, cdnReferencedResources), generateCDNCode(plan));
|
|
206
|
+
}
|
|
207
|
+
const code = parts.join("");
|
|
208
|
+
if (plan.customCodeBlocks && plan.customCodeBlocks.length > 0) {
|
|
209
|
+
const injectionResult = injectCustomCodeBlocks(code, plan.customCodeBlocks, options?.resourceMapping);
|
|
210
|
+
if (!injectionResult.success) {
|
|
211
|
+
return failure(new Error(`Custom code injection failed: ${injectionResult.error ?? "unknown error"}`));
|
|
212
|
+
}
|
|
213
|
+
return success(injectionResult.content);
|
|
214
|
+
}
|
|
215
|
+
return success(code);
|
|
216
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from "./tierPresets.js";
|
|
2
|
+
export { PATTERN_TIER_NAMES, type PatternTierName, PATTERN_TYPES_WITH_CUSTOM, type PatternTypeWithCustom, type PatternDatabasePreset, type PatternComputePreset, type PatternTierPreset, PATTERN_TIER_PRESETS, getPatternTierPreset, getPatternTierOptions, isPatternTierName, } from "./patternTierPresets.js";
|
|
3
|
+
export { type StoragePreset, STORAGE_PRESETS, getStoragePreset, getStoragePresetOptions, } from "./storagePresets.js";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from "./tierPresets.js";
|
|
2
|
+
export { PATTERN_TIER_NAMES, PATTERN_TYPES_WITH_CUSTOM, PATTERN_TIER_PRESETS, getPatternTierPreset, getPatternTierOptions, isPatternTierName, } from "./patternTierPresets.js";
|
|
3
|
+
export { STORAGE_PRESETS, getStoragePreset, getStoragePresetOptions, } from "./storagePresets.js";
|