@noony-serverless/core 0.1.0 → 0.1.5

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 (56) hide show
  1. package/build/middlewares/authenticationMiddleware.d.ts +379 -0
  2. package/build/middlewares/authenticationMiddleware.js +216 -0
  3. package/build/middlewares/bodyParserMiddleware.d.ts +99 -0
  4. package/build/middlewares/bodyParserMiddleware.js +99 -0
  5. package/build/middlewares/bodyValidationMiddleware.d.ts +68 -4
  6. package/build/middlewares/bodyValidationMiddleware.js +64 -0
  7. package/build/middlewares/dependencyInjectionMiddleware.d.ts +238 -0
  8. package/build/middlewares/dependencyInjectionMiddleware.js +238 -0
  9. package/build/middlewares/errorHandlerMiddleware.d.ts +94 -0
  10. package/build/middlewares/errorHandlerMiddleware.js +105 -0
  11. package/build/middlewares/guards/RouteGuards.d.ts +475 -0
  12. package/build/middlewares/guards/RouteGuards.js +604 -0
  13. package/build/middlewares/guards/cache/CacheAdapter.d.ts +473 -0
  14. package/build/middlewares/guards/cache/CacheAdapter.js +205 -0
  15. package/build/middlewares/guards/cache/ConservativeCacheInvalidation.d.ts +191 -0
  16. package/build/middlewares/guards/cache/ConservativeCacheInvalidation.js +510 -0
  17. package/build/middlewares/guards/cache/MemoryCacheAdapter.d.ts +228 -0
  18. package/build/middlewares/guards/cache/MemoryCacheAdapter.js +403 -0
  19. package/build/middlewares/guards/cache/NoopCacheAdapter.d.ts +95 -0
  20. package/build/middlewares/guards/cache/NoopCacheAdapter.js +131 -0
  21. package/build/middlewares/guards/config/GuardConfiguration.d.ts +612 -0
  22. package/build/middlewares/guards/config/GuardConfiguration.js +334 -0
  23. package/build/middlewares/guards/guards/FastAuthGuard.d.ts +201 -0
  24. package/build/middlewares/guards/guards/FastAuthGuard.js +460 -0
  25. package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +202 -0
  26. package/build/middlewares/guards/guards/PermissionGuardFactory.js +563 -0
  27. package/build/middlewares/guards/index.d.ts +67 -0
  28. package/build/middlewares/guards/index.js +192 -0
  29. package/build/middlewares/guards/registry/PermissionRegistry.d.ts +188 -0
  30. package/build/middlewares/guards/registry/PermissionRegistry.js +425 -0
  31. package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +129 -0
  32. package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +451 -0
  33. package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +155 -0
  34. package/build/middlewares/guards/resolvers/PermissionResolver.js +176 -0
  35. package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +101 -0
  36. package/build/middlewares/guards/resolvers/PlainPermissionResolver.js +248 -0
  37. package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +146 -0
  38. package/build/middlewares/guards/resolvers/WildcardPermissionResolver.js +377 -0
  39. package/build/middlewares/guards/services/FastUserContextService.d.ts +216 -0
  40. package/build/middlewares/guards/services/FastUserContextService.js +435 -0
  41. package/build/middlewares/headerVariablesMiddleware.d.ts +118 -0
  42. package/build/middlewares/headerVariablesMiddleware.js +118 -0
  43. package/build/middlewares/httpAttributesMiddleware.d.ts +235 -0
  44. package/build/middlewares/httpAttributesMiddleware.js +235 -0
  45. package/build/middlewares/index.d.ts +1 -0
  46. package/build/middlewares/index.js +1 -0
  47. package/build/middlewares/queryParametersMiddleware.d.ts +105 -0
  48. package/build/middlewares/queryParametersMiddleware.js +105 -0
  49. package/build/middlewares/rateLimitingMiddleware.d.ts +109 -5
  50. package/build/middlewares/rateLimitingMiddleware.js +109 -5
  51. package/build/middlewares/responseWrapperMiddleware.d.ts +170 -1
  52. package/build/middlewares/responseWrapperMiddleware.js +170 -1
  53. package/build/middlewares/securityAuditMiddleware.js +5 -5
  54. package/build/middlewares/validationMiddleware.d.ts +145 -0
  55. package/build/middlewares/validationMiddleware.js +145 -0
  56. package/package.json +2 -2
