@noony-serverless/core 0.1.5 → 0.2.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.
Files changed (42) hide show
  1. package/build/core/core.d.ts +16 -48
  2. package/build/core/core.js +2 -61
  3. package/build/core/handler.d.ts +37 -16
  4. package/build/core/handler.js +131 -42
  5. package/build/core/index.d.ts +0 -1
  6. package/build/core/index.js +0 -1
  7. package/build/middlewares/ConsolidatedValidationMiddleware.d.ts +126 -0
  8. package/build/middlewares/ConsolidatedValidationMiddleware.js +330 -0
  9. package/build/middlewares/ProcessingMiddleware.d.ts +138 -0
  10. package/build/middlewares/ProcessingMiddleware.js +425 -0
  11. package/build/middlewares/SecurityMiddleware.d.ts +157 -0
  12. package/build/middlewares/SecurityMiddleware.js +307 -0
  13. package/build/middlewares/bodyValidationMiddleware.d.ts +12 -10
  14. package/build/middlewares/bodyValidationMiddleware.js +10 -8
  15. package/build/middlewares/guards/RouteGuards.d.ts +239 -4
  16. package/build/middlewares/guards/RouteGuards.js +301 -8
  17. package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +271 -0
  18. package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.js +301 -0
  19. package/build/middlewares/guards/config/GuardConfiguration.d.ts +50 -0
  20. package/build/middlewares/guards/config/GuardConfiguration.js +59 -0
  21. package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
  22. package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +5 -13
  23. package/build/middlewares/guards/guards/PermissionGuardFactory.js +4 -4
  24. package/build/middlewares/guards/index.d.ts +43 -1
  25. package/build/middlewares/guards/index.js +46 -1
  26. package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
  27. package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
  28. package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
  29. package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
  30. package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
  31. package/build/middlewares/guards/services/FastUserContextService.d.ts +20 -33
  32. package/build/middlewares/guards/services/FastUserContextService.js +17 -4
  33. package/build/middlewares/httpAttributesMiddleware.js +1 -1
  34. package/build/middlewares/index.d.ts +3 -1
  35. package/build/middlewares/index.js +6 -1
  36. package/build/middlewares/rateLimitingMiddleware.d.ts +492 -4
  37. package/build/middlewares/rateLimitingMiddleware.js +514 -6
  38. package/package.json +11 -9
  39. package/build/core/containerPool.d.ts +0 -44
  40. package/build/core/containerPool.js +0 -103
  41. package/build/middlewares/validationMiddleware.d.ts +0 -154
  42. package/build/middlewares/validationMiddleware.js +0 -185
@@ -107,6 +107,37 @@ const getRateLimit = (context, options) => {
107
107
  * Rate Limiting Middleware with sliding window implementation.
108
108
  * Implements comprehensive rate limiting with dynamic limits, custom storage, and security features.
109
109
  *
110
+ * ## When to Use RateLimitingMiddleware
111
+ *
112
+ * ### ✅ Recommended Use Cases:
113
+ * - **Business Logic Rate Limiting**: User-specific quotas, subscription-based limits
114
+ * - **Authentication & Security**: Login attempts, password resets, token refresh
115
+ * - **Content Creation**: Post creation, comment submission, profile updates
116
+ * - **Resource-Intensive Operations**: File uploads, data processing, complex queries
117
+ * - **Advanced Scenarios**: A/B testing limits, geographic restrictions, time-based rules
118
+ *
119
+ * ### ❌ Not Recommended Use Cases:
120
+ * - **Basic DDoS Protection**: Use WAF/CloudFlare instead
121
+ * - **Static Asset Protection**: Use CDN rate limiting
122
+ * - **Simple Volumetric Attacks**: Network-level solutions more effective
123
+ *
124
+ * ## Architecture Integration
125
+ *
126
+ * ### With WAF (Web Application Firewall):
127
+ * - WAF handles: IP blocking, DDoS protection, bot detection
128
+ * - Application handles: Business logic, user-aware limits, complex rules
129
+ * - Focus on complementary functionality, not duplication
130
+ *
131
+ * ### With API Gateway:
132
+ * - Gateway handles: Service-level limits, routing quotas, load balancing
133
+ * - Application handles: User context, subscription limits, feature-specific rules
134
+ * - Different layers for different concerns
135
+ *
136
+ * ### Direct Exposure (No WAF/Gateway):
137
+ * - Application must handle comprehensive protection
138
+ * - Implement multiple protection layers within middleware
139
+ * - Critical for security in simple deployments
140
+ *
110
141
  * @implements {BaseMiddleware}
111
142
  *
112
143
  * @example
@@ -167,6 +198,99 @@ const getRateLimit = (context, options) => {
167
198
  * return { success: true, limit: 'applied dynamically' };
168
199
  * });
