mcp-wordpress 2.4.2 → 2.5.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 +114 -48
- package/dist/ajv-patch.js +34 -0
- package/dist/cache/CacheInvalidation.d.ts +3 -1
- package/dist/cache/CacheInvalidation.d.ts.map +1 -1
- package/dist/cache/CacheInvalidation.js +10 -4
- package/dist/cache/CacheInvalidation.js.map +1 -1
- package/dist/cache/CacheManager.d.ts +3 -2
- package/dist/cache/CacheManager.d.ts.map +1 -1
- package/dist/cache/CacheManager.js +11 -3
- package/dist/cache/CacheManager.js.map +1 -1
- package/dist/cache/HttpCacheWrapper.d.ts +7 -6
- package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
- package/dist/cache/HttpCacheWrapper.js +8 -5
- package/dist/cache/HttpCacheWrapper.js.map +1 -1
- package/dist/cache/__tests__/HttpCacheWrapper.test.js +6 -5
- package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -1
- package/dist/cache/index.d.ts +3 -3
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/client/CachedWordPressClient.d.ts +23 -9
- package/dist/client/CachedWordPressClient.d.ts.map +1 -1
- package/dist/client/CachedWordPressClient.js +4 -1
- package/dist/client/CachedWordPressClient.js.map +1 -1
- package/dist/client/MockWordPressClient.d.ts +2 -1
- package/dist/client/MockWordPressClient.d.ts.map +1 -1
- package/dist/client/MockWordPressClient.js +3 -1
- package/dist/client/MockWordPressClient.js.map +1 -1
- package/dist/client/api.d.ts +17 -13
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +135 -30
- package/dist/client/api.js.map +1 -1
- package/dist/client/auth.d.ts.map +1 -1
- package/dist/client/auth.js +2 -3
- package/dist/client/auth.js.map +1 -1
- package/dist/client/managers/AuthenticationManager.d.ts +55 -2
- package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
- package/dist/client/managers/AuthenticationManager.js +269 -71
- package/dist/client/managers/AuthenticationManager.js.map +1 -1
- package/dist/client/managers/BaseManager.d.ts +3 -3
- package/dist/client/managers/BaseManager.d.ts.map +1 -1
- package/dist/client/managers/BaseManager.js +11 -5
- package/dist/client/managers/BaseManager.js.map +1 -1
- package/dist/client/managers/RequestManager.d.ts +2 -2
- package/dist/client/managers/RequestManager.d.ts.map +1 -1
- package/dist/client/managers/RequestManager.js +25 -12
- package/dist/client/managers/RequestManager.js.map +1 -1
- package/dist/config/Config.d.ts +155 -0
- package/dist/config/Config.d.ts.map +1 -0
- package/dist/config/Config.js +215 -0
- package/dist/config/Config.js.map +1 -0
- package/dist/config/ConfigurationSchema.d.ts +21 -21
- package/dist/config/ConfigurationSchema.d.ts.map +1 -1
- package/dist/config/ConfigurationSchema.js +19 -2
- package/dist/config/ConfigurationSchema.js.map +1 -1
- package/dist/config/ServerConfiguration.d.ts +2 -1
- package/dist/config/ServerConfiguration.d.ts.map +1 -1
- package/dist/config/ServerConfiguration.js +50 -41
- package/dist/config/ServerConfiguration.js.map +1 -1
- package/dist/docs/DocumentationGenerator.d.ts +9 -8
- package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
- package/dist/docs/DocumentationGenerator.js +10 -7
- package/dist/docs/DocumentationGenerator.js.map +1 -1
- package/dist/docs/MarkdownFormatter.d.ts.map +1 -1
- package/dist/docs/MarkdownFormatter.js +3 -2
- package/dist/docs/MarkdownFormatter.js.map +1 -1
- package/dist/dxt-entry.cjs +81 -0
- package/dist/dxt-entry.js +15 -14
- package/dist/dxt-entry.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -21
- package/dist/index.js.map +1 -1
- package/dist/performance/MetricsCollector.d.ts +13 -7
- package/dist/performance/MetricsCollector.d.ts.map +1 -1
- package/dist/performance/MetricsCollector.js +69 -27
- package/dist/performance/MetricsCollector.js.map +1 -1
- package/dist/performance/PerformanceAnalytics.d.ts +8 -2
- package/dist/performance/PerformanceAnalytics.d.ts.map +1 -1
- package/dist/performance/PerformanceAnalytics.js +17 -47
- package/dist/performance/PerformanceAnalytics.js.map +1 -1
- package/dist/performance/PerformanceMonitor.d.ts +2 -1
- package/dist/performance/PerformanceMonitor.d.ts.map +1 -1
- package/dist/performance/PerformanceMonitor.js +12 -13
- package/dist/performance/PerformanceMonitor.js.map +1 -1
- package/dist/performance/index.d.ts +2 -2
- package/dist/performance/index.d.ts.map +1 -1
- package/dist/security/AISecurityScanner.d.ts +1 -0
- package/dist/security/AISecurityScanner.d.ts.map +1 -1
- package/dist/security/AISecurityScanner.js +22 -12
- package/dist/security/AISecurityScanner.js.map +1 -1
- package/dist/security/AutomatedRemediation.d.ts +4 -3
- package/dist/security/AutomatedRemediation.d.ts.map +1 -1
- package/dist/security/AutomatedRemediation.js +46 -15
- package/dist/security/AutomatedRemediation.js.map +1 -1
- package/dist/security/InputValidator.d.ts +13 -9
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +4 -2
- package/dist/security/InputValidator.js.map +1 -1
- package/dist/security/SecurityCIPipeline.d.ts +1 -1
- package/dist/security/SecurityCIPipeline.d.ts.map +1 -1
- package/dist/security/SecurityCIPipeline.js +38 -29
- package/dist/security/SecurityCIPipeline.js.map +1 -1
- package/dist/security/SecurityConfig.d.ts +3 -3
- package/dist/security/SecurityConfig.d.ts.map +1 -1
- package/dist/security/SecurityConfig.js +13 -9
- package/dist/security/SecurityConfig.js.map +1 -1
- package/dist/security/SecurityConfigManager.d.ts +2 -2
- package/dist/security/SecurityConfigManager.d.ts.map +1 -1
- package/dist/security/SecurityConfigManager.js +20 -15
- package/dist/security/SecurityConfigManager.js.map +1 -1
- package/dist/security/SecurityMonitoring.d.ts +2 -2
- package/dist/security/SecurityMonitoring.d.ts.map +1 -1
- package/dist/security/SecurityMonitoring.js +19 -17
- package/dist/security/SecurityMonitoring.js.map +1 -1
- package/dist/security/SecurityReviewer.d.ts.map +1 -1
- package/dist/security/SecurityReviewer.js +10 -7
- package/dist/security/SecurityReviewer.js.map +1 -1
- package/dist/security/index.d.ts +24 -23
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +52 -23
- package/dist/security/index.js.map +1 -1
- package/dist/server/ConnectionTester.d.ts +12 -4
- package/dist/server/ConnectionTester.d.ts.map +1 -1
- package/dist/server/ConnectionTester.js +96 -22
- 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 +10 -5
- package/dist/server/ToolRegistry.js.map +1 -1
- package/dist/tools/BaseToolManager.d.ts +47 -11
- package/dist/tools/BaseToolManager.d.ts.map +1 -1
- package/dist/tools/BaseToolManager.js +168 -29
- package/dist/tools/BaseToolManager.js.map +1 -1
- package/dist/tools/auth.d.ts +16 -10
- package/dist/tools/auth.d.ts.map +1 -1
- package/dist/tools/auth.js +3 -2
- package/dist/tools/auth.js.map +1 -1
- package/dist/tools/cache.d.ts +30 -30
- package/dist/tools/cache.d.ts.map +1 -1
- package/dist/tools/cache.js +1 -6
- package/dist/tools/cache.js.map +1 -1
- package/dist/tools/comments.d.ts +20 -20
- package/dist/tools/comments.d.ts.map +1 -1
- package/dist/tools/comments.js +16 -9
- package/dist/tools/comments.js.map +1 -1
- package/dist/tools/media.d.ts +18 -16
- package/dist/tools/media.d.ts.map +1 -1
- package/dist/tools/media.js +16 -15
- package/dist/tools/media.js.map +1 -1
- package/dist/tools/pages.d.ts +19 -17
- package/dist/tools/pages.d.ts.map +1 -1
- package/dist/tools/pages.js +16 -12
- package/dist/tools/pages.js.map +1 -1
- package/dist/tools/performance.d.ts +11 -1
- package/dist/tools/performance.d.ts.map +1 -1
- package/dist/tools/performance.js +67 -34
- package/dist/tools/performance.js.map +1 -1
- package/dist/tools/posts/PostHandlers.d.ts +46 -0
- package/dist/tools/posts/PostHandlers.d.ts.map +1 -0
- package/dist/tools/posts/PostHandlers.js +400 -0
- package/dist/tools/posts/PostHandlers.js.map +1 -0
- package/dist/tools/posts/PostToolDefinitions.d.ts +37 -0
- package/dist/tools/posts/PostToolDefinitions.d.ts.map +1 -0
- package/dist/tools/posts/PostToolDefinitions.js +236 -0
- package/dist/tools/posts/PostToolDefinitions.js.map +1 -0
- package/dist/tools/posts/index.d.ts +138 -0
- package/dist/tools/posts/index.d.ts.map +1 -0
- package/dist/tools/posts/index.js +163 -0
- package/dist/tools/posts/index.js.map +1 -0
- package/dist/tools/posts.d.ts +10 -246
- package/dist/tools/posts.d.ts.map +1 -1
- package/dist/tools/posts.js +11 -723
- package/dist/tools/posts.js.map +1 -1
- package/dist/tools/site.d.ts +19 -18
- package/dist/tools/site.d.ts.map +1 -1
- package/dist/tools/site.js +14 -10
- package/dist/tools/site.js.map +1 -1
- package/dist/tools/taxonomies.d.ts +23 -24
- package/dist/tools/taxonomies.d.ts.map +1 -1
- package/dist/tools/taxonomies.js +24 -18
- package/dist/tools/taxonomies.js.map +1 -1
- package/dist/tools/users.d.ts +20 -15
- package/dist/tools/users.d.ts.map +1 -1
- package/dist/tools/users.js +12 -8
- package/dist/tools/users.js.map +1 -1
- package/dist/types/client.d.ts +48 -41
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/client.js +30 -5
- package/dist/types/client.js.map +1 -1
- package/dist/types/enhanced.d.ts +237 -0
- package/dist/types/enhanced.d.ts.map +1 -0
- package/dist/types/enhanced.js +49 -0
- package/dist/types/enhanced.js.map +1 -0
- package/dist/types/index.d.ts +15 -12
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/mcp.d.ts +12 -12
- package/dist/types/mcp.d.ts.map +1 -1
- package/dist/types/requests.d.ts +322 -0
- package/dist/types/requests.d.ts.map +1 -0
- package/dist/types/requests.js +8 -0
- package/dist/types/requests.js.map +1 -0
- package/dist/types/tools.d.ts +506 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +8 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/types/wordpress.d.ts +43 -15
- package/dist/types/wordpress.d.ts.map +1 -1
- package/dist/types/wordpress.js +8 -1
- package/dist/types/wordpress.js.map +1 -1
- package/dist/utils/debug.d.ts +19 -11
- package/dist/utils/debug.d.ts.map +1 -1
- package/dist/utils/debug.js +46 -10
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/enhancedError.d.ts +8 -8
- package/dist/utils/enhancedError.d.ts.map +1 -1
- package/dist/utils/enhancedError.js.map +1 -1
- package/dist/utils/error.d.ts +2 -4
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.js +42 -5
- package/dist/utils/error.js.map +1 -1
- package/dist/utils/logger.d.ts +106 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +280 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/streaming.d.ts +9 -9
- package/dist/utils/streaming.d.ts.map +1 -1
- package/dist/utils/streaming.js +71 -52
- package/dist/utils/streaming.js.map +1 -1
- package/dist/utils/toolWrapper.d.ts +9 -7
- package/dist/utils/toolWrapper.d.ts.map +1 -1
- package/dist/utils/toolWrapper.js.map +1 -1
- package/dist/utils/validation/core.d.ts +21 -0
- package/dist/utils/validation/core.d.ts.map +1 -0
- package/dist/utils/validation/core.js +71 -0
- package/dist/utils/validation/core.js.map +1 -0
- package/dist/utils/validation/index.d.ts +25 -0
- package/dist/utils/validation/index.d.ts.map +1 -0
- package/dist/utils/validation/index.js +29 -0
- package/dist/utils/validation/index.js.map +1 -0
- package/dist/utils/validation/network.d.ts +19 -0
- package/dist/utils/validation/network.d.ts.map +1 -0
- package/dist/utils/validation/network.js +93 -0
- package/dist/utils/validation/network.js.map +1 -0
- package/dist/utils/validation/rateLimit.d.ts +21 -0
- package/dist/utils/validation/rateLimit.d.ts.map +1 -0
- package/dist/utils/validation/rateLimit.js +43 -0
- package/dist/utils/validation/rateLimit.js.map +1 -0
- package/dist/utils/validation/security.d.ts +29 -0
- package/dist/utils/validation/security.d.ts.map +1 -0
- package/dist/utils/validation/security.js +327 -0
- package/dist/utils/validation/security.js.map +1 -0
- package/dist/utils/validation/wordpress.d.ts +31 -0
- package/dist/utils/validation/wordpress.d.ts.map +1 -0
- package/dist/utils/validation/wordpress.js +146 -0
- package/dist/utils/validation/wordpress.js.map +1 -0
- package/dist/utils/validation.d.ts +13 -82
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +25 -343
- package/dist/utils/validation.js.map +1 -1
- package/docs/BADGE_UPDATES.md +132 -0
- package/docs/CI_CD_IMPROVEMENTS.md +191 -0
- package/docs/INCREMENTAL_COVERAGE.md +183 -0
- package/docs/api/README.md +3 -1
- package/docs/api/openapi.json +5 -1
- package/docs/api/summary.json +1 -1
- package/docs/api/tools/wp_create_post.md +12 -14
- package/docs/examples/claude-desktop-config.md +1 -1
- package/docs/examples/docker-production.md +100 -93
- package/docs/examples/multi-site-setup.md +5 -4
- package/docs/examples/single-site-setup.md +3 -4
- package/docs/examples/use-case-workflows.md +4 -5
- package/docs/integrations/claude-desktop.md +31 -31
- package/docs/integrations/cline.md +4 -4
- package/docs/integrations/vs-code.md +9 -8
- package/docs/user-guides/SMITHERY_SETUP.md +10 -10
- package/package.json +44 -25
- package/src/cache/CacheInvalidation.ts +12 -5
- package/src/cache/CacheManager.ts +18 -15
- package/src/cache/HttpCacheWrapper.ts +30 -59
- package/src/cache/__tests__/HttpCacheWrapper.test.ts +6 -5
- package/src/cache/index.ts +3 -14
- package/src/client/CachedWordPressClient.ts +32 -30
- package/src/client/MockWordPressClient.ts +4 -2
- package/src/client/api.ts +186 -64
- package/src/client/auth.ts +15 -40
- package/src/client/managers/AuthenticationManager.ts +337 -77
- package/src/client/managers/BaseManager.ts +18 -30
- package/src/client/managers/RequestManager.ts +39 -44
- package/src/config/Config.ts +308 -0
- package/src/config/ConfigurationSchema.ts +23 -2
- package/src/config/ServerConfiguration.ts +51 -47
- package/src/docs/DocumentationGenerator.ts +50 -39
- package/src/docs/MarkdownFormatter.ts +19 -29
- package/src/dxt-entry.cjs +26 -16
- package/src/dxt-entry.ts +17 -27
- package/src/index.ts +42 -28
- package/src/performance/MetricsCollector.ts +108 -86
- package/src/performance/PerformanceAnalytics.ts +69 -164
- package/src/performance/PerformanceMonitor.ts +32 -47
- package/src/performance/index.ts +2 -10
- package/src/security/AISecurityScanner.ts +22 -12
- package/src/security/AutomatedRemediation.ts +49 -18
- package/src/security/InputValidator.ts +9 -6
- package/src/security/SecurityCIPipeline.ts +53 -37
- package/src/security/SecurityConfig.ts +22 -22
- package/src/security/SecurityConfigManager.ts +23 -19
- package/src/security/SecurityMonitoring.ts +24 -21
- package/src/security/SecurityReviewer.ts +10 -7
- package/src/security/index.ts +64 -29
- package/src/server/ConnectionTester.ts +120 -31
- package/src/server/ToolRegistry.ts +31 -21
- package/src/tools/BaseToolManager.ts +286 -33
- package/src/tools/auth.ts +20 -8
- package/src/tools/cache.ts +5 -15
- package/src/tools/comments.ts +34 -48
- package/src/tools/media.ts +41 -53
- package/src/tools/pages.ts +32 -54
- package/src/tools/performance.ts +141 -176
- package/src/tools/posts/PostHandlers.ts +474 -0
- package/src/tools/posts/PostToolDefinitions.ts +250 -0
- package/src/tools/posts/index.ts +192 -0
- package/src/tools/posts.ts +24 -780
- package/src/tools/site.ts +34 -19
- package/src/tools/taxonomies.ts +41 -57
- package/src/tools/users.ts +28 -16
- package/src/types/client.ts +114 -138
- package/src/types/enhanced.ts +318 -0
- package/src/types/index.ts +51 -30
- package/src/types/mcp.ts +20 -42
- package/src/types/requests.ts +378 -0
- package/src/types/tools.ts +608 -0
- package/src/types/wordpress.ts +56 -34
- package/src/utils/debug.ts +77 -59
- package/src/utils/enhancedError.ts +8 -8
- package/src/utils/error.ts +53 -31
- package/src/utils/logger.ts +351 -0
- package/src/utils/streaming.ts +86 -68
- package/src/utils/toolWrapper.ts +10 -12
- package/src/utils/validation/core.ts +108 -0
- package/src/utils/validation/index.ts +36 -0
- package/src/utils/validation/network.ts +132 -0
- package/src/utils/validation/rateLimit.ts +54 -0
- package/src/utils/validation/security.ts +361 -0
- package/src/utils/validation/wordpress.ts +180 -0
- package/src/utils/validation.ts +47 -470
package/src/utils/error.ts
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Error handling utilities
|
|
3
3
|
*/
|
|
4
|
+
import { LoggerFactory } from "./logger.js";
|
|
5
|
+
import { config } from "../config/Config.js";
|
|
6
|
+
|
|
7
|
+
const logger = LoggerFactory.server().child({ component: "ErrorUtils" });
|
|
8
|
+
|
|
9
|
+
// Environment flag to control legacy console logging noise. Default enabled to preserve
|
|
10
|
+
// backward compatibility and existing test expectations. Set LEGACY_ERROR_LOGS=0 to disable
|
|
11
|
+
// the direct console.error side-channel (structured logger still emits).
|
|
12
|
+
const LEGACY_ERROR_LOGS_ENABLED = config().error.legacyLogsEnabled;
|
|
13
|
+
|
|
14
|
+
// Internal helper to avoid sprinkling conditionals
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
function legacyConsoleError(...args: any[]) {
|
|
17
|
+
if (LEGACY_ERROR_LOGS_ENABLED) {
|
|
18
|
+
console.error(...args);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Test hook: exported only for instrumentation in unit tests (tree-shakeable)
|
|
23
|
+
// @__PURE__ This constant has no side effects and can be dropped in production builds
|
|
24
|
+
export const __errorUtilsLogger = logger;
|
|
4
25
|
|
|
5
26
|
export function getErrorMessage(error: unknown): string {
|
|
6
27
|
if (error instanceof Error) {
|
|
@@ -23,25 +44,34 @@ export function isError(error: unknown): error is Error {
|
|
|
23
44
|
}
|
|
24
45
|
|
|
25
46
|
export function logAndReturn<T>(error: unknown, defaultValue: T): T {
|
|
26
|
-
|
|
47
|
+
const message = getErrorMessage(error);
|
|
48
|
+
// Legacy console logging (can be disabled via LEGACY_ERROR_LOGS=0)
|
|
49
|
+
legacyConsoleError("Error occurred:", message);
|
|
50
|
+
logger.warn("Error occurred - returning default value", {
|
|
51
|
+
error: message,
|
|
52
|
+
});
|
|
27
53
|
return defaultValue;
|
|
28
54
|
}
|
|
29
55
|
|
|
30
56
|
/**
|
|
31
57
|
* Enhanced error handler for consistent tool error handling
|
|
32
58
|
*/
|
|
33
|
-
export function handleToolError(
|
|
34
|
-
error
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
console.error(`Error in ${operation}:`, error);
|
|
39
|
-
|
|
59
|
+
export function handleToolError(error: unknown, operation: string, context?: Record<string, unknown>): never {
|
|
60
|
+
const message = getErrorMessage(error);
|
|
61
|
+
const errObj = error instanceof Error ? error : new Error(message);
|
|
62
|
+
// Legacy console logging (can be disabled via LEGACY_ERROR_LOGS=0)
|
|
63
|
+
legacyConsoleError(`Error in ${operation}:`, errObj);
|
|
40
64
|
if (context) {
|
|
41
|
-
|
|
65
|
+
legacyConsoleError("Context:", context);
|
|
42
66
|
}
|
|
67
|
+
logger.error(`Error in ${operation}`, {
|
|
68
|
+
error: message,
|
|
69
|
+
...(context && { context }),
|
|
70
|
+
});
|
|
43
71
|
|
|
44
|
-
|
|
72
|
+
if (error instanceof Error && error.stack) {
|
|
73
|
+
logger.debug("Error stack trace", { stack: error.stack });
|
|
74
|
+
}
|
|
45
75
|
|
|
46
76
|
// Provide more specific error messages based on error content
|
|
47
77
|
if (message.includes("ECONNREFUSED") || message.includes("ENOTFOUND")) {
|
|
@@ -51,21 +81,15 @@ export function handleToolError(
|
|
|
51
81
|
}
|
|
52
82
|
|
|
53
83
|
if (message.includes("401") || message.includes("Unauthorized")) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
`Authentication failed during ${operation}. Please check your WordPress credentials.`,
|
|
56
|
-
);
|
|
84
|
+
throw new Error(`Authentication failed during ${operation}. Please check your WordPress credentials.`);
|
|
57
85
|
}
|
|
58
86
|
|
|
59
87
|
if (message.includes("403") || message.includes("Forbidden")) {
|
|
60
|
-
throw new Error(
|
|
61
|
-
`Permission denied during ${operation}. Please check your user permissions.`,
|
|
62
|
-
);
|
|
88
|
+
throw new Error(`Permission denied during ${operation}. Please check your user permissions.`);
|
|
63
89
|
}
|
|
64
90
|
|
|
65
91
|
if (message.includes("429") || message.includes("Too Many Requests")) {
|
|
66
|
-
throw new Error(
|
|
67
|
-
`Rate limit exceeded during ${operation}. Please try again later.`,
|
|
68
|
-
);
|
|
92
|
+
throw new Error(`Rate limit exceeded during ${operation}. Please try again later.`);
|
|
69
93
|
}
|
|
70
94
|
|
|
71
95
|
throw new Error(`Failed to ${operation}: ${message}`);
|
|
@@ -74,11 +98,14 @@ export function handleToolError(
|
|
|
74
98
|
/**
|
|
75
99
|
* Validates required parameters
|
|
76
100
|
*/
|
|
77
|
-
export function validateRequired(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
101
|
+
export function validateRequired(params: Record<string, unknown> | unknown, required: string[]): void {
|
|
102
|
+
// Runtime guard: ensure params is a non-null object (tests expect throw on invalid input)
|
|
103
|
+
if (params === null || typeof params !== "object") {
|
|
104
|
+
throw new Error("Parameters must be an object");
|
|
105
|
+
}
|
|
106
|
+
// Only treat undefined or null as missing; accept legitimate falsy values: 0, false, ""
|
|
107
|
+
const obj = params as Record<string, unknown>;
|
|
108
|
+
const missing = required.filter((key) => obj[key] === undefined || obj[key] === null);
|
|
82
109
|
if (missing.length > 0) {
|
|
83
110
|
throw new Error(`Missing required parameters: ${missing.join(", ")}`);
|
|
84
111
|
}
|
|
@@ -87,10 +114,7 @@ export function validateRequired(
|
|
|
87
114
|
/**
|
|
88
115
|
* Validates site parameter for multi-site configurations
|
|
89
116
|
*/
|
|
90
|
-
export function validateSite(
|
|
91
|
-
site: string | undefined,
|
|
92
|
-
availableSites: string[],
|
|
93
|
-
): string {
|
|
117
|
+
export function validateSite(site: string | undefined, availableSites: string[]): string {
|
|
94
118
|
if (!site) {
|
|
95
119
|
if (availableSites.length === 1) {
|
|
96
120
|
return availableSites[0];
|
|
@@ -101,9 +125,7 @@ export function validateSite(
|
|
|
101
125
|
}
|
|
102
126
|
|
|
103
127
|
if (!availableSites.includes(site)) {
|
|
104
|
-
throw new Error(
|
|
105
|
-
`Site '${site}' not found. Available sites: ${availableSites.join(", ")}`,
|
|
106
|
-
);
|
|
128
|
+
throw new Error(`Site '${site}' not found. Available sites: ${availableSites.join(", ")}`);
|
|
107
129
|
}
|
|
108
130
|
|
|
109
131
|
return site;
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Logging System
|
|
3
|
+
*
|
|
4
|
+
* Replaces scattered console.log usage with structured, configurable logging.
|
|
5
|
+
* Integrates with the centralized Config system for environment-aware behavior.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ConfigHelpers } from "../config/Config.js";
|
|
9
|
+
|
|
10
|
+
export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
11
|
+
export type LogContext = Record<string, unknown>;
|
|
12
|
+
|
|
13
|
+
export interface LogEntry {
|
|
14
|
+
readonly timestamp: string;
|
|
15
|
+
readonly level: LogLevel;
|
|
16
|
+
readonly message: string;
|
|
17
|
+
readonly context?: LogContext | undefined;
|
|
18
|
+
readonly component?: string | undefined;
|
|
19
|
+
readonly requestId?: string | undefined;
|
|
20
|
+
readonly siteId?: string | undefined;
|
|
21
|
+
readonly userId?: string | undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface LoggerOptions {
|
|
25
|
+
readonly component?: string | undefined;
|
|
26
|
+
readonly context?: LogContext | undefined;
|
|
27
|
+
readonly siteId?: string | undefined;
|
|
28
|
+
readonly requestId?: string | undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Log level priorities (higher number = more important)
|
|
33
|
+
*/
|
|
34
|
+
const LOG_LEVELS: Record<LogLevel, number> = {
|
|
35
|
+
trace: 0,
|
|
36
|
+
debug: 1,
|
|
37
|
+
info: 2,
|
|
38
|
+
warn: 3,
|
|
39
|
+
error: 4,
|
|
40
|
+
fatal: 5,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get minimum log level from configuration
|
|
45
|
+
*/
|
|
46
|
+
function getMinLogLevel(): LogLevel {
|
|
47
|
+
const configInstance = ConfigHelpers.get();
|
|
48
|
+
const appConfig = configInstance.get();
|
|
49
|
+
const configLevel = appConfig.debug.logLevel.toLowerCase();
|
|
50
|
+
return LOG_LEVELS[configLevel as LogLevel] !== undefined ? (configLevel as LogLevel) : "info";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check if log level should be output
|
|
55
|
+
*/
|
|
56
|
+
function shouldLog(level: LogLevel): boolean {
|
|
57
|
+
const minLevel = getMinLogLevel();
|
|
58
|
+
return LOG_LEVELS[level] >= LOG_LEVELS[minLevel];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Format log entry for output
|
|
63
|
+
*/
|
|
64
|
+
function formatLogEntry(entry: LogEntry): string {
|
|
65
|
+
const timestamp = entry.timestamp;
|
|
66
|
+
const level = entry.level.toUpperCase().padEnd(5);
|
|
67
|
+
const component = entry.component ? `[${entry.component}]` : "";
|
|
68
|
+
const siteId = entry.siteId ? `{site:${entry.siteId}}` : "";
|
|
69
|
+
const requestId = entry.requestId ? `{req:${entry.requestId.slice(0, 8)}}` : "";
|
|
70
|
+
|
|
71
|
+
let message = `${timestamp} ${level} ${component}${siteId}${requestId} ${entry.message}`;
|
|
72
|
+
|
|
73
|
+
if (entry.context && Object.keys(entry.context).length > 0) {
|
|
74
|
+
const contextStr = JSON.stringify(entry.context);
|
|
75
|
+
message += ` ${contextStr}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return message;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Sanitize sensitive data from log context
|
|
83
|
+
*/
|
|
84
|
+
function sanitizeContext(context: LogContext): LogContext {
|
|
85
|
+
const sanitized: LogContext = {};
|
|
86
|
+
|
|
87
|
+
for (const [key, value] of Object.entries(context)) {
|
|
88
|
+
const keyLower = key.toLowerCase();
|
|
89
|
+
const isSensitive =
|
|
90
|
+
keyLower.includes("password") ||
|
|
91
|
+
keyLower.includes("secret") ||
|
|
92
|
+
keyLower.includes("token") ||
|
|
93
|
+
keyLower.includes("key") ||
|
|
94
|
+
keyLower.includes("credential");
|
|
95
|
+
|
|
96
|
+
if (isSensitive) {
|
|
97
|
+
if (typeof value === "string") {
|
|
98
|
+
sanitized[key] = value.length > 0 ? `[REDACTED:${value.length}chars]` : "[EMPTY]";
|
|
99
|
+
} else if (Array.isArray(value)) {
|
|
100
|
+
sanitized[key] = "[EMPTY]"; // Redact entire array for sensitive fields
|
|
101
|
+
} else {
|
|
102
|
+
sanitized[key] = value; // Keep non-string, non-array values as-is
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
sanitized[key] = value;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return sanitized;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Output log entry to appropriate destination
|
|
114
|
+
*/
|
|
115
|
+
function outputLog(entry: LogEntry): void {
|
|
116
|
+
// In test environment, only log errors and fatals
|
|
117
|
+
if (ConfigHelpers.isTest() && LOG_LEVELS[entry.level] < LOG_LEVELS.error) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// In DXT mode, suppress most logging
|
|
122
|
+
if (ConfigHelpers.isDXT() && LOG_LEVELS[entry.level] < LOG_LEVELS.warn) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const formatted = formatLogEntry(entry);
|
|
127
|
+
|
|
128
|
+
// Use stderr for all log output to avoid STDIO interference
|
|
129
|
+
console.error(formatted);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Main Logger Class
|
|
134
|
+
*/
|
|
135
|
+
export class Logger {
|
|
136
|
+
private readonly options: LoggerOptions;
|
|
137
|
+
|
|
138
|
+
constructor(options: LoggerOptions = {}) {
|
|
139
|
+
this.options = options;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Create child logger with additional context
|
|
144
|
+
*/
|
|
145
|
+
child(additionalOptions: LoggerOptions): Logger {
|
|
146
|
+
return new Logger({
|
|
147
|
+
component: additionalOptions.component ?? this.options.component,
|
|
148
|
+
siteId: additionalOptions.siteId ?? this.options.siteId,
|
|
149
|
+
requestId: additionalOptions.requestId ?? this.options.requestId,
|
|
150
|
+
context: {
|
|
151
|
+
...this.options.context,
|
|
152
|
+
...additionalOptions.context,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Log at specific level
|
|
159
|
+
*/
|
|
160
|
+
log(level: LogLevel, message: string, context?: LogContext): void {
|
|
161
|
+
if (!shouldLog(level)) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const mergedContext = context ? sanitizeContext({ ...this.options.context, ...context }) : this.options.context;
|
|
166
|
+
|
|
167
|
+
const entry: LogEntry = {
|
|
168
|
+
timestamp: new Date().toISOString(),
|
|
169
|
+
level,
|
|
170
|
+
message,
|
|
171
|
+
...(mergedContext && Object.keys(mergedContext).length > 0 && { context: mergedContext }),
|
|
172
|
+
...(this.options.component && { component: this.options.component }),
|
|
173
|
+
...(this.options.requestId && { requestId: this.options.requestId }),
|
|
174
|
+
...(this.options.siteId && { siteId: this.options.siteId }),
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
outputLog(entry);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Convenience methods
|
|
181
|
+
trace(message: string, context?: LogContext): void {
|
|
182
|
+
this.log("trace", message, context);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
debug(message: string, context?: LogContext): void {
|
|
186
|
+
this.log("debug", message, context);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
info(message: string, context?: LogContext): void {
|
|
190
|
+
this.log("info", message, context);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
warn(message: string, context?: LogContext): void {
|
|
194
|
+
this.log("warn", message, context);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
error(message: string, context?: LogContext): void;
|
|
198
|
+
error(error: Error, context?: LogContext): void;
|
|
199
|
+
error(messageOrError: string | Error, context?: LogContext): void {
|
|
200
|
+
if (messageOrError instanceof Error) {
|
|
201
|
+
this.log("error", messageOrError.message, {
|
|
202
|
+
...context,
|
|
203
|
+
errorName: messageOrError.name,
|
|
204
|
+
errorStack: messageOrError.stack,
|
|
205
|
+
});
|
|
206
|
+
} else {
|
|
207
|
+
this.log("error", messageOrError, context);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
fatal(message: string, context?: LogContext): void;
|
|
212
|
+
fatal(error: Error, context?: LogContext): void;
|
|
213
|
+
fatal(messageOrError: string | Error, context?: LogContext): void {
|
|
214
|
+
if (messageOrError instanceof Error) {
|
|
215
|
+
this.log("fatal", messageOrError.message, {
|
|
216
|
+
...context,
|
|
217
|
+
errorName: messageOrError.name,
|
|
218
|
+
errorStack: messageOrError.stack,
|
|
219
|
+
});
|
|
220
|
+
} else {
|
|
221
|
+
this.log("fatal", messageOrError, context);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Time a function execution
|
|
227
|
+
*/
|
|
228
|
+
time<T>(message: string, fn: () => T): T;
|
|
229
|
+
time<T>(message: string, fn: () => Promise<T>): Promise<T>;
|
|
230
|
+
time<T>(message: string, fn: () => T | Promise<T>): T | Promise<T> {
|
|
231
|
+
const start = Date.now();
|
|
232
|
+
this.debug(`Starting: ${message}`);
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
const result = fn();
|
|
236
|
+
|
|
237
|
+
// Check if result is a Promise by checking for then method
|
|
238
|
+
if (result && typeof result === "object" && "then" in result) {
|
|
239
|
+
// Cast to Promise<T> since we know it has a then method
|
|
240
|
+
const promiseResult = result as Promise<T>;
|
|
241
|
+
return promiseResult
|
|
242
|
+
.then((value: T) => {
|
|
243
|
+
const duration = Date.now() - start;
|
|
244
|
+
this.debug(`Completed: ${message}`, { duration: `${duration}ms` });
|
|
245
|
+
return value;
|
|
246
|
+
})
|
|
247
|
+
.catch((error: unknown) => {
|
|
248
|
+
const duration = Date.now() - start;
|
|
249
|
+
this.error(`Failed: ${message}`, {
|
|
250
|
+
duration: `${duration}ms`,
|
|
251
|
+
error: error instanceof Error ? error.message : String(error),
|
|
252
|
+
});
|
|
253
|
+
throw error;
|
|
254
|
+
});
|
|
255
|
+
} else {
|
|
256
|
+
const duration = Date.now() - start;
|
|
257
|
+
this.debug(`Completed: ${message}`, { duration: `${duration}ms` });
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
} catch (error) {
|
|
261
|
+
const duration = Date.now() - start;
|
|
262
|
+
this.error(`Failed: ${message}`, {
|
|
263
|
+
duration: `${duration}ms`,
|
|
264
|
+
error: error instanceof Error ? error.message : String(error),
|
|
265
|
+
});
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Default logger instance
|
|
273
|
+
*/
|
|
274
|
+
export const logger = new Logger();
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Create component-specific logger
|
|
278
|
+
*/
|
|
279
|
+
export function createLogger(component: string, options: Omit<LoggerOptions, "component"> = {}): Logger {
|
|
280
|
+
return new Logger({ ...options, component });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Create site-specific logger
|
|
285
|
+
*/
|
|
286
|
+
export function createSiteLogger(siteId: string, component?: string | undefined): Logger {
|
|
287
|
+
return new Logger({
|
|
288
|
+
siteId,
|
|
289
|
+
...(component && { component }),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Create request-specific logger
|
|
295
|
+
*/
|
|
296
|
+
export function createRequestLogger(
|
|
297
|
+
requestId: string,
|
|
298
|
+
component?: string | undefined,
|
|
299
|
+
siteId?: string | undefined,
|
|
300
|
+
): Logger {
|
|
301
|
+
return new Logger({
|
|
302
|
+
requestId,
|
|
303
|
+
...(component && { component }),
|
|
304
|
+
...(siteId && { siteId }),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Logger factory for common scenarios
|
|
310
|
+
*/
|
|
311
|
+
export const LoggerFactory = {
|
|
312
|
+
/**
|
|
313
|
+
* Create logger for WordPress API operations
|
|
314
|
+
*/
|
|
315
|
+
api: (siteId?: string | undefined) => createLogger("API", siteId ? { siteId } : {}),
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Create logger for cache operations
|
|
319
|
+
*/
|
|
320
|
+
cache: (siteId?: string | undefined) => createLogger("CACHE", siteId ? { siteId } : {}),
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Create logger for tool operations
|
|
324
|
+
*/
|
|
325
|
+
tool: (toolName: string, siteId?: string | undefined) => createLogger(`TOOL:${toolName}`, siteId ? { siteId } : {}),
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Create logger for authentication
|
|
329
|
+
*/
|
|
330
|
+
auth: (siteId?: string | undefined) => createLogger("AUTH", siteId ? { siteId } : {}),
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Create logger for configuration
|
|
334
|
+
*/
|
|
335
|
+
config: () => createLogger("CONFIG"),
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Create logger for security operations
|
|
339
|
+
*/
|
|
340
|
+
security: () => createLogger("SECURITY"),
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Create logger for performance monitoring
|
|
344
|
+
*/
|
|
345
|
+
performance: () => createLogger("PERF"),
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Create logger for server operations
|
|
349
|
+
*/
|
|
350
|
+
server: () => createLogger("SERVER"),
|
|
351
|
+
};
|