@@ -0,0 +1,435 @@
1
+ "use strict";
2
+ /**
3
+ * Fast User Context Service
4
+ *
5
+ * High-performance user context management with configurable permission resolution.
6
+ * This service orchestrates the permission resolution strategies, manages caching,
7
+ * and provides sub-millisecond user permission checks for serverless environments.
8
+ *
9
+ * Key Features:
10
+ * - Configurable permission resolution (pre-expansion vs on-demand)
11
+ * - Multi-layer caching (L1 memory + L2 distributed)
12
+ * - Conservative cache invalidation for security
13
+ * - Permission expansion and validation
14
+ * - Performance monitoring and metrics
15
+ * - TypeDI integration for dependency injection
16
+ *
17
+ * Architecture:
18
+ * - Uses strategy pattern for different resolution approaches
19
+ * - Implements repository pattern for user context storage
20
+ * - Follows single responsibility principle with focused methods
21
+ * - Provides comprehensive error handling and logging
22
+ *
23
+ * @author Noony Framework Team
24
+ * @version 1.0.0
25
+ */
26
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
27
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
28
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
29
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
30
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
31
+ };
32
+ var __metadata = (this && this.__metadata) || function (k, v) {
33
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
34
+ };
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.FastUserContextService = void 0;
37
+ const typedi_1 = require("typedi");
38
+ const CacheAdapter_1 = require("../cache/CacheAdapter");
39
+ const GuardConfiguration_1 = require("../config/GuardConfiguration");
40
+ const PlainPermissionResolver_1 = require("../resolvers/PlainPermissionResolver");
41
+ const WildcardPermissionResolver_1 = require("../resolvers/WildcardPermissionResolver");
42
+ const ExpressionPermissionResolver_1 = require("../resolvers/ExpressionPermissionResolver");
43
+ const PermissionResolver_1 = require("../resolvers/PermissionResolver");
44
+ /**
45
+ * Fast User Context Service Implementation
46
+ */
47
+ let FastUserContextService = class FastUserContextService {
48
+ cache;
49
+ config;
50
+ permissionSource;
51
+ _permissionRegistry;
52
+ // Permission resolvers
53
+ plainResolver;
54
+ wildcardResolver;
55
+ expressionResolver;
56
+ // Performance tracking
57
+ contextLoads = 0;
58
+ cacheHits = 0;
59
+ cacheMisses = 0;
60
+ permissionChecks = 0;
61
+ totalResolutionTimeUs = 0;
62
+ constructor(cache, config, permissionSource, permissionRegistry) {
63
+ this.cache = cache;
64
+ this.config = config;
65
+ this.permissionSource = permissionSource;
66
+ this._permissionRegistry = permissionRegistry;
67
+ // Initialize permission resolvers
68
+ this.plainResolver = new PlainPermissionResolver_1.PlainPermissionResolver();
69
+ this.wildcardResolver = new WildcardPermissionResolver_1.WildcardPermissionResolver(config.security.permissionResolutionStrategy ??
70
+ GuardConfiguration_1.PermissionResolutionStrategy.PRE_EXPANSION, this._permissionRegistry, cache);
71
+ this.expressionResolver = new ExpressionPermissionResolver_1.ExpressionPermissionResolver(cache);
72
+ }
73
+ /**
74
+ * Get or load user context with permissions
75
+ *
76
+ * This is the primary method for retrieving user contexts with caching.
77
+ * It handles both pre-expansion and on-demand permission strategies.
78
+ *
79
+ * @param userId - Unique user identifier
80
+ * @param forceRefresh - Skip cache and force reload
81
+ * @returns User context with permissions or null if user not found
82
+ */
83
+ async getUserContext(userId, forceRefresh = false) {
84
+ const startTime = process.hrtime.bigint();
85
+ this.contextLoads++;
86
+ try {
87
+ // Check cache first unless forced refresh
88
+ if (!forceRefresh) {
89
+ const cachedContext = await this.loadFromCache(userId);
90
+ if (cachedContext) {
91
+ this.cacheHits++;
92
+ return cachedContext;
93
+ }
94
+ }
95
+ this.cacheMisses++;
96
+ // Load from permission source
97
+ const userData = await this.permissionSource.getUserPermissions(userId);
98
+ if (!userData) {
99
+ return null;
100
+ }
101
+ // Build user context
102
+ const context = await this.buildUserContext(userId, userData);
103
+ // Cache the context
104
+ await this.saveToCache(context);
105
+ return context;
106
+ }
107
+ finally {
108
+ const endTime = process.hrtime.bigint();
109
+ this.totalResolutionTimeUs += Number(endTime - startTime) / 1000;
110
+ }
111
+ }
112
+ /**
113
+ * Check user permission using appropriate resolver
114
+ *
115
+ * Routes permission checks to the optimal resolver based on requirement type.
116
+ * Provides detailed results including performance metrics and cache status.
117
+ *
118
+ * @param userId - User identifier
119
+ * @param requirement - Permission requirement (string[], wildcard pattern, or expression)
120
+ * @param options - Check options
121
+ * @returns Detailed permission check result
122
+ */
123
+ async checkPermission(userId, requirement, options = {}) {
124
+ const startTime = process.hrtime.bigint();
125
+ this.permissionChecks++;
126
+ try {
127
+ // Load user context
128
+ const userContext = await this.getUserContext(userId, !options.useCache);
129
+ if (!userContext) {
130
+ return {
131
+ allowed: false,
132
+ resolverType: PermissionResolver_1.PermissionResolverType.PLAIN,
133
+ resolutionTimeUs: 0,
134
+ cached: false,
135
+ reason: 'User not found',
136
+ };
137
+ }
138
+ // Select appropriate resolver
139
+ const resolver = this.selectResolver(requirement, options.resolverType);
140
+ if (!resolver) {
141
+ return {
142
+ allowed: false,
143
+ resolverType: PermissionResolver_1.PermissionResolverType.PLAIN,
144
+ resolutionTimeUs: 0,
145
+ cached: false,
146
+ reason: 'No suitable resolver found',
147
+ };
148
+ }
149
+ // Perform permission check
150
+ const permissions = userContext.expandedPermissions || userContext.permissions;
151
+ const result = await resolver.checkWithResult(permissions, requirement);
152
+ // Add audit trail if enabled
153
+ if (options.auditTrail && result.allowed) {
154
+ await this.recordAuditTrail(userId, requirement, result);
155
+ }
156
+ return result;
157
+ }
158
+ finally {
159
+ const endTime = process.hrtime.bigint();
160
+ this.totalResolutionTimeUs += Number(endTime - startTime) / 1000;
161
+ }
162
+ }
163
+ /**
164
+ * Batch check multiple permissions for a user
165
+ *
166
+ * Optimized for checking multiple permissions at once.
167
+ * Uses the same user context for all checks to minimize overhead.
168
+ *
169
+ * @param userId - User identifier
170
+ * @param requirements - Array of permission requirements
171
+ * @param options - Check options
172
+ * @returns Array of permission check results
173
+ */
174
+ async checkPermissions(userId, requirements, options = {}) {
175
+ const startTime = process.hrtime.bigint();
176
+ try {
177
+ // Load user context once for all checks
178
+ const userContext = await this.getUserContext(userId, !options.useCache);
179
+ if (!userContext) {
180
+ const failResult = {
181
+ allowed: false,
182
+ resolverType: PermissionResolver_1.PermissionResolverType.PLAIN,
183
+ resolutionTimeUs: 0,
184
+ cached: false,
185
+ reason: 'User not found',
186
+ };
187
+ return requirements.map(() => ({ ...failResult }));
188
+ }
189
+ // Process all requirements
190
+ const results = [];
191
+ const permissions = userContext.expandedPermissions || userContext.permissions;
192
+ for (const { requirement, resolverType } of requirements) {
193
+ const resolver = this.selectResolver(requirement, resolverType);
194
+ if (!resolver) {
195
+ results.push({
196
+ allowed: false,
197
+ resolverType: PermissionResolver_1.PermissionResolverType.PLAIN,
198
+ resolutionTimeUs: 0,
199
+ cached: false,
200
+ reason: 'No suitable resolver found',
201
+ });
202
+ continue;
203
+ }
204
+ const result = await resolver.checkWithResult(permissions, requirement);
205
+ results.push(result);
206
+ // Add audit trail for allowed permissions
207
+ if (options.auditTrail && result.allowed) {
208
+ await this.recordAuditTrail(userId, requirement, result);
209
+ }
210
+ }
211
+ return results;
212
+ }
213
+ finally {
214
+ const endTime = process.hrtime.bigint();
215
+ this.totalResolutionTimeUs += Number(endTime - startTime) / 1000;
216
+ this.permissionChecks += requirements.length;
217
+ }
218
+ }
219
+ /**
220
+ * Invalidate user context cache
221
+ *
222
+ * Removes user context from cache when permissions change.
223
+ * Uses conservative approach by also clearing related cached data.
224
+ *
225
+ * @param userId - User identifier
226
+ * @param clearRelated - Also clear permission-related caches
227
+ */
228
+ async invalidateUserContext(userId, clearRelated = true) {
229
+ const cacheKey = CacheAdapter_1.CacheKeyBuilder.userContext(userId);
230
+ await this.cache.delete(cacheKey);
231
+ if (clearRelated && this.config.security.conservativeCacheInvalidation) {
232
+ // Clear permission check caches that might be affected
233
+ await this.cache.deletePattern(`perm:*:${userId}:*`);
234
+ await this.cache.deletePattern(`expr:*:${userId}:*`);
235
+ await this.cache.deletePattern(`wild:*:${userId}:*`);
236
+ }
237
+ console.log(`🔄 Invalidated user context cache`, {
238
+ userId,
239
+ clearRelated,
240
+ timestamp: new Date().toISOString(),
241
+ });
242
+ }
243
+ /**
244
+ * Pre-expand wildcard permissions for user context
245
+ *
246
+ * Used when pre-expansion strategy is enabled to convert
247
+ * wildcard permissions to concrete permission sets.
248
+ *
249
+ * @param permissions - Raw permissions from user/roles
250
+ * @returns Expanded permission set
251
+ */
252
+ async expandPermissions(permissions) {
253
+ const expanded = new Set();
254
+ for (const permission of permissions) {
255
+ if (permission.includes('*')) {
256
+ // Expand wildcard
257
+ const concretePermissions = await this.wildcardResolver.expandWildcardPatterns([permission]);
258
+ concretePermissions.forEach((p) => expanded.add(p));
259
+ }
260
+ else {
261
+ // Add concrete permission
262
+ expanded.add(permission);
263
+ }
264
+ }
265
+ return expanded;
266
+ }
267
+ /**
268
+ * Get service performance statistics
269
+ */
270
+ getStats() {
271
+ const totalCacheRequests = this.cacheHits + this.cacheMisses;
272
+ return {
273
+ contextLoads: this.contextLoads,
274
+ permissionChecks: this.permissionChecks,
275
+ cacheHitRate: totalCacheRequests > 0
276
+ ? (this.cacheHits / totalCacheRequests) * 100
277
+ : 0,
278
+ cacheHits: this.cacheHits,
279
+ cacheMisses: this.cacheMisses,
280
+ averageResolutionTimeUs: this.contextLoads > 0
281
+ ? this.totalResolutionTimeUs / this.contextLoads
282
+ : 0,
283
+ totalResolutionTimeUs: this.totalResolutionTimeUs,
284
+ resolverStats: {
285
+ plain: this.plainResolver.getStats(),
286
+ wildcard: this.wildcardResolver.getStats(),
287
+ expression: this.expressionResolver.getStats(),
288
+ },
289
+ };
290
+ }
291
+ /**
292
+ * Reset performance statistics
293
+ */
294
+ resetStats() {
295
+ this.contextLoads = 0;
296
+ this.cacheHits = 0;
297
+ this.cacheMisses = 0;
298
+ this.permissionChecks = 0;
299
+ this.totalResolutionTimeUs = 0;
300
+ this.plainResolver.resetStats();
301
+ this.wildcardResolver.resetStats();
302
+ this.expressionResolver.resetStats();
303
+ }
304
+ /**
305
+ * Load user context from cache
306
+ */
307
+ async loadFromCache(userId) {
308
+ const cacheKey = CacheAdapter_1.CacheKeyBuilder.userContext(userId);
309
+ const cachedData = await this.cache.get(cacheKey);
310
+ if (!cachedData) {
311
+ return null;
312
+ }
313
+ // Check if context is stale
314
+ if (await this.permissionSource.isUserContextStale(userId, cachedData.context.lastUpdated)) {
315
+ await this.cache.delete(cacheKey);
316
+ return null;
317
+ }
318
+ // Reconstruct context with Set objects
319
+ return {
320
+ ...cachedData.context,
321
+ permissions: new Set(cachedData.permissions),
322
+ expandedPermissions: cachedData.expandedPermissions
323
+ ? new Set(cachedData.expandedPermissions)
324
+ : undefined,
325
+ };
326
+ }
327
+ /**
328
+ * Save user context to cache
329
+ */
330
+ async saveToCache(context) {
331
+ const cacheKey = CacheAdapter_1.CacheKeyBuilder.userContext(context.userId);
332
+ // Serialize Sets to arrays for caching
333
+ const cacheData = {
334
+ context: {
335
+ userId: context.userId,
336
+ roles: context.roles,
337
+ metadata: context.metadata,
338
+ lastUpdated: context.lastUpdated,
339
+ expiresAt: context.expiresAt,
340
+ },
341
+ permissions: Array.from(context.permissions),
342
+ expandedPermissions: context.expandedPermissions
343
+ ? Array.from(context.expandedPermissions)
344
+ : undefined,
345
+ };
346
+ const ttlMs = this.config.cache.userContextTtlMs || 15 * 60 * 1000; // 15 minutes default
347
+ await this.cache.set(cacheKey, cacheData, ttlMs);
348
+ }
349
+ /**
350
+ * Build user context from raw user data
351
+ */
352
+ async buildUserContext(userId, userData) {
353
+ const now = new Date().toISOString();
354
+ // Combine user and role permissions
355
+ const rolePermissions = await this.permissionSource.getRolePermissions(userData.roles);
356
+ const allPermissions = [
357
+ ...new Set([...userData.permissions, ...rolePermissions]),
358
+ ];
359
+ // Create base context
360
+ const context = {
361
+ userId,
362
+ permissions: new Set(allPermissions),
363
+ roles: userData.roles,
364
+ metadata: userData.metadata || {},
365
+ lastUpdated: now,
366
+ };
367
+ // Add expanded permissions for pre-expansion strategy
368
+ if (this.config.security.permissionResolutionStrategy ===
369
+ GuardConfiguration_1.PermissionResolutionStrategy.PRE_EXPANSION) {
370
+ context.expandedPermissions =
371
+ await this.expandPermissions(allPermissions);
372
+ }
373
+ return context;
374
+ }
375
+ /**
376
+ * Select appropriate permission resolver
377
+ */
378
+ selectResolver(requirement, preferredType) {
379
+ // Use preferred type if specified and resolver can handle it
380
+ if (preferredType) {
381
+ const resolver = this.getResolverByType(preferredType);
382
+ if (resolver && resolver.canHandle(requirement)) {
383
+ return resolver;
384
+ }
385
+ }
386
+ // Auto-select based on requirement type
387
+ if (this.expressionResolver.canHandle(requirement)) {
388
+ return this.expressionResolver;
389
+ }
390
+ if (this.wildcardResolver.canHandle(requirement)) {
391
+ return this.wildcardResolver;
392
+ }
393
+ if (this.plainResolver.canHandle(requirement)) {
394
+ return this.plainResolver;
395
+ }
396
+ return null;
397
+ }
398
+ /**
399
+ * Get resolver by type
400
+ */
401
+ getResolverByType(type) {
402
+ switch (type) {
403
+ case PermissionResolver_1.PermissionResolverType.PLAIN:
404
+ return this.plainResolver;
405
+ case PermissionResolver_1.PermissionResolverType.WILDCARD:
406
+ return this.wildcardResolver;
407
+ case PermissionResolver_1.PermissionResolverType.EXPRESSION:
408
+ return this.expressionResolver;
409
+ default:
410
+ return null;
411
+ }
412
+ }
413
+ /**
414
+ * Record audit trail for permission checks
415
+ */
416
+ async recordAuditTrail(userId, requirement, result) {
417
+ // In production, this would write to an audit log
418
+ console.log(`🔍 Permission granted`, {
419
+ userId,
420
+ requirement: typeof requirement === 'object'
421
+ ? JSON.stringify(requirement)
422
+ : requirement,
423
+ resolverType: result.resolverType,
424
+ resolutionTimeUs: result.resolutionTimeUs,
425
+ matchedPermissions: result.matchedPermissions,
426
+ timestamp: new Date().toISOString(),
427
+ });
428
+ }
429
+ };
430
+ exports.FastUserContextService = FastUserContextService;
431
+ exports.FastUserContextService = FastUserContextService = __decorate([
432
+ (0, typedi_1.Service)(),
433
+ __metadata("design:paramtypes", [Object, GuardConfiguration_1.GuardConfiguration, Object, Object])
434
+ ], FastUserContextService);
435
+ //# sourceMappingURL=FastUserContextService.js.map
@@ -1,8 +1,126 @@
1
1
  import { BaseMiddleware, Context } from '../core';
