@cloudnux/cli 0.12.0 → 0.15.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/.deploy/aws/scheduler/main.tf +1 -1
- package/.deploy/aws/scheduler/variables.tf +2 -2
- package/.deploy/aws/websocket/main.tf +49 -0
- package/.deploy/aws/websocket/variables.tf +22 -0
- package/dist/cli.mjs +2841 -370
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +2950 -0
- package/dist/schema/entrypoint.schema.json +16 -3
- package/dist/templates/cloud/entrypoint-build.ts.ejs +4 -18
- package/dist/templates/cloud/entrypoint-triggers.tf.ejs +98 -51
- package/dist/templates/local/dev-server.ts.ejs +8 -4
- package/dist/templates/local/module.ts.ejs +4 -3
- package/dist/types.d.ts +10 -11
- package/package.json +12 -11
- package/dist/templates/cloud/WIP.ts.ejs +0 -564
- package/dist/templates/local/triggers/event.ts.ejs +0 -7
- package/dist/templates/local/triggers/http.ts.ejs +0 -11
- package/dist/templates/local/triggers/schedule.ts.ejs +0 -7
|
@@ -6,11 +6,16 @@
|
|
|
6
6
|
"properties": {
|
|
7
7
|
"entries": {
|
|
8
8
|
"$ref": "#/definitions/Record"
|
|
9
|
+
},
|
|
10
|
+
"includes": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "string"
|
|
14
|
+
},
|
|
15
|
+
"description": "Relative paths to partial entrypoint files whose entries are merged into this one"
|
|
9
16
|
}
|
|
10
17
|
},
|
|
11
|
-
"required": [
|
|
12
|
-
"entries"
|
|
13
|
-
],
|
|
18
|
+
"required": [],
|
|
14
19
|
"definitions": {
|
|
15
20
|
"MethodType": {
|
|
16
21
|
"enum": [
|
|
@@ -32,6 +37,10 @@
|
|
|
32
37
|
},
|
|
33
38
|
"method": {
|
|
34
39
|
"$ref": "#/definitions/MethodType"
|
|
40
|
+
},
|
|
41
|
+
"gateway": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"description": "Tag value used to look up the target AWS API Gateway V2 (HTTP) instance"
|
|
35
44
|
}
|
|
36
45
|
},
|
|
37
46
|
"required": [
|
|
@@ -316,6 +325,10 @@
|
|
|
316
325
|
},
|
|
317
326
|
"routeKey": {
|
|
318
327
|
"type": "string"
|
|
328
|
+
},
|
|
329
|
+
"gateway": {
|
|
330
|
+
"type": "string",
|
|
331
|
+
"description": "Tag value used to look up the target AWS API Gateway V2 (WebSocket) instance"
|
|
319
332
|
}
|
|
320
333
|
},
|
|
321
334
|
"required": [
|
|
@@ -6,8 +6,7 @@ import {
|
|
|
6
6
|
scheduleHandler,
|
|
7
7
|
websocketHandler,
|
|
8
8
|
useCloudProvider,
|
|
9
|
-
} from "@cloudnux/cloud-sdk";
|
|
10
|
-
import { initializeLogger, logger } from "@cloudnux/utils";
|
|
9
|
+
} from "@cloudnux/cloud-sdk";
|
|
11
10
|
|
|
12
11
|
import * as src from "../../../packages/modules/<%=module%>/src";
|
|
13
12
|
|
|
@@ -47,26 +46,13 @@ router.event(
|
|
|
47
46
|
router.websocket(
|
|
48
47
|
"<%= wsRouteKey %>",
|
|
49
48
|
(event, context) => {
|
|
50
|
-
return websocketHandler(src["<%= entry.handler %>"],event,context);
|
|
49
|
+
return websocketHandler(src["<%= entry.handler %>"],event,context, <%- JSON.stringify(entry.trigger, null, 2) %> );
|
|
51
50
|
}
|
|
52
51
|
);
|
|
53
52
|
<%_ } _%>
|
|
54
53
|
<%_ } _%>
|
|
55
54
|
|
|
56
55
|
export async function handler(event, context) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
logger.debug("Received event", { event, requestId: context.awsRequestId });
|
|
60
|
-
let response;
|
|
61
|
-
try {
|
|
62
|
-
response = await router.run(event, context);
|
|
63
|
-
return response;
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
logger.error("Error occurred", { error, requestId: context.awsRequestId });
|
|
67
|
-
throw error;
|
|
68
|
-
}
|
|
69
|
-
finally {
|
|
70
|
-
logger.info("request finished", { response, requestId: context.awsRequestId });
|
|
71
|
-
}
|
|
56
|
+
const response = await router.run(event, context);
|
|
57
|
+
return response;
|
|
72
58
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
terraform {
|
|
2
2
|
backend "s3" {
|
|
3
|
-
key = "<%= module %>/terraform.state"
|
|
4
|
-
workspace_key_prefix = "state/<%= module %>"
|
|
3
|
+
key = "<%= namespace %>_<%= module %>/terraform.state"
|
|
4
|
+
workspace_key_prefix = "state/<%= namespace %>_<%= module %>"
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
required_providers {
|
|
@@ -15,71 +15,118 @@ terraform {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
data "aws_lambda_function" "this" {
|
|
18
|
-
|
|
18
|
+
function_name = "<%= namespace %>_<%= module %>"
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
<%_
|
|
22
|
+
// ── HTTP triggers ────────────────────────────────────────────────────────────
|
|
23
|
+
const httpEntries = Object.entries(entries).filter(([, e]) => e.trigger.type.toLowerCase() === "http");
|
|
24
|
+
const httpByGateway = httpEntries.reduce((acc, entry) => {
|
|
25
|
+
const tag = entry[1].trigger.options.gateway;
|
|
26
|
+
if (tag) { if (!acc[tag]) acc[tag] = []; acc[tag].push(entry); }
|
|
27
|
+
return acc;
|
|
28
|
+
}, {});
|
|
29
|
+
_%>
|
|
30
|
+
<%_ for (const [gatewayTag, gatewayEntries] of Object.entries(httpByGateway)) {
|
|
31
|
+
const safeName = gatewayTag.replace(/[^a-zA-Z0-9]/g, '_');
|
|
32
|
+
_%>
|
|
33
|
+
data "aws_apigatewayv2_apis" "http_<%= safeName %>" {
|
|
34
|
+
tags = {
|
|
35
|
+
Name = "<%= gatewayTag %>"
|
|
36
|
+
}
|
|
25
37
|
}
|
|
26
38
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
source = "../.deploy/aws/http"
|
|
31
|
-
api_gateway_id = sort(data.aws_apigatewayv2_apis.this.ids)[0]
|
|
39
|
+
module "http_trigger_<%= safeName %>_for_<%= namespace %>_<%= module %>" {
|
|
40
|
+
source = "<%= tfModules.http %>"
|
|
41
|
+
api_gateway_id = sort(data.aws_apigatewayv2_apis.http_<%= safeName %>.ids)[0]
|
|
32
42
|
lambda_arn = data.aws_lambda_function.this.arn
|
|
33
|
-
lambda_name =
|
|
43
|
+
lambda_name = "<%= namespace %>_<%= module %>"
|
|
34
44
|
entrypoints = {
|
|
35
|
-
<% for(const [key,entry] of
|
|
45
|
+
<%_ for (const [key, entry] of gatewayEntries) { _%>
|
|
36
46
|
"<%= key %>" = {
|
|
37
|
-
description
|
|
38
|
-
method
|
|
39
|
-
path
|
|
47
|
+
description = ""
|
|
48
|
+
method = "<%= entry.trigger.options.method %>"
|
|
49
|
+
path = "<%= entry.trigger.options.route %>"
|
|
40
50
|
}
|
|
41
|
-
|
|
51
|
+
<%_ } _%>
|
|
42
52
|
}
|
|
43
53
|
}
|
|
54
|
+
<%_ } _%>
|
|
44
55
|
|
|
45
|
-
<%
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
56
|
+
<%_
|
|
57
|
+
// ── Schedule triggers ────────────────────────────────────────────────────────
|
|
58
|
+
const scheduleEntries = Object.entries(entries).filter(([, e]) => e.trigger.type.toLowerCase() === "schedule");
|
|
59
|
+
_%>
|
|
60
|
+
<%_ if (scheduleEntries.length > 0) { _%>
|
|
61
|
+
module "schedule_trigger_for_<%= namespace %>_<%= module %>" {
|
|
62
|
+
source = "<%= tfModules.scheduler %>"
|
|
63
|
+
module = "<%= namespace %>_<%= module %>"
|
|
64
|
+
target_arn = data.aws_lambda_function.this.arn
|
|
65
|
+
schedules = {
|
|
66
|
+
<%_ for (const [key, entry] of scheduleEntries) { _%>
|
|
67
|
+
"<%= key %>" = {
|
|
68
|
+
name = "<%= key %>"
|
|
69
|
+
pattern = "<%= entry.trigger.options.pattern %>"
|
|
70
|
+
timezone = "UTC"
|
|
71
|
+
state = "DISABLED"
|
|
72
|
+
retry_policy = {
|
|
73
|
+
maximum_retry_attempts = 3
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
<%_ } _%>
|
|
77
|
+
}
|
|
66
78
|
}
|
|
67
|
-
<% } %>
|
|
79
|
+
<%_ } _%>
|
|
68
80
|
|
|
69
|
-
<%_
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
<%_
|
|
82
|
+
// ── Event (SQS) triggers ─────────────────────────────────────────────────────
|
|
83
|
+
const sqsEntries = Object.entries(entries).filter(([, e]) => e.trigger.type.toLowerCase() === "event" && e.trigger.options.sourceType?.toLowerCase() === "sqs");
|
|
84
|
+
_%>
|
|
85
|
+
<%_ if (sqsEntries.length > 0) { _%>
|
|
86
|
+
module "sqs_trigger_for_<%= namespace %>_<%= module %>" {
|
|
87
|
+
source = "<%= tfModules.sqs %>"
|
|
88
|
+
lambda_name = "<%= namespace %>_<%= module %>"
|
|
74
89
|
event_sources = {
|
|
75
|
-
<% for(const [key,entry] of
|
|
90
|
+
<%_ for (const [key, entry] of sqsEntries) { _%>
|
|
76
91
|
"<%= key %>" = {
|
|
77
|
-
queue_name
|
|
78
|
-
enabled
|
|
79
|
-
batch_size
|
|
92
|
+
queue_name = "<%= entry.trigger.options.source %>"
|
|
93
|
+
enabled = true
|
|
94
|
+
batch_size = 10
|
|
80
95
|
}
|
|
81
|
-
|
|
96
|
+
<%_ } _%>
|
|
82
97
|
}
|
|
83
98
|
}
|
|
99
|
+
<%_ } _%>
|
|
84
100
|
|
|
85
|
-
<%
|
|
101
|
+
<%_
|
|
102
|
+
// ── WebSocket triggers ───────────────────────────────────────────────────────
|
|
103
|
+
const wsEntries = Object.entries(entries).filter(([, e]) => e.trigger.type.toLowerCase() === "websocket");
|
|
104
|
+
const wsByGateway = wsEntries.reduce((acc, entry) => {
|
|
105
|
+
const tag = entry[1].trigger.options.gateway;
|
|
106
|
+
if (tag) { if (!acc[tag]) acc[tag] = []; acc[tag].push(entry); }
|
|
107
|
+
return acc;
|
|
108
|
+
}, {});
|
|
109
|
+
_%>
|
|
110
|
+
<%_ for (const [gatewayTag, wsGatewayEntries] of Object.entries(wsByGateway)) {
|
|
111
|
+
const safeName = gatewayTag.replace(/[^a-zA-Z0-9]/g, '_');
|
|
112
|
+
_%>
|
|
113
|
+
data "aws_apigatewayv2_apis" "ws_<%= safeName %>" {
|
|
114
|
+
tags = {
|
|
115
|
+
Name = "<%= gatewayTag %>"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module "ws_trigger_<%= safeName %>_for_<%= namespace %>_<%= module %>" {
|
|
120
|
+
source = "<%= tfModules.websocket %>"
|
|
121
|
+
api_gateway_id = sort(data.aws_apigatewayv2_apis.ws_<%= safeName %>.ids)[0]
|
|
122
|
+
lambda_arn = data.aws_lambda_function.this.arn
|
|
123
|
+
lambda_name = "<%= namespace %>_<%= module %>"
|
|
124
|
+
routes = {
|
|
125
|
+
<%_ for (const [key, entry] of wsGatewayEntries) { _%>
|
|
126
|
+
"<%= key %>" = {
|
|
127
|
+
event = "<%= entry.trigger.options.event %>"
|
|
128
|
+
}
|
|
129
|
+
<%_ } _%>
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
<%_ } _%>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
1
2
|
import { useCloudProvider } from "@cloudnux/cloud-sdk";
|
|
2
3
|
import { createRouter, localCloudProvider } from '@cloudnux/local-cloud-provider';
|
|
3
4
|
import { queuesPlugin } from "@cloudnux/local-cloud-provider/queue-plugin";
|
|
@@ -5,16 +6,19 @@ import { schedulerPlugin } from "@cloudnux/local-cloud-provider/schedule-plugin"
|
|
|
5
6
|
import { devConsolePlugin } from "@cloudnux/local-cloud-provider/dev-console-plugin";
|
|
6
7
|
import { websocketsPlugin } from "@cloudnux/local-cloud-provider/websocket-plugin";
|
|
7
8
|
|
|
9
|
+
// __dirname is injected by the esbuild banner and resolves to the workingDir/env folder
|
|
10
|
+
process.env.DEV_CLOUD_LOCATION_PATH ??= path.join(__dirname, '.local-location');
|
|
11
|
+
|
|
8
12
|
useCloudProvider(localCloudProvider);
|
|
9
13
|
|
|
10
14
|
<%_ for(const module of moduleNames){ _%>
|
|
11
|
-
import <%=module%>Entries from "./<%=module%>"
|
|
15
|
+
import <%=module%>Entries from "./<%=module%>"
|
|
12
16
|
<%_ } _%>
|
|
13
17
|
|
|
14
18
|
const router = createRouter({logger : true});
|
|
15
19
|
|
|
16
|
-
router.register(queuesPlugin, { prefix: "queues" });
|
|
17
|
-
router.register(schedulerPlugin, { prefix: "schedules" });
|
|
20
|
+
router.register(queuesPlugin, { prefix: "queues", config: { persistence: { directory: path.join(__dirname, 'queue-data') } } });
|
|
21
|
+
router.register(schedulerPlugin, { prefix: "schedules", config: { persistence: { directory: path.join(__dirname, 'scheduler-data') } } });
|
|
18
22
|
router.register(devConsolePlugin, { prefix: 'console' });
|
|
19
23
|
router.register(websocketsPlugin, { prefix: "websockets" });
|
|
20
24
|
|
|
@@ -22,7 +26,7 @@ router.register(websocketsPlugin, { prefix: "websockets" });
|
|
|
22
26
|
router.register(<%=module%>Entries, { prefix: "api" });
|
|
23
27
|
<%_ } _%>
|
|
24
28
|
|
|
25
|
-
router.listen({ port:
|
|
29
|
+
router.listen({ port: <%=port%>, host: "::" }, (err) => {
|
|
26
30
|
if (err) {
|
|
27
31
|
console.error('Error starting server:', err);
|
|
28
32
|
process.exit(1);
|
|
@@ -41,13 +41,14 @@ async function entries(app: RouterInstance) {
|
|
|
41
41
|
<%_ } _%>
|
|
42
42
|
<%_ if(entry.trigger.type === "websocket") { _%>
|
|
43
43
|
app.websockets.registerHandler({
|
|
44
|
-
path: "<%= entry.trigger.options.path %>",
|
|
44
|
+
path: "<%= $$convertRouteParamstoFastifyRouteTemplate(entry.trigger.options.path) %>",
|
|
45
45
|
event: "<%= entry.trigger.options.event %>",
|
|
46
|
+
module: "<%=module%>",
|
|
46
47
|
<%_ if(entry.trigger.options.route) { _%>
|
|
47
48
|
route: "<%= entry.trigger.options.route %>",
|
|
48
49
|
<%_ } _%>
|
|
49
|
-
handler: async (connectionId, event, data) => {
|
|
50
|
-
return websocketHandler(src["<%= entry.handler %>"], connectionId, event, data);
|
|
50
|
+
handler: async (connectionId, event, data, request, reply) => {
|
|
51
|
+
return websocketHandler(src["<%= entry.handler %>"], connectionId, event, data, request, reply);
|
|
51
52
|
}
|
|
52
53
|
});
|
|
53
54
|
<%_ } _%>
|
package/dist/types.d.ts
CHANGED
|
@@ -22,15 +22,6 @@ type TaskParam = {
|
|
|
22
22
|
* environment name
|
|
23
23
|
*/
|
|
24
24
|
environment: string;
|
|
25
|
-
/**
|
|
26
|
-
* logger function to log messages
|
|
27
|
-
*/
|
|
28
|
-
logger: (arg: any, data?: any) => void;
|
|
29
|
-
/**
|
|
30
|
-
* event emitter function to emit events
|
|
31
|
-
*/
|
|
32
|
-
eventEmitter: (type: string, data?: any) => void;
|
|
33
|
-
children?: Task[];
|
|
34
25
|
[key: string]: any;
|
|
35
26
|
};
|
|
36
27
|
type TaskTitle = string | ((params: TaskParam) => string);
|
|
@@ -38,13 +29,16 @@ type Task<TTaskParams extends TaskParamBase = any> = {
|
|
|
38
29
|
title: string | ((params: TTaskParams) => string);
|
|
39
30
|
action: (params: TTaskParams) => any | Promise<any>;
|
|
40
31
|
skip?: (params: TTaskParams) => boolean;
|
|
32
|
+
};
|
|
33
|
+
type TaskEntry<TTaskParams extends TaskParamBase = any> = {
|
|
34
|
+
task: Task<TTaskParams>;
|
|
41
35
|
children?: Task<TTaskParams>[];
|
|
42
36
|
};
|
|
43
37
|
type Environment<TTaskParams extends TaskParamBase = any> = {
|
|
44
38
|
/**
|
|
45
39
|
* tasks to be executed for this environment
|
|
46
40
|
*/
|
|
47
|
-
tasks:
|
|
41
|
+
tasks: TaskEntry<TTaskParams>[];
|
|
48
42
|
/**
|
|
49
43
|
* watch task
|
|
50
44
|
* if set, task will be executed and all logs will be routed to the watch view.
|
|
@@ -59,6 +53,11 @@ type Environment<TTaskParams extends TaskParamBase = any> = {
|
|
|
59
53
|
[key: string]: any;
|
|
60
54
|
};
|
|
61
55
|
type Config<TTaskParams extends TaskParamBase = any> = {
|
|
56
|
+
/**
|
|
57
|
+
* Namespace prefix for all resources (lambdas, state keys, etc.)
|
|
58
|
+
* @default root package.json `name` field
|
|
59
|
+
*/
|
|
60
|
+
namespace?: string;
|
|
62
61
|
/**
|
|
63
62
|
* glob Path to find all modules (package.json) having entrypoints
|
|
64
63
|
* @default './packages/modules/**\/package.json'
|
|
@@ -162,4 +161,4 @@ interface DevServerStore {
|
|
|
162
161
|
resetSelection: () => void;
|
|
163
162
|
}
|
|
164
163
|
|
|
165
|
-
export type { AppProps, Args, Config, DevServerStore, Environment, Log, Task, TaskManagerStore, TaskParam, TaskParamBase, TaskState, TaskStatus, TaskTitle };
|
|
164
|
+
export type { AppProps, Args, Config, DevServerStore, Environment, Log, Task, TaskEntry, TaskManagerStore, TaskParam, TaskParamBase, TaskState, TaskStatus, TaskTitle };
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudnux/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/cloudnux/cloudnux.git"
|
|
8
|
+
},
|
|
5
9
|
"bin": {
|
|
6
10
|
"nux": "dist/cli.mjs"
|
|
7
11
|
},
|
|
@@ -11,6 +15,10 @@
|
|
|
11
15
|
".": {
|
|
12
16
|
"types": "./dist/types.d.ts",
|
|
13
17
|
"import": "./dist/types.mjs"
|
|
18
|
+
},
|
|
19
|
+
"./defaults": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.mjs"
|
|
14
22
|
}
|
|
15
23
|
},
|
|
16
24
|
"type": "module",
|
|
@@ -33,25 +41,18 @@
|
|
|
33
41
|
"dependencies": {
|
|
34
42
|
"@types/findup-sync": "^4.0.5",
|
|
35
43
|
"ejs": "^3.1.10",
|
|
44
|
+
"esbuild": "0.25.4",
|
|
36
45
|
"fast-glob": "^3.3.2",
|
|
37
|
-
"fastify": "^5.2.1",
|
|
38
|
-
"fastify-raw-body": "^5.0.0",
|
|
39
46
|
"findup-sync": "^5.0.0",
|
|
40
47
|
"interpret": "^3.1.1",
|
|
41
|
-
"jsonwebtoken": "^9.0.2",
|
|
42
48
|
"meow": "^11.0.0",
|
|
43
|
-
"pino-pretty": "^13.0.0",
|
|
44
49
|
"rechoir": "^0.8.0",
|
|
45
|
-
"tsup": "^8.3.5"
|
|
46
|
-
"@cloudnux/aws-cloud-provider": "0.12.0",
|
|
47
|
-
"@cloudnux/local-cloud-provider": "0.12.0",
|
|
48
|
-
"@cloudnux/cloud-sdk": "0.12.0",
|
|
49
|
-
"@cloudnux/dev-console": "0.12.0"
|
|
50
|
+
"tsup": "^8.3.5"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
53
|
+
"@types/node": "^24.10.1",
|
|
52
54
|
"@types/ejs": "^3.1.5",
|
|
53
55
|
"@types/findup-sync": "^4.0.5",
|
|
54
|
-
"@types/jsonwebtoken": "^9.0.7",
|
|
55
56
|
"@types/rechoir": "^0.6.4",
|
|
56
57
|
"typescript": "^5.0.3"
|
|
57
58
|
},
|