@noony-serverless/core 0.2.2 → 0.3.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.
Files changed (42) hide show
  1. package/README.md +7 -7
  2. package/build/core/containerPool.d.ts +44 -0
  3. package/build/core/containerPool.js +100 -0
  4. package/build/core/core.d.ts +68 -17
  5. package/build/core/core.js +63 -2
  6. package/build/core/errors.d.ts +43 -0
  7. package/build/core/errors.js +74 -1
  8. package/build/core/handler.d.ts +16 -37
  9. package/build/core/handler.js +42 -131
  10. package/build/core/index.d.ts +1 -0
  11. package/build/core/index.js +1 -0
  12. package/build/index.d.ts +1 -0
  13. package/build/index.js +4 -0
  14. package/build/middlewares/authenticationMiddleware.d.ts +8 -6
  15. package/build/middlewares/authenticationMiddleware.js +4 -2
  16. package/build/middlewares/bodyParserMiddleware.d.ts +7 -5
  17. package/build/middlewares/bodyParserMiddleware.js +4 -2
  18. package/build/middlewares/bodyValidationMiddleware.d.ts +10 -12
  19. package/build/middlewares/bodyValidationMiddleware.js +7 -9
  20. package/build/middlewares/errorHandlerMiddleware.d.ts +8 -3
  21. package/build/middlewares/errorHandlerMiddleware.js +7 -0
  22. package/build/middlewares/guards/RouteGuards.d.ts +2 -2
  23. package/build/middlewares/guards/RouteGuards.js +2 -2
  24. package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +1 -1
  25. package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
  26. package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +10 -2
  27. package/build/middlewares/guards/guards/PermissionGuardFactory.js +1 -1
  28. package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
  29. package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
  30. package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
  31. package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
  32. package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
  33. package/build/middlewares/guards/services/FastUserContextService.d.ts +34 -10
  34. package/build/middlewares/index.d.ts +1 -3
  35. package/build/middlewares/index.js +1 -6
  36. package/build/middlewares/queryParametersMiddleware.d.ts +7 -3
  37. package/build/middlewares/queryParametersMiddleware.js +4 -0
  38. package/build/middlewares/responseWrapperMiddleware.d.ts +10 -4
  39. package/build/middlewares/responseWrapperMiddleware.js +6 -0
  40. package/build/middlewares/validationMiddleware.d.ts +154 -0
  41. package/build/middlewares/validationMiddleware.js +185 -0
  42. package/package.json +1 -3
@@ -412,7 +412,7 @@ class ExpressionPermissionResolver extends PermissionResolver_1.PermissionResolv
412
412
  * Check if this resolver can handle the given requirement type
413
413
  */