2
+ /**
3
+ * Middleware class that validates the presence of required HTTP headers.
4
+ * Throws a ValidationError if any required header is missing or empty.
5
+ *
6
+ * @implements {BaseMiddleware}
7
+ *
8
+ * @example
9
+ * API key authentication via headers:
10
+ * ```typescript
11
+ * import { Handler, HeaderVariablesMiddleware } from '@noony-serverless/core';
12
+ *
13
+ * const requiredHeaders = ['authorization', 'x-api-key', 'content-type'];
14
+ *
15
+ * const secureApiHandler = new Handler()
16
+ * .use(new HeaderVariablesMiddleware(requiredHeaders))
17
+ * .handle(async (context) => {
18
+ * const authHeader = context.req.headers.authorization;
19
+ * const apiKey = context.req.headers['x-api-key'];
20
+ *
21
+ * // Headers are guaranteed to exist after middleware validation
22
+ * console.log('Auth header:', authHeader);
23
+ * console.log('API key:', apiKey);
24
+ *
25
+ * return { success: true, authenticated: true };
26
+ * });
27
+ * ```
28
+ *
29
+ * @example
30
+ * Content negotiation requirements:
31
+ * ```typescript
32
+ * const contentHeaders = ['accept', 'content-type', 'accept-language'];
33
+ *
34
+ * const internationalApiHandler = new Handler()
35
+ * .use(new HeaderVariablesMiddleware(contentHeaders))
36
+ * .handle(async (context) => {
37
+ * const acceptLang = context.req.headers['accept-language'];
38
+ * const contentType = context.req.headers['content-type'];
39
+ *
40
+ * const language = Array.isArray(acceptLang) ? acceptLang[0] : acceptLang;
41
+ * const responseData = getLocalizedContent(language);
42
+ *
43
+ * return { success: true, data: responseData, language };
44
+ * });
45
+ * ```
46
+ *
47
+ * @example
48
+ * Custom business headers validation:
49
+ * ```typescript
50
+ * const businessHeaders = ['x-tenant-id', 'x-request-id', 'x-client-version'];
51
+ *
52
+ * const multiTenantHandler = new Handler()
53
+ * .use(new HeaderVariablesMiddleware(businessHeaders))
54
+ * .handle(async (context) => {
55
+ * const tenantId = context.req.headers['x-tenant-id'];
56
+ * const requestId = context.req.headers['x-request-id'];
57
+ * const clientVersion = context.req.headers['x-client-version'];
58
+ *
59
+ * console.log(`Processing request ${requestId} for tenant ${tenantId} with client ${clientVersion}`);
60
+ *
61
+ * const tenantData = await getTenantData(tenantId as string);
62
+ * return { success: true, tenant: tenantData };
63
+ * });
64
+ * ```
65
+ */
2
66
  export declare class HeaderVariablesMiddleware implements BaseMiddleware {
3
67
  private requiredHeaders;
4
68
  constructor(requiredHeaders: string[]);
5
69
  before(context: Context): Promise<void>;
6
70
  }
