mcp-wordpress 1.5.2 → 2.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 (190) hide show
  1. package/README.md +332 -61
  2. package/dist/cache/CacheInvalidation.d.ts.map +1 -1
  3. package/dist/cache/CacheInvalidation.js +4 -4
  4. package/dist/cache/CacheInvalidation.js.map +1 -1
  5. package/dist/client/MockWordPressClient.d.ts +55 -0
  6. package/dist/client/MockWordPressClient.d.ts.map +1 -0
  7. package/dist/client/MockWordPressClient.js +369 -0
  8. package/dist/client/MockWordPressClient.js.map +1 -0
  9. package/dist/client/api.d.ts +1 -0
  10. package/dist/client/api.d.ts.map +1 -1
  11. package/dist/client/api.js +26 -60
  12. package/dist/client/api.js.map +1 -1
  13. package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
  14. package/dist/client/managers/AuthenticationManager.js +4 -3
  15. package/dist/client/managers/AuthenticationManager.js.map +1 -1
  16. package/dist/config/ConfigurationSchema.d.ts +3 -3
  17. package/dist/config/ConfigurationSchema.d.ts.map +1 -1
  18. package/dist/config/ConfigurationSchema.js +7 -24
  19. package/dist/config/ConfigurationSchema.js.map +1 -1
  20. package/dist/config/ServerConfiguration.d.ts +8 -0
  21. package/dist/config/ServerConfiguration.d.ts.map +1 -1
  22. package/dist/config/ServerConfiguration.js +80 -31
  23. package/dist/config/ServerConfiguration.js.map +1 -1
  24. package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
  25. package/dist/docs/DocumentationGenerator.js +5 -7
  26. package/dist/docs/DocumentationGenerator.js.map +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +33 -29
  29. package/dist/index.js.map +1 -1
  30. package/dist/security/InputValidator.d.ts.map +1 -1
  31. package/dist/security/InputValidator.js +3 -11
  32. package/dist/security/InputValidator.js.map +1 -1
  33. package/dist/server/ToolRegistry.d.ts +4 -0
  34. package/dist/server/ToolRegistry.d.ts.map +1 -1
  35. package/dist/server/ToolRegistry.js +71 -8
  36. package/dist/server/ToolRegistry.js.map +1 -1
  37. package/dist/tools/auth.d.ts.map +1 -1
  38. package/dist/tools/auth.js +8 -3
  39. package/dist/tools/auth.js.map +1 -1
  40. package/dist/tools/posts.d.ts.map +1 -1
  41. package/dist/tools/posts.js +287 -20
  42. package/dist/tools/posts.js.map +1 -1
  43. package/dist/tools/site.d.ts.map +1 -1
  44. package/dist/tools/site.js +47 -9
  45. package/dist/tools/site.js.map +1 -1
  46. package/dist/tools/users.d.ts.map +1 -1
  47. package/dist/tools/users.js +113 -10
  48. package/dist/tools/users.js.map +1 -1
  49. package/dist/utils/enhancedError.d.ts +61 -0
  50. package/dist/utils/enhancedError.d.ts.map +1 -0
  51. package/dist/utils/enhancedError.js +221 -0
  52. package/dist/utils/enhancedError.js.map +1 -0
  53. package/dist/utils/streaming.d.ts +104 -0
  54. package/dist/utils/streaming.d.ts.map +1 -0
  55. package/dist/utils/streaming.js +312 -0
  56. package/dist/utils/streaming.js.map +1 -0
  57. package/dist/utils/validation.d.ts +19 -3
  58. package/dist/utils/validation.d.ts.map +1 -1
  59. package/dist/utils/validation.js +174 -24
  60. package/dist/utils/validation.js.map +1 -1
  61. package/docs/ARCHITECTURE.md +850 -0
  62. package/docs/CACHING.md +20 -17
  63. package/docs/CONFIGURATION.md +660 -0
  64. package/docs/DOCKER.md +61 -60
  65. package/docs/EVALUATION.md +397 -0
  66. package/docs/INSTALLATION.md +423 -0
  67. package/docs/PERFORMANCE_MONITORING.md +17 -15
  68. package/docs/SECURITY.md +621 -0
  69. package/docs/SECURITY_TESTING.md +22 -26
  70. package/docs/TEST_SITE_SETUP.md +136 -0
  71. package/docs/TROUBLESHOOTING.md +578 -0
  72. package/docs/api/README.md +76 -91
  73. package/docs/api/categories/auth.md +0 -2
  74. package/docs/api/categories/cache.md +0 -2
  75. package/docs/api/categories/comment.md +0 -2
  76. package/docs/api/categories/media.md +0 -2
  77. package/docs/api/categories/page.md +0 -2
  78. package/docs/api/categories/performance.md +0 -2
  79. package/docs/api/categories/post.md +0 -2
  80. package/docs/api/categories/site.md +0 -2
  81. package/docs/api/categories/taxonomy.md +0 -2
  82. package/docs/api/categories/user.md +0 -2
  83. package/docs/api/summary.json +1 -1
  84. package/docs/api/tools/wp_approve_comment.md +11 -3
  85. package/docs/api/tools/wp_cache_clear.md +14 -5
  86. package/docs/api/tools/wp_cache_info.md +14 -5
  87. package/docs/api/tools/wp_cache_stats.md +14 -5
  88. package/docs/api/tools/wp_cache_warm.md +14 -5
  89. package/docs/api/tools/wp_create_application_password.md +11 -3
  90. package/docs/api/tools/wp_create_category.md +11 -3
  91. package/docs/api/tools/wp_create_comment.md +14 -5
  92. package/docs/api/tools/wp_create_page.md +13 -5
  93. package/docs/api/tools/wp_create_post.md +14 -7
  94. package/docs/api/tools/wp_create_tag.md +11 -3
  95. package/docs/api/tools/wp_create_user.md +13 -5
  96. package/docs/api/tools/wp_delete_application_password.md +11 -3
  97. package/docs/api/tools/wp_delete_category.md +11 -3
  98. package/docs/api/tools/wp_delete_comment.md +11 -3
  99. package/docs/api/tools/wp_delete_media.md +10 -3
  100. package/docs/api/tools/wp_delete_page.md +10 -3
  101. package/docs/api/tools/wp_delete_post.md +11 -5
  102. package/docs/api/tools/wp_delete_tag.md +11 -3
  103. package/docs/api/tools/wp_delete_user.md +10 -3
  104. package/docs/api/tools/wp_get_application_passwords.md +11 -3
  105. package/docs/api/tools/wp_get_auth_status.md +11 -3
  106. package/docs/api/tools/wp_get_category.md +11 -3
  107. package/docs/api/tools/wp_get_comment.md +11 -3
  108. package/docs/api/tools/wp_get_current_user.md +11 -3
  109. package/docs/api/tools/wp_get_media.md +11 -3
  110. package/docs/api/tools/wp_get_page.md +11 -3
  111. package/docs/api/tools/wp_get_page_revisions.md +11 -3
  112. package/docs/api/tools/wp_get_post.md +12 -5
  113. package/docs/api/tools/wp_get_post_revisions.md +11 -3
  114. package/docs/api/tools/wp_get_site_settings.md +10 -3
  115. package/docs/api/tools/wp_get_tag.md +11 -3
  116. package/docs/api/tools/wp_get_user.md +11 -3
  117. package/docs/api/tools/wp_list_categories.md +11 -3
  118. package/docs/api/tools/wp_list_comments.md +11 -3
  119. package/docs/api/tools/wp_list_media.md +14 -5
  120. package/docs/api/tools/wp_list_pages.md +14 -5
  121. package/docs/api/tools/wp_list_posts.md +15 -7
  122. package/docs/api/tools/wp_list_tags.md +11 -3
  123. package/docs/api/tools/wp_list_users.md +11 -3
  124. package/docs/api/tools/wp_performance_alerts.md +17 -7
  125. package/docs/api/tools/wp_performance_benchmark.md +17 -7
  126. package/docs/api/tools/wp_performance_export.md +17 -7
  127. package/docs/api/tools/wp_performance_history.md +17 -7
  128. package/docs/api/tools/wp_performance_optimize.md +17 -7
  129. package/docs/api/tools/wp_performance_stats.md +17 -7
  130. package/docs/api/tools/wp_search_site.md +11 -3
  131. package/docs/api/tools/wp_spam_comment.md +11 -3
  132. package/docs/api/tools/wp_switch_auth_method.md +14 -5
  133. package/docs/api/tools/wp_test_auth.md +11 -3
  134. package/docs/api/tools/wp_update_category.md +11 -3
  135. package/docs/api/tools/wp_update_comment.md +14 -5
  136. package/docs/api/tools/wp_update_media.md +14 -5
  137. package/docs/api/tools/wp_update_page.md +13 -5
  138. package/docs/api/tools/wp_update_post.md +14 -7
  139. package/docs/api/tools/wp_update_site_settings.md +14 -5
  140. package/docs/api/tools/wp_update_tag.md +11 -3
  141. package/docs/api/tools/wp_update_user.md +13 -5
  142. package/docs/api/tools/wp_upload_media.md +13 -5
  143. package/docs/api/types/WordPressPost.md +2 -0
  144. package/docs/code-improvements.md +40 -0
  145. package/docs/contract-testing.md +1 -1
  146. package/docs/developer/API_REFERENCE.md +19 -59
  147. package/docs/developer/ARCHITECTURE.md +8 -11
  148. package/docs/developer/BUILD_SYSTEM.md +2 -2
  149. package/docs/developer/CONTRIBUTING.md +3 -5
  150. package/docs/developer/GITHUB_ACTIONS_SETUP.md +2 -2
  151. package/docs/developer/MIGRATION_GUIDE.md +5 -6
  152. package/docs/developer/README.md +2 -1
  153. package/docs/developer/REFACTORING.md +9 -15
  154. package/docs/developer/RELEASE_PROCESS.md +4 -3
  155. package/docs/developer/TESTING.md +2 -2
  156. package/docs/examples/claude-desktop-config.md +8 -0
  157. package/docs/integrations/claude-desktop.md +426 -0
  158. package/docs/integrations/cline.md +537 -0
  159. package/docs/integrations/vs-code.md +515 -0
  160. package/docs/releases/COMMUNITY_ANNOUNCEMENT_v1.1.2.md +30 -23
  161. package/docs/releases/RELEASE_NOTES_v1.1.2.md +7 -6
  162. package/docs/testing-configurations.md +11 -0
  163. package/docs/user-guides/DOCKER_NPM_DTX_SETUP.md +3 -2
  164. package/docs/user-guides/DOCKER_SETUP.md +3 -2
  165. package/docs/user-guides/DTX_SETUP.md +6 -5
  166. package/docs/user-guides/DXT_INSTALLATION.md +4 -4
  167. package/docs/user-guides/NPM_SETUP.md +4 -2
  168. package/docs/user-guides/NPX_SETUP.md +4 -2
  169. package/docs/user-guides/SMITHERY_SETUP.md +402 -0
  170. package/docs/wordpress-rest-api-authentication-troubleshooting.md +45 -42
  171. package/package.json +12 -2
  172. package/src/cache/CacheInvalidation.ts +7 -18
  173. package/src/client/MockWordPressClient.ts +398 -0
  174. package/src/client/api.ts +77 -237
  175. package/src/client/managers/AuthenticationManager.ts +19 -56
  176. package/src/config/ConfigurationSchema.ts +14 -45
  177. package/src/config/ServerConfiguration.ts +98 -71
  178. package/src/docs/DocumentationGenerator.ts +39 -123
  179. package/src/dxt-entry.cjs +4 -1
  180. package/src/index.ts +35 -54
  181. package/src/security/InputValidator.ts +15 -57
  182. package/src/server/ToolRegistry.ts +88 -17
  183. package/src/tools/auth.ts +15 -22
  184. package/src/tools/posts.ts +347 -64
  185. package/src/tools/site.ts +69 -46
  186. package/src/tools/users.ts +142 -44
  187. package/src/utils/enhancedError.ts +248 -0
  188. package/src/utils/streaming.ts +428 -0
  189. package/src/utils/validation.ts +253 -92
  190. package/dist/mcp-wordpress-1.5.2.tgz +0 -0
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Streaming utilities for handling large result sets
3
+ * Implements streaming responses for better performance and memory usage
4
+ */
5
+ /**
6
+ * Creates a streaming response for large datasets
7
+ */
8
+ export class DataStreamer {
9
+ batchSize;
10
+ delay;
11
+ transformItem;
12
+ filterItem;
13
+ constructor(options = {}) {
14
+ this.batchSize = options.batchSize || 50;
15
+ this.delay = options.delay || 0;
16
+ this.transformItem = options.transformItem || undefined;
17
+ this.filterItem = options.filterItem || undefined;
18
+ }
19
+ /**
20
+ * Processes data in batches with streaming
21
+ */
22
+ async *streamBatches(data, processor) {
23
+ const total = data.length;
24
+ let processed = 0;
25
+ for (let i = 0; i < data.length; i += this.batchSize) {
26
+ const batch = data.slice(i, i + this.batchSize);
27
+ // Apply filtering if provided
28
+ const filteredBatch = this.filterItem ? batch.filter(this.filterItem) : batch;
29
+ // Process the batch
30
+ const processedBatch = await processor(filteredBatch);
31
+ // Apply transformation if provided
32
+ const transformedBatch = this.transformItem
33
+ ? processedBatch.map((item) => this.transformItem(item))
34
+ : processedBatch;
35
+ processed += batch.length;
36
+ const hasMore = processed < total;
37
+ yield {
38
+ data: transformedBatch,
39
+ hasMore,
40
+ cursor: hasMore ? String(i + this.batchSize) : undefined,
41
+ total,
42
+ processed,
43
+ };
44
+ // Add delay between batches if specified
45
+ if (this.delay > 0 && hasMore) {
46
+ await new Promise((resolve) => setTimeout(resolve, this.delay));
47
+ }
48
+ }
49
+ }
50
+ /**
51
+ * Processes large datasets with pagination
52
+ */
53
+ async *streamPages(fetcher, processor) {
54
+ let page = 1;
55
+ let totalProcessed = 0;
56
+ while (true) {
57
+ const result = await fetcher(page, this.batchSize);
58
+ if (result.data.length === 0) {
59
+ break;
60
+ }
61
+ // Apply filtering if provided
62
+ const filteredData = this.filterItem ? result.data.filter(this.filterItem) : result.data;
63
+ // Process the data
64
+ const processedData = await processor(filteredData);
65
+ // Apply transformation if provided
66
+ const transformedData = this.transformItem
67
+ ? processedData.map((item) => this.transformItem(item))
68
+ : processedData;
69
+ totalProcessed += result.data.length;
70
+ yield {
71
+ data: transformedData,
72
+ hasMore: result.hasMore,
73
+ cursor: result.hasMore ? String(page + 1) : undefined,
74
+ total: undefined, // Unknown for paginated results
75
+ processed: totalProcessed,
76
+ };
77
+ if (!result.hasMore) {
78
+ break;
79
+ }
80
+ page++;
81
+ // Add delay between pages if specified
82
+ if (this.delay > 0) {
83
+ await new Promise((resolve) => setTimeout(resolve, this.delay));
84
+ }
85
+ }
86
+ }
87
+ }
88
+ /**
89
+ * Streaming formatter for WordPress data
90
+ */
91
+ export class WordPressDataStreamer {
92
+ /**
93
+ * Streams WordPress posts with author and taxonomy information
94
+ */
95
+ static async *streamPosts(posts, options = {}) {
96
+ const streamer = new DataStreamer({
97
+ batchSize: options.batchSize || 20,
98
+ transformItem: (post) => ({
99
+ id: post.id,
100
+ title: post.title?.rendered || "Untitled",
101
+ excerpt: post.excerpt?.rendered
102
+ ? post.excerpt.rendered.replace(/<[^>]*>/g, "").substring(0, 150) + "..."
103
+ : "No excerpt",
104
+ status: post.status,
105
+ date: new Date(post.date).toLocaleDateString(),
106
+ link: post.link,
107
+ author: options.includeAuthor ? post.author : undefined,
108
+ categories: options.includeCategories ? post.categories : undefined,
109
+ tags: options.includeTags ? post.tags : undefined,
110
+ }),
111
+ filterItem: (post) => post.status !== "trash", // Filter out trashed posts
112
+ });
113
+ const processor = async (batch) => {
114
+ // Simulate processing time for large datasets
115
+ await new Promise((resolve) => setTimeout(resolve, 10));
116
+ return batch;
117
+ };
118
+ for await (const result of streamer.streamBatches(posts, processor)) {
119
+ yield result;
120
+ }
121
+ }
122
+ /**
123
+ * Streams WordPress users with role information
124
+ */
125
+ static async *streamUsers(users, options = {}) {
126
+ const streamer = new DataStreamer({
127
+ batchSize: options.batchSize || 30,
128
+ transformItem: (user) => ({
129
+ id: user.id,
130
+ name: user.name || "No name",
131
+ username: user.slug || "unknown",
132
+ email: user.email || "No email",
133
+ roles: options.includeRoles ? user.roles : undefined,
134
+ capabilities: options.includeCapabilities ? Object.keys(user.capabilities || {}) : undefined,
135
+ registeredDate: user.registered_date ? new Date(user.registered_date).toLocaleDateString() : "Unknown",
136
+ }),
137
+ });
138
+ const processor = async (batch) => {
139
+ // Add user processing logic here if needed
140
+ return batch;
141
+ };
142
+ for await (const result of streamer.streamBatches(users, processor)) {
143
+ yield result;
144
+ }
145
+ }
146
+ /**
147
+ * Streams WordPress comments with moderation status
148
+ */
149
+ static async *streamComments(comments, options = {}) {
150
+ const streamer = new DataStreamer({
151
+ batchSize: options.batchSize || 40,
152
+ transformItem: (comment) => ({
153
+ id: comment.id,
154
+ content: comment.content?.rendered
155
+ ? comment.content.rendered.replace(/<[^>]*>/g, "").substring(0, 200) + "..."
156
+ : "No content",
157
+ status: comment.status,
158
+ date: new Date(comment.date).toLocaleDateString(),
159
+ author: options.includeAuthor
160
+ ? {
161
+ name: comment.author_name,
162
+ email: comment.author_email,
163
+ url: comment.author_url,
164
+ }
165
+ : undefined,
166
+ post: options.includePost ? comment.post : undefined,
167
+ }),
168
+ filterItem: (comment) => comment.status !== "spam", // Filter out spam comments
169
+ });
170
+ const processor = async (batch) => {
171
+ // Add comment processing logic here if needed
172
+ return batch;
173
+ };
174
+ for await (const result of streamer.streamBatches(comments, processor)) {
175
+ yield result;
176
+ }
177
+ }
178
+ }
179
+ /**
180
+ * Utility functions for streaming responses
181
+ */
182
+ export class StreamingUtils {
183
+ /**
184
+ * Formats streaming results for display
185
+ */
186
+ static formatStreamingResponse(results, type = "posts") {
187
+ const allData = results.flatMap((result) => result.data);
188
+ const totalProcessed = results[results.length - 1]?.processed || 0;
189
+ const hasMore = results[results.length - 1]?.hasMore || false;
190
+ const typeEmojis = {
191
+ posts: "📄",
192
+ users: "👥",
193
+ comments: "💬",
194
+ media: "📎",
195
+ };
196
+ const emoji = typeEmojis[type];
197
+ const typeName = type.charAt(0).toUpperCase() + type.slice(1);
198
+ let response = `${emoji} **${typeName} Results** (Streamed)\n\n`;
199
+ response += `📊 **Summary**: ${allData.length} items displayed, ${totalProcessed} processed total\n`;
200
+ if (hasMore) {
201
+ response += `⏳ **Status**: More data available (streaming in progress)\n`;
202
+ }
203
+ else {
204
+ response += `✅ **Status**: Complete\n`;
205
+ }
206
+ response += `🕐 **Retrieved**: ${new Date().toLocaleString()}\n\n`;
207
+ // Format individual items
208
+ allData.forEach((item, index) => {
209
+ response += `${index + 1}. **${item.title || item.name || item.content?.substring(0, 50) || "Item"}**\n`;
210
+ if (item.excerpt)
211
+ response += ` 📝 ${item.excerpt}\n`;
212
+ if (item.email)
213
+ response += ` 📧 ${item.email}\n`;
214
+ if (item.status)
215
+ response += ` 🏷️ Status: ${item.status}\n`;
216
+ if (item.date)
217
+ response += ` 📅 Date: ${item.date}\n`;
218
+ response += "\n";
219
+ });
220
+ return response;
221
+ }
222
+ /**
223
+ * Implements progressive loading for large datasets
224
+ */
225
+ static async loadProgressively(fetcher, options = {}) {
226
+ const initialLoad = options.initialLoad || 50;
227
+ const batchSize = options.batchSize || 25;
228
+ const maxItems = options.maxItems || 1000;
229
+ const results = [];
230
+ let offset = 0;
231
+ let hasMore = true;
232
+ // Initial load
233
+ const initialBatch = await fetcher(offset, initialLoad);
234
+ results.push(...initialBatch);
235
+ offset += initialLoad;
236
+ if (options.onProgress) {
237
+ options.onProgress(results.length);
238
+ }
239
+ // Progressive loading
240
+ while (hasMore && results.length < maxItems) {
241
+ const batch = await fetcher(offset, batchSize);
242
+ if (batch.length === 0) {
243
+ hasMore = false;
244
+ break;
245
+ }
246
+ results.push(...batch);
247
+ offset += batchSize;
248
+ if (options.onProgress) {
249
+ options.onProgress(results.length, maxItems);
250
+ }
251
+ // Small delay to prevent overwhelming the server
252
+ await new Promise((resolve) => setTimeout(resolve, 100));
253
+ }
254
+ return results.slice(0, maxItems);
255
+ }
256
+ }
257
+ /**
258
+ * Memory-efficient data processor
259
+ */
260
+ export class MemoryEfficientProcessor {
261
+ /**
262
+ * Processes large datasets with memory monitoring
263
+ */
264
+ static async processLargeDataset(dataProvider, processor, options = {}) {
265
+ const maxMemory = options.maxMemoryUsage || 100; // 100MB default
266
+ const batchSize = options.batchSize || 50;
267
+ const results = [];
268
+ let processed = 0;
269
+ for await (const batch of dataProvider()) {
270
+ // Check memory usage
271
+ const memoryUsage = process.memoryUsage();
272
+ const memoryUsageMB = memoryUsage.heapUsed / 1024 / 1024;
273
+ if (memoryUsageMB > maxMemory) {
274
+ // If memory usage is too high, process in smaller batches
275
+ const smallerBatches = this.chunkArray(batch, Math.floor(batchSize / 2));
276
+ for (const smallBatch of smallerBatches) {
277
+ const processed_batch = await processor(smallBatch);
278
+ results.push(...processed_batch);
279
+ processed += smallBatch.length;
280
+ if (options.onProgress) {
281
+ options.onProgress(processed);
282
+ }
283
+ // Force garbage collection if available
284
+ if (global.gc) {
285
+ global.gc();
286
+ }
287
+ }
288
+ }
289
+ else {
290
+ // Normal processing
291
+ const processed_batch = await processor(batch);
292
+ results.push(...processed_batch);
293
+ processed += batch.length;
294
+ if (options.onProgress) {
295
+ options.onProgress(processed);
296
+ }
297
+ }
298
+ }
299
+ return results;
300
+ }
301
+ /**
302
+ * Helper method to split arrays into chunks
303
+ */
304
+ static chunkArray(array, chunkSize) {
305
+ const chunks = [];
306
+ for (let i = 0; i < array.length; i += chunkSize) {
307
+ chunks.push(array.slice(i, i + chunkSize));
308
+ }
309
+ return chunks;
310
+ }
311
+ }
312
+ //# sourceMappingURL=streaming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../src/utils/streaming.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * Security-focused validation utilities for MCP WordPress
3
3
  */
