mcp-wordpress 1.2.2 → 1.3.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 +210 -182
- package/dist/cache/CacheInvalidation.d.ts +3 -3
- package/dist/cache/CacheInvalidation.d.ts.map +1 -1
- package/dist/cache/CacheInvalidation.js +119 -119
- package/dist/cache/CacheInvalidation.js.map +1 -1
- package/dist/cache/CacheManager.d.ts +5 -0
- package/dist/cache/CacheManager.d.ts.map +1 -1
- package/dist/cache/CacheManager.js +26 -16
- package/dist/cache/CacheManager.js.map +1 -1
- package/dist/cache/HttpCacheWrapper.d.ts +1 -1
- package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
- package/dist/cache/HttpCacheWrapper.js +29 -29
- package/dist/cache/HttpCacheWrapper.js.map +1 -1
- package/dist/cache/__tests__/CacheInvalidation.test.js +96 -94
- package/dist/cache/__tests__/CacheInvalidation.test.js.map +1 -1
- package/dist/cache/__tests__/CacheManager.test.js +113 -113
- package/dist/cache/__tests__/CacheManager.test.js.map +1 -1
- package/dist/cache/__tests__/CachedWordPressClient.test.js +102 -99
- package/dist/cache/__tests__/CachedWordPressClient.test.js.map +1 -1
- package/dist/cache/__tests__/HttpCacheWrapper.test.js +98 -95
- package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -1
- package/dist/cache/index.d.ts +7 -7
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +4 -4
- package/dist/cache/index.js.map +1 -1
- package/dist/client/CachedWordPressClient.d.ts +4 -4
- package/dist/client/CachedWordPressClient.d.ts.map +1 -1
- package/dist/client/CachedWordPressClient.js +55 -51
- package/dist/client/CachedWordPressClient.js.map +1 -1
- package/dist/client/api.d.ts +10 -10
- package/dist/client/api.js +158 -158
- package/dist/client/api.js.map +1 -1
- package/dist/client/auth.d.ts +2 -2
- package/dist/client/auth.js +72 -72
- package/dist/client/managers/AuthenticationManager.d.ts +2 -2
- package/dist/client/managers/AuthenticationManager.js +46 -46
- package/dist/client/managers/BaseManager.d.ts +1 -1
- package/dist/client/managers/BaseManager.js +9 -9
- package/dist/client/managers/RequestManager.d.ts +5 -3
- package/dist/client/managers/RequestManager.d.ts.map +1 -1
- package/dist/client/managers/RequestManager.js +39 -19
- package/dist/client/managers/RequestManager.js.map +1 -1
- package/dist/client/managers/index.d.ts +3 -3
- package/dist/client/managers/index.js +3 -3
- package/dist/config/ConfigurationSchema.d.ts +2 -2
- package/dist/config/ConfigurationSchema.d.ts.map +1 -1
- package/dist/config/ConfigurationSchema.js +40 -40
- package/dist/config/ConfigurationSchema.js.map +1 -1
- package/dist/config/ServerConfiguration.d.ts +2 -2
- package/dist/config/ServerConfiguration.js +35 -35
- package/dist/config/ServerConfiguration.js.map +1 -1
- package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
- package/dist/docs/DocumentationGenerator.js +296 -255
- package/dist/docs/DocumentationGenerator.js.map +1 -1
- package/dist/docs/MarkdownFormatter.d.ts +1 -1
- package/dist/docs/MarkdownFormatter.d.ts.map +1 -1
- package/dist/docs/MarkdownFormatter.js +60 -51
- package/dist/docs/MarkdownFormatter.js.map +1 -1
- package/dist/docs/index.d.ts +3 -3
- package/dist/docs/index.d.ts.map +1 -1
- package/dist/docs/index.js +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/mcp-wordpress-1.3.0.tgz +0 -0
- package/dist/performance/MetricsCollector.d.ts +3 -3
- package/dist/performance/MetricsCollector.d.ts.map +1 -1
- package/dist/performance/MetricsCollector.js +33 -27
- package/dist/performance/MetricsCollector.js.map +1 -1
- package/dist/performance/PerformanceAnalytics.d.ts +12 -12
- package/dist/performance/PerformanceAnalytics.d.ts.map +1 -1
- package/dist/performance/PerformanceAnalytics.js +200 -154
- package/dist/performance/PerformanceAnalytics.js.map +1 -1
- package/dist/performance/PerformanceMonitor.d.ts +5 -5
- package/dist/performance/PerformanceMonitor.d.ts.map +1 -1
- package/dist/performance/PerformanceMonitor.js +53 -52
- package/dist/performance/PerformanceMonitor.js.map +1 -1
- package/dist/performance/index.d.ts +6 -6
- package/dist/performance/index.d.ts.map +1 -1
- package/dist/performance/index.js +3 -3
- package/dist/security/InputValidator.d.ts +1 -1
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +111 -88
- package/dist/security/InputValidator.js.map +1 -1
- package/dist/security/SecurityConfig.d.ts +5 -5
- package/dist/security/SecurityConfig.js +92 -92
- package/dist/security/SecurityConfig.js.map +1 -1
- package/dist/server/ConnectionTester.d.ts +1 -1
- package/dist/server/ConnectionTester.d.ts.map +1 -1
- package/dist/server/ConnectionTester.js +4 -4
- package/dist/server/ConnectionTester.js.map +1 -1
- package/dist/server/ToolRegistry.d.ts +2 -2
- package/dist/server/ToolRegistry.d.ts.map +1 -1
- package/dist/server/ToolRegistry.js +35 -32
- package/dist/server/ToolRegistry.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/dist/tools/BaseToolManager.js +5 -5
- package/dist/tools/auth.d.ts +2 -2
- package/dist/tools/auth.d.ts.map +1 -1
- package/dist/tools/auth.js +32 -31
- package/dist/tools/auth.js.map +1 -1
- package/dist/tools/cache.d.ts +1 -1
- package/dist/tools/cache.d.ts.map +1 -1
- package/dist/tools/cache.js +71 -71
- package/dist/tools/cache.js.map +1 -1
- package/dist/tools/comments.d.ts +2 -2
- package/dist/tools/comments.d.ts.map +1 -1
- package/dist/tools/comments.js +79 -79
- package/dist/tools/comments.js.map +1 -1
- package/dist/tools/index.d.ts +10 -10
- package/dist/tools/index.js +10 -10
- package/dist/tools/media.d.ts +2 -2
- package/dist/tools/media.js +80 -80
- package/dist/tools/pages.d.ts +2 -2
- package/dist/tools/pages.d.ts.map +1 -1
- package/dist/tools/pages.js +75 -75
- package/dist/tools/pages.js.map +1 -1
- package/dist/tools/performance.d.ts +1 -1
- package/dist/tools/performance.d.ts.map +1 -1
- package/dist/tools/performance.js +311 -287
- package/dist/tools/performance.js.map +1 -1
- package/dist/tools/posts.d.ts +2 -2
- package/dist/tools/posts.d.ts.map +1 -1
- package/dist/tools/posts.js +94 -94
- package/dist/tools/posts.js.map +1 -1
- package/dist/tools/site.d.ts +2 -2
- package/dist/tools/site.d.ts.map +1 -1
- package/dist/tools/site.js +60 -60
- package/dist/tools/site.js.map +1 -1
- package/dist/tools/taxonomies.d.ts +2 -2
- package/dist/tools/taxonomies.js +89 -89
- package/dist/tools/users.d.ts +2 -2
- package/dist/tools/users.js +68 -68
- package/dist/tools/users.js.map +1 -1
- package/dist/types/client.d.ts +13 -13
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/client.js +12 -12
- package/dist/types/client.js.map +1 -1
- package/dist/types/index.d.ts +19 -19
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -3
- package/dist/types/mcp.d.ts +7 -7
- package/dist/types/wordpress.d.ts +21 -21
- package/dist/types/wordpress.d.ts.map +1 -1
- package/dist/utils/debug.d.ts +2 -2
- package/dist/utils/debug.js +28 -28
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.js +13 -13
- package/dist/utils/error.js.map +1 -1
- package/dist/utils/toolWrapper.d.ts.map +1 -1
- package/dist/utils/toolWrapper.js +5 -5
- package/dist/utils/toolWrapper.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +41 -31
- package/dist/utils/validation.js.map +1 -1
- package/docs/CACHING.md +36 -2
- package/docs/DOCKER.md +24 -18
- package/docs/PERFORMANCE_MONITORING.md +49 -1
- package/docs/SECURITY_TESTING.md +30 -1
- package/docs/api/README.md +9 -1
- package/docs/api/summary.json +1 -1
- package/docs/contract-testing.md +24 -3
- package/docs/developer/GITHUB_ACTIONS_SETUP.md +8 -2
- package/docs/developer/MAINTENANCE.md +29 -3
- package/docs/developer/MIGRATION_GUIDE.md +13 -1
- package/docs/developer/NPM_AUTH_SETUP.md +13 -2
- package/docs/developer/REFACTORING.md +31 -1
- package/docs/releases/COMMUNITY_ANNOUNCEMENT_v1.1.2.md +18 -7
- package/docs/releases/RELEASE_NOTES_v1.1.2.md +31 -5
- package/docs/user-guides/DOCKER_SETUP.md +264 -0
- package/docs/user-guides/DTX_SETUP.md +327 -0
- package/docs/user-guides/NPM_SETUP.md +109 -0
- package/docs/user-guides/NPX_SETUP.md +281 -0
- package/docs/wordpress-rest-api-authentication-troubleshooting.md +13 -2
- package/package.json +27 -8
- package/src/cache/CacheInvalidation.ts +140 -132
- package/src/cache/CacheManager.ts +40 -29
- package/src/cache/HttpCacheWrapper.ts +105 -68
- package/src/cache/__tests__/CacheInvalidation.test.ts +123 -118
- package/src/cache/__tests__/CacheManager.test.ts +156 -152
- package/src/cache/__tests__/CachedWordPressClient.test.ts +131 -116
- package/src/cache/__tests__/HttpCacheWrapper.test.ts +118 -115
- package/src/cache/index.ts +13 -13
- package/src/client/CachedWordPressClient.ts +90 -80
- package/src/client/api.ts +205 -205
- package/src/client/auth.ts +80 -80
- package/src/client/managers/AuthenticationManager.ts +61 -61
- package/src/client/managers/BaseManager.ts +11 -11
- package/src/client/managers/RequestManager.ts +79 -47
- package/src/client/managers/index.ts +3 -3
- package/src/config/ConfigurationSchema.ts +44 -44
- package/src/config/ServerConfiguration.ts +39 -39
- package/src/docs/DocumentationGenerator.ts +402 -295
- package/src/docs/MarkdownFormatter.ts +94 -69
- package/src/docs/index.ts +4 -4
- package/src/index.ts +24 -21
- package/src/performance/MetricsCollector.ts +90 -58
- package/src/performance/PerformanceAnalytics.ts +386 -262
- package/src/performance/PerformanceMonitor.ts +152 -118
- package/src/performance/index.ts +9 -9
- package/src/security/InputValidator.ts +148 -91
- package/src/security/SecurityConfig.ts +94 -94
- package/src/server/ConnectionTester.ts +21 -15
- package/src/server/ToolRegistry.ts +64 -51
- package/src/server.ts +2 -2
- package/src/tools/BaseToolManager.ts +6 -6
- package/src/tools/auth.ts +42 -37
- package/src/tools/cache.ts +85 -81
- package/src/tools/comments.ts +93 -91
- package/src/tools/index.ts +10 -10
- package/src/tools/media.ts +89 -89
- package/src/tools/pages.ts +89 -87
- package/src/tools/performance.ts +443 -352
- package/src/tools/posts.ts +109 -107
- package/src/tools/site.ts +86 -77
- package/src/tools/taxonomies.ts +102 -102
- package/src/tools/users.ts +77 -77
- package/src/types/client.ts +157 -60
- package/src/types/index.ts +49 -27
- package/src/types/mcp.ts +15 -15
- package/src/types/wordpress.ts +57 -29
- package/src/utils/debug.ts +37 -37
- package/src/utils/error.ts +47 -25
- package/src/utils/toolWrapper.ts +12 -8
- package/src/utils/validation.ts +116 -65
- package/dist/client/WordPressClient.d.ts +0 -81
- package/dist/client/WordPressClient.d.ts.map +0 -1
- package/dist/client/WordPressClient.js +0 -354
- package/dist/client/WordPressClient.js.map +0 -1
- package/dist/performance/AnomalyDetector.d.ts +0 -63
- package/dist/performance/AnomalyDetector.d.ts.map +0 -1
- package/dist/performance/AnomalyDetector.js +0 -222
- package/dist/performance/AnomalyDetector.js.map +0 -1
- package/dist/performance/BenchmarkAnalyzer.d.ts +0 -67
- package/dist/performance/BenchmarkAnalyzer.d.ts.map +0 -1
- package/dist/performance/BenchmarkAnalyzer.js +0 -301
- package/dist/performance/BenchmarkAnalyzer.js.map +0 -1
- package/dist/performance/TrendAnalyzer.d.ts +0 -69
- package/dist/performance/TrendAnalyzer.d.ts.map +0 -1
- package/dist/performance/TrendAnalyzer.js +0 -203
- package/dist/performance/TrendAnalyzer.js.map +0 -1
- package/dist/tools/BaseToolClass.d.ts +0 -76
- package/dist/tools/BaseToolClass.d.ts.map +0 -1
- package/dist/tools/BaseToolClass.js +0 -104
- package/dist/tools/BaseToolClass.js.map +0 -1
- package/dist/tools/base.d.ts +0 -37
- package/dist/tools/base.d.ts.map +0 -1
- package/dist/tools/base.js +0 -60
- package/dist/tools/base.js.map +0 -1
- package/docs/user-guides/CLAUDE_DESKTOP_SETUP.md +0 -187
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Handles all authentication methods and token management
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { AuthConfig, AuthMethod } from
|
|
7
|
-
import { AuthenticationError } from
|
|
8
|
-
import { BaseManager } from
|
|
9
|
-
import { debug } from
|
|
6
|
+
import type { AuthConfig, AuthMethod } from "../../types/client.js";
|
|
7
|
+
import { AuthenticationError } from "../../types/client.js";
|
|
8
|
+
import { BaseManager } from "./BaseManager.js";
|
|
9
|
+
import { debug } from "../../utils/debug.js";
|
|
10
10
|
|
|
11
11
|
export class AuthenticationManager extends BaseManager {
|
|
12
12
|
private jwtToken: string | null = null;
|
|
@@ -17,44 +17,44 @@ export class AuthenticationManager extends BaseManager {
|
|
|
17
17
|
*/
|
|
18
18
|
static getAuthFromEnv(): AuthConfig {
|
|
19
19
|
const method: AuthMethod =
|
|
20
|
-
(process.env.WORDPRESS_AUTH_METHOD as AuthMethod) ||
|
|
20
|
+
(process.env.WORDPRESS_AUTH_METHOD as AuthMethod) || "app-password";
|
|
21
21
|
|
|
22
22
|
switch (method) {
|
|
23
|
-
case
|
|
23
|
+
case "app-password":
|
|
24
24
|
return {
|
|
25
|
-
method:
|
|
26
|
-
username: process.env.WORDPRESS_USERNAME ||
|
|
27
|
-
appPassword: process.env.WORDPRESS_APP_PASSWORD ||
|
|
25
|
+
method: "app-password",
|
|
26
|
+
username: process.env.WORDPRESS_USERNAME || "",
|
|
27
|
+
appPassword: process.env.WORDPRESS_APP_PASSWORD || "",
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
case
|
|
30
|
+
case "jwt":
|
|
31
31
|
return {
|
|
32
|
-
method:
|
|
33
|
-
username: process.env.WORDPRESS_USERNAME ||
|
|
32
|
+
method: "jwt",
|
|
33
|
+
username: process.env.WORDPRESS_USERNAME || "",
|
|
34
34
|
password:
|
|
35
35
|
process.env.WORDPRESS_JWT_PASSWORD ||
|
|
36
36
|
process.env.WORDPRESS_PASSWORD ||
|
|
37
|
-
|
|
38
|
-
secret: process.env.WORDPRESS_JWT_SECRET ||
|
|
37
|
+
"",
|
|
38
|
+
secret: process.env.WORDPRESS_JWT_SECRET || "",
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
case
|
|
41
|
+
case "basic":
|
|
42
42
|
return {
|
|
43
|
-
method:
|
|
44
|
-
username: process.env.WORDPRESS_USERNAME ||
|
|
45
|
-
password: process.env.WORDPRESS_PASSWORD ||
|
|
43
|
+
method: "basic",
|
|
44
|
+
username: process.env.WORDPRESS_USERNAME || "",
|
|
45
|
+
password: process.env.WORDPRESS_PASSWORD || "",
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
case
|
|
48
|
+
case "api-key":
|
|
49
49
|
return {
|
|
50
|
-
method:
|
|
51
|
-
apiKey: process.env.WORDPRESS_API_KEY ||
|
|
50
|
+
method: "api-key",
|
|
51
|
+
apiKey: process.env.WORDPRESS_API_KEY || "",
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
default:
|
|
55
55
|
throw new AuthenticationError(
|
|
56
56
|
`Unsupported authentication method: ${method}`,
|
|
57
|
-
method
|
|
57
|
+
method,
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -66,48 +66,48 @@ export class AuthenticationManager extends BaseManager {
|
|
|
66
66
|
const auth = this.config.auth;
|
|
67
67
|
|
|
68
68
|
switch (auth.method) {
|
|
69
|
-
case
|
|
69
|
+
case "app-password":
|
|
70
70
|
if (!auth.username || !auth.appPassword) {
|
|
71
71
|
throw new AuthenticationError(
|
|
72
|
-
|
|
73
|
-
auth.method
|
|
72
|
+
"Username and app password are required",
|
|
73
|
+
auth.method,
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const credentials = Buffer.from(
|
|
78
|
-
`${auth.username}:${auth.appPassword}
|
|
79
|
-
).toString(
|
|
78
|
+
`${auth.username}:${auth.appPassword}`,
|
|
79
|
+
).toString("base64");
|
|
80
80
|
return { Authorization: `Basic ${credentials}` };
|
|
81
81
|
|
|
82
|
-
case
|
|
82
|
+
case "jwt":
|
|
83
83
|
if (!this.jwtToken) {
|
|
84
84
|
await this.authenticateJWT();
|
|
85
85
|
}
|
|
86
86
|
return { Authorization: `Bearer ${this.jwtToken}` };
|
|
87
87
|
|
|
88
|
-
case
|
|
88
|
+
case "basic":
|
|
89
89
|
if (!auth.username || !auth.password) {
|
|
90
90
|
throw new AuthenticationError(
|
|
91
|
-
|
|
92
|
-
auth.method
|
|
91
|
+
"Username and password are required",
|
|
92
|
+
auth.method,
|
|
93
93
|
);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
const basicCredentials = Buffer.from(
|
|
97
|
-
`${auth.username}:${auth.password}
|
|
98
|
-
).toString(
|
|
97
|
+
`${auth.username}:${auth.password}`,
|
|
98
|
+
).toString("base64");
|
|
99
99
|
return { Authorization: `Basic ${basicCredentials}` };
|
|
100
100
|
|
|
101
|
-
case
|
|
101
|
+
case "api-key":
|
|
102
102
|
if (!auth.apiKey) {
|
|
103
|
-
throw new AuthenticationError(
|
|
103
|
+
throw new AuthenticationError("API key is required", auth.method);
|
|
104
104
|
}
|
|
105
|
-
return {
|
|
105
|
+
return { "X-API-Key": auth.apiKey };
|
|
106
106
|
|
|
107
107
|
default:
|
|
108
108
|
throw new AuthenticationError(
|
|
109
109
|
`Unsupported authentication method: ${auth.method}`,
|
|
110
|
-
auth.method
|
|
110
|
+
auth.method,
|
|
111
111
|
);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -118,10 +118,10 @@ export class AuthenticationManager extends BaseManager {
|
|
|
118
118
|
private async authenticateJWT(): Promise<void> {
|
|
119
119
|
const auth = this.config.auth;
|
|
120
120
|
|
|
121
|
-
if (auth.method !==
|
|
121
|
+
if (auth.method !== "jwt" || !auth.username || !auth.password) {
|
|
122
122
|
throw new AuthenticationError(
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
"JWT authentication requires username and password",
|
|
124
|
+
"jwt",
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -129,11 +129,11 @@ export class AuthenticationManager extends BaseManager {
|
|
|
129
129
|
// This would need the RequestManager instance to make the request
|
|
130
130
|
// For now, we'll throw an error indicating this needs to be implemented
|
|
131
131
|
throw new AuthenticationError(
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
"JWT authentication requires RequestManager integration",
|
|
133
|
+
"jwt",
|
|
134
134
|
);
|
|
135
135
|
} catch (error) {
|
|
136
|
-
this.handleError(error,
|
|
136
|
+
this.handleError(error, "JWT authentication");
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -143,8 +143,8 @@ export class AuthenticationManager extends BaseManager {
|
|
|
143
143
|
async testAuthentication(): Promise<boolean> {
|
|
144
144
|
try {
|
|
145
145
|
const _headers = await this.getAuthHeaders();
|
|
146
|
-
debug.log(
|
|
147
|
-
method: this.config.auth.method
|
|
146
|
+
debug.log("Authentication headers prepared", {
|
|
147
|
+
method: this.config.auth.method,
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
// This would need the RequestManager to actually test the connection
|
|
@@ -153,7 +153,7 @@ export class AuthenticationManager extends BaseManager {
|
|
|
153
153
|
return true;
|
|
154
154
|
} catch (error) {
|
|
155
155
|
this.authenticated = false;
|
|
156
|
-
debug.log(
|
|
156
|
+
debug.log("Authentication test failed", error);
|
|
157
157
|
return false;
|
|
158
158
|
}
|
|
159
159
|
}
|
|
@@ -181,44 +181,44 @@ export class AuthenticationManager extends BaseManager {
|
|
|
181
181
|
|
|
182
182
|
if (!auth.method) {
|
|
183
183
|
throw new AuthenticationError(
|
|
184
|
-
|
|
185
|
-
|
|
184
|
+
"Authentication method is required",
|
|
185
|
+
"app-password",
|
|
186
186
|
);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
switch (auth.method) {
|
|
190
|
-
case
|
|
190
|
+
case "app-password":
|
|
191
191
|
if (!auth.username || !auth.appPassword) {
|
|
192
192
|
throw new AuthenticationError(
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
"App password authentication requires username and appPassword",
|
|
194
|
+
"app-password",
|
|
195
195
|
);
|
|
196
196
|
}
|
|
197
197
|
break;
|
|
198
198
|
|
|
199
|
-
case
|
|
199
|
+
case "jwt":
|
|
200
200
|
if (!auth.username || !auth.password || !auth.secret) {
|
|
201
201
|
throw new AuthenticationError(
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
"JWT authentication requires username, password, and secret",
|
|
203
|
+
"jwt",
|
|
204
204
|
);
|
|
205
205
|
}
|
|
206
206
|
break;
|
|
207
207
|
|
|
208
|
-
case
|
|
208
|
+
case "basic":
|
|
209
209
|
if (!auth.username || !auth.password) {
|
|
210
210
|
throw new AuthenticationError(
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
"Basic authentication requires username and password",
|
|
212
|
+
"basic",
|
|
213
213
|
);
|
|
214
214
|
}
|
|
215
215
|
break;
|
|
216
216
|
|
|
217
|
-
case
|
|
217
|
+
case "api-key":
|
|
218
218
|
if (!auth.apiKey) {
|
|
219
219
|
throw new AuthenticationError(
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
"API key authentication requires apiKey",
|
|
221
|
+
"api-key",
|
|
222
222
|
);
|
|
223
223
|
}
|
|
224
224
|
break;
|
|
@@ -226,7 +226,7 @@ export class AuthenticationManager extends BaseManager {
|
|
|
226
226
|
default:
|
|
227
227
|
throw new AuthenticationError(
|
|
228
228
|
`Unsupported authentication method: ${auth.method}`,
|
|
229
|
-
auth.method
|
|
229
|
+
auth.method,
|
|
230
230
|
);
|
|
231
231
|
}
|
|
232
232
|
}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Provides common functionality and error handling
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { WordPressClientConfig } from
|
|
7
|
-
import { WordPressAPIError } from
|
|
8
|
-
import { debug, logError } from
|
|
9
|
-
import { getErrorMessage } from
|
|
6
|
+
import type { WordPressClientConfig } from "../../types/client.js";
|
|
7
|
+
import { WordPressAPIError } from "../../types/client.js";
|
|
8
|
+
import { debug, logError } from "../../utils/debug.js";
|
|
9
|
+
import { getErrorMessage } from "../../utils/error.js";
|
|
10
10
|
|
|
11
11
|
export abstract class BaseManager {
|
|
12
12
|
protected config: WordPressClientConfig;
|
|
@@ -25,19 +25,19 @@ export abstract class BaseManager {
|
|
|
25
25
|
throw error;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
if (error.name ===
|
|
28
|
+
if (error.name === "AbortError" || error.code === "ABORT_ERR") {
|
|
29
29
|
throw new WordPressAPIError(
|
|
30
30
|
`Request timeout after ${this.config.timeout}ms`,
|
|
31
31
|
408,
|
|
32
|
-
|
|
32
|
+
"timeout",
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
if (error.code ===
|
|
36
|
+
if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND") {
|
|
37
37
|
throw new WordPressAPIError(
|
|
38
38
|
`Cannot connect to WordPress site: ${this.config.baseUrl}`,
|
|
39
39
|
503,
|
|
40
|
-
|
|
40
|
+
"connection_failed",
|
|
41
41
|
);
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -45,7 +45,7 @@ export abstract class BaseManager {
|
|
|
45
45
|
throw new WordPressAPIError(
|
|
46
46
|
`${operation} failed: ${message}`,
|
|
47
47
|
500,
|
|
48
|
-
|
|
48
|
+
"unknown_error",
|
|
49
49
|
);
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -61,14 +61,14 @@ export abstract class BaseManager {
|
|
|
61
61
|
*/
|
|
62
62
|
protected validateRequired(
|
|
63
63
|
params: Record<string, any>,
|
|
64
|
-
requiredFields: string[]
|
|
64
|
+
requiredFields: string[],
|
|
65
65
|
): void {
|
|
66
66
|
for (const field of requiredFields) {
|
|
67
67
|
if (params[field] === undefined || params[field] === null) {
|
|
68
68
|
throw new WordPressAPIError(
|
|
69
69
|
`Missing required parameter: ${field}`,
|
|
70
70
|
400,
|
|
71
|
-
|
|
71
|
+
"missing_parameter",
|
|
72
72
|
);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -3,33 +3,39 @@
|
|
|
3
3
|
* Handles all HTTP operations, rate limiting, and retries
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import fetch from
|
|
7
|
-
import type {
|
|
8
|
-
HTTPMethod,
|
|
9
|
-
RequestOptions,
|
|
6
|
+
import fetch from "node-fetch";
|
|
7
|
+
import type {
|
|
8
|
+
HTTPMethod,
|
|
9
|
+
RequestOptions,
|
|
10
10
|
ClientStats,
|
|
11
|
-
WordPressClientConfig
|
|
12
|
-
} from
|
|
13
|
-
import { WordPressAPIError, RateLimitError } from
|
|
14
|
-
import { BaseManager } from
|
|
15
|
-
import {
|
|
11
|
+
WordPressClientConfig,
|
|
12
|
+
} from "../../types/client.js";
|
|
13
|
+
import { WordPressAPIError, RateLimitError } from "../../types/client.js";
|
|
14
|
+
import { BaseManager } from "./BaseManager.js";
|
|
15
|
+
import { AuthenticationManager } from "./AuthenticationManager.js";
|
|
16
|
+
import { debug, startTimer } from "../../utils/debug.js";
|
|
16
17
|
|
|
17
18
|
export class RequestManager extends BaseManager {
|
|
18
19
|
private stats: ClientStats;
|
|
19
20
|
private lastRequestTime: number = 0;
|
|
20
21
|
private requestInterval: number;
|
|
22
|
+
private authManager: AuthenticationManager;
|
|
21
23
|
|
|
22
|
-
constructor(
|
|
24
|
+
constructor(
|
|
25
|
+
config: WordPressClientConfig,
|
|
26
|
+
authManager: AuthenticationManager,
|
|
27
|
+
) {
|
|
23
28
|
super(config);
|
|
24
|
-
|
|
25
|
-
this.
|
|
29
|
+
|
|
30
|
+
this.authManager = authManager;
|
|
31
|
+
this.requestInterval = 60000 / parseInt(process.env.RATE_LIMIT || "60");
|
|
26
32
|
this.stats = {
|
|
27
33
|
totalRequests: 0,
|
|
28
34
|
successfulRequests: 0,
|
|
29
35
|
failedRequests: 0,
|
|
30
36
|
averageResponseTime: 0,
|
|
31
37
|
rateLimitHits: 0,
|
|
32
|
-
authFailures: 0
|
|
38
|
+
authFailures: 0,
|
|
33
39
|
};
|
|
34
40
|
}
|
|
35
41
|
|
|
@@ -40,18 +46,23 @@ export class RequestManager extends BaseManager {
|
|
|
40
46
|
method: HTTPMethod,
|
|
41
47
|
endpoint: string,
|
|
42
48
|
data?: any,
|
|
43
|
-
options: RequestOptions = {}
|
|
49
|
+
options: RequestOptions = {},
|
|
44
50
|
): Promise<T> {
|
|
45
51
|
const timer = startTimer();
|
|
46
|
-
|
|
52
|
+
|
|
47
53
|
try {
|
|
48
54
|
await this.enforceRateLimit();
|
|
49
|
-
|
|
50
|
-
const response = await this.makeRequestWithRetry(
|
|
51
|
-
|
|
55
|
+
|
|
56
|
+
const response = await this.makeRequestWithRetry(
|
|
57
|
+
method,
|
|
58
|
+
endpoint,
|
|
59
|
+
data,
|
|
60
|
+
options,
|
|
61
|
+
);
|
|
62
|
+
|
|
52
63
|
this.stats.successfulRequests++;
|
|
53
64
|
this.updateAverageResponseTime(timer.end());
|
|
54
|
-
|
|
65
|
+
|
|
55
66
|
return response as T;
|
|
56
67
|
} catch (error) {
|
|
57
68
|
this.stats.failedRequests++;
|
|
@@ -68,7 +79,7 @@ export class RequestManager extends BaseManager {
|
|
|
68
79
|
method: HTTPMethod,
|
|
69
80
|
endpoint: string,
|
|
70
81
|
data?: any,
|
|
71
|
-
options: RequestOptions = {}
|
|
82
|
+
options: RequestOptions = {},
|
|
72
83
|
): Promise<T> {
|
|
73
84
|
let lastError: any;
|
|
74
85
|
const maxRetries = options.retries ?? this.config.maxRetries ?? 3;
|
|
@@ -78,17 +89,20 @@ export class RequestManager extends BaseManager {
|
|
|
78
89
|
return await this.makeRequest<T>(method, endpoint, data, options);
|
|
79
90
|
} catch (error: any) {
|
|
80
91
|
lastError = error;
|
|
81
|
-
|
|
92
|
+
|
|
82
93
|
// Don't retry on authentication errors or client errors
|
|
83
94
|
if (error.statusCode < 500 || attempt === maxRetries) {
|
|
84
95
|
throw error;
|
|
85
96
|
}
|
|
86
97
|
|
|
87
|
-
debug.log(
|
|
88
|
-
|
|
98
|
+
debug.log(
|
|
99
|
+
`Request failed (attempt ${attempt}/${maxRetries}):`,
|
|
100
|
+
error.message,
|
|
101
|
+
);
|
|
102
|
+
|
|
89
103
|
// Exponential backoff
|
|
90
104
|
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
|
|
91
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
105
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
92
106
|
}
|
|
93
107
|
}
|
|
94
108
|
|
|
@@ -102,40 +116,57 @@ export class RequestManager extends BaseManager {
|
|
|
102
116
|
method: HTTPMethod,
|
|
103
117
|
endpoint: string,
|
|
104
118
|
data?: any,
|
|
105
|
-
options: RequestOptions = {}
|
|
119
|
+
options: RequestOptions = {},
|
|
106
120
|
): Promise<T> {
|
|
107
121
|
const url = this.buildUrl(endpoint);
|
|
108
122
|
const timeout = options.timeout ?? this.config.timeout ?? 30000;
|
|
109
|
-
|
|
123
|
+
|
|
110
124
|
const controller = new AbortController();
|
|
111
125
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
112
126
|
|
|
113
127
|
try {
|
|
128
|
+
// Get authentication headers
|
|
129
|
+
const authHeaders = await this.authManager.getAuthHeaders();
|
|
130
|
+
|
|
114
131
|
const fetchOptions: any = {
|
|
115
132
|
method,
|
|
116
133
|
headers: {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
...
|
|
134
|
+
"Content-Type": "application/json",
|
|
135
|
+
"User-Agent": "MCP-WordPress/1.1.1",
|
|
136
|
+
...authHeaders, // Add auth headers before custom headers
|
|
137
|
+
...options.headers,
|
|
120
138
|
},
|
|
121
|
-
signal: controller.signal
|
|
139
|
+
signal: controller.signal,
|
|
122
140
|
};
|
|
123
141
|
|
|
124
|
-
if (data && method !==
|
|
125
|
-
|
|
142
|
+
if (data && method !== "GET") {
|
|
143
|
+
if (
|
|
144
|
+
data instanceof FormData ||
|
|
145
|
+
(data && typeof data.append === "function")
|
|
146
|
+
) {
|
|
147
|
+
// For FormData, don't set Content-Type (let fetch set it with boundary)
|
|
148
|
+
delete fetchOptions.headers["Content-Type"];
|
|
149
|
+
fetchOptions.body = data;
|
|
150
|
+
} else if (Buffer.isBuffer(data)) {
|
|
151
|
+
// For Buffer data, keep Content-Type from headers
|
|
152
|
+
fetchOptions.body = data;
|
|
153
|
+
} else if (typeof data === "string") {
|
|
154
|
+
fetchOptions.body = data;
|
|
155
|
+
} else {
|
|
156
|
+
fetchOptions.body = JSON.stringify(data);
|
|
157
|
+
}
|
|
126
158
|
}
|
|
127
159
|
|
|
128
160
|
debug.log(`API Request: ${method} ${url}`);
|
|
129
|
-
|
|
161
|
+
|
|
130
162
|
const response = await fetch(url, fetchOptions);
|
|
131
|
-
|
|
163
|
+
|
|
132
164
|
if (!response.ok) {
|
|
133
165
|
await this.handleErrorResponse(response);
|
|
134
166
|
}
|
|
135
167
|
|
|
136
168
|
const responseData = await response.json();
|
|
137
169
|
return responseData as T;
|
|
138
|
-
|
|
139
170
|
} finally {
|
|
140
171
|
clearTimeout(timeoutId);
|
|
141
172
|
}
|
|
@@ -146,15 +177,16 @@ export class RequestManager extends BaseManager {
|
|
|
146
177
|
*/
|
|
147
178
|
private async handleErrorResponse(response: any): Promise<never> {
|
|
148
179
|
let errorData: any = {};
|
|
149
|
-
|
|
180
|
+
|
|
150
181
|
try {
|
|
151
182
|
errorData = await response.json();
|
|
152
183
|
} catch {
|
|
153
184
|
// Ignore JSON parsing errors
|
|
154
185
|
}
|
|
155
186
|
|
|
156
|
-
const message =
|
|
157
|
-
|
|
187
|
+
const message =
|
|
188
|
+
errorData.message || `HTTP ${response.status}: ${response.statusText}`;
|
|
189
|
+
const code = errorData.code || "http_error";
|
|
158
190
|
|
|
159
191
|
if (response.status === 429) {
|
|
160
192
|
this.stats.rateLimitHits++;
|
|
@@ -172,10 +204,10 @@ export class RequestManager extends BaseManager {
|
|
|
172
204
|
* Build full URL from endpoint
|
|
173
205
|
*/
|
|
174
206
|
private buildUrl(endpoint: string): string {
|
|
175
|
-
const baseUrl = this.config.baseUrl.replace(/\/$/,
|
|
176
|
-
const apiBase =
|
|
177
|
-
const cleanEndpoint = endpoint.startsWith(
|
|
178
|
-
|
|
207
|
+
const baseUrl = this.config.baseUrl.replace(/\/$/, "");
|
|
208
|
+
const apiBase = "/wp-json/wp/v2";
|
|
209
|
+
const cleanEndpoint = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
210
|
+
|
|
179
211
|
return `${baseUrl}${apiBase}${cleanEndpoint}`;
|
|
180
212
|
}
|
|
181
213
|
|
|
@@ -185,12 +217,12 @@ export class RequestManager extends BaseManager {
|
|
|
185
217
|
private async enforceRateLimit(): Promise<void> {
|
|
186
218
|
const now = Date.now();
|
|
187
219
|
const timeSinceLastRequest = now - this.lastRequestTime;
|
|
188
|
-
|
|
220
|
+
|
|
189
221
|
if (timeSinceLastRequest < this.requestInterval) {
|
|
190
222
|
const delay = this.requestInterval - timeSinceLastRequest;
|
|
191
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
223
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
192
224
|
}
|
|
193
|
-
|
|
225
|
+
|
|
194
226
|
this.lastRequestTime = Date.now();
|
|
195
227
|
}
|
|
196
228
|
|
|
@@ -200,8 +232,8 @@ export class RequestManager extends BaseManager {
|
|
|
200
232
|
private updateAverageResponseTime(responseTime: number): void {
|
|
201
233
|
const totalRequests = this.stats.successfulRequests;
|
|
202
234
|
const currentAverage = this.stats.averageResponseTime;
|
|
203
|
-
|
|
204
|
-
this.stats.averageResponseTime =
|
|
235
|
+
|
|
236
|
+
this.stats.averageResponseTime =
|
|
205
237
|
(currentAverage * (totalRequests - 1) + responseTime) / totalRequests;
|
|
206
238
|
}
|
|
207
239
|
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* Exports all manager classes for the WordPress client
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export { BaseManager } from
|
|
7
|
-
export { AuthenticationManager } from
|
|
8
|
-
export { RequestManager } from
|
|
6
|
+
export { BaseManager } from "./BaseManager.js";
|
|
7
|
+
export { AuthenticationManager } from "./AuthenticationManager.js";
|
|
8
|
+
export { RequestManager } from "./RequestManager.js";
|