@actuallyjamez/elysian 0.11.0 → 0.12.0
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/cli/commands/build.js +172 -87
- package/dist/cli/commands/dev.d.ts +2 -0
- package/dist/cli/commands/dev.js +491 -178
- package/dist/cli/commands/generate-iac.js +23 -23
- package/dist/cli/commands/init/detect.d.ts +3 -3
- package/dist/cli/commands/init/detect.js +4 -4
- package/dist/cli/commands/init/prompts.js +2 -1
- package/dist/cli/commands/init/scaffold.js +55 -93
- package/dist/cli/commands/init/templates.d.ts +9 -1
- package/dist/cli/commands/init/templates.js +28 -4
- package/dist/cli/commands/init/terraform-module.d.ts +76 -0
- package/dist/cli/commands/init/terraform-module.js +1353 -0
- package/dist/cli/commands/init.js +16 -16
- package/dist/cli/logger.d.ts +346 -0
- package/dist/cli/logger.js +968 -0
- package/dist/core/appsync-client.d.ts +5 -0
- package/dist/core/appsync-client.js +9 -2
- package/dist/core/bundler.d.ts +20 -3
- package/dist/core/bundler.js +141 -67
- package/dist/core/config.d.ts +51 -11
- package/dist/core/config.js +59 -17
- package/dist/core/discovery.d.ts +96 -0
- package/dist/core/discovery.js +229 -0
- package/dist/core/handler-wrapper.d.ts +22 -10
- package/dist/core/handler-wrapper.js +44 -45
- package/dist/core/localstack.d.ts +36 -0
- package/dist/core/localstack.js +180 -1
- package/dist/core/manifest.d.ts +51 -2
- package/dist/core/manifest.js +175 -20
- package/dist/core/openapi.d.ts +8 -3
- package/dist/core/openapi.js +24 -14
- package/dist/core/terraform.d.ts +34 -3
- package/dist/core/terraform.js +115 -6
- package/dist/core/worker-runner.d.ts +2 -1
- package/dist/core/worker-runner.js +132 -15
- package/dist/index.d.ts +2 -29
- package/dist/index.js +3 -47
- package/dist/runtime/define-lambda.d.ts +246 -0
- package/dist/runtime/define-lambda.js +140 -0
- package/dist/runtime/define-routes.d.ts +48 -0
- package/dist/runtime/define-routes.js +67 -0
- package/dist/runtime/stub.d.ts +1 -0
- package/dist/runtime/stub.js +44 -26
- package/package.json +6 -2
- package/dist/cli/commands/init/terraform-live.d.ts +0 -27
- package/dist/cli/commands/init/terraform-live.js +0 -140
- package/dist/cli/commands/init/terraform.d.ts +0 -44
- package/dist/cli/commands/init/terraform.js +0 -333
- package/dist/cli/ui.d.ts +0 -114
- package/dist/cli/ui.js +0 -233
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
* Build command - Production build of all lambdas
|
|
3
3
|
*/
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
|
-
import {
|
|
5
|
+
import { mkdirSync, rmSync } from "fs";
|
|
6
6
|
import { join } from "path";
|
|
7
7
|
import { loadConfig } from "../../core/config";
|
|
8
|
-
import {
|
|
8
|
+
import { bundleApiRoute, bundleGenericLambda, } from "../../core/bundler";
|
|
9
9
|
import { packageLambda } from "../../core/packager";
|
|
10
10
|
import { generateManifest, writeManifest } from "../../core/manifest";
|
|
11
11
|
import { writeTerraformVars } from "../../core/terraform";
|
|
12
12
|
import { shouldGenerateOpenApi, writeOpenApiLambda, } from "../../core/openapi";
|
|
13
|
-
import { createWrapperEntry } from "../../core/handler-wrapper";
|
|
13
|
+
import { createWrapperEntry, createGenericLambdaWrapper } from "../../core/handler-wrapper";
|
|
14
14
|
import { getLambdaBundleName } from "../../core/naming";
|
|
15
|
-
import {
|
|
15
|
+
import { discoverLambdas, validateExport, } from "../../core/discovery";
|
|
16
|
+
import { logger, printHeader, printSection, printDivider, printBlank, printLambda, printRoute, formatDuration, formatSize, } from "../logger";
|
|
16
17
|
export const buildCommand = defineCommand({
|
|
17
18
|
meta: {
|
|
18
19
|
name: "build",
|
|
@@ -32,127 +33,211 @@ export const buildCommand = defineCommand({
|
|
|
32
33
|
process.env.NODE_ENV = "production";
|
|
33
34
|
}
|
|
34
35
|
// Header
|
|
35
|
-
|
|
36
|
+
printHeader(args.prod ? "\x1b[33mproduction\x1b[0m" : "development");
|
|
36
37
|
// Load config
|
|
37
38
|
let config;
|
|
38
39
|
try {
|
|
39
40
|
config = await loadConfig();
|
|
40
41
|
}
|
|
41
42
|
catch (error) {
|
|
42
|
-
|
|
43
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
43
44
|
process.exit(1);
|
|
44
45
|
}
|
|
46
|
+
const cwd = process.cwd();
|
|
45
47
|
const name = config.name;
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
// Ensure directories exist
|
|
50
|
-
if (!existsSync(lambdasDir)) {
|
|
51
|
-
ui.error(`Lambdas directory not found: ${lambdasDir}`);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
48
|
+
const outputDir = join(cwd, config.outputDir);
|
|
49
|
+
const terraformDir = join(cwd, config.terraform.outputDir);
|
|
50
|
+
// Ensure output directories exist
|
|
54
51
|
mkdirSync(outputDir, { recursive: true });
|
|
55
52
|
mkdirSync(terraformDir, { recursive: true });
|
|
53
|
+
// Discover lambdas in both directories
|
|
54
|
+
const discovered = await discoverLambdas(cwd, config, (filename, reason) => {
|
|
55
|
+
logger.warn(`Skipping ${filename}: ${reason}`);
|
|
56
|
+
});
|
|
57
|
+
// Check if we have anything to build
|
|
58
|
+
if (discovered.apiRoutes.length === 0 && discovered.functions.length === 0) {
|
|
59
|
+
logger.warn(`No lambda files found in ${config.api.dir} or ${config.functions.dir}`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
56
62
|
// Create temp directory for generated files
|
|
57
63
|
const tempDir = join(outputDir, "__temp__");
|
|
58
64
|
mkdirSync(tempDir, { recursive: true });
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
// Track all build results
|
|
66
|
+
const allBuildResults = [];
|
|
67
|
+
const packageSizes = new Map();
|
|
68
|
+
// =====================
|
|
69
|
+
// Build API Routes
|
|
70
|
+
// =====================
|
|
71
|
+
if (discovered.apiRoutes.length > 0) {
|
|
72
|
+
printSection("API Routes");
|
|
73
|
+
logger.success(`Compiling ${discovered.apiRoutes.length} API routes from ${config.api.dir}...`);
|
|
74
|
+
// Generate OpenAPI aggregator if enabled
|
|
75
|
+
let apiRoutesWithOpenApi = [...discovered.apiRoutes];
|
|
76
|
+
if (shouldGenerateOpenApi(config)) {
|
|
77
|
+
const openApiPath = await writeOpenApiLambda(discovered.apiRoutes, config, tempDir);
|
|
78
|
+
const openApiRoute = {
|
|
79
|
+
name: "openapi",
|
|
80
|
+
sourcePath: openApiPath,
|
|
81
|
+
bundleName: getLambdaBundleName(name, "openapi"),
|
|
82
|
+
};
|
|
83
|
+
apiRoutesWithOpenApi.push(openApiRoute);
|
|
84
|
+
}
|
|
85
|
+
for (const route of apiRoutesWithOpenApi) {
|
|
86
|
+
// Create wrapper entry that imports the original and exports handler
|
|
87
|
+
const wrapperPath = join(tempDir, `${route.name}-wrapper.ts`);
|
|
88
|
+
const wrapperContent = createWrapperEntry(route.sourcePath);
|
|
89
|
+
await Bun.write(wrapperPath, wrapperContent);
|
|
90
|
+
// Bundle the wrapper
|
|
91
|
+
const result = await bundleApiRoute({ ...route, sourcePath: wrapperPath }, outputDir, config);
|
|
92
|
+
allBuildResults.push(result);
|
|
93
|
+
if (!result.success) {
|
|
94
|
+
logger.error(`Failed to build ${route.name}: ${result.error}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Validate exports (skip openapi which is auto-generated)
|
|
99
|
+
for (const route of discovered.apiRoutes) {
|
|
100
|
+
const bundlePath = join(outputDir, `${route.bundleName}.js`);
|
|
101
|
+
const validationError = await validateExport(bundlePath, "routes", route.sourcePath);
|
|
102
|
+
if (validationError) {
|
|
103
|
+
logger.error(validationError.message);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
69
107
|
}
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
108
|
+
// =====================
|
|
109
|
+
// Build Generic Functions
|
|
110
|
+
// =====================
|
|
111
|
+
if (discovered.functions.length > 0) {
|
|
112
|
+
printSection("Generic Functions");
|
|
113
|
+
logger.success(`Compiling ${discovered.functions.length} generic functions from ${config.functions.dir}...`);
|
|
114
|
+
for (const fn of discovered.functions) {
|
|
115
|
+
// Create wrapper that extracts handler from defineLambda export
|
|
116
|
+
const wrapperPath = join(tempDir, `${fn.name}-lambda-wrapper.ts`);
|
|
117
|
+
const wrapperContent = createGenericLambdaWrapper(fn.sourcePath);
|
|
118
|
+
await Bun.write(wrapperPath, wrapperContent);
|
|
119
|
+
// Bundle the wrapper
|
|
120
|
+
const result = await bundleGenericLambda({ ...fn, sourcePath: wrapperPath }, outputDir, config);
|
|
121
|
+
allBuildResults.push(result);
|
|
122
|
+
if (!result.success) {
|
|
123
|
+
logger.error(`Failed to build ${fn.name}: ${result.error}`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Validate exports
|
|
128
|
+
for (const fn of discovered.functions) {
|
|
129
|
+
const bundlePath = join(outputDir, `${fn.bundleName}.js`);
|
|
130
|
+
const validationError = await validateExport(bundlePath, "lambda", fn.sourcePath);
|
|
131
|
+
if (validationError) {
|
|
132
|
+
logger.error(validationError.message);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
90
135
|
}
|
|
91
136
|
}
|
|
92
137
|
// Clean up temp directory
|
|
93
138
|
rmSync(tempDir, { recursive: true, force: true });
|
|
94
|
-
//
|
|
95
|
-
// Package
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
139
|
+
// =====================
|
|
140
|
+
// Package Phase
|
|
141
|
+
// =====================
|
|
142
|
+
printSection("Packaging");
|
|
143
|
+
logger.success("Packaging lambdas...");
|
|
144
|
+
for (const result of allBuildResults) {
|
|
145
|
+
if (!result.success)
|
|
146
|
+
continue;
|
|
147
|
+
const jsPath = join(outputDir, `${result.bundleName}.js`);
|
|
148
|
+
const packageResult = await packageLambda(result.bundleName, jsPath, outputDir);
|
|
149
|
+
if (!packageResult.success) {
|
|
150
|
+
logger.error(`Failed to package ${result.name}: ${packageResult.error}`);
|
|
105
151
|
process.exit(1);
|
|
106
152
|
}
|
|
107
|
-
// Get zip size
|
|
108
|
-
const zipPath = join(outputDir, `${bundleName}.zip`);
|
|
153
|
+
// Get zip size
|
|
154
|
+
const zipPath = join(outputDir, `${result.bundleName}.zip`);
|
|
109
155
|
const stat = await Bun.file(zipPath).stat();
|
|
110
156
|
if (stat) {
|
|
111
|
-
packageSizes.set(
|
|
157
|
+
packageSizes.set(result.name, stat.size);
|
|
112
158
|
}
|
|
113
159
|
}
|
|
114
|
-
//
|
|
115
|
-
|
|
160
|
+
// =====================
|
|
161
|
+
// Generate Manifest
|
|
162
|
+
// =====================
|
|
163
|
+
printSection("Manifest");
|
|
164
|
+
logger.success("Generating manifest...");
|
|
116
165
|
try {
|
|
117
|
-
const manifest = await generateManifest(
|
|
166
|
+
const manifest = await generateManifest(discovered.apiRoutes, discovered.functions, outputDir, config.api.openapi.enabled, name);
|
|
118
167
|
// Write JSON manifest
|
|
119
168
|
const manifestPath = join(outputDir, "manifest.json");
|
|
120
169
|
await writeManifest(manifest, manifestPath);
|
|
121
|
-
// Write Terraform variables
|
|
170
|
+
// Write Terraform variables (both files)
|
|
122
171
|
await writeTerraformVars(manifest, config);
|
|
123
172
|
// Duration
|
|
124
173
|
const duration = Date.now() - startTime;
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
174
|
+
// =====================
|
|
175
|
+
// Output Summary
|
|
176
|
+
// =====================
|
|
177
|
+
// API Routes table
|
|
178
|
+
if (manifest.routes.length > 0) {
|
|
179
|
+
printSection("API Routes");
|
|
180
|
+
// Group routes by lambda
|
|
181
|
+
const routesByLambda = new Map();
|
|
182
|
+
for (const route of manifest.routes) {
|
|
183
|
+
const displayName = route.lambda.startsWith(`${name}-`)
|
|
184
|
+
? route.lambda.slice(name.length + 1)
|
|
185
|
+
: route.lambda;
|
|
186
|
+
const existing = routesByLambda.get(displayName) || [];
|
|
187
|
+
existing.push(route);
|
|
188
|
+
routesByLambda.set(displayName, existing);
|
|
189
|
+
}
|
|
190
|
+
const maxPathLen = Math.max(...manifest.routes.map((r) => r.path.length));
|
|
191
|
+
for (const [displayName, routes] of routesByLambda) {
|
|
192
|
+
const size = packageSizes.get(displayName);
|
|
193
|
+
const sizeStr = size ? formatSize(size) : undefined;
|
|
194
|
+
printLambda(displayName, sizeStr);
|
|
195
|
+
for (const route of routes) {
|
|
196
|
+
printRoute(route.method, route.path, route.pathParameters, maxPathLen);
|
|
197
|
+
}
|
|
198
|
+
printBlank();
|
|
199
|
+
}
|
|
137
200
|
}
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
201
|
+
// Generic Lambdas table
|
|
202
|
+
if (manifest.genericLambdas.length > 0) {
|
|
203
|
+
printSection("Functions");
|
|
204
|
+
for (const lambda of manifest.genericLambdas) {
|
|
205
|
+
const size = packageSizes.get(lambda.name);
|
|
206
|
+
const sizeStr = size ? formatSize(size) : undefined;
|
|
207
|
+
let triggerStr;
|
|
208
|
+
if (lambda.trigger?.type) {
|
|
209
|
+
const triggerType = lambda.trigger.type;
|
|
210
|
+
// Show schedule duration if available
|
|
211
|
+
if (triggerType === "schedule" && lambda.trigger.config && "every" in lambda.trigger.config) {
|
|
212
|
+
triggerStr = `\x1b[90m[${triggerType}: ${lambda.trigger.config.every}]\x1b[0m`;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
triggerStr = `\x1b[90m[${triggerType}]\x1b[0m`;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
triggerStr = "\x1b[90m[manual]\x1b[0m";
|
|
220
|
+
}
|
|
221
|
+
printLambda(`${lambda.name} ${triggerStr}`, sizeStr);
|
|
146
222
|
}
|
|
147
|
-
|
|
223
|
+
printBlank();
|
|
148
224
|
}
|
|
149
225
|
// Summary footer
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
226
|
+
printDivider();
|
|
227
|
+
const totalLambdas = manifest.lambdas.length + manifest.genericLambdas.length;
|
|
228
|
+
const routeCount = manifest.routes.length;
|
|
229
|
+
const parts = [];
|
|
230
|
+
if (manifest.lambdas.length > 0) {
|
|
231
|
+
parts.push(`${manifest.lambdas.length} API routes`);
|
|
232
|
+
}
|
|
233
|
+
if (manifest.genericLambdas.length > 0) {
|
|
234
|
+
parts.push(`${manifest.genericLambdas.length} functions`);
|
|
235
|
+
}
|
|
236
|
+
logger.success(`Compiled \x1b[1m${totalLambdas}\x1b[0m lambdas (${parts.join(", ")}) in \x1b[1m${formatDuration(duration)}\x1b[0m`);
|
|
237
|
+
printBlank();
|
|
153
238
|
}
|
|
154
239
|
catch (error) {
|
|
155
|
-
|
|
240
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
156
241
|
process.exit(1);
|
|
157
242
|
}
|
|
158
243
|
},
|