mcp-wordpress 1.1.7 → 1.2.2

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 (255) hide show
  1. package/README.md +388 -66
  2. package/dist/cache/CacheInvalidation.d.ts +118 -0
  3. package/dist/cache/CacheInvalidation.d.ts.map +1 -0
  4. package/dist/cache/CacheInvalidation.js +349 -0
  5. package/dist/cache/CacheInvalidation.js.map +1 -0
  6. package/dist/cache/CacheManager.d.ts +143 -0
  7. package/dist/cache/CacheManager.d.ts.map +1 -0
  8. package/dist/cache/CacheManager.js +308 -0
  9. package/dist/cache/CacheManager.js.map +1 -0
  10. package/dist/cache/HttpCacheWrapper.d.ts +121 -0
  11. package/dist/cache/HttpCacheWrapper.d.ts.map +1 -0
  12. package/dist/cache/HttpCacheWrapper.js +280 -0
  13. package/dist/cache/HttpCacheWrapper.js.map +1 -0
  14. package/dist/cache/__tests__/CacheInvalidation.test.d.ts +5 -0
  15. package/dist/cache/__tests__/CacheInvalidation.test.d.ts.map +1 -0
  16. package/dist/cache/__tests__/CacheInvalidation.test.js +236 -0
  17. package/dist/cache/__tests__/CacheInvalidation.test.js.map +1 -0
  18. package/dist/cache/__tests__/CacheManager.test.d.ts +5 -0
  19. package/dist/cache/__tests__/CacheManager.test.d.ts.map +1 -0
  20. package/dist/cache/__tests__/CacheManager.test.js +233 -0
  21. package/dist/cache/__tests__/CacheManager.test.js.map +1 -0
  22. package/dist/cache/__tests__/CachedWordPressClient.test.d.ts +5 -0
  23. package/dist/cache/__tests__/CachedWordPressClient.test.d.ts.map +1 -0
  24. package/dist/cache/__tests__/CachedWordPressClient.test.js +228 -0
  25. package/dist/cache/__tests__/CachedWordPressClient.test.js.map +1 -0
  26. package/dist/cache/__tests__/HttpCacheWrapper.test.d.ts +5 -0
  27. package/dist/cache/__tests__/HttpCacheWrapper.test.d.ts.map +1 -0
  28. package/dist/cache/__tests__/HttpCacheWrapper.test.js +296 -0
  29. package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -0
  30. package/dist/cache/index.d.ts +12 -0
  31. package/dist/cache/index.d.ts.map +1 -0
  32. package/dist/cache/index.js +9 -0
  33. package/dist/cache/index.js.map +1 -0
  34. package/dist/client/CachedWordPressClient.d.ts +160 -0
  35. package/dist/client/CachedWordPressClient.d.ts.map +1 -0
  36. package/dist/client/CachedWordPressClient.js +338 -0
  37. package/dist/client/CachedWordPressClient.js.map +1 -0
  38. package/dist/client/WordPressClient.d.ts +81 -0
  39. package/dist/client/WordPressClient.d.ts.map +1 -0
  40. package/dist/client/WordPressClient.js +354 -0
  41. package/dist/client/WordPressClient.js.map +1 -0
  42. package/dist/config/ConfigurationSchema.d.ts +281 -0
  43. package/dist/config/ConfigurationSchema.d.ts.map +1 -0
  44. package/dist/config/ConfigurationSchema.js +205 -0
  45. package/dist/config/ConfigurationSchema.js.map +1 -0
  46. package/dist/config/ServerConfiguration.d.ts +38 -0
  47. package/dist/config/ServerConfiguration.d.ts.map +1 -0
  48. package/dist/config/ServerConfiguration.js +158 -0
  49. package/dist/config/ServerConfiguration.js.map +1 -0
  50. package/dist/docs/DocumentationGenerator.d.ts +184 -0
  51. package/dist/docs/DocumentationGenerator.d.ts.map +1 -0
  52. package/dist/docs/DocumentationGenerator.js +735 -0
  53. package/dist/docs/DocumentationGenerator.js.map +1 -0
  54. package/dist/docs/MarkdownFormatter.d.ts +84 -0
  55. package/dist/docs/MarkdownFormatter.d.ts.map +1 -0
  56. package/dist/docs/MarkdownFormatter.js +448 -0
  57. package/dist/docs/MarkdownFormatter.js.map +1 -0
  58. package/dist/docs/index.d.ts +8 -0
  59. package/dist/docs/index.d.ts.map +1 -0
  60. package/dist/docs/index.js +7 -0
  61. package/dist/docs/index.js.map +1 -0
  62. package/dist/index.d.ts +1 -4
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +12 -212
  65. package/dist/index.js.map +1 -1
  66. package/dist/performance/AnomalyDetector.d.ts +63 -0
  67. package/dist/performance/AnomalyDetector.d.ts.map +1 -0
  68. package/dist/performance/AnomalyDetector.js +222 -0
  69. package/dist/performance/AnomalyDetector.js.map +1 -0
  70. package/dist/performance/BenchmarkAnalyzer.d.ts +67 -0
  71. package/dist/performance/BenchmarkAnalyzer.d.ts.map +1 -0
  72. package/dist/performance/BenchmarkAnalyzer.js +301 -0
  73. package/dist/performance/BenchmarkAnalyzer.js.map +1 -0
  74. package/dist/performance/MetricsCollector.d.ts +139 -0
  75. package/dist/performance/MetricsCollector.d.ts.map +1 -0
  76. package/dist/performance/MetricsCollector.js +320 -0
  77. package/dist/performance/MetricsCollector.js.map +1 -0
  78. package/dist/performance/PerformanceAnalytics.d.ts +162 -0
  79. package/dist/performance/PerformanceAnalytics.d.ts.map +1 -0
  80. package/dist/performance/PerformanceAnalytics.js +554 -0
  81. package/dist/performance/PerformanceAnalytics.js.map +1 -0
  82. package/dist/performance/PerformanceMonitor.d.ts +202 -0
  83. package/dist/performance/PerformanceMonitor.d.ts.map +1 -0
  84. package/dist/performance/PerformanceMonitor.js +478 -0
  85. package/dist/performance/PerformanceMonitor.js.map +1 -0
  86. package/dist/performance/TrendAnalyzer.d.ts +69 -0
  87. package/dist/performance/TrendAnalyzer.d.ts.map +1 -0
  88. package/dist/performance/TrendAnalyzer.js +203 -0
  89. package/dist/performance/TrendAnalyzer.js.map +1 -0
  90. package/dist/performance/index.d.ts +11 -0
  91. package/dist/performance/index.d.ts.map +1 -0
  92. package/dist/performance/index.js +8 -0
  93. package/dist/performance/index.js.map +1 -0
  94. package/dist/security/InputValidator.d.ts +215 -0
  95. package/dist/security/InputValidator.d.ts.map +1 -0
  96. package/dist/security/InputValidator.js +278 -0
  97. package/dist/security/InputValidator.js.map +1 -0
  98. package/dist/security/SecurityConfig.d.ts +129 -0
  99. package/dist/security/SecurityConfig.d.ts.map +1 -0
  100. package/dist/security/SecurityConfig.js +262 -0
  101. package/dist/security/SecurityConfig.js.map +1 -0
  102. package/dist/server/ConnectionTester.d.ts +24 -0
  103. package/dist/server/ConnectionTester.d.ts.map +1 -0
  104. package/dist/server/ConnectionTester.js +61 -0
  105. package/dist/server/ConnectionTester.js.map +1 -0
  106. package/dist/server/ToolRegistry.d.ts +46 -0
  107. package/dist/server/ToolRegistry.d.ts.map +1 -0
  108. package/dist/server/ToolRegistry.js +148 -0
  109. package/dist/server/ToolRegistry.js.map +1 -0
  110. package/dist/tools/BaseToolClass.d.ts +76 -0
  111. package/dist/tools/BaseToolClass.d.ts.map +1 -0
  112. package/dist/tools/BaseToolClass.js +104 -0
  113. package/dist/tools/BaseToolClass.js.map +1 -0
  114. package/dist/tools/BaseToolManager.d.ts +26 -0
  115. package/dist/tools/BaseToolManager.d.ts.map +1 -0
  116. package/dist/tools/BaseToolManager.js +56 -0
  117. package/dist/tools/BaseToolManager.js.map +1 -0
  118. package/dist/tools/base.d.ts +37 -0
  119. package/dist/tools/base.d.ts.map +1 -0
  120. package/dist/tools/base.js +60 -0
  121. package/dist/tools/base.js.map +1 -0
  122. package/dist/tools/cache.d.ts +260 -0
  123. package/dist/tools/cache.d.ts.map +1 -0
  124. package/dist/tools/cache.js +237 -0
  125. package/dist/tools/cache.js.map +1 -0
  126. package/dist/tools/index.d.ts +2 -0
  127. package/dist/tools/index.d.ts.map +1 -1
  128. package/dist/tools/index.js +2 -0
  129. package/dist/tools/index.js.map +1 -1
  130. package/dist/tools/performance.d.ts +63 -0
  131. package/dist/tools/performance.d.ts.map +1 -0
  132. package/dist/tools/performance.js +865 -0
  133. package/dist/tools/performance.js.map +1 -0
  134. package/dist/types/client.d.ts +1 -0
  135. package/dist/types/client.d.ts.map +1 -1
  136. package/dist/types/client.js.map +1 -1
  137. package/dist/utils/toolWrapper.d.ts +4 -0
  138. package/dist/utils/toolWrapper.d.ts.map +1 -1
  139. package/dist/utils/toolWrapper.js +11 -0
  140. package/dist/utils/toolWrapper.js.map +1 -1
  141. package/dist/utils/validation.d.ts +68 -0
  142. package/dist/utils/validation.d.ts.map +1 -0
  143. package/dist/utils/validation.js +185 -0
  144. package/dist/utils/validation.js.map +1 -0
  145. package/docs/CACHING.md +340 -0
  146. package/docs/DOCKER.md +451 -0
  147. package/docs/PERFORMANCE_MONITORING.md +471 -0
  148. package/docs/SECURITY_TESTING.md +393 -0
  149. package/docs/api/README.md +200 -0
  150. package/docs/api/categories/auth.md +40 -0
  151. package/docs/api/categories/cache.md +41 -0
  152. package/docs/api/categories/comment.md +44 -0
  153. package/docs/api/categories/media.md +43 -0
  154. package/docs/api/categories/page.md +43 -0
  155. package/docs/api/categories/performance.md +44 -0
  156. package/docs/api/categories/post.md +43 -0
  157. package/docs/api/categories/site.md +43 -0
  158. package/docs/api/categories/taxonomy.md +47 -0
  159. package/docs/api/categories/user.md +43 -0
  160. package/docs/api/openapi.json +3305 -0
  161. package/docs/api/summary.json +12 -0
  162. package/docs/api/tools/wp_approve_comment.md +98 -0
  163. package/docs/api/tools/wp_cache_clear.md +120 -0
  164. package/docs/api/tools/wp_cache_info.md +119 -0
  165. package/docs/api/tools/wp_cache_stats.md +119 -0
  166. package/docs/api/tools/wp_cache_warm.md +119 -0
  167. package/docs/api/tools/wp_create_application_password.md +102 -0
  168. package/docs/api/tools/wp_create_category.md +102 -0
  169. package/docs/api/tools/wp_create_comment.md +128 -0
  170. package/docs/api/tools/wp_create_page.md +135 -0
  171. package/docs/api/tools/wp_create_post.md +147 -0
  172. package/docs/api/tools/wp_create_tag.md +101 -0
  173. package/docs/api/tools/wp_create_user.md +135 -0
  174. package/docs/api/tools/wp_delete_application_password.md +101 -0
  175. package/docs/api/tools/wp_delete_category.md +100 -0
  176. package/docs/api/tools/wp_delete_comment.md +101 -0
  177. package/docs/api/tools/wp_delete_media.md +108 -0
  178. package/docs/api/tools/wp_delete_page.md +108 -0
  179. package/docs/api/tools/wp_delete_post.md +117 -0
  180. package/docs/api/tools/wp_delete_tag.md +100 -0
  181. package/docs/api/tools/wp_delete_user.md +108 -0
  182. package/docs/api/tools/wp_get_application_passwords.md +103 -0
  183. package/docs/api/tools/wp_get_auth_status.md +101 -0
  184. package/docs/api/tools/wp_get_category.md +103 -0
  185. package/docs/api/tools/wp_get_comment.md +103 -0
  186. package/docs/api/tools/wp_get_current_user.md +101 -0
  187. package/docs/api/tools/wp_get_media.md +103 -0
  188. package/docs/api/tools/wp_get_page.md +103 -0
  189. package/docs/api/tools/wp_get_page_revisions.md +103 -0
  190. package/docs/api/tools/wp_get_post.md +112 -0
  191. package/docs/api/tools/wp_get_post_revisions.md +103 -0
  192. package/docs/api/tools/wp_get_site_settings.md +108 -0
  193. package/docs/api/tools/wp_get_tag.md +103 -0
  194. package/docs/api/tools/wp_get_user.md +103 -0
  195. package/docs/api/tools/wp_list_categories.md +111 -0
  196. package/docs/api/tools/wp_list_comments.md +111 -0
  197. package/docs/api/tools/wp_list_media.md +145 -0
  198. package/docs/api/tools/wp_list_pages.md +145 -0
  199. package/docs/api/tools/wp_list_posts.md +156 -0
  200. package/docs/api/tools/wp_list_tags.md +110 -0
  201. package/docs/api/tools/wp_list_users.md +111 -0
  202. package/docs/api/tools/wp_performance_alerts.md +162 -0
  203. package/docs/api/tools/wp_performance_benchmark.md +160 -0
  204. package/docs/api/tools/wp_performance_export.md +162 -0
  205. package/docs/api/tools/wp_performance_history.md +161 -0
  206. package/docs/api/tools/wp_performance_optimize.md +162 -0
  207. package/docs/api/tools/wp_performance_stats.md +160 -0
  208. package/docs/api/tools/wp_search_site.md +99 -0
  209. package/docs/api/tools/wp_spam_comment.md +98 -0
  210. package/docs/api/tools/wp_switch_auth_method.md +122 -0
  211. package/docs/api/tools/wp_test_auth.md +96 -0
  212. package/docs/api/tools/wp_update_category.md +102 -0
  213. package/docs/api/tools/wp_update_comment.md +127 -0
  214. package/docs/api/tools/wp_update_media.md +129 -0
  215. package/docs/api/tools/wp_update_page.md +135 -0
  216. package/docs/api/tools/wp_update_post.md +144 -0
  217. package/docs/api/tools/wp_update_site_settings.md +127 -0
  218. package/docs/api/tools/wp_update_tag.md +102 -0
  219. package/docs/api/tools/wp_update_user.md +134 -0
  220. package/docs/api/tools/wp_upload_media.md +131 -0
  221. package/docs/api/types/WordPressPost.md +39 -0
  222. package/docs/contract-testing.md +183 -0
  223. package/docs/developer/NPM_AUTH_SETUP.md +3 -3
  224. package/docs/wordpress-rest-api-authentication-troubleshooting.md +218 -0
  225. package/package.json +84 -64
  226. package/src/cache/CacheInvalidation.ts +421 -0
  227. package/src/cache/CacheManager.ts +391 -0
  228. package/src/cache/HttpCacheWrapper.ts +372 -0
  229. package/src/cache/__tests__/CacheInvalidation.test.ts +299 -0
  230. package/src/cache/__tests__/CacheManager.test.ts +300 -0
  231. package/src/cache/__tests__/CachedWordPressClient.test.ts +304 -0
  232. package/src/cache/__tests__/HttpCacheWrapper.test.ts +359 -0
  233. package/src/cache/index.ts +26 -0
  234. package/src/client/CachedWordPressClient.ts +442 -0
  235. package/src/config/ConfigurationSchema.ts +246 -0
  236. package/src/config/ServerConfiguration.ts +215 -0
  237. package/src/docs/DocumentationGenerator.ts +952 -0
  238. package/src/docs/MarkdownFormatter.ts +494 -0
  239. package/src/docs/index.ts +21 -0
  240. package/src/index.ts +14 -274
  241. package/src/performance/MetricsCollector.ts +447 -0
  242. package/src/performance/PerformanceAnalytics.ts +762 -0
  243. package/src/performance/PerformanceMonitor.ts +649 -0
  244. package/src/performance/index.ts +28 -0
  245. package/src/security/InputValidator.ts +319 -0
  246. package/src/security/SecurityConfig.ts +301 -0
  247. package/src/server/ConnectionTester.ts +74 -0
  248. package/src/server/ToolRegistry.ts +194 -0
  249. package/src/tools/BaseToolManager.ts +66 -0
  250. package/src/tools/cache.ts +259 -0
  251. package/src/tools/index.ts +2 -0
  252. package/src/tools/performance.ts +948 -0
  253. package/src/types/client.ts +1 -0
  254. package/src/utils/toolWrapper.ts +11 -0
  255. package/src/utils/validation.ts +259 -0