169
200
  * ```
201
+ *
202
+ * @example
203
+ * Multi-layer defense (with WAF):
204
+ * ```typescript
205
+ * // WAF handles basic IP limits (10,000/min), DDoS protection
206
+ * // Application refines with business logic
207
+ * const wafAwareHandler = new Handler()
208
+ * .use(new RateLimitingMiddleware({
209
+ * maxRequests: 100, // Refined limit after WAF filtering
210
+ * windowMs: 60000,
211
+ * dynamicLimits: {
212
+ * premium: {
213
+ * maxRequests: 500,
214
+ * windowMs: 60000,
215
+ * matcher: (context) => context.user?.plan === 'premium'
216
+ * }
217
+ * },
218
+ * keyGenerator: (context) => `user:${context.user?.id || context.req.ip}`
219
+ * }))
220
+ * .handle(async (context) => {
221
+ * // Business logic with user-aware limits
222
+ * return await processUserRequest(context);
223
+ * });
224
+ * ```
225
+ *
226
+ * @example
227
+ * API Gateway integration:
228
+ * ```typescript
229
+ * // Gateway: 10,000 req/hour per service, 1,000 req/min per endpoint
230
+ * // Application: User-specific limits within gateway envelope
231
+ * const gatewayAwareHandler = new Handler()
232
+ * .use(new RateLimitingMiddleware({
233
+ * maxRequests: 100, // Per user within gateway limits
234
+ * windowMs: 60000,
235
+ * dynamicLimits: {
236
+ * freeTrial: {
237
+ * maxRequests: 10,
238
+ * windowMs: 60000,
239
+ * matcher: (context) => context.user?.trialExpired === false
240
+ * },
241
+ * enterprise: {
242
+ * maxRequests: 5000,
243
+ * windowMs: 60000,
244
+ * matcher: (context) => context.user?.plan === 'enterprise'
245
+ * }
246
+ * },
247
+ * keyGenerator: (context) => `user:${context.user?.id}`
248
+ * }))
249
+ * .handle(async (context) => {
250
+ * // Refined business logic limits
251
+ * return await handleApiRequest(context);
252
+ * });
253
+ * ```
254
+ *
255
+ * @example
256
+ * Comprehensive protection (no WAF/Gateway):
257
+ * ```typescript
258
+ * // Application must handle all protection layers
259
+ * const comprehensiveHandler = new Handler()
260
+ * .use(new RateLimitingMiddleware({
261
+ * maxRequests: 100,
262
+ * windowMs: 60000,
263
+ * dynamicLimits: {
264
+ * // IP-based protection (WAF-like)
265
+ * suspicious_ip: {
266
+ * maxRequests: 10,
267
+ * windowMs: 60000,
268
+ * matcher: (context) => detectSuspiciousIP(context.req.ip)
269
+ * },
270
+ * // Endpoint-specific (Gateway-like)
271
+ * auth_endpoint: {
272
+ * maxRequests: 5,
273
+ * windowMs: 60000,
274
+ * matcher: (context) => context.req.path?.includes('/auth/')
275
+ * },
276
+ * // Business logic (Application-specific)
277
+ * user_specific: {
278
+ * maxRequests: 1000,
279
+ * windowMs: 60000,
280
+ * matcher: (context) => !!context.user
281
+ * }
282
+ * },
283
+ * keyGenerator: (context) => {
284
+ * const user = context.user?.id;
285
+ * const ip = context.req.ip;
286
+ * const endpoint = context.req.path;
287
+ * return user ? `user:${user}` : `ip:${ip}:${endpoint}`;
288
+ * }
289
+ * }))
290
+ * .handle(async (context) => {
291
+ * return await processRequest(context);
292
+ * });
293
+ * ```
170
294
  */
171
295
  class RateLimitingMiddleware {
172
296
  store;
@@ -243,6 +367,70 @@ exports.RateLimitingMiddleware = RateLimitingMiddleware;
243
367
  * Factory function that creates a rate limiting middleware.
244
368
  * Provides flexible rate limiting with configurable options and presets.
245
369
  *
370
+ * ## Architecture Decision Matrix
371
+ *
372
+ * | Infrastructure | WAF Rate Limiting | Gateway Rate Limiting | Application Rate Limiting |
373
+ * |----------------|------------------|---------------------|-------------------------|
374
+ * | **WAF + Gateway + App** | ✅ Basic DDoS protection | ✅ Service-level limits | ✅ Business logic |
375
+ * | **Gateway + App** | ❌ Not available | ✅ Service + IP limits | ✅ User context + business |
376
+ * | **WAF + App** | ✅ Network protection | ❌ Not available | ✅ All business logic |
377
+ * | **App Only** | ❌ Must implement | ❌ Must implement | ✅ Everything |
378
+ *
379
+ * ## Implementation Strategy by Architecture
380
+ *
381
+ * ### Multi-Layer Defense (Recommended for Enterprise)
382
+ * ```typescript
383
+ * // WAF Layer: 10,000 req/min per IP (CloudFlare/AWS WAF)
384
+ * // Gateway Layer: 1,000 req/min per API key (Kong/AWS API Gateway)
385
+ * // Application Layer: User-specific business rules (This middleware)
386
+ *
387
+ * const enterprise = rateLimiting({
388
+ * maxRequests: 100, // Refined after other layers
389
+ * dynamicLimits: {
390
+ * premium: { maxRequests: 500, matcher: (ctx) => ctx.user?.plan === 'premium' }
391
+ * }
392
+ * });
393
+ * ```
394
+ *
395
+ * ### Gateway + Application (Good for Most Applications)
396
+ * ```typescript
397
+ * // Gateway: Service capacity protection
398
+ * // Application: Business logic enforcement
399
+ *
400
+ * const standard = rateLimiting({
401
+ * maxRequests: 200, // Higher since Gateway pre-filters
402
+ * dynamicLimits: {
403
+ * authenticated: { maxRequests: 1000, matcher: (ctx) => !!ctx.user }
404
+ * }
405
+ * });
406
+ * ```
407
+ *
408
+ * ### Application Only (Comprehensive Protection Required)
409
+ * ```typescript
410
+ * // Must handle all layers of protection
411
+ *
412
+ * const comprehensive = rateLimiting({
413
+ * maxRequests: 50, // Conservative default
414
+ * dynamicLimits: {
415
+ * // WAF-like: IP protection
416
+ * suspicious: { maxRequests: 5, matcher: (ctx) => detectSuspicious(ctx.req.ip) },
417
+ * // Gateway-like: Endpoint protection
418
+ * auth: { maxRequests: 10, matcher: (ctx) => ctx.req.path?.includes('/auth/') },
419
+ * // Business: User-specific
420
+ * premium: { maxRequests: 1000, matcher: (ctx) => ctx.user?.plan === 'premium' }
421
+ * }
422
+ * });
423
+ * ```
424
+ *
425
+ * ## Cost-Benefit Analysis
426
+ *
427
+ * | Architecture | Setup Complexity | Runtime Cost | Protection Level | Maintenance |
428
+ * |-------------|-----------------|-------------|-----------------|-------------|
429
+ * | **WAF + Gateway + App** | High | High | Maximum | Medium |
430
+ * | **Gateway + App** | Medium | Medium | Good | Low |
431
+ * | **WAF + App** | Medium | Medium | Good | Medium |
432
+ * | **App Only** | Low | Low | Variable | High |
433
+ *
246
434
  * @param options - Rate limiting configuration options
247
435
  * @returns BaseMiddleware instance
248
436
  *
@@ -286,15 +474,114 @@ exports.RateLimitingMiddleware = RateLimitingMiddleware;
286
474
  * return { success: true, message: 'Request processed' };
287
475
  * });
288
476
  * ```
