@cloudnux/cli 0.1.0 → 0.11.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.
@@ -1,75 +1,55 @@
1
1
  <%# Template generated from a single entrypoint
2
2
  input:
3
3
  - source : the main export of the package
4
+ - module : the module (package) name
4
5
  - config: the full entrypoint object
5
6
  %>
6
- import { AddressInfo } from "node:net";
7
- import querystring from "node:querystring";
8
- import jwt from "jsonwebtoken";
9
-
10
- import { FastifyInstance } from "fastify";
11
-
12
- import {
13
- HTTPAuth,
14
- HttpMethod,
15
- createHttpContext,
16
- createScheduleContext,
17
- } from "@@cloudcore";
7
+ import { RouterInstance } from '@cloudnux/local-cloud-provider';
8
+ import { httpHandler, scheduleHandler, eventBrokerHandler, websocketHandler } from "@cloudnux/cloud-sdk";
9
+ import "@cloudnux/local-cloud-provider/schedule-plugin";
10
+ import "@cloudnux/local-cloud-provider/queue-plugin";
11
+ import "@cloudnux/local-cloud-provider/websocket-plugin";
18
12
 
19
13
  import * as src from "<%= source %>";
20
14
 
21
- const prefix = "DEV_IDENTITY_";
22
- function buildAuth(headers: { authorization?: any; }) {
23
- try {
24
- // Case 1: DEV_IDENTITY_TOKEN
25
- const devToken = process.env[`${prefix}TOKEN`];
26
- if (devToken) {
27
- const claims = jwt.decode(devToken) as Record<string, unknown>;
28
- return { token: devToken, ...claims };
29
- }
30
-
31
- // Case 2: DEV_IDENTITY_ variables
32
- const devIdentityVars = Object.entries(process.env)
33
- .filter(([key]) => key.startsWith(prefix) && key !== `${prefix}TOKEN`)
34
- .reduce((acc, [key, value]) => {
35
- const claimKey = key.replace(prefix, '').toLowerCase();
36
- acc[claimKey] = value;
37
- return acc;
38
- }, {} as Record<string, unknown>);
39
-
40
- if (Object.keys(devIdentityVars).length > 0) {
41
- return { token: '', ...devIdentityVars };
42
- }
43
-
44
- // Case 3: Authorization header
45
- const authHeader = headers.authorization;
46
- if (authHeader?.startsWith('Bearer ')) {
47
- const token = authHeader.substring(7);
48
- const claims = jwt.decode(token) as Record<string, unknown>;
49
- return { token, ...claims };
50
- }
51
-
52
- // Case 4: Nothing exists
53
- return undefined;
54
- } catch (error) {
55
- console.error('Error processing identity token:', error);
56
- return undefined;
57
- }
58
- }
59
-
60
- async function entries(app: FastifyInstance) {
15
+ async function entries(app: RouterInstance) {
61
16
  <%_ for (const [name, entry] of Object.entries(entries)) { _%>
62
17
  <%_ if (entry.trigger.type === "http") { _%>
63
- <%- include("triggers/http.ts.ejs", {
64
- name,
65
- entry
66
- }) %>
18
+ app.route({
19
+ method: "<%= entry.trigger.options.method %>" as any,
20
+ url: `/http<%= $$convertRouteParamstoFastifyRouteTemplate(entry.trigger.options.route) %>`,
21
+ module : "<%=module%>",
22
+ handler: async (request, reply) => {
23
+ await httpHandler(src["<%= entry.handler %>"], request, reply);
24
+ }
25
+ });
67
26
  <%_ } _%>
68
27
  <%_ if (entry.trigger.type === "schedule") { _%>
69
- <%- include("triggers/schedule.ts.ejs", {
70
- name,
71
- entry
72
- }) %>
28
+ app.scheduler.addJob({
29
+ name: '<%= name %>',
30
+ cronExpression: '<%= entry.trigger.options.pattern %>',
31
+ module : "<%=module%>",
32
+ handler: async (job, execution) => {
33
+ return scheduleHandler(src["<%= entry.handler %>"], job,execution)
34
+ }});
35
+ <%_ } _%>
36
+ <%_ if(entry.trigger.type === "event") { _%>
37
+ app.queues.addQueue("<%=entry.trigger.options.source%>",
38
+ (msg) => eventBrokerHandler(src["<%= entry.handler %>"], msg),
39
+ "<%=module%>"
40
+ );
41
+ <%_ } _%>
42
+ <%_ if(entry.trigger.type === "websocket") { _%>
43
+ app.websockets.registerHandler({
44
+ path: "<%= entry.trigger.options.path %>",
45
+ event: "<%= entry.trigger.options.event %>",
46
+ <%_ if(entry.trigger.options.route) { _%>
47
+ route: "<%= entry.trigger.options.route %>",
48
+ <%_ } _%>
49
+ handler: async (connectionId, event, data) => {
50
+ return websocketHandler(src["<%= entry.handler %>"], connectionId, event, data);
51
+ }
52
+ });
73
53
  <%_ } _%>
74
54
  <%_ } _%>
75
55
  }
@@ -0,0 +1,7 @@
1
+ app.route({
2
+ method: "GET",
3
+ url: `/event/<%= name %>`,
4
+ handler: async function (...args) {
5
+ await eventBrokerHandler(src["<%= entry.handler %>"], ..args);
6
+ }
7
+ });
@@ -5,29 +5,7 @@
5
5
  app.route({
6
6
  method: "<%= entry.trigger.options.method %>" as any,
7
7
  url: `/http<%= $$convertRouteParamstoFastifyRouteTemplate(entry.trigger.options.route) %>`,
8
- handler: async function (request, reply) {
9
- const baseAddress = app.server.address() as AddressInfo;
10
- const routePath = `/http<%= $$convertRouteParamstoFastifyRouteTemplate(entry.trigger.options.route) %>`;
11
- const ctx = createHttpContext({
12
- body: request.rawBody as string,
13
- headers: request.headers,
14
- method: request.method as HttpMethod,
15
- url: `http://${request.hostname}:${baseAddress!.port}/api${routePath}`,
16
- matchingKey: "<%= entry.trigger.options.route %>",
17
- params: request.params as Record<string, string>,
18
- rawQueryString : querystring.stringify(request.query),
19
- host: request.hostname
20
- }, buildAuth(request.headers));
21
-
22
- try {
23
- await src["<%= entry.handler %>"](ctx);
24
- reply
25
- .headers(ctx.response.headers || {})
26
- .status(ctx.response.status)
27
- .send(ctx.response.body);
28
- }
29
- catch(e){
30
- reply.send(e);
31
- }
8
+ handler: async (request, reply) => {
9
+ await httpHandler(src["<%= entry.handler %>"], request, reply);
32
10
  }
33
11
  });
@@ -1,15 +1,7 @@
1
- logEntryURL('GET','/schedule/<%= name %>');
2
- app.route({
3
- method: "GET",
4
- url: `/schedule/<%= name %>`,
5
- handler: async function (request, reply) {
6
- const ctx = createScheduleContext("<%= name %>");
7
- try {
8
- await src["<%= entry.handler %>"](ctx);
9
- reply.status(200).send("success");
10
- }
11
- catch (e) {
12
- reply.send(e);
13
- }
14
- }
15
- });
1
+ app.route({
2
+ method: "GET",
3
+ url: `/schedule/<%= name %>`,
4
+ handler: async function (...args) {
5
+ await scheduleHandler(src["<%= entry.handler %>"], ...args);
6
+ }
7
+ });
@@ -0,0 +1,165 @@
1
+ type TaskParamBase = Record<string, any>;
2
+ type TaskParam = {
3
+ modulesPath: string;
4
+ /**
5
+ * cloud provider package to use, any locally installed package can be used
6
+ * aws is an alias for @cloudnux/aws-cloud-provider
7
+ * azure is an alias for @cloudnux/azure-cloud-provider
8
+ * gcp is an alias for @cloudnux/gcp-cloud-provider
9
+ */
10
+ cloudProvider: string;
11
+ /**
12
+ * Path to store the current environment build artifacts
13
+ * @default '.nux/<environment>'
14
+ */
15
+ workingDir: string;
16
+ /**
17
+ * task title
18
+ * @note: this is set by the task manager
19
+ */
20
+ title?: string;
21
+ /**
22
+ * environment name
23
+ */
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
+ [key: string]: any;
35
+ };
36
+ type TaskTitle = string | ((params: TaskParam) => string);
37
+ type Task<TTaskParams extends TaskParamBase = any> = {
38
+ title: string | ((params: TTaskParams) => string);
39
+ action: (params: TTaskParams) => any | Promise<any>;
40
+ skip?: (params: TTaskParams) => boolean;
41
+ children?: Task<TTaskParams>[];
42
+ };
43
+ type Environment<TTaskParams extends TaskParamBase = any> = {
44
+ /**
45
+ * tasks to be executed for this environment
46
+ */
47
+ tasks: Task<TTaskParams>[];
48
+ /**
49
+ * watch task
50
+ * if set, task will be executed and all logs will be routed to the watch view.
51
+ * This is useful for development environments where you want to see the logs in real-time
52
+ * @note: process will not exit until error or ctrl+c is pressed
53
+ * @default undefined
54
+ */
55
+ watch?: Task;
56
+ /**
57
+ * additional parameters for this environment
58
+ */
59
+ [key: string]: any;
60
+ };
61
+ type Config<TTaskParams extends TaskParamBase = any> = {
62
+ /**
63
+ * glob Path to find all modules (package.json) having entrypoints
64
+ * @default './packages/modules/**\/package.json'
65
+ */
66
+ modulesPath: string;
67
+ /**
68
+ * cloud provider package to use, any locally installed package can be used
69
+ * aws is an alias for @cloudnux/aws-cloud-provider
70
+ * azure is an alias for @cloudnux/azure-cloud-provider
71
+ * gcp is an alias for @cloudnux/gcp-cloud-provider
72
+ * @default 'aws'
73
+ */
74
+ cloudProvider: string;
75
+ /**
76
+ * Path to store the build artifacts for all environments
77
+ * @default './.nux'
78
+ */
79
+ workingDir: string;
80
+ /**
81
+ * environment configuration with key as environment name and value as Environment
82
+ * @default { develop: { tasks: [] }, prod: { tasks: [] } }
83
+ */
84
+ environments: Record<string, Environment<TTaskParams>>;
85
+ /**
86
+ * External packages to be used in the module build
87
+ * @default: ["aws-sdk", "@aws-sdk/*"]
88
+ */
89
+ externalPackages: string[];
90
+ };
91
+ type Args = {
92
+ inputs: {
93
+ env: string;
94
+ module?: string;
95
+ };
96
+ flags: {
97
+ configFile: string | undefined;
98
+ };
99
+ };
100
+ type AppProps = {
101
+ config: Config;
102
+ args: Args;
103
+ };
104
+ type Module = {
105
+ id: string;
106
+ name: string;
107
+ endpoints: any[];
108
+ data?: any;
109
+ };
110
+ type TaskStatus = 'pending' | 'running' | 'completed' | 'error' | 'skipped';
111
+ interface TaskState {
112
+ id: string;
113
+ title: string;
114
+ status: TaskStatus;
115
+ error?: string;
116
+ children: string[];
117
+ logs: any[];
118
+ parentId?: string;
119
+ }
120
+ interface TaskManagerStore {
121
+ tasks: Record<string, TaskState>;
122
+ currentTaskId: string | null;
123
+ environment: string;
124
+ isRunning: boolean;
125
+ tasksCount: number;
126
+ start: (config: Config, env: string) => Promise<void>;
127
+ addTask: (task: {
128
+ id: string;
129
+ title: string;
130
+ parentTaskId?: string;
131
+ }) => void;
132
+ updateTaskStatus: (taskId: string, status: TaskStatus, error?: string) => void;
133
+ addTaskLog: (taskId: string, log: any, data: any) => void;
134
+ }
135
+ interface Log {
136
+ url: string;
137
+ method: string;
138
+ status: number;
139
+ payload: any;
140
+ time: Date;
141
+ }
142
+ interface DevServerStore {
143
+ isRunning: boolean;
144
+ modules: Module[];
145
+ selectedModule: string | null;
146
+ selectedEndpoint: any | null;
147
+ port: string;
148
+ host: string;
149
+ logs: Array<any>;
150
+ pinoLogs: Array<any>;
151
+ watch: (config: Config, env: string) => Promise<void>;
152
+ addModule: (id: string, opts: any) => void;
153
+ addRoute: (route: any) => void;
154
+ addActionLog(id: string, data: any): void;
155
+ addPinoLog(id: string, data: any): void;
156
+ startListening: ({ host, port }: {
157
+ host: string;
158
+ port: string;
159
+ }) => void;
160
+ selectModule: (id: string) => void;
161
+ selectEndpoint: (endpoint: any) => void;
162
+ resetSelection: () => void;
163
+ }
164
+
165
+ export type { AppProps, Args, Config, DevServerStore, Environment, Log, Task, TaskManagerStore, TaskParam, TaskParamBase, TaskState, TaskStatus, TaskTitle };
package/dist/types.mjs ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/package.json CHANGED
@@ -1,54 +1,58 @@
1
1
  {
2
2
  "name": "@cloudnux/cli",
3
- "version": "0.1.0",
3
+ "version": "0.11.0",
4
4
  "license": "MIT",
5
5
  "bin": {
6
- "epf": "dist/cli.js"
6
+ "nux": "dist/cli.mjs"
7
+ },
8
+ "main": "./dist/cli.js",
9
+ "types": "./dist/cli.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/types.d.ts",
13
+ "import": "./dist/types.mjs"
14
+ }
7
15
  },
8
16
  "type": "module",
9
17
  "engines": {
10
18
  "node": ">=22"
11
19
  },
12
20
  "scripts": {
13
- "develop": "tsup --watch && chmod +x dist/cli.js",
14
- "build": "tsup && chmod +x dist/cli.js",
15
- "link": "yarn link"
21
+ "dev": "tsup",
22
+ "build": "tsup",
23
+ "link": "yarn link",
24
+ "type-check": "tsc --noEmit",
25
+ "clean": "rm -rf dist"
16
26
  },
17
27
  "files": [
18
28
  ".deploy",
19
29
  "dist",
20
- "pakage.json",
30
+ "package.json",
21
31
  "README.md"
22
32
  ],
23
33
  "dependencies": {
24
- "@inkjs/ui": "^2.0.0",
25
34
  "@types/findup-sync": "^4.0.5",
26
35
  "ejs": "^3.1.10",
27
36
  "fast-glob": "^3.3.2",
28
37
  "fastify": "^5.2.1",
29
38
  "fastify-raw-body": "^5.0.0",
30
39
  "findup-sync": "^5.0.0",
31
- "immer": "^10.1.1",
32
- "ink": "^4.1.0",
33
- "ink-spinner": "^5.0.0",
34
40
  "interpret": "^3.1.1",
35
41
  "jsonwebtoken": "^9.0.2",
36
42
  "meow": "^11.0.0",
37
43
  "pino-pretty": "^13.0.0",
38
- "react": "^18.2.0",
39
44
  "rechoir": "^0.8.0",
40
45
  "tsup": "^8.3.5",
41
- "zustand": "^5.0.2"
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"
42
50
  },
43
51
  "devDependencies": {
44
52
  "@types/ejs": "^3.1.5",
45
53
  "@types/findup-sync": "^4.0.5",
46
54
  "@types/jsonwebtoken": "^9.0.7",
47
- "@types/react": "^18.0.32",
48
55
  "@types/rechoir": "^0.6.4",
49
- "chalk": "^5.2.0",
50
- "ink-testing-library": "^4.0.0",
51
- "react-devtools-core": "^6.0.1",
52
56
  "typescript": "^5.0.3"
53
57
  },
54
58
  "publishConfig": {
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # EntryPoint Framework CLI
1
+ # CloudNux CLI
2
2
 
3
3
  A task-based CLI framework for managing cloud function deployments and local development.
4
4
 
@@ -6,7 +6,7 @@ A task-based CLI framework for managing cloud function deployments and local dev
6
6
 
7
7
  Create an
8
8
 
9
- `epf.config.js` or `.epfrc.js` in your project root:
9
+ `nux.config.js` or `.nuxrc.js` in your project root:
10
10
 
11
11
  ```typescript
12
12
  export default {
@@ -42,7 +42,7 @@ export default {
42
42
 
43
43
  ## Task System
44
44
 
45
- Tasks are the core building blocks of EPF workflows. Each task has:
45
+ Tasks are the core building blocks of CloudNux workflows. Each task has:
46
46
 
47
47
  ```typescript
48
48
  {
@@ -64,10 +64,10 @@ Tasks are the core building blocks of EPF workflows. Each task has:
64
64
 
65
65
  ```bash
66
66
  # Run with environment
67
- epf <environment>
67
+ nux <environment>
68
68
 
69
69
  # Specify config file
70
- epf <environment> --config=./custom-config.js
70
+ nux <environment> --config=./custom-config.js
71
71
  ```
72
72
 
73
73
  ## Environments
@@ -125,12 +125,12 @@ Tasks receive parameters including:
125
125
 
126
126
  ```
127
127
  .
128
- ├── epf.config.js # CLI configuration
128
+ ├── nux.config.js # CLI configuration
129
129
  ├── packages/
130
130
  │ └── modules/ # Function modules
131
131
  │ └── */
132
132
  │ └── entrypoint.json # Module definition
133
- └── .epf/ # Build artifacts
133
+ └── .nux/ # Build artifacts
134
134
  └── <environment>/ # Environment builds
135
135
  ```
136
136
 
@@ -1,134 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "title": "Task Configuration Schema",
4
- "type": "object",
5
- "definitions": {
6
- "TaskParamBase": {
7
- "type": "object",
8
- "properties": {
9
- "modulesPath": {
10
- "type": "string",
11
- "description": "Path to find all modules"
12
- },
13
- "cloudProvider": {
14
- "type": "string",
15
- "description": "Cloud provider package to use. aws/azure/gcp are aliases for respective @entrypoint-framework packages"
16
- },
17
- "workingDir": {
18
- "type": "string",
19
- "description": "Path to store the current environment build artifacts",
20
- "default": ".epf/<environment>"
21
- },
22
- "title": {
23
- "type": "string",
24
- "description": "Task title (set by task manager)"
25
- },
26
- "environment": {
27
- "type": "string",
28
- "description": "Environment name"
29
- },
30
- "children": {
31
- "type": "array",
32
- "items": {
33
- "$ref": "#/definitions/Task"
34
- }
35
- }
36
- },
37
- "required": [
38
- "modulesPath",
39
- "cloudProvider",
40
- "workingDir",
41
- "environment"
42
- ],
43
- "additionalProperties": true
44
- },
45
- "Task": {
46
- "type": "object",
47
- "properties": {
48
- "title": {
49
- "oneOf": [
50
- {
51
- "type": "string"
52
- },
53
- {
54
- "type": "object",
55
- "description": "Function that returns a string based on task parameters"
56
- }
57
- ]
58
- },
59
- "skip": {
60
- "type": "object",
61
- "description": "Function that determines if task should be skipped"
62
- },
63
- "action": {
64
- "type": "object",
65
- "description": "Async function that executes the task"
66
- },
67
- "children": {
68
- "type": "array",
69
- "items": {
70
- "$ref": "#/definitions/Task"
71
- }
72
- }
73
- },
74
- "required": [
75
- "title",
76
- "action"
77
- ]
78
- },
79
- "Environment": {
80
- "type": "object",
81
- "properties": {
82
- "tasks": {
83
- "type": "array",
84
- "items": {
85
- "$ref": "#/definitions/Task"
86
- },
87
- "description": "Tasks to be executed for this environment"
88
- }
89
- },
90
- "required": [
91
- "tasks"
92
- ],
93
- "additionalProperties": true
94
- }
95
- },
96
- "properties": {
97
- "modulesPath": {
98
- "type": "string",
99
- "description": "Glob path to find all modules (package.json) having entrypoints",
100
- "default": "./packages/modules/**/package.json"
101
- },
102
- "cloudProvider": {
103
- "type": "string",
104
- "description": "Cloud provider package to use",
105
- "default": "aws"
106
- },
107
- "workingDir": {
108
- "type": "string",
109
- "description": "Path to store the build artifacts for all environments",
110
- "default": "./.epf"
111
- },
112
- "environments": {
113
- "type": "object",
114
- "description": "Environment configuration with key as environment name",
115
- "additionalProperties": {
116
- "$ref": "#/definitions/Environment"
117
- },
118
- "default": {
119
- "develop": {
120
- "tasks": []
121
- },
122
- "prod": {
123
- "tasks": []
124
- }
125
- }
126
- }
127
- },
128
- "required": [
129
- "modulesPath",
130
- "cloudProvider",
131
- "workingDir",
132
- "environments"
133
- ]
134
- }
@@ -1,50 +0,0 @@
1
- import { Context, S3Event,
2
- APIGatewayProxyEventV2WithJWTAuthorizer,
3
- ScheduledEvent
4
- } from "aws-lambda";
5
-
6
- import { createRouter, httpMatcher, scheduleMatcher } from "@anubis/cloud-provider";
7
- import { functions } from "@anubis/aws-cloud-provider";
8
- import { initialize } from "@anubis/datastore";
9
- import { logger } from "@anubis/utils";
10
-
11
- import * as src from "../../packages/components/<%=component%>/src";
12
-
13
- type AWSEventType = S3Event | APIGatewayProxyEventV2WithJWTAuthorizer | ScheduledEvent;
14
-
15
- const router = createRouter();
16
- <%_ for(var [key,entry] of Object.entries(entries)) { _%>
17
- <%_ if(entry.trigger.type.toLowerCase() === "http") { _%>
18
- router.add(httpMatcher("<%=entry.trigger.options.method%>", "<%=entry.trigger.options.route%>"), src["<%= entry.handler %>"])
19
- <%_ } _%>
20
- <%_ if(entry.trigger.type.toLowerCase() === "schedule") { _%>
21
- router.add(scheduleMatcher("<%= key %>"), src["<%= entry.handler %>"])
22
- <%_ } _%>
23
- <%_ } _%>
24
-
25
- export async function handler(event: AWSEventType, context: Context) {
26
- logger.initialize("locations", context.awsRequestId);
27
- logger.info("request started");
28
- logger.debug({ event }, "Received event");
29
-
30
- try {
31
- await initialize();
32
- let output = null;
33
- if ("rawPath" in event) {
34
- output = await router.run("Http", functions.httpAdapter, event, context);
35
- }
36
- else if ("source" in event) {
37
- output = await router.run("Schedule", functions.scheduleAdapter, event, context);
38
- }
39
- else {
40
- throw new Error("invalid handler");
41
- }
42
- logger.debug({ output }, "Response Sent");
43
- logger.info("request completed");
44
- return output;
45
- }
46
- catch (error) {
47
- logger.error({ error }, "Error occurred");
48
- throw error;
49
- }
50
- }