@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.
@@ -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.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").typeToFlattenedError<any, string>;
16
- getFormattedErrors(): {
17
- _errors: string[];
18
- };
15
+ getFlattenedErrors(): import("zod").ZodFlattenedError<unknown, string>;
16
+ getFormattedErrors(): import("zod").ZodFormattedError<unknown, string>;
19
17
  }
@@ -9,6 +9,7 @@ export * from './application';
9
9
  export * from './decorators';
10
10
  export * from './exceptions';
11
11
  export * from './guards';
12
+ export * from './middleware';
12
13
  export * from './config';
13
14
  export * from './metadata';
14
15
  export { z } from 'zod';
@@ -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,2 @@
1
+ import 'reflect-metadata';
2
+ export declare function Middleware(): ClassDecorator;
@@ -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,5 @@
1
+ import type { FastifyRequest, FastifyReply } from 'fastify';
2
+ export type NextFunction = () => void | Promise<void>;
3
+ export interface RiktaMiddleware {
4
+ use(req: FastifyRequest, res: FastifyReply, next: NextFunction): void | Promise<void>;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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
- let routeHandler;
47
- if (!hasGuards && !hasParams && !statusCode) {
48
- routeHandler = async (_request, _reply) => {
49
- return handler.call(controllerInstance);
50
- };
51
- }
52
- else if (!hasGuards && !hasParams) {
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
- 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
+ }
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.4.7",
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.25.76"
36
+ "zod": "4.3.5"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.10.2",