hi-secure 1.0.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 (210) hide show
  1. package/dist/adapters/ArgonAdapter.d.ts +8 -0
  2. package/dist/adapters/ArgonAdapter.d.ts.map +1 -0
  3. package/dist/adapters/ArgonAdapter.js +45 -0
  4. package/dist/adapters/ArgonAdapter.js.map +1 -0
  5. package/dist/adapters/BcryptAdapter.d.ts +7 -0
  6. package/dist/adapters/BcryptAdapter.d.ts.map +1 -0
  7. package/dist/adapters/BcryptAdapter.js +48 -0
  8. package/dist/adapters/BcryptAdapter.js.map +1 -0
  9. package/dist/adapters/DomPurifyAdapter.d.ts +13 -0
  10. package/dist/adapters/DomPurifyAdapter.d.ts.map +1 -0
  11. package/dist/adapters/DomPurifyAdapter.js +61 -0
  12. package/dist/adapters/DomPurifyAdapter.js.map +1 -0
  13. package/dist/adapters/ExpressRLAdapter.d.ts +13 -0
  14. package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -0
  15. package/dist/adapters/ExpressRLAdapter.js +68 -0
  16. package/dist/adapters/ExpressRLAdapter.js.map +1 -0
  17. package/dist/adapters/ExpressValidatorAdapter.d.ts +6 -0
  18. package/dist/adapters/ExpressValidatorAdapter.d.ts.map +1 -0
  19. package/dist/adapters/ExpressValidatorAdapter.js +78 -0
  20. package/dist/adapters/ExpressValidatorAdapter.js.map +1 -0
  21. package/dist/adapters/GoggleAdapter.d.ts +15 -0
  22. package/dist/adapters/GoggleAdapter.d.ts.map +1 -0
  23. package/dist/adapters/GoggleAdapter.js +91 -0
  24. package/dist/adapters/GoggleAdapter.js.map +1 -0
  25. package/dist/adapters/GoogleAdapter.d.ts +15 -0
  26. package/dist/adapters/GoogleAdapter.d.ts.map +1 -0
  27. package/dist/adapters/GoogleAdapter.js +159 -0
  28. package/dist/adapters/GoogleAdapter.js.map +1 -0
  29. package/dist/adapters/JWTAdapter.d.ts +28 -0
  30. package/dist/adapters/JWTAdapter.d.ts.map +1 -0
  31. package/dist/adapters/JWTAdapter.js +276 -0
  32. package/dist/adapters/JWTAdapter.js.map +1 -0
  33. package/dist/adapters/RLFlexibleAdapter.d.ts +11 -0
  34. package/dist/adapters/RLFlexibleAdapter.d.ts.map +1 -0
  35. package/dist/adapters/RLFlexibleAdapter.js +115 -0
  36. package/dist/adapters/RLFlexibleAdapter.js.map +1 -0
  37. package/dist/adapters/SanitizeHtmlAdapter.d.ts +12 -0
  38. package/dist/adapters/SanitizeHtmlAdapter.d.ts.map +1 -0
  39. package/dist/adapters/SanitizeHtmlAdapter.js +141 -0
  40. package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -0
  41. package/dist/adapters/XSSAdapter.d.ts +33 -0
  42. package/dist/adapters/XSSAdapter.d.ts.map +1 -0
  43. package/dist/adapters/XSSAdapter.js +127 -0
  44. package/dist/adapters/XSSAdapter.js.map +1 -0
  45. package/dist/adapters/ZodAdapter.d.ts +7 -0
  46. package/dist/adapters/ZodAdapter.d.ts.map +1 -0
  47. package/dist/adapters/ZodAdapter.js +39 -0
  48. package/dist/adapters/ZodAdapter.js.map +1 -0
  49. package/dist/core/HiSecure.d.ts +62 -0
  50. package/dist/core/HiSecure.d.ts.map +1 -0
  51. package/dist/core/HiSecure.js +273 -0
  52. package/dist/core/HiSecure.js.map +1 -0
  53. package/dist/core/config.d.ts +3 -0
  54. package/dist/core/config.d.ts.map +1 -0
  55. package/dist/core/config.js +53 -0
  56. package/dist/core/config.js.map +1 -0
  57. package/dist/core/constants.d.ts +37 -0
  58. package/dist/core/constants.d.ts.map +1 -0
  59. package/dist/core/constants.js +67 -0
  60. package/dist/core/constants.js.map +1 -0
  61. package/dist/core/errors/AdapterError.d.ts +5 -0
  62. package/dist/core/errors/AdapterError.d.ts.map +1 -0
  63. package/dist/core/errors/AdapterError.js +15 -0
  64. package/dist/core/errors/AdapterError.js.map +1 -0
  65. package/dist/core/errors/HttpErrror.d.ts +17 -0
  66. package/dist/core/errors/HttpErrror.d.ts.map +1 -0
  67. package/dist/core/errors/HttpErrror.js +36 -0
  68. package/dist/core/errors/HttpErrror.js.map +1 -0
  69. package/dist/core/errors/SanitizerError.d.ts +5 -0
  70. package/dist/core/errors/SanitizerError.d.ts.map +1 -0
  71. package/dist/core/errors/SanitizerError.js +14 -0
  72. package/dist/core/errors/SanitizerError.js.map +1 -0
  73. package/dist/core/errors/SecurityError.d.ts +5 -0
  74. package/dist/core/errors/SecurityError.d.ts.map +1 -0
  75. package/dist/core/errors/SecurityError.js +14 -0
  76. package/dist/core/errors/SecurityError.js.map +1 -0
  77. package/dist/core/errors/ValidationError.d.ts +5 -0
  78. package/dist/core/errors/ValidationError.d.ts.map +1 -0
  79. package/dist/core/errors/ValidationError.js +14 -0
  80. package/dist/core/errors/ValidationError.js.map +1 -0
  81. package/dist/core/types/HiSecureConfig.d.ts +47 -0
  82. package/dist/core/types/HiSecureConfig.d.ts.map +1 -0
  83. package/dist/core/types/HiSecureConfig.js +3 -0
  84. package/dist/core/types/HiSecureConfig.js.map +1 -0
  85. package/dist/core/types/SecureOptions.d.ts +30 -0
  86. package/dist/core/types/SecureOptions.d.ts.map +1 -0
  87. package/dist/core/types/SecureOptions.js +4 -0
  88. package/dist/core/types/SecureOptions.js.map +1 -0
  89. package/dist/core/useSecure.d.ts +10 -0
  90. package/dist/core/useSecure.d.ts.map +1 -0
  91. package/dist/core/useSecure.js +85 -0
  92. package/dist/core/useSecure.js.map +1 -0
  93. package/dist/examples/e1.d.ts +1 -0
  94. package/dist/examples/e1.d.ts.map +1 -0
  95. package/dist/examples/e1.js +3 -0
  96. package/dist/examples/e1.js.map +1 -0
  97. package/dist/index.d.ts +9 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +15 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/logging/index.d.ts +3 -0
  102. package/dist/logging/index.d.ts.map +1 -0
  103. package/dist/logging/index.js +19 -0
  104. package/dist/logging/index.js.map +1 -0
  105. package/dist/logging/morganSetup.d.ts +2 -0
  106. package/dist/logging/morganSetup.d.ts.map +1 -0
  107. package/dist/logging/morganSetup.js +9 -0
  108. package/dist/logging/morganSetup.js.map +1 -0
  109. package/dist/logging/winstonSetup.d.ts +6 -0
  110. package/dist/logging/winstonSetup.d.ts.map +1 -0
  111. package/dist/logging/winstonSetup.js +22 -0
  112. package/dist/logging/winstonSetup.js.map +1 -0
  113. package/dist/managers/AuthManager.d.ts +23 -0
  114. package/dist/managers/AuthManager.d.ts.map +1 -0
  115. package/dist/managers/AuthManager.js +190 -0
  116. package/dist/managers/AuthManager.js.map +1 -0
  117. package/dist/managers/CorsManager.d.ts +9 -0
  118. package/dist/managers/CorsManager.d.ts.map +1 -0
  119. package/dist/managers/CorsManager.js +55 -0
  120. package/dist/managers/CorsManager.js.map +1 -0
  121. package/dist/managers/HashManager.d.ts +22 -0
  122. package/dist/managers/HashManager.d.ts.map +1 -0
  123. package/dist/managers/HashManager.js +319 -0
  124. package/dist/managers/HashManager.js.map +1 -0
  125. package/dist/managers/JsonManager.d.ts +6 -0
  126. package/dist/managers/JsonManager.d.ts.map +1 -0
  127. package/dist/managers/JsonManager.js +142 -0
  128. package/dist/managers/JsonManager.js.map +1 -0
  129. package/dist/managers/RateLimitManager.d.ts +16 -0
  130. package/dist/managers/RateLimitManager.d.ts.map +1 -0
  131. package/dist/managers/RateLimitManager.js +108 -0
  132. package/dist/managers/RateLimitManager.js.map +1 -0
  133. package/dist/managers/SanitizerManager.d.ts +18 -0
  134. package/dist/managers/SanitizerManager.d.ts.map +1 -0
  135. package/dist/managers/SanitizerManager.js +296 -0
  136. package/dist/managers/SanitizerManager.js.map +1 -0
  137. package/dist/managers/ValidatorManager.d.ts +13 -0
  138. package/dist/managers/ValidatorManager.d.ts.map +1 -0
  139. package/dist/managers/ValidatorManager.js +218 -0
  140. package/dist/managers/ValidatorManager.js.map +1 -0
  141. package/dist/middlewares/errorHandler.d.ts +3 -0
  142. package/dist/middlewares/errorHandler.d.ts.map +1 -0
  143. package/dist/middlewares/errorHandler.js +94 -0
  144. package/dist/middlewares/errorHandler.js.map +1 -0
  145. package/dist/middlewares/index.d.ts +3 -0
  146. package/dist/middlewares/index.d.ts.map +1 -0
  147. package/dist/middlewares/index.js +19 -0
  148. package/dist/middlewares/index.js.map +1 -0
  149. package/dist/middlewares/requestLogger.d.ts +2 -0
  150. package/dist/middlewares/requestLogger.d.ts.map +1 -0
  151. package/dist/middlewares/requestLogger.js +8 -0
  152. package/dist/middlewares/requestLogger.js.map +1 -0
  153. package/dist/test/t1.d.ts +1 -0
  154. package/dist/test/t1.d.ts.map +1 -0
  155. package/dist/test/t1.js +3 -0
  156. package/dist/test/t1.js.map +1 -0
  157. package/dist/utils/deepFreeze.d.ts +2 -0
  158. package/dist/utils/deepFreeze.d.ts.map +1 -0
  159. package/dist/utils/deepFreeze.js +69 -0
  160. package/dist/utils/deepFreeze.js.map +1 -0
  161. package/dist/utils/deepMerge.d.ts +5 -0
  162. package/dist/utils/deepMerge.d.ts.map +1 -0
  163. package/dist/utils/deepMerge.js +68 -0
  164. package/dist/utils/deepMerge.js.map +1 -0
  165. package/dist/utils/normalizeOptions.d.ts +38 -0
  166. package/dist/utils/normalizeOptions.d.ts.map +1 -0
  167. package/dist/utils/normalizeOptions.js +119 -0
  168. package/dist/utils/normalizeOptions.js.map +1 -0
  169. package/package.json +50 -0
  170. package/src/adapters/ArgonAdapter.ts +41 -0
  171. package/src/adapters/BcryptAdapter.ts +49 -0
  172. package/src/adapters/ExpressRLAdapter.ts +84 -0
  173. package/src/adapters/ExpressValidatorAdapter.ts +99 -0
  174. package/src/adapters/GoogleAdapter.ts +206 -0
  175. package/src/adapters/JWTAdapter.ts +346 -0
  176. package/src/adapters/RLFlexibleAdapter.ts +139 -0
  177. package/src/adapters/SanitizeHtmlAdapter.ts +162 -0
  178. package/src/adapters/XSSAdapter.ts +153 -0
  179. package/src/adapters/ZodAdapter.ts +91 -0
  180. package/src/core/HiSecure.ts +955 -0
  181. package/src/core/config.ts +156 -0
  182. package/src/core/constants.ts +73 -0
  183. package/src/core/errors/AdapterError.ts +14 -0
  184. package/src/core/errors/HttpErrror.ts +46 -0
  185. package/src/core/errors/SanitizerError.ts +13 -0
  186. package/src/core/errors/SecurityError.ts +13 -0
  187. package/src/core/errors/ValidationError.ts +13 -0
  188. package/src/core/types/HiSecureConfig.ts +62 -0
  189. package/src/core/types/SecureOptions.ts +61 -0
  190. package/src/core/useSecure.ts +111 -0
  191. package/src/examples/e1.ts +1 -0
  192. package/src/index.ts +17 -0
  193. package/src/logging/index.ts +2 -0
  194. package/src/logging/morganSetup.ts +3 -0
  195. package/src/logging/winstonSetup.ts +17 -0
  196. package/src/managers/AuthManager.ts +237 -0
  197. package/src/managers/CorsManager.ts +58 -0
  198. package/src/managers/HashManager.ts +390 -0
  199. package/src/managers/JsonManager.ts +149 -0
  200. package/src/managers/RateLimitManager.ts +368 -0
  201. package/src/managers/SanitizerManager.ts +359 -0
  202. package/src/managers/ValidatorManager.ts +269 -0
  203. package/src/middlewares/errorHandler.ts +265 -0
  204. package/src/middlewares/index.ts +2 -0
  205. package/src/middlewares/requestLogger.ts +5 -0
  206. package/src/test/t1.ts +1 -0
  207. package/src/utils/deepFreeze.ts +76 -0
  208. package/src/utils/deepMerge.ts +87 -0
  209. package/src/utils/normalizeOptions.ts +265 -0
  210. package/tsconfig.json +30 -0