4
4
  /**
5
- * Validates and sanitizes numeric IDs
5
+ * Validates and sanitizes numeric IDs with comprehensive edge case handling
6
6
  */
7
7
  export declare function validateId(id: any, fieldName?: string): number;
8
8
  /**
@@ -18,7 +18,7 @@ export declare function validateFilePath(userPath: string, allowedBasePath: stri
18
18
  */
19
19
  export declare function validatePostStatus(status: string): string;
20
20
  /**
21
- * Validates and sanitizes URLs
21
+ * Validates and sanitizes URLs with enhanced edge case handling
22
22
  */
23
23
  export declare function validateUrl(url: string, fieldName?: string): string;
24
24
  /**
@@ -44,7 +44,7 @@ export declare function validateArray<T>(value: any, fieldName: string, minItems
44
44
  */
45
45
  export declare function validateEmail(email: string): string;
46
46
  /**
47
- * Validates username format
47
+ * Validates username format with enhanced security checks
48
48
  */
49
49
  export declare function validateUsername(username: string): string;
50
50
  /**
@@ -64,5 +64,21 @@ export declare const authRateLimiter: RateLimiter;
64
64
  * Validates and sanitizes search queries
65
65
  */
66
66
  export declare function validateSearchQuery(query: string): string;
67
+ /**
68
+ * Validates pagination parameters as a set
69
+ */
70
+ export declare function validatePaginationParams(params: {
71
+ page?: any;
72
+ per_page?: any;
73
+ offset?: any;
74
+ }): {
75
+ page?: number;
76
+ per_page?: number;
77
+ offset?: number;
78
+ };
79
+ /**
80
+ * Validates complex post creation parameters
81
+ */
82
+ export declare function validatePostParams(params: any): any;
67
83
  export {};