71
+ /**
72
+ * Factory function that creates a header validation middleware.
73
+ * Validates that all required headers are present in the request.
74
+ *
75
+ * @param requiredHeaders - Array of header names that must be present
76
+ * @returns BaseMiddleware object with header validation logic
77
+ *
78
+ * @example
79
+ * Simple header validation:
80
+ * ```typescript
81
+ * import { Handler, headerVariablesMiddleware } from '@noony-serverless/core';
82
+ *
83
+ * const authHandler = new Handler()
84
+ * .use(headerVariablesMiddleware(['authorization']))
85
+ * .handle(async (context) => {
86
+ * const token = context.req.headers.authorization;
87
+ * // Proceed with authentication logic
88
+ * return { success: true, message: 'Authenticated' };
89
+ * });
90
+ * ```
91
+ *
92
+ * @example
93
+ * Multiple required headers:
94
+ * ```typescript
95
+ * const webhookHandler = new Handler()
96
+ * .use(headerVariablesMiddleware([
97
+ * 'x-webhook-signature',
98
+ * 'x-webhook-timestamp',
99
+ * 'content-type'
100
+ * ]))
101
+ * .handle(async (context) => {
102
+ * const signature = context.req.headers['x-webhook-signature'];
103
+ * const timestamp = context.req.headers['x-webhook-timestamp'];
104
+ *
105
+ * // Validate webhook authenticity
106
+ * const isValid = validateWebhookSignature(signature, timestamp, context.req.body);
107
+ * return { success: isValid };
108
+ * });
109
+ * ```
110
+ *
111
+ * @example
112
+ * API versioning through headers:
113
+ * ```typescript
114
+ * const versionedApiHandler = new Handler()
115
+ * .use(headerVariablesMiddleware(['x-api-version', 'accept']))
116
+ * .handle(async (context) => {
117
+ * const apiVersion = context.req.headers['x-api-version'];
118
+ * const accept = context.req.headers.accept;
119
+ *
120
+ * const handler = getHandlerForVersion(apiVersion as string);
121
+ * return handler.process(context.req.body);
122
+ * });
123
+ * ```
124
+ */
7
125
  export declare const headerVariablesMiddleware: (requiredHeaders: string[]) => BaseMiddleware;
