mcp-wordpress 2.4.2 → 2.5.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 (348) hide show
  1. package/README.md +114 -48
  2. package/dist/ajv-patch.js +34 -0
  3. package/dist/cache/CacheInvalidation.d.ts +3 -1
  4. package/dist/cache/CacheInvalidation.d.ts.map +1 -1
  5. package/dist/cache/CacheInvalidation.js +10 -4
  6. package/dist/cache/CacheInvalidation.js.map +1 -1
  7. package/dist/cache/CacheManager.d.ts +3 -2
  8. package/dist/cache/CacheManager.d.ts.map +1 -1
  9. package/dist/cache/CacheManager.js +11 -3
  10. package/dist/cache/CacheManager.js.map +1 -1
  11. package/dist/cache/HttpCacheWrapper.d.ts +7 -6
  12. package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
  13. package/dist/cache/HttpCacheWrapper.js +8 -5
  14. package/dist/cache/HttpCacheWrapper.js.map +1 -1
  15. package/dist/cache/__tests__/HttpCacheWrapper.test.js +6 -5
  16. package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -1
  17. package/dist/cache/index.d.ts +3 -3
  18. package/dist/cache/index.d.ts.map +1 -1
  19. package/dist/cache/index.js +1 -1
  20. package/dist/cache/index.js.map +1 -1
  21. package/dist/client/CachedWordPressClient.d.ts +23 -9
  22. package/dist/client/CachedWordPressClient.d.ts.map +1 -1
  23. package/dist/client/CachedWordPressClient.js +4 -1
  24. package/dist/client/CachedWordPressClient.js.map +1 -1
  25. package/dist/client/MockWordPressClient.d.ts +2 -1
  26. package/dist/client/MockWordPressClient.d.ts.map +1 -1
  27. package/dist/client/MockWordPressClient.js +3 -1
  28. package/dist/client/MockWordPressClient.js.map +1 -1
  29. package/dist/client/api.d.ts +17 -13
  30. package/dist/client/api.d.ts.map +1 -1
  31. package/dist/client/api.js +135 -30
  32. package/dist/client/api.js.map +1 -1
  33. package/dist/client/auth.d.ts.map +1 -1
  34. package/dist/client/auth.js +2 -3
  35. package/dist/client/auth.js.map +1 -1
  36. package/dist/client/managers/AuthenticationManager.d.ts +55 -2
  37. package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
  38. package/dist/client/managers/AuthenticationManager.js +269 -71
  39. package/dist/client/managers/AuthenticationManager.js.map +1 -1
  40. package/dist/client/managers/BaseManager.d.ts +3 -3
  41. package/dist/client/managers/BaseManager.d.ts.map +1 -1
  42. package/dist/client/managers/BaseManager.js +11 -5
  43. package/dist/client/managers/BaseManager.js.map +1 -1
  44. package/dist/client/managers/RequestManager.d.ts +2 -2
  45. package/dist/client/managers/RequestManager.d.ts.map +1 -1
  46. package/dist/client/managers/RequestManager.js +25 -12
  47. package/dist/client/managers/RequestManager.js.map +1 -1
  48. package/dist/config/Config.d.ts +155 -0
  49. package/dist/config/Config.d.ts.map +1 -0
  50. package/dist/config/Config.js +215 -0
  51. package/dist/config/Config.js.map +1 -0
  52. package/dist/config/ConfigurationSchema.d.ts +21 -21
  53. package/dist/config/ConfigurationSchema.d.ts.map +1 -1
  54. package/dist/config/ConfigurationSchema.js +19 -2
  55. package/dist/config/ConfigurationSchema.js.map +1 -1
  56. package/dist/config/ServerConfiguration.d.ts +2 -1
  57. package/dist/config/ServerConfiguration.d.ts.map +1 -1
  58. package/dist/config/ServerConfiguration.js +50 -41
  59. package/dist/config/ServerConfiguration.js.map +1 -1
  60. package/dist/docs/DocumentationGenerator.d.ts +9 -8
  61. package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
  62. package/dist/docs/DocumentationGenerator.js +10 -7
  63. package/dist/docs/DocumentationGenerator.js.map +1 -1
  64. package/dist/docs/MarkdownFormatter.d.ts.map +1 -1
  65. package/dist/docs/MarkdownFormatter.js +3 -2
  66. package/dist/docs/MarkdownFormatter.js.map +1 -1
  67. package/dist/dxt-entry.cjs +81 -0
  68. package/dist/dxt-entry.js +15 -14
  69. package/dist/dxt-entry.js.map +1 -1
  70. package/dist/index.d.ts +3 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +37 -21
  73. package/dist/index.js.map +1 -1
  74. package/dist/performance/MetricsCollector.d.ts +13 -7
  75. package/dist/performance/MetricsCollector.d.ts.map +1 -1
  76. package/dist/performance/MetricsCollector.js +69 -27
  77. package/dist/performance/MetricsCollector.js.map +1 -1
  78. package/dist/performance/PerformanceAnalytics.d.ts +8 -2
  79. package/dist/performance/PerformanceAnalytics.d.ts.map +1 -1
  80. package/dist/performance/PerformanceAnalytics.js +17 -47
  81. package/dist/performance/PerformanceAnalytics.js.map +1 -1
  82. package/dist/performance/PerformanceMonitor.d.ts +2 -1
  83. package/dist/performance/PerformanceMonitor.d.ts.map +1 -1
  84. package/dist/performance/PerformanceMonitor.js +12 -13
  85. package/dist/performance/PerformanceMonitor.js.map +1 -1
  86. package/dist/performance/index.d.ts +2 -2
  87. package/dist/performance/index.d.ts.map +1 -1
  88. package/dist/security/AISecurityScanner.d.ts +1 -0
  89. package/dist/security/AISecurityScanner.d.ts.map +1 -1
  90. package/dist/security/AISecurityScanner.js +22 -12
  91. package/dist/security/AISecurityScanner.js.map +1 -1
  92. package/dist/security/AutomatedRemediation.d.ts +4 -3
  93. package/dist/security/AutomatedRemediation.d.ts.map +1 -1
  94. package/dist/security/AutomatedRemediation.js +46 -15
  95. package/dist/security/AutomatedRemediation.js.map +1 -1
  96. package/dist/security/InputValidator.d.ts +13 -9
  97. package/dist/security/InputValidator.d.ts.map +1 -1
  98. package/dist/security/InputValidator.js +4 -2
  99. package/dist/security/InputValidator.js.map +1 -1
  100. package/dist/security/SecurityCIPipeline.d.ts +1 -1
  101. package/dist/security/SecurityCIPipeline.d.ts.map +1 -1
  102. package/dist/security/SecurityCIPipeline.js +38 -29
  103. package/dist/security/SecurityCIPipeline.js.map +1 -1
  104. package/dist/security/SecurityConfig.d.ts +3 -3
  105. package/dist/security/SecurityConfig.d.ts.map +1 -1
  106. package/dist/security/SecurityConfig.js +13 -9
  107. package/dist/security/SecurityConfig.js.map +1 -1
  108. package/dist/security/SecurityConfigManager.d.ts +2 -2
  109. package/dist/security/SecurityConfigManager.d.ts.map +1 -1
  110. package/dist/security/SecurityConfigManager.js +20 -15
  111. package/dist/security/SecurityConfigManager.js.map +1 -1
  112. package/dist/security/SecurityMonitoring.d.ts +2 -2
  113. package/dist/security/SecurityMonitoring.d.ts.map +1 -1
  114. package/dist/security/SecurityMonitoring.js +19 -17
  115. package/dist/security/SecurityMonitoring.js.map +1 -1
  116. package/dist/security/SecurityReviewer.d.ts.map +1 -1
  117. package/dist/security/SecurityReviewer.js +10 -7
  118. package/dist/security/SecurityReviewer.js.map +1 -1
  119. package/dist/security/index.d.ts +24 -23
  120. package/dist/security/index.d.ts.map +1 -1
  121. package/dist/security/index.js +52 -23
  122. package/dist/security/index.js.map +1 -1
  123. package/dist/server/ConnectionTester.d.ts +12 -4
  124. package/dist/server/ConnectionTester.d.ts.map +1 -1
  125. package/dist/server/ConnectionTester.js +96 -22
  126. package/dist/server/ConnectionTester.js.map +1 -1
  127. package/dist/server/ToolRegistry.d.ts +2 -2
  128. package/dist/server/ToolRegistry.d.ts.map +1 -1
  129. package/dist/server/ToolRegistry.js +10 -5
  130. package/dist/server/ToolRegistry.js.map +1 -1
  131. package/dist/tools/BaseToolManager.d.ts +47 -11
  132. package/dist/tools/BaseToolManager.d.ts.map +1 -1
  133. package/dist/tools/BaseToolManager.js +168 -29
  134. package/dist/tools/BaseToolManager.js.map +1 -1
  135. package/dist/tools/auth.d.ts +16 -10
  136. package/dist/tools/auth.d.ts.map +1 -1
  137. package/dist/tools/auth.js +3 -2
  138. package/dist/tools/auth.js.map +1 -1
  139. package/dist/tools/cache.d.ts +30 -30
  140. package/dist/tools/cache.d.ts.map +1 -1
  141. package/dist/tools/cache.js +1 -6
  142. package/dist/tools/cache.js.map +1 -1
  143. package/dist/tools/comments.d.ts +20 -20
  144. package/dist/tools/comments.d.ts.map +1 -1
  145. package/dist/tools/comments.js +16 -9
  146. package/dist/tools/comments.js.map +1 -1
  147. package/dist/tools/media.d.ts +18 -16
  148. package/dist/tools/media.d.ts.map +1 -1
  149. package/dist/tools/media.js +16 -15
  150. package/dist/tools/media.js.map +1 -1
  151. package/dist/tools/pages.d.ts +19 -17
  152. package/dist/tools/pages.d.ts.map +1 -1
  153. package/dist/tools/pages.js +16 -12
  154. package/dist/tools/pages.js.map +1 -1
  155. package/dist/tools/performance.d.ts +11 -1
  156. package/dist/tools/performance.d.ts.map +1 -1
  157. package/dist/tools/performance.js +67 -34
  158. package/dist/tools/performance.js.map +1 -1
  159. package/dist/tools/posts/PostHandlers.d.ts +46 -0
  160. package/dist/tools/posts/PostHandlers.d.ts.map +1 -0
  161. package/dist/tools/posts/PostHandlers.js +400 -0
  162. package/dist/tools/posts/PostHandlers.js.map +1 -0
  163. package/dist/tools/posts/PostToolDefinitions.d.ts +37 -0
  164. package/dist/tools/posts/PostToolDefinitions.d.ts.map +1 -0
  165. package/dist/tools/posts/PostToolDefinitions.js +236 -0
  166. package/dist/tools/posts/PostToolDefinitions.js.map +1 -0
  167. package/dist/tools/posts/index.d.ts +138 -0
  168. package/dist/tools/posts/index.d.ts.map +1 -0
  169. package/dist/tools/posts/index.js +163 -0
  170. package/dist/tools/posts/index.js.map +1 -0
  171. package/dist/tools/posts.d.ts +10 -246
  172. package/dist/tools/posts.d.ts.map +1 -1
  173. package/dist/tools/posts.js +11 -723
  174. package/dist/tools/posts.js.map +1 -1
  175. package/dist/tools/site.d.ts +19 -18
  176. package/dist/tools/site.d.ts.map +1 -1
  177. package/dist/tools/site.js +14 -10
  178. package/dist/tools/site.js.map +1 -1
  179. package/dist/tools/taxonomies.d.ts +23 -24
  180. package/dist/tools/taxonomies.d.ts.map +1 -1
  181. package/dist/tools/taxonomies.js +24 -18
  182. package/dist/tools/taxonomies.js.map +1 -1
  183. package/dist/tools/users.d.ts +20 -15
  184. package/dist/tools/users.d.ts.map +1 -1
  185. package/dist/tools/users.js +12 -8
  186. package/dist/tools/users.js.map +1 -1
  187. package/dist/types/client.d.ts +48 -41
  188. package/dist/types/client.d.ts.map +1 -1
  189. package/dist/types/client.js +30 -5
  190. package/dist/types/client.js.map +1 -1
  191. package/dist/types/enhanced.d.ts +237 -0
  192. package/dist/types/enhanced.d.ts.map +1 -0
  193. package/dist/types/enhanced.js +49 -0
  194. package/dist/types/enhanced.js.map +1 -0
  195. package/dist/types/index.d.ts +15 -12
  196. package/dist/types/index.d.ts.map +1 -1
  197. package/dist/types/index.js +2 -0
  198. package/dist/types/index.js.map +1 -1
  199. package/dist/types/mcp.d.ts +12 -12
  200. package/dist/types/mcp.d.ts.map +1 -1
  201. package/dist/types/requests.d.ts +322 -0
  202. package/dist/types/requests.d.ts.map +1 -0
  203. package/dist/types/requests.js +8 -0
  204. package/dist/types/requests.js.map +1 -0
  205. package/dist/types/tools.d.ts +506 -0
  206. package/dist/types/tools.d.ts.map +1 -0
  207. package/dist/types/tools.js +8 -0
  208. package/dist/types/tools.js.map +1 -0
  209. package/dist/types/wordpress.d.ts +43 -15
  210. package/dist/types/wordpress.d.ts.map +1 -1
  211. package/dist/types/wordpress.js +8 -1
  212. package/dist/types/wordpress.js.map +1 -1
  213. package/dist/utils/debug.d.ts +19 -11
  214. package/dist/utils/debug.d.ts.map +1 -1
  215. package/dist/utils/debug.js +46 -10
  216. package/dist/utils/debug.js.map +1 -1
  217. package/dist/utils/enhancedError.d.ts +8 -8
  218. package/dist/utils/enhancedError.d.ts.map +1 -1
  219. package/dist/utils/enhancedError.js.map +1 -1
  220. package/dist/utils/error.d.ts +2 -4
  221. package/dist/utils/error.d.ts.map +1 -1
  222. package/dist/utils/error.js +42 -5
  223. package/dist/utils/error.js.map +1 -1
  224. package/dist/utils/logger.d.ts +106 -0
  225. package/dist/utils/logger.d.ts.map +1 -0
  226. package/dist/utils/logger.js +280 -0
  227. package/dist/utils/logger.js.map +1 -0
  228. package/dist/utils/streaming.d.ts +9 -9
  229. package/dist/utils/streaming.d.ts.map +1 -1
  230. package/dist/utils/streaming.js +71 -52
  231. package/dist/utils/streaming.js.map +1 -1
  232. package/dist/utils/toolWrapper.d.ts +9 -7
  233. package/dist/utils/toolWrapper.d.ts.map +1 -1
  234. package/dist/utils/toolWrapper.js.map +1 -1
  235. package/dist/utils/validation/core.d.ts +21 -0
  236. package/dist/utils/validation/core.d.ts.map +1 -0
  237. package/dist/utils/validation/core.js +71 -0
  238. package/dist/utils/validation/core.js.map +1 -0
  239. package/dist/utils/validation/index.d.ts +25 -0
  240. package/dist/utils/validation/index.d.ts.map +1 -0
  241. package/dist/utils/validation/index.js +29 -0
  242. package/dist/utils/validation/index.js.map +1 -0
  243. package/dist/utils/validation/network.d.ts +19 -0
  244. package/dist/utils/validation/network.d.ts.map +1 -0
  245. package/dist/utils/validation/network.js +93 -0
  246. package/dist/utils/validation/network.js.map +1 -0
  247. package/dist/utils/validation/rateLimit.d.ts +21 -0
  248. package/dist/utils/validation/rateLimit.d.ts.map +1 -0
  249. package/dist/utils/validation/rateLimit.js +43 -0
  250. package/dist/utils/validation/rateLimit.js.map +1 -0
  251. package/dist/utils/validation/security.d.ts +29 -0
  252. package/dist/utils/validation/security.d.ts.map +1 -0
  253. package/dist/utils/validation/security.js +327 -0
  254. package/dist/utils/validation/security.js.map +1 -0
  255. package/dist/utils/validation/wordpress.d.ts +31 -0
  256. package/dist/utils/validation/wordpress.d.ts.map +1 -0
  257. package/dist/utils/validation/wordpress.js +146 -0
  258. package/dist/utils/validation/wordpress.js.map +1 -0
  259. package/dist/utils/validation.d.ts +13 -82
  260. package/dist/utils/validation.d.ts.map +1 -1
  261. package/dist/utils/validation.js +25 -343
  262. package/dist/utils/validation.js.map +1 -1
  263. package/docs/BADGE_UPDATES.md +132 -0
  264. package/docs/CI_CD_IMPROVEMENTS.md +191 -0
  265. package/docs/INCREMENTAL_COVERAGE.md +183 -0
  266. package/docs/api/README.md +3 -1
  267. package/docs/api/openapi.json +5 -1
  268. package/docs/api/summary.json +1 -1
  269. package/docs/api/tools/wp_create_post.md +12 -14
  270. package/docs/examples/claude-desktop-config.md +1 -1
  271. package/docs/examples/docker-production.md +100 -93
  272. package/docs/examples/multi-site-setup.md +5 -4
  273. package/docs/examples/single-site-setup.md +3 -4
  274. package/docs/examples/use-case-workflows.md +4 -5
  275. package/docs/integrations/claude-desktop.md +31 -31
  276. package/docs/integrations/cline.md +4 -4
  277. package/docs/integrations/vs-code.md +9 -8
  278. package/docs/user-guides/SMITHERY_SETUP.md +10 -10
  279. package/package.json +44 -25
  280. package/src/cache/CacheInvalidation.ts +12 -5
  281. package/src/cache/CacheManager.ts +18 -15
  282. package/src/cache/HttpCacheWrapper.ts +30 -59
  283. package/src/cache/__tests__/HttpCacheWrapper.test.ts +6 -5
  284. package/src/cache/index.ts +3 -14
  285. package/src/client/CachedWordPressClient.ts +32 -30
  286. package/src/client/MockWordPressClient.ts +4 -2
  287. package/src/client/api.ts +186 -64
  288. package/src/client/auth.ts +15 -40
  289. package/src/client/managers/AuthenticationManager.ts +337 -77
  290. package/src/client/managers/BaseManager.ts +18 -30
  291. package/src/client/managers/RequestManager.ts +39 -44
  292. package/src/config/Config.ts +308 -0
  293. package/src/config/ConfigurationSchema.ts +23 -2
  294. package/src/config/ServerConfiguration.ts +51 -47
  295. package/src/docs/DocumentationGenerator.ts +50 -39
  296. package/src/docs/MarkdownFormatter.ts +19 -29
  297. package/src/dxt-entry.cjs +26 -16
  298. package/src/dxt-entry.ts +17 -27
  299. package/src/index.ts +42 -28
  300. package/src/performance/MetricsCollector.ts +108 -86
  301. package/src/performance/PerformanceAnalytics.ts +69 -164
  302. package/src/performance/PerformanceMonitor.ts +32 -47
  303. package/src/performance/index.ts +2 -10
  304. package/src/security/AISecurityScanner.ts +22 -12
  305. package/src/security/AutomatedRemediation.ts +49 -18
  306. package/src/security/InputValidator.ts +9 -6
  307. package/src/security/SecurityCIPipeline.ts +53 -37
  308. package/src/security/SecurityConfig.ts +22 -22
  309. package/src/security/SecurityConfigManager.ts +23 -19
  310. package/src/security/SecurityMonitoring.ts +24 -21
  311. package/src/security/SecurityReviewer.ts +10 -7
  312. package/src/security/index.ts +64 -29
  313. package/src/server/ConnectionTester.ts +120 -31
  314. package/src/server/ToolRegistry.ts +31 -21
  315. package/src/tools/BaseToolManager.ts +286 -33
  316. package/src/tools/auth.ts +20 -8
  317. package/src/tools/cache.ts +5 -15
  318. package/src/tools/comments.ts +34 -48
  319. package/src/tools/media.ts +41 -53
  320. package/src/tools/pages.ts +32 -54
  321. package/src/tools/performance.ts +141 -176
  322. package/src/tools/posts/PostHandlers.ts +474 -0
  323. package/src/tools/posts/PostToolDefinitions.ts +250 -0
  324. package/src/tools/posts/index.ts +192 -0
  325. package/src/tools/posts.ts +24 -780
  326. package/src/tools/site.ts +34 -19
  327. package/src/tools/taxonomies.ts +41 -57
  328. package/src/tools/users.ts +28 -16
  329. package/src/types/client.ts +114 -138
  330. package/src/types/enhanced.ts +318 -0
  331. package/src/types/index.ts +51 -30
  332. package/src/types/mcp.ts +20 -42
  333. package/src/types/requests.ts +378 -0
  334. package/src/types/tools.ts +608 -0
  335. package/src/types/wordpress.ts +56 -34
  336. package/src/utils/debug.ts +77 -59
  337. package/src/utils/enhancedError.ts +8 -8
  338. package/src/utils/error.ts +53 -31
  339. package/src/utils/logger.ts +351 -0
  340. package/src/utils/streaming.ts +86 -68
  341. package/src/utils/toolWrapper.ts +10 -12
  342. package/src/utils/validation/core.ts +108 -0
  343. package/src/utils/validation/index.ts +36 -0
  344. package/src/utils/validation/network.ts +132 -0
  345. package/src/utils/validation/rateLimit.ts +54 -0
  346. package/src/utils/validation/security.ts +361 -0
  347. package/src/utils/validation/wordpress.ts +180 -0
  348. package/src/utils/validation.ts +47 -470