414
414
  canHandle(requirement) {
415
- return Boolean(requirement &&
415
+ return (requirement &&
416
416
  typeof requirement === 'object' &&
417
417
  PermissionResolver_1.PermissionUtils.isValidExpression(requirement));
418
418
  }
@@ -19,7 +19,7 @@
19
19
  * different types of permission requirements. The generic type T represents
20
20
  * the specific requirement format for each resolver.
21
21
  */
22
- export declare abstract class PermissionResolver<T = unknown> {
22
+ export declare abstract class PermissionResolver<T = any> {
23
23
  /**
24
24
  * Check if user permissions satisfy the requirement
25
25
  *
@@ -96,6 +96,6 @@ export declare class PlainPermissionResolver extends PermissionResolver<string[]
96
96
  * @param requirement - The requirement to check
97
97
  * @returns true if this resolver can handle the requirement
98
98
  */
99
- canHandle(requirement: unknown): requirement is string[];
99
+ canHandle(requirement: any): requirement is string[];
100
100
  }
101
101
  //# sourceMappingURL=PlainPermissionResolver.d.ts.map
@@ -141,6 +141,6 @@ export declare class WildcardPermissionResolver extends PermissionResolver<strin
141
141
  /**
142
142
  * Check if this resolver can handle the given requirement type
143
143
  */
144
- canHandle(requirement: unknown): requirement is string[];
144
+ canHandle(requirement: any): requirement is string[];
145
145
  }
146
146
  //# sourceMappingURL=WildcardPermissionResolver.d.ts.map
@@ -23,13 +23,14 @@
23
23
  * @version 1.0.0
24
24
  */
25
25
  import { CacheAdapter } from '../cache/CacheAdapter';
26
- import { GuardConfiguration } from '../config/GuardConfiguration';
26
+ import { GuardConfiguration, PermissionResolutionStrategy } from '../config/GuardConfiguration';
27
27
  import { PermissionRegistry } from '../registry/PermissionRegistry';
28
28
  import { PermissionResolverType, PermissionCheckResult, PermissionExpression } from '../resolvers/PermissionResolver';
29
29
  /**
30
30
  * Type alias for permission requirements that can be strings, string arrays, or complex expressions
31
+ * Note: Currently defined but reserved for future use
31
32
  */
32
- type PermissionRequirement = string | string[] | PermissionExpression | Record<string, unknown>;
33
+ export type PermissionRequirement = string | string[] | PermissionExpression | Record<string, unknown>;
33
34
  /**
34
35
  * User context with cached permissions and metadata
35
36
  */
@@ -37,7 +38,7 @@ export interface UserContext {
37
38
  userId: string;
38
39
  permissions: Set<string>;
39
40
  roles: string[];
40
- metadata: Record<string, unknown>;
41
+ metadata: Record<string, any>;
41
42
  expandedPermissions?: Set<string>;
42
43
  lastUpdated: string;
43
44
  expiresAt?: string;
@@ -52,7 +53,7 @@ export interface UserPermissionSource {
52
53
  getUserPermissions(userId: string): Promise<{
53
54
  permissions: string[];
54
55
  roles: string[];
55
- metadata?: Record<string, unknown>;
56
+ metadata?: Record<string, any>;
56
57
  } | null>;
57
58
  /**
58
59
  * Get role-based permissions for expansion
@@ -117,7 +118,7 @@ export declare class FastUserContextService {
117
118
  * @param options - Check options
118
119
  * @returns Detailed permission check result
119
120
  */
120
- checkPermission(userId: string, requirement: PermissionRequirement, options?: PermissionCheckOptions): Promise<PermissionCheckResult>;
121
+ checkPermission(userId: string, requirement: any, options?: PermissionCheckOptions): Promise<PermissionCheckResult>;
121
122
  /**
122
123
  * Batch check multiple permissions for a user
123
124
  *
@@ -130,7 +131,7 @@ export declare class FastUserContextService {
130
131
  * @returns Array of permission check results
131
132
  */
132
133
  checkPermissions(userId: string, requirements: Array<{
133
- requirement: PermissionRequirement;
134
+ requirement: any;
134
135
  resolverType?: PermissionResolverType;
135
136
  }>, options?: PermissionCheckOptions): Promise<PermissionCheckResult[]>;
136
137
  /**
@@ -165,9 +166,33 @@ export declare class FastUserContextService {
165
166
  averageResolutionTimeUs: number;
166
167
  totalResolutionTimeUs: number;
167
168
  resolverStats: {
168
- plain: Record<string, unknown>;
169
- wildcard: Record<string, unknown>;
170
- expression: Record<string, unknown>;
169
+ plain: {
170
+ checkCount: number;
171
+ averageResolutionTimeUs: number;
172
+ totalResolutionTimeUs: number;
173
+ };
174
+ wildcard: {
175
+ strategy: PermissionResolutionStrategy;
176
+ checkCount: number;
177
+ averageResolutionTimeUs: number;
178
+ totalResolutionTimeUs: number;
179
+ cacheHitRate: number;
180
+ cacheHits: number;
181
+ cacheMisses: number;
182
+ };
183
+ expression: {
184
+ checkCount: number;
185
+ averageResolutionTimeUs: number;
186
+ totalResolutionTimeUs: number;
187
+ cacheHitRate: number;
188
+ cacheHits: number;
189
+ cacheMisses: number;
190
+ complexityDistribution: {
191
+ simple: number;
192
+ moderate: number;
193
+ complex: number;
194
+ };
195
+ };
171
196
  };
172
197
  };
173
198
  /**
@@ -199,5 +224,4 @@ export declare class FastUserContextService {
199
224
  */
200
225
  private recordAuditTrail;
201
226
  }
202
- export {};
203
227
  //# sourceMappingURL=FastUserContextService.d.ts.map
@@ -1,6 +1,3 @@
1
- export * from './SecurityMiddleware';
2
- export * from './ConsolidatedValidationMiddleware';
3
- export * from './ProcessingMiddleware';
4
1
  export * from './authenticationMiddleware';
5
2
  export * from './bodyParserMiddleware';
6
3
  export * from './bodyValidationMiddleware';
@@ -13,5 +10,6 @@ export * from './rateLimitingMiddleware';
13
10
  export * from './responseWrapperMiddleware';
14
11
  export * from './securityAuditMiddleware';
15
12
  export * from './securityHeadersMiddleware';
13
+ export * from './validationMiddleware';
16
14
  export * from './guards';
17
15
  //# sourceMappingURL=index.d.ts.map
@@ -14,11 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- // === NEW CONSOLIDATED MIDDLEWARES ===
18
- __exportStar(require("./SecurityMiddleware"), exports);
19
- __exportStar(require("./ConsolidatedValidationMiddleware"), exports);
20
- __exportStar(require("./ProcessingMiddleware"), exports);
21
- // === EXISTING INDIVIDUAL MIDDLEWARES (for backward compatibility) ===
22
17
  __exportStar(require("./authenticationMiddleware"), exports);
23
18
  __exportStar(require("./bodyParserMiddleware"), exports);
24
19
  __exportStar(require("./bodyValidationMiddleware"), exports);
@@ -31,6 +26,6 @@ __exportStar(require("./rateLimitingMiddleware"), exports);
31
26
  __exportStar(require("./responseWrapperMiddleware"), exports);
32
27
  __exportStar(require("./securityAuditMiddleware"), exports);
33
28
  __exportStar(require("./securityHeadersMiddleware"), exports);
34
- // NOTE: validationMiddleware export removed due to naming conflict with new ValidationMiddleware
29
+ __exportStar(require("./validationMiddleware"), exports);
35
30
  __exportStar(require("./guards"), exports);
36
31
  //# sourceMappingURL=index.js.map
@@ -3,6 +3,8 @@ import { BaseMiddleware, Context } from '../core';
3
3
  * Middleware class that validates and processes query parameters from the request URL.
4
4
  * Extracts query parameters and validates that required parameters are present.
5
5
  *
6
+ * @template TBody - The type of the request body payload (preserves type chain)
7
+ * @template TUser - The type of the authenticated user (preserves type chain)
6
8
  * @implements {BaseMiddleware}
7
9
  *
8
10
  * @example
@@ -43,15 +45,17 @@ import { BaseMiddleware, Context } from '../core';
43
45
  * });