@@ -0,0 +1,442 @@
1
+ /**
2
+ * Cached WordPress API Client
3
+ * Extends the base WordPress client with intelligent caching capabilities and performance monitoring
4
+ */
5
+
6
+ import { WordPressClient } from './api.js';
7
+ import { CacheManager } from '../cache/CacheManager.js';
8
+ import { HttpCacheWrapper } from '../cache/HttpCacheWrapper.js';
9
+ import { CacheInvalidation } from '../cache/CacheInvalidation.js';
10
+ import { SecurityConfig } from '../security/SecurityConfig.js';
11
+ import type {
12
+ WordPressClientConfig,
13
+ HTTPMethod,
14
+ RequestOptions
15
+ } from '../types/client.js';
16
+ import type {
17
+ WordPressPost,
18
+ WordPressUser,
19
+ WordPressCategory,
20
+ WordPressTag,
21
+ WordPressSiteSettings,
22
+ PostQueryParams,
23
+ CreatePostRequest,
24
+ UpdatePostRequest
25
+ } from '../types/wordpress.js';
26
+
27
+ /**
28
+ * WordPress client with intelligent caching
29
+ */
30
+ export class CachedWordPressClient extends WordPressClient {
31
+ private cacheManager: CacheManager;
32
+ private httpCache: HttpCacheWrapper;
33
+ private cacheInvalidation: CacheInvalidation;
34
+ private siteId: string;
35
+
36
+ constructor(config: WordPressClientConfig, siteId: string = 'default') {
37
+ super(config);
38
+ this.siteId = siteId;
39
+
40
+ // Initialize caching system
41
+ this.cacheManager = new CacheManager({
42
+ maxSize: SecurityConfig.cache.maxSize,
43
+ defaultTTL: SecurityConfig.cache.defaultTTL,
44
+ enableLRU: SecurityConfig.cache.enableLRU,
45
+ enableStats: SecurityConfig.cache.enableStats,
46
+ sitePrefix: siteId
47
+ });
48
+
49
+ this.httpCache = new HttpCacheWrapper(this.cacheManager, siteId);
50
+ this.cacheInvalidation = new CacheInvalidation(this.httpCache);
51
+ }
52
+
53
+ /**
54
+ * Override request method to add caching
55
+ */
56
+ async request<T = any>(
57
+ method: HTTPMethod,
58
+ endpoint: string,
59
+ data: any = null,
60
+ options: RequestOptions = {}
61
+ ): Promise<T> {
62
+ // Only cache GET requests
63
+ if (method.toUpperCase() !== 'GET' || !SecurityConfig.cache.enabled) {
64
+ const response = await super.request<T>(method, endpoint, data, options);
65
+
66
+ // Trigger cache invalidation for write operations
67
+ if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(method.toUpperCase())) {
68
+ await this.handleCacheInvalidation(method, endpoint, data);
69
+ }
70
+
71
+ return response;
72
+ }
73
+
74
+ // Use cached request for GET operations
75
+ const requestFn = () => super.request<T>(method, endpoint, data, options);
76
+
77
+ const requestOptions = {
78
+ method,
79
+ url: `${this.config.baseUrl}/wp-json/wp/v2/${endpoint}`,
80
+ headers: {},
81
+ params: {},
82
+ data
83
+ };
84
+
85
+ const cacheOptions = this.getCacheOptions(endpoint);
86
+
87
+ const response = await this.httpCache.request(
88
+ async () => {
89
+ const result = await requestFn();
90
+ return {
91
+ data: result,
92
+ status: 200,
93
+ headers: {}
94
+ };
95
+ },
96
+ requestOptions,
97
+ cacheOptions
98
+ );
99
+
100
+ return response.data;
101
+ }
102
+
103
+ /**
104
+ * Enhanced methods with caching optimization
105
+ */
106
+
107
+ /**
108
+ * Get posts with intelligent caching
109
+ */
110
+ async getPosts(params: PostQueryParams = {}): Promise<WordPressPost[]> {
111
+ return await this.request<WordPressPost[]>('GET', 'posts', null, { params });
112
+ }
113
+
114
+ /**
115
+ * Get single post with caching
116
+ */
117
+ async getPost(id: number): Promise<WordPressPost> {
118
+ return await this.request<WordPressPost>('GET', `posts/${id}`);
119
+ }
120
+
121
+ /**
122
+ * Create post with cache invalidation
123
+ */
124
+ async createPost(data: CreatePostRequest): Promise<WordPressPost> {
125
+ const post = await super.createPost(data);
126
+
127
+ // Invalidate related caches
128
+ await this.cacheInvalidation.invalidateResource('posts', post.id, 'create');
129
+
130
+ return post;
131
+ }
132
+
133
+ /**
134
+ * Update post with cache invalidation
135
+ */
136
+ async updatePost(data: UpdatePostRequest): Promise<WordPressPost> {
137
+ const post = await super.updatePost(data);
138
+
139
+ // Invalidate related caches
140
+ await this.cacheInvalidation.invalidateResource('posts', post.id, 'update');
141
+
142
+ return post;
143
+ }
144
+
145
+ /**
146
+ * Delete post with cache invalidation
147
+ */
148
+ async deletePost(id: number, force?: boolean): Promise<{ deleted: boolean; previous?: WordPressPost }> {
149
+ const result = await super.deletePost(id, force);
150
+
151
+ // Invalidate related caches
152
+ await this.cacheInvalidation.invalidateResource('posts', id, 'delete');
153
+
154
+ return result;
155
+ }
156
+
157
+ /**
158
+ * Get current user with session caching
159
+ */
160
+ async getCurrentUser(): Promise<WordPressUser> {
161
+ return await this.request<WordPressUser>('GET', 'users/me');
162
+ }
163
+
164
+ /**
165
+ * Get categories with semi-static caching
166
+ */
167
+ async getCategories(params: any = {}): Promise<WordPressCategory[]> {
168
+ return await this.request<WordPressCategory[]>('GET', 'categories', null, { params });
169
+ }
170
+
171
+ /**
172
+ * Get tags with semi-static caching
173
+ */
174
+ async getTags(params: any = {}): Promise<WordPressTag[]> {
175
+ return await this.request<WordPressTag[]>('GET', 'tags', null, { params });
176
+ }
177
+
178
+ /**
179
+ * Get site settings with static caching
180
+ */
181
+ async getSiteSettings(): Promise<WordPressSiteSettings> {
182
+ return await this.request<WordPressSiteSettings>('GET', 'settings');
183
+ }
184
+
185
+ /**
186
+ * Cache management methods
187
+ */
188
+
189
+
190
+ /**
191
+ * Private helper methods
192
+ */
193
+
194
+ private extractEndpoint(url: string): string {
195
+ // Simple approach - use the endpoint part
196
+ return url.replace(/^.*\/wp-json\/wp\/v2\//, '').split('?')[0];
197
+ }
198
+
199
+ /**
200
+ * Get cache options based on endpoint
201
+ */
202
+ private getCacheOptions(endpoint: string) {
203
+ // Determine cache type based on endpoint
204
+ if (this.isStaticEndpoint(endpoint)) {
205
+ return {
206
+ ttl: SecurityConfig.cache.ttlPresets.static,
207
+ cacheControl: SecurityConfig.cache.cacheHeaders.static
208
+ };
209
+ }
210
+
211
+ if (this.isSemiStaticEndpoint(endpoint)) {
212
+ return {
213
+ ttl: SecurityConfig.cache.ttlPresets.semiStatic,
214
+ cacheControl: SecurityConfig.cache.cacheHeaders.semiStatic
215
+ };
216
+ }
217
+
218
+ if (this.isSessionEndpoint(endpoint)) {
219
+ return {
220
+ ttl: SecurityConfig.cache.ttlPresets.session,
221
+ cacheControl: SecurityConfig.cache.cacheHeaders.session,
222
+ private: true
223
+ };
224
+ }
225
+
226
+ // Default to dynamic caching
227
+ return {
228
+ ttl: SecurityConfig.cache.ttlPresets.dynamic,
229
+ cacheControl: SecurityConfig.cache.cacheHeaders.dynamic
230
+ };
231
+ }
232
+
233
+ /**
234
+ * Handle cache invalidation for write operations
235
+ */
236
+ private async handleCacheInvalidation(
237
+ method: string,
238
+ endpoint: string,
239
+ data: any
240
+ ): Promise<void> {
241
+ const resource = this.extractResourceFromEndpoint(endpoint);
242
+ const id = this.extractIdFromEndpoint(endpoint);
243
+
244
+ let operationType: 'create' | 'update' | 'delete';
245
+
246
+ switch (method.toUpperCase()) {
247
+ case 'POST':
248
+ operationType = 'create';
249
+ break;
250
+ case 'PUT':
251
+ case 'PATCH':
252
+ operationType = 'update';
253
+ break;
254
+ case 'DELETE':
255
+ operationType = 'delete';
256
+ break;
257
+ default:
258
+ return;
259
+ }
260
+
261
+ await this.cacheInvalidation.invalidateResource(resource, id, operationType);
262
+ }
263
+
264
+ /**
265
+ * Extract resource type from endpoint
266
+ */
267
+ private extractResourceFromEndpoint(endpoint: string): string {
268
+ const parts = endpoint.split('/');
269
+ return parts[0] || 'unknown';
270
+ }
271
+
272
+ /**
273
+ * Extract ID from endpoint
274
+ */
275
+ private extractIdFromEndpoint(endpoint: string): number | undefined {
276
+ const match = endpoint.match(/\/(\d+)(?:\/|$)/);
277
+ return match ? parseInt(match[1], 10) : undefined;
278
+ }
279
+
280
+ /**
281
+ * Check if endpoint contains static data
282
+ */
283
+ private isStaticEndpoint(endpoint: string): boolean {
284
+ const staticEndpoints = ['settings', 'types', 'statuses'];
285
+ return staticEndpoints.some(pattern => endpoint.includes(pattern));
286
+ }
287
+
288
+ /**
289
+ * Check if endpoint contains semi-static data
290
+ */
291
+ private isSemiStaticEndpoint(endpoint: string): boolean {
292
+ const semiStaticEndpoints = ['categories', 'tags', 'users', 'taxonomies'];
293
+ return semiStaticEndpoints.some(pattern => endpoint.includes(pattern));
294
+ }
295
+
296
+ /**
297
+ * Check if endpoint is session-related
298
+ */
299
+ private isSessionEndpoint(endpoint: string): boolean {
300
+ const sessionEndpoints = ['users/me', 'application-passwords'];
301
+ return sessionEndpoints.some(pattern => endpoint.includes(pattern));
302
+ }
303
+
304
+ /**
305
+ * Performance monitoring and cache management methods
306
+ */
307
+
308
+ /**
309
+ * Get cache statistics for performance monitoring
310
+ */
311
+ getCacheStats(): any {
312
+ return this.cacheManager.getStats();
313
+ }
314
+
315
+ /**
316
+ * Get cache manager instance (for performance monitoring integration)
317
+ */
318
+ getCacheManager(): CacheManager {
319
+ return this.cacheManager;
320
+ }
321
+
322
+ /**
323
+ * Clear cache entries (for cache management tools)
324
+ */
325
+ clearCache(): number {
326
+ const stats = this.cacheManager.getStats();
327
+ this.cacheManager.clear();
328
+ return stats.totalSize;
329
+ }
330
+
331
+ /**
332
+ * Clear cache entries matching pattern
333
+ */
334
+ clearCachePattern(pattern: string): number {
335
+ const regex = new RegExp(pattern, 'i');
336
+ return this.cacheManager.clearPattern(regex);
337
+ }
338
+
339
+ /**
340
+ * Warm cache with essential data
341
+ */
342
+ async warmCache(): Promise<void> {
343
+ try {
344
+ // Pre-load frequently accessed data
345
+ const warmupOperations = [
346
+ () => this.getCurrentUser().catch(() => null),
347
+ () => this.getCategories().catch(() => null),
348
+ () => this.getTags().catch(() => null),
349
+ () => this.getSiteSettings().catch(() => null)
350
+ ];
351
+
352
+ // Execute warmup operations in parallel
353
+ await Promise.allSettled(warmupOperations.map(op => op()));
354
+ } catch (_error) {
355
+ // Ignore warmup errors - they shouldn't fail the cache warming
356
+ }
357
+ }
358
+
359
+ /**
360
+ * Get cache efficiency metrics
361
+ */
362
+ getCacheEfficiency(): {
363
+ hitRate: number;
364
+ missRate: number;
365
+ efficiency: string;
366
+ memoryUsage: number;
367
+ totalEntries: number;
368
+ } {
369
+ const stats = this.cacheManager.getStats();
370
+ const total = stats.hits + stats.misses;
371
+ const hitRate = total > 0 ? stats.hits / total : 0;
372
+ const missRate = 1 - hitRate;
373
+
374
+ let efficiency = 'Poor';
375
+ if (hitRate >= 0.9) efficiency = 'Excellent';
376
+ else if (hitRate >= 0.8) efficiency = 'Good';
377
+ else if (hitRate >= 0.6) efficiency = 'Fair';
378
+
379
+ return {
380
+ hitRate,
381
+ missRate,
382
+ efficiency,
383
+ memoryUsage: this.estimateMemoryUsage(),
384
+ totalEntries: stats.totalSize
385
+ };
386
+ }
387
+
388
+ /**
389
+ * Get cache configuration info
390
+ */
391
+ getCacheInfo(): {
392
+ enabled: boolean;
393
+ siteId: string;
394
+ maxSize: number;
395
+ defaultTTL: number;
396
+ currentSize: number;
397
+ ttlPresets: any;
398
+ } {
399
+ const stats = this.cacheManager.getStats();
400
+
401
+ return {
402
+ enabled: SecurityConfig.cache.enabled,
403
+ siteId: this.siteId,
404
+ maxSize: SecurityConfig.cache.maxSize,
405
+ defaultTTL: SecurityConfig.cache.defaultTTL,
406
+ currentSize: stats.totalSize,
407
+ ttlPresets: SecurityConfig.cache.ttlPresets
408
+ };
409
+ }
410
+
411
+ /**
412
+ * Estimate memory usage of cache (in MB)
413
+ */
414
+ private estimateMemoryUsage(): number {
415
+ const stats = this.cacheManager.getStats();
416
+ // Rough estimate: ~1KB per cache entry
417
+ return (stats.totalSize * 1024) / (1024 * 1024);
418
+ }
419
+
420
+ /**
421
+ * Get detailed cache performance metrics
422
+ */
423
+ getDetailedCacheMetrics(): {
424
+ statistics: any;
425
+ efficiency: any;
426
+ configuration: any;
427
+ siteInfo: {
428
+ siteId: string;
429
+ baseUrl: string;
430
+ };
431
+ } {
432
+ return {
433
+ statistics: this.getCacheStats(),
434
+ efficiency: this.getCacheEfficiency(),
435
+ configuration: this.getCacheInfo(),
436
+ siteInfo: {
437
+ siteId: this.siteId,
438
+ baseUrl: this.config.baseUrl
439
+ }
440
+ };
441
+ }
442
+ }
@@ -0,0 +1,246 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Zod schema for WordPress authentication methods
5
+ */
6
+ const AuthMethodSchema = z.enum([
7
+ 'app-password',
8
+ 'jwt',
9
+ 'basic',
10
+ 'api-key',
11
+ 'cookie'
12
+ ] as const);
13
+
14
+ /**
15
+ * Zod schema for URL validation
16
+ */
17
+ const UrlSchema = z
18
+ .string()
19
+ .url('Must be a valid URL')
20
+ .refine((url) => {
21
+ const parsed = new URL(url);
22
+ return parsed.protocol === 'http:' || parsed.protocol === 'https:';
23
+ }, 'URL must use http or https protocol');
24
+
25
+ /**
26
+ * Zod schema for WordPress site configuration
27
+ */
28
+ const SiteConfigSchema = z.object({
29
+ WORDPRESS_SITE_URL: UrlSchema,
30
+ WORDPRESS_USERNAME: z
31
+ .string()
32
+ .min(1, 'Username is required')
33
+ .max(60, 'Username must be 60 characters or less')
34
+ .regex(/^[a-zA-Z0-9._@-]+$/, 'Username contains invalid characters'),
35
+ WORDPRESS_APP_PASSWORD: z
36
+ .string()
37
+ .min(1, 'Password is required')
38
+ .refine((password) => {
39
+ // WordPress app passwords are typically 24 characters with spaces
40
+ // But we'll be flexible to support different auth methods
41
+ return password.length >= 8;
42
+ }, 'Password must be at least 8 characters'),
43
+ WORDPRESS_AUTH_METHOD: AuthMethodSchema.optional().default('app-password')
44
+ });
45
+
46
+ /**
47
+ * Zod schema for site configuration with metadata
48
+ */
49
+ const SiteSchema = z.object({
50
+ id: z
51
+ .string()
52
+ .min(1, 'Site ID is required')
53
+ .max(50, 'Site ID must be 50 characters or less')
54
+ .regex(
55
+ /^[a-zA-Z0-9_-]+$/,
56
+ 'Site ID can only contain letters, numbers, underscores, and hyphens'
57
+ ),
58
+ name: z
59
+ .string()
60
+ .min(1, 'Site name is required')
61
+ .max(100, 'Site name must be 100 characters or less'),
62
+ config: SiteConfigSchema
63
+ });
64
+
65
+ /**
66
+ * Zod schema for multi-site configuration file
67
+ */
68
+ const MultiSiteConfigSchema = z.object({
69
+ sites: z
70
+ .array(SiteSchema)
71
+ .min(1, 'At least one site must be configured')
72
+ .max(50, 'Maximum of 50 sites supported')
73
+ .refine((sites) => {
74
+ const ids = sites.map((site) => site.id);
75
+ const uniqueIds = new Set(ids);
76
+ return ids.length === uniqueIds.size;
77
+ }, 'Site IDs must be unique')
78
+ .refine((sites) => {
79
+ const names = sites.map((site) => site.name);
80
+ const uniqueNames = new Set(names);
81
+ return names.length === uniqueNames.size;
82
+ }, 'Site names must be unique')
83
+ .refine((sites) => {
84
+ const urls = sites.map((site) => site.config.WORDPRESS_SITE_URL);
85
+ const uniqueUrls = new Set(urls);
86
+ return urls.length === uniqueUrls.size;
87
+ }, 'Site URLs must be unique')
88
+ });
89
+
90
+ /**
91
+ * Zod schema for environment variables (single-site mode)
92
+ */
93
+ const EnvironmentConfigSchema = z.object({
94
+ WORDPRESS_SITE_URL: UrlSchema,
95
+ WORDPRESS_USERNAME: SiteConfigSchema.shape.WORDPRESS_USERNAME,
96
+ WORDPRESS_APP_PASSWORD: SiteConfigSchema.shape.WORDPRESS_APP_PASSWORD,
97
+ WORDPRESS_AUTH_METHOD: AuthMethodSchema.optional().default('app-password'),
98
+ // Optional environment variables
99
+ NODE_ENV: z.enum(['development', 'production', 'test']).optional(),
100
+ DEBUG: z.string().optional(),
101
+ DISABLE_CACHE: z.string().optional(),
102
+ LOG_LEVEL: z.enum(['error', 'warn', 'info', 'debug']).optional()
103
+ });
104
+
105
+ /**
106
+ * Zod schema for MCP configuration passed from client
107
+ */
108
+ const McpConfigSchema = z
109
+ .object({
110
+ wordpressSiteUrl: UrlSchema.optional(),
111
+ wordpressUsername: SiteConfigSchema.shape.WORDPRESS_USERNAME.optional(),
112
+ wordpressAppPassword:
113
+ SiteConfigSchema.shape.WORDPRESS_APP_PASSWORD.optional(),
114
+ wordpressAuthMethod: AuthMethodSchema.optional()
115
+ })
116
+ .optional();
117
+
118
+ /**
119
+ * Type definitions derived from Zod schemas
120
+ */
121
+ export type SiteConfigType = z.infer<typeof SiteConfigSchema>;
122
+ export type SiteType = z.infer<typeof SiteSchema>;
123
+ export type MultiSiteConfigType = z.infer<typeof MultiSiteConfigSchema>;
124
+ export type EnvironmentConfigType = z.infer<typeof EnvironmentConfigSchema>;
125
+ export type McpConfigType = z.infer<typeof McpConfigSchema>;
126
+
127
+ /**
128
+ * Configuration validation utilities
129
+ */
130
+ export class ConfigurationValidator {
131
+ /**
132
+ * Validate multi-site configuration from JSON file
133
+ */
134
+ static validateMultiSiteConfig(config: unknown): MultiSiteConfigType {
135
+ try {
136
+ return MultiSiteConfigSchema.parse(config);
137
+ } catch (error) {
138
+ if (error instanceof z.ZodError) {
139
+ const messages = error.errors
140
+ .map((err) => `${err.path.join('.')}: ${err.message}`)
141
+ .join('; ');
142
+ throw new Error(
143
+ `Multi-site configuration validation failed: ${messages}`
144
+ );
145
+ }
146
+ throw error;
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Validate environment configuration for single-site mode
152
+ */
153
+ static validateEnvironmentConfig(
154
+ env: Record<string, string | undefined>
155
+ ): EnvironmentConfigType {
156
+ try {
157
+ return EnvironmentConfigSchema.parse(env);
158
+ } catch (error) {
159
+ if (error instanceof z.ZodError) {
160
+ const messages = error.errors
161
+ .map((err) => `${err.path.join('.')}: ${err.message}`)
162
+ .join('; ');
163
+ throw new Error(
164
+ `Environment configuration validation failed: ${messages}`
165
+ );
166
+ }
167
+ throw error;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Validate MCP configuration passed from client
173
+ */
174
+ static validateMcpConfig(config: unknown): McpConfigType {
175
+ try {
176
+ return McpConfigSchema.parse(config);
177
+ } catch (error) {
178
+ if (error instanceof z.ZodError) {
179
+ const messages = error.errors
180
+ .map((err) => `${err.path.join('.')}: ${err.message}`)
181
+ .join('; ');
182
+ throw new Error(`MCP configuration validation failed: ${messages}`);
183
+ }
184
+ throw error;
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Validate a single site configuration
190
+ */
191
+ static validateSiteConfig(config: unknown): SiteType {
192
+ try {
193
+ return SiteSchema.parse(config);
194
+ } catch (error) {
195
+ if (error instanceof z.ZodError) {
196
+ const messages = error.errors
197
+ .map((err) => `${err.path.join('.')}: ${err.message}`)
198
+ .join('; ');
199
+ throw new Error(`Site configuration validation failed: ${messages}`);
200
+ }
201
+ throw error;
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Check if a configuration file structure is valid without throwing
207
+ */
208
+ static isValidMultiSiteConfig(config: unknown): boolean {
209
+ const result = MultiSiteConfigSchema.safeParse(config);
210
+ return result.success;
211
+ }
212
+
213
+ /**
214
+ * Check if environment configuration is valid without throwing
215
+ */
216
+ static isValidEnvironmentConfig(
217
+ env: Record<string, string | undefined>
218
+ ): boolean {
219
+ const result = EnvironmentConfigSchema.safeParse(env);
220
+ return result.success;
221
+ }
222
+
223
+ /**
224
+ * Get validation errors without throwing
225
+ */
226
+ static getValidationErrors(schema: z.ZodSchema, data: unknown): string[] {
227
+ const result = schema.safeParse(data);
228
+ if (result.success) {
229
+ return [];
230
+ }
231
+ return result.error.errors.map(
232
+ (err) => `${err.path.join('.')}: ${err.message}`
233
+ );
234
+ }
235
+ }
236
+
237
+ // Export schemas for direct use if needed
238
+ export {
239
+ SiteConfigSchema,
240
+ SiteSchema,
241
+ MultiSiteConfigSchema,
242
+ EnvironmentConfigSchema,
243
+ McpConfigSchema,
244
+ AuthMethodSchema,
245
+ UrlSchema
246
+ };