@cloudnux/cli 0.1.0 → 0.10.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
+ });
package/package.json CHANGED
@@ -1,54 +1,52 @@
1
1
  {
2
2
  "name": "@cloudnux/cli",
3
- "version": "0.1.0",
3
+ "version": "0.10.0",
4
4
  "license": "MIT",
5
5
  "bin": {
6
- "epf": "dist/cli.js"
6
+ "nux": "dist/cli.mjs"
7
7
  },
8
+ "main": "./dist/cli.js",
9
+ "types": "./dist/cli.d.ts",
8
10
  "type": "module",
9
11
  "engines": {
10
12
  "node": ">=22"
11
13
  },
12
14
  "scripts": {
13
- "develop": "tsup --watch && chmod +x dist/cli.js",
14
- "build": "tsup && chmod +x dist/cli.js",
15
- "link": "yarn link"
15
+ "dev": "tsup",
16
+ "build": "tsup",
17
+ "link": "yarn link",
18
+ "type-check": "tsc --noEmit",
19
+ "clean": "rm -rf dist"
16
20
  },
17
21
  "files": [
18
22
  ".deploy",
19
23
  "dist",
20
- "pakage.json",
24
+ "package.json",
21
25
  "README.md"
22
26
  ],
23
27
  "dependencies": {
24
- "@inkjs/ui": "^2.0.0",
25
28
  "@types/findup-sync": "^4.0.5",
26
29
  "ejs": "^3.1.10",
27
30
  "fast-glob": "^3.3.2",
28
31
  "fastify": "^5.2.1",
29
32
  "fastify-raw-body": "^5.0.0",
30
33
  "findup-sync": "^5.0.0",
31
- "immer": "^10.1.1",
32
- "ink": "^4.1.0",
33
- "ink-spinner": "^5.0.0",
34
34
  "interpret": "^3.1.1",
35
35
  "jsonwebtoken": "^9.0.2",
36
36
  "meow": "^11.0.0",
37
37
  "pino-pretty": "^13.0.0",
38
- "react": "^18.2.0",
39
38
  "rechoir": "^0.8.0",
40
39
  "tsup": "^8.3.5",
41
- "zustand": "^5.0.2"
40
+ "@cloudnux/aws-cloud-provider": "0.10.0",
41
+ "@cloudnux/local-cloud-provider": "0.10.0",
42
+ "@cloudnux/cloud-sdk": "0.10.0",
43
+ "@cloudnux/dev-console": "0.10.0"
42
44
  },
43
45
  "devDependencies": {
44
46
  "@types/ejs": "^3.1.5",
45
47
  "@types/findup-sync": "^4.0.5",
46
48
  "@types/jsonwebtoken": "^9.0.7",
47
- "@types/react": "^18.0.32",
48
49
  "@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
50
  "typescript": "^5.0.3"
53
51
  },
54
52
  "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
- }
@@ -1,67 +0,0 @@
1
- terraform {
2
- backend "s3" {
3
- key = "<%= component %>/terraform.state"
4
- workspace_key_prefix = "state/<%= component %>"
5
- }
6
-
7
- required_providers {
8
- aws = {
9
- source = "hashicorp/aws"
10
- version = ">= 4.0"
11
- }
12
- }
13
-
14
- required_version = ">= 0.13.1"
15
- }
16
-
17
- data "aws_lambda_function" "this" {
18
- function_name = "<%= component %>"
19
- }
20
-
21
- data "aws_apigatewayv2_apis" "this" {
22
- tags = {
23
- application = "anubis"
24
- }
25
- }
26
-
27
- <% const httpEntries = Object.entries(entries).filter(([k,e]) => e.trigger.type.toLowerCase() === "http") %>
28
- <% if(httpEntries.length > 0) { %>
29
- module "http_trigger_for_<%= component %>" {
30
- source = "../../.deploy/aws/http"
31
- api_gateway_id = sort(data.aws_apigatewayv2_apis.this.ids)[0]
32
- lambda_arn = data.aws_lambda_function.this.arn
33
- lambda_name = "<%= component %>"
34
- entrypoints = {
35
- <% for(const [key,entry] of httpEntries){ %>
36
- "<%= key %>" = {
37
- description = "<% entry.trigger.options.description %>"
38
- method = "<%= entry.trigger.options.method %>"
39
- path = "<%= entry.trigger.options.route %>"
40
- }
41
- <% } %>
42
- }
43
- }
44
-
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_<%= component %>" {
50
- source = "../../.deploy/aws/scheduler"
51
- component = "<%= component %>"
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
- }
66
- }
67
- <% } %>
@@ -1,63 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import Fastify, { FastifyInstance } from "fastify";
4
- import { initialize } from "@anubis/datastore";
5
- import { logger } from "@anubis/utils";
6
-
7
- <% for(const component of components){ %>
8
- import <%=component%>Entries from "./<%=component%>/entrypoint.ts" <% }
9
- %>
10
-
11
- async function docs(app: FastifyInstance) {
12
- const docsBuildPath = path.resolve("../../../.dist/docs");
13
-
14
- app.get("/index.js", function (request, reply) {
15
- const stream = fs.createReadStream(path.resolve(docsBuildPath, "index.js"));
16
- reply.type("text/javascript").send(stream);
17
- });
18
-
19
- app.get("/index.js.map", function (request, reply) {
20
- const stream = fs.createReadStream(path.resolve(docsBuildPath, "index.js.map"));
21
- reply.type("text/javascript").send(stream);
22
- });
23
-
24
- app.get("/index.css", function (request, reply) {
25
- const stream = fs.createReadStream(path.resolve(docsBuildPath, "index.css"));
26
- reply.type("text/javascript").send(stream);
27
- });
28
-
29
- app.get("*", function (request, reply) {
30
- const filePath = path.resolve(docsBuildPath, "index.html");
31
- const stream = fs.createReadStream(filePath);
32
- reply.type("text/html").send(stream);
33
- });
34
- }
35
-
36
- const fastify = Fastify({
37
- maxParamLength : 1000,
38
- logger: {
39
- transport: {
40
- target: 'pino-pretty',
41
- options: {
42
- colorize: true,
43
- translateTime: 'HH:MM:ss Z',
44
- ignore: 'pid,hostname',
45
- },
46
- }
47
- }
48
- });
49
-
50
- // Register the fastify-raw-body plugin
51
- fastify.register(require('fastify-raw-body'), {
52
- field: 'rawBody',
53
- encoding: 'utf8',
54
- });
55
-
56
- fastify.register(docs, { prefix: "docs" });
57
- <% for(const component of components){ %>
58
- fastify.register(<%=component%>Entries, { prefix: "api" });
59
- <%}%>
60
- fastify.listen({ port: 3000, host : "::" }).then((address) => {
61
- logger.setLogger(fastify.log as any);
62
- initialize();
63
- });
@@ -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
- }