44
46
  * ```
45
47
  */
46
- export declare class QueryParametersMiddleware implements BaseMiddleware {
48
+ export declare class QueryParametersMiddleware<TBody = unknown, TUser = unknown> implements BaseMiddleware<TBody, TUser> {
47
49
  private readonly requiredParams;
48
50
  constructor(requiredParams?: string[]);
49
- before(context: Context): Promise<void>;
51
+ before(context: Context<TBody, TUser>): Promise<void>;
50
52
  }
51
53
  /**
52
54
  * Factory function that creates a query parameter processing middleware.
53
55
  * Extracts and validates query parameters from the request URL.
54
56
  *
57
+ * @template TBody - The type of the request body payload (preserves type chain)
58
+ * @template TUser - The type of the authenticated user (preserves type chain)
55
59
  * @param requiredParams - Array of parameter names that must be present (default: empty array)
56
60
  * @returns BaseMiddleware object with query parameter processing logic
57
61
  *
@@ -109,5 +113,5 @@ export declare class QueryParametersMiddleware implements BaseMiddleware {
109
113
  * });
110
114
  * ```
111
115
  */
112
- export declare const queryParametersMiddleware: (requiredParams?: string[]) => BaseMiddleware;
116
+ export declare const queryParametersMiddleware: <TBody = unknown, TUser = unknown>(requiredParams?: string[]) => BaseMiddleware<TBody, TUser>;
113
117
  //# sourceMappingURL=queryParametersMiddleware.d.ts.map
