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.
- package/README.md +332 -61
- package/dist/cache/CacheInvalidation.d.ts.map +1 -1
- package/dist/cache/CacheInvalidation.js +4 -4
- package/dist/cache/CacheInvalidation.js.map +1 -1
- package/dist/client/MockWordPressClient.d.ts +55 -0
- package/dist/client/MockWordPressClient.d.ts.map +1 -0
- package/dist/client/MockWordPressClient.js +369 -0
- package/dist/client/MockWordPressClient.js.map +1 -0
- package/dist/client/api.d.ts +1 -0
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +26 -60
- package/dist/client/api.js.map +1 -1
- package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
- package/dist/client/managers/AuthenticationManager.js +4 -3
- package/dist/client/managers/AuthenticationManager.js.map +1 -1
- package/dist/config/ConfigurationSchema.d.ts +3 -3
- package/dist/config/ConfigurationSchema.d.ts.map +1 -1
- package/dist/config/ConfigurationSchema.js +7 -24
- package/dist/config/ConfigurationSchema.js.map +1 -1
- package/dist/config/ServerConfiguration.d.ts +8 -0
- package/dist/config/ServerConfiguration.d.ts.map +1 -1
- package/dist/config/ServerConfiguration.js +80 -31
- package/dist/config/ServerConfiguration.js.map +1 -1
- package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
- package/dist/docs/DocumentationGenerator.js +5 -7
- package/dist/docs/DocumentationGenerator.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -29
- package/dist/index.js.map +1 -1
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +3 -11
- package/dist/security/InputValidator.js.map +1 -1
- package/dist/server/ToolRegistry.d.ts +4 -0
- package/dist/server/ToolRegistry.d.ts.map +1 -1
- package/dist/server/ToolRegistry.js +71 -8
- package/dist/server/ToolRegistry.js.map +1 -1
- package/dist/tools/auth.d.ts.map +1 -1
- package/dist/tools/auth.js +8 -3
- package/dist/tools/auth.js.map +1 -1
- package/dist/tools/posts.d.ts.map +1 -1
- package/dist/tools/posts.js +287 -20
- package/dist/tools/posts.js.map +1 -1
- package/dist/tools/site.d.ts.map +1 -1
- package/dist/tools/site.js +47 -9
- package/dist/tools/site.js.map +1 -1
- package/dist/tools/users.d.ts.map +1 -1
- package/dist/tools/users.js +113 -10
- package/dist/tools/users.js.map +1 -1
- package/dist/utils/enhancedError.d.ts +61 -0
- package/dist/utils/enhancedError.d.ts.map +1 -0
- package/dist/utils/enhancedError.js +221 -0
- package/dist/utils/enhancedError.js.map +1 -0
- package/dist/utils/streaming.d.ts +104 -0
- package/dist/utils/streaming.d.ts.map +1 -0
- package/dist/utils/streaming.js +312 -0
- package/dist/utils/streaming.js.map +1 -0
- package/dist/utils/validation.d.ts +19 -3
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +174 -24
- package/dist/utils/validation.js.map +1 -1
- package/docs/ARCHITECTURE.md +850 -0
- package/docs/CACHING.md +20 -17
- package/docs/CONFIGURATION.md +660 -0
- package/docs/DOCKER.md +61 -60
- package/docs/EVALUATION.md +397 -0
- package/docs/INSTALLATION.md +423 -0
- package/docs/PERFORMANCE_MONITORING.md +17 -15
- package/docs/SECURITY.md +621 -0
- package/docs/SECURITY_TESTING.md +22 -26
- package/docs/TEST_SITE_SETUP.md +136 -0
- package/docs/TROUBLESHOOTING.md +578 -0
- package/docs/api/README.md +76 -91
- package/docs/api/categories/auth.md +0 -2
- package/docs/api/categories/cache.md +0 -2
- package/docs/api/categories/comment.md +0 -2
- package/docs/api/categories/media.md +0 -2
- package/docs/api/categories/page.md +0 -2
- package/docs/api/categories/performance.md +0 -2
- package/docs/api/categories/post.md +0 -2
- package/docs/api/categories/site.md +0 -2
- package/docs/api/categories/taxonomy.md +0 -2
- package/docs/api/categories/user.md +0 -2
- package/docs/api/summary.json +1 -1
- package/docs/api/tools/wp_approve_comment.md +11 -3
- package/docs/api/tools/wp_cache_clear.md +14 -5
- package/docs/api/tools/wp_cache_info.md +14 -5
- package/docs/api/tools/wp_cache_stats.md +14 -5
- package/docs/api/tools/wp_cache_warm.md +14 -5
- package/docs/api/tools/wp_create_application_password.md +11 -3
- package/docs/api/tools/wp_create_category.md +11 -3
- package/docs/api/tools/wp_create_comment.md +14 -5
- package/docs/api/tools/wp_create_page.md +13 -5
- package/docs/api/tools/wp_create_post.md +14 -7
- package/docs/api/tools/wp_create_tag.md +11 -3
- package/docs/api/tools/wp_create_user.md +13 -5
- package/docs/api/tools/wp_delete_application_password.md +11 -3
- package/docs/api/tools/wp_delete_category.md +11 -3
- package/docs/api/tools/wp_delete_comment.md +11 -3
- package/docs/api/tools/wp_delete_media.md +10 -3
- package/docs/api/tools/wp_delete_page.md +10 -3
- package/docs/api/tools/wp_delete_post.md +11 -5
- package/docs/api/tools/wp_delete_tag.md +11 -3
- package/docs/api/tools/wp_delete_user.md +10 -3
- package/docs/api/tools/wp_get_application_passwords.md +11 -3
- package/docs/api/tools/wp_get_auth_status.md +11 -3
- package/docs/api/tools/wp_get_category.md +11 -3
- package/docs/api/tools/wp_get_comment.md +11 -3
- package/docs/api/tools/wp_get_current_user.md +11 -3
- package/docs/api/tools/wp_get_media.md +11 -3
- package/docs/api/tools/wp_get_page.md +11 -3
- package/docs/api/tools/wp_get_page_revisions.md +11 -3
- package/docs/api/tools/wp_get_post.md +12 -5
- package/docs/api/tools/wp_get_post_revisions.md +11 -3
- package/docs/api/tools/wp_get_site_settings.md +10 -3
- package/docs/api/tools/wp_get_tag.md +11 -3
- package/docs/api/tools/wp_get_user.md +11 -3
- package/docs/api/tools/wp_list_categories.md +11 -3
- package/docs/api/tools/wp_list_comments.md +11 -3
- package/docs/api/tools/wp_list_media.md +14 -5
- package/docs/api/tools/wp_list_pages.md +14 -5
- package/docs/api/tools/wp_list_posts.md +15 -7
- package/docs/api/tools/wp_list_tags.md +11 -3
- package/docs/api/tools/wp_list_users.md +11 -3
- package/docs/api/tools/wp_performance_alerts.md +17 -7
- package/docs/api/tools/wp_performance_benchmark.md +17 -7
- package/docs/api/tools/wp_performance_export.md +17 -7
- package/docs/api/tools/wp_performance_history.md +17 -7
- package/docs/api/tools/wp_performance_optimize.md +17 -7
- package/docs/api/tools/wp_performance_stats.md +17 -7
- package/docs/api/tools/wp_search_site.md +11 -3
- package/docs/api/tools/wp_spam_comment.md +11 -3
- package/docs/api/tools/wp_switch_auth_method.md +14 -5
- package/docs/api/tools/wp_test_auth.md +11 -3
- package/docs/api/tools/wp_update_category.md +11 -3
- package/docs/api/tools/wp_update_comment.md +14 -5
- package/docs/api/tools/wp_update_media.md +14 -5
- package/docs/api/tools/wp_update_page.md +13 -5
- package/docs/api/tools/wp_update_post.md +14 -7
- package/docs/api/tools/wp_update_site_settings.md +14 -5
- package/docs/api/tools/wp_update_tag.md +11 -3
- package/docs/api/tools/wp_update_user.md +13 -5
- package/docs/api/tools/wp_upload_media.md +13 -5
- package/docs/api/types/WordPressPost.md +2 -0
- package/docs/code-improvements.md +40 -0
- package/docs/contract-testing.md +1 -1
- package/docs/developer/API_REFERENCE.md +19 -59
- package/docs/developer/ARCHITECTURE.md +8 -11
- package/docs/developer/BUILD_SYSTEM.md +2 -2
- package/docs/developer/CONTRIBUTING.md +3 -5
- package/docs/developer/GITHUB_ACTIONS_SETUP.md +2 -2
- package/docs/developer/MIGRATION_GUIDE.md +5 -6
- package/docs/developer/README.md +2 -1
- package/docs/developer/REFACTORING.md +9 -15
- package/docs/developer/RELEASE_PROCESS.md +4 -3
- package/docs/developer/TESTING.md +2 -2
- package/docs/examples/claude-desktop-config.md +8 -0
- package/docs/integrations/claude-desktop.md +426 -0
- package/docs/integrations/cline.md +537 -0
- package/docs/integrations/vs-code.md +515 -0
- package/docs/releases/COMMUNITY_ANNOUNCEMENT_v1.1.2.md +30 -23
- package/docs/releases/RELEASE_NOTES_v1.1.2.md +7 -6
- package/docs/testing-configurations.md +11 -0
- package/docs/user-guides/DOCKER_NPM_DTX_SETUP.md +3 -2
- package/docs/user-guides/DOCKER_SETUP.md +3 -2
- package/docs/user-guides/DTX_SETUP.md +6 -5
- package/docs/user-guides/DXT_INSTALLATION.md +4 -4
- package/docs/user-guides/NPM_SETUP.md +4 -2
- package/docs/user-guides/NPX_SETUP.md +4 -2
- package/docs/user-guides/SMITHERY_SETUP.md +402 -0
- package/docs/wordpress-rest-api-authentication-troubleshooting.md +45 -42
- package/package.json +12 -2
- package/src/cache/CacheInvalidation.ts +7 -18
- package/src/client/MockWordPressClient.ts +398 -0
- package/src/client/api.ts +77 -237
- package/src/client/managers/AuthenticationManager.ts +19 -56
- package/src/config/ConfigurationSchema.ts +14 -45
- package/src/config/ServerConfiguration.ts +98 -71
- package/src/docs/DocumentationGenerator.ts +39 -123
- package/src/dxt-entry.cjs +4 -1
- package/src/index.ts +35 -54
- package/src/security/InputValidator.ts +15 -57
- package/src/server/ToolRegistry.ts +88 -17
- package/src/tools/auth.ts +15 -22
- package/src/tools/posts.ts +347 -64
- package/src/tools/site.ts +69 -46
- package/src/tools/users.ts +142 -44
- package/src/utils/enhancedError.ts +248 -0
- package/src/utils/streaming.ts +428 -0
- package/src/utils/validation.ts +253 -92
- 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,
|
|
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"}
|
package/dist/utils/validation.js
CHANGED
|
@@ -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
|
-
|
|
11
|
-
if (
|
|
12
|
-
throw new WordPressAPIError(
|
|
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(
|
|
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
|
|
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
|
|
111
|
+
return cleanUrl;
|
|
71
112
|
}
|
|
72
|
-
catch {
|
|
73
|
-
|
|
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(
|
|
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
|
-
|
|
141
|
-
|
|
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
|
-
|
|
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
|