mcp-wordpress 2.11.13 → 3.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 (247) hide show
  1. package/README.md +14 -29
  2. package/dist/cache/CacheInvalidation.js.map +1 -1
  3. package/dist/cache/CacheManager.d.ts +7 -0
  4. package/dist/cache/CacheManager.d.ts.map +1 -1
  5. package/dist/cache/CacheManager.js +21 -7
  6. package/dist/cache/CacheManager.js.map +1 -1
  7. package/dist/cache/HttpCacheWrapper.js.map +1 -1
  8. package/dist/cache/SEOCacheManager.d.ts.map +1 -1
  9. package/dist/cache/SEOCacheManager.js +6 -1
  10. package/dist/cache/SEOCacheManager.js.map +1 -1
  11. package/dist/cache/index.d.ts.map +1 -1
  12. package/dist/cache/index.js.map +1 -1
  13. package/dist/client/CachedWordPressClient.d.ts.map +1 -1
  14. package/dist/client/CachedWordPressClient.js.map +1 -1
  15. package/dist/client/MockWordPressClient.d.ts.map +1 -1
  16. package/dist/client/MockWordPressClient.js.map +1 -1
  17. package/dist/client/SEOWordPressClient.d.ts.map +1 -1
  18. package/dist/client/SEOWordPressClient.js.map +1 -1
  19. package/dist/client/api.d.ts +11 -26
  20. package/dist/client/api.d.ts.map +1 -1
  21. package/dist/client/api.js +111 -203
  22. package/dist/client/api.js.map +1 -1
  23. package/dist/client/auth.d.ts.map +1 -1
  24. package/dist/client/auth.js.map +1 -1
  25. package/dist/client/managers/AuthManager.d.ts.map +1 -1
  26. package/dist/client/managers/RequestManager.d.ts.map +1 -1
  27. package/dist/client/managers/RequestManager.js +6 -5
  28. package/dist/client/managers/RequestManager.js.map +1 -1
  29. package/dist/client/managers/composed/MigrationAdapter.d.ts +3 -3
  30. package/dist/client/managers/composed/MigrationAdapter.d.ts.map +1 -1
  31. package/dist/client/managers/composed/MigrationAdapter.js +2 -2
  32. package/dist/client/managers/composed/MigrationAdapter.js.map +1 -1
  33. package/dist/client/managers/composed/index.d.ts +7 -7
  34. package/dist/client/managers/composed/index.d.ts.map +1 -1
  35. package/dist/client/managers/composed/index.js +6 -6
  36. package/dist/client/managers/composed/index.js.map +1 -1
  37. package/dist/client/managers/implementations/ConfigurationProviderImpl.d.ts +1 -1
  38. package/dist/client/managers/implementations/ConfigurationProviderImpl.d.ts.map +1 -1
  39. package/dist/client/managers/implementations/ErrorHandlerImpl.d.ts +1 -1
  40. package/dist/client/managers/implementations/ErrorHandlerImpl.d.ts.map +1 -1
  41. package/dist/client/managers/implementations/ParameterValidatorImpl.d.ts +1 -1
  42. package/dist/client/managers/implementations/ParameterValidatorImpl.d.ts.map +1 -1
  43. package/dist/client/operations/comments.d.ts +58 -0
  44. package/dist/client/operations/comments.d.ts.map +1 -0
  45. package/dist/client/operations/comments.js +74 -0
  46. package/dist/client/operations/comments.js.map +1 -0
  47. package/dist/client/operations/index.d.ts +12 -0
  48. package/dist/client/operations/index.d.ts.map +1 -0
  49. package/dist/client/operations/index.js +12 -0
  50. package/dist/client/operations/index.js.map +1 -0
  51. package/dist/client/operations/media.d.ts +55 -0
  52. package/dist/client/operations/media.d.ts.map +1 -0
  53. package/dist/client/operations/media.js +132 -0
  54. package/dist/client/operations/media.js.map +1 -0
  55. package/dist/client/operations/pages.d.ts +50 -0
  56. package/dist/client/operations/pages.d.ts.map +1 -0
  57. package/dist/client/operations/pages.js +56 -0
  58. package/dist/client/operations/pages.js.map +1 -0
  59. package/dist/client/operations/posts.d.ts +50 -0
  60. package/dist/client/operations/posts.d.ts.map +1 -0
  61. package/dist/client/operations/posts.js +53 -0
  62. package/dist/client/operations/posts.js.map +1 -0
  63. package/dist/client/operations/site.d.ts +60 -0
  64. package/dist/client/operations/site.d.ts.map +1 -0
  65. package/dist/client/operations/site.js +83 -0
  66. package/dist/client/operations/site.js.map +1 -0
  67. package/dist/client/operations/taxonomies.d.ts +69 -0
  68. package/dist/client/operations/taxonomies.d.ts.map +1 -0
  69. package/dist/client/operations/taxonomies.js +87 -0
  70. package/dist/client/operations/taxonomies.js.map +1 -0
  71. package/dist/client/operations/users.d.ts +50 -0
  72. package/dist/client/operations/users.d.ts.map +1 -0
  73. package/dist/client/operations/users.js +57 -0
  74. package/dist/client/operations/users.js.map +1 -0
  75. package/dist/config/ServerConfiguration.d.ts.map +1 -1
  76. package/dist/config/ServerConfiguration.js.map +1 -1
  77. package/dist/docs/DocumentationGenerator.js.map +1 -1
  78. package/dist/performance/MetricsCollector.d.ts.map +1 -1
  79. package/dist/performance/MetricsCollector.js.map +1 -1
  80. package/dist/performance/PerformanceMonitor.js.map +1 -1
  81. package/dist/security/AISecurityScanner.d.ts.map +1 -1
  82. package/dist/security/AISecurityScanner.js +3 -2
  83. package/dist/security/AISecurityScanner.js.map +1 -1
  84. package/dist/security/AutomatedRemediation.js.map +1 -1
  85. package/dist/security/InputValidator.d.ts.map +1 -1
  86. package/dist/security/InputValidator.js +30 -18
  87. package/dist/security/InputValidator.js.map +1 -1
  88. package/dist/security/SecurityCIPipeline.d.ts +19 -196
  89. package/dist/security/SecurityCIPipeline.d.ts.map +1 -1
  90. package/dist/security/SecurityCIPipeline.js +95 -639
  91. package/dist/security/SecurityCIPipeline.js.map +1 -1
  92. package/dist/security/SecurityConfig.js.map +1 -1
  93. package/dist/security/SecurityConfigManager.js.map +1 -1
  94. package/dist/security/SecurityGateExecutor.d.ts +67 -0
  95. package/dist/security/SecurityGateExecutor.d.ts.map +1 -0
  96. package/dist/security/SecurityGateExecutor.js +363 -0
  97. package/dist/security/SecurityGateExecutor.js.map +1 -0
  98. package/dist/security/SecurityMonitoring.js.map +1 -1
  99. package/dist/security/SecurityReportGenerator.d.ts +65 -0
  100. package/dist/security/SecurityReportGenerator.d.ts.map +1 -0
  101. package/dist/security/SecurityReportGenerator.js +210 -0
  102. package/dist/security/SecurityReportGenerator.js.map +1 -0
  103. package/dist/security/SecurityReviewer.js.map +1 -1
  104. package/dist/security/SecurityTypes.d.ts +188 -0
  105. package/dist/security/SecurityTypes.d.ts.map +1 -0
  106. package/dist/security/SecurityTypes.js +6 -0
  107. package/dist/security/SecurityTypes.js.map +1 -0
  108. package/dist/security/index.d.ts +5 -28
  109. package/dist/security/index.d.ts.map +1 -1
  110. package/dist/security/index.js +4 -0
  111. package/dist/security/index.js.map +1 -1
  112. package/dist/server/ConnectionTester.d.ts.map +1 -1
  113. package/dist/server/ConnectionTester.js.map +1 -1
  114. package/dist/server/ToolRegistry.d.ts.map +1 -1
  115. package/dist/server/ToolRegistry.js.map +1 -1
  116. package/dist/tools/BaseToolManager.d.ts.map +1 -1
  117. package/dist/tools/BaseToolManager.js.map +1 -1
  118. package/dist/tools/auth.d.ts.map +1 -1
  119. package/dist/tools/auth.js.map +1 -1
  120. package/dist/tools/cache.d.ts.map +1 -1
  121. package/dist/tools/cache.js.map +1 -1
  122. package/dist/tools/comments.d.ts.map +1 -1
  123. package/dist/tools/comments.js.map +1 -1
  124. package/dist/tools/media.d.ts.map +1 -1
  125. package/dist/tools/media.js.map +1 -1
  126. package/dist/tools/pages.d.ts.map +1 -1
  127. package/dist/tools/pages.js.map +1 -1
  128. package/dist/tools/performance/PerformanceHelpers.d.ts +116 -0
  129. package/dist/tools/performance/PerformanceHelpers.d.ts.map +1 -0
  130. package/dist/tools/performance/PerformanceHelpers.js +298 -0
  131. package/dist/tools/performance/PerformanceHelpers.js.map +1 -0
  132. package/dist/tools/performance/PerformanceTools.d.ts +54 -0
  133. package/dist/tools/performance/PerformanceTools.d.ts.map +1 -0
  134. package/dist/tools/performance/PerformanceTools.js +687 -0
  135. package/dist/tools/performance/PerformanceTools.js.map +1 -0
  136. package/dist/tools/performance/index.d.ts +8 -0
  137. package/dist/tools/performance/index.d.ts.map +1 -0
  138. package/dist/tools/performance/index.js +8 -0
  139. package/dist/tools/performance/index.js.map +1 -0
  140. package/dist/tools/performance.d.ts +12 -69
  141. package/dist/tools/performance.d.ts.map +1 -1
  142. package/dist/tools/performance.js +12 -920
  143. package/dist/tools/performance.js.map +1 -1
  144. package/dist/tools/posts.d.ts.map +1 -1
  145. package/dist/tools/seo/analyzers/ContentAnalyzer.d.ts.map +1 -1
  146. package/dist/tools/seo/analyzers/ContentAnalyzer.js +14 -3
  147. package/dist/tools/seo/analyzers/ContentAnalyzer.js.map +1 -1
  148. package/dist/tools/seo/auditors/SiteAuditor.d.ts.map +1 -1
  149. package/dist/tools/seo/auditors/SiteAuditor.js +12 -3
  150. package/dist/tools/seo/auditors/SiteAuditor.js.map +1 -1
  151. package/dist/tools/seo/generators/MetaGenerator.d.ts.map +1 -1
  152. package/dist/tools/seo/generators/MetaGenerator.js +25 -8
  153. package/dist/tools/seo/generators/MetaGenerator.js.map +1 -1
  154. package/dist/tools/seo/generators/SchemaGenerator.d.ts.map +1 -1
  155. package/dist/tools/seo/generators/SchemaGenerator.js.map +1 -1
  156. package/dist/tools/seo/optimizers/InternalLinkingSuggester.d.ts.map +1 -1
  157. package/dist/tools/seo/optimizers/InternalLinkingSuggester.js.map +1 -1
  158. package/dist/tools/site.d.ts.map +1 -1
  159. package/dist/tools/site.js.map +1 -1
  160. package/dist/tools/taxonomies.d.ts.map +1 -1
  161. package/dist/tools/taxonomies.js.map +1 -1
  162. package/dist/tools/users.d.ts.map +1 -1
  163. package/dist/tools/users.js.map +1 -1
  164. package/dist/utils/CircuitBreaker.d.ts +243 -0
  165. package/dist/utils/CircuitBreaker.d.ts.map +1 -0
  166. package/dist/utils/CircuitBreaker.js +456 -0
  167. package/dist/utils/CircuitBreaker.js.map +1 -0
  168. package/dist/utils/debug.d.ts.map +1 -1
  169. package/dist/utils/debug.js.map +1 -1
  170. package/dist/utils/error.js.map +1 -1
  171. package/dist/utils/index.d.ts +1 -0
  172. package/dist/utils/index.d.ts.map +1 -1
  173. package/dist/utils/index.js +2 -0
  174. package/dist/utils/index.js.map +1 -1
  175. package/dist/utils/logger.js.map +1 -1
  176. package/dist/utils/toolWrapper.d.ts.map +1 -1
  177. package/docs/DEPRECATIONS.md +157 -0
  178. package/package.json +2 -3
  179. package/src/cache/CacheInvalidation.ts +1 -1
  180. package/src/cache/CacheManager.ts +25 -8
  181. package/src/cache/HttpCacheWrapper.ts +1 -1
  182. package/src/cache/SEOCacheManager.ts +9 -3
  183. package/src/cache/index.ts +1 -1
  184. package/src/client/CachedWordPressClient.ts +6 -6
  185. package/src/client/MockWordPressClient.ts +3 -3
  186. package/src/client/SEOWordPressClient.ts +6 -6
  187. package/src/client/api.ts +129 -215
  188. package/src/client/auth.ts +3 -3
  189. package/src/client/managers/AuthManager.ts +1 -1
  190. package/src/client/managers/RequestManager.ts +6 -7
  191. package/src/client/managers/composed/MigrationAdapter.ts +4 -4
  192. package/src/client/managers/composed/index.ts +7 -7
  193. package/src/client/managers/implementations/ConfigurationProviderImpl.ts +1 -1
  194. package/src/client/managers/implementations/ErrorHandlerImpl.ts +1 -1
  195. package/src/client/managers/implementations/ParameterValidatorImpl.ts +1 -1
  196. package/src/client/operations/comments.ts +96 -0
  197. package/src/client/operations/index.ts +12 -0
  198. package/src/client/operations/media.ts +162 -0
  199. package/src/client/operations/pages.ts +71 -0
  200. package/src/client/operations/posts.ts +68 -0
  201. package/src/client/operations/site.ts +106 -0
  202. package/src/client/operations/taxonomies.ts +115 -0
  203. package/src/client/operations/users.ts +72 -0
  204. package/src/config/ServerConfiguration.ts +6 -6
  205. package/src/docs/DocumentationGenerator.ts +3 -3
  206. package/src/performance/MetricsCollector.ts +4 -4
  207. package/src/performance/PerformanceMonitor.ts +1 -1
  208. package/src/security/AISecurityScanner.ts +4 -3
  209. package/src/security/AutomatedRemediation.ts +1 -1
  210. package/src/security/InputValidator.ts +36 -19
  211. package/src/security/SecurityCIPipeline.ts +130 -953
  212. package/src/security/SecurityConfig.ts +1 -1
  213. package/src/security/SecurityConfigManager.ts +1 -1
  214. package/src/security/SecurityGateExecutor.ts +485 -0
  215. package/src/security/SecurityMonitoring.ts +1 -1
  216. package/src/security/SecurityReportGenerator.ts +272 -0
  217. package/src/security/SecurityReviewer.ts +1 -1
  218. package/src/security/SecurityTypes.ts +199 -0
  219. package/src/security/index.ts +6 -1
  220. package/src/server/ConnectionTester.ts +4 -4
  221. package/src/server/ToolRegistry.ts +6 -6
  222. package/src/tools/BaseToolManager.ts +2 -2
  223. package/src/tools/auth.ts +3 -3
  224. package/src/tools/cache.ts +3 -3
  225. package/src/tools/comments.ts +3 -3
  226. package/src/tools/media.ts +3 -3
  227. package/src/tools/pages.ts +3 -3
  228. package/src/tools/performance/PerformanceHelpers.ts +330 -0
  229. package/src/tools/performance/PerformanceTools.ts +854 -0
  230. package/src/tools/performance/index.ts +8 -0
  231. package/src/tools/performance.ts +12 -1073
  232. package/src/tools/posts.ts +1 -1
  233. package/src/tools/seo/analyzers/ContentAnalyzer.ts +21 -7
  234. package/src/tools/seo/auditors/SiteAuditor.ts +18 -7
  235. package/src/tools/seo/generators/MetaGenerator.ts +33 -12
  236. package/src/tools/seo/generators/SchemaGenerator.ts +3 -3
  237. package/src/tools/seo/optimizers/InternalLinkingSuggester.ts +4 -4
  238. package/src/tools/site.ts +3 -3
  239. package/src/tools/taxonomies.ts +3 -3
  240. package/src/tools/users.ts +4 -4
  241. package/src/utils/CircuitBreaker.ts +572 -0
  242. package/src/utils/debug.ts +3 -3
  243. package/src/utils/error.ts +1 -1
  244. package/src/utils/index.ts +3 -0
  245. package/src/utils/logger.ts +1 -1
  246. package/src/utils/toolWrapper.ts +2 -2
  247. package/docs/BRANCH_PROTECTION.md +0 -0