68
84
  //# sourceMappingURL=validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,SAAS,GAAE,MAAa,GAAG,MAAM,CAUpE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,GAAG,EACV,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,MAAU,EACrB,SAAS,GAAE,MAAa,GACvB,MAAM,CAmBR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GACtB,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAkBzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAc,GAAG,MAAM,CAe1E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,MAAW,GACvB,IAAI,CASN;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EAAE,GACrB,IAAI,CAQN;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBjD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,GAAG,EACV,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,MAAU,EACpB,QAAQ,GAAE,MAAY,GACrB,CAAC,EAAE,CAkBL;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUnD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoBzD;AAED;;;GAGG;AACH,cAAM,WAAW;IAKb,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ;IALlB,OAAO,CAAC,QAAQ,CACJ;gBAGF,WAAW,GAAE,MAAU,EACvB,QAAQ,GAAE,MAAc;IAGlC,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAwB/B,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;CAGhC;AAGD,eAAO,MAAM,eAAe,aAA6B,CAAC;AAE1D;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAmBzD"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,SAAS,GAAE,MAAa,GAAG,MAAM,CA6CpE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,MAAU,EAAE,SAAS,GAAE,MAAa,GAAG,MAAM,CAerH;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAWlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAc,GAAG,MAAM,CAgE1E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,GAAE,MAAW,GAAG,IAAI,CAKpF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAQ/E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcjD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAY,GAAG,CAAC,EAAE,CAcjH;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAsCzD;AAED;;;GAGG;AACH,cAAM,WAAW;IAIb,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ;IAJlB,OAAO,CAAC,QAAQ,CAAgE;gBAGtE,WAAW,GAAE,MAAU,EACvB,QAAQ,GAAE,MAAc;IAGlC,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAwB/B,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;CAGhC;AAGD,eAAO,MAAM,eAAe,aAA6B,CAAC;AAE1D;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBzD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,GAAG;IAC9F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAiDA;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAsDnD"}
