nicola-framework 1.0.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/core/Core.js ADDED
@@ -0,0 +1,84 @@
1
+ import http from 'http'
2
+ import Remote from './Remote.js';
3
+ import BlackBox from '../middlewares/BlackBox.js'
4
+ import Shadowgraph from '../middlewares/Shadowgraph.js';
5
+ import Teleforce from '../middlewares/Teleforce.js';
6
+ import EasyCors from '../middlewares/EasyCors.js';
7
+ class Core extends Remote {
8
+
9
+ constructor() {
10
+ super();
11
+ }
12
+
13
+
14
+
15
+
16
+ listen(port, callback) {
17
+
18
+ const server = http.createServer((req, res) => {
19
+ const myURL = new URL(req.url, 'http://' + req.headers.host);
20
+ const pathURL = myURL.pathname;
21
+ const urlParams = Object.fromEntries(myURL.searchParams);
22
+
23
+ req.url = pathURL;
24
+ req.query = urlParams;
25
+
26
+ Shadowgraph(req, res, () => {
27
+ this.__addHelper(res);
28
+ EasyCors(req, res, () =>{
29
+
30
+ Teleforce(req, res, () => {
31
+ const done = (err) => {
32
+ if (!err) {
33
+ res.statusCode = 404;
34
+ res.end('Not Found')
35
+ }
36
+ else {
37
+ BlackBox.ignite(err, req, res);
38
+ }
39
+ }
40
+
41
+ let dataString = ''
42
+ req.on('data', chunk => {
43
+ dataString += chunk;
44
+
45
+ })
46
+
47
+ req.on('end', () => {
48
+ try {
49
+ if (dataString) {
50
+ req.body = JSON.parse(dataString);
51
+ }
52
+ else {
53
+ req.body = {}
54
+ }
55
+ }
56
+ catch (error) {
57
+ req.body = {}
58
+ }
59
+ this.handle(req, res, done);
60
+
61
+ });
62
+ })
63
+ })
64
+ })
65
+ })
66
+ server.listen(port, callback);
67
+ }
68
+
69
+ __addHelper(res) {
70
+ res.json = (data) => {
71
+ res.setHeader('Content-Type', 'application/json');
72
+ res.end(JSON.stringify(data));
73
+ }
74
+
75
+ res.send = (data) => {
76
+ res.setHeader('Content-Type', 'text/plain');
77
+ res.end(data);
78
+ }
79
+ }
80
+
81
+
82
+ }
83
+
84
+ export default Core;
package/core/Remote.js ADDED
@@ -0,0 +1,158 @@
1
+
2
+ class Remote {
3
+
4
+ constructor() {
5
+ this.stack = []
6
+ }
7
+
8
+ __add(method, path, handlers) {
9
+ const results = this.parsePath(path)
10
+ const allHandlers = handlers.flat(Infinity);
11
+ if (allHandlers.length === 1 && allHandlers[0] instanceof Remote) {
12
+ this.stack.push({
13
+ method: method.toUpperCase(),
14
+ path: path,
15
+ handler: allHandlers[0]
16
+ })
17
+ return;
18
+ }
19
+
20
+ const runner = (req, res, routerNext) => {
21
+ let idx = 0
22
+ const internalNext = (err) => {
23
+ if (err) return routerNext(err);
24
+
25
+ const fn = allHandlers[idx];
26
+ idx++;
27
+ if (!fn) {
28
+ return routerNext();
29
+ }
30
+
31
+ try {
32
+ fn(req, res, internalNext);
33
+ }
34
+ catch (error) {
35
+ internalNext(error);
36
+ }
37
+ }
38
+ internalNext();
39
+ }
40
+ if (results.regex) {
41
+ this.stack.push({
42
+ method: method.toUpperCase(),
43
+ path: path,
44
+ regex: results.regex,
45
+ keys: results.keys,
46
+ handler: runner
47
+ })
48
+ }
49
+ else {
50
+ this.stack.push({
51
+ method: method.toUpperCase(),
52
+ path: results,
53
+ handler: runner
54
+ })
55
+ }
56
+ }
57
+
58
+ get(path, ...handlers) {
59
+ this.__add('GET', path, handlers);
60
+ }
61
+ post(path, ...handlers) {
62
+ this.__add('POST', path, handlers);
63
+ }
64
+ put(path, ...handlers) {
65
+ this.__add('PUT', path, handlers);
66
+ }
67
+ patch(path, ...handlers) {
68
+ this.__add('PATCH', path, handlers);
69
+ }
70
+ delete(path, ...handlers) {
71
+ this.__add('DELETE', path, handlers);
72
+ }
73
+
74
+
75
+ use(path, ...handlers) {
76
+ if (typeof path == 'function') {
77
+ this.__add('USE', '/', [path, ...handlers])
78
+ }
79
+ else {
80
+ this.__add('USE', path, handlers);
81
+ }
82
+
83
+ }
84
+
85
+ handle(req, res, done) {
86
+ let index = 0
87
+ let match = false
88
+ const next = (err) => {
89
+ if (err) {
90
+ return done(err)
91
+ }
92
+
93
+ try {
94
+ const route = this.stack[index]
95
+ index++;
96
+ if (!route) {
97
+ return done()
98
+ }
99
+ const middleware = route.method === 'USE' && req.url.startsWith(route.path);
100
+ const rutaCoincidence = route.path === req.url && route.method === req.method;
101
+ match = route.regex && route.regex.test(req.url) && route.method === req.method;
102
+ if(match){
103
+ if(route.regex){
104
+ const valueCatch = req.url.match(route.regex)
105
+ req.params = {}
106
+ route.keys.forEach((key, index) => {
107
+ req.params[key]= valueCatch[index + 1];
108
+ });
109
+ }
110
+ }
111
+ if (rutaCoincidence || middleware || match) {
112
+ if (route.handler instanceof Remote) {
113
+ const urlBackup = req.url;
114
+ req.url = req.url.slice(route.path.length) || '/'
115
+ const done = (err) => {
116
+ req.url = urlBackup
117
+ next(err)
118
+ }
119
+ route.handler.handle(req, res, done);
120
+
121
+ console.log('Esto es un sub router')
122
+ } else {
123
+
124
+ route.handler(req, res, next);
125
+ }
126
+ }
127
+ else {
128
+ next()
129
+ }
130
+ } catch (err) {
131
+ next(err);
132
+ }
133
+ }
134
+
135
+
136
+
137
+ next()
138
+ }
139
+
140
+ parsePath(path) {
141
+ if (!path.includes(':')) {
142
+ return path;
143
+ }
144
+ if (path.includes(':')) {
145
+ const keys = []
146
+ let pathString = path.replace(/:(\w+)/g, (match, paramName) => {
147
+ keys.push(paramName);
148
+
149
+ return '([^/]+)';
150
+ })
151
+
152
+ const regex = new RegExp(`^${pathString}$`)
153
+ return { regex, keys };
154
+ }
155
+ }
156
+ }
157
+
158
+ export default Remote;
@@ -0,0 +1,41 @@
1
+ import Postgres from "./dialects/Postgres.js";
2
+
3
+ class Connection {
4
+ static client = null
5
+
6
+
7
+ static async connect() {
8
+ const DB_DRIVER = process.env.DB_DRIVER
9
+ const config = {
10
+ user: process.env.DB_USER,
11
+ password: process.env.DB_PASS,
12
+ host: process.env.DB_HOST,
13
+ port: process.env.DB_PORT,
14
+ database: process.env.DB_NAME
15
+ }
16
+
17
+ if(DB_DRIVER === 'postgres'){
18
+ this.client = new Postgres(config)
19
+ await this.client.connect()
20
+ return;
21
+ }
22
+ if(DB_DRIVER === 'mysql'){
23
+ await this.__connectMysql()
24
+ return;
25
+ }
26
+ throw new Error("Driver no soportado" + DB_DRIVER)
27
+ }
28
+
29
+
30
+
31
+ static async __connectMysql(){
32
+
33
+ }
34
+
35
+ static async query(sql, params){
36
+ return this.client.query(sql, params);
37
+ }
38
+ }
39
+
40
+
41
+ export default Connection;
@@ -0,0 +1,38 @@
1
+ class Driver {
2
+
3
+
4
+ constructor(config){
5
+ this.config = config
6
+ }
7
+
8
+ async connect(){
9
+ throw new Error("Method 'connect()' must be implemented");
10
+ }
11
+
12
+ async query(sql, params){
13
+ throw new Error("Method 'query()' must be implemented");
14
+ }
15
+
16
+ async disconnect(){
17
+ throw new Error("Method 'disconnect()' must be implemented");
18
+ }
19
+
20
+ compileSelect(builder){
21
+
22
+ }
23
+
24
+ compileInsert(builder, data){
25
+
26
+ }
27
+
28
+ compileUpdate(builder, data){
29
+
30
+ }
31
+
32
+ compileDelete(builder){
33
+
34
+ }
35
+ }
36
+
37
+
38
+ export default Driver;
@@ -0,0 +1,48 @@
1
+ import QueryBuilder from "./QueryBuilder.js";
2
+ import Schema from "./Schema.js";
3
+
4
+ class Model {
5
+ static tableName = null
6
+ static schema = {}
7
+ static query(){
8
+ return new QueryBuilder(this.tableName)
9
+ }
10
+
11
+ static select(...params){
12
+ return this.query().select(...params);
13
+ }
14
+
15
+ static where(...params){
16
+ return this.query().where(...params);
17
+ }
18
+
19
+ static all(){
20
+ return this.query().get();
21
+ }
22
+
23
+ static create(...params){
24
+ Schema.validate(...params, this.schema)
25
+ return this.query().insert(...params);
26
+ }
27
+
28
+ static update(...params){
29
+ return this.query().update(...params);
30
+ }
31
+
32
+ static delete(){
33
+ return this.query().delete();
34
+ }
35
+
36
+ static orderBy(...params){
37
+ return this.query().orderby(...params);
38
+ }
39
+ static limit(...params){
40
+ return this.query().limit(...params);
41
+ }
42
+ static offset(...params){
43
+ return this.query().offset(...params);
44
+ }
45
+ }
46
+
47
+
48
+ export default Model;
@@ -0,0 +1,96 @@
1
+ import Connection from "./Connection.js";
2
+
3
+ class QueryBuilder {
4
+ constructor(db_name) {
5
+ this.table = db_name;
6
+ this.columns = ["*"];
7
+ this.conditions = [];
8
+ this.bindings = [];
9
+ this.orders= [];
10
+ this.limitCount= null;
11
+ this.offsetCount = null;
12
+ }
13
+
14
+ select(columns) {
15
+ if (Array.isArray(columns)) {
16
+ this.columns = columns;
17
+ }
18
+ if (typeof columns === "string") {
19
+ let columnsSplit = columns.split(",");
20
+ let cleanCols = [];
21
+ for (const col of columnsSplit) {
22
+ cleanCols.push(col.trim());
23
+ }
24
+ this.columns = cleanCols;
25
+ }
26
+ return this;
27
+ }
28
+
29
+ where(column, operator, value) {
30
+ if (value === undefined) {
31
+ value = operator;
32
+ operator = "=";
33
+ }
34
+
35
+ let totalIndex = this.bindings.length + 1;
36
+
37
+ this.conditions.push({
38
+ column: column,
39
+ operator: operator,
40
+ bindingsIndex: totalIndex,
41
+ });
42
+
43
+ this.bindings.push(value);
44
+
45
+ return this;
46
+ }
47
+
48
+ async get() {
49
+ const { sql, bindings } = Connection.client.compileSelect(this);
50
+ const result = await Connection.query(sql, bindings);
51
+ return result.rows;
52
+ }
53
+
54
+ async insert(data) {
55
+ const { sql, bindings } = Connection.client.compileInsert(this, data);
56
+ const result = await Connection.query(sql, bindings);
57
+ return result.rows[0];
58
+ }
59
+
60
+ async update(data) {
61
+ const { sql, bindings } = Connection.client.compileUpdate(this, data);
62
+ const result = await Connection.query(sql, bindings);
63
+ return result.count;
64
+ }
65
+
66
+ async delete() {
67
+ const { sql, bindings } = Connection.client.compileDelete(this);
68
+ const result = await Connection.query(sql, bindings);
69
+ return result.count;
70
+ }
71
+
72
+ orderBy(column, direction = "ASC"){
73
+ this.orders.push({
74
+ column: column,
75
+ direction: direction.toUpperCase()
76
+ })
77
+
78
+ return this;
79
+ }
80
+
81
+ limit(number){
82
+ this.limitCount = number
83
+
84
+ return this;
85
+ }
86
+
87
+ offset(number){
88
+ this.offsetCount = number
89
+
90
+ return this;
91
+ }
92
+
93
+
94
+ }
95
+
96
+ export default QueryBuilder;
@@ -0,0 +1,24 @@
1
+
2
+
3
+ class Schema{
4
+
5
+
6
+
7
+ static validate(data, rules){
8
+ for(const field in rules){
9
+ const rule = rules[field]
10
+ const value = data[field]
11
+
12
+ if(rule.required === true && (value === undefined || value === null || value === '')){
13
+ throw new Error(`Field ${field} is required`)
14
+ }
15
+ if(typeof value !== rule.type && value !== undefined && value !== null){
16
+ throw new Error(`Field ${field} must be a ${rule.type}`)
17
+ }
18
+ };
19
+
20
+ return true;
21
+ }
22
+ }
23
+
24
+ export default Schema;
File without changes
@@ -0,0 +1,162 @@
1
+ import Driver from "../Driver.js";
2
+
3
+
4
+ class Postgres extends Driver {
5
+ constructor(config) {
6
+ super(config);
7
+ this.client = null
8
+ }
9
+
10
+ async connect() {
11
+ try {
12
+ const pg = await import('pg')
13
+ const { Pool } = pg.default || pg
14
+
15
+ const config = {
16
+ user: this.config.user,
17
+ password: this.config.password,
18
+ host: this.config.host,
19
+ port: this.config.port,
20
+ database: this.config.database
21
+ }
22
+
23
+ if (process.env.DB_SSLMODE) {
24
+ const sslMode = process.env.DB_SSLMODE.toLowerCase();
25
+
26
+ if (sslMode === 'require') {
27
+ config.ssl = { rejectUnauthorized: false };
28
+ } else if (sslMode === 'verify-ca' || sslMode === 'verify-full') {
29
+ config.ssl = { rejectUnauthorized: true };
30
+ } else if (sslMode === 'disable' || sslMode === 'prefer') {
31
+ config.ssl = false;
32
+ } else {
33
+ config.ssl = { rejectUnauthorized: false };
34
+ }
35
+ }
36
+
37
+ this.client = new Pool(config)
38
+
39
+ await this.client.query('SELECT NOW()')
40
+ }
41
+ catch (e) {
42
+ if (e.code === 'ERR_MODULE_NOT_FOUND') {
43
+ console.log('Por favor utiliza el comando npm install pg')
44
+ }
45
+ else {
46
+ console.error(e)
47
+ }
48
+ }
49
+ }
50
+
51
+
52
+ async query(sql, params) {
53
+ if (!this.client) {
54
+ return console.log("Dynamo: No hay ninguna conexion activa")
55
+ }
56
+ const result = await this.client.query(sql, params);
57
+ return {
58
+ rows: result.rows,
59
+ count: result.rowCount
60
+ }
61
+ }
62
+
63
+ compileSelect(builder) {
64
+ const stringColums = builder.columns.join(', ')
65
+ let ordersBy = ''
66
+ let limit = ''
67
+ let offset = ''
68
+ if(builder.orders.length > 0){
69
+ const OrdesArray = builder.orders.map(o => {
70
+ return ` ${o.column} ${o.direction}`
71
+ })
72
+ ordersBy =' ORDER BY ' + OrdesArray.join(',')
73
+
74
+ }
75
+ if(builder.limitCount !== null){
76
+ limit = ` LIMIT ${builder.limitCount}`
77
+ }
78
+ if(builder.offsetCount !== null){
79
+ offset = ` OFFSET ${builder.offsetCount}`
80
+ }
81
+ const where = this._buildWhere(builder.conditions)
82
+ const sql = `SELECT ${stringColums} FROM ${builder.table} ${where} ${ordersBy} ${limit} ${offset}`
83
+
84
+ return {
85
+ sql: sql,
86
+ bindings: builder.bindings
87
+ }
88
+ }
89
+
90
+ _buildWhere(conditions) {
91
+ let whereQuery = ''
92
+
93
+ if (conditions.length > 0) {
94
+ const query = conditions.map(condition => {
95
+ return ` ${condition.column} ${condition.operator} $${condition.bindingsIndex}`
96
+ })
97
+
98
+ return whereQuery = 'WHERE ' + query.join(' AND ')
99
+ }
100
+
101
+ return whereQuery
102
+ }
103
+
104
+
105
+ compileInsert(builder, data) {
106
+ let columns = Object.keys(data);
107
+ columns = columns.join(', ')
108
+ let values = Object.values(data)
109
+ let bindingsIndex = []
110
+ values.forEach(v => {
111
+ let index = builder.bindings.length + 1
112
+ bindingsIndex.push(`$${index}`)
113
+ builder.bindings.push(v)
114
+ })
115
+
116
+ bindingsIndex = bindingsIndex.join(', ')
117
+
118
+ let sql = `INSERT INTO ${builder.table} (${columns}) VALUES (${bindingsIndex}) RETURNING *`
119
+
120
+ return {
121
+ sql: sql,
122
+ bindings: builder.bindings
123
+ }
124
+ }
125
+
126
+ compileUpdate(builder, data) {
127
+ const columns = Object.keys(data)
128
+ const values = Object.values(data)
129
+ let stringColums = []
130
+ let whereQuery = ''
131
+ let index = 0
132
+ columns.forEach((c, i) => {
133
+ index = builder.bindings.length + 1
134
+ builder.bindings.push(values[i])
135
+ stringColums.push(`${c} = $${index}`)
136
+ })
137
+
138
+ const where = this._buildWhere(builder.conditions)
139
+
140
+ stringColums = stringColums.join(', ')
141
+
142
+ const sql = `UPDATE ${builder.table} SET ${stringColums} ${where}`
143
+
144
+ return {
145
+ sql:sql,
146
+ bindings: builder.bindings
147
+ }
148
+ }
149
+
150
+ compileDelete(builder) {
151
+ const where = this._buildWhere(builder.conditions)
152
+
153
+ const sql = `DELETE FROM ${builder.table} ${where}`
154
+
155
+ return{
156
+ sql:sql,
157
+ bindings: builder.bindings
158
+ }
159
+ }
160
+ }
161
+
162
+ export default Postgres;
@@ -0,0 +1,20 @@
1
+ import Model from './Model.js'
2
+ import QueryBuilder from './QueryBuilder.js'
3
+ import Connection from './Connection.js'
4
+
5
+ class Dynamo{
6
+ static async connect(){
7
+ return Connection.connect()
8
+ }
9
+
10
+ static async query(sql, params){
11
+ return Connection.query(sql, params)
12
+ }
13
+
14
+
15
+ static Model = Model;
16
+ static QueryBuilder = QueryBuilder;
17
+ }
18
+
19
+
20
+ export default Dynamo;
@@ -0,0 +1,6 @@
1
+
2
+ import LiveCurrent from "./LiveCurrent.js";
3
+
4
+ const Live = new LiveCurrent('Server.js')
5
+
6
+ Live.boot()
@@ -0,0 +1,38 @@
1
+ import fs from 'fs/promises'
2
+ import { spawn } from 'child_process'
3
+ import chalk from 'chalk'
4
+ class LiveCurrent{
5
+ constructor(entryPoint){
6
+ this.entryPoint = entryPoint;
7
+ this.process = null;
8
+ }
9
+
10
+ boot(){
11
+ this.watch()
12
+ this.ignite()
13
+ }
14
+
15
+ ignite(){
16
+ this.process= spawn('node', [this.entryPoint], {stdio: 'inherit'});
17
+ console.log(chalk.greenBright(`LiveCurrent: Iniciando Servidor...`));
18
+ }
19
+ reload(){
20
+ if(this.process){
21
+ this.process.kill()
22
+ this.ignite()
23
+ }
24
+ }
25
+
26
+ watch(){
27
+ fs.watch(process.cwd(), {recursive: true}, (eventType, filename) => {
28
+ if(filename.includes('node_modules') || filename === ''){
29
+ return
30
+ }
31
+ this.reload()
32
+ })
33
+ }
34
+
35
+ }
36
+
37
+
38
+ export default LiveCurrent;
package/index.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Tesla Framework - Main Export
3
+ *
4
+ * Punto de entrada principal del framework
5
+ */
6
+
7
+ // Core
8
+ export { default as Tesla } from './core/Core.js';
9
+ export { default as Remote } from './core/Remote.js';
10
+
11
+ // Middlewares
12
+ export { default as Shadowgraph } from './middlewares/Shadowgraph.js';
13
+ export { default as Teleforce } from './middlewares/Teleforce.js';
14
+ export { default as BlackBox } from './middlewares/BlackBox.js';
15
+ export { default as EasyCors } from './middlewares/EasyCors.js';
16
+ export { default as Insulator } from './middlewares/Insulator.js';
17
+
18
+ // Security
19
+ export { default as Coherer } from './security/Coherer.js';
20
+ export { default as Regulator } from './security/Regulator.js';
21
+
22
+ // Dev Tools
23
+ export { default as LiveCurrent } from './dev-tools/LiveCurrent.js';
24
+ export { default as DevRunner } from './dev-tools/DevRunner.js';
25
+
26
+ // Database (Dynamo ORM)
27
+ export { default as Dynamo } from './database/index.js';
28
+
29
+ // Default export (Tesla Core)
30
+ import Tesla from './core/Core.js';
31
+ export default Tesla;
@@ -0,0 +1,15 @@
1
+ import { error } from '../templates/error.js'
2
+ class BlackBox{
3
+ constructor(){
4
+
5
+ }
6
+
7
+ static ignite(err, req , res){
8
+
9
+ res.writeHead(500, {'Content-Type': 'text/html'})
10
+ res.end(error(err.message, err.stack))
11
+ }
12
+ }
13
+
14
+
15
+ export default BlackBox;
@@ -0,0 +1,19 @@
1
+
2
+
3
+ const EasyCors = (req, res, next) =>{
4
+ res.setHeader('Access-Control-Allow-Origin','*')
5
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH')
6
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
7
+
8
+ if(req.method === 'OPTIONS'){
9
+ res.statusCode = 204
10
+ res.end()
11
+ return;
12
+ }
13
+ else{
14
+ next()
15
+ }
16
+ }
17
+
18
+
19
+ export default EasyCors;
@@ -0,0 +1,24 @@
1
+
2
+ const Insulator = (schema) => {
3
+
4
+ return (req, res, next) => {
5
+ for (const key in schema) {
6
+ const expectedType = schema[key];
7
+ const value = req.body[key]
8
+ if (value === undefined) {
9
+ res.statusCode = 400;
10
+ res.end(`Falta campo: ${key}`)
11
+ return;
12
+ }
13
+ if (typeof value !== expectedType) {
14
+ res.statusCode = 400;
15
+ res.end(`El campo ${key} debe ser ${expectedType}`)
16
+ return;
17
+ }
18
+ }
19
+ next()
20
+ }
21
+ }
22
+
23
+
24
+ export default Insulator;
@@ -0,0 +1,13 @@
1
+ import chalk from 'chalk'
2
+
3
+ const Shadowgraph = (req, res, next) =>{
4
+ const inicio = Date.now()
5
+ res.on('finish', () =>{
6
+ const duracion = Date.now() - inicio
7
+ console.log(chalk.green(`[${req.method}] ${req.url} - ${res.statusCode} ${res.statusMessage} - ${duracion}ms`))
8
+ })
9
+ next()
10
+ }
11
+
12
+
13
+ export default Shadowgraph;
@@ -0,0 +1,11 @@
1
+
2
+
3
+ const Teleforce = (req, res, next) =>{
4
+ res.removeHeader('X-Powered-By');
5
+ res.setHeader('X-Content-Type-Options', 'nosniff')
6
+ res.setHeader('X-Frame-Options', 'Deny')
7
+ res.setHeader('X-XSS-Protection', '1')
8
+ next()
9
+ }
10
+
11
+ export default Teleforce;
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "nicola-framework",
3
+ "version": "1.0.0",
4
+ "description": "Zero-dependency web framework for Node.js",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./core": "./core/Core.js",
10
+ "./router": "./core/Remote.js",
11
+ "./middlewares/*": "./middlewares/*.js",
12
+ "./security/*": "./security/*.js",
13
+ "./database": "./database/index.js"
14
+ },
15
+ "scripts": {
16
+ "test": "echo \"Error: no test specified\" && exit 1"
17
+ },
18
+ "keywords": [
19
+ "framework",
20
+ "web",
21
+ "http",
22
+ "server",
23
+ "router",
24
+ "middleware",
25
+ "zero-dependency",
26
+ "orm"
27
+ ],
28
+ "author": "Your Name",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "chalk": "^5.6.2"
32
+ }
33
+ }
@@ -0,0 +1,53 @@
1
+ import crypto from 'crypto'
2
+ import Regulator from './Regulator.js';
3
+
4
+ class Coherer{
5
+ constructor(){
6
+
7
+ }
8
+ static SECRET = process.env.TESLA_SECRET || 'tesla_secret_dev_key'
9
+
10
+ static codec(jsonData){
11
+ const dataString = JSON.stringify(jsonData);
12
+ const buffer = Buffer.from(dataString);
13
+ return buffer.toString('base64url')
14
+ }
15
+
16
+ static sign(Payload){
17
+ const payloadB64 = this.codec(Payload);
18
+ const header = {
19
+ alg: 'HS256',
20
+ typ: 'JWT'
21
+ }
22
+ const headerB64 = this.codec(header)
23
+
24
+ const data = headerB64 + '.' + payloadB64
25
+
26
+ const signature = crypto.createHmac('sha256', this.SECRET)
27
+ .update(data)
28
+ .digest('base64url')
29
+
30
+ return data + '.' + signature
31
+ }
32
+ static verify(data){
33
+ const [headerB64, payloadB64, signature] = data.token.split('.');
34
+
35
+ const dataToCheck = headerB64 + '.' + payloadB64
36
+
37
+ const signatureToChecks = crypto.createHmac('sha256', this.SECRET)
38
+ .update(dataToCheck)
39
+ .digest('base64url')
40
+
41
+ if(signature === signatureToChecks){
42
+ let decodedPayload = Buffer.from(payloadB64, 'base64url').toString('utf-8')
43
+ decodedPayload = JSON.parse(decodedPayload)
44
+ return decodedPayload
45
+ }
46
+ else{
47
+ throw new Error('Token Invalido')
48
+ }
49
+ }
50
+ }
51
+
52
+
53
+ export default Coherer;
@@ -0,0 +1,38 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+
4
+
5
+ class Regulator{
6
+
7
+
8
+
9
+ static load(){
10
+ const CURRENT_DIR = path.join(process.cwd(), ".env")
11
+
12
+ if(fs.existsSync(CURRENT_DIR)){
13
+ const envFile= fs.readFileSync(CURRENT_DIR, 'utf-8');
14
+ let lineEnv = envFile.split('\n')
15
+ lineEnv.forEach(line => {
16
+ let lineClean = line.trim()
17
+ if(lineClean.length === 0 || lineClean.startsWith('#')){
18
+ return;
19
+ }
20
+ let index = lineClean.indexOf('=')
21
+ if(index === -1){
22
+ return;
23
+ }
24
+
25
+ let key = lineClean.substring(0, index);
26
+ let value = lineClean.substring(index + 1);
27
+
28
+ key = key.trim()
29
+ value = value.trim()
30
+
31
+ process.env[key] = value;
32
+ })
33
+ }
34
+
35
+ }
36
+ }
37
+
38
+ export default Regulator;
@@ -0,0 +1,36 @@
1
+
2
+
3
+ export const error = (message, stack) =>{
4
+
5
+ return `
6
+ <html>
7
+ <head>
8
+ <style>
9
+ body {
10
+ background-color: #111;
11
+ color: #fff;
12
+ font-family: monospace;
13
+ padding: 20px;
14
+ }
15
+ h1 {
16
+ color: #ff3333;
17
+ }
18
+ pre {
19
+ background: #222;
20
+ padding: 15px;
21
+ border-radius: 5px;
22
+ overflow-x: auto;
23
+ }
24
+ </style>
25
+ </head>
26
+ <body>
27
+ <div class = "error-box">
28
+ <h1> Reporte de Error </h1>
29
+ <h2>${message}</h2>
30
+ </div>
31
+ <h3> Reporte de Error </h3>
32
+ <pre>${stack}</pre>
33
+ </body>
34
+ </html>
35
+ `
36
+ }