@@ -0,0 +1,149 @@
1
+ // // import express from "express";
2
+ // // import { logger } from "../logging";
3
+ // // import { AdapterError } from "../core/errors/AdapterError";
4
+
5
+ // // export class JsonManager {
6
+
7
+ // // /**
8
+ // // * JSON parser middleware — global + dynamic override
9
+ // // */
10
+ // // middleware(options?: any) {
11
+ // // try {
12
+ // // const opts = options || {};
13
+ // // return express.json(opts);
14
+ // // } catch (err: any) {
15
+ // // logger.error("❌ JSON Manager: failed to create JSON parser", {
16
+ // // error: err?.message || err
17
+ // // });
18
+ // // throw new AdapterError("JSON parser initialization failed.");
19
+ // // }
20
+ // // }
21
+
22
+ // // /**
23
+ // // * URL-encoded parser — same global + dynamic style
24
+ // // */
25
+ // // urlencoded(options?: any) {
26
+ // // try {
27
+ // // const opts = options || { extended: true };
28
+ // // return express.urlencoded(opts);
29
+ // // } catch (err: any) {
30
+ // // logger.error("❌ JSON Manager: failed to create urlencoded parser", {
31
+ // // error: err?.message || err
32
+ // // });
33
+ // // throw new AdapterError("URL-encoded parser initialization failed.");
34
+ // // }
35
+ // // }
36
+ // // }
37
+
38
+
39
+
40
+ // import express from "express";
41
+ // import qs from "qs";
42
+ // import { logger } from "../logging";
43
+ // import { AdapterError } from "../core/errors/AdapterError.js";
44
+
45
+ // export class JsonManager {
46
+
47
+ // // JSON parser
48
+ // middleware(options?: any) {
49
+ // try {
50
+ // return express.json(options || {});
51
+ // } catch (err: any) {
52
+ // logger.error("❌ JSON Manager: failed to create JSON parser");
53
+ // throw new AdapterError("JSON parser initialization failed.");
54
+ // }
55
+ // }
56
+
57
+ // // URL-encoded parser
58
+ // urlencoded(options?: any) {
59
+ // try {
60
+ // const opts = options || { extended: true };
61
+ // return express.urlencoded(opts);
62
+ // } catch (err: any) {
63
+ // logger.error("❌ URL-encoded parser failed");
64
+ // throw new AdapterError("URL-encoded parser initialization failed.");
65
+ // }
66
+ // }
67
+
68
+ // // NEW: Query-string parser
69
+ // queryParser() {
70
+ // return (req: any, res: any, next: any) => {
71
+ // try {
72
+ // req.query = qs.parse(req.url.split("?")[1] || "");
73
+ // } catch (err: any) {
74
+ // logger.error("❌ Failed to parse query", { error: err?.message });
75
+ // throw new AdapterError("Query parsing failed.");
76
+ // }
77
+ // next();
78
+ // };
79
+ // }
80
+ // }
81
+
82
+
83
+
84
+
85
+ // src/managers/JsonManager.ts - FIXED
86
+ import express from "express";
87
+ import qs from "qs";
88
+ import { logger } from "../logging";
89
+ import { AdapterError } from "../core/errors/AdapterError.js";
90
+
91
+ export class JsonManager {
92
+ // JSON parser
93
+ middleware(options?: any) {
94
+ try {
95
+ const defaultOptions = {
96
+ limit: '1mb',
97
+ inflate: true,
98
+ strict: true
99
+ };
100
+ return express.json({ ...defaultOptions, ...(options || {}) });
101
+ } catch (err: any) {
102
+ logger.error("❌ JSON Manager: failed to create JSON parser");
103
+ throw new AdapterError("JSON parser initialization failed.");
104
+ }
105
+ }
106
+
107
+ // URL-encoded parser
108
+ urlencoded(options?: any) {
109
+ try {
110
+ const defaultOptions = {
111
+ extended: true,
112
+ limit: '1mb',
113
+ parameterLimit: 1000
114
+ };
115
+ const opts = { ...defaultOptions, ...(options || {}) };
116
+ return express.urlencoded(opts);
117
+ } catch (err: any) {
118
+ logger.error("❌ URL-encoded parser failed");
119
+ throw new AdapterError("URL-encoded parser initialization failed.");
120
+ }
121
+ }
122
+
123
+ // Query-string parser (doesn't override Express's query)
124
+ queryParser(options?: any) {
125
+ return (req: any, res: any, next: any) => {
126
+ try {
127
+ // Only parse if not already parsed by Express
128
+ if (!req.parsedQuery && req.url.includes('?')) {
129
+ const queryString = req.url.split("?")[1] || "";
130
+ const parsed = qs.parse(queryString, {
131
+ depth: 5, // Prevent deep nesting attacks
132
+ parameterLimit: 100,
133
+ ...options
134
+ });
135
+
136
+ // Store separately, don't override req.query
137
+ req.parsedQuery = parsed;
138
+ logger.debug("🔍 Query parsed", {
139
+ keys: Object.keys(parsed)
140
+ });
141
+ }
142
+ next();
143
+ } catch (err: any) {
144
+ logger.error("❌ Failed to parse query", { error: err?.message });
145
+ next(new AdapterError("Query parsing failed."));
146
+ }
147
+ };
148
+ }
149
+ }
@@ -0,0 +1,368 @@
1
+
2
+
3
+ // // // src/managers/RateLimitManager.ts - COMPLETE FIXED
4
+ // // import { HiSecureConfig } from "../core/types/HiSecureConfig.js";
5
+ // // import { AdapterError } from "../core/errors/AdapterError.js";
6
+ // // import { logger } from "../logging";
7
+
8
+ // // interface RateLimiterAdapter {
9
+ // // getMiddleware: (options?: any) => any;
10
+ // // }
11
+
12
+ // // export class RateLimitManager {
13
+ // // private config: HiSecureConfig["rateLimiter"];
14
+ // // private primaryAdapter: RateLimiterAdapter;
15
+ // // private fallbackAdapter: RateLimiterAdapter | null;
16
+
17
+ // // constructor(
18
+ // // config: HiSecureConfig["rateLimiter"],
19
+ // // primaryAdapter: RateLimiterAdapter,
20
+ // // fallbackAdapter: RateLimiterAdapter | null
21
+ // // ) {
22
+ // // this.config = config;
23
+ // // this.primaryAdapter = primaryAdapter;
24
+ // // this.fallbackAdapter = fallbackAdapter;
25
+ // // }
26
+
27
+ // // middleware(opts?: { mode?: "strict" | "relaxed" | "api"; options?: any }) {
28
+ // // let finalOptions: any = {};
29
+
30
+ // // // Handle presets (user cannot override these)
31
+ // // if (opts?.mode === "strict") {
32
+ // // finalOptions = {
33
+ // // windowMs: 10_000,
34
+ // // max: 5,
35
+ // // points: 5,
36
+ // // duration: 10,
37
+ // // message: "Too many requests, please slow down."
38
+ // // };
39
+ // // } else if (opts?.mode === "relaxed") {
40
+ // // finalOptions = {
41
+ // // windowMs: 60_000,
42
+ // // max: 100,
43
+ // // points: 100,
44
+ // // duration: 60,
45
+ // // message: "Rate limit exceeded."
46
+ // // };
47
+ // // } else if (opts?.mode === "api") {
48
+ // // finalOptions = {
49
+ // // windowMs: 15 * 60 * 1000, // 15 minutes
50
+ // // max: 100,
51
+ // // points: 100,
52
+ // // duration: 900,
53
+ // // message: "API rate limit exceeded."
54
+ // // };
55
+ // // } else {
56
+ // // // Use defaults
57
+ // // finalOptions = {
58
+ // // windowMs: this.config.windowMs,
59
+ // // max: this.config.maxRequests,
60
+ // // duration: this.config.windowMs / 1000,
61
+ // // points: this.config.maxRequests,
62
+ // // message: this.config.message
63
+ // // };
64
+ // // }
65
+
66
+ // // // Apply custom options WITHOUT overriding preset values
67
+ // // if (opts?.options) {
68
+ // // // Only allow specific overrides, not preset overrides
69
+ // // const allowedOverrides = ['message', 'skipFailedRequests', 'standardHeaders'];
70
+ // // for (const key of allowedOverrides) {
71
+ // // if (opts.options[key] !== undefined) {
72
+ // // finalOptions[key] = opts.options[key];
73
+ // // }
74
+ // // }
75
+
76
+ // // // Log if user tried to override preset
77
+ // // const attemptedOverrides = Object.keys(opts.options).filter(
78
+ // // k => !allowedOverrides.includes(k) && k !== 'mode'
79
+ // // );
80
+ // // if (attemptedOverrides.length > 0) {
81
+ // // logger.warn("⚠ Rate limit overrides ignored", { // ✅ FIXED: Better message
82
+ // // preset: opts?.mode || 'default', // ✅ FIXED: Handle undefined
83
+ // // ignoredOptions: attemptedOverrides
84
+ // // });
85
+ // // }
86
+ // // }
87
+
88
+ // // // Try primary adapter
89
+ // // try {
90
+ // // logger.info("📌 Applying rate limiting", {
91
+ // // mode: opts?.mode || 'default',
92
+ // // windowMs: finalOptions.windowMs,
93
+ // // max: finalOptions.max
94
+ // // });
95
+
96
+ // // return this.primaryAdapter.getMiddleware(finalOptions);
97
+ // // } catch (err: any) {
98
+ // // logger.warn("⚠ Primary rate limiter failed → fallback", {
99
+ // // error: err?.message
100
+ // // });
101
+
102
+ // // if (!this.fallbackAdapter) {
103
+ // // throw new AdapterError("Rate limiters failed; no fallback adapter.");
104
+ // // }
105
+
106
+ // // try {
107
+ // // logger.info("📌 Using fallback rate limiter");
108
+ // // return this.fallbackAdapter.getMiddleware(finalOptions);
109
+ // // } catch (fallbackErr: any) {
110
+ // // logger.error("❌ Fallback limiter also failed", {
111
+ // // error: fallbackErr?.message
112
+ // // });
113
+ // // throw new AdapterError("Both primary and fallback limiters failed.");
114
+ // // }
115
+ // // }
116
+ // // }
117
+ // // }
118
+
119
+
120
+
121
+ // // src/managers/RateLimitManager.ts - FIXED
122
+ // import { HiSecureConfig } from "../core/types/HiSecureConfig.js";
123
+ // import { AdapterError } from "../core/errors/AdapterError.js";
124
+ // import { logger } from "../logging";
125
+
126
+ // interface RateLimiterAdapter {
127
+ // getMiddleware: (options?: any) => any;
128
+ // }
129
+
130
+ // export class RateLimitManager {
131
+ // private config: HiSecureConfig["rateLimiter"];
132
+ // private primaryAdapter: RateLimiterAdapter;
133
+ // private fallbackAdapter: RateLimiterAdapter | null;
134
+
135
+ // constructor(
136
+ // config: HiSecureConfig["rateLimiter"],
137
+ // primaryAdapter: RateLimiterAdapter,
138
+ // fallbackAdapter: RateLimiterAdapter | null
139
+ // ) {
140
+ // this.config = config;
141
+ // this.primaryAdapter = primaryAdapter;
142
+ // this.fallbackAdapter = fallbackAdapter;
143
+ // }
144
+
145
+ // middleware(opts?: { mode?: "strict" | "relaxed" | "api"; options?: any }) {
146
+ // let finalOptions: any = {};
147
+
148
+ // // Handle presets (user cannot override these)
149
+ // if (opts?.mode === "strict") {
150
+ // finalOptions = {
151
+ // windowMs: 10_000,
152
+ // max: 5,
153
+ // points: 5,
154
+ // // ❌ REMOVED: duration: 10,
155
+ // message: "Too many requests, please slow down."
156
+ // };
157
+ // } else if (opts?.mode === "relaxed") {
158
+ // finalOptions = {
159
+ // windowMs: 60_000,
160
+ // max: 100,
161
+ // points: 100,
162
+ // // ❌ REMOVED: duration: 60,
163
+ // message: "Rate limit exceeded."
164
+ // };
165
+ // } else if (opts?.mode === "api") {
166
+ // finalOptions = {
167
+ // windowMs: 15 * 60 * 1000, // 15 minutes
168
+ // max: 100,
169
+ // points: 100,
170
+ // // ❌ REMOVED: duration: 900,
171
+ // message: "API rate limit exceeded."
172
+ // };
173
+ // } else {
174
+ // // Use defaults
175
+ // finalOptions = {
176
+ // windowMs: this.config.windowMs,
177
+ // max: this.config.maxRequests,
178
+ // // ❌ REMOVED: duration: this.config.windowMs / 1000,
179
+ // points: this.config.maxRequests,
180
+ // message: this.config.message,
181
+ // standardHeaders: true, // ✅ ADD
182
+ // legacyHeaders: false // ✅ ADD
183
+ // };
184
+ // }
185
+
186
+ // // Apply custom options WITHOUT overriding preset values
187
+ // if (opts?.options) {
188
+ // // Only allow specific overrides, not preset overrides
189
+ // const allowedOverrides = ['message', 'skipFailedRequests', 'standardHeaders', 'legacyHeaders'];
190
+ // for (const key of allowedOverrides) {
191
+ // if (opts.options[key] !== undefined) {
192
+ // finalOptions[key] = opts.options[key];
193
+ // }
194
+ // }
195
+
196
+ // // Log if user tried to override preset
197
+ // const attemptedOverrides = Object.keys(opts.options).filter(
198
+ // k => !allowedOverrides.includes(k) && k !== 'mode'
199
+ // );
200
+ // if (attemptedOverrides.length > 0) {
201
+ // logger.warn("⚠ Rate limit overrides ignored", {
202
+ // preset: opts?.mode || 'default',
203
+ // ignoredOptions: attemptedOverrides
204
+ // });
205
+ // }
206
+ // }
207
+
208
+ // // Add v8+ options if not present
209
+ // if (finalOptions.standardHeaders === undefined) {
210
+ // finalOptions.standardHeaders = true;
211
+ // }
212
+ // if (finalOptions.legacyHeaders === undefined) {
213
+ // finalOptions.legacyHeaders = false;
214
+ // }
215
+
216
+ // // Try primary adapter
217
+ // try {
218
+ // logger.info("📌 Applying rate limiting", {
219
+ // mode: opts?.mode || 'default',
220
+ // windowMs: finalOptions.windowMs,
221
+ // max: finalOptions.max
222
+ // });
223
+
224
+ // return this.primaryAdapter.getMiddleware(finalOptions);
225
+ // } catch (err: any) {
226
+ // logger.warn("⚠ Primary rate limiter failed → fallback", {
227
+ // error: err?.message
228
+ // });
229
+
230
+ // if (!this.fallbackAdapter) {
231
+ // throw new AdapterError("Rate limiters failed; no fallback adapter.");
232
+ // }
233
+
234
+ // try {
235
+ // logger.info("📌 Using fallback rate limiter");
236
+ // return this.fallbackAdapter.getMiddleware(finalOptions);
237
+ // } catch (fallbackErr: any) {
238
+ // logger.error("❌ Fallback limiter also failed", {
239
+ // error: fallbackErr?.message
240
+ // });
241
+ // throw new AdapterError("Both primary and fallback limiters failed.");
242
+ // }
243
+ // }
244
+ // }
245
+ // }
246
+
247
+
248
+
249
+ // src/managers/RateLimitManager.ts - COMPLETELY FIXED
250
+ import { HiSecureConfig } from "../core/types/HiSecureConfig.js";
251
+ import { AdapterError } from "../core/errors/AdapterError.js";
252
+ import { logger } from "../logging";
253
+
254
+ interface RateLimiterAdapter {
255
+ getMiddleware: (options?: any) => any;
256
+ }
257
+
258
+ export class RateLimitManager {
259
+ private config: HiSecureConfig["rateLimiter"];
260
+ private primaryAdapter: RateLimiterAdapter;
261
+ private fallbackAdapter: RateLimiterAdapter | null;
262
+
263
+ constructor(
264
+ config: HiSecureConfig["rateLimiter"],
265
+ primaryAdapter: RateLimiterAdapter,
266
+ fallbackAdapter: RateLimiterAdapter | null
267
+ ) {
268
+ this.config = config;
269
+ this.primaryAdapter = primaryAdapter;
270
+ this.fallbackAdapter = fallbackAdapter;
271
+ }
272
+
273
+ middleware(opts?: { mode?: "strict" | "relaxed" | "api"; options?: any }) {
274
+ let finalOptions: any = {};
275
+
276
+ // Handle presets (user cannot override these)
277
+ if (opts?.mode === "strict") {
278
+ finalOptions = {
279
+ windowMs: 10_000,
280
+ max: 5,
281
+ // ❌ REMOVED: points: 5,
282
+ message: "Too many requests, please slow down."
283
+ };
284
+ } else if (opts?.mode === "relaxed") {
285
+ finalOptions = {
286
+ windowMs: 60_000,
287
+ max: 100,
288
+ // ❌ REMOVED: points: 100,
289
+ message: "Rate limit exceeded."
290
+ };
291
+ } else if (opts?.mode === "api") {
292
+ finalOptions = {
293
+ windowMs: 15 * 60 * 1000, // 15 minutes
294
+ max: 100,
295
+ // ❌ REMOVED: points: 100,
296
+ message: "API rate limit exceeded."
297
+ };
298
+ } else {
299
+ // Use defaults
300
+ finalOptions = {
301
+ windowMs: this.config.windowMs,
302
+ max: this.config.maxRequests,
303
+ message: this.config.message,
304
+ standardHeaders: true, // ✅ ADD
305
+ legacyHeaders: false // ✅ ADD
306
+ };
307
+ }
308
+
309
+ // Apply custom options WITHOUT overriding preset values
310
+ if (opts?.options) {
311
+ // Only allow specific overrides, not preset overrides
312
+ const allowedOverrides = ['message', 'skipFailedRequests', 'standardHeaders', 'legacyHeaders'];
313
+ for (const key of allowedOverrides) {
314
+ if (opts.options[key] !== undefined) {
315
+ finalOptions[key] = opts.options[key];
316
+ }
317
+ }
318
+
319
+ // Log if user tried to override preset
320
+ const attemptedOverrides = Object.keys(opts.options).filter(
321
+ k => !allowedOverrides.includes(k) && k !== 'mode'
322
+ );
323
+ if (attemptedOverrides.length > 0) {
324
+ logger.warn("⚠ Rate limit overrides ignored", {
325
+ preset: opts?.mode || 'default',
326
+ ignoredOptions: attemptedOverrides
327
+ });
328
+ }
329
+ }
330
+
331
+ // Add v8+ options if not present
332
+ if (finalOptions.standardHeaders === undefined) {
333
+ finalOptions.standardHeaders = true;
334
+ }
335
+ if (finalOptions.legacyHeaders === undefined) {
336
+ finalOptions.legacyHeaders = false;
337
+ }
338
+
339
+ // Try primary adapter
340
+ try {
341
+ logger.info("📌 Applying rate limiting", {
342
+ mode: opts?.mode || 'default',
343
+ windowMs: finalOptions.windowMs,
344
+ max: finalOptions.max
345
+ });
346
+
347
+ return this.primaryAdapter.getMiddleware(finalOptions);
348
+ } catch (err: any) {
349
+ logger.warn("⚠ Primary rate limiter failed → fallback", {
350
+ error: err?.message
351
+ });
352
+
353
+ if (!this.fallbackAdapter) {
354
+ throw new AdapterError("Rate limiters failed; no fallback adapter.");
355
+ }
356
+
357
+ try {
358
+ logger.info("📌 Using fallback rate limiter");
359
+ return this.fallbackAdapter.getMiddleware(finalOptions);
360
+ } catch (fallbackErr: any) {
361
+ logger.error("❌ Fallback limiter also failed", {
362
+ error: fallbackErr?.message
363
+ });
364
+ throw new AdapterError("Both primary and fallback limiters failed.");
365
+ }
366
+ }
367
+ }
368
+ }