@riktajs/core 0.4.7 → 0.6.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/dist/core/config/abstract-config-provider.js +1 -1
- package/dist/core/decorators/param.decorator.js +1 -1
- package/dist/core/exceptions/validation.exception.d.ts +2 -4
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/middleware/index.d.ts +3 -0
- package/dist/core/middleware/index.js +9 -0
- package/dist/core/middleware/middleware.decorator.d.ts +2 -0
- package/dist/core/middleware/middleware.decorator.js +10 -0
- package/dist/core/middleware/rikta-middleware.interface.d.ts +5 -0
- package/dist/core/middleware/rikta-middleware.interface.js +2 -0
- package/dist/core/middleware/use-middleware.decorator.d.ts +6 -0
- package/dist/core/middleware/use-middleware.decorator.js +26 -0
- package/dist/core/router/router.d.ts +3 -0
- package/dist/core/router/router.js +52 -35
- package/package.json +2 -2
|
@@ -7,7 +7,7 @@ const env_loader_1 = require("./env-loader");
|
|
|
7
7
|
class ConfigValidationException extends Error {
|
|
8
8
|
errors;
|
|
9
9
|
constructor(errors, providerName) {
|
|
10
|
-
const errorMessages = errors.
|
|
10
|
+
const errorMessages = errors.issues
|
|
11
11
|
.map(err => ` - ${err.path.join('.')}: ${err.message}`)
|
|
12
12
|
.join('\n');
|
|
13
13
|
super(`Configuration validation failed for ${providerName}:\n${errorMessages}\n\n` +
|
|
@@ -6,7 +6,7 @@ const constants_1 = require("../constants");
|
|
|
6
6
|
function isZodType(value) {
|
|
7
7
|
return (value !== null &&
|
|
8
8
|
typeof value === 'object' &&
|
|
9
|
-
'_def' in value &&
|
|
9
|
+
('_zod' in value || '_def' in value) &&
|
|
10
10
|
'safeParse' in value &&
|
|
11
11
|
typeof value.safeParse === 'function');
|
|
12
12
|
}
|
|
@@ -12,8 +12,6 @@ export declare class ValidationException extends HttpException {
|
|
|
12
12
|
readonly errors: ValidationErrorDetails[];
|
|
13
13
|
constructor(zodError: ZodError, message?: string);
|
|
14
14
|
getValidationErrors(): ValidationErrorDetails[];
|
|
15
|
-
getFlattenedErrors(): import("zod").
|
|
16
|
-
getFormattedErrors():
|
|
17
|
-
_errors: string[];
|
|
18
|
-
};
|
|
15
|
+
getFlattenedErrors(): import("zod").ZodFlattenedError<unknown, string>;
|
|
16
|
+
getFormattedErrors(): import("zod").ZodFormattedError<unknown, string>;
|
|
19
17
|
}
|
package/dist/core/index.d.ts
CHANGED
package/dist/core/index.js
CHANGED
|
@@ -26,6 +26,7 @@ __exportStar(require("./application"), exports);
|
|
|
26
26
|
__exportStar(require("./decorators"), exports);
|
|
27
27
|
__exportStar(require("./exceptions"), exports);
|
|
28
28
|
__exportStar(require("./guards"), exports);
|
|
29
|
+
__exportStar(require("./middleware"), exports);
|
|
29
30
|
__exportStar(require("./config"), exports);
|
|
30
31
|
__exportStar(require("./metadata"), exports);
|
|
31
32
|
var zod_1 = require("zod");
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { Middleware } from './middleware.decorator';
|
|
2
|
+
export { RiktaMiddleware, NextFunction } from './rikta-middleware.interface';
|
|
3
|
+
export { UseMiddleware, getMiddlewareMetadata, getMiddlewareMetadata as getMiddlewaresMetadata, MiddlewareClass } from './use-middleware.decorator';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMiddlewaresMetadata = exports.getMiddlewareMetadata = exports.UseMiddleware = exports.Middleware = void 0;
|
|
4
|
+
var middleware_decorator_1 = require("./middleware.decorator");
|
|
5
|
+
Object.defineProperty(exports, "Middleware", { enumerable: true, get: function () { return middleware_decorator_1.Middleware; } });
|
|
6
|
+
var use_middleware_decorator_1 = require("./use-middleware.decorator");
|
|
7
|
+
Object.defineProperty(exports, "UseMiddleware", { enumerable: true, get: function () { return use_middleware_decorator_1.UseMiddleware; } });
|
|
8
|
+
Object.defineProperty(exports, "getMiddlewareMetadata", { enumerable: true, get: function () { return use_middleware_decorator_1.getMiddlewareMetadata; } });
|
|
9
|
+
Object.defineProperty(exports, "getMiddlewaresMetadata", { enumerable: true, get: function () { return use_middleware_decorator_1.getMiddlewareMetadata; } });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Middleware = Middleware;
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
function Middleware() {
|
|
6
|
+
return (target) => {
|
|
7
|
+
Reflect.defineMetadata('middleware', true, target);
|
|
8
|
+
Reflect.defineMetadata('injectable', true, target);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import type { Constructor } from '../types';
|
|
3
|
+
import type { RiktaMiddleware } from './rikta-middleware.interface';
|
|
4
|
+
export type MiddlewareClass = Constructor<RiktaMiddleware>;
|
|
5
|
+
export declare function UseMiddleware(...middleware: MiddlewareClass[]): ClassDecorator & MethodDecorator;
|
|
6
|
+
export declare function getMiddlewareMetadata(target: Constructor, propertyKey?: string | symbol): MiddlewareClass[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UseMiddleware = UseMiddleware;
|
|
4
|
+
exports.getMiddlewareMetadata = getMiddlewareMetadata;
|
|
5
|
+
require("reflect-metadata");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
7
|
+
function UseMiddleware(...middleware) {
|
|
8
|
+
return (target, propertyKey) => {
|
|
9
|
+
if (propertyKey !== undefined) {
|
|
10
|
+
const existingMiddleware = Reflect.getMetadata(constants_1.MIDDLEWARE_METADATA, target.constructor, propertyKey) ?? [];
|
|
11
|
+
Reflect.defineMetadata(constants_1.MIDDLEWARE_METADATA, [...existingMiddleware, ...middleware], target.constructor, propertyKey);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
const existingMiddleware = Reflect.getMetadata(constants_1.MIDDLEWARE_METADATA, target) ?? [];
|
|
15
|
+
Reflect.defineMetadata(constants_1.MIDDLEWARE_METADATA, [...existingMiddleware, ...middleware], target);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function getMiddlewareMetadata(target, propertyKey) {
|
|
20
|
+
const controllerMiddleware = Reflect.getMetadata(constants_1.MIDDLEWARE_METADATA, target) ?? [];
|
|
21
|
+
if (!propertyKey) {
|
|
22
|
+
return controllerMiddleware;
|
|
23
|
+
}
|
|
24
|
+
const methodMiddleware = Reflect.getMetadata(constants_1.MIDDLEWARE_METADATA, target, propertyKey) ?? [];
|
|
25
|
+
return [...controllerMiddleware, ...methodMiddleware];
|
|
26
|
+
}
|
|
@@ -7,6 +7,7 @@ export declare class Router {
|
|
|
7
7
|
private readonly container;
|
|
8
8
|
private readonly globalPrefix;
|
|
9
9
|
private readonly guardCache;
|
|
10
|
+
private readonly middlewareCache;
|
|
10
11
|
constructor(server: FastifyInstance, container: Container, globalPrefix?: string);
|
|
11
12
|
registerController(controllerClass: Constructor, silent?: boolean): void;
|
|
12
13
|
private registerRoute;
|
|
@@ -15,5 +16,7 @@ export declare class Router {
|
|
|
15
16
|
private resolveParamsOptimized;
|
|
16
17
|
private resolveGuardInstances;
|
|
17
18
|
private executeGuardsOptimized;
|
|
19
|
+
private resolveMiddlewareInstances;
|
|
20
|
+
private executeMiddlewareChain;
|
|
18
21
|
private buildPath;
|
|
19
22
|
}
|
|
@@ -7,11 +7,13 @@ const validation_exception_1 = require("../exceptions/validation.exception");
|
|
|
7
7
|
const exceptions_1 = require("../exceptions/exceptions");
|
|
8
8
|
const execution_context_1 = require("../guards/execution-context");
|
|
9
9
|
const use_guards_decorator_1 = require("../guards/use-guards.decorator");
|
|
10
|
+
const use_middleware_decorator_1 = require("../middleware/use-middleware.decorator");
|
|
10
11
|
class Router {
|
|
11
12
|
server;
|
|
12
13
|
container;
|
|
13
14
|
globalPrefix;
|
|
14
15
|
guardCache = new Map();
|
|
16
|
+
middlewareCache = new Map();
|
|
15
17
|
constructor(server, container, globalPrefix = '') {
|
|
16
18
|
this.server = server;
|
|
17
19
|
this.container = container;
|
|
@@ -38,47 +40,31 @@ class Router {
|
|
|
38
40
|
const paramsMeta = Reflect.getMetadata(constants_1.PARAM_METADATA, controllerClass, route.handlerName) ?? [];
|
|
39
41
|
const statusCode = Reflect.getMetadata(constants_1.HTTP_CODE_METADATA, controllerClass, route.handlerName);
|
|
40
42
|
const guards = (0, use_guards_decorator_1.getGuardsMetadata)(controllerClass, route.handlerName);
|
|
43
|
+
const middleware = (0, use_middleware_decorator_1.getMiddlewareMetadata)(controllerClass, route.handlerName);
|
|
41
44
|
const compiledResolvers = this.compileParamResolvers(paramsMeta);
|
|
42
45
|
const hasParams = compiledResolvers.length > 0;
|
|
43
46
|
const maxParamIndex = hasParams ? Math.max(...compiledResolvers.map(r => r.index)) : -1;
|
|
44
47
|
const guardInstances = this.resolveGuardInstances(guards);
|
|
45
48
|
const hasGuards = guardInstances.length > 0;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
routeHandler = async (_request, reply) => {
|
|
54
|
-
const result = await handler.call(controllerInstance);
|
|
55
|
-
if (statusCode)
|
|
56
|
-
reply.status(statusCode);
|
|
57
|
-
return result;
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
else if (!hasGuards) {
|
|
61
|
-
routeHandler = async (request, reply) => {
|
|
62
|
-
const args = this.resolveParamsOptimized(compiledResolvers, maxParamIndex, request, reply);
|
|
63
|
-
const result = await handler.apply(controllerInstance, args);
|
|
64
|
-
if (statusCode)
|
|
65
|
-
reply.status(statusCode);
|
|
66
|
-
return result;
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
const createContext = (req, rep) => new execution_context_1.ExecutionContextImpl(req, rep, controllerClass, route.handlerName);
|
|
71
|
-
routeHandler = async (request, reply) => {
|
|
49
|
+
const middlewareInstances = this.resolveMiddlewareInstances(middleware);
|
|
50
|
+
const hasMiddleware = middlewareInstances.length > 0;
|
|
51
|
+
const createContext = hasGuards
|
|
52
|
+
? (req, rep) => new execution_context_1.ExecutionContextImpl(req, rep, controllerClass, route.handlerName)
|
|
53
|
+
: null;
|
|
54
|
+
const routeHandler = async (request, reply) => {
|
|
55
|
+
if (createContext) {
|
|
72
56
|
await this.executeGuardsOptimized(guardInstances, createContext(request, reply));
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
57
|
+
}
|
|
58
|
+
if (hasMiddleware) {
|
|
59
|
+
await this.executeMiddlewareChain(middlewareInstances, request, reply);
|
|
60
|
+
}
|
|
61
|
+
const result = hasParams
|
|
62
|
+
? await handler.apply(controllerInstance, this.resolveParamsOptimized(compiledResolvers, maxParamIndex, request, reply))
|
|
63
|
+
: await handler.call(controllerInstance);
|
|
64
|
+
if (statusCode)
|
|
65
|
+
reply.status(statusCode);
|
|
66
|
+
return result;
|
|
67
|
+
};
|
|
82
68
|
const method = route.method.toLowerCase();
|
|
83
69
|
this.server[method](fullPath, routeHandler);
|
|
84
70
|
if (!silent)
|
|
@@ -179,6 +165,37 @@ class Router {
|
|
|
179
165
|
}
|
|
180
166
|
}
|
|
181
167
|
}
|
|
168
|
+
resolveMiddlewareInstances(middleware) {
|
|
169
|
+
return middleware.map(MiddlewareClass => {
|
|
170
|
+
let instance = this.middlewareCache.get(MiddlewareClass);
|
|
171
|
+
if (instance)
|
|
172
|
+
return instance;
|
|
173
|
+
try {
|
|
174
|
+
instance = this.container.resolve(MiddlewareClass);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
throw new Error(`Failed to resolve middleware ${MiddlewareClass.name}. ` +
|
|
178
|
+
`Make sure it is decorated with @Injectable(). ` +
|
|
179
|
+
`Original error: ${error instanceof Error ? error.message : String(error)}`);
|
|
180
|
+
}
|
|
181
|
+
if (typeof instance.use !== 'function') {
|
|
182
|
+
throw new Error(`${MiddlewareClass.name} does not implement RiktaMiddleware interface. ` +
|
|
183
|
+
`The middleware must have a use(req, res, next) method.`);
|
|
184
|
+
}
|
|
185
|
+
this.middlewareCache.set(MiddlewareClass, instance);
|
|
186
|
+
return instance;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async executeMiddlewareChain(middlewareInstances, request, reply) {
|
|
190
|
+
let index = 0;
|
|
191
|
+
const next = async () => {
|
|
192
|
+
if (index < middlewareInstances.length) {
|
|
193
|
+
const middleware = middlewareInstances[index++];
|
|
194
|
+
await middleware.use(request, reply, next);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
await next();
|
|
198
|
+
}
|
|
182
199
|
buildPath(controllerPrefix, routePath) {
|
|
183
200
|
const parts = [this.globalPrefix, controllerPrefix, routePath]
|
|
184
201
|
.filter(Boolean)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riktajs/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "A fast and modern TypeScript backend framework with zero-config autowiring, powered by Fastify",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"fast-glob": "3.3.3",
|
|
34
34
|
"fastify": "5.3.2",
|
|
35
35
|
"reflect-metadata": "0.2.2",
|
|
36
|
-
"zod": "3.
|
|
36
|
+
"zod": "4.3.5"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.10.2",
|