@@ -24,6 +24,8 @@ const convertQueryToRecord = (query) => {
24
24
  * Middleware class that validates and processes query parameters from the request URL.
25
25
  * Extracts query parameters and validates that required parameters are present.
26
26
  *
27
+ * @template TBody - The type of the request body payload (preserves type chain)
28
+ * @template TUser - The type of the authenticated user (preserves type chain)
27
29
  * @implements {BaseMiddleware}
28
30
  *
29
31
  * @example
@@ -84,6 +86,8 @@ exports.QueryParametersMiddleware = QueryParametersMiddleware;
84
86
  * Factory function that creates a query parameter processing middleware.
85
87
  * Extracts and validates query parameters from the request URL.
86
88
  *
89
+ * @template TBody - The type of the request body payload (preserves type chain)
90
+ * @template TUser - The type of the authenticated user (preserves type chain)
87
91
  * @param requiredParams - Array of parameter names that must be present (default: empty array)
88
92
  * @returns BaseMiddleware object with query parameter processing logic
89
93
  *
@@ -5,6 +5,8 @@ import { Context } from '../core/core';
5
5
  * Automatically wraps the response with success flag, payload, and timestamp.
6
6
  *
7
7
  * @template T - The type of response data being wrapped
8
+ * @template TBody - The type of the request body payload (preserves type chain)
9
+ * @template TUser - The type of the authenticated user (preserves type chain)
8
10
  * @implements {BaseMiddleware}
9
11
  *
10
12
  * @example
@@ -60,14 +62,16 @@ import { Context } from '../core/core';
60
62
  * });
61
63
  * ```
62
64
  */
63
- export declare class ResponseWrapperMiddleware<T> implements BaseMiddleware {
64
- after(context: Context): Promise<void>;
65
+ export declare class ResponseWrapperMiddleware<T = unknown, TBody = unknown, TUser = unknown> implements BaseMiddleware<TBody, TUser> {
66
+ after(context: Context<TBody, TUser>): Promise<void>;
65
67
  }
66
68
  /**
67
69
  * Factory function that creates a response wrapper middleware.
68
70
  * Automatically wraps response data in a standardized format with success flag and timestamp.
69
71
  *
70
72
  * @template T - The type of response data being wrapped
73
+ * @template TBody - The type of the request body payload (preserves type chain)
74
+ * @template TUser - The type of the authenticated user (preserves type chain)
71
75
  * @returns BaseMiddleware object with response wrapping logic
72
76
  *
73
77
  * @example
@@ -118,12 +122,14 @@ export declare class ResponseWrapperMiddleware<T> implements BaseMiddleware {
118
122
  * });
119
123
  * ```
120
124
  */
121
- export declare const responseWrapperMiddleware: <T>() => BaseMiddleware;
125
+ export declare const responseWrapperMiddleware: <T = unknown, TBody = unknown, TUser = unknown>() => BaseMiddleware<TBody, TUser>;
122
126
  /**
123
127
  * Helper function to set response data in context for later wrapping.
124
128
  * This function should be used in handlers when using ResponseWrapperMiddleware.
125
129
  *
126
130
  * @template T - The type of data being set
131
+ * @template TBody - The type of the request body payload (preserves type chain)
132
+ * @template TUser - The type of the authenticated user (preserves type chain)
127
133
  * @param context - The request context
128
134
  * @param data - The data to be included in the response payload
129
135
  *
@@ -176,5 +182,5 @@ export declare const responseWrapperMiddleware: <T>() => BaseMiddleware;
176
182
  * });
177
183
  * ```
178
184
  */