477
+ *
478
+ * @example
479
+ * Production Redis store integration:
480
+ * ```typescript
481
+ * import Redis from 'ioredis';
482
+ *
483
+ * class RedisRateLimitStore implements RateLimitStore {
484
+ * constructor(private redis: Redis) {}
485
+ *
486
+ * async increment(key: string, windowMs: number) {
487
+ * const multi = this.redis.multi();
488
+ * multi.incr(key);
489
+ * multi.expire(key, Math.ceil(windowMs / 1000));
490
+ * const results = await multi.exec();
491
+ * return { count: results![0][1] as number, resetTime: Date.now() + windowMs };
492
+ * }
493
+ * }
494
+ *
495
+ * const productionHandler = new Handler()
496
+ * .use(rateLimiting({
497
+ * store: new RedisRateLimitStore(redisClient),
498
+ * maxRequests: 1000,
499
+ * windowMs: 60000
500
+ * }))
501
+ * .handle(async (context) => {
502
+ * return await handleHighVolumeAPI(context);
503
+ * });
504
+ * ```
505
+ *
506
+ * @example
507
+ * Multi-dimensional rate limiting:
508
+ * ```typescript
509
+ * const advancedHandler = new Handler()
510
+ * .use(rateLimiting({
511
+ * maxRequests: 100,
512
+ * windowMs: 60000,
513
+ * dynamicLimits: {
514
+ * // Different limits by operation type
515
+ * read_operations: {
516
+ * maxRequests: 1000,
517
+ * windowMs: 60000,
518
+ * matcher: (context) => context.req.method === 'GET'
519
+ * },
520
+ * write_operations: {
521
+ * maxRequests: 50,
522
+ * windowMs: 60000,
523
+ * matcher: (context) => ['POST', 'PUT', 'DELETE'].includes(context.req.method || '')
524
+ * },
525
+ * // Different limits by user tier
526
+ * enterprise_users: {
527
+ * maxRequests: 5000,
528
+ * windowMs: 60000,
529
+ * matcher: (context) => context.user?.tier === 'enterprise'
530
+ * }
531
+ * },
532
+ * keyGenerator: (context) => {
533
+ * // Multi-dimensional key: user + operation type
534
+ * const userId = context.user?.id || context.req.ip;
535
+ * const operation = context.req.method === 'GET' ? 'read' : 'write';
536
+ * return `${operation}:${userId}`;
537
+ * }
538
+ * }))
539
+ * .handle(async (context) => {
540
+ * return await processAdvancedRequest(context);
541
+ * });
542
+ * ```
289
543
  */
