@actuallyjamez/elysian 0.3.0 → 0.5.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/README.md +143 -50
- package/dist/cli/commands/build.js +6 -6
- package/dist/cli/commands/dev.js +2 -2
- package/dist/cli/commands/generate-iac.js +3 -3
- package/dist/cli/commands/init/detect.d.ts +33 -0
- package/dist/cli/commands/init/detect.js +98 -0
- package/dist/cli/commands/init/index.d.ts +6 -0
- package/dist/cli/commands/init/index.js +6 -0
- package/dist/cli/commands/init/prompts.d.ts +23 -0
- package/dist/cli/commands/init/prompts.js +95 -0
- package/dist/cli/commands/init/scaffold.d.ts +26 -0
- package/dist/cli/commands/init/scaffold.js +196 -0
- package/dist/cli/commands/init/templates.d.ts +23 -0
- package/dist/cli/commands/init/templates.js +99 -0
- package/dist/cli/commands/init/terraform.d.ts +44 -0
- package/dist/cli/commands/init/terraform.js +309 -0
- package/dist/cli/commands/init.d.ts +1 -6
- package/dist/cli/commands/init.js +79 -268
- package/dist/core/config.d.ts +6 -6
- package/dist/core/config.js +22 -8
- package/dist/core/manifest.d.ts +1 -1
- package/dist/core/manifest.js +5 -5
- package/dist/core/naming.d.ts +7 -6
- package/dist/core/naming.js +9 -8
- package/package.json +1 -1
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Init command -
|
|
2
|
+
* Init command - Interactive wizard to initialize elysian projects
|
|
3
3
|
*/
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import consola from "consola";
|
|
6
|
+
import pc from "picocolors";
|
|
6
7
|
import { existsSync, mkdirSync } from "fs";
|
|
7
|
-
import {
|
|
8
|
+
import { resolve, basename } from "path";
|
|
9
|
+
import { detectProject, } from "./init/detect";
|
|
10
|
+
import { promptTargetDirectory, runFreshProjectWizard, runExistingProjectWizard, } from "./init/prompts";
|
|
11
|
+
import { scaffoldProject, installDependencies, printResults, } from "./init/scaffold";
|
|
8
12
|
export const initCommand = defineCommand({
|
|
9
13
|
meta: {
|
|
10
14
|
name: "init",
|
|
11
15
|
description: "Initialize a new elysian project",
|
|
12
16
|
},
|
|
13
17
|
args: {
|
|
14
|
-
name: {
|
|
15
|
-
type: "string",
|
|
16
|
-
description: "API name",
|
|
17
|
-
default: "my-api",
|
|
18
|
-
},
|
|
19
18
|
force: {
|
|
20
19
|
type: "boolean",
|
|
21
20
|
description: "Overwrite existing files",
|
|
@@ -23,273 +22,85 @@ export const initCommand = defineCommand({
|
|
|
23
22
|
},
|
|
24
23
|
},
|
|
25
24
|
async run({ args }) {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
const originalCwd = process.cwd();
|
|
26
|
+
// Step 1: Get target directory
|
|
27
|
+
const targetDir = await promptTargetDirectory(basename(originalCwd));
|
|
28
|
+
if (!targetDir) {
|
|
29
|
+
consola.info("Cancelled");
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
// Resolve the target directory
|
|
33
|
+
const cwd = resolve(originalCwd, targetDir);
|
|
34
|
+
const name = basename(cwd);
|
|
35
|
+
// Create directory if it doesn't exist
|
|
36
|
+
if (!existsSync(cwd)) {
|
|
37
|
+
mkdirSync(cwd, { recursive: true });
|
|
38
|
+
consola.success(`Created directory: ${targetDir}`);
|
|
39
|
+
}
|
|
40
|
+
// Detect project state in target directory
|
|
41
|
+
const info = await detectProject(cwd);
|
|
42
|
+
// Check for existing config (unless force)
|
|
43
|
+
if (info.hasElysianConfig && !args.force) {
|
|
32
44
|
consola.error("elysian.config.ts already exists. Use --force to overwrite.");
|
|
33
45
|
process.exit(1);
|
|
34
46
|
}
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
version: "1.0.0",
|
|
59
|
-
description: "API powered by Elysia and AWS Lambda",
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
// Terraform configuration
|
|
63
|
-
terraform: {
|
|
64
|
-
outputDir: "terraform",
|
|
65
|
-
tfvarsFilename: "api-routes.auto.tfvars",
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
// Lambda defaults
|
|
69
|
-
lambda: {
|
|
70
|
-
runtime: "nodejs20.x",
|
|
71
|
-
memorySize: 256,
|
|
72
|
-
timeout: 30,
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
`;
|
|
76
|
-
await Bun.write(configPath, configContent);
|
|
77
|
-
consola.success("Created elysian.config.ts");
|
|
78
|
-
// Write example lambda
|
|
79
|
-
const exampleLambdaPath = join(lambdasDir, "hello.ts");
|
|
80
|
-
if (!existsSync(exampleLambdaPath) || args.force) {
|
|
81
|
-
const exampleLambdaContent = `import { createLambda, t } from "@actuallyjamez/elysian";
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Example Lambda - Hello World
|
|
85
|
-
*
|
|
86
|
-
* Routes defined here will be automatically:
|
|
87
|
-
* - Bundled into a Lambda function
|
|
88
|
-
* - Mapped to API Gateway routes
|
|
89
|
-
* - Included in OpenAPI documentation
|
|
90
|
-
*/
|
|
91
|
-
export default createLambda()
|
|
92
|
-
.get("/hello", ({ query }) => {
|
|
93
|
-
return \`Hello, \${query.name ?? "World"}!\`;
|
|
94
|
-
}, {
|
|
95
|
-
response: t.String(),
|
|
96
|
-
query: t.Object({
|
|
97
|
-
name: t.Optional(t.String()),
|
|
98
|
-
}),
|
|
99
|
-
detail: {
|
|
100
|
-
summary: "Say hello",
|
|
101
|
-
description: "Returns a greeting message",
|
|
102
|
-
tags: ["Greeting"],
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
`;
|
|
106
|
-
await Bun.write(exampleLambdaPath, exampleLambdaContent);
|
|
107
|
-
consola.success("Created src/lambdas/hello.ts");
|
|
47
|
+
// Run appropriate wizard based on whether directory is empty
|
|
48
|
+
let answers;
|
|
49
|
+
if (info.isEmpty) {
|
|
50
|
+
const result = await runFreshProjectWizard(name);
|
|
51
|
+
if (!result) {
|
|
52
|
+
consola.info("Cancelled");
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
answers = {
|
|
56
|
+
targetDir,
|
|
57
|
+
...result,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const result = await runExistingProjectWizard(name, info.packageManager);
|
|
62
|
+
if (!result) {
|
|
63
|
+
consola.info("Cancelled");
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
answers = {
|
|
67
|
+
targetDir,
|
|
68
|
+
...result,
|
|
69
|
+
};
|
|
108
70
|
}
|
|
109
|
-
//
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
region = var.region
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
variable "region" {
|
|
126
|
-
type = string
|
|
127
|
-
default = "eu-west-2"
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
variable "lambda_names" {
|
|
131
|
-
type = list(string)
|
|
132
|
-
default = []
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
variable "api_routes" {
|
|
136
|
-
type = map(object({
|
|
137
|
-
lambda_key = string
|
|
138
|
-
route_key = string
|
|
139
|
-
path_parameters = list(string)
|
|
140
|
-
}))
|
|
141
|
-
default = {}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
variable "lambda_runtime" {
|
|
145
|
-
type = string
|
|
146
|
-
default = "nodejs20.x"
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
variable "lambda_memory_size" {
|
|
150
|
-
type = number
|
|
151
|
-
default = 256
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
variable "lambda_timeout" {
|
|
155
|
-
type = number
|
|
156
|
-
default = 30
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
variable "api_name" {
|
|
160
|
-
type = string
|
|
161
|
-
default = "${apiName}"
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
variable "tags" {
|
|
165
|
-
type = map(string)
|
|
166
|
-
default = {}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
locals {
|
|
170
|
-
lambda_functions = {
|
|
171
|
-
for name in var.lambda_names : name => {
|
|
172
|
-
filename = "\${path.module}/../dist/\${name}.zip"
|
|
173
|
-
handler = "index.handler"
|
|
174
|
-
source_code_hash = filebase64sha256("\${path.module}/../dist/\${name}.zip")
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
# API Gateway
|
|
180
|
-
resource "aws_apigatewayv2_api" "this" {
|
|
181
|
-
name = var.api_name
|
|
182
|
-
protocol_type = "HTTP"
|
|
183
|
-
description = "API Gateway for \${var.api_name}"
|
|
184
|
-
tags = var.tags
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
# IAM Role for Lambda
|
|
188
|
-
resource "aws_iam_role" "lambda" {
|
|
189
|
-
name = "\${var.api_name}-lambda-role"
|
|
190
|
-
|
|
191
|
-
assume_role_policy = jsonencode({
|
|
192
|
-
Version = "2012-10-17"
|
|
193
|
-
Statement = [{
|
|
194
|
-
Action = "sts:AssumeRole"
|
|
195
|
-
Effect = "Allow"
|
|
196
|
-
Principal = {
|
|
197
|
-
Service = "lambda.amazonaws.com"
|
|
198
|
-
}
|
|
199
|
-
}]
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
tags = var.tags
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
resource "aws_iam_role_policy_attachment" "lambda_basic" {
|
|
206
|
-
role = aws_iam_role.lambda.name
|
|
207
|
-
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
# Lambda Functions
|
|
211
|
-
resource "aws_lambda_function" "this" {
|
|
212
|
-
for_each = local.lambda_functions
|
|
213
|
-
|
|
214
|
-
filename = each.value.filename
|
|
215
|
-
function_name = "\${var.api_name}-\${each.key}"
|
|
216
|
-
role = aws_iam_role.lambda.arn
|
|
217
|
-
handler = each.value.handler
|
|
218
|
-
source_code_hash = each.value.source_code_hash
|
|
219
|
-
runtime = var.lambda_runtime
|
|
220
|
-
memory_size = var.lambda_memory_size
|
|
221
|
-
timeout = var.lambda_timeout
|
|
222
|
-
|
|
223
|
-
tags = var.tags
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
# API Gateway Integrations
|
|
227
|
-
resource "aws_apigatewayv2_integration" "this" {
|
|
228
|
-
for_each = local.lambda_functions
|
|
229
|
-
|
|
230
|
-
api_id = aws_apigatewayv2_api.this.id
|
|
231
|
-
integration_type = "AWS_PROXY"
|
|
232
|
-
integration_uri = aws_lambda_function.this[each.key].invoke_arn
|
|
233
|
-
integration_method = "POST"
|
|
234
|
-
payload_format_version = "2.0"
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
# Lambda Permissions
|
|
238
|
-
resource "aws_lambda_permission" "apigateway" {
|
|
239
|
-
for_each = local.lambda_functions
|
|
240
|
-
|
|
241
|
-
statement_id = "AllowExecutionFromAPIGateway-\${each.key}"
|
|
242
|
-
action = "lambda:InvokeFunction"
|
|
243
|
-
function_name = aws_lambda_function.this[each.key].function_name
|
|
244
|
-
principal = "apigateway.amazonaws.com"
|
|
245
|
-
source_arn = "\${aws_apigatewayv2_api.this.execution_arn}/*/*"
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
# API Gateway Routes
|
|
249
|
-
resource "aws_apigatewayv2_route" "this" {
|
|
250
|
-
for_each = var.api_routes
|
|
251
|
-
|
|
252
|
-
api_id = aws_apigatewayv2_api.this.id
|
|
253
|
-
route_key = each.value.route_key
|
|
254
|
-
target = "integrations/\${aws_apigatewayv2_integration.this[each.value.lambda_key].id}"
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
# API Gateway Stage
|
|
258
|
-
resource "aws_apigatewayv2_stage" "this" {
|
|
259
|
-
api_id = aws_apigatewayv2_api.this.id
|
|
260
|
-
name = "$default"
|
|
261
|
-
auto_deploy = true
|
|
262
|
-
|
|
263
|
-
tags = var.tags
|
|
264
|
-
|
|
265
|
-
depends_on = [
|
|
266
|
-
aws_apigatewayv2_route.this,
|
|
267
|
-
aws_lambda_permission.apigateway
|
|
268
|
-
]
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
# Outputs
|
|
272
|
-
output "api_endpoint" {
|
|
273
|
-
value = aws_apigatewayv2_stage.this.invoke_url
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
output "lambda_functions" {
|
|
277
|
-
value = { for k, v in aws_lambda_function.this : k => v.arn }
|
|
278
|
-
}
|
|
279
|
-
`;
|
|
280
|
-
await Bun.write(terraformMainPath, terraformContent);
|
|
281
|
-
consola.success("Created terraform/main.tf");
|
|
71
|
+
// Scaffold files
|
|
72
|
+
const scaffoldResult = await scaffoldProject(cwd, info, answers, args.force);
|
|
73
|
+
// Print results
|
|
74
|
+
printResults(cwd, scaffoldResult);
|
|
75
|
+
// Install dependencies if requested
|
|
76
|
+
if (answers.installDeps) {
|
|
77
|
+
try {
|
|
78
|
+
await installDependencies(cwd, answers.packageManager);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
consola.error(error instanceof Error ? error.message : "Failed to install dependencies");
|
|
82
|
+
consola.info(`You can manually install with: ${answers.packageManager} add elysia @actuallyjamez/elysian`);
|
|
83
|
+
}
|
|
282
84
|
}
|
|
283
85
|
// Print next steps
|
|
284
86
|
console.log("");
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
87
|
+
const pm = answers.packageManager;
|
|
88
|
+
const runCmd = pm === "npm" ? "npm run" : pm;
|
|
89
|
+
// If we created in a subdirectory, tell user to cd into it
|
|
90
|
+
const cdStep = targetDir !== "." ? `cd ${targetDir}\n\n` : "";
|
|
91
|
+
console.log(` ${pc.green("✓")} Project initialized!`);
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(` ${pc.bold("Next steps")}:`);
|
|
94
|
+
console.log();
|
|
95
|
+
if (cdStep) {
|
|
96
|
+
console.log(` ${cdStep}`);
|
|
97
|
+
}
|
|
98
|
+
if (!answers.installDeps) {
|
|
99
|
+
console.log(` ${pm} add elysia @actuallyjamez/elysian`);
|
|
100
|
+
console.log();
|
|
101
|
+
}
|
|
102
|
+
console.log(` ${runCmd} elysian build`);
|
|
103
|
+
console.log();
|
|
104
|
+
console.log(` cd terraform && terraform init && terraform apply`);
|
|
294
105
|
},
|
|
295
106
|
});
|
package/dist/core/config.d.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
export interface OpenAPIConfig {
|
|
5
5
|
/** Enable OpenAPI auto-aggregation (default: true) */
|
|
6
6
|
enabled?: boolean;
|
|
7
|
-
/** API title for OpenAPI spec */
|
|
7
|
+
/** API title for OpenAPI spec (defaults to name if not provided) */
|
|
8
8
|
title?: string;
|
|
9
|
-
/** API version for OpenAPI spec */
|
|
9
|
+
/** API version for OpenAPI spec (defaults to package.json version if not provided) */
|
|
10
10
|
version?: string;
|
|
11
11
|
/** API description for OpenAPI spec */
|
|
12
12
|
description?: string;
|
|
@@ -20,7 +20,7 @@ export interface BuildConfig {
|
|
|
20
20
|
external?: string[];
|
|
21
21
|
}
|
|
22
22
|
export interface LambdaConfig {
|
|
23
|
-
/** Lambda runtime (default: "
|
|
23
|
+
/** Lambda runtime (default: "nodejs22.x") */
|
|
24
24
|
runtime?: string;
|
|
25
25
|
/** Lambda memory size in MB (default: 256) */
|
|
26
26
|
memorySize?: number;
|
|
@@ -35,7 +35,7 @@ export interface TerraformConfig {
|
|
|
35
35
|
}
|
|
36
36
|
export interface ElysianConfig {
|
|
37
37
|
/** Name of the API (used for resource naming) */
|
|
38
|
-
|
|
38
|
+
name: string;
|
|
39
39
|
/** Directory containing lambda files (default: "src/lambdas") */
|
|
40
40
|
lambdasDir?: string;
|
|
41
41
|
/** Output directory for built lambdas (default: "dist") */
|
|
@@ -50,7 +50,7 @@ export interface ElysianConfig {
|
|
|
50
50
|
terraform?: TerraformConfig;
|
|
51
51
|
}
|
|
52
52
|
export interface ResolvedConfig {
|
|
53
|
-
|
|
53
|
+
name: string;
|
|
54
54
|
lambdasDir: string;
|
|
55
55
|
outputDir: string;
|
|
56
56
|
openapi: Required<OpenAPIConfig>;
|
|
@@ -65,7 +65,7 @@ export declare function defineConfig(config: ElysianConfig): ElysianConfig;
|
|
|
65
65
|
/**
|
|
66
66
|
* Resolve configuration with defaults applied
|
|
67
67
|
*/
|
|
68
|
-
export declare function resolveConfig(config: ElysianConfig): ResolvedConfig
|
|
68
|
+
export declare function resolveConfig(config: ElysianConfig, cwd: string): Promise<ResolvedConfig>;
|
|
69
69
|
/**
|
|
70
70
|
* Load configuration from elysian.config.ts
|
|
71
71
|
*/
|
package/dist/core/config.js
CHANGED
|
@@ -16,7 +16,7 @@ const DEFAULT_CONFIG = {
|
|
|
16
16
|
external: ["@aws-sdk/*"],
|
|
17
17
|
},
|
|
18
18
|
lambda: {
|
|
19
|
-
runtime: "
|
|
19
|
+
runtime: "nodejs22.x",
|
|
20
20
|
memorySize: 256,
|
|
21
21
|
timeout: 30,
|
|
22
22
|
},
|
|
@@ -25,6 +25,19 @@ const DEFAULT_CONFIG = {
|
|
|
25
25
|
tfvarsFilename: "api-routes.auto.tfvars",
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Read version from package.json
|
|
30
|
+
*/
|
|
31
|
+
async function readPackageVersion(cwd) {
|
|
32
|
+
const packagePath = `${cwd}/package.json`;
|
|
33
|
+
try {
|
|
34
|
+
const content = await Bun.file(packagePath).json();
|
|
35
|
+
return content.version || null;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
28
41
|
/**
|
|
29
42
|
* Define configuration with type safety and defaults
|
|
30
43
|
*/
|
|
@@ -34,15 +47,16 @@ export function defineConfig(config) {
|
|
|
34
47
|
/**
|
|
35
48
|
* Resolve configuration with defaults applied
|
|
36
49
|
*/
|
|
37
|
-
export function resolveConfig(config) {
|
|
50
|
+
export async function resolveConfig(config, cwd) {
|
|
51
|
+
const pkgVersion = await readPackageVersion(cwd);
|
|
38
52
|
return {
|
|
39
|
-
|
|
53
|
+
name: config.name,
|
|
40
54
|
lambdasDir: config.lambdasDir ?? DEFAULT_CONFIG.lambdasDir,
|
|
41
55
|
outputDir: config.outputDir ?? DEFAULT_CONFIG.outputDir,
|
|
42
56
|
openapi: {
|
|
43
57
|
enabled: config.openapi?.enabled ?? DEFAULT_CONFIG.openapi.enabled,
|
|
44
|
-
title: config.openapi?.title ??
|
|
45
|
-
version: config.openapi?.version ?? DEFAULT_CONFIG.openapi.version,
|
|
58
|
+
title: config.openapi?.title ?? config.name,
|
|
59
|
+
version: config.openapi?.version ?? pkgVersion ?? DEFAULT_CONFIG.openapi.version,
|
|
46
60
|
description: config.openapi?.description ?? DEFAULT_CONFIG.openapi.description,
|
|
47
61
|
},
|
|
48
62
|
build: {
|
|
@@ -70,10 +84,10 @@ export async function loadConfig(cwd = process.cwd()) {
|
|
|
70
84
|
try {
|
|
71
85
|
const configModule = await import(configPath);
|
|
72
86
|
const config = configModule.default;
|
|
73
|
-
if (!config.
|
|
74
|
-
throw new Error("
|
|
87
|
+
if (!config.name) {
|
|
88
|
+
throw new Error("name is required in elysian.config.ts");
|
|
75
89
|
}
|
|
76
|
-
return resolveConfig(config);
|
|
90
|
+
return resolveConfig(config, cwd);
|
|
77
91
|
}
|
|
78
92
|
catch (error) {
|
|
79
93
|
if (error.code === "ERR_MODULE_NOT_FOUND") {
|
package/dist/core/manifest.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export declare function generateRouteName(lambda: string, method: string, path:
|
|
|
36
36
|
/**
|
|
37
37
|
* Generate manifest by introspecting built lambda modules
|
|
38
38
|
*/
|
|
39
|
-
export declare function generateManifest(lambdaFiles: string[], outputDir: string, openapiEnabled?: boolean,
|
|
39
|
+
export declare function generateManifest(lambdaFiles: string[], outputDir: string, openapiEnabled?: boolean, name?: string): Promise<ApiManifest>;
|
|
40
40
|
/**
|
|
41
41
|
* Write manifest to JSON file
|
|
42
42
|
*/
|
package/dist/core/manifest.js
CHANGED
|
@@ -31,7 +31,7 @@ export function generateRouteName(lambda, method, path) {
|
|
|
31
31
|
/**
|
|
32
32
|
* Generate manifest by introspecting built lambda modules
|
|
33
33
|
*/
|
|
34
|
-
export async function generateManifest(lambdaFiles, outputDir, openapiEnabled = true,
|
|
34
|
+
export async function generateManifest(lambdaFiles, outputDir, openapiEnabled = true, name = "") {
|
|
35
35
|
const manifest = {
|
|
36
36
|
lambdas: [],
|
|
37
37
|
routes: [],
|
|
@@ -43,7 +43,7 @@ export async function generateManifest(lambdaFiles, outputDir, openapiEnabled =
|
|
|
43
43
|
for (const file of sortedFiles) {
|
|
44
44
|
const originalName = file.replace(/\.ts$/, "");
|
|
45
45
|
// Use prefixed bundle name for file lookup
|
|
46
|
-
const bundleName =
|
|
46
|
+
const bundleName = name ? getLambdaBundleName(name, originalName) : originalName;
|
|
47
47
|
const modulePath = isAbsolute(outputDir)
|
|
48
48
|
? join(outputDir, `${bundleName}.js`)
|
|
49
49
|
: join(process.cwd(), outputDir, `${bundleName}.js`);
|
|
@@ -71,12 +71,12 @@ export async function generateManifest(lambdaFiles, outputDir, openapiEnabled =
|
|
|
71
71
|
});
|
|
72
72
|
// Determine which lambda should handle this route
|
|
73
73
|
let targetLambda = bundleName;
|
|
74
|
-
// OpenAPI routes always go to
|
|
74
|
+
// OpenAPI routes always go to __openapi__ lambda if enabled
|
|
75
75
|
if (openapiEnabled && path.startsWith("/openapi")) {
|
|
76
|
-
targetLambda =
|
|
76
|
+
targetLambda = name ? getLambdaBundleName(name, "__openapi__") : "__openapi__";
|
|
77
77
|
}
|
|
78
78
|
else if (originalName === "__openapi__") {
|
|
79
|
-
// Skip non-openapi routes from
|
|
79
|
+
// Skip non-openapi routes from openapi aggregator lambda
|
|
80
80
|
continue;
|
|
81
81
|
}
|
|
82
82
|
// Check for route conflicts
|
package/dist/core/naming.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Lambda naming utilities
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Generate
|
|
6
|
-
* Format: {
|
|
5
|
+
* Generate Lambda bundle name with API name prefix
|
|
6
|
+
* Format: {name}-{lambdaName}
|
|
7
7
|
*/
|
|
8
|
-
export declare function getLambdaBundleName(
|
|
8
|
+
export declare function getLambdaBundleName(name: string, lambdaName: string): string;
|
|
9
9
|
/**
|
|
10
|
-
* Extract
|
|
10
|
+
* Extract original lambda name from bundle name
|
|
11
|
+
* Reverses getLambdaBundleName()
|
|
11
12
|
*/
|
|
12
|
-
export declare function getOriginalLambdaName(
|
|
13
|
+
export declare function getOriginalLambdaName(name: string, bundleName: string): string;
|
package/dist/core/naming.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Lambda naming utilities
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Generate
|
|
6
|
-
* Format: {
|
|
5
|
+
* Generate Lambda bundle name with API name prefix
|
|
6
|
+
* Format: {name}-{lambdaName}
|
|
7
7
|
*/
|
|
8
|
-
export function getLambdaBundleName(
|
|
9
|
-
return `${
|
|
8
|
+
export function getLambdaBundleName(name, lambdaName) {
|
|
9
|
+
return `${name}-${lambdaName}`;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* Extract
|
|
12
|
+
* Extract original lambda name from bundle name
|
|
13
|
+
* Reverses getLambdaBundleName()
|
|
13
14
|
*/
|
|
14
|
-
export function getOriginalLambdaName(
|
|
15
|
-
const prefix = `${
|
|
15
|
+
export function getOriginalLambdaName(name, bundleName) {
|
|
16
|
+
const prefix = `${name}-`;
|
|
16
17
|
if (bundleName.startsWith(prefix)) {
|
|
17
18
|
return bundleName.slice(prefix.length);
|
|
18
19
|
}
|