8
126
  //# sourceMappingURL=headerVariablesMiddleware.d.ts.map
@@ -11,6 +11,70 @@ const validateHeaders = (requiredHeaders, headers) => {
11
11
  }
12
12
  }
13
13
  };
14
+ /**
15
+ * Middleware class that validates the presence of required HTTP headers.
16
+ * Throws a ValidationError if any required header is missing or empty.
17
+ *
18
+ * @implements {BaseMiddleware}
19
+ *
20
+ * @example
21
+ * API key authentication via headers:
22
+ * ```typescript
23
+ * import { Handler, HeaderVariablesMiddleware } from '@noony-serverless/core';
24
+ *
25
+ * const requiredHeaders = ['authorization', 'x-api-key', 'content-type'];
26
+ *
27
+ * const secureApiHandler = new Handler()
28
+ * .use(new HeaderVariablesMiddleware(requiredHeaders))
29
+ * .handle(async (context) => {
30
+ * const authHeader = context.req.headers.authorization;
31
+ * const apiKey = context.req.headers['x-api-key'];
32
+ *
33
+ * // Headers are guaranteed to exist after middleware validation
34
+ * console.log('Auth header:', authHeader);
35
+ * console.log('API key:', apiKey);
36
+ *
37
+ * return { success: true, authenticated: true };
38
+ * });
39
+ * ```
40
+ *
41
+ * @example
42
+ * Content negotiation requirements:
43
+ * ```typescript
44
+ * const contentHeaders = ['accept', 'content-type', 'accept-language'];
45
+ *
46
+ * const internationalApiHandler = new Handler()
47
+ * .use(new HeaderVariablesMiddleware(contentHeaders))
48
+ * .handle(async (context) => {
49
+ * const acceptLang = context.req.headers['accept-language'];
50
+ * const contentType = context.req.headers['content-type'];
51
+ *
52
+ * const language = Array.isArray(acceptLang) ? acceptLang[0] : acceptLang;
53
+ * const responseData = getLocalizedContent(language);
54
+ *
55
+ * return { success: true, data: responseData, language };
56
+ * });
57
+ * ```
58
+ *
59
+ * @example
60
+ * Custom business headers validation:
61
+ * ```typescript
62
+ * const businessHeaders = ['x-tenant-id', 'x-request-id', 'x-client-version'];
63
+ *
64
+ * const multiTenantHandler = new Handler()
65
+ * .use(new HeaderVariablesMiddleware(businessHeaders))
66
+ * .handle(async (context) => {
67
+ * const tenantId = context.req.headers['x-tenant-id'];
68
+ * const requestId = context.req.headers['x-request-id'];
69
+ * const clientVersion = context.req.headers['x-client-version'];
70
+ *
71
+ * console.log(`Processing request ${requestId} for tenant ${tenantId} with client ${clientVersion}`);
72
+ *
73
+ * const tenantData = await getTenantData(tenantId as string);
74
+ * return { success: true, tenant: tenantData };
75
+ * });
76
+ * ```
77
+ */
14
78
  class HeaderVariablesMiddleware {
15
79
  requiredHeaders;
16
80
  constructor(requiredHeaders) {
@@ -22,6 +86,60 @@ class HeaderVariablesMiddleware {
22
86
  }
23
87
  }
24
88
  exports.HeaderVariablesMiddleware = HeaderVariablesMiddleware;
89
+ /**
90
+ * Factory function that creates a header validation middleware.
91
+ * Validates that all required headers are present in the request.
92
+ *
93
+ * @param requiredHeaders - Array of header names that must be present
94
+ * @returns BaseMiddleware object with header validation logic
95
+ *
96
+ * @example
97
+ * Simple header validation:
98
+ * ```typescript
99
+ * import { Handler, headerVariablesMiddleware } from '@noony-serverless/core';
100
+ *
101
+ * const authHandler = new Handler()
102
+ * .use(headerVariablesMiddleware(['authorization']))
103
+ * .handle(async (context) => {
104
+ * const token = context.req.headers.authorization;
105
+ * // Proceed with authentication logic
106
+ * return { success: true, message: 'Authenticated' };
107
+ * });
108
+ * ```
109
+ *
110
+ * @example
111
+ * Multiple required headers:
112
+ * ```typescript
113
+ * const webhookHandler = new Handler()
114
+ * .use(headerVariablesMiddleware([
115
+ * 'x-webhook-signature',
116
+ * 'x-webhook-timestamp',
117
+ * 'content-type'
118
+ * ]))
119
+ * .handle(async (context) => {
120
+ * const signature = context.req.headers['x-webhook-signature'];
121
+ * const timestamp = context.req.headers['x-webhook-timestamp'];
122
+ *
123
+ * // Validate webhook authenticity
124
+ * const isValid = validateWebhookSignature(signature, timestamp, context.req.body);
125
+ * return { success: isValid };
126
+ * });
127
+ * ```
128
+ *
129
+ * @example
130
+ * API versioning through headers:
131
+ * ```typescript
132
+ * const versionedApiHandler = new Handler()
133
+ * .use(headerVariablesMiddleware(['x-api-version', 'accept']))
134
+ * .handle(async (context) => {
135
+ * const apiVersion = context.req.headers['x-api-version'];
136
+ * const accept = context.req.headers.accept;
137
+ *
138
+ * const handler = getHandlerForVersion(apiVersion as string);
139
+ * return handler.process(context.req.body);
140
+ * });
141
+ * ```
142
+ */
25
143
  const headerVariablesMiddleware = (requiredHeaders) => ({
26
144
  async before(context) {
27
145
  context.req.headers = context.req.headers || {};