290
544
  const rateLimiting = (options = {}) => new RateLimitingMiddleware(options);
291
545
  exports.rateLimiting = rateLimiting;
292
546
  /**
293
- * Predefined rate limit configurations
547
+ * Predefined rate limit configurations for common use cases.
548
+ *
549
+ * These presets are designed to work well in different infrastructure scenarios:
550
+ * - WAF + Application: Higher limits since WAF pre-filters traffic
551
+ * - Gateway + Application: Moderate limits complementing gateway quotas
552
+ * - Application Only: Conservative limits for comprehensive protection
553
+ *
554
+ * ## Preset Selection Guide
555
+ *
556
+ * | Preset | Use Case | Infrastructure | Requests/Min |
557
+ * |--------|----------|---------------|-------------|
558
+ * | `STRICT` | Sensitive operations | Any | 5 |
559
+ * | `AUTH` | Authentication endpoints | Any | 10 |
560
+ * | `PUBLIC` | Public/unauthenticated | App Only | 50 |
561
+ * | `API` | Standard API endpoints | WAF/Gateway + App | 100-1000 |
562
+ * | `DEVELOPMENT` | Development/testing | Development | 10,000 |
563
+ *
564
+ * @example
565
+ * Choosing the right preset:
566
+ * ```typescript
567
+ * // High-security endpoint (password reset)
568
+ * .use(rateLimiting(RateLimitPresets.STRICT))
569
+ *
570
+ * // Login/registration
571
+ * .use(rateLimiting(RateLimitPresets.AUTH))
572
+ *
573
+ * // Public API with WAF protection
574
+ * .use(rateLimiting(RateLimitPresets.API))
575
+ *
576
+ * // Public API without WAF (direct exposure)
577
+ * .use(rateLimiting(RateLimitPresets.PUBLIC))
578
+ * ```
294
579
  */