179
- export declare function setResponseData<T>(context: Context, data: T): void;
185
+ export declare function setResponseData<T, TBody = unknown, TUser = unknown>(context: Context<TBody, TUser>, data: T): void;
180
186
  //# sourceMappingURL=responseWrapperMiddleware.d.ts.map
@@ -18,6 +18,8 @@ const wrapResponse = (context) => {
18
18
  * Automatically wraps the response with success flag, payload, and timestamp.
19
19
  *
20
20
  * @template T - The type of response data being wrapped
21
+ * @template TBody - The type of the request body payload (preserves type chain)
22
+ * @template TUser - The type of the authenticated user (preserves type chain)
21
23
  * @implements {BaseMiddleware}
22
24
  *
23
25
  * @example
@@ -84,6 +86,8 @@ exports.ResponseWrapperMiddleware = ResponseWrapperMiddleware;
84
86
  * Automatically wraps response data in a standardized format with success flag and timestamp.
85
87
  *
86
88
  * @template T - The type of response data being wrapped
89
+ * @template TBody - The type of the request body payload (preserves type chain)
90
+ * @template TUser - The type of the authenticated user (preserves type chain)
87
91
  * @returns BaseMiddleware object with response wrapping logic
88
92
  *
89
93
  * @example
@@ -145,6 +149,8 @@ exports.responseWrapperMiddleware = responseWrapperMiddleware;
145
149
  * This function should be used in handlers when using ResponseWrapperMiddleware.
146
150
  *
147
151
  * @template T - The type of data being set
152
+ * @template TBody - The type of the request body payload (preserves type chain)
153
+ * @template TUser - The type of the authenticated user (preserves type chain)
148
154
  * @param context - The request context
149
155
  * @param data - The data to be included in the response payload
150
156
  *
@@ -0,0 +1,154 @@
1
+ import { BaseMiddleware, Context } from '../core';
2
+ import { z } from 'zod';
3
+ /**
4
+ * Middleware class that validates request data (body or query parameters) using Zod schemas.
5
+ * Automatically detects GET requests and validates query parameters, or validates body for other methods.
6
+ *
7
+ * @implements {BaseMiddleware}
8
+ *
9
+ * @example
10
+ * User registration validation:
11
+ * ```typescript
12
+ * import { z } from 'zod';
13
+ * import { Handler, ValidationMiddleware } from '@noony-serverless/core';
14
+ *
15
+ * const userRegistrationSchema = z.object({
16
+ * email: z.string().email(),
17
+ * password: z.string().min(8),
18
+ * firstName: z.string().min(1),
19
+ * lastName: z.string().min(1),
20
+ * age: z.number().int().min(18).max(120)
21
+ * });
22
+ *
23
+ * const registerHandler = new Handler()
24
+ * .use(bodyParser())
25
+ * .use(new ValidationMiddleware(userRegistrationSchema))
26
+ * .handle(async (context) => {
27
+ * const validatedUser = context.req.validatedBody;
28
+ * const newUser = await createUser(validatedUser);
29
+ * return { success: true, userId: newUser.id };
30
+ * });
31
+ * ```
32
+ *
33
+ * @example
34
+ * GET request query parameter validation:
35
+ * ```typescript
36
+ * const searchSchema = z.object({
37
+ * q: z.string().min(1),
38
+ * page: z.string().regex(/^\d+$/).transform(Number).default('1'),
39
+ * limit: z.string().regex(/^\d+$/).transform(Number).default('10'),
40
+ * category: z.string().optional()
41
+ * });
42
+ *
43
+ * const searchHandler = new Handler()
44
+ * .use(new ValidationMiddleware(searchSchema))
45
+ * .handle(async (context) => {
46
+ * const { q, page, limit, category } = context.req.query;
47
+ * const results = await searchItems(q, { page, limit, category });
48
+ * return { success: true, results, query: { q, page, limit, category } };
49
+ * });
50
+ * ```
51
+ *
52
+ * @example
53
+ * Product creation with nested validation:
54
+ * ```typescript
55
+ * const productSchema = z.object({
56
+ * name: z.string().min(1).max(100),
57
+ * description: z.string().max(1000),
58
+ * price: z.number().positive(),
59
+ * category: z.enum(['electronics', 'clothing', 'books', 'home']),
60
+ * specifications: z.record(z.string()),
61
+ * images: z.array(z.string().url()).max(5),
62
+ * inventory: z.object({
63
+ * inStock: z.boolean(),
64
+ * quantity: z.number().int().min(0),
65
+ * warehouse: z.string()
66
+ * })
67
+ * });
68
+ *
69
+ * const createProductHandler = new Handler()
70
+ * .use(bodyParser())
71
+ * .use(new ValidationMiddleware(productSchema))
72
+ * .handle(async (context) => {
73
+ * const productData = context.req.validatedBody;
74
+ * const product = await createProduct(productData);
75
+ * return { success: true, productId: product.id };
76
+ * });
77
+ * ```
78
+ */
79
+ export declare class ValidationMiddleware implements BaseMiddleware {
80
+ private readonly schema;
81
+ constructor(schema: z.ZodSchema);
82
+ before(context: Context): Promise<void>;
83
+ }
84
+ /**
85
+ * Factory function that creates a validation middleware using Zod schema.
86
+ * Automatically validates request body for non-GET requests or query parameters for GET requests.
87
+ *
88
+ * @param schema - Zod schema to validate against
89
+ * @returns BaseMiddleware object with validation logic
90
+ *
91
+ * @example
92
+ * Login endpoint validation:
93
+ * ```typescript
94
+ * import { z } from 'zod';
95
+ * import { Handler, validationMiddleware } from '@noony-serverless/core';
96
+ *
97
+ * const loginSchema = z.object({
98
+ * email: z.string().email(),
99
+ * password: z.string().min(1),
100
+ * rememberMe: z.boolean().optional()
101
+ * });
102
+ *
103
+ * const loginHandler = new Handler()
104
+ * .use(bodyParser())
105
+ * .use(validationMiddleware(loginSchema))
106
+ * .handle(async (context) => {
107
+ * const { email, password, rememberMe } = context.req.validatedBody;
108
+ * const token = await authenticate(email, password);
109
+ * return { success: true, token, rememberMe };
110
+ * });
111
+ * ```
112
+ *
113
+ * @example
114
+ * API filtering with query validation:
115
+ * ```typescript
116
+ * const filterSchema = z.object({
117
+ * status: z.enum(['active', 'inactive', 'pending']).optional(),
118
+ * sort: z.enum(['name', 'date', 'status']).default('name'),
119
+ * order: z.enum(['asc', 'desc']).default('asc'),
120
+ * limit: z.coerce.number().int().min(1).max(100).default(10)
121
+ * });
122
+ *
123
+ * const getItemsHandler = new Handler()
124
+ * .use(validationMiddleware(filterSchema))
125
+ * .handle(async (context) => {
126
+ * const filters = context.req.query;
127
+ * const items = await getFilteredItems(filters);
128
+ * return { success: true, items, appliedFilters: filters };
129
+ * });
130
+ * ```
131
+ *
132
+ * @example
133
+ * File upload validation:
134
+ * ```typescript
135
+ * const uploadSchema = z.object({
136
+ * filename: z.string().min(1),
137
+ * mimeType: z.string().regex(/^(image|document)\//),
138
+ * size: z.number().max(10 * 1024 * 1024), // 10MB max
139
+ * description: z.string().max(200).optional(),
140
+ * tags: z.array(z.string()).max(10).optional()
141
+ * });
142
+ *
143
+ * const uploadHandler = new Handler()
144
+ * .use(bodyParser())
145
+ * .use(validationMiddleware(uploadSchema))
146
+ * .handle(async (context) => {
147
+ * const fileData = context.req.validatedBody;
148
+ * const upload = await processFileUpload(fileData);
149
+ * return { success: true, fileId: upload.id };
150
+ * });
151
+ * ```
152
+ */
153
+ export declare const validationMiddleware: (schema: z.ZodSchema) => BaseMiddleware;
154
+ //# sourceMappingURL=validationMiddleware.d.ts.map
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validationMiddleware = exports.ValidationMiddleware = void 0;
4
+ const core_1 = require("../core");
5
+ const zod_1 = require("zod");
6
+ const validate = async (schema, context) => {
7
+ try {
8
+ const data = context.req.method === 'GET' ? context.req.query : context.req.parsedBody;
9
+ const validated = await schema.parseAsync(data);
10
+ if (context.req.method === 'GET') {
11
+ context.req.query = validated;
12
+ }
13
+ else {
14
+ context.req.validatedBody = validated;
15
+ }
16
+ }
17
+ catch (error) {
18
+ if (error instanceof zod_1.z.ZodError) {
19
+ throw new core_1.ValidationError('Validation error', JSON.stringify(error.issues));
20
+ }
21
+ throw error;
22
+ }
23
+ };
24
+ /**
25
+ * Middleware class that validates request data (body or query parameters) using Zod schemas.
26
+ * Automatically detects GET requests and validates query parameters, or validates body for other methods.
27
+ *
28
+ * @implements {BaseMiddleware}
29
+ *
30
+ * @example
31
+ * User registration validation:
32
+ * ```typescript
33
+ * import { z } from 'zod';
34
+ * import { Handler, ValidationMiddleware } from '@noony-serverless/core';
35
+ *
36
+ * const userRegistrationSchema = z.object({
37
+ * email: z.string().email(),
38
+ * password: z.string().min(8),
39
+ * firstName: z.string().min(1),
40
+ * lastName: z.string().min(1),
41
+ * age: z.number().int().min(18).max(120)
42
+ * });
43
+ *
44
+ * const registerHandler = new Handler()
45
+ * .use(bodyParser())
46
+ * .use(new ValidationMiddleware(userRegistrationSchema))
47
+ * .handle(async (context) => {
48
+ * const validatedUser = context.req.validatedBody;
49
+ * const newUser = await createUser(validatedUser);
50
+ * return { success: true, userId: newUser.id };
51
+ * });
52
+ * ```
53
+ *
54
+ * @example
55
+ * GET request query parameter validation:
56
+ * ```typescript
57
+ * const searchSchema = z.object({
58
+ * q: z.string().min(1),
59
+ * page: z.string().regex(/^\d+$/).transform(Number).default('1'),
60
+ * limit: z.string().regex(/^\d+$/).transform(Number).default('10'),
61
+ * category: z.string().optional()
62
+ * });
63
+ *
64
+ * const searchHandler = new Handler()
65
+ * .use(new ValidationMiddleware(searchSchema))
66
+ * .handle(async (context) => {
67
+ * const { q, page, limit, category } = context.req.query;
68
+ * const results = await searchItems(q, { page, limit, category });
69
+ * return { success: true, results, query: { q, page, limit, category } };
70
+ * });
71
+ * ```
72
+ *
73
+ * @example
74
+ * Product creation with nested validation:
75
+ * ```typescript
76
+ * const productSchema = z.object({
77
+ * name: z.string().min(1).max(100),
78
+ * description: z.string().max(1000),
79
+ * price: z.number().positive(),
80
+ * category: z.enum(['electronics', 'clothing', 'books', 'home']),
81
+ * specifications: z.record(z.string()),
82
+ * images: z.array(z.string().url()).max(5),
83
+ * inventory: z.object({
84
+ * inStock: z.boolean(),
85
+ * quantity: z.number().int().min(0),
86
+ * warehouse: z.string()
87
+ * })
88
+ * });
89
+ *
90
+ * const createProductHandler = new Handler()
91
+ * .use(bodyParser())
92
+ * .use(new ValidationMiddleware(productSchema))
93
+ * .handle(async (context) => {
94
+ * const productData = context.req.validatedBody;
95
+ * const product = await createProduct(productData);
96
+ * return { success: true, productId: product.id };
97
+ * });
98
+ * ```
99
+ */
100
+ class ValidationMiddleware {
101
+ schema;
102
+ constructor(schema) {
103
+ this.schema = schema;
104
+ }
105
+ async before(context) {
106
+ await validate(this.schema, context);
107
+ }
108
+ }
109
+ exports.ValidationMiddleware = ValidationMiddleware;
110
+ /**
111
+ * Factory function that creates a validation middleware using Zod schema.
112
+ * Automatically validates request body for non-GET requests or query parameters for GET requests.
113
+ *
114
+ * @param schema - Zod schema to validate against
115
+ * @returns BaseMiddleware object with validation logic
116
+ *
117
+ * @example
118
+ * Login endpoint validation:
119
+ * ```typescript
120
+ * import { z } from 'zod';
121
+ * import { Handler, validationMiddleware } from '@noony-serverless/core';
122
+ *
123
+ * const loginSchema = z.object({
124
+ * email: z.string().email(),
125
+ * password: z.string().min(1),
126
+ * rememberMe: z.boolean().optional()
127
+ * });
128
+ *
129
+ * const loginHandler = new Handler()
130
+ * .use(bodyParser())
131
+ * .use(validationMiddleware(loginSchema))
132
+ * .handle(async (context) => {
133
+ * const { email, password, rememberMe } = context.req.validatedBody;
134
+ * const token = await authenticate(email, password);
135
+ * return { success: true, token, rememberMe };
136
+ * });
137
+ * ```
138
+ *
139
+ * @example
140
+ * API filtering with query validation:
141
+ * ```typescript
142
+ * const filterSchema = z.object({
143
+ * status: z.enum(['active', 'inactive', 'pending']).optional(),
144
+ * sort: z.enum(['name', 'date', 'status']).default('name'),
145
+ * order: z.enum(['asc', 'desc']).default('asc'),
146
+ * limit: z.coerce.number().int().min(1).max(100).default(10)
147
+ * });
148
+ *
149
+ * const getItemsHandler = new Handler()
150
+ * .use(validationMiddleware(filterSchema))
151
+ * .handle(async (context) => {
152
+ * const filters = context.req.query;
153
+ * const items = await getFilteredItems(filters);
154
+ * return { success: true, items, appliedFilters: filters };
155
+ * });
156
+ * ```
157
+ *
158
+ * @example
159
+ * File upload validation:
160
+ * ```typescript
161
+ * const uploadSchema = z.object({
162
+ * filename: z.string().min(1),
163
+ * mimeType: z.string().regex(/^(image|document)\//),
164
+ * size: z.number().max(10 * 1024 * 1024), // 10MB max
165
+ * description: z.string().max(200).optional(),
166
+ * tags: z.array(z.string()).max(10).optional()
167
+ * });
168
+ *
169
+ * const uploadHandler = new Handler()
170
+ * .use(bodyParser())
171
+ * .use(validationMiddleware(uploadSchema))
172
+ * .handle(async (context) => {
173
+ * const fileData = context.req.validatedBody;
174
+ * const upload = await processFileUpload(fileData);
175
+ * return { success: true, fileId: upload.id };
176
+ * });
177
+ * ```
178
+ */
179
+ const validationMiddleware = (schema) => ({
180
+ before: async (context) => {
181
+ await validate(schema, context);
182
+ },
183
+ });
184
+ exports.validationMiddleware = validationMiddleware;
185
+ //# sourceMappingURL=validationMiddleware.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noony-serverless/core",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "A Middy base framework compatible with Firebase and GCP Cloud Functions with TypeScript",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -43,13 +43,11 @@
43
43
  "@google-cloud/functions-framework": "^4.0.0",
44
44
  "@google-cloud/pubsub": "^4.1.0",
45
45
  "@types/jsonwebtoken": "^9.0.10",
46
- "@types/qs": "^6.14.0",
47
46
  "axios": "^1.11.0",
48
47
  "fastify": "^5.6.0",
49
48
  "firebase-admin": "^13.5.0",
50
49
  "firebase-functions": "^6.4.0",
51
50
  "jsonwebtoken": "^9.0.2",
52
- "qs": "^6.14.0",
53
51
  "reflect-metadata": "^0.2.2",
54
52
  "typedi": "^0.10.0",
55
53
  "zod": "^4.1.5"