@riktajs/core 0.5.0 → 0.7.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/decorators/apply-decorators.d.ts +8 -0
- package/dist/core/decorators/apply-decorators.js +40 -0
- package/dist/core/decorators/create-param-decorator.d.ts +11 -0
- package/dist/core/decorators/create-param-decorator.js +26 -0
- package/dist/core/decorators/index.d.ts +2 -0
- package/dist/core/decorators/index.js +2 -0
- 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 +4 -1
- package/dist/core/router/router.js +81 -43
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
|
|
3
|
+
type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
|
|
4
|
+
type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
|
|
5
|
+
type AnyDecorator = ClassDecorator | MethodDecorator | PropertyDecorator;
|
|
6
|
+
export declare function applyDecorators(...decorators: AnyDecorator[]): MethodDecorator & ClassDecorator & PropertyDecorator;
|
|
7
|
+
export declare function SetMetadata<T = unknown>(key: string | symbol, value: T): MethodDecorator & ClassDecorator;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyDecorators = applyDecorators;
|
|
4
|
+
exports.SetMetadata = SetMetadata;
|
|
5
|
+
require("reflect-metadata");
|
|
6
|
+
function applyDecorators(...decorators) {
|
|
7
|
+
return ((target, propertyKey, descriptor) => {
|
|
8
|
+
for (const decorator of decorators.reverse()) {
|
|
9
|
+
if (descriptor) {
|
|
10
|
+
const result = decorator(target, propertyKey, descriptor);
|
|
11
|
+
if (result) {
|
|
12
|
+
descriptor = result;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
else if (propertyKey !== undefined) {
|
|
16
|
+
decorator(target, propertyKey);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
const result = decorator(target);
|
|
20
|
+
if (result) {
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (descriptor) {
|
|
26
|
+
return descriptor;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function SetMetadata(key, value) {
|
|
31
|
+
const decoratorFactory = (target, propertyKey, descriptor) => {
|
|
32
|
+
if (descriptor) {
|
|
33
|
+
Reflect.defineMetadata(key, value, target.constructor, propertyKey);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
Reflect.defineMetadata(key, value, target);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
return decoratorFactory;
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { ExecutionContext } from '../guards/execution-context';
|
|
3
|
+
export declare const CUSTOM_PARAM_METADATA: unique symbol;
|
|
4
|
+
export interface CustomParamMetadata<T = unknown> {
|
|
5
|
+
index: number;
|
|
6
|
+
factory: CustomParamFactory<T, unknown>;
|
|
7
|
+
data?: T;
|
|
8
|
+
}
|
|
9
|
+
export type CustomParamFactory<TData = unknown, TResult = unknown> = (data: TData, ctx: ExecutionContext) => TResult | Promise<TResult>;
|
|
10
|
+
export declare function createParamDecorator<TData = unknown, TResult = unknown>(factory: CustomParamFactory<TData, TResult>): (data?: TData) => ParameterDecorator;
|
|
11
|
+
export declare function getCustomParamMetadata<T = unknown>(target: Function, propertyKey: string | symbol): CustomParamMetadata<T>[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CUSTOM_PARAM_METADATA = void 0;
|
|
4
|
+
exports.createParamDecorator = createParamDecorator;
|
|
5
|
+
exports.getCustomParamMetadata = getCustomParamMetadata;
|
|
6
|
+
require("reflect-metadata");
|
|
7
|
+
exports.CUSTOM_PARAM_METADATA = Symbol.for('rikta:custom:param:metadata');
|
|
8
|
+
function createParamDecorator(factory) {
|
|
9
|
+
return (data) => {
|
|
10
|
+
return (target, propertyKey, parameterIndex) => {
|
|
11
|
+
if (propertyKey === undefined)
|
|
12
|
+
return;
|
|
13
|
+
const existingParams = Reflect.getMetadata(exports.CUSTOM_PARAM_METADATA, target.constructor, propertyKey) ?? [];
|
|
14
|
+
const metadata = {
|
|
15
|
+
index: parameterIndex,
|
|
16
|
+
factory: factory,
|
|
17
|
+
data,
|
|
18
|
+
};
|
|
19
|
+
existingParams.push(metadata);
|
|
20
|
+
Reflect.defineMetadata(exports.CUSTOM_PARAM_METADATA, existingParams, target.constructor, propertyKey);
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function getCustomParamMetadata(target, propertyKey) {
|
|
25
|
+
return Reflect.getMetadata(exports.CUSTOM_PARAM_METADATA, target, propertyKey) ?? [];
|
|
26
|
+
}
|
|
@@ -21,3 +21,5 @@ __exportStar(require("./param.decorator"), exports);
|
|
|
21
21
|
__exportStar(require("./autowired.decorator"), exports);
|
|
22
22
|
__exportStar(require("./provider.decorator"), exports);
|
|
23
23
|
__exportStar(require("./config-property.decorator"), exports);
|
|
24
|
+
__exportStar(require("./create-param-decorator"), exports);
|
|
25
|
+
__exportStar(require("./apply-decorators"), exports);
|
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,13 +7,16 @@ 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;
|
|
13
14
|
private compileParamResolvers;
|
|
14
15
|
private createParamExtractor;
|
|
15
|
-
private
|
|
16
|
+
private resolveAllParams;
|
|
16
17
|
private resolveGuardInstances;
|
|
17
18
|
private executeGuardsOptimized;
|
|
19
|
+
private resolveMiddlewareInstances;
|
|
20
|
+
private executeMiddlewareChain;
|
|
18
21
|
private buildPath;
|
|
19
22
|
}
|
|
@@ -3,15 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Router = void 0;
|
|
4
4
|
require("reflect-metadata");
|
|
5
5
|
const constants_1 = require("../constants");
|
|
6
|
+
const create_param_decorator_1 = require("../decorators/create-param-decorator");
|
|
6
7
|
const validation_exception_1 = require("../exceptions/validation.exception");
|
|
7
8
|
const exceptions_1 = require("../exceptions/exceptions");
|
|
8
9
|
const execution_context_1 = require("../guards/execution-context");
|
|
9
10
|
const use_guards_decorator_1 = require("../guards/use-guards.decorator");
|
|
11
|
+
const use_middleware_decorator_1 = require("../middleware/use-middleware.decorator");
|
|
10
12
|
class Router {
|
|
11
13
|
server;
|
|
12
14
|
container;
|
|
13
15
|
globalPrefix;
|
|
14
16
|
guardCache = new Map();
|
|
17
|
+
middlewareCache = new Map();
|
|
15
18
|
constructor(server, container, globalPrefix = '') {
|
|
16
19
|
this.server = server;
|
|
17
20
|
this.container = container;
|
|
@@ -36,49 +39,46 @@ class Router {
|
|
|
36
39
|
throw new Error(`Handler ${String(route.handlerName)} not found on ${controllerClass.name}`);
|
|
37
40
|
}
|
|
38
41
|
const paramsMeta = Reflect.getMetadata(constants_1.PARAM_METADATA, controllerClass, route.handlerName) ?? [];
|
|
42
|
+
const customParamsMeta = (0, create_param_decorator_1.getCustomParamMetadata)(controllerClass, route.handlerName);
|
|
39
43
|
const statusCode = Reflect.getMetadata(constants_1.HTTP_CODE_METADATA, controllerClass, route.handlerName);
|
|
40
44
|
const guards = (0, use_guards_decorator_1.getGuardsMetadata)(controllerClass, route.handlerName);
|
|
45
|
+
const middleware = (0, use_middleware_decorator_1.getMiddlewareMetadata)(controllerClass, route.handlerName);
|
|
41
46
|
const compiledResolvers = this.compileParamResolvers(paramsMeta);
|
|
42
|
-
const
|
|
43
|
-
const
|
|
47
|
+
const hasBuiltinParams = compiledResolvers.length > 0;
|
|
48
|
+
const hasCustomParams = customParamsMeta.length > 0;
|
|
49
|
+
const hasParams = hasBuiltinParams || hasCustomParams;
|
|
50
|
+
const allParamIndexes = [
|
|
51
|
+
...compiledResolvers.map(r => r.index),
|
|
52
|
+
...customParamsMeta.map(r => r.index)
|
|
53
|
+
];
|
|
54
|
+
const maxParamIndex = hasParams ? Math.max(...allParamIndexes) : -1;
|
|
44
55
|
const guardInstances = this.resolveGuardInstances(guards);
|
|
45
56
|
const hasGuards = guardInstances.length > 0;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
routeHandler = async (request, reply) => {
|
|
72
|
-
await this.executeGuardsOptimized(guardInstances, createContext(request, reply));
|
|
73
|
-
const args = hasParams
|
|
74
|
-
? this.resolveParamsOptimized(compiledResolvers, maxParamIndex, request, reply)
|
|
75
|
-
: [];
|
|
76
|
-
const result = await handler.apply(controllerInstance, args);
|
|
77
|
-
if (statusCode)
|
|
78
|
-
reply.status(statusCode);
|
|
79
|
-
return result;
|
|
80
|
-
};
|
|
81
|
-
}
|
|
57
|
+
const middlewareInstances = this.resolveMiddlewareInstances(middleware);
|
|
58
|
+
const hasMiddleware = middlewareInstances.length > 0;
|
|
59
|
+
const needsContext = hasGuards || hasCustomParams;
|
|
60
|
+
const createContext = needsContext
|
|
61
|
+
? (req, rep) => new execution_context_1.ExecutionContextImpl(req, rep, controllerClass, route.handlerName)
|
|
62
|
+
: null;
|
|
63
|
+
const routeHandler = async (request, reply) => {
|
|
64
|
+
const executionContext = createContext ? createContext(request, reply) : null;
|
|
65
|
+
if (hasGuards && executionContext) {
|
|
66
|
+
await this.executeGuardsOptimized(guardInstances, executionContext);
|
|
67
|
+
}
|
|
68
|
+
if (hasMiddleware) {
|
|
69
|
+
await this.executeMiddlewareChain(middlewareInstances, request, reply);
|
|
70
|
+
}
|
|
71
|
+
let args;
|
|
72
|
+
if (hasParams) {
|
|
73
|
+
args = await this.resolveAllParams(compiledResolvers, customParamsMeta, maxParamIndex, request, reply, executionContext);
|
|
74
|
+
}
|
|
75
|
+
const result = args
|
|
76
|
+
? await handler.apply(controllerInstance, args)
|
|
77
|
+
: await handler.call(controllerInstance);
|
|
78
|
+
if (statusCode)
|
|
79
|
+
reply.status(statusCode);
|
|
80
|
+
return result;
|
|
81
|
+
};
|
|
82
82
|
const method = route.method.toLowerCase();
|
|
83
83
|
this.server[method](fullPath, routeHandler);
|
|
84
84
|
if (!silent)
|
|
@@ -127,8 +127,8 @@ class Router {
|
|
|
127
127
|
return () => undefined;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
-
|
|
131
|
-
const
|
|
130
|
+
async resolveAllParams(compiledResolvers, customParams, maxIndex, request, reply, executionContext) {
|
|
131
|
+
const routeContext = {
|
|
132
132
|
request,
|
|
133
133
|
reply,
|
|
134
134
|
params: request.params,
|
|
@@ -136,9 +136,9 @@ class Router {
|
|
|
136
136
|
body: request.body,
|
|
137
137
|
};
|
|
138
138
|
const args = new Array(maxIndex + 1);
|
|
139
|
-
for (let i = 0; i <
|
|
140
|
-
const resolver =
|
|
141
|
-
let value = resolver.extract(
|
|
139
|
+
for (let i = 0; i < compiledResolvers.length; i++) {
|
|
140
|
+
const resolver = compiledResolvers[i];
|
|
141
|
+
let value = resolver.extract(routeContext);
|
|
142
142
|
if (resolver.zodSchema) {
|
|
143
143
|
const result = resolver.zodSchema.safeParse(value);
|
|
144
144
|
if (!result.success) {
|
|
@@ -148,6 +148,13 @@ class Router {
|
|
|
148
148
|
}
|
|
149
149
|
args[resolver.index] = value;
|
|
150
150
|
}
|
|
151
|
+
if (customParams.length > 0) {
|
|
152
|
+
const ctx = executionContext ?? new execution_context_1.ExecutionContextImpl(request, reply, {}, '');
|
|
153
|
+
for (const customParam of customParams) {
|
|
154
|
+
const value = await customParam.factory(customParam.data, ctx);
|
|
155
|
+
args[customParam.index] = value;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
151
158
|
return args;
|
|
152
159
|
}
|
|
153
160
|
resolveGuardInstances(guards) {
|
|
@@ -179,6 +186,37 @@ class Router {
|
|
|
179
186
|
}
|
|
180
187
|
}
|
|
181
188
|
}
|
|
189
|
+
resolveMiddlewareInstances(middleware) {
|
|
190
|
+
return middleware.map(MiddlewareClass => {
|
|
191
|
+
let instance = this.middlewareCache.get(MiddlewareClass);
|
|
192
|
+
if (instance)
|
|
193
|
+
return instance;
|
|
194
|
+
try {
|
|
195
|
+
instance = this.container.resolve(MiddlewareClass);
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
throw new Error(`Failed to resolve middleware ${MiddlewareClass.name}. ` +
|
|
199
|
+
`Make sure it is decorated with @Injectable(). ` +
|
|
200
|
+
`Original error: ${error instanceof Error ? error.message : String(error)}`);
|
|
201
|
+
}
|
|
202
|
+
if (typeof instance.use !== 'function') {
|
|
203
|
+
throw new Error(`${MiddlewareClass.name} does not implement RiktaMiddleware interface. ` +
|
|
204
|
+
`The middleware must have a use(req, res, next) method.`);
|
|
205
|
+
}
|
|
206
|
+
this.middlewareCache.set(MiddlewareClass, instance);
|
|
207
|
+
return instance;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
async executeMiddlewareChain(middlewareInstances, request, reply) {
|
|
211
|
+
let index = 0;
|
|
212
|
+
const next = async () => {
|
|
213
|
+
if (index < middlewareInstances.length) {
|
|
214
|
+
const middleware = middlewareInstances[index++];
|
|
215
|
+
await middleware.use(request, reply, next);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
await next();
|
|
219
|
+
}
|
|
182
220
|
buildPath(controllerPrefix, routePath) {
|
|
183
221
|
const parts = [this.globalPrefix, controllerPrefix, routePath]
|
|
184
222
|
.filter(Boolean)
|
package/package.json
CHANGED