@cloudnux/cli 0.11.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.
@@ -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
- initializeLogger("<%=module%>",context.awsRequestId);
58
- logger.info("request started", { requestId: context.awsRequestId });
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
- function_name = "<%= module %>"
18
+ function_name = "<%= namespace %>_<%= module %>"
19
19
  }
20
20
 
21
- data "aws_apigatewayv2_apis" "this" {
22
- tags = {
23
- application = "epf"
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
- <% const httpEntries = Object.entries(entries).filter(([k,e]) => e.trigger.type.toLowerCase() === "http") %>
28
- <% if(httpEntries.length > 0) { %>
29
- module "http_trigger_for_<%= module %>" {
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 = "<%= module %>"
43
+ lambda_name = "<%= namespace %>_<%= module %>"
34
44
  entrypoints = {
35
- <% for(const [key,entry] of httpEntries){ %>
45
+ <%_ for (const [key, entry] of gatewayEntries) { _%>
36
46
  "<%= key %>" = {
37
- description = "<% entry.trigger.options.description %>"
38
- method = "<%= entry.trigger.options.method %>"
39
- path = "<%= entry.trigger.options.route %>"
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
- <% const scheduleEntries = Object.entries(entries).filter(([k,e]) => e.trigger.type.toLowerCase() === "schedule") %>
48
- <% if(scheduleEntries.length > 0) { %>
49
- module "schedule_trigger_for_<%= module %>" {
50
- source = "../.deploy/aws/scheduler"
51
- component = "<%= module %>"
52
- target_arn = data.aws_lambda_function.this.arn
53
- schedules = {
54
- <% for(const [key,entry] of scheduleEntries) { %>
55
- "<%= key %>" = {
56
- name = "<%= key %>"
57
- pattern = "<%= entry.trigger.options.pattern %>"
58
- timezone = "UTC"
59
- state = "DISABLED"
60
- retry_policy = {
61
- maximum_retry_attempts = 3
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
- <%_ const eventEntries = Object.entries(entries).filter(([k,e]) => e.trigger.type.toLowerCase() === "event" && e.trigger.options.sourceType?.toLowerCase() === "sqs") _%>
70
- <% if(eventEntries.length > 0) { %>
71
- module "sqs_trigger_for_<%= module %>" {
72
- source = "../.deploy/aws/sqs"
73
- lambda_name = "<%= module %>"
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 eventEntries) { %>
90
+ <%_ for (const [key, entry] of sqsEntries) { _%>
76
91
  "<%= key %>" = {
77
- queue_name = "<%= entry.trigger.options.source %>"
78
- enabled = true
79
- batch_size = 10
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,21 +1,24 @@
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";
4
5
  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
- import { initializeLogger } from "@cloudnux/utils";
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');
8
11
 
9
12
  useCloudProvider(localCloudProvider);
10
13
 
11
14
  <%_ for(const module of moduleNames){ _%>
12
- import <%=module%>Entries from "./<%=module%>"
15
+ import <%=module%>Entries from "./<%=module%>"
13
16
  <%_ } _%>
14
17
 
15
18
  const router = createRouter({logger : true});
16
19
 
17
- router.register(queuesPlugin, { prefix: "queues" });
18
- 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') } } });
19
22
  router.register(devConsolePlugin, { prefix: 'console' });
20
23
  router.register(websocketsPlugin, { prefix: "websockets" });
21
24
 
@@ -23,16 +26,7 @@ router.register(websocketsPlugin, { prefix: "websockets" });
23
26
  router.register(<%=module%>Entries, { prefix: "api" });
24
27
  <%_ } _%>
25
28
 
26
- router.addHook('onRequest', async (request, reply) => {
27
- const [pathname] = request.url.split('?');
28
- const match = pathname.match(/^\/api\/([^/]+)(?:\/([^/]+))?/);
29
- initializeLogger(match?.[2] || "", request.id);
30
- });
31
- router.addHook('onResponse', async () => {
32
- initializeLogger("default", undefined);
33
- });
34
-
35
- router.listen({ port: 3000, host: "::" }, (err) => {
29
+ router.listen({ port: <%=port%>, host: "::" }, (err) => {
36
30
  if (err) {
37
31
  console.error('Error starting server:', err);
38
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: Task<TTaskParams>[];
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.11.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.11.0",
47
- "@cloudnux/local-cloud-provider": "0.11.0",
48
- "@cloudnux/cloud-sdk": "0.11.0",
49
- "@cloudnux/dev-console": "0.11.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
  },