mcp-wordpress 2.6.3 → 2.7.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 +1 -1
- package/dist/cache/CacheInvalidation.d.ts +25 -6
- package/dist/cache/CacheInvalidation.d.ts.map +1 -1
- package/dist/cache/CacheInvalidation.js +168 -16
- package/dist/cache/CacheInvalidation.js.map +1 -1
- package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
- package/dist/cache/HttpCacheWrapper.js +3 -4
- package/dist/cache/HttpCacheWrapper.js.map +1 -1
- package/dist/cache/SEOCacheManager.d.ts +150 -0
- package/dist/cache/SEOCacheManager.d.ts.map +1 -0
- package/dist/cache/SEOCacheManager.js +275 -0
- package/dist/cache/SEOCacheManager.js.map +1 -0
- package/dist/client/SEOWordPressClient.d.ts +164 -0
- package/dist/client/SEOWordPressClient.d.ts.map +1 -0
- package/dist/client/SEOWordPressClient.js +674 -0
- package/dist/client/SEOWordPressClient.js.map +1 -0
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +50 -20
- package/dist/client/api.js.map +1 -1
- package/dist/client/auth.js +19 -19
- package/dist/client/auth.js.map +1 -1
- package/dist/client/index.d.ts +11 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +14 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/managers/AuthManager.d.ts +39 -0
- package/dist/client/managers/AuthManager.d.ts.map +1 -0
- package/dist/client/managers/AuthManager.js +142 -0
- package/dist/client/managers/AuthManager.js.map +1 -0
- package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
- package/dist/client/managers/AuthenticationManager.js +10 -9
- package/dist/client/managers/AuthenticationManager.js.map +1 -1
- package/dist/client/managers/BaseManager.d.ts.map +1 -1
- package/dist/client/managers/BaseManager.js +12 -0
- package/dist/client/managers/BaseManager.js.map +1 -1
- package/dist/client/managers/ComposedAuthenticationManager.d.ts +94 -0
- package/dist/client/managers/ComposedAuthenticationManager.d.ts.map +1 -0
- package/dist/client/managers/ComposedAuthenticationManager.js +340 -0
- package/dist/client/managers/ComposedAuthenticationManager.js.map +1 -0
- package/dist/client/managers/ComposedManagerFactory.d.ts +104 -0
- package/dist/client/managers/ComposedManagerFactory.d.ts.map +1 -0
- package/dist/client/managers/ComposedManagerFactory.js +180 -0
- package/dist/client/managers/ComposedManagerFactory.js.map +1 -0
- package/dist/client/managers/ComposedRequestManager.d.ts +82 -0
- package/dist/client/managers/ComposedRequestManager.d.ts.map +1 -0
- package/dist/client/managers/ComposedRequestManager.js +260 -0
- package/dist/client/managers/ComposedRequestManager.js.map +1 -0
- package/dist/client/managers/JWTAuthImplementation.d.ts +86 -0
- package/dist/client/managers/JWTAuthImplementation.d.ts.map +1 -0
- package/dist/client/managers/JWTAuthImplementation.js +240 -0
- package/dist/client/managers/JWTAuthImplementation.js.map +1 -0
- package/dist/client/managers/ManagersIndex.d.ts +6 -0
- package/dist/client/managers/ManagersIndex.d.ts.map +1 -0
- package/dist/client/managers/ManagersIndex.js +6 -0
- package/dist/client/managers/ManagersIndex.js.map +1 -0
- package/dist/client/managers/RequestManager.d.ts.map +1 -1
- package/dist/client/managers/RequestManager.js +5 -3
- package/dist/client/managers/RequestManager.js.map +1 -1
- package/dist/client/managers/composed/MigrationAdapter.d.ts +80 -0
- package/dist/client/managers/composed/MigrationAdapter.d.ts.map +1 -0
- package/dist/client/managers/composed/MigrationAdapter.js +214 -0
- package/dist/client/managers/composed/MigrationAdapter.js.map +1 -0
- package/dist/client/managers/composed/index.d.ts +23 -0
- package/dist/client/managers/composed/index.d.ts.map +1 -0
- package/dist/client/managers/composed/index.js +26 -0
- package/dist/client/managers/composed/index.js.map +1 -0
- package/dist/client/managers/implementations/ConfigurationProviderImpl.d.ts +27 -0
- package/dist/client/managers/implementations/ConfigurationProviderImpl.d.ts.map +1 -0
- package/dist/client/managers/implementations/ConfigurationProviderImpl.js +41 -0
- package/dist/client/managers/implementations/ConfigurationProviderImpl.js.map +1 -0
- package/dist/client/managers/implementations/ErrorHandlerImpl.d.ts +31 -0
- package/dist/client/managers/implementations/ErrorHandlerImpl.d.ts.map +1 -0
- package/dist/client/managers/implementations/ErrorHandlerImpl.js +73 -0
- package/dist/client/managers/implementations/ErrorHandlerImpl.js.map +1 -0
- package/dist/client/managers/implementations/ParameterValidatorImpl.d.ts +47 -0
- package/dist/client/managers/implementations/ParameterValidatorImpl.d.ts.map +1 -0
- package/dist/client/managers/implementations/ParameterValidatorImpl.js +141 -0
- package/dist/client/managers/implementations/ParameterValidatorImpl.js.map +1 -0
- package/dist/client/managers/interfaces/ManagerInterfaces.d.ts +147 -0
- package/dist/client/managers/interfaces/ManagerInterfaces.d.ts.map +1 -0
- package/dist/client/managers/interfaces/ManagerInterfaces.js +6 -0
- package/dist/client/managers/interfaces/ManagerInterfaces.js.map +1 -0
- package/dist/config/Config.d.ts +30 -0
- package/dist/config/Config.d.ts.map +1 -1
- package/dist/config/Config.js +30 -0
- package/dist/config/Config.js.map +1 -1
- package/dist/config/ConfigurationSchema.d.ts +75 -198
- package/dist/config/ConfigurationSchema.d.ts.map +1 -1
- package/dist/config/ConfigurationSchema.js +17 -17
- package/dist/config/ConfigurationSchema.js.map +1 -1
- package/dist/config/ServerConfiguration.d.ts +2 -2
- package/dist/config/ServerConfiguration.d.ts.map +1 -1
- package/dist/config/ServerConfiguration.js +15 -13
- package/dist/config/ServerConfiguration.js.map +1 -1
- package/dist/config/index.d.ts +8 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +11 -0
- package/dist/config/index.js.map +1 -0
- package/dist/docs/DocumentationGenerator.js +2 -2
- package/dist/docs/DocumentationGenerator.js.map +1 -1
- package/dist/dxt-entry.js +3 -3
- package/dist/dxt-entry.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -37
- package/dist/index.js.map +1 -1
- package/dist/performance/MetricsCollector.d.ts.map +1 -1
- package/dist/performance/MetricsCollector.js +5 -4
- package/dist/performance/MetricsCollector.js.map +1 -1
- package/dist/security/AISecurityScanner.js +7 -7
- package/dist/security/AISecurityScanner.js.map +1 -1
- package/dist/security/AutomatedRemediation.d.ts.map +1 -1
- package/dist/security/AutomatedRemediation.js +11 -11
- package/dist/security/AutomatedRemediation.js.map +1 -1
- package/dist/security/InputValidator.d.ts +50 -126
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +9 -9
- package/dist/security/InputValidator.js.map +1 -1
- package/dist/security/SecurityCIPipeline.d.ts +47 -5
- package/dist/security/SecurityCIPipeline.d.ts.map +1 -1
- package/dist/security/SecurityCIPipeline.js +390 -49
- package/dist/security/SecurityCIPipeline.js.map +1 -1
- package/dist/security/SecurityConfigManager.js +10 -10
- package/dist/security/SecurityConfigManager.js.map +1 -1
- package/dist/security/SecurityMonitoring.js +4 -4
- package/dist/security/SecurityMonitoring.js.map +1 -1
- package/dist/security/SecurityReviewer.d.ts.map +1 -1
- package/dist/security/SecurityReviewer.js +13 -6
- package/dist/security/SecurityReviewer.js.map +1 -1
- package/dist/security/index.js +3 -3
- package/dist/security/index.js.map +1 -1
- package/dist/server/ConnectionTester.js +5 -5
- 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 +7 -6
- package/dist/server/ToolRegistry.js.map +1 -1
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +9 -0
- package/dist/server/index.js.map +1 -0
- package/dist/tools/BaseToolManager.d.ts.map +1 -1
- package/dist/tools/BaseToolManager.js +11 -11
- package/dist/tools/BaseToolManager.js.map +1 -1
- package/dist/tools/auth.d.ts.map +1 -1
- package/dist/tools/auth.js +7 -7
- package/dist/tools/auth.js.map +1 -1
- package/dist/tools/comments.d.ts.map +1 -1
- package/dist/tools/comments.js +14 -14
- package/dist/tools/comments.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/media.d.ts.map +1 -1
- package/dist/tools/media.js +14 -11
- package/dist/tools/media.js.map +1 -1
- package/dist/tools/pages.d.ts.map +1 -1
- package/dist/tools/pages.js +12 -12
- package/dist/tools/pages.js.map +1 -1
- package/dist/tools/performance.d.ts.map +1 -1
- package/dist/tools/performance.js +13 -11
- package/dist/tools/performance.js.map +1 -1
- package/dist/tools/posts/PostHandlers.d.ts.map +1 -1
- package/dist/tools/posts/PostHandlers.js +16 -16
- package/dist/tools/posts/PostHandlers.js.map +1 -1
- package/dist/tools/posts/PostToolDefinitions.d.ts.map +1 -1
- package/dist/tools/posts/index.d.ts.map +1 -1
- package/dist/tools/seo/BulkOperations.d.ts +113 -0
- package/dist/tools/seo/BulkOperations.d.ts.map +1 -0
- package/dist/tools/seo/BulkOperations.js +398 -0
- package/dist/tools/seo/BulkOperations.js.map +1 -0
- package/dist/tools/seo/SEOHandlers.d.ts +55 -0
- package/dist/tools/seo/SEOHandlers.d.ts.map +1 -0
- package/dist/tools/seo/SEOHandlers.js +255 -0
- package/dist/tools/seo/SEOHandlers.js.map +1 -0
- package/dist/tools/seo/SEOToolDefinitions.d.ts +59 -0
- package/dist/tools/seo/SEOToolDefinitions.d.ts.map +1 -0
- package/dist/tools/seo/SEOToolDefinitions.js +385 -0
- package/dist/tools/seo/SEOToolDefinitions.js.map +1 -0
- package/dist/tools/seo/SEOTools.d.ts +203 -0
- package/dist/tools/seo/SEOTools.d.ts.map +1 -0
- package/dist/tools/seo/SEOTools.js +708 -0
- package/dist/tools/seo/SEOTools.js.map +1 -0
- package/dist/tools/seo/analyzers/ContentAnalyzer.d.ts +94 -0
- package/dist/tools/seo/analyzers/ContentAnalyzer.d.ts.map +1 -0
- package/dist/tools/seo/analyzers/ContentAnalyzer.js +402 -0
- package/dist/tools/seo/analyzers/ContentAnalyzer.js.map +1 -0
- package/dist/tools/seo/auditors/SiteAuditor.d.ts +121 -0
- package/dist/tools/seo/auditors/SiteAuditor.d.ts.map +1 -0
- package/dist/tools/seo/auditors/SiteAuditor.js +600 -0
- package/dist/tools/seo/auditors/SiteAuditor.js.map +1 -0
- package/dist/tools/seo/generators/MetaGenerator.d.ts +128 -0
- package/dist/tools/seo/generators/MetaGenerator.d.ts.map +1 -0
- package/dist/tools/seo/generators/MetaGenerator.js +547 -0
- package/dist/tools/seo/generators/MetaGenerator.js.map +1 -0
- package/dist/tools/seo/generators/SchemaGenerator.d.ts +204 -0
- package/dist/tools/seo/generators/SchemaGenerator.d.ts.map +1 -0
- package/dist/tools/seo/generators/SchemaGenerator.js +670 -0
- package/dist/tools/seo/generators/SchemaGenerator.js.map +1 -0
- package/dist/tools/seo/index.d.ts +17 -0
- package/dist/tools/seo/index.d.ts.map +1 -0
- package/dist/tools/seo/index.js +18 -0
- package/dist/tools/seo/index.js.map +1 -0
- package/dist/tools/seo/optimizers/InternalLinkingSuggester.d.ts +186 -0
- package/dist/tools/seo/optimizers/InternalLinkingSuggester.d.ts.map +1 -0
- package/dist/tools/seo/optimizers/InternalLinkingSuggester.js +683 -0
- package/dist/tools/seo/optimizers/InternalLinkingSuggester.js.map +1 -0
- package/dist/tools/site.d.ts.map +1 -1
- package/dist/tools/site.js +12 -12
- package/dist/tools/site.js.map +1 -1
- package/dist/tools/taxonomies.d.ts.map +1 -1
- package/dist/tools/taxonomies.js +20 -20
- package/dist/tools/taxonomies.js.map +1 -1
- package/dist/tools/users.d.ts.map +1 -1
- package/dist/tools/users.js +12 -12
- package/dist/tools/users.js.map +1 -1
- package/dist/types/client.d.ts +8 -6
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/client.js.map +1 -1
- package/dist/types/seo.d.ts +473 -0
- package/dist/types/seo.d.ts.map +1 -0
- package/dist/types/seo.js +94 -0
- package/dist/types/seo.js.map +1 -0
- package/dist/utils/enhancedError.js +1 -1
- package/dist/utils/enhancedError.js.map +1 -1
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.js +0 -1
- package/dist/utils/error.js.map +1 -1
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.js +3 -3
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/toolWrapper.d.ts +2 -2
- package/dist/utils/toolWrapper.js +8 -8
- package/dist/utils/toolWrapper.js.map +1 -1
- package/dist/utils/validation/core.d.ts.map +1 -1
- package/dist/utils/validation/core.js.map +1 -1
- package/dist/utils/validation/index.d.ts.map +1 -1
- package/dist/utils/validation/index.js.map +1 -1
- package/dist/utils/validation/network.js +3 -3
- package/dist/utils/validation/network.js.map +1 -1
- package/dist/utils/validation/rateLimit.js.map +1 -1
- package/dist/utils/validation/security.js.map +1 -1
- package/dist/utils/validation/wordpress.js.map +1 -1
- package/dist/utils/version.d.ts +144 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +318 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +24 -58
- package/src/cache/CacheInvalidation.ts +183 -20
- package/src/cache/HttpCacheWrapper.ts +8 -5
- package/src/cache/SEOCacheManager.ts +330 -0
- package/src/cache/__tests__/CacheInvalidation.test.ts +6 -11
- package/src/cache/__tests__/CachedWordPressClient.test.ts +37 -62
- package/src/client/SEOWordPressClient.ts +876 -0
- package/src/client/api.ts +50 -21
- package/src/client/auth.ts +19 -19
- package/src/client/index.ts +16 -0
- package/src/client/managers/AuthManager.ts +175 -0
- package/src/client/managers/AuthenticationManager.ts +16 -14
- package/src/client/managers/BaseManager.ts +24 -5
- package/src/client/managers/ComposedAuthenticationManager.ts +409 -0
- package/src/client/managers/ComposedManagerFactory.ts +231 -0
- package/src/client/managers/ComposedRequestManager.ts +336 -0
- package/src/client/managers/JWTAuthImplementation.ts +326 -0
- package/src/client/managers/ManagersIndex.ts +6 -0
- package/src/client/managers/RequestManager.ts +9 -7
- package/src/client/managers/composed/MigrationAdapter.ts +263 -0
- package/src/client/managers/composed/index.ts +47 -0
- package/src/client/managers/implementations/ConfigurationProviderImpl.ts +52 -0
- package/src/client/managers/implementations/ErrorHandlerImpl.ts +102 -0
- package/src/client/managers/implementations/ParameterValidatorImpl.ts +221 -0
- package/src/client/managers/interfaces/ManagerInterfaces.ts +171 -0
- package/src/config/Config.ts +63 -0
- package/src/config/ConfigurationSchema.ts +17 -17
- package/src/config/ServerConfiguration.ts +18 -16
- package/src/config/index.ts +13 -0
- package/src/docs/DocumentationGenerator.ts +2 -2
- package/src/dxt-entry.ts +3 -3
- package/src/index.ts +43 -43
- package/src/performance/MetricsCollector.ts +15 -11
- package/src/security/AISecurityScanner.ts +7 -7
- package/src/security/AutomatedRemediation.ts +13 -11
- package/src/security/InputValidator.ts +10 -9
- package/src/security/SecurityCIPipeline.ts +494 -56
- package/src/security/SecurityConfigManager.ts +10 -10
- package/src/security/SecurityMonitoring.ts +5 -5
- package/src/security/SecurityReviewer.ts +13 -6
- package/src/security/index.ts +3 -3
- package/src/server/ConnectionTester.ts +5 -5
- package/src/server/ToolRegistry.ts +9 -8
- package/src/server/index.ts +10 -0
- package/src/tools/BaseToolManager.ts +55 -83
- package/src/tools/auth.ts +21 -12
- package/src/tools/comments.ts +23 -19
- package/src/tools/index.ts +1 -0
- package/src/tools/media.ts +23 -20
- package/src/tools/pages.ts +20 -13
- package/src/tools/performance.ts +101 -32
- package/src/tools/posts/PostHandlers.ts +23 -23
- package/src/tools/posts/PostToolDefinitions.ts +1 -1
- package/src/tools/posts/index.ts +2 -2
- package/src/tools/seo/BulkOperations.ts +557 -0
- package/src/tools/seo/SEOHandlers.ts +296 -0
- package/src/tools/seo/SEOToolDefinitions.ts +402 -0
- package/src/tools/seo/SEOTools.ts +871 -0
- package/src/tools/seo/analyzers/ContentAnalyzer.ts +493 -0
- package/src/tools/seo/auditors/SiteAuditor.ts +787 -0
- package/src/tools/seo/generators/MetaGenerator.ts +694 -0
- package/src/tools/seo/generators/SchemaGenerator.ts +955 -0
- package/src/tools/seo/index.ts +47 -0
- package/src/tools/seo/optimizers/InternalLinkingSuggester.ts +934 -0
- package/src/tools/site.ts +27 -26
- package/src/tools/taxonomies.ts +29 -25
- package/src/tools/users.ts +20 -13
- package/src/types/client.ts +8 -6
- package/src/types/seo.ts +546 -0
- package/src/utils/enhancedError.ts +1 -1
- package/src/utils/error.ts +1 -2
- package/src/utils/index.ts +23 -0
- package/src/utils/logger.ts +3 -3
- package/src/utils/toolWrapper.ts +10 -10
- package/src/utils/validation/core.ts +2 -2
- package/src/utils/validation/index.ts +2 -2
- package/src/utils/validation/network.ts +5 -5
- package/src/utils/validation/rateLimit.ts +1 -1
- package/src/utils/validation/security.ts +1 -1
- package/src/utils/validation/wordpress.ts +1 -1
- package/src/utils/version.ts +402 -0
- package/src/dxt-entry.cjs +0 -68
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration Adapter
|
|
3
|
+
* Provides backward compatibility while transitioning from inheritance to composition
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { WordPressClientConfig, HTTPMethod } from "@/types/client.js";
|
|
7
|
+
import { RequestManager } from "../RequestManager.js";
|
|
8
|
+
import { AuthenticationManager } from "../AuthenticationManager.js";
|
|
9
|
+
import { ComposedRequestManager } from "../ComposedRequestManager.js";
|
|
10
|
+
import { ComposedAuthenticationManager } from "../ComposedAuthenticationManager.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Adapter that wraps composed managers to provide the same interface as inheritance-based ones
|
|
14
|
+
*/
|
|
15
|
+
export class RequestManagerAdapter {
|
|
16
|
+
private composedManager: ComposedRequestManager;
|
|
17
|
+
|
|
18
|
+
constructor(clientConfig: WordPressClientConfig, authManager: AuthenticationManager | ComposedAuthenticationManager) {
|
|
19
|
+
// If the authManager is the old inheritance-based one, create a composed one
|
|
20
|
+
let composedAuthManager: ComposedAuthenticationManager;
|
|
21
|
+
|
|
22
|
+
if (authManager instanceof ComposedAuthenticationManager) {
|
|
23
|
+
composedAuthManager = authManager;
|
|
24
|
+
} else {
|
|
25
|
+
// Create composed auth manager from config
|
|
26
|
+
composedAuthManager = ComposedAuthenticationManager.create(clientConfig);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.composedManager = ComposedRequestManager.create(clientConfig, composedAuthManager);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Initialize the adapter
|
|
34
|
+
*/
|
|
35
|
+
async initialize(): Promise<void> {
|
|
36
|
+
await this.composedManager.initialize();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Delegate request method to composed manager
|
|
41
|
+
*/
|
|
42
|
+
async request<T>(method: HTTPMethod, endpoint: string, data?: unknown, options?: unknown): Promise<T> {
|
|
43
|
+
return this.composedManager.request<T>(
|
|
44
|
+
method,
|
|
45
|
+
endpoint,
|
|
46
|
+
data,
|
|
47
|
+
options as Parameters<ComposedRequestManager["request"]>[3],
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Delegate stats method
|
|
53
|
+
*/
|
|
54
|
+
getStats(): unknown {
|
|
55
|
+
return this.composedManager.getStats();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Delegate reset stats method
|
|
60
|
+
*/
|
|
61
|
+
resetStats(): void {
|
|
62
|
+
this.composedManager.resetStats();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Cleanup method
|
|
67
|
+
*/
|
|
68
|
+
dispose(): void {
|
|
69
|
+
this.composedManager.dispose();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Migration utilities for gradual transition
|
|
75
|
+
*/
|
|
76
|
+
export class MigrationAdapter {
|
|
77
|
+
/**
|
|
78
|
+
* Create managers using the new composition approach but with backward-compatible interface
|
|
79
|
+
*/
|
|
80
|
+
static async createCompatibleManagers(config: WordPressClientConfig): Promise<{
|
|
81
|
+
requestManager: RequestManagerAdapter;
|
|
82
|
+
authManager: ComposedAuthenticationManager;
|
|
83
|
+
}> {
|
|
84
|
+
const authManager = ComposedAuthenticationManager.create(config);
|
|
85
|
+
await authManager.authenticate();
|
|
86
|
+
|
|
87
|
+
const requestManager = new RequestManagerAdapter(config, authManager);
|
|
88
|
+
await requestManager.initialize();
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
requestManager,
|
|
92
|
+
authManager,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Factory method that returns either old or new managers based on feature flag
|
|
98
|
+
*/
|
|
99
|
+
static async createManagers(
|
|
100
|
+
config: WordPressClientConfig,
|
|
101
|
+
useComposition: boolean = true,
|
|
102
|
+
): Promise<{
|
|
103
|
+
requestManager: RequestManager | RequestManagerAdapter;
|
|
104
|
+
authManager: AuthenticationManager | ComposedAuthenticationManager;
|
|
105
|
+
}> {
|
|
106
|
+
if (useComposition) {
|
|
107
|
+
return MigrationAdapter.createCompatibleManagers(config);
|
|
108
|
+
} else {
|
|
109
|
+
// Return old inheritance-based managers (simplified for now)
|
|
110
|
+
throw new Error("Legacy managers not available in this implementation");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check if a manager is using the new composed approach
|
|
116
|
+
*/
|
|
117
|
+
static isComposed(manager: unknown): boolean {
|
|
118
|
+
return (
|
|
119
|
+
manager instanceof ComposedAuthenticationManager ||
|
|
120
|
+
manager instanceof ComposedRequestManager ||
|
|
121
|
+
manager instanceof RequestManagerAdapter
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get migration progress information
|
|
127
|
+
*/
|
|
128
|
+
static getMigrationStatus(managers: unknown[]): {
|
|
129
|
+
total: number;
|
|
130
|
+
composed: number;
|
|
131
|
+
inheritance: number;
|
|
132
|
+
percentage: number;
|
|
133
|
+
} {
|
|
134
|
+
const total = managers.length;
|
|
135
|
+
const composed = managers.filter((manager) => MigrationAdapter.isComposed(manager)).length;
|
|
136
|
+
const inheritance = total - composed;
|
|
137
|
+
const percentage = total > 0 ? Math.round((composed / total) * 100) : 0;
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
total,
|
|
141
|
+
composed,
|
|
142
|
+
inheritance,
|
|
143
|
+
percentage,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Performance comparison between inheritance and composition approaches
|
|
149
|
+
*/
|
|
150
|
+
static async performanceComparison(
|
|
151
|
+
config: WordPressClientConfig,
|
|
152
|
+
iterations: number = 100,
|
|
153
|
+
): Promise<{
|
|
154
|
+
inheritance: number;
|
|
155
|
+
composition: number;
|
|
156
|
+
improvement: string;
|
|
157
|
+
}> {
|
|
158
|
+
// Running performance comparison with iterations
|
|
159
|
+
|
|
160
|
+
// Test composition approach only (inheritance baseline would require old managers)
|
|
161
|
+
const compositionStart = performance.now();
|
|
162
|
+
for (let i = 0; i < iterations; i++) {
|
|
163
|
+
const authManager = ComposedAuthenticationManager.create(config);
|
|
164
|
+
const requestManager = ComposedRequestManager.create(config, authManager);
|
|
165
|
+
// Simulate usage
|
|
166
|
+
authManager.isAuthenticated();
|
|
167
|
+
requestManager.getStats();
|
|
168
|
+
}
|
|
169
|
+
const compositionTime = performance.now() - compositionStart;
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
inheritance: 0, // Would require old managers to measure
|
|
173
|
+
composition: compositionTime,
|
|
174
|
+
improvement: "Composition pattern implemented",
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Migration guide generator
|
|
180
|
+
*/
|
|
181
|
+
static generateMigrationGuide(): string {
|
|
182
|
+
return `
|
|
183
|
+
# Migration Guide: Inheritance to Composition
|
|
184
|
+
|
|
185
|
+
## Overview
|
|
186
|
+
This migration guide helps transition from inheritance-based managers to composition-based managers.
|
|
187
|
+
|
|
188
|
+
## Benefits of Composition
|
|
189
|
+
1. **Better Testability**: Each component can be tested in isolation
|
|
190
|
+
2. **Improved Flexibility**: Components can be mixed and matched
|
|
191
|
+
3. **SOLID Principles**: Better adherence to Single Responsibility and Dependency Inversion
|
|
192
|
+
4. **Reduced Coupling**: Components depend on interfaces, not concrete classes
|
|
193
|
+
|
|
194
|
+
## Migration Steps
|
|
195
|
+
|
|
196
|
+
### Step 1: Update Imports
|
|
197
|
+
\`\`\`typescript
|
|
198
|
+
// Old approach
|
|
199
|
+
import { RequestManager } from '@/client/managers/RequestManager.js';
|
|
200
|
+
import { AuthenticationManager } from '@/client/managers/AuthenticationManager.js';
|
|
201
|
+
|
|
202
|
+
// New approach
|
|
203
|
+
import { createComposedWordPressClient } from '@/client/managers/composed';
|
|
204
|
+
\`\`\`
|
|
205
|
+
|
|
206
|
+
### Step 2: Replace Manager Creation
|
|
207
|
+
\`\`\`typescript
|
|
208
|
+
// Old approach
|
|
209
|
+
const authManager = new AuthenticationManager(config);
|
|
210
|
+
const requestManager = new RequestManager(config, authManager);
|
|
211
|
+
|
|
212
|
+
// New approach
|
|
213
|
+
const client = await createComposedWordPressClient(config);
|
|
214
|
+
\`\`\`
|
|
215
|
+
|
|
216
|
+
### Step 3: Update Usage Patterns
|
|
217
|
+
\`\`\`typescript
|
|
218
|
+
// Old approach
|
|
219
|
+
await requestManager.request('GET', '/wp/v2/posts');
|
|
220
|
+
|
|
221
|
+
// New approach
|
|
222
|
+
await client.request('GET', '/wp/v2/posts');
|
|
223
|
+
// or use convenience methods
|
|
224
|
+
await client.getPosts();
|
|
225
|
+
\`\`\`
|
|
226
|
+
|
|
227
|
+
### Step 4: Handle Dependency Injection
|
|
228
|
+
\`\`\`typescript
|
|
229
|
+
// Custom implementations can be injected
|
|
230
|
+
const customErrorHandler = new CustomErrorHandler();
|
|
231
|
+
const factory = new ComposedManagerFactory();
|
|
232
|
+
const client = await factory.createComposedClient({
|
|
233
|
+
clientConfig: config,
|
|
234
|
+
customErrorHandler
|
|
235
|
+
});
|
|
236
|
+
\`\`\`
|
|
237
|
+
|
|
238
|
+
## Gradual Migration
|
|
239
|
+
Use the MigrationAdapter for gradual migration:
|
|
240
|
+
|
|
241
|
+
\`\`\`typescript
|
|
242
|
+
import { MigrationAdapter } from '@/client/managers/composed';
|
|
243
|
+
|
|
244
|
+
// Feature flag to control migration
|
|
245
|
+
const USE_COMPOSITION = process.env.USE_COMPOSED_MANAGERS === 'true';
|
|
246
|
+
|
|
247
|
+
const { requestManager, authManager } = await MigrationAdapter.createManagers(
|
|
248
|
+
config,
|
|
249
|
+
USE_COMPOSITION
|
|
250
|
+
);
|
|
251
|
+
\`\`\`
|
|
252
|
+
|
|
253
|
+
## Testing the Migration
|
|
254
|
+
1. Run existing tests with both approaches
|
|
255
|
+
2. Performance test both implementations
|
|
256
|
+
3. Gradually migrate components one by one
|
|
257
|
+
4. Monitor for any behavioral differences
|
|
258
|
+
|
|
259
|
+
## Rollback Plan
|
|
260
|
+
The MigrationAdapter provides backward compatibility, allowing easy rollback if issues arise.
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composed Managers Export
|
|
3
|
+
*
|
|
4
|
+
* This module provides composition-based alternatives to the inheritance-based managers.
|
|
5
|
+
* The composed managers offer better testability, flexibility, and adherence to SOLID principles.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { createComposedWordPressClient } from '@/client/managers/composed';
|
|
10
|
+
*
|
|
11
|
+
* const client = await createComposedWordPressClient(config);
|
|
12
|
+
* const posts = await client.getPosts();
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Interfaces
|
|
17
|
+
export type {
|
|
18
|
+
ConfigurationProvider,
|
|
19
|
+
ErrorHandler,
|
|
20
|
+
ParameterValidator,
|
|
21
|
+
AuthenticationProvider,
|
|
22
|
+
RequestHandler,
|
|
23
|
+
BaseManagerContract,
|
|
24
|
+
ComposedManager,
|
|
25
|
+
ManagerFactory,
|
|
26
|
+
ManagerCompositionConfig
|
|
27
|
+
} from "../interfaces/ManagerInterfaces.js";
|
|
28
|
+
|
|
29
|
+
// Implementations
|
|
30
|
+
export { ConfigurationProviderImpl } from "../implementations/ConfigurationProviderImpl.js";
|
|
31
|
+
export { ErrorHandlerImpl } from "../implementations/ErrorHandlerImpl.js";
|
|
32
|
+
export { ParameterValidatorImpl } from "../implementations/ParameterValidatorImpl.js";
|
|
33
|
+
|
|
34
|
+
// Composed Managers
|
|
35
|
+
export { ComposedAuthenticationManager } from "../ComposedAuthenticationManager.js";
|
|
36
|
+
export { ComposedRequestManager } from "../ComposedRequestManager.js";
|
|
37
|
+
|
|
38
|
+
// Factory and Client
|
|
39
|
+
export {
|
|
40
|
+
ComposedManagerFactory,
|
|
41
|
+
ComposedWordPressClient,
|
|
42
|
+
createComposedWordPressClient,
|
|
43
|
+
type ComposedWordPressClientDependencies
|
|
44
|
+
} from "../ComposedManagerFactory.js";
|
|
45
|
+
|
|
46
|
+
// Migration utilities (for gradual migration from inheritance to composition)
|
|
47
|
+
export { MigrationAdapter } from "./MigrationAdapter.js";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Provider Implementation
|
|
3
|
+
* Provides centralized configuration management for managers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { WordPressClientConfig } from "@/types/client.js";
|
|
7
|
+
import type { ConfigurationProvider } from "../interfaces/ManagerInterfaces.js";
|
|
8
|
+
|
|
9
|
+
export class ConfigurationProviderImpl implements ConfigurationProvider {
|
|
10
|
+
public readonly config: WordPressClientConfig;
|
|
11
|
+
|
|
12
|
+
constructor(config: WordPressClientConfig) {
|
|
13
|
+
// Create defensive copy to prevent external mutation
|
|
14
|
+
this.config = Object.freeze({ ...config });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get configuration value by path (dot notation)
|
|
19
|
+
*/
|
|
20
|
+
getConfigValue<T = unknown>(path: string, defaultValue?: T): T | undefined {
|
|
21
|
+
return (
|
|
22
|
+
(path.split(".").reduce((obj, key) => (obj as Record<string, unknown>)?.[key], this.config as unknown) as T) ??
|
|
23
|
+
defaultValue
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Validate configuration completeness
|
|
29
|
+
*/
|
|
30
|
+
validateConfiguration(): void {
|
|
31
|
+
const required = ["baseUrl", "auth"];
|
|
32
|
+
const missing = required.filter((field) => !this.config[field as keyof WordPressClientConfig]);
|
|
33
|
+
|
|
34
|
+
if (missing.length > 0) {
|
|
35
|
+
throw new Error(`Missing required configuration: ${missing.join(", ")}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get timeout value with fallbacks
|
|
41
|
+
*/
|
|
42
|
+
getTimeout(): number {
|
|
43
|
+
return this.config.timeout || 30000;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check if debug mode is enabled
|
|
48
|
+
*/
|
|
49
|
+
isDebugEnabled(): boolean {
|
|
50
|
+
return Boolean((this.config as unknown as Record<string, unknown>).debug);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handler Implementation
|
|
3
|
+
* Provides standardized error handling and logging for managers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { WordPressAPIError } from "@/types/client.js";
|
|
7
|
+
import { debug, logError } from "@/utils/debug.js";
|
|
8
|
+
import { getErrorMessage } from "@/utils/error.js";
|
|
9
|
+
import type { ErrorHandler, ConfigurationProvider } from "../interfaces/ManagerInterfaces.js";
|
|
10
|
+
|
|
11
|
+
export class ErrorHandlerImpl implements ErrorHandler {
|
|
12
|
+
constructor(private configProvider: ConfigurationProvider) {}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Handle and transform errors with context
|
|
16
|
+
*/
|
|
17
|
+
handleError(error: unknown, operation: string): never {
|
|
18
|
+
logError(`${operation} failed:`, error as Record<string, unknown>);
|
|
19
|
+
|
|
20
|
+
if (error instanceof WordPressAPIError) {
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Type guard for error-like objects
|
|
25
|
+
const isErrorLike = (err: unknown): err is { name?: string; code?: string; message?: string } => {
|
|
26
|
+
return typeof err === "object" && err !== null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (isErrorLike(error)) {
|
|
30
|
+
if (error.name === "AbortError" || error.code === "ABORT_ERR") {
|
|
31
|
+
throw new WordPressAPIError(
|
|
32
|
+
`Request timeout after ${this.configProvider.config.timeout}ms`,
|
|
33
|
+
408,
|
|
34
|
+
"timeout"
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND") {
|
|
39
|
+
throw new WordPressAPIError(
|
|
40
|
+
`Cannot connect to WordPress site: ${this.configProvider.config.baseUrl}`,
|
|
41
|
+
503,
|
|
42
|
+
"connection_failed"
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const message = getErrorMessage(error);
|
|
48
|
+
throw new WordPressAPIError(`${operation} failed: ${message}`, 500, "unknown_error");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Log successful operations
|
|
53
|
+
*/
|
|
54
|
+
logSuccess(operation: string, details?: unknown): void {
|
|
55
|
+
debug.log(`${operation} completed successfully`, details);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Handle authentication errors specifically
|
|
60
|
+
*/
|
|
61
|
+
handleAuthError(error: unknown, operation: string): never {
|
|
62
|
+
logError(`Authentication failed during ${operation}:`, error as Record<string, unknown>);
|
|
63
|
+
|
|
64
|
+
if (error instanceof WordPressAPIError) {
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const message = getErrorMessage(error);
|
|
69
|
+
throw new WordPressAPIError(
|
|
70
|
+
`Authentication failed during ${operation}: ${message}`,
|
|
71
|
+
401,
|
|
72
|
+
"auth_failed"
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Handle rate limit errors specifically
|
|
78
|
+
*/
|
|
79
|
+
handleRateLimitError(retryAfter?: number): never {
|
|
80
|
+
const message = retryAfter
|
|
81
|
+
? `Rate limit exceeded. Retry after ${retryAfter} seconds.`
|
|
82
|
+
: "Rate limit exceeded.";
|
|
83
|
+
|
|
84
|
+
throw new WordPressAPIError(message, 429, "rate_limited");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Create context-aware error
|
|
89
|
+
*/
|
|
90
|
+
createContextualError(baseError: unknown, context: Record<string, unknown>): WordPressAPIError {
|
|
91
|
+
const message = getErrorMessage(baseError);
|
|
92
|
+
const contextString = Object.entries(context)
|
|
93
|
+
.map(([key, value]) => `${key}=${String(value)}`)
|
|
94
|
+
.join(', ');
|
|
95
|
+
|
|
96
|
+
return new WordPressAPIError(
|
|
97
|
+
`${message} (Context: ${contextString})`,
|
|
98
|
+
500,
|
|
99
|
+
"contextual_error"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parameter Validator Implementation
|
|
3
|
+
* Provides comprehensive parameter validation for managers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { WordPressAPIError } from "@/types/client.js";
|
|
7
|
+
import type { ParameterValidator } from "../interfaces/ManagerInterfaces.js";
|
|
8
|
+
|
|
9
|
+
export class ParameterValidatorImpl implements ParameterValidator {
|
|
10
|
+
/**
|
|
11
|
+
* Validate required parameters are present
|
|
12
|
+
*/
|
|
13
|
+
validateRequired(params: Record<string, unknown>, requiredFields: string[]): void {
|
|
14
|
+
for (const field of requiredFields) {
|
|
15
|
+
if (params[field] === undefined || params[field] === null) {
|
|
16
|
+
throw new WordPressAPIError(`Missing required parameter: ${field}`, 400, "missing_parameter");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Validate parameter types and formats
|
|
23
|
+
*/
|
|
24
|
+
validateParameters<T>(params: unknown, schema?: unknown): T {
|
|
25
|
+
if (params === null || params === undefined) {
|
|
26
|
+
throw new WordPressAPIError("Parameters cannot be null or undefined", 400, "invalid_parameters");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// If no schema provided, return params as-is with type assertion
|
|
30
|
+
if (!schema) {
|
|
31
|
+
return params as T;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Basic runtime validation (can be extended with schema validation libraries)
|
|
35
|
+
if (typeof params !== "object") {
|
|
36
|
+
throw new WordPressAPIError("Parameters must be an object", 400, "invalid_parameters");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return params as T;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Validate string parameters
|
|
44
|
+
*/
|
|
45
|
+
validateString(value: unknown, fieldName: string, options?: {
|
|
46
|
+
required?: boolean;
|
|
47
|
+
minLength?: number;
|
|
48
|
+
maxLength?: number;
|
|
49
|
+
pattern?: RegExp;
|
|
50
|
+
}): string {
|
|
51
|
+
if (options?.required && (value === undefined || value === null || value === "")) {
|
|
52
|
+
throw new WordPressAPIError(`${fieldName} is required`, 400, "missing_parameter");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (value === undefined || value === null) {
|
|
56
|
+
return "";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (typeof value !== "string") {
|
|
60
|
+
throw new WordPressAPIError(`${fieldName} must be a string`, 400, "invalid_parameter_type");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (options?.minLength && value.length < options.minLength) {
|
|
64
|
+
throw new WordPressAPIError(
|
|
65
|
+
`${fieldName} must be at least ${options.minLength} characters`,
|
|
66
|
+
400,
|
|
67
|
+
"parameter_too_short"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (options?.maxLength && value.length > options.maxLength) {
|
|
72
|
+
throw new WordPressAPIError(
|
|
73
|
+
`${fieldName} must be no more than ${options.maxLength} characters`,
|
|
74
|
+
400,
|
|
75
|
+
"parameter_too_long"
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (options?.pattern && !options.pattern.test(value)) {
|
|
80
|
+
throw new WordPressAPIError(
|
|
81
|
+
`${fieldName} format is invalid`,
|
|
82
|
+
400,
|
|
83
|
+
"invalid_parameter_format"
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Validate numeric parameters
|
|
92
|
+
*/
|
|
93
|
+
validateNumber(value: unknown, fieldName: string, options?: {
|
|
94
|
+
required?: boolean;
|
|
95
|
+
min?: number;
|
|
96
|
+
max?: number;
|
|
97
|
+
integer?: boolean;
|
|
98
|
+
}): number {
|
|
99
|
+
if (options?.required && (value === undefined || value === null)) {
|
|
100
|
+
throw new WordPressAPIError(`${fieldName} is required`, 400, "missing_parameter");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (value === undefined || value === null) {
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const numValue = typeof value === "string" ? parseFloat(value) : Number(value);
|
|
108
|
+
|
|
109
|
+
if (isNaN(numValue)) {
|
|
110
|
+
throw new WordPressAPIError(`${fieldName} must be a valid number`, 400, "invalid_parameter_type");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (options?.integer && !Number.isInteger(numValue)) {
|
|
114
|
+
throw new WordPressAPIError(`${fieldName} must be an integer`, 400, "invalid_parameter_type");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (options?.min !== undefined && numValue < options.min) {
|
|
118
|
+
throw new WordPressAPIError(
|
|
119
|
+
`${fieldName} must be at least ${options.min}`,
|
|
120
|
+
400,
|
|
121
|
+
"parameter_too_small"
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (options?.max !== undefined && numValue > options.max) {
|
|
126
|
+
throw new WordPressAPIError(
|
|
127
|
+
`${fieldName} must be no more than ${options.max}`,
|
|
128
|
+
400,
|
|
129
|
+
"parameter_too_large"
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return numValue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Validate array parameters
|
|
138
|
+
*/
|
|
139
|
+
validateArray<T>(value: unknown, fieldName: string, options?: {
|
|
140
|
+
required?: boolean;
|
|
141
|
+
minLength?: number;
|
|
142
|
+
maxLength?: number;
|
|
143
|
+
itemValidator?: (item: unknown) => T;
|
|
144
|
+
}): T[] {
|
|
145
|
+
if (options?.required && (value === undefined || value === null)) {
|
|
146
|
+
throw new WordPressAPIError(`${fieldName} is required`, 400, "missing_parameter");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (value === undefined || value === null) {
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!Array.isArray(value)) {
|
|
154
|
+
throw new WordPressAPIError(`${fieldName} must be an array`, 400, "invalid_parameter_type");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (options?.minLength && value.length < options.minLength) {
|
|
158
|
+
throw new WordPressAPIError(
|
|
159
|
+
`${fieldName} must contain at least ${options.minLength} items`,
|
|
160
|
+
400,
|
|
161
|
+
"array_too_short"
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (options?.maxLength && value.length > options.maxLength) {
|
|
166
|
+
throw new WordPressAPIError(
|
|
167
|
+
`${fieldName} must contain no more than ${options.maxLength} items`,
|
|
168
|
+
400,
|
|
169
|
+
"array_too_long"
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (options?.itemValidator) {
|
|
174
|
+
try {
|
|
175
|
+
return value.map((item, index) => {
|
|
176
|
+
try {
|
|
177
|
+
return options.itemValidator!(item);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
throw new WordPressAPIError(
|
|
180
|
+
`${fieldName}[${index}] validation failed: ${getErrorMessage(error)}`,
|
|
181
|
+
400,
|
|
182
|
+
"array_item_invalid"
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (error instanceof WordPressAPIError) {
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
throw new WordPressAPIError(
|
|
191
|
+
`${fieldName} validation failed: ${getErrorMessage(error)}`,
|
|
192
|
+
400,
|
|
193
|
+
"array_validation_failed"
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return value as T[];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Validate WordPress ID parameters
|
|
203
|
+
*/
|
|
204
|
+
validateWordPressId(value: unknown, fieldName: string = "id"): number {
|
|
205
|
+
const id = this.validateNumber(value, fieldName, {
|
|
206
|
+
required: true,
|
|
207
|
+
min: 1,
|
|
208
|
+
integer: true
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return id;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Helper function to get error message
|
|
216
|
+
function getErrorMessage(error: unknown): string {
|
|
217
|
+
if (error instanceof Error) {
|
|
218
|
+
return error.message;
|
|
219
|
+
}
|
|
220
|
+
return String(error);
|
|
221
|
+
}
|