@athenna/http 3.1.0 → 3.1.1
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/build/Commands/MakeControllerCommand.js +1 -1
- package/build/Commands/MakeInterceptorCommand.js +1 -1
- package/build/Commands/MakeMiddlewareCommand.js +1 -1
- package/build/Commands/MakeTerminatorCommand.js +1 -1
- package/build/Commands/RouteListCommand.d.ts +0 -4
- package/build/Commands/RouteListCommand.js +1 -18
- package/build/Handlers/HttpExceptionHandler.d.ts +0 -4
- package/build/Handlers/HttpExceptionHandler.js +4 -19
- package/build/Kernels/HttpKernel.d.ts +1 -1
- package/build/Kernels/HttpKernel.js +34 -38
- package/package.json +11 -1
|
@@ -26,7 +26,7 @@ export class MakeControllerCommand extends BaseCommand {
|
|
|
26
26
|
this.logger.simple('({bold,green} [ MAKING CONTROLLER ])\n');
|
|
27
27
|
const file = await this.generator
|
|
28
28
|
.path(Path.http(`Controllers/${this.name}.${Path.ext()}`))
|
|
29
|
-
.template('
|
|
29
|
+
.template('controller')
|
|
30
30
|
.setNameProperties(true)
|
|
31
31
|
.make();
|
|
32
32
|
this.logger.success(`Controller ({yellow} "${file.name}") successfully created.`);
|
|
@@ -26,7 +26,7 @@ export class MakeInterceptorCommand extends BaseCommand {
|
|
|
26
26
|
this.logger.simple('({bold,green} [ MAKING INTERCEPTOR ])\n');
|
|
27
27
|
const file = await this.generator
|
|
28
28
|
.path(Path.http(`Interceptors/${this.name}.${Path.ext()}`))
|
|
29
|
-
.template('
|
|
29
|
+
.template('interceptor')
|
|
30
30
|
.setNameProperties(true)
|
|
31
31
|
.make();
|
|
32
32
|
this.logger.success(`Interceptor ({yellow} "${file.name}") successfully created.`);
|
|
@@ -26,7 +26,7 @@ export class MakeMiddlewareCommand extends BaseCommand {
|
|
|
26
26
|
this.logger.simple('({bold,green} [ MAKING MIDDLEWARE ])\n');
|
|
27
27
|
const file = await this.generator
|
|
28
28
|
.path(Path.http(`Middlewares/${this.name}.${Path.ext()}`))
|
|
29
|
-
.template('
|
|
29
|
+
.template('middleware')
|
|
30
30
|
.setNameProperties(true)
|
|
31
31
|
.make();
|
|
32
32
|
this.logger.success(`Middleware ({yellow} "${file.name}") successfully created.`);
|
|
@@ -26,7 +26,7 @@ export class MakeTerminatorCommand extends BaseCommand {
|
|
|
26
26
|
this.logger.simple('({bold,green} [ MAKING TERMINATOR ])\n');
|
|
27
27
|
const file = await this.generator
|
|
28
28
|
.path(Path.http(`Terminators/${this.name}.${Path.ext()}`))
|
|
29
|
-
.template('
|
|
29
|
+
.template('terminator')
|
|
30
30
|
.setNameProperties(true)
|
|
31
31
|
.make();
|
|
32
32
|
this.logger.success(`Terminator ({yellow} "${file.name}") successfully created.`);
|
|
@@ -12,8 +12,4 @@ export declare class RouteListCommand extends BaseCommand {
|
|
|
12
12
|
static signature(): string;
|
|
13
13
|
static description(): string;
|
|
14
14
|
handle(): Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* Resolve the import path by meta URL and import it.
|
|
17
|
-
*/
|
|
18
|
-
private resolveRoutePathAndImport;
|
|
19
15
|
}
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
* For the full copyright and license information, please view the LICENSE
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
|
-
import { resolve } from 'node:path';
|
|
10
|
-
import { pathToFileURL } from 'node:url';
|
|
11
9
|
import { Config } from '@athenna/config';
|
|
12
10
|
import { Module } from '@athenna/common';
|
|
13
11
|
import { BaseCommand } from '@athenna/artisan';
|
|
@@ -27,7 +25,7 @@ export class RouteListCommand extends BaseCommand {
|
|
|
27
25
|
const kernel = new HttpKernel();
|
|
28
26
|
await kernel.registerControllers();
|
|
29
27
|
await kernel.registerMiddlewares();
|
|
30
|
-
await this.
|
|
28
|
+
await Module.resolve(this.routeFilePath, Config.get('rc.meta'));
|
|
31
29
|
const routes = Route.list();
|
|
32
30
|
const table = this.logger.table();
|
|
33
31
|
table.head('Methods', 'Route', 'Name', 'Handler');
|
|
@@ -44,19 +42,4 @@ export class RouteListCommand extends BaseCommand {
|
|
|
44
42
|
});
|
|
45
43
|
table.render();
|
|
46
44
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Resolve the import path by meta URL and import it.
|
|
49
|
-
*/
|
|
50
|
-
resolveRoutePathAndImport() {
|
|
51
|
-
if (this.routeFilePath.includes('./') ||
|
|
52
|
-
this.routeFilePath.includes('../')) {
|
|
53
|
-
this.routeFilePath = resolve(this.routeFilePath);
|
|
54
|
-
}
|
|
55
|
-
if (!this.routeFilePath.startsWith('#')) {
|
|
56
|
-
this.routeFilePath = pathToFileURL(this.routeFilePath).href;
|
|
57
|
-
}
|
|
58
|
-
return import.meta
|
|
59
|
-
.resolve(this.routeFilePath, Config.get('rc.meta'))
|
|
60
|
-
.then(meta => Module.get(import(meta)));
|
|
61
|
-
}
|
|
62
45
|
}
|
|
@@ -24,8 +24,4 @@ export declare class HttpExceptionHandler {
|
|
|
24
24
|
* Return a boolean indicating if the error can be logged or not.
|
|
25
25
|
*/
|
|
26
26
|
private canBeLogged;
|
|
27
|
-
/**
|
|
28
|
-
* Returns a boolean indicating if the error is an internal server error.
|
|
29
|
-
*/
|
|
30
|
-
private isInternalServerError;
|
|
31
27
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
9
|
import { Log } from '@athenna/logger';
|
|
10
|
-
import { String } from '@athenna/common';
|
|
10
|
+
import { Is, String } from '@athenna/common';
|
|
11
11
|
export class HttpExceptionHandler {
|
|
12
12
|
/**
|
|
13
13
|
* Error codes that should be ignored from logging.
|
|
@@ -35,7 +35,7 @@ export class HttpExceptionHandler {
|
|
|
35
35
|
if (error.help) {
|
|
36
36
|
body.help = error.help;
|
|
37
37
|
}
|
|
38
|
-
const isInternalServerError =
|
|
38
|
+
const isInternalServerError = Is.Error(error) && !Is.Exception(error);
|
|
39
39
|
const isDebugMode = Config.is('app.debug', true);
|
|
40
40
|
if (isInternalServerError && !isDebugMode) {
|
|
41
41
|
body.code = 'E_INTERNAL_SERVER';
|
|
@@ -47,10 +47,10 @@ export class HttpExceptionHandler {
|
|
|
47
47
|
if (!this.canBeLogged(error)) {
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
if (!error
|
|
50
|
+
if (!Is.Exception(error)) {
|
|
51
51
|
error = error.toAthennaException();
|
|
52
52
|
}
|
|
53
|
-
Log.channelOrVanilla('exception').error(
|
|
53
|
+
Log.channelOrVanilla('exception').error(await error.prettify());
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Return a boolean indicating if the error can be logged or not.
|
|
@@ -64,19 +64,4 @@ export class HttpExceptionHandler {
|
|
|
64
64
|
}
|
|
65
65
|
return true;
|
|
66
66
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Returns a boolean indicating if the error is an internal server error.
|
|
69
|
-
*/
|
|
70
|
-
isInternalServerError(error) {
|
|
71
|
-
return [
|
|
72
|
-
'Error',
|
|
73
|
-
'URIError',
|
|
74
|
-
'TypeError',
|
|
75
|
-
'EvalError',
|
|
76
|
-
'RangeError',
|
|
77
|
-
'SyntaxError',
|
|
78
|
-
'InternalError',
|
|
79
|
-
'ReferenceError',
|
|
80
|
-
].includes(error.name);
|
|
81
|
-
}
|
|
82
67
|
}
|
|
@@ -8,60 +8,64 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import 'reflect-metadata';
|
|
10
10
|
import { Server } from '#src';
|
|
11
|
-
import { resolve } from 'node:path';
|
|
12
11
|
import { Log } from '@athenna/logger';
|
|
13
|
-
import { pathToFileURL } from 'node:url';
|
|
14
12
|
import { Config } from '@athenna/config';
|
|
15
|
-
import { Is, Module } from '@athenna/common';
|
|
13
|
+
import { Exec, Is, Module } from '@athenna/common';
|
|
16
14
|
import { HttpExceptionHandler } from '#src/Handlers/HttpExceptionHandler';
|
|
15
|
+
const corsPlugin = await Module.safeImport('@fastify/cors');
|
|
16
|
+
const helmetPlugin = await Module.safeImport('@fastify/helmet');
|
|
17
|
+
const swaggerPlugin = await Module.safeImport('@fastify/swagger');
|
|
18
|
+
const swaggerUiPlugin = await Module.safeImport('@fastify/swagger-ui');
|
|
19
|
+
const rateLimitPlugin = await Module.safeImport('@fastify/rate-limit');
|
|
20
|
+
const rTracerPlugin = await Module.safeImport('cls-rtracer');
|
|
17
21
|
export class HttpKernel {
|
|
18
22
|
/**
|
|
19
23
|
* Register the @fastify/cors plugin in the Http server.
|
|
20
24
|
*/
|
|
21
25
|
async registerCors() {
|
|
22
|
-
if (!
|
|
26
|
+
if (!corsPlugin) {
|
|
23
27
|
return;
|
|
24
28
|
}
|
|
25
|
-
await Server.plugin(
|
|
29
|
+
await Server.plugin(corsPlugin, Config.get('http.cors'));
|
|
26
30
|
}
|
|
27
31
|
/**
|
|
28
32
|
* Register the @fastify/helmet plugin in the Http server.
|
|
29
33
|
*/
|
|
30
34
|
async registerHelmet() {
|
|
31
|
-
if (!
|
|
35
|
+
if (!helmetPlugin) {
|
|
32
36
|
return;
|
|
33
37
|
}
|
|
34
|
-
await Server.plugin(
|
|
38
|
+
await Server.plugin(helmetPlugin, Config.get('http.helmet'));
|
|
35
39
|
}
|
|
36
40
|
/**
|
|
37
41
|
* Register the @fastify/swagger plugin in the Http server.
|
|
38
42
|
*/
|
|
39
43
|
async registerSwagger() {
|
|
40
|
-
if (
|
|
41
|
-
|
|
44
|
+
if (swaggerPlugin) {
|
|
45
|
+
await Server.plugin(swaggerPlugin, Config.get('http.swagger.configurations'));
|
|
46
|
+
}
|
|
47
|
+
if (swaggerUiPlugin) {
|
|
48
|
+
await Server.plugin(swaggerUiPlugin, Config.get('http.swagger.ui'));
|
|
42
49
|
}
|
|
43
|
-
await Server.plugin(import('@fastify/swagger'), Config.get('http.swagger.configurations'));
|
|
44
|
-
await Server.plugin(import('@fastify/swagger-ui'), Config.get('http.swagger.ui'));
|
|
45
50
|
}
|
|
46
51
|
/**
|
|
47
52
|
* Register the @fastify/rate-limit plugin in the Http server.
|
|
48
53
|
*/
|
|
49
54
|
async registerRateLimit() {
|
|
50
|
-
if (!
|
|
55
|
+
if (!rateLimitPlugin) {
|
|
51
56
|
return;
|
|
52
57
|
}
|
|
53
|
-
await Server.plugin(
|
|
58
|
+
await Server.plugin(rateLimitPlugin, Config.get('http.rateLimit'));
|
|
54
59
|
}
|
|
55
60
|
/**
|
|
56
61
|
* Register the cls-rtracer plugin in the Http server.
|
|
57
62
|
*/
|
|
58
63
|
async registerRTracer() {
|
|
59
|
-
if (!
|
|
64
|
+
if (!rTracerPlugin) {
|
|
60
65
|
return;
|
|
61
66
|
}
|
|
62
|
-
|
|
63
|
-
Server.
|
|
64
|
-
await Server.plugin(rTracer.fastifyPlugin, Config.get('http.rTracer'));
|
|
67
|
+
Server.middleware(async (ctx) => (ctx.data.traceId = rTracerPlugin.id()));
|
|
68
|
+
await Server.plugin(rTracerPlugin.fastifyPlugin, Config.get('http.rTracer'));
|
|
65
69
|
}
|
|
66
70
|
/**
|
|
67
71
|
* Register the global log terminator in the Http server.
|
|
@@ -78,15 +82,15 @@ export class HttpKernel {
|
|
|
78
82
|
*/
|
|
79
83
|
async registerControllers() {
|
|
80
84
|
const controllers = Config.get('rc.controllers', []);
|
|
81
|
-
|
|
85
|
+
await Exec.concurrently(controllers, async (path) => {
|
|
86
|
+
const Controller = await this.resolvePath(path);
|
|
82
87
|
if (Reflect.hasMetadata('provider:registered', Controller)) {
|
|
83
88
|
return;
|
|
84
89
|
}
|
|
85
90
|
const createCamelAlias = false;
|
|
86
91
|
const alias = `App/Http/Controllers/${Controller.name}`;
|
|
87
92
|
ioc.bind(alias, Controller, createCamelAlias);
|
|
88
|
-
})
|
|
89
|
-
await Promise.all(promises);
|
|
93
|
+
});
|
|
90
94
|
}
|
|
91
95
|
/**
|
|
92
96
|
* Register all the middlewares found inside "rc.middlewares" config
|
|
@@ -97,7 +101,7 @@ export class HttpKernel {
|
|
|
97
101
|
await this.registerNamedMiddlewares();
|
|
98
102
|
await this.registerGlobalMiddlewares();
|
|
99
103
|
if (Config.exists('rc.middlewares')) {
|
|
100
|
-
await
|
|
104
|
+
await Exec.concurrently(Config.get('rc.middlewares'), this.resolvePath);
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
/**
|
|
@@ -109,15 +113,15 @@ export class HttpKernel {
|
|
|
109
113
|
if (Is.Empty(namedMiddlewares)) {
|
|
110
114
|
return;
|
|
111
115
|
}
|
|
112
|
-
|
|
116
|
+
await Exec.concurrently(Object.keys(namedMiddlewares), async (key) => {
|
|
117
|
+
const Middleware = await this.resolvePath(namedMiddlewares[key]);
|
|
113
118
|
if (Reflect.hasMetadata('provider:registered', Middleware)) {
|
|
114
119
|
return;
|
|
115
120
|
}
|
|
116
121
|
const createCamelAlias = false;
|
|
117
122
|
const { alias, namedAlias } = this.getNamedMiddlewareAlias(key, Middleware);
|
|
118
123
|
ioc.bind(alias, Middleware, createCamelAlias).alias(namedAlias, alias);
|
|
119
|
-
})
|
|
120
|
-
await Promise.all(promises);
|
|
124
|
+
});
|
|
121
125
|
}
|
|
122
126
|
/**
|
|
123
127
|
* Register all the named middlewares found inside "rc.globalMiddlewares"
|
|
@@ -128,7 +132,8 @@ export class HttpKernel {
|
|
|
128
132
|
if (Is.Empty(globalMiddlewares)) {
|
|
129
133
|
return;
|
|
130
134
|
}
|
|
131
|
-
|
|
135
|
+
await Exec.concurrently(globalMiddlewares, async (path) => {
|
|
136
|
+
const Middleware = await this.resolvePath(path);
|
|
132
137
|
if (Reflect.hasMetadata('provider:registered', Middleware)) {
|
|
133
138
|
return;
|
|
134
139
|
}
|
|
@@ -136,8 +141,7 @@ export class HttpKernel {
|
|
|
136
141
|
const { alias, handler, serverMethod } = this.getGlobalMiddlewareAliasAndHandler(Middleware);
|
|
137
142
|
ioc.bind(alias, Middleware, createCamelAlias);
|
|
138
143
|
Server[serverMethod](ioc.safeUse(alias)[handler]);
|
|
139
|
-
})
|
|
140
|
-
await Promise.all(promises);
|
|
144
|
+
});
|
|
141
145
|
}
|
|
142
146
|
/**
|
|
143
147
|
* Register the exception handler for all request handlers.
|
|
@@ -148,7 +152,7 @@ export class HttpKernel {
|
|
|
148
152
|
Server.setErrorHandler(handler.handle.bind(handler));
|
|
149
153
|
return;
|
|
150
154
|
}
|
|
151
|
-
const Handler = await this.
|
|
155
|
+
const Handler = await this.resolvePath(path);
|
|
152
156
|
const handler = new Handler();
|
|
153
157
|
Server.setErrorHandler(handler.handle.bind(handler));
|
|
154
158
|
}
|
|
@@ -207,15 +211,7 @@ export class HttpKernel {
|
|
|
207
211
|
/**
|
|
208
212
|
* Resolve the import path by meta URL and import it.
|
|
209
213
|
*/
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
path = resolve(path);
|
|
213
|
-
}
|
|
214
|
-
if (!path.startsWith('#')) {
|
|
215
|
-
path = pathToFileURL(path).href;
|
|
216
|
-
}
|
|
217
|
-
return import.meta
|
|
218
|
-
.resolve(path, Config.get('rc.meta'))
|
|
219
|
-
.then(meta => Module.get(import(`${meta}?version=${Math.random()}`)));
|
|
214
|
+
resolvePath(path) {
|
|
215
|
+
return Module.resolve(`${path}?version=${Math.random()}`, Config.get('rc.meta'));
|
|
220
216
|
}
|
|
221
217
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@athenna/http",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "The Athenna Http server. Built on top of fastify.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "João Lenon <lenon@athenna.io>",
|
|
@@ -213,6 +213,16 @@
|
|
|
213
213
|
}
|
|
214
214
|
},
|
|
215
215
|
"athenna": {
|
|
216
|
+
"view": {
|
|
217
|
+
"disks": {},
|
|
218
|
+
"templates": {
|
|
219
|
+
"controller": "./templates/controller.edge",
|
|
220
|
+
"interceptor": "./templates/interceptor.edge",
|
|
221
|
+
"middleware": "./templates/middleware.edge",
|
|
222
|
+
"terminator": "./templates/terminator.edge",
|
|
223
|
+
"command": "@athenna/artisan/templates/command.edge"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
216
226
|
"preloads": [],
|
|
217
227
|
"services": [],
|
|
218
228
|
"providers": [],
|