295
580
  exports.RateLimitPresets = {
296
581
  /**
297
582
  * Very strict limits for sensitive endpoints
583
+ * Use for: Password resets, account changes, payment operations
584
+ * Infrastructure: Any (universal protection)
298
585
  */
299
586
  STRICT: {
300
587
  maxRequests: 5,
@@ -302,14 +589,16 @@ exports.RateLimitPresets = {
302
589
  message: 'Too many requests to sensitive endpoint',
303
590
  },
304
591
  /**
305
- * Standard API limits
592
+ * Standard API limits with dynamic scaling for authenticated users
593
+ * Use for: Main API endpoints, data retrieval, business operations
594
+ * Infrastructure: Best with WAF or Gateway (higher baseline limits)
306
595
  */
307
596
  API: {
308
- maxRequests: 100,
597
+ maxRequests: 100, // Baseline for unauthenticated/free users
309
598
  windowMs: 60000, // 1 minute
310
599
  dynamicLimits: {
311
600
  authenticated: {
312
- maxRequests: 1000,
601
+ maxRequests: 1000, // 10x increase for authenticated users
313
602
  windowMs: 60000,
314
603
  matcher: (context) => !!context.user,
315
604
  },
@@ -317,25 +606,244 @@ exports.RateLimitPresets = {
317
606
  },
318
607
  /**
319
608
  * Authentication endpoint limits
609
+ * Use for: Login, registration, token refresh, password operations
610
+ * Infrastructure: Any (essential security protection)
320
611
  */
321
612
  AUTH: {
322
613
  maxRequests: 10,
323
614
  windowMs: 60000, // 1 minute
324
615
  message: 'Too many authentication attempts',
616
+ keyGenerator: (context) => {
617
+ // Rate limit per IP + email combination for better security
618
+ const ip = context.req.ip || 'unknown';
619
+ const email = context.req.parsedBody?.email;
620
+ return email ? `auth:${email}:${ip}` : `auth:${ip}`;
621
+ },
325
622
  },
326
623
  /**
327
- * Public endpoint limits
624
+ * Public endpoint limits for direct application exposure
625
+ * Use for: Public APIs, webhooks, health checks
626
+ * Infrastructure: Application only (no WAF/Gateway protection)
328
627
  */
329
628
  PUBLIC: {
330
629
  maxRequests: 50,
331
630
  windowMs: 60000, // 1 minute
631
+ dynamicLimits: {
632
+ // Be more restrictive with suspicious traffic patterns
633
+ suspicious: {
634
+ maxRequests: 10,
635
+ windowMs: 60000,
636
+ matcher: (context) => {
637
+ const userAgent = context.req.headers?.['user-agent'] || '';
638
+ return (!userAgent || userAgent.includes('bot') || userAgent.length < 10);
639
+ },
640
+ },
641
+ },
332
642
  },
333
643
  /**
334
- * Development mode - very permissive
644
+ * Development mode - very permissive limits
645
+ * Use for: Development, testing, debugging
646
+ * Infrastructure: Development environment only
335
647
  */
336
648
  DEVELOPMENT: {
337
649
  maxRequests: 10000,
338
650
  windowMs: 60000, // 1 minute
651
+ skip: (context) => {
652
+ // Skip rate limiting for localhost and development IPs
653
+ const ip = context.req.ip || '';
654
+ return (ip.startsWith('127.') ||
655
+ ip.startsWith('::1') ||
656
+ ip.startsWith('192.168.'));
657
+ },
658
+ },
659
+ /**
660
+ * Enterprise-grade configuration with multi-tier support
661
+ * Use for: Production SaaS applications, enterprise APIs
662
+ * Infrastructure: WAF + Gateway + Application (full stack protection)
663
+ */
664
+ ENTERPRISE: {
665
+ maxRequests: 200, // Higher baseline with multiple protection layers
666
+ windowMs: 60000,
667
+ dynamicLimits: {
668
+ free: {
669
+ maxRequests: 100,
670
+ windowMs: 60000,
671
+ matcher: (context) => !context.user || context.user?.plan === 'free',
672
+ },
673
+ premium: {
674
+ maxRequests: 1000,
675
+ windowMs: 60000,
676
+ matcher: (context) => context.user?.plan === 'premium',
677
+ },
678
+ enterprise: {
679
+ maxRequests: 5000,
680
+ windowMs: 60000,
681
+ matcher: (context) => context.user?.plan === 'enterprise',
682
+ },
683
+ admin: {
684
+ maxRequests: 10000,
685
+ windowMs: 60000,
686
+ matcher: (context) => context.user?.role === 'admin',
687
+ },
688
+ },
689
+ keyGenerator: (context) => {
690
+ // Use user ID for authenticated, IP for anonymous
691
+ return context.user?.id
692
+ ? `user:${context.user.id}`
693
+ : `ip:${context.req.ip}`;
694
+ },
339
695
  },
340
696
  };
697
+ /**
698
+ * Configuration helpers and utilities for rate limiting setup
699
+ *
700
+ * ## Best Practices for Production
701
+ *
702
+ * ### 1. Store Selection
703
+ * - **Development**: Use default `MemoryStore` (built-in)
704
+ * - **Production Single Instance**: Use `MemoryStore` with cleanup
705
+ * - **Production Multi-Instance**: Use Redis-based store
706
+ * - **Serverless**: Use external store (Redis/DynamoDB) for state persistence
707
+ *
708
+ * ### 2. Key Generation Strategy
709
+ * ```typescript
710
+ * // Bad: Too generic, easy to abuse
711
+ * keyGenerator: () => 'global'
712
+ *
713
+ * // Good: Multi-dimensional keys
714
+ * keyGenerator: (context) => {
715
+ * const user = context.user?.id;
716
+ * const endpoint = context.req.path?.split('/')[2]; // /api/users -> users
717
+ * const method = context.req.method;
718
+ * return user ? `${user}:${endpoint}:${method}` : `${context.req.ip}:${endpoint}`;
719
+ * }
720
+ * ```
721
+ *
722
+ * ### 3. Dynamic Limits Best Practices
723
+ * ```typescript
724
+ * // Order matchers from most specific to least specific
725
+ * dynamicLimits: {
726
+ * admin: { maxRequests: 10000, matcher: (ctx) => ctx.user?.role === 'admin' },
727
+ * enterprise: { maxRequests: 5000, matcher: (ctx) => ctx.user?.plan === 'enterprise' },
728
+ * premium: { maxRequests: 1000, matcher: (ctx) => ctx.user?.plan === 'premium' },
729
+ * authenticated: { maxRequests: 500, matcher: (ctx) => !!ctx.user },
730
+ * // Default fallback handled by maxRequests
731
+ * }
732
+ * ```
733
+ *
734
+ * ### 4. Error Handling and Fallback
735
+ * ```typescript
736
+ * const resilientRateLimit = rateLimiting({
737
+ * maxRequests: 100,
738
+ * windowMs: 60000,
739
+ *
740
+ * // Custom store with fallback
741
+ * store: new ResilientStore({
742
+ * primary: redisStore,
743
+ * fallback: new MemoryStore(),
744
+ * timeout: 500 // ms
745
+ * }),
746
+ *
747
+ * // Graceful degradation on errors
748
+ * onError: (error, context) => {
749
+ * logger.warn('Rate limiting error, allowing request', { error, ip: context.req.ip });
750
+ * return false; // Don't block request on store errors
751
+ * }
752
+ * });
753
+ * ```
754
+ *
755
+ * ### 5. Monitoring and Alerting
756
+ * ```typescript
757
+ * // Monitor rate limit effectiveness
758
+ * const monitoredRateLimit = rateLimiting({
759
+ * maxRequests: 100,
760
+ * windowMs: 60000,
761
+ *
762
+ * onRateLimit: (context, info) => {
763
+ * // Alert on high rate limit hits
764
+ * metrics.increment('rate_limit.exceeded', {
765
+ * endpoint: context.req.path,
766
+ * user: context.user?.id || 'anonymous'
767
+ * });
768
+ *
769
+ * // Log suspicious patterns
770
+ * if (info.current > info.limit * 2) {
771
+ * logger.warn('Potential abuse detected', {
772
+ * ip: context.req.ip,
773
+ * userAgent: context.req.headers?.['user-agent'],
774
+ * attempts: info.current
775
+ * });
776
+ * }
777
+ * }
778
+ * });
779
+ * ```
780
+ *
781
+ * ### 6. Testing Rate Limits
782
+ * ```typescript
783
+ * // Test helper for rate limit validation
784
+ * export const testRateLimit = async (
785
+ * handler: Handler,
786
+ * requests: number,
787
+ * shouldSucceed: number
788
+ * ) => {
789
+ * const results = await Promise.all(
790
+ * Array(requests).fill(0).map(() => handler.execute(mockRequest, mockResponse))
791
+ * );
792
+ *
793
+ * const successful = results.filter(r => r.statusCode !== 429).length;
794
+ * expect(successful).toBe(shouldSucceed);
795
+ * };
796
+ * ```
797
+ *
798
+ * ## Troubleshooting Common Issues
799
+ *
800
+ * ### Issue: Rate limits not working
801
+ * **Solution**: Check key generation and store connection
802
+ * ```typescript
803
+ * // Debug key generation
804
+ * keyGenerator: (context) => {
805
+ * const key = generateKey(context);
806
+ * console.log('Rate limit key:', key); // Remove in production
807
+ * return key;
808
+ * }
809
+ * ```
810
+ *
811
+ * ### Issue: Too many false positives
812
+ * **Solution**: Refine dynamic limits and key generation
813
+ * ```typescript
814
+ * // More granular limits
815
+ * dynamicLimits: {
816
+ * read: { maxRequests: 1000, matcher: (ctx) => ctx.req.method === 'GET' },
817
+ * write: { maxRequests: 100, matcher: (ctx) => ctx.req.method !== 'GET' }
818
+ * }
819
+ * ```
820
+ *
821
+ * ### Issue: Memory leaks in MemoryStore
822
+ * **Solution**: Ensure proper cleanup interval and limits
823
+ * ```typescript
824
+ * // Monitor store size
825
+ * setInterval(() => {
826
+ * const storeSize = memoryStore.size();
827
+ * if (storeSize > 10000) {
828
+ * logger.warn('Rate limit store size growing', { size: storeSize });
829
+ * }
830
+ * }, 60000);
831
+ * ```
832
+ *
833
+ * ### Issue: Rate limits too restrictive
834
+ * **Solution**: Implement gradual enforcement
835
+ * ```typescript
836
+ * const gradualLimit = rateLimiting({
837
+ * maxRequests: 100,
838
+ * windowMs: 60000,
839
+ *
840
+ * // Warn before blocking
841
+ * onApproachingLimit: (context, info) => {
842
+ * if (info.remaining < 10) {
843
+ * context.res.header('X-Rate-Limit-Warning', 'Approaching limit');
844
+ * }
845
+ * }
846
+ * });
847
+ * ```
848
+ */
341
849
  //# sourceMappingURL=rateLimitingMiddleware.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noony-serverless/core",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
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",
@@ -40,17 +40,19 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@google-cloud/firestore": "^7.1.0",
43
- "@google-cloud/functions-framework": "^3.3.0",
43
+ "@google-cloud/functions-framework": "^4.0.0",
44
44
  "@google-cloud/pubsub": "^4.1.0",
45
- "@types/jsonwebtoken": "^9.0.8",
46
- "axios": "^1.7.9",
47
- "fastify": "^5.3.3",
48
- "firebase-admin": "^12.6.0",
49
- "firebase-functions": "^6.3.1",
45
+ "@types/jsonwebtoken": "^9.0.10",
46
+ "@types/qs": "^6.14.0",
47
+ "axios": "^1.11.0",
48
+ "fastify": "^5.6.0",
49
+ "firebase-admin": "^13.5.0",
50
+ "firebase-functions": "^6.4.0",
50
51
  "jsonwebtoken": "^9.0.2",
52
+ "qs": "^6.14.0",
51
53
  "reflect-metadata": "^0.2.2",
52
54
  "typedi": "^0.10.0",
53
- "zod": "^3.22.4"
55
+ "zod": "^4.1.5"
54
56
  },
55
57
  "devDependencies": {
56
58
  "@types/jest": "^29.5.11",
@@ -58,7 +60,7 @@
58
60
  "@types/node": "^20.10.5",
59
61
  "@typescript-eslint/eslint-plugin": "^6.15.0",
60
62
  "@typescript-eslint/parser": "^6.15.0",
61
- "concurrently": "^8.2.2",
63
+ "concurrently": "^9.2.1",
62
64
  "eslint": "^8.56.0",
63
65
  "eslint-config-prettier": "^9.1.0",
64
66
  "eslint-plugin-prettier": "^5.1.2",
@@ -1,44 +0,0 @@
1
- import Container from 'typedi';
2
- /**
3
- * Performance optimization: Container Pool for reusing TypeDI containers
4
- * This reduces object creation overhead and improves memory efficiency
5
- */
6
- declare class ContainerPool {
7
- private availableContainers;
8
- private maxPoolSize;
9
- private createdContainers;
10
- constructor(maxPoolSize?: number);
11
- /**
12
- * Get a container from the pool or create a new one
13
- */
14
- acquire(): Container;
15
- /**
16
- * Return a container to the pool for reuse
17
- */
18
- release(container: Container): void;
19
- /**
20
- * Reset container state to prevent cross-request contamination
21
- * Note: TypeDI containers are isolated by default, so we mainly need
22
- * to clear any manually set values
23
- */
24
- private resetContainer;
25
- /**
26
- * Get pool statistics for monitoring
27
- */
28
- getStats(): {
29
- available: number;
30
- created: number;
31
- maxSize: number;
32
- };
33
- /**
34
- * Warm up the pool by pre-creating containers
35
- */
36
- warmUp(count?: number): void;
37
- /**
38
- * Clear all containers from the pool
39
- */
40
- clear(): void;
41
- }
42
- declare const containerPool: ContainerPool;
43
- export { ContainerPool, containerPool };
44
- //# sourceMappingURL=containerPool.d.ts.map