@@ -4,12 +4,13 @@
4
4
  */
5
5
 
6
6
  // Node.js streaming imports removed - not currently used but available for future enhancement
7
+ import { sanitizeHtml } from "./validation/security.js";
7
8
 
8
9
  export interface StreamingOptions {
9
10
  batchSize?: number;
10
11
  delay?: number;
11
- transformItem?: (item: any) => any;
12
- filterItem?: (item: any) => boolean;
12
+ transformItem?: (item: unknown) => unknown;
13
+ filterItem?: (item: unknown) => boolean;
13
14
  }
14
15
 
15
16
  export interface StreamingResult<T> {
@@ -26,7 +27,7 @@ export interface StreamingResult<T> {
26
27
  export class DataStreamer<T> {
27
28
  private batchSize: number;
28
29
  private delay: number;
29
- private transformItem: ((item: T) => any) | undefined;
30
+ private transformItem: ((item: T) => unknown) | undefined;
30
31
  private filterItem: ((item: T) => boolean) | undefined;
31
32
 
32
33
  constructor(options: StreamingOptions = {}) {
@@ -57,14 +58,14 @@ export class DataStreamer<T> {
57
58
 
58
59
  // Apply transformation if provided
59
60
  const transformedBatch = this.transformItem
60
- ? processedBatch.map((item: any) => this.transformItem!(item))
61
+ ? processedBatch.map((item: unknown) => this.transformItem!(item as T))
61
62
  : processedBatch;
62
63
 
63
64
  processed += batch.length;
64
65
  const hasMore = processed < total;
65
66
 
66
67
  yield {
67
- data: transformedBatch,
68
+ data: transformedBatch as U[],
68
69
  hasMore,
69
70
  cursor: hasMore ? String(i + this.batchSize) : undefined,
70
71
  total,
@@ -103,13 +104,13 @@ export class DataStreamer<T> {
103
104
 
104
105
  // Apply transformation if provided
105
106
  const transformedData = this.transformItem
106
- ? processedData.map((item: any) => this.transformItem!(item))
107
+ ? processedData.map((item: unknown) => this.transformItem!(item as T))
107
108
  : processedData;
108
109
 
109
110
  totalProcessed += result.data.length;
110
111
 
111
112
  yield {
112
- data: transformedData,
113
+ data: transformedData as U[],
113
114
  hasMore: result.hasMore,
114
115
  cursor: result.hasMore ? String(page + 1) : undefined,
115
116
  total: undefined, // Unknown for paginated results
@@ -138,33 +139,39 @@ export class WordPressDataStreamer {
138
139
  * Streams WordPress posts with author and taxonomy information
139
140
  */
140
141
  static async *streamPosts(
141
- posts: any[],
142
+ posts: unknown[],
142
143
  options: {
143
144
  includeAuthor?: boolean;
144
145
  includeCategories?: boolean;
145
146
  includeTags?: boolean;
146
147
  batchSize?: number;
147
148
  } = {},
148
- ): AsyncGenerator<StreamingResult<any>, void, unknown> {
149
- const streamer = new DataStreamer<any>({
149
+ ): AsyncGenerator<StreamingResult<unknown>, void, unknown> {
150
+ const streamer = new DataStreamer<unknown>({
150
151
  batchSize: options.batchSize || 20,
151
- transformItem: (post) => ({
152
- id: post.id,
153
- title: post.title?.rendered || "Untitled",
154
- excerpt: post.excerpt?.rendered
155
- ? post.excerpt.rendered.replace(/<[^>]*>/g, "").substring(0, 150) + "..."
156
- : "No excerpt",
157
- status: post.status,
158
- date: new Date(post.date).toLocaleDateString(),
159
- link: post.link,
160
- author: options.includeAuthor ? post.author : undefined,
161
- categories: options.includeCategories ? post.categories : undefined,
162
- tags: options.includeTags ? post.tags : undefined,
163
- }),
164
- filterItem: (post) => post.status !== "trash", // Filter out trashed posts
152
+ transformItem: (post) => {
153
+ const p = post as Record<string, unknown>;
154
+ const title = p.title as Record<string, unknown> | undefined;
155
+ const excerpt = p.excerpt as Record<string, unknown> | undefined;
156
+ return {
157
+ id: p.id,
158
+ title: title?.rendered || "Untitled",
159
+ excerpt: excerpt?.rendered ? sanitizeHtml(String(excerpt.rendered)).substring(0, 150) + "..." : "No excerpt",
160
+ status: p.status,
161
+ date: new Date(String(p.date)).toLocaleDateString(),
162
+ link: p.link,
163
+ author: options.includeAuthor ? p.author : undefined,
164
+ categories: options.includeCategories ? p.categories : undefined,
165
+ tags: options.includeTags ? p.tags : undefined,
166
+ };
167
+ },
168
+ filterItem: (post) => {
169
+ const p = post as Record<string, unknown>;
170
+ return p.status !== "trash";
171
+ }, // Filter out trashed posts
165
172
  });
166
173
 
167
- const processor = async (batch: any[]) => {
174
+ const processor = async (batch: unknown[]) => {
168
175
  // Simulate processing time for large datasets
169
176
  await new Promise((resolve) => setTimeout(resolve, 10));
170
177
  return batch;
@@ -179,27 +186,32 @@ export class WordPressDataStreamer {
179
186
  * Streams WordPress users with role information
180
187
  */
181
188
  static async *streamUsers(
182
- users: any[],
189
+ users: unknown[],
183
190
  options: {
184
191
  includeRoles?: boolean;
185
192
  includeCapabilities?: boolean;
186
193
  batchSize?: number;
187
194
  } = {},
188
- ): AsyncGenerator<StreamingResult<any>, void, unknown> {
189
- const streamer = new DataStreamer<any>({
195
+ ): AsyncGenerator<StreamingResult<unknown>, void, unknown> {
196
+ const streamer = new DataStreamer<unknown>({
190
197
  batchSize: options.batchSize || 30,
191
- transformItem: (user) => ({
192
- id: user.id,
193
- name: user.name || "No name",
194
- username: user.slug || "unknown",
195
- email: user.email || "No email",
196
- roles: options.includeRoles ? user.roles : undefined,
197
- capabilities: options.includeCapabilities ? Object.keys(user.capabilities || {}) : undefined,
198
- registeredDate: user.registered_date ? new Date(user.registered_date).toLocaleDateString() : "Unknown",
199
- }),
198
+ transformItem: (user) => {
199
+ const u = user as Record<string, unknown>;
200
+ return {
201
+ id: u.id,
202
+ name: u.name || "No name",
203
+ username: u.slug || "unknown",
204
+ email: u.email || "No email",
205
+ roles: options.includeRoles ? u.roles : undefined,
206
+ capabilities: options.includeCapabilities
207
+ ? Object.keys((u.capabilities as Record<string, unknown>) || {})
208
+ : undefined,
209
+ registeredDate: u.registered_date ? new Date(String(u.registered_date)).toLocaleDateString() : "Unknown",
210
+ };
211
+ },
200
212
  });
201
213
 
202
- const processor = async (batch: any[]) => {
214
+ const processor = async (batch: unknown[]) => {
203
215
  // Add user processing logic here if needed
204
216
  return batch;
205
217
  };
@@ -213,35 +225,40 @@ export class WordPressDataStreamer {
213
225
  * Streams WordPress comments with moderation status
214
226
  */
215
227
  static async *streamComments(
216
- comments: any[],
228
+ comments: unknown[],
217
229
  options: {
218
230
  includeAuthor?: boolean;
219
231
  includePost?: boolean;
220
232
  batchSize?: number;
221
233
  } = {},
222
- ): AsyncGenerator<StreamingResult<any>, void, unknown> {
223
- const streamer = new DataStreamer<any>({
234
+ ): AsyncGenerator<StreamingResult<unknown>, void, unknown> {
235
+ const streamer = new DataStreamer<unknown>({
224
236
  batchSize: options.batchSize || 40,
225
- transformItem: (comment) => ({
226
- id: comment.id,
227
- content: comment.content?.rendered
228
- ? comment.content.rendered.replace(/<[^>]*>/g, "").substring(0, 200) + "..."
229
- : "No content",
230
- status: comment.status,
231
- date: new Date(comment.date).toLocaleDateString(),
232
- author: options.includeAuthor
233
- ? {
234
- name: comment.author_name,
235
- email: comment.author_email,
236
- url: comment.author_url,
237
- }
238
- : undefined,
239
- post: options.includePost ? comment.post : undefined,
240
- }),
241
- filterItem: (comment) => comment.status !== "spam", // Filter out spam comments
237
+ transformItem: (comment) => {
238
+ const c = comment as Record<string, unknown>;
239
+ const content = c.content as Record<string, unknown> | undefined;
240
+ return {
241
+ id: c.id,
242
+ content: content?.rendered ? sanitizeHtml(String(content.rendered)).substring(0, 200) + "..." : "No content",
243
+ status: c.status,
244
+ date: new Date(String(c.date)).toLocaleDateString(),
245
+ author: options.includeAuthor
246
+ ? {
247
+ name: c.author_name,
248
+ email: c.author_email,
249
+ url: c.author_url,
250
+ }
251
+ : undefined,
252
+ post: options.includePost ? c.post : undefined,
253
+ };
254
+ },
255
+ filterItem: (comment) => {
256
+ const c = comment as Record<string, unknown>;
257
+ return c.status !== "spam";
258
+ }, // Filter out spam comments
242
259
  });
243
260
 
244
- const processor = async (batch: any[]) => {
261
+ const processor = async (batch: unknown[]) => {
245
262
  // Add comment processing logic here if needed
246
263
  return batch;
247
264
  };
@@ -260,7 +277,7 @@ export class StreamingUtils {
260
277
  * Formats streaming results for display
261
278
  */
262
279
  static formatStreamingResponse(
263
- results: StreamingResult<any>[],
280
+ results: StreamingResult<unknown>[],
264
281
  type: "posts" | "users" | "comments" | "media" = "posts",
265
282
  ): string {
266
283
  const allData = results.flatMap((result) => result.data);
@@ -290,12 +307,15 @@ export class StreamingUtils {
290
307
 
291
308
  // Format individual items
292
309
  allData.forEach((item, index) => {
293
- response += `${index + 1}. **${item.title || item.name || item.content?.substring(0, 50) || "Item"}**\n`;
310
+ // Type-safe property access
311
+ const itemObj = item as Record<string, unknown>;
312
+ const title = itemObj.title || itemObj.name || (itemObj.content as string)?.substring(0, 50) || "Item";
313
+ response += `${index + 1}. **${title}**\n`;
294
314
 
295
- if (item.excerpt) response += ` 📝 ${item.excerpt}\n`;
296
- if (item.email) response += ` 📧 ${item.email}\n`;
297
- if (item.status) response += ` 🏷️ Status: ${item.status}\n`;
298
- if (item.date) response += ` 📅 Date: ${item.date}\n`;
315
+ if (itemObj.excerpt) response += ` 📝 ${itemObj.excerpt}\n`;
316
+ if (itemObj.email) response += ` 📧 ${itemObj.email}\n`;
317
+ if (itemObj.status) response += ` 🏷️ Status: ${itemObj.status}\n`;
318
+ if (itemObj.date) response += ` 📅 Date: ${itemObj.date}\n`;
299
319
 
300
320
  response += "\n";
301
321
  });
@@ -321,7 +341,6 @@ export class StreamingUtils {
321
341
 
322
342
  const results: T[] = [];
323
343
  let offset = 0;
324
- let hasMore = true;
325
344
 
326
345
  // Initial load
327
346
  const initialBatch = await fetcher(offset, initialLoad);
@@ -333,11 +352,10 @@ export class StreamingUtils {
333
352
  }
334
353
 
335
354
  // Progressive loading
336
- while (hasMore && results.length < maxItems) {
355
+ while (results.length < maxItems) {
337
356
  const batch = await fetcher(offset, batchSize);
338
357
 
339
358
  if (batch.length === 0) {
340
- hasMore = false;
341
359
  break;
342
360
  }
343
361
 
@@ -4,11 +4,13 @@
4
4
  */
5
5
 
6
6
  import { getErrorMessage } from "./error.js";
7
+ import type { IWordPressClient } from '../types/client.js';
8
+ import type { BaseToolParams } from '../types/tools.js';
7
9
 
8
10
  /**
9
11
  * Wrapper for tool methods that standardizes error handling
10
12
  */
11
- export function withErrorHandling<T extends any[], R>(
13
+ export function withErrorHandling<T extends readonly unknown[], R>(
12
14
  operation: string,
13
15
  fn: (...args: T) => Promise<R>,
14
16
  ): (...args: T) => Promise<R> {
@@ -24,7 +26,7 @@ export function withErrorHandling<T extends any[], R>(
24
26
  /**
25
27
  * Wrapper for tool methods with validation
26
28
  */
27
- export function withValidation<T extends any[], R>(
29
+ export function withValidation<T extends readonly unknown[], R>(
28
30
  operation: string,
29
31
  validator: (...args: T) => void,
30
32
  fn: (...args: T) => Promise<R>,
@@ -43,7 +45,7 @@ export function withValidation<T extends any[], R>(
43
45
  * Common validation functions
44
46
  */
45
47
  export const validators = {
46
- requireSite: (client: any, params: any) => {
48
+ requireSite: (client: IWordPressClient | null | undefined, params: BaseToolParams) => {
47
49
  if (!client) {
48
50
  throw new Error("WordPress client is required");
49
51
  }
@@ -55,13 +57,13 @@ export const validators = {
55
57
  }
56
58
  },
57
59
 
58
- requireNonEmpty: (value: any, fieldName: string) => {
60
+ requireNonEmpty: (value: unknown, fieldName: string) => {
59
61
  if (!value || (typeof value === "string" && value.trim() === "")) {
60
62
  throw new Error(`${fieldName} cannot be empty`);
61
63
  }
62
64
  },
63
65
 
64
- requireFields: (params: any, fields: string[]) => {
66
+ requireFields: (params: Record<string, unknown>, fields: readonly string[]) => {
65
67
  for (const field of fields) {
66
68
  if (params[field] === undefined || params[field] === null) {
67
69
  throw new Error(`${field} is required`);
@@ -74,14 +76,10 @@ export const validators = {
74
76
  * Decorator for class methods to add error handling
75
77
  */
76
78
  export function errorHandler(operation: string) {
77
- return function (
78
- target: any,
79
- propertyKey: string,
80
- descriptor: PropertyDescriptor,
81
- ) {
79
+ return function (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) {
82
80
  const originalMethod = descriptor.value;
83
81
 
84
- descriptor.value = async function (...args: any[]) {
82
+ descriptor.value = async function (...args: unknown[]) {
85
83
  try {
86
84
  return await originalMethod.apply(this, args);
87
85
  } catch (error) {
@@ -103,7 +101,7 @@ export function formatSuccessResponse(content: string): string {
103
101
  /**
104
102
  * Helper to format error responses consistently
105
103
  */
106
- export function formatErrorResponse(operation: string, error: any): never {
104
+ export function formatErrorResponse(operation: string, error: unknown): never {
107
105
  const message = getErrorMessage(error);
108
106
  throw new Error(`${operation}: ${message}`);
109
107
  }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Core Validation Utilities
3
+ *
4
+ * Basic validation functions for common data types including IDs, strings, and arrays.
5
+ * These validators form the foundation for more specific validation logic.
6
+ */
7
+
8
+ import { WordPressAPIError } from "../../types/client.js";
9
+ import { WordPressId, createWordPressId } from "../../types/enhanced.js";
10
+
11
+ /**
12
+ * Validates and sanitizes numeric IDs with comprehensive edge case handling
13
+ * Returns branded WordPress ID type for enhanced type safety
14
+ */
15
+ export function validateId(id: unknown, fieldName: string = "id"): WordPressId {
16
+ // Handle null/undefined
17
+ if (id === null || id === undefined) {
18
+ throw new WordPressAPIError(`${fieldName} is required`, 400, "MISSING_PARAMETER");
19
+ }
20
+
21
+ // Convert to string first to handle various input types
22
+ const strId = String(id).trim();
23
+
24
+ // Check for empty string after trim
25
+ if (strId === "") {
26
+ throw new WordPressAPIError(`${fieldName} cannot be empty`, 400, "INVALID_PARAMETER");
27
+ }
28
+
29
+ // Handle decimal inputs
30
+ if (strId.includes(".")) {
31
+ throw new WordPressAPIError(`${fieldName} must be a whole number, not a decimal`, 400, "INVALID_PARAMETER");
32
+ }
33
+
34
+ const numId = parseInt(strId, 10);
35
+
36
+ // Check for NaN
37
+ if (isNaN(numId)) {
38
+ throw new WordPressAPIError(`Invalid ${fieldName}: "${id}" is not a valid number`, 400, "INVALID_PARAMETER");
39
+ }
40
+
41
+ // Check for negative or zero
42
+ if (numId <= 0) {
43
+ throw new WordPressAPIError(
44
+ `Invalid ${fieldName}: must be a positive number (got ${numId})`,
45
+ 400,
46
+ "INVALID_PARAMETER",
47
+ );
48
+ }
49
+
50
+ // Check for max int32 limit (WordPress database limit)
51
+ if (numId > 2147483647) {
52
+ throw new WordPressAPIError(
53
+ `Invalid ${fieldName}: exceeds maximum allowed value (2147483647)`,
54
+ 400,
55
+ "INVALID_PARAMETER",
56
+ );
57
+ }
58
+
59
+ return createWordPressId(numId);
60
+ }
61
+
62
+ /**
63
+ * Validates string length within bounds
64
+ */
65
+ export function validateString(
66
+ value: unknown,
67
+ fieldName: string,
68
+ minLength: number = 1,
69
+ maxLength: number = 1000,
70
+ ): string {
71
+ if (typeof value !== "string") {
72
+ throw new WordPressAPIError(`Invalid ${fieldName}: must be a string`, 400, "INVALID_PARAMETER");
73
+ }
74
+
75
+ const trimmed = value.trim();
76
+ if (trimmed.length < minLength || trimmed.length > maxLength) {
77
+ throw new WordPressAPIError(
78
+ `Invalid ${fieldName}: length must be between ${minLength} and ${maxLength} characters`,
79
+ 400,
80
+ "INVALID_PARAMETER",
81
+ );
82
+ }
83
+
84
+ return trimmed;
85
+ }
86
+
87
+ /**
88
+ * Validates arrays with size constraints and type safety
89
+ */
90
+ export function validateArray<T>(value: unknown, fieldName: string, minItems: number = 0, maxItems: number = 100): T[] {
91
+ if (!Array.isArray(value)) {
92
+ throw new WordPressAPIError(`Invalid ${fieldName}: must be an array`, 400, "INVALID_PARAMETER");
93
+ }
94
+
95
+ if (value.length < minItems) {
96
+ throw new WordPressAPIError(`Invalid ${fieldName}: must have at least ${minItems} items`, 400, "INVALID_PARAMETER");
97
+ }
98
+
99
+ if (value.length > maxItems) {
100
+ throw new WordPressAPIError(
101
+ `Invalid ${fieldName}: cannot have more than ${maxItems} items`,
102
+ 400,
103
+ "INVALID_PARAMETER",
104
+ );
105
+ }
106
+
107
+ return value as T[];
108
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Validation Utilities - Modular Export Index
3
+ *
4
+ * This module re-exports all validation functions from their focused modules
5
+ * for backward compatibility and convenient imports.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // Import all validators (backward compatible)
10
+ * import { validateId, validateUrl, validatePostParams } from "./utils/validation";
11
+ *
12
+ * // Or import from specific modules
13
+ * import { validateId } from "./utils/validation/core";
14
+ * import { validateUrl } from "./utils/validation/network";
15
+ * import { validatePostParams } from "./utils/validation/wordpress";
16
+ * ```
17
+ */
18
+
19
+ // Core validators - basic data types
20
+ export { validateId, validateString, validateArray } from "./core.js";
21
+
22
+ // Security validators - file and content safety
23
+ export { validateFilePath, validateFileSize, validateMimeType, sanitizeHtml } from "./security.js";
24
+
25
+ // Network validators - URLs, emails, usernames
26
+ export { validateUrl, validateEmail, validateUsername } from "./network.js";
27
+
28
+ // WordPress-specific validators
29
+ export { validatePostStatus, validateSearchQuery, validatePaginationParams, validatePostParams } from "./wordpress.js";
30
+
31
+ // Rate limiting utilities
32
+ export { RateLimiter, authRateLimiter } from "./rateLimit.js";
33
+
34
+ // Re-export type dependencies for convenience
35
+ export type { WordPressId } from "../../types/enhanced.js";
36
+ export { WordPressAPIError } from "../../types/client.js";
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Network Validation Utilities
3
+ *
4
+ * Validation functions for network-related data including URLs, email addresses,
5
+ * and username validation with security considerations.
6
+ */
7
+
8
+ import { WordPressAPIError } from "../../types/client.js";
9
+ import { config } from "../../config/Config.js";
10
+
11
+ /**
12
+ * Validates and sanitizes URLs with enhanced edge case handling
13
+ */
14
+ export function validateUrl(url: string, fieldName: string = "url"): string {
15
+ // Check for empty or whitespace-only URLs
16
+ const trimmedUrl = url.trim();
17
+ if (!trimmedUrl) {
18
+ throw new WordPressAPIError(`${fieldName} cannot be empty`, 400, "INVALID_PARAMETER");
19
+ }
20
+
21
+ // Remove trailing slashes for consistency
22
+ const cleanUrl = trimmedUrl.replace(/\/+$/, "");
23
+
24
+ // Check for common URL mistakes
25
+ if (!cleanUrl.match(/^https?:\/\//i)) {
26
+ throw new WordPressAPIError(
27
+ `Invalid ${fieldName}: must start with http:// or https:// (got "${cleanUrl}")`,
28
+ 400,
29
+ "INVALID_PARAMETER",
30
+ );
31
+ }
32
+
33
+ try {
34
+ const urlObj = new URL(cleanUrl);
35
+
36
+ // Only allow http and https protocols
37
+ if (!["http:", "https:"].includes(urlObj.protocol)) {
38
+ throw new WordPressAPIError(
39
+ `Invalid ${fieldName}: only HTTP and HTTPS protocols are allowed`,
40
+ 400,
41
+ "INVALID_PARAMETER",
42
+ );
43
+ }
44
+
45
+ // Validate hostname
46
+ if (!urlObj.hostname || urlObj.hostname.length < 3) {
47
+ throw new WordPressAPIError(`Invalid ${fieldName}: hostname is missing or too short`, 400, "INVALID_PARAMETER");
48
+ }
49
+
50
+ // Check for localhost in production
51
+ if (config().app.isProduction && (urlObj.hostname === "localhost" || urlObj.hostname === "127.0.0.1")) {
52
+ throw new WordPressAPIError(
53
+ `Invalid ${fieldName}: localhost URLs are not allowed in production`,
54
+ 400,
55
+ "INVALID_PARAMETER",
56
+ );
57
+ }
58
+
59
+ // Validate port if present
60
+ if (urlObj.port) {
61
+ const port = parseInt(urlObj.port);
62
+ if (port < 1 || port > 65535) {
63
+ throw new WordPressAPIError(
64
+ `Invalid ${fieldName}: port number must be between 1 and 65535`,
65
+ 400,
66
+ "INVALID_PARAMETER",
67
+ );
68
+ }
69
+ }
70
+
71
+ return cleanUrl;
72
+ } catch (error) {
73
+ if (error instanceof WordPressAPIError) {
74
+ throw error;
75
+ }
76
+ throw new WordPressAPIError(`Invalid ${fieldName}: malformed URL "${cleanUrl}"`, 400, "INVALID_PARAMETER");
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Validates email addresses
82
+ */
83
+ export function validateEmail(email: string): string {
84
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
85
+ if (!emailRegex.test(email)) {
86
+ throw new WordPressAPIError("Invalid email address format", 400, "INVALID_PARAMETER");
87
+ }
88
+ return email.toLowerCase();
89
+ }
90
+
91
+ /**
92
+ * Validates username format with enhanced security checks
93
+ */
94
+ export function validateUsername(username: string): string {
95
+ // Trim and check for empty
96
+ const trimmed = username.trim();
97
+ if (!trimmed) {
98
+ throw new WordPressAPIError("Username cannot be empty", 400, "INVALID_PARAMETER");
99
+ }
100
+
101
+ // WordPress username rules: alphanumeric, space, underscore, hyphen, period, @ symbol
102
+ const usernameRegex = /^[a-zA-Z0-9 _.\-@]+$/;
103
+ if (!usernameRegex.test(trimmed)) {
104
+ throw new WordPressAPIError(
105
+ "Invalid username: can only contain letters, numbers, spaces, and _.-@ symbols",
106
+ 400,
107
+ "INVALID_PARAMETER",
108
+ );
109
+ }
110
+
111
+ // Length validation
112
+ if (trimmed.length < 3 || trimmed.length > 60) {
113
+ throw new WordPressAPIError(
114
+ `Invalid username: must be between 3 and 60 characters (got ${trimmed.length})`,
115
+ 400,
116
+ "INVALID_PARAMETER",
117
+ );
118
+ }
119
+
120
+ // Check for consecutive spaces
121
+ if (/\s{2,}/.test(trimmed)) {
122
+ throw new WordPressAPIError("Invalid username: cannot contain consecutive spaces", 400, "INVALID_PARAMETER");
123
+ }
124
+
125
+ // Security: Prevent common problematic usernames
126
+ const blacklist = ["admin", "root", "wordpress", "wp-admin", "administrator"];
127
+ if (blacklist.includes(trimmed.toLowerCase())) {
128
+ throw new WordPressAPIError(`Username "${trimmed}" is reserved and cannot be used`, 400, "RESERVED_USERNAME");
129
+ }
130
+
131
+ return trimmed;
132
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Rate Limiting Utilities
3
+ *
4
+ * Simple in-memory rate limiting for authentication and API requests.
5
+ * For production, consider using Redis or similar distributed cache.
6
+ */
7
+
8
+ import { WordPressAPIError } from "../../types/client.js";
9
+
10
+ /**
11
+ * Rate limiting tracker (simple in-memory implementation)
12
+ * For production, use Redis or similar
13
+ */
14
+ class RateLimiter {
15
+ private attempts: Map<string, { count: number; resetTime: number }> = new Map();
16
+
17
+ constructor(
18
+ private maxAttempts: number = 5,
19
+ private windowMs: number = 60000, // 1 minute
20
+ ) {}
21
+
22
+ check(identifier: string): void {
23
+ const now = Date.now();
24
+ const record = this.attempts.get(identifier);
25
+
26
+ if (!record || record.resetTime < now) {
27
+ this.attempts.set(identifier, {
28
+ count: 1,
29
+ resetTime: now + this.windowMs,
30
+ });
31
+ return;
32
+ }
33
+
34
+ if (record.count >= this.maxAttempts) {
35
+ const waitTime = Math.ceil((record.resetTime - now) / 1000);
36
+ throw new WordPressAPIError(
37
+ `Rate limit exceeded. Please wait ${waitTime} seconds before trying again.`,
38
+ 429,
39
+ "RATE_LIMIT_EXCEEDED",
40
+ );
41
+ }
42
+
43
+ record.count++;
44
+ }
45
+
46
+ reset(identifier: string): void {
47
+ this.attempts.delete(identifier);
48
+ }
49
+ }
50
+
51
+ // Export a default rate limiter for authentication attempts
52
+ export const authRateLimiter = new RateLimiter(5, 300000); // 5 attempts per 5 minutes
53
+
54
+ export { RateLimiter };