@@ -4,12 +4,35 @@ import { WordPressAPIError } from "../types/client.js";
4
4
  * Security-focused validation utilities for MCP WordPress
5
5
  */
6
6
  /**
7
- * Validates and sanitizes numeric IDs
7
+ * Validates and sanitizes numeric IDs with comprehensive edge case handling
8
8
  */
9
9
  export function validateId(id, fieldName = "id") {
10
- const numId = parseInt(String(id), 10);
11
- if (isNaN(numId) || numId <= 0) {
12
- throw new WordPressAPIError(`Invalid ${fieldName}: must be a positive number`, 400, "INVALID_PARAMETER");
10
+ // Handle null/undefined
11
+ if (id === null || id === undefined) {
12
+ throw new WordPressAPIError(`${fieldName} is required`, 400, "MISSING_PARAMETER");
13
+ }
14
+ // Convert to string first to handle various input types
15
+ const strId = String(id).trim();
16
+ // Check for empty string after trim
17
+ if (strId === "") {
18
+ throw new WordPressAPIError(`${fieldName} cannot be empty`, 400, "INVALID_PARAMETER");
19
+ }
20
+ // Handle decimal inputs
21
+ if (strId.includes(".")) {
22
+ throw new WordPressAPIError(`${fieldName} must be a whole number, not a decimal`, 400, "INVALID_PARAMETER");
23
+ }
24
+ const numId = parseInt(strId, 10);
25
+ // Check for NaN
26
+ if (isNaN(numId)) {
27
+ throw new WordPressAPIError(`Invalid ${fieldName}: "${id}" is not a valid number`, 400, "INVALID_PARAMETER");
28
+ }
29
+ // Check for negative or zero
30
+ if (numId <= 0) {
31
+ throw new WordPressAPIError(`Invalid ${fieldName}: must be a positive number (got ${numId})`, 400, "INVALID_PARAMETER");
32
+ }
33
+ // Check for max int32 limit (WordPress database limit)
34
+ if (numId > 2147483647) {
35
+ throw new WordPressAPIError(`Invalid ${fieldName}: exceeds maximum allowed value (2147483647)`, 400, "INVALID_PARAMETER");
13
36
  }
14
37
  return numId;
15
38
  }
@@ -43,34 +66,55 @@ export function validateFilePath(userPath, allowedBasePath) {
43
66
  * Validates WordPress post status values
44
67
  */
45
68
  export function validatePostStatus(status) {
46
- const validStatuses = [
47
- "publish",
48
- "draft",
49
- "pending",
50
- "private",
51
- "future",
52
- "auto-draft",
53
- "trash",
54
- ];
69
+ const validStatuses = ["publish", "draft", "pending", "private", "future", "auto-draft", "trash"];
55
70
  if (!validStatuses.includes(status)) {
56
71
  throw new WordPressAPIError(`Invalid status: must be one of ${validStatuses.join(", ")}`, 400, "INVALID_PARAMETER");
57
72
  }
58
73
  return status;
59
74
  }
60
75
  /**
61
- * Validates and sanitizes URLs
76
+ * Validates and sanitizes URLs with enhanced edge case handling
62
77
  */
63
78
  export function validateUrl(url, fieldName = "url") {
79
+ // Check for empty or whitespace-only URLs
80
+ const trimmedUrl = url.trim();
81
+ if (!trimmedUrl) {
82
+ throw new WordPressAPIError(`${fieldName} cannot be empty`, 400, "INVALID_PARAMETER");
83
+ }
84
+ // Remove trailing slashes for consistency
85
+ const cleanUrl = trimmedUrl.replace(/\/+$/, "");
86
+ // Check for common URL mistakes
87
+ if (!cleanUrl.match(/^https?:\/\//i)) {
88
+ throw new WordPressAPIError(`Invalid ${fieldName}: must start with http:// or https:// (got "${cleanUrl}")`, 400, "INVALID_PARAMETER");
89
+ }
64
90
  try {
65
- const urlObj = new URL(url);
91
+ const urlObj = new URL(cleanUrl);
66
92
  // Only allow http and https protocols
67
93
  if (!["http:", "https:"].includes(urlObj.protocol)) {
68
- throw new Error("Invalid protocol");
94
+ throw new WordPressAPIError(`Invalid ${fieldName}: only HTTP and HTTPS protocols are allowed`, 400, "INVALID_PARAMETER");
95
+ }
96
+ // Validate hostname
97
+ if (!urlObj.hostname || urlObj.hostname.length < 3) {
98
+ throw new WordPressAPIError(`Invalid ${fieldName}: hostname is missing or too short`, 400, "INVALID_PARAMETER");
99
+ }
100
+ // Check for localhost in production
101
+ if (process.env.NODE_ENV === "production" && (urlObj.hostname === "localhost" || urlObj.hostname === "127.0.0.1")) {
102
+ throw new WordPressAPIError(`Invalid ${fieldName}: localhost URLs are not allowed in production`, 400, "INVALID_PARAMETER");
103
+ }
104
+ // Validate port if present
105
+ if (urlObj.port) {
106
+ const port = parseInt(urlObj.port);
107
+ if (port < 1 || port > 65535) {
108
+ throw new WordPressAPIError(`Invalid ${fieldName}: port number must be between 1 and 65535`, 400, "INVALID_PARAMETER");
109
+ }
69
110
  }
70
- return urlObj.toString();
111
+ return cleanUrl;
71
112
  }
72
- catch {
73
- throw new WordPressAPIError(`Invalid ${fieldName}: must be a valid URL`, 400, "INVALID_PARAMETER");
113
+ catch (error) {
114
+ if (error instanceof WordPressAPIError) {
115
+ throw error;
116
+ }
117
+ throw new WordPressAPIError(`Invalid ${fieldName}: malformed URL "${cleanUrl}"`, 400, "INVALID_PARAMETER");
74
118
  }
75
119
  }
76
120
  /**
@@ -129,18 +173,33 @@ export function validateEmail(email) {
129
173
  return email.toLowerCase();
130
174
  }
131
175
  /**
132
- * Validates username format
176
+ * Validates username format with enhanced security checks
133
177
  */
134
178
  export function validateUsername(username) {
179
+ // Trim and check for empty
180
+ const trimmed = username.trim();
181
+ if (!trimmed) {
182
+ throw new WordPressAPIError("Username cannot be empty", 400, "INVALID_PARAMETER");
183
+ }
135
184
  // WordPress username rules: alphanumeric, space, underscore, hyphen, period, @ symbol
136
185
  const usernameRegex = /^[a-zA-Z0-9 _.\-@]+$/;
137
- if (!usernameRegex.test(username)) {
186
+ if (!usernameRegex.test(trimmed)) {
138
187
  throw new WordPressAPIError("Invalid username: can only contain letters, numbers, spaces, and _.-@ symbols", 400, "INVALID_PARAMETER");
139
188
  }
140
- if (username.length < 3 || username.length > 60) {
141
- throw new WordPressAPIError("Invalid username: must be between 3 and 60 characters", 400, "INVALID_PARAMETER");
189
+ // Length validation
190
+ if (trimmed.length < 3 || trimmed.length > 60) {
191
+ throw new WordPressAPIError(`Invalid username: must be between 3 and 60 characters (got ${trimmed.length})`, 400, "INVALID_PARAMETER");
192
+ }
193
+ // Check for consecutive spaces
194
+ if (/\s{2,}/.test(trimmed)) {
195
+ throw new WordPressAPIError("Invalid username: cannot contain consecutive spaces", 400, "INVALID_PARAMETER");
142
196
  }
143
- return username;
197
+ // Security: Prevent common problematic usernames
198
+ const blacklist = ["admin", "root", "wordpress", "wp-admin", "administrator"];
199
+ if (blacklist.includes(trimmed.toLowerCase())) {
200
+ throw new WordPressAPIError(`Username "${trimmed}" is reserved and cannot be used`, 400, "RESERVED_USERNAME");
201
+ }
202
+ return trimmed;
144
203
  }
145
204
  /**
146
205
  * Rate limiting tracker (simple in-memory implementation)
@@ -192,4 +251,95 @@ export function validateSearchQuery(query) {
192
251
  sanitized = sanitized.replace(/[<>'"`;\\]/g, "");
193
252
  return sanitized;
194
253
  }
254
+ /**
255
+ * Validates pagination parameters as a set
256
+ */
257
+ export function validatePaginationParams(params) {
258
+ const validated = {};
259
+ // Validate page
260
+ if (params.page !== undefined) {
261
+ const page = parseInt(String(params.page), 10);
262
+ if (isNaN(page) || page < 1) {
263
+ throw new WordPressAPIError("Page must be a positive integer", 400, "INVALID_PARAMETER");
264
+ }
265
+ if (page > 10000) {
266
+ throw new WordPressAPIError("Page number too high (max 10000)", 400, "INVALID_PARAMETER");
267
+ }
268
+ validated.page = page;
269
+ }
270
+ // Validate per_page
271
+ if (params.per_page !== undefined) {
272
+ const perPage = parseInt(String(params.per_page), 10);
273
+ if (isNaN(perPage) || perPage < 1) {
274
+ throw new WordPressAPIError("Per page must be a positive integer", 400, "INVALID_PARAMETER");
275
+ }
276
+ if (perPage > 100) {
277
+ throw new WordPressAPIError(`Per page exceeds maximum allowed (100), got ${perPage}`, 400, "INVALID_PARAMETER");
278
+ }
279
+ validated.per_page = perPage;
280
+ }
281
+ // Validate offset
282
+ if (params.offset !== undefined) {
283
+ const offset = parseInt(String(params.offset), 10);
284
+ if (isNaN(offset) || offset < 0) {
285
+ throw new WordPressAPIError("Offset must be a non-negative integer", 400, "INVALID_PARAMETER");
286
+ }
287
+ if (offset > 1000000) {
288
+ throw new WordPressAPIError("Offset too large (max 1000000)", 400, "INVALID_PARAMETER");
289
+ }
290
+ validated.offset = offset;
291
+ }
292
+ // Check for conflicting parameters
293
+ if (validated.page && validated.offset) {
294
+ throw new WordPressAPIError("Cannot use both 'page' and 'offset' parameters together", 400, "CONFLICTING_PARAMETERS");
295
+ }
296
+ return validated;
297
+ }
298
+ /**
299
+ * Validates complex post creation parameters
300
+ */
301
+ export function validatePostParams(params) {
302
+ const validated = {};
303
+ // Title validation
304
+ if (!params.title || typeof params.title !== "string") {
305
+ throw new WordPressAPIError("Post title is required and must be a string", 400, "INVALID_PARAMETER");
306
+ }
307
+ validated.title = validateString(params.title, "title", 1, 200);
308
+ // Content validation
309
+ if (params.content !== undefined) {
310
+ validated.content = sanitizeHtml(String(params.content));
311
+ }
312
+ // Status validation with context
313
+ if (params.status) {
314
+ validated.status = validatePostStatus(params.status);
315
+ // Future posts need a date
316
+ if (validated.status === "future" && !params.date) {
317
+ throw new WordPressAPIError("Future posts require a 'date' parameter", 400, "MISSING_PARAMETER");
318
+ }
319
+ }
320
+ // Categories and tags validation
321
+ if (params.categories) {
322
+ validated.categories = validateArray(params.categories, "categories", 0, 50);
323
+ validated.categories = validated.categories.map((id) => validateId(id, "category ID"));
324
+ }
325
+ if (params.tags) {
326
+ validated.tags = validateArray(params.tags, "tags", 0, 100);
327
+ validated.tags = validated.tags.map((id) => validateId(id, "tag ID"));
328
+ }
329
+ // Date validation for scheduled posts
330
+ if (params.date) {
331
+ try {
332
+ const date = new Date(params.date);
333
+ if (isNaN(date.getTime())) {
334
+ throw new Error("Invalid date");
335
+ }
336
+ // WordPress expects ISO 8601 format
337
+ validated.date = date.toISOString();
338
+ }
339
+ catch {
340
+ throw new WordPressAPIError("Invalid date format. Use ISO 8601 format (YYYY-MM-DDTHH:mm:ss)", 400, "INVALID_PARAMETER");
341
+ }
342
+ }
343
+ return validated;
344
+ }
195
345
  //# sourceMappingURL=validation.js.map