@@ -0,0 +1,572 @@
1
+ /**
2
+ * Circuit Breaker Pattern Implementation
3
+ *
4
+ * Provides fault tolerance for external service calls by preventing
5
+ * cascading failures and allowing systems to recover gracefully.
6
+ *
7
+ * States:
8
+ * - CLOSED: Normal operation, requests pass through
9
+ * - OPEN: Failures exceeded threshold, requests fail fast
10
+ * - HALF_OPEN: Testing if service recovered, limited requests allowed
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const breaker = new CircuitBreaker({
15
+ * failureThreshold: 5,
16
+ * resetTimeout: 30000,
17
+ * name: 'wordpress-api'
18
+ * });
19
+ *
20
+ * try {
21
+ * const result = await breaker.execute(() => apiCall());
22
+ * } catch (error) {
23
+ * if (error instanceof CircuitBreakerOpenError) {
24
+ * // Circuit is open, use fallback
25
+ * }
26
+ * }
27
+ * ```
28
+ */
29
+
30
+ import { createLogger } from "./logger.js";
31
+
32
+ /**
33
+ * Circuit breaker states
34
+ */
35
+ /**
36
+ * Circuit state values
37
+ */
38
+ export const CircuitState = {
39
+ CLOSED: "CLOSED",
40
+ OPEN: "OPEN",
41
+ HALF_OPEN: "HALF_OPEN",
42
+ } as const;
43
+
44
+ /**
45
+ * Circuit state type
46
+ */
47
+ export type CircuitStateType = (typeof CircuitState)[keyof typeof CircuitState];
48
+
49
+ /**
50
+ * Circuit breaker configuration options
51
+ */
52
+ export interface CircuitBreakerOptions {
53
+ /** Name for logging and identification */
54
+ name: string;
55
+ /** Number of failures before opening circuit (default: 5) */
56
+ failureThreshold?: number;
57
+ /** Time in ms before attempting to close circuit (default: 30000) */
58
+ resetTimeout?: number;
59
+ /** Number of successful calls needed to close circuit from half-open (default: 2) */
60
+ successThreshold?: number;
61
+ /** Time window in ms to count failures (default: 60000) */
62
+ failureWindow?: number;
63
+ /** Timeout for individual operations in ms (default: 30000) */
64
+ timeout?: number;
65
+ /** Function to determine if an error should trip the breaker */
66
+ isFailure?: (error: Error) => boolean;
67
+ /** Callback when circuit opens */
68
+ onOpen?: (name: string, failures: number) => void;
69
+ /** Callback when circuit closes */
70
+ onClose?: (name: string) => void;
71
+ /** Callback when circuit enters half-open state */
72
+ onHalfOpen?: (name: string) => void;
73
+ }
74
+
75
+ /**
76
+ * Circuit breaker statistics
77
+ */
78
+ export interface CircuitBreakerStats {
79
+ state: CircuitStateType;
80
+ failures: number;
81
+ successes: number;
82
+ lastFailure: Date | null;
83
+ lastSuccess: Date | null;
84
+ totalRequests: number;
85
+ failedRequests: number;
86
+ successfulRequests: number;
87
+ rejectedRequests: number;
88
+ timeInCurrentState: number;
89
+ }
90
+
91
+ /**
92
+ * Error thrown when circuit breaker is open
93
+ */
94
+ export class CircuitBreakerOpenError extends Error {
95
+ constructor(
96
+ public readonly circuitName: string,
97
+ public readonly resetTime: number,
98
+ ) {
99
+ super(`Circuit breaker '${circuitName}' is open. Retry after ${Math.ceil(resetTime / 1000)}s`);
100
+ this.name = "CircuitBreakerOpenError";
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Error thrown when operation times out
106
+ */
107
+ export class CircuitBreakerTimeoutError extends Error {
108
+ constructor(
109
+ public readonly circuitName: string,
110
+ public readonly timeout: number,
111
+ ) {
112
+ super(`Circuit breaker '${circuitName}' operation timed out after ${timeout}ms`);
113
+ this.name = "CircuitBreakerTimeoutError";
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Failure record for tracking failures within time window
119
+ */
120
+ interface FailureRecord {
121
+ timestamp: number;
122
+ error: Error;
123
+ }
124
+
125
+ /**
126
+ * Circuit Breaker Implementation
127
+ */
128
+ export class CircuitBreaker {
129
+ private state: CircuitStateType = CircuitState.CLOSED;
130
+ private failures: FailureRecord[] = [];
131
+ private successes: number = 0;
132
+ private lastStateChange: number = Date.now();
133
+ private lastFailure: Date | null = null;
134
+ private lastSuccess: Date | null = null;
135
+
136
+ // Statistics
137
+ private totalRequests: number = 0;
138
+ private failedRequests: number = 0;
139
+ private successfulRequests: number = 0;
140
+ private rejectedRequests: number = 0;
141
+
142
+ // Configuration with defaults
143
+ private readonly name: string;
144
+ private readonly failureThreshold: number;
145
+ private readonly resetTimeout: number;
146
+ private readonly successThreshold: number;
147
+ private readonly failureWindow: number;
148
+ private readonly timeout: number;
149
+ private readonly isFailure: (error: Error) => boolean;
150
+ private readonly onOpen: ((name: string, failures: number) => void) | undefined;
151
+ private readonly onClose: ((name: string) => void) | undefined;
152
+ private readonly onHalfOpen: ((name: string) => void) | undefined;
153
+
154
+ private readonly logger = createLogger("CircuitBreaker");
155
+
156
+ constructor(options: CircuitBreakerOptions) {
157
+ this.name = options.name;
158
+ this.failureThreshold = options.failureThreshold ?? 5;
159
+ this.resetTimeout = options.resetTimeout ?? 30000;
160
+ this.successThreshold = options.successThreshold ?? 2;
161
+ this.failureWindow = options.failureWindow ?? 60000;
162
+ this.timeout = options.timeout ?? 30000;
163
+ this.isFailure = options.isFailure ?? this.defaultIsFailure;
164
+ this.onOpen = options.onOpen;
165
+ this.onClose = options.onClose;
166
+ this.onHalfOpen = options.onHalfOpen;
167
+
168
+ this.logger.debug(`Circuit breaker '${this.name}' initialized`, {
169
+ failureThreshold: this.failureThreshold,
170
+ resetTimeout: this.resetTimeout,
171
+ successThreshold: this.successThreshold,
172
+ });
173
+ }
174
+
175
+ /**
176
+ * Execute an operation through the circuit breaker
177
+ */
178
+ async execute<T>(operation: () => Promise<T>): Promise<T> {
179
+ this.totalRequests++;
180
+
181
+ // Check if circuit should transition from OPEN to HALF_OPEN
182
+ if (this.state === CircuitState.OPEN) {
183
+ if (this.shouldAttemptReset()) {
184
+ this.transitionTo(CircuitState.HALF_OPEN);
185
+ } else {
186
+ this.rejectedRequests++;
187
+ const remainingTime = this.getRemainingResetTime();
188
+ throw new CircuitBreakerOpenError(this.name, remainingTime);
189
+ }
190
+ }
191
+
192
+ try {
193
+ const result = await this.executeWithTimeout(operation);
194
+ this.onSuccess();
195
+ return result;
196
+ } catch (error) {
197
+ this.onError(error as Error);
198
+ throw error;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Execute operation with timeout
204
+ */
205
+ private async executeWithTimeout<T>(operation: () => Promise<T>): Promise<T> {
206
+ return new Promise<T>((resolve, reject) => {
207
+ const timeoutId = setTimeout(() => {
208
+ reject(new CircuitBreakerTimeoutError(this.name, this.timeout));
209
+ }, this.timeout);
210
+
211
+ operation()
212
+ .then((result) => {
213
+ clearTimeout(timeoutId);
214
+ resolve(result);
215
+ })
216
+ .catch((error) => {
217
+ clearTimeout(timeoutId);
218
+ reject(error);
219
+ });
220
+ });
221
+ }
222
+
223
+ /**
224
+ * Handle successful operation
225
+ */
226
+ private onSuccess(): void {
227
+ this.successfulRequests++;
228
+ this.lastSuccess = new Date();
229
+ this.successes++;
230
+
231
+ if (this.state === CircuitState.HALF_OPEN) {
232
+ if (this.successes >= this.successThreshold) {
233
+ this.transitionTo(CircuitState.CLOSED);
234
+ }
235
+ }
236
+
237
+ // Clear old failures when successful in closed state
238
+ if (this.state === CircuitState.CLOSED) {
239
+ this.cleanOldFailures();
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Handle operation error
245
+ */
246
+ private onError(error: Error): void {
247
+ // Check if this error should count as a failure
248
+ if (!this.isFailure(error)) {
249
+ return;
250
+ }
251
+
252
+ this.failedRequests++;
253
+ this.lastFailure = new Date();
254
+
255
+ if (this.state === CircuitState.HALF_OPEN) {
256
+ // Any failure in half-open state reopens the circuit
257
+ this.transitionTo(CircuitState.OPEN);
258
+ return;
259
+ }
260
+
261
+ if (this.state === CircuitState.CLOSED) {
262
+ this.recordFailure(error);
263
+
264
+ // Clean old failures and check threshold
265
+ this.cleanOldFailures();
266
+ if (this.failures.length >= this.failureThreshold) {
267
+ this.transitionTo(CircuitState.OPEN);
268
+ }
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Record a failure
274
+ */
275
+ private recordFailure(error: Error): void {
276
+ this.failures.push({
277
+ timestamp: Date.now(),
278
+ error,
279
+ });
280
+ }
281
+
282
+ /**
283
+ * Remove failures outside the time window
284
+ */
285
+ private cleanOldFailures(): void {
286
+ const cutoff = Date.now() - this.failureWindow;
287
+ this.failures = this.failures.filter((f) => f.timestamp > cutoff);
288
+ }
289
+
290
+ /**
291
+ * Check if we should attempt to reset (transition to half-open)
292
+ */
293
+ private shouldAttemptReset(): boolean {
294
+ return Date.now() - this.lastStateChange >= this.resetTimeout;
295
+ }
296
+
297
+ /**
298
+ * Get remaining time until reset attempt
299
+ */
300
+ private getRemainingResetTime(): number {
301
+ const elapsed = Date.now() - this.lastStateChange;
302
+ return Math.max(0, this.resetTimeout - elapsed);
303
+ }
304
+
305
+ /**
306
+ * Transition to a new state
307
+ */
308
+ private transitionTo(newState: CircuitStateType): void {
309
+ const oldState = this.state;
310
+ this.state = newState;
311
+ this.lastStateChange = Date.now();
312
+
313
+ this.logger.info(`Circuit '${this.name}' state change: ${oldState} -> ${newState}`);
314
+
315
+ // Reset counters on state change
316
+ if (newState === CircuitState.CLOSED) {
317
+ this.failures = [];
318
+ this.successes = 0;
319
+ this.onClose?.(this.name);
320
+ } else if (newState === CircuitState.OPEN) {
321
+ this.successes = 0;
322
+ this.onOpen?.(this.name, this.failures.length);
323
+ } else if (newState === CircuitState.HALF_OPEN) {
324
+ this.successes = 0;
325
+ this.onHalfOpen?.(this.name);
326
+ }
327
+ }
328
+
329
+ /**
330
+ * Default failure detection - all errors are failures except timeouts and circuit breaker errors
331
+ */
332
+ private defaultIsFailure(error: Error): boolean {
333
+ // Don't count circuit breaker's own errors as failures
334
+ if (error instanceof CircuitBreakerOpenError || error instanceof CircuitBreakerTimeoutError) {
335
+ return false;
336
+ }
337
+
338
+ // Count all other errors as failures
339
+ return true;
340
+ }
341
+
342
+ /**
343
+ * Get current circuit breaker statistics
344
+ */
345
+ getStats(): CircuitBreakerStats {
346
+ this.cleanOldFailures();
347
+
348
+ return {
349
+ state: this.state,
350
+ failures: this.failures.length,
351
+ successes: this.successes,
352
+ lastFailure: this.lastFailure,
353
+ lastSuccess: this.lastSuccess,
354
+ totalRequests: this.totalRequests,
355
+ failedRequests: this.failedRequests,
356
+ successfulRequests: this.successfulRequests,
357
+ rejectedRequests: this.rejectedRequests,
358
+ timeInCurrentState: Date.now() - this.lastStateChange,
359
+ };
360
+ }
361
+
362
+ /**
363
+ * Get current state
364
+ */
365
+ getState(): CircuitStateType {
366
+ // Check for automatic transition to half-open
367
+ if (this.state === CircuitState.OPEN && this.shouldAttemptReset()) {
368
+ this.transitionTo(CircuitState.HALF_OPEN);
369
+ }
370
+ return this.state;
371
+ }
372
+
373
+ /**
374
+ * Check if circuit is allowing requests
375
+ */
376
+ isAvailable(): boolean {
377
+ const state = this.getState();
378
+ return state === CircuitState.CLOSED || state === CircuitState.HALF_OPEN;
379
+ }
380
+
381
+ /**
382
+ * Force circuit to open state (for testing or manual intervention)
383
+ */
384
+ forceOpen(): void {
385
+ this.logger.warn(`Circuit '${this.name}' forced open`);
386
+ this.transitionTo(CircuitState.OPEN);
387
+ }
388
+
389
+ /**
390
+ * Force circuit to closed state (for testing or manual intervention)
391
+ */
392
+ forceClose(): void {
393
+ this.logger.warn(`Circuit '${this.name}' forced closed`);
394
+ this.transitionTo(CircuitState.CLOSED);
395
+ }
396
+
397
+ /**
398
+ * Reset circuit breaker to initial state
399
+ */
400
+ reset(): void {
401
+ this.state = CircuitState.CLOSED;
402
+ this.failures = [];
403
+ this.successes = 0;
404
+ this.lastStateChange = Date.now();
405
+ this.totalRequests = 0;
406
+ this.failedRequests = 0;
407
+ this.successfulRequests = 0;
408
+ this.rejectedRequests = 0;
409
+ this.lastFailure = null;
410
+ this.lastSuccess = null;
411
+
412
+ this.logger.info(`Circuit '${this.name}' reset`);
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Circuit Breaker Registry
418
+ * Manages multiple circuit breakers for different services
419
+ */
420
+ export class CircuitBreakerRegistry {
421
+ private static instance: CircuitBreakerRegistry;
422
+ private breakers: Map<string, CircuitBreaker> = new Map();
423
+ private readonly logger = createLogger("CircuitBreakerRegistry");
424
+
425
+ private constructor() {}
426
+
427
+ /**
428
+ * Get singleton instance
429
+ */
430
+ static getInstance(): CircuitBreakerRegistry {
431
+ if (!CircuitBreakerRegistry.instance) {
432
+ CircuitBreakerRegistry.instance = new CircuitBreakerRegistry();
433
+ }
434
+ return CircuitBreakerRegistry.instance;
435
+ }
436
+
437
+ /**
438
+ * Get or create a circuit breaker
439
+ */
440
+ getBreaker(options: CircuitBreakerOptions): CircuitBreaker {
441
+ let breaker = this.breakers.get(options.name);
442
+
443
+ if (!breaker) {
444
+ breaker = new CircuitBreaker(options);
445
+ this.breakers.set(options.name, breaker);
446
+ this.logger.debug(`Created circuit breaker: ${options.name}`);
447
+ }
448
+
449
+ return breaker;
450
+ }
451
+
452
+ /**
453
+ * Get existing circuit breaker by name
454
+ */
455
+ get(name: string): CircuitBreaker | undefined {
456
+ return this.breakers.get(name);
457
+ }
458
+
459
+ /**
460
+ * Get all circuit breaker statistics
461
+ */
462
+ getAllStats(): Record<string, CircuitBreakerStats> {
463
+ const stats: Record<string, CircuitBreakerStats> = {};
464
+
465
+ for (const [name, breaker] of this.breakers) {
466
+ stats[name] = breaker.getStats();
467
+ }
468
+
469
+ return stats;
470
+ }
471
+
472
+ /**
473
+ * Get health summary of all circuit breakers
474
+ */
475
+ getHealthSummary(): {
476
+ total: number;
477
+ closed: number;
478
+ open: number;
479
+ halfOpen: number;
480
+ healthy: boolean;
481
+ } {
482
+ let closed = 0;
483
+ let open = 0;
484
+ let halfOpen = 0;
485
+
486
+ for (const breaker of this.breakers.values()) {
487
+ switch (breaker.getState()) {
488
+ case CircuitState.CLOSED:
489
+ closed++;
490
+ break;
491
+ case CircuitState.OPEN:
492
+ open++;
493
+ break;
494
+ case CircuitState.HALF_OPEN:
495
+ halfOpen++;
496
+ break;
497
+ }
498
+ }
499
+
500
+ return {
501
+ total: this.breakers.size,
502
+ closed,
503
+ open,
504
+ halfOpen,
505
+ healthy: open === 0,
506
+ };
507
+ }
508
+
509
+ /**
510
+ * Reset all circuit breakers
511
+ */
512
+ resetAll(): void {
513
+ for (const breaker of this.breakers.values()) {
514
+ breaker.reset();
515
+ }
516
+ this.logger.info("All circuit breakers reset");
517
+ }
518
+
519
+ /**
520
+ * Remove a circuit breaker
521
+ */
522
+ remove(name: string): boolean {
523
+ return this.breakers.delete(name);
524
+ }
525
+
526
+ /**
527
+ * Clear all circuit breakers
528
+ */
529
+ clear(): void {
530
+ this.breakers.clear();
531
+ this.logger.info("All circuit breakers cleared");
532
+ }
533
+ }
534
+
535
+ /**
536
+ * Create a circuit breaker with default WordPress API settings
537
+ */
538
+ export function createWordPressCircuitBreaker(
539
+ siteId: string,
540
+ options?: Partial<CircuitBreakerOptions>,
541
+ ): CircuitBreaker {
542
+ return CircuitBreakerRegistry.getInstance().getBreaker({
543
+ name: `wordpress-api-${siteId}`,
544
+ failureThreshold: 5,
545
+ resetTimeout: 30000,
546
+ successThreshold: 2,
547
+ failureWindow: 60000,
548
+ timeout: 30000,
549
+ isFailure: (error: Error) => {
550
+ // Don't trip on client errors (4xx) except rate limiting
551
+ const message = error.message.toLowerCase();
552
+ if (message.includes("401") || message.includes("403")) {
553
+ return false; // Auth errors shouldn't trip the breaker
554
+ }
555
+ if (message.includes("404")) {
556
+ return false; // Not found is a valid response
557
+ }
558
+ if (message.includes("429")) {
559
+ return true; // Rate limiting should trip the breaker
560
+ }
561
+ // Server errors (5xx) and network errors should trip
562
+ return (
563
+ message.includes("5") ||
564
+ message.includes("timeout") ||
565
+ message.includes("network") ||
566
+ message.includes("econnrefused") ||
567
+ message.includes("econnreset")
568
+ );
569
+ },
570
+ ...options,
571
+ });
572
+ }
@@ -5,8 +5,8 @@
5
5
  * This prevents console.log from interfering with MCP STDIO communication.
6
6
  */
7
7
 
8
- import type { DebugInfo } from "../types/index.js";
9
- import { config } from "../config/Config.js";
8
+ import type { DebugInfo } from "@/types/index.js";
9
+ import { config } from "@/config/Config.js";
10
10
 
11
11
  // Log levels
12
12
  export type LogLevel = "debug" | "info" | "warn" | "error";
@@ -25,7 +25,7 @@ export interface StructuredLogger extends Logger {
25
25
  child(context: Record<string, unknown>): StructuredLogger;
26
26
  }
27
27
 
28
- import { ConfigHelpers } from "../config/Config.js";
28
+ import { ConfigHelpers } from "@/config/Config.js";
29
29
 
30
30
  // Check if debug mode is enabled
31
31
  const isDebugMode = (): boolean => ConfigHelpers.shouldDebug();
@@ -2,7 +2,7 @@
2
2
  * Error handling utilities
3
3
  */
4
4
  import { LoggerFactory } from "./logger.js";
5
- import { config } from "../config/Config.js";
5
+ import { config } from "@/config/Config.js";
6
6
 
7
7
  const logger = LoggerFactory.server().child({ component: "ErrorUtils" });
8
8
 
@@ -21,3 +21,6 @@ export * from "./toolWrapper.js";
21
21
 
22
22
  // Streaming utilities (if any exports exist)
23
23
  export * from "./streaming.js";
24
+
25
+ // Circuit breaker for fault tolerance
26
+ export * from "./CircuitBreaker.js";
@@ -5,7 +5,7 @@
5
5
  * Integrates with the centralized Config system for environment-aware behavior.
6
6
  */
7
7
 
8
- import { ConfigHelpers } from "../config/Config.js";
8
+ import { ConfigHelpers } from "@/config/Config.js";
9
9
 
10
10
  export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
11
11
  export type LogContext = Record<string, unknown>;
@@ -4,8 +4,8 @@
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
+ import type { IWordPressClient } from "@/types/client.js";
8
+ import type { BaseToolParams } from "@/types/tools.js";
9
9
 
10
10
  /**
11
11
  * Wrapper for tool methods that standardizes error handling
File without changes