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.
Files changed (333) hide show
  1. package/README.md +1 -1
  2. package/dist/cache/CacheInvalidation.d.ts +25 -6
  3. package/dist/cache/CacheInvalidation.d.ts.map +1 -1
  4. package/dist/cache/CacheInvalidation.js +168 -16
  5. package/dist/cache/CacheInvalidation.js.map +1 -1
  6. package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
  7. package/dist/cache/HttpCacheWrapper.js +3 -4
  8. package/dist/cache/HttpCacheWrapper.js.map +1 -1
  9. package/dist/cache/SEOCacheManager.d.ts +150 -0
  10. package/dist/cache/SEOCacheManager.d.ts.map +1 -0
  11. package/dist/cache/SEOCacheManager.js +275 -0
  12. package/dist/cache/SEOCacheManager.js.map +1 -0
  13. package/dist/client/SEOWordPressClient.d.ts +164 -0
  14. package/dist/client/SEOWordPressClient.d.ts.map +1 -0
  15. package/dist/client/SEOWordPressClient.js +674 -0
  16. package/dist/client/SEOWordPressClient.js.map +1 -0
  17. package/dist/client/api.d.ts.map +1 -1
  18. package/dist/client/api.js +50 -20
  19. package/dist/client/api.js.map +1 -1
  20. package/dist/client/auth.js +19 -19
  21. package/dist/client/auth.js.map +1 -1
  22. package/dist/client/index.d.ts +11 -0
  23. package/dist/client/index.d.ts.map +1 -0
  24. package/dist/client/index.js +14 -0
  25. package/dist/client/index.js.map +1 -0
  26. package/dist/client/managers/AuthManager.d.ts +39 -0
  27. package/dist/client/managers/AuthManager.d.ts.map +1 -0
  28. package/dist/client/managers/AuthManager.js +142 -0
  29. package/dist/client/managers/AuthManager.js.map +1 -0
  30. package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
  31. package/dist/client/managers/AuthenticationManager.js +10 -9
  32. package/dist/client/managers/AuthenticationManager.js.map +1 -1
  33. package/dist/client/managers/BaseManager.d.ts.map +1 -1
  34. package/dist/client/managers/BaseManager.js +12 -0
  35. package/dist/client/managers/BaseManager.js.map +1 -1
  36. package/dist/client/managers/ComposedAuthenticationManager.d.ts +94 -0
  37. package/dist/client/managers/ComposedAuthenticationManager.d.ts.map +1 -0
  38. package/dist/client/managers/ComposedAuthenticationManager.js +340 -0
  39. package/dist/client/managers/ComposedAuthenticationManager.js.map +1 -0
  40. package/dist/client/managers/ComposedManagerFactory.d.ts +104 -0
  41. package/dist/client/managers/ComposedManagerFactory.d.ts.map +1 -0
  42. package/dist/client/managers/ComposedManagerFactory.js +180 -0
  43. package/dist/client/managers/ComposedManagerFactory.js.map +1 -0
  44. package/dist/client/managers/ComposedRequestManager.d.ts +82 -0
  45. package/dist/client/managers/ComposedRequestManager.d.ts.map +1 -0
  46. package/dist/client/managers/ComposedRequestManager.js +260 -0
  47. package/dist/client/managers/ComposedRequestManager.js.map +1 -0
  48. package/dist/client/managers/JWTAuthImplementation.d.ts +86 -0
  49. package/dist/client/managers/JWTAuthImplementation.d.ts.map +1 -0
  50. package/dist/client/managers/JWTAuthImplementation.js +240 -0
  51. package/dist/client/managers/JWTAuthImplementation.js.map +1 -0
  52. package/dist/client/managers/ManagersIndex.d.ts +6 -0
  53. package/dist/client/managers/ManagersIndex.d.ts.map +1 -0
  54. package/dist/client/managers/ManagersIndex.js +6 -0
  55. package/dist/client/managers/ManagersIndex.js.map +1 -0
  56. package/dist/client/managers/RequestManager.d.ts.map +1 -1
  57. package/dist/client/managers/RequestManager.js +5 -3
  58. package/dist/client/managers/RequestManager.js.map +1 -1
  59. package/dist/client/managers/composed/MigrationAdapter.d.ts +80 -0
  60. package/dist/client/managers/composed/MigrationAdapter.d.ts.map +1 -0
  61. package/dist/client/managers/composed/MigrationAdapter.js +214 -0
  62. package/dist/client/managers/composed/MigrationAdapter.js.map +1 -0
  63. package/dist/client/managers/composed/index.d.ts +23 -0
  64. package/dist/client/managers/composed/index.d.ts.map +1 -0
  65. package/dist/client/managers/composed/index.js +26 -0
  66. package/dist/client/managers/composed/index.js.map +1 -0
  67. package/dist/client/managers/implementations/ConfigurationProviderImpl.d.ts +27 -0
  68. package/dist/client/managers/implementations/ConfigurationProviderImpl.d.ts.map +1 -0
  69. package/dist/client/managers/implementations/ConfigurationProviderImpl.js +41 -0
  70. package/dist/client/managers/implementations/ConfigurationProviderImpl.js.map +1 -0
  71. package/dist/client/managers/implementations/ErrorHandlerImpl.d.ts +31 -0
  72. package/dist/client/managers/implementations/ErrorHandlerImpl.d.ts.map +1 -0
  73. package/dist/client/managers/implementations/ErrorHandlerImpl.js +73 -0
  74. package/dist/client/managers/implementations/ErrorHandlerImpl.js.map +1 -0
  75. package/dist/client/managers/implementations/ParameterValidatorImpl.d.ts +47 -0
  76. package/dist/client/managers/implementations/ParameterValidatorImpl.d.ts.map +1 -0
  77. package/dist/client/managers/implementations/ParameterValidatorImpl.js +141 -0
  78. package/dist/client/managers/implementations/ParameterValidatorImpl.js.map +1 -0
  79. package/dist/client/managers/interfaces/ManagerInterfaces.d.ts +147 -0
  80. package/dist/client/managers/interfaces/ManagerInterfaces.d.ts.map +1 -0
  81. package/dist/client/managers/interfaces/ManagerInterfaces.js +6 -0
  82. package/dist/client/managers/interfaces/ManagerInterfaces.js.map +1 -0
  83. package/dist/config/Config.d.ts +30 -0
  84. package/dist/config/Config.d.ts.map +1 -1
  85. package/dist/config/Config.js +30 -0
  86. package/dist/config/Config.js.map +1 -1
  87. package/dist/config/ConfigurationSchema.d.ts +75 -198
  88. package/dist/config/ConfigurationSchema.d.ts.map +1 -1
  89. package/dist/config/ConfigurationSchema.js +17 -17
  90. package/dist/config/ConfigurationSchema.js.map +1 -1
  91. package/dist/config/ServerConfiguration.d.ts +2 -2
  92. package/dist/config/ServerConfiguration.d.ts.map +1 -1
  93. package/dist/config/ServerConfiguration.js +15 -13
  94. package/dist/config/ServerConfiguration.js.map +1 -1
  95. package/dist/config/index.d.ts +8 -0
  96. package/dist/config/index.d.ts.map +1 -0
  97. package/dist/config/index.js +11 -0
  98. package/dist/config/index.js.map +1 -0
  99. package/dist/docs/DocumentationGenerator.js +2 -2
  100. package/dist/docs/DocumentationGenerator.js.map +1 -1
  101. package/dist/dxt-entry.js +3 -3
  102. package/dist/dxt-entry.js.map +1 -1
  103. package/dist/index.d.ts +1 -0
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +38 -37
  106. package/dist/index.js.map +1 -1
  107. package/dist/performance/MetricsCollector.d.ts.map +1 -1
  108. package/dist/performance/MetricsCollector.js +5 -4
  109. package/dist/performance/MetricsCollector.js.map +1 -1
  110. package/dist/security/AISecurityScanner.js +7 -7
  111. package/dist/security/AISecurityScanner.js.map +1 -1
  112. package/dist/security/AutomatedRemediation.d.ts.map +1 -1
  113. package/dist/security/AutomatedRemediation.js +11 -11
  114. package/dist/security/AutomatedRemediation.js.map +1 -1
  115. package/dist/security/InputValidator.d.ts +50 -126
  116. package/dist/security/InputValidator.d.ts.map +1 -1
  117. package/dist/security/InputValidator.js +9 -9
  118. package/dist/security/InputValidator.js.map +1 -1
  119. package/dist/security/SecurityCIPipeline.d.ts +47 -5
  120. package/dist/security/SecurityCIPipeline.d.ts.map +1 -1
  121. package/dist/security/SecurityCIPipeline.js +390 -49
  122. package/dist/security/SecurityCIPipeline.js.map +1 -1
  123. package/dist/security/SecurityConfigManager.js +10 -10
  124. package/dist/security/SecurityConfigManager.js.map +1 -1
  125. package/dist/security/SecurityMonitoring.js +4 -4
  126. package/dist/security/SecurityMonitoring.js.map +1 -1
  127. package/dist/security/SecurityReviewer.d.ts.map +1 -1
  128. package/dist/security/SecurityReviewer.js +13 -6
  129. package/dist/security/SecurityReviewer.js.map +1 -1
  130. package/dist/security/index.js +3 -3
  131. package/dist/security/index.js.map +1 -1
  132. package/dist/server/ConnectionTester.js +5 -5
  133. package/dist/server/ConnectionTester.js.map +1 -1
  134. package/dist/server/ToolRegistry.d.ts +2 -2
  135. package/dist/server/ToolRegistry.d.ts.map +1 -1
  136. package/dist/server/ToolRegistry.js +7 -6
  137. package/dist/server/ToolRegistry.js.map +1 -1
  138. package/dist/server/index.d.ts +7 -0
  139. package/dist/server/index.d.ts.map +1 -0
  140. package/dist/server/index.js +9 -0
  141. package/dist/server/index.js.map +1 -0
  142. package/dist/tools/BaseToolManager.d.ts.map +1 -1
  143. package/dist/tools/BaseToolManager.js +11 -11
  144. package/dist/tools/BaseToolManager.js.map +1 -1
  145. package/dist/tools/auth.d.ts.map +1 -1
  146. package/dist/tools/auth.js +7 -7
  147. package/dist/tools/auth.js.map +1 -1
  148. package/dist/tools/comments.d.ts.map +1 -1
  149. package/dist/tools/comments.js +14 -14
  150. package/dist/tools/comments.js.map +1 -1
  151. package/dist/tools/index.d.ts +1 -0
  152. package/dist/tools/index.d.ts.map +1 -1
  153. package/dist/tools/index.js +1 -0
  154. package/dist/tools/index.js.map +1 -1
  155. package/dist/tools/media.d.ts.map +1 -1
  156. package/dist/tools/media.js +14 -11
  157. package/dist/tools/media.js.map +1 -1
  158. package/dist/tools/pages.d.ts.map +1 -1
  159. package/dist/tools/pages.js +12 -12
  160. package/dist/tools/pages.js.map +1 -1
  161. package/dist/tools/performance.d.ts.map +1 -1
  162. package/dist/tools/performance.js +13 -11
  163. package/dist/tools/performance.js.map +1 -1
  164. package/dist/tools/posts/PostHandlers.d.ts.map +1 -1
  165. package/dist/tools/posts/PostHandlers.js +16 -16
  166. package/dist/tools/posts/PostHandlers.js.map +1 -1
  167. package/dist/tools/posts/PostToolDefinitions.d.ts.map +1 -1
  168. package/dist/tools/posts/index.d.ts.map +1 -1
  169. package/dist/tools/seo/BulkOperations.d.ts +113 -0
  170. package/dist/tools/seo/BulkOperations.d.ts.map +1 -0
  171. package/dist/tools/seo/BulkOperations.js +398 -0
  172. package/dist/tools/seo/BulkOperations.js.map +1 -0
  173. package/dist/tools/seo/SEOHandlers.d.ts +55 -0
  174. package/dist/tools/seo/SEOHandlers.d.ts.map +1 -0
  175. package/dist/tools/seo/SEOHandlers.js +255 -0
  176. package/dist/tools/seo/SEOHandlers.js.map +1 -0
  177. package/dist/tools/seo/SEOToolDefinitions.d.ts +59 -0
  178. package/dist/tools/seo/SEOToolDefinitions.d.ts.map +1 -0
  179. package/dist/tools/seo/SEOToolDefinitions.js +385 -0
  180. package/dist/tools/seo/SEOToolDefinitions.js.map +1 -0
  181. package/dist/tools/seo/SEOTools.d.ts +203 -0
  182. package/dist/tools/seo/SEOTools.d.ts.map +1 -0
  183. package/dist/tools/seo/SEOTools.js +708 -0
  184. package/dist/tools/seo/SEOTools.js.map +1 -0
  185. package/dist/tools/seo/analyzers/ContentAnalyzer.d.ts +94 -0
  186. package/dist/tools/seo/analyzers/ContentAnalyzer.d.ts.map +1 -0
  187. package/dist/tools/seo/analyzers/ContentAnalyzer.js +402 -0
  188. package/dist/tools/seo/analyzers/ContentAnalyzer.js.map +1 -0
  189. package/dist/tools/seo/auditors/SiteAuditor.d.ts +121 -0
  190. package/dist/tools/seo/auditors/SiteAuditor.d.ts.map +1 -0
  191. package/dist/tools/seo/auditors/SiteAuditor.js +600 -0
  192. package/dist/tools/seo/auditors/SiteAuditor.js.map +1 -0
  193. package/dist/tools/seo/generators/MetaGenerator.d.ts +128 -0
  194. package/dist/tools/seo/generators/MetaGenerator.d.ts.map +1 -0
  195. package/dist/tools/seo/generators/MetaGenerator.js +547 -0
  196. package/dist/tools/seo/generators/MetaGenerator.js.map +1 -0
  197. package/dist/tools/seo/generators/SchemaGenerator.d.ts +204 -0
  198. package/dist/tools/seo/generators/SchemaGenerator.d.ts.map +1 -0
  199. package/dist/tools/seo/generators/SchemaGenerator.js +670 -0
  200. package/dist/tools/seo/generators/SchemaGenerator.js.map +1 -0
  201. package/dist/tools/seo/index.d.ts +17 -0
  202. package/dist/tools/seo/index.d.ts.map +1 -0
  203. package/dist/tools/seo/index.js +18 -0
  204. package/dist/tools/seo/index.js.map +1 -0
  205. package/dist/tools/seo/optimizers/InternalLinkingSuggester.d.ts +186 -0
  206. package/dist/tools/seo/optimizers/InternalLinkingSuggester.d.ts.map +1 -0
  207. package/dist/tools/seo/optimizers/InternalLinkingSuggester.js +683 -0
  208. package/dist/tools/seo/optimizers/InternalLinkingSuggester.js.map +1 -0
  209. package/dist/tools/site.d.ts.map +1 -1
  210. package/dist/tools/site.js +12 -12
  211. package/dist/tools/site.js.map +1 -1
  212. package/dist/tools/taxonomies.d.ts.map +1 -1
  213. package/dist/tools/taxonomies.js +20 -20
  214. package/dist/tools/taxonomies.js.map +1 -1
  215. package/dist/tools/users.d.ts.map +1 -1
  216. package/dist/tools/users.js +12 -12
  217. package/dist/tools/users.js.map +1 -1
  218. package/dist/types/client.d.ts +8 -6
  219. package/dist/types/client.d.ts.map +1 -1
  220. package/dist/types/client.js.map +1 -1
  221. package/dist/types/seo.d.ts +473 -0
  222. package/dist/types/seo.d.ts.map +1 -0
  223. package/dist/types/seo.js +94 -0
  224. package/dist/types/seo.js.map +1 -0
  225. package/dist/utils/enhancedError.js +1 -1
  226. package/dist/utils/enhancedError.js.map +1 -1
  227. package/dist/utils/error.d.ts.map +1 -1
  228. package/dist/utils/error.js +0 -1
  229. package/dist/utils/error.js.map +1 -1
  230. package/dist/utils/index.d.ts +12 -0
  231. package/dist/utils/index.d.ts.map +1 -0
  232. package/dist/utils/index.js +18 -0
  233. package/dist/utils/index.js.map +1 -0
  234. package/dist/utils/logger.js +3 -3
  235. package/dist/utils/logger.js.map +1 -1
  236. package/dist/utils/toolWrapper.d.ts +2 -2
  237. package/dist/utils/toolWrapper.js +8 -8
  238. package/dist/utils/toolWrapper.js.map +1 -1
  239. package/dist/utils/validation/core.d.ts.map +1 -1
  240. package/dist/utils/validation/core.js.map +1 -1
  241. package/dist/utils/validation/index.d.ts.map +1 -1
  242. package/dist/utils/validation/index.js.map +1 -1
  243. package/dist/utils/validation/network.js +3 -3
  244. package/dist/utils/validation/network.js.map +1 -1
  245. package/dist/utils/validation/rateLimit.js.map +1 -1
  246. package/dist/utils/validation/security.js.map +1 -1
  247. package/dist/utils/validation/wordpress.js.map +1 -1
  248. package/dist/utils/version.d.ts +144 -0
  249. package/dist/utils/version.d.ts.map +1 -0
  250. package/dist/utils/version.js +318 -0
  251. package/dist/utils/version.js.map +1 -0
  252. package/package.json +24 -58
  253. package/src/cache/CacheInvalidation.ts +183 -20
  254. package/src/cache/HttpCacheWrapper.ts +8 -5
  255. package/src/cache/SEOCacheManager.ts +330 -0
  256. package/src/cache/__tests__/CacheInvalidation.test.ts +6 -11
  257. package/src/cache/__tests__/CachedWordPressClient.test.ts +37 -62
  258. package/src/client/SEOWordPressClient.ts +876 -0
  259. package/src/client/api.ts +50 -21
  260. package/src/client/auth.ts +19 -19
  261. package/src/client/index.ts +16 -0
  262. package/src/client/managers/AuthManager.ts +175 -0
  263. package/src/client/managers/AuthenticationManager.ts +16 -14
  264. package/src/client/managers/BaseManager.ts +24 -5
  265. package/src/client/managers/ComposedAuthenticationManager.ts +409 -0
  266. package/src/client/managers/ComposedManagerFactory.ts +231 -0
  267. package/src/client/managers/ComposedRequestManager.ts +336 -0
  268. package/src/client/managers/JWTAuthImplementation.ts +326 -0
  269. package/src/client/managers/ManagersIndex.ts +6 -0
  270. package/src/client/managers/RequestManager.ts +9 -7
  271. package/src/client/managers/composed/MigrationAdapter.ts +263 -0
  272. package/src/client/managers/composed/index.ts +47 -0
  273. package/src/client/managers/implementations/ConfigurationProviderImpl.ts +52 -0
  274. package/src/client/managers/implementations/ErrorHandlerImpl.ts +102 -0
  275. package/src/client/managers/implementations/ParameterValidatorImpl.ts +221 -0
  276. package/src/client/managers/interfaces/ManagerInterfaces.ts +171 -0
  277. package/src/config/Config.ts +63 -0
  278. package/src/config/ConfigurationSchema.ts +17 -17
  279. package/src/config/ServerConfiguration.ts +18 -16
  280. package/src/config/index.ts +13 -0
  281. package/src/docs/DocumentationGenerator.ts +2 -2
  282. package/src/dxt-entry.ts +3 -3
  283. package/src/index.ts +43 -43
  284. package/src/performance/MetricsCollector.ts +15 -11
  285. package/src/security/AISecurityScanner.ts +7 -7
  286. package/src/security/AutomatedRemediation.ts +13 -11
  287. package/src/security/InputValidator.ts +10 -9
  288. package/src/security/SecurityCIPipeline.ts +494 -56
  289. package/src/security/SecurityConfigManager.ts +10 -10
  290. package/src/security/SecurityMonitoring.ts +5 -5
  291. package/src/security/SecurityReviewer.ts +13 -6
  292. package/src/security/index.ts +3 -3
  293. package/src/server/ConnectionTester.ts +5 -5
  294. package/src/server/ToolRegistry.ts +9 -8
  295. package/src/server/index.ts +10 -0
  296. package/src/tools/BaseToolManager.ts +55 -83
  297. package/src/tools/auth.ts +21 -12
  298. package/src/tools/comments.ts +23 -19
  299. package/src/tools/index.ts +1 -0
  300. package/src/tools/media.ts +23 -20
  301. package/src/tools/pages.ts +20 -13
  302. package/src/tools/performance.ts +101 -32
  303. package/src/tools/posts/PostHandlers.ts +23 -23
  304. package/src/tools/posts/PostToolDefinitions.ts +1 -1
  305. package/src/tools/posts/index.ts +2 -2
  306. package/src/tools/seo/BulkOperations.ts +557 -0
  307. package/src/tools/seo/SEOHandlers.ts +296 -0
  308. package/src/tools/seo/SEOToolDefinitions.ts +402 -0
  309. package/src/tools/seo/SEOTools.ts +871 -0
  310. package/src/tools/seo/analyzers/ContentAnalyzer.ts +493 -0
  311. package/src/tools/seo/auditors/SiteAuditor.ts +787 -0
  312. package/src/tools/seo/generators/MetaGenerator.ts +694 -0
  313. package/src/tools/seo/generators/SchemaGenerator.ts +955 -0
  314. package/src/tools/seo/index.ts +47 -0
  315. package/src/tools/seo/optimizers/InternalLinkingSuggester.ts +934 -0
  316. package/src/tools/site.ts +27 -26
  317. package/src/tools/taxonomies.ts +29 -25
  318. package/src/tools/users.ts +20 -13
  319. package/src/types/client.ts +8 -6
  320. package/src/types/seo.ts +546 -0
  321. package/src/utils/enhancedError.ts +1 -1
  322. package/src/utils/error.ts +1 -2
  323. package/src/utils/index.ts +23 -0
  324. package/src/utils/logger.ts +3 -3
  325. package/src/utils/toolWrapper.ts +10 -10
  326. package/src/utils/validation/core.ts +2 -2
  327. package/src/utils/validation/index.ts +2 -2
  328. package/src/utils/validation/network.ts +5 -5
  329. package/src/utils/validation/rateLimit.ts +1 -1
  330. package/src/utils/validation/security.ts +1 -1
  331. package/src/utils/validation/wordpress.ts +1 -1
  332. package/src/utils/version.ts +402 -0
  333. package/src/dxt-entry.cjs +0 -68
@@ -6,7 +6,7 @@
6
6
  * for better maintainability and testing.
7
7
  */
8
8
 
9
- import type { MCPTool } from "../../types/mcp.js";
9
+ import type { MCPTool } from "@/types/mcp.js";
10
10
 
11
11
  /**
12
12
  * Tool definition for listing WordPress posts
@@ -27,8 +27,8 @@
27
27
  * ```
28
28
  */
29
29
 
30
- import { WordPressClient } from "../../client/api.js";
31
- import { CreatePostRequest, PostQueryParams, UpdatePostRequest, WordPressPost } from "../../types/wordpress.js";
30
+ import { WordPressClient } from "@/client/api.js";
31
+ import { CreatePostRequest, PostQueryParams, UpdatePostRequest, WordPressPost } from "@/types/wordpress.js";
32
32
  import { postToolDefinitions } from "./PostToolDefinitions.js";
33
33
  import {
34
34
  handleListPosts,
@@ -0,0 +1,557 @@
1
+ /**
2
+ * Bulk SEO Operations
3
+ *
4
+ * This module provides batch processing capabilities for SEO operations,
5
+ * including metadata updates, content analysis, and schema generation.
6
+ * It supports chunked processing, progress tracking, retry logic, and dry-run mode.
7
+ *
8
+ * @since 2.7.0
9
+ */
10
+
11
+ import { WordPressClient } from "@/client/api.js";
12
+ import { MetaGenerator } from "./generators/MetaGenerator.js";
13
+ import { ContentAnalyzer } from "./analyzers/ContentAnalyzer.js";
14
+ import { SEOCacheManager } from "@/cache/SEOCacheManager.js";
15
+ import { LoggerFactory } from "@/utils/logger.js";
16
+ import { SEOToolParams, BulkOperationResult, SEOAnalysisResult } from "@/types/seo.js";
17
+ import type { WordPressPost } from "@/types/wordpress.js";
18
+
19
+ /**
20
+ * Configuration for bulk operations
21
+ */
22
+ interface BulkOperationConfig {
23
+ /** Number of items per batch */
24
+ batchSize: number;
25
+
26
+ /** Maximum number of retry attempts */
27
+ maxRetries: number;
28
+
29
+ /** Initial delay for exponential backoff (ms) */
30
+ retryDelayMs: number;
31
+
32
+ /** Maximum delay for exponential backoff (ms) */
33
+ maxRetryDelayMs: number;
34
+
35
+ /** Timeout per operation (ms) */
36
+ operationTimeoutMs: number;
37
+
38
+ /** Enable progress callbacks */
39
+ enableProgress: boolean;
40
+ }
41
+
42
+ /**
43
+ * Progress information for bulk operations
44
+ */
45
+ interface BulkProgress {
46
+ /** Total items to process */
47
+ total: number;
48
+
49
+ /** Items processed so far */
50
+ processed: number;
51
+
52
+ /** Items successfully completed */
53
+ completed: number;
54
+
55
+ /** Items that failed */
56
+ failed: number;
57
+
58
+ /** Items that were skipped */
59
+ skipped: number;
60
+
61
+ /** Current batch being processed */
62
+ currentBatch: number;
63
+
64
+ /** Total number of batches */
65
+ totalBatches: number;
66
+
67
+ /** Estimated completion time */
68
+ eta?: Date;
69
+
70
+ /** Average processing time per item (ms) */
71
+ avgProcessingTime: number;
72
+ }
73
+
74
+ /**
75
+ * Error information for failed operations
76
+ */
77
+ interface BulkOperationError {
78
+ /** Post ID that failed */
79
+ postId: number;
80
+
81
+ /** Error message */
82
+ error: string;
83
+
84
+ /** Retry attempt count */
85
+ attempts: number;
86
+
87
+ /** Whether this error is retryable */
88
+ retryable: boolean;
89
+ }
90
+
91
+ /**
92
+ * Type for progress callback function
93
+ */
94
+ type ProgressCallback = (progress: BulkProgress) => void;
95
+
96
+ /**
97
+ * Bulk SEO Operations Manager
98
+ */
99
+ export class BulkOperations {
100
+ private logger = LoggerFactory.tool("bulk_operations");
101
+ private config: BulkOperationConfig;
102
+ private metaGenerator: MetaGenerator;
103
+ private contentAnalyzer: ContentAnalyzer;
104
+ private cacheManager: SEOCacheManager | undefined;
105
+
106
+ constructor(
107
+ private client: WordPressClient,
108
+ cacheManager?: SEOCacheManager,
109
+ config?: Partial<BulkOperationConfig>,
110
+ ) {
111
+ this.cacheManager = cacheManager;
112
+ this.metaGenerator = new MetaGenerator();
113
+ this.contentAnalyzer = new ContentAnalyzer();
114
+
115
+ // Default configuration
116
+ this.config = {
117
+ batchSize: 10,
118
+ maxRetries: 3,
119
+ retryDelayMs: 1000,
120
+ maxRetryDelayMs: 30000,
121
+ operationTimeoutMs: 60000,
122
+ enableProgress: true,
123
+ ...config,
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Bulk update metadata for multiple posts
129
+ */
130
+ async bulkUpdateMetadata(params: SEOToolParams, progressCallback?: ProgressCallback): Promise<BulkOperationResult> {
131
+ const startTime = Date.now();
132
+ this.logger.info("Starting bulk metadata update", {
133
+ postIds: params.postIds?.length,
134
+ dryRun: params.dryRun,
135
+ batchSize: this.config.batchSize,
136
+ });
137
+
138
+ if (!params.postIds?.length) {
139
+ throw new Error("No post IDs provided for bulk operation");
140
+ }
141
+
142
+ const progress: BulkProgress = {
143
+ total: params.postIds.length,
144
+ processed: 0,
145
+ completed: 0,
146
+ failed: 0,
147
+ skipped: 0,
148
+ currentBatch: 0,
149
+ totalBatches: Math.ceil(params.postIds.length / this.config.batchSize),
150
+ avgProcessingTime: 0,
151
+ };
152
+
153
+ const errors: BulkOperationError[] = [];
154
+ const batches = this.createBatches(params.postIds, this.config.batchSize);
155
+
156
+ // Process each batch
157
+ for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
158
+ const batch = batches[batchIndex];
159
+ progress.currentBatch = batchIndex + 1;
160
+
161
+ this.logger.debug(`Processing batch ${progress.currentBatch}/${progress.totalBatches}`, {
162
+ batchSize: batch.length,
163
+ postIds: batch,
164
+ });
165
+
166
+ // Process batch items
167
+ await Promise.all(
168
+ batch.map(async (postId) => {
169
+ const itemStartTime = Date.now();
170
+
171
+ try {
172
+ await this.processMetadataUpdate(postId, params);
173
+ progress.completed++;
174
+
175
+ // Update average processing time
176
+ const processingTime = Date.now() - itemStartTime;
177
+ progress.avgProcessingTime =
178
+ (progress.avgProcessingTime * progress.processed + processingTime) / (progress.processed + 1);
179
+ } catch (_error) {
180
+ const bulkError: BulkOperationError = {
181
+ postId,
182
+ error: _error instanceof Error ? _error.message : String(_error),
183
+ attempts: 1,
184
+ retryable: this.isRetryableError(_error),
185
+ };
186
+
187
+ // Attempt retries
188
+ if (bulkError.retryable) {
189
+ const retryResult = await this.retryOperation(
190
+ () => this.processMetadataUpdate(postId, params),
191
+ bulkError,
192
+ );
193
+
194
+ if (retryResult.success) {
195
+ progress.completed++;
196
+ } else {
197
+ progress.failed++;
198
+ errors.push(retryResult.error);
199
+ }
200
+ } else {
201
+ progress.failed++;
202
+ errors.push(bulkError);
203
+ }
204
+ }
205
+
206
+ progress.processed++;
207
+ }),
208
+ );
209
+
210
+ // Calculate ETA
211
+ if (progress.avgProcessingTime > 0 && progress.processed < progress.total) {
212
+ const remainingItems = progress.total - progress.processed;
213
+ const etaMs = remainingItems * progress.avgProcessingTime;
214
+ progress.eta = new Date(Date.now() + etaMs);
215
+ } else if (progress.processed > 0 && progress.processed < progress.total) {
216
+ // Fallback ETA calculation even with minimal processing time
217
+ const remainingItems = progress.total - progress.processed;
218
+ const averageTime = progress.avgProcessingTime || 100; // Fallback to 100ms
219
+ const etaMs = remainingItems * averageTime;
220
+ progress.eta = new Date(Date.now() + etaMs);
221
+ }
222
+
223
+ // Call progress callback
224
+ if (progressCallback && this.config.enableProgress) {
225
+ progressCallback(progress);
226
+ }
227
+
228
+ // Small delay between batches to avoid overwhelming the server
229
+ if (batchIndex < batches.length - 1) {
230
+ await this.delay(100);
231
+ }
232
+ }
233
+
234
+ const result: BulkOperationResult = {
235
+ total: params.postIds.length,
236
+ success: progress.completed,
237
+ failed: progress.failed,
238
+ skipped: progress.skipped,
239
+ errors: errors.map((e) => ({ postId: e.postId, error: e.error })),
240
+ processingTime: Date.now() - startTime,
241
+ dryRun: params.dryRun || false,
242
+ };
243
+
244
+ this.logger.info("Bulk metadata update completed", {
245
+ ...result,
246
+ successRate: ((result.success / result.total) * 100).toFixed(1) + "%",
247
+ });
248
+
249
+ return result;
250
+ }
251
+
252
+ /**
253
+ * Bulk analyze content for multiple posts
254
+ */
255
+ async bulkAnalyzeContent(
256
+ params: SEOToolParams,
257
+ progressCallback?: ProgressCallback,
258
+ ): Promise<{ results: SEOAnalysisResult[]; summary: BulkOperationResult }> {
259
+ const startTime = Date.now();
260
+ this.logger.info("Starting bulk content analysis", {
261
+ postIds: params.postIds?.length,
262
+ analysisType: params.analysisType,
263
+ batchSize: this.config.batchSize,
264
+ });
265
+
266
+ if (!params.postIds?.length) {
267
+ throw new Error("No post IDs provided for bulk analysis");
268
+ }
269
+
270
+ const results: SEOAnalysisResult[] = [];
271
+ const progress: BulkProgress = {
272
+ total: params.postIds.length,
273
+ processed: 0,
274
+ completed: 0,
275
+ failed: 0,
276
+ skipped: 0,
277
+ currentBatch: 0,
278
+ totalBatches: Math.ceil(params.postIds.length / this.config.batchSize),
279
+ avgProcessingTime: 0,
280
+ };
281
+
282
+ const errors: BulkOperationError[] = [];
283
+ const batches = this.createBatches(params.postIds, this.config.batchSize);
284
+
285
+ // Process each batch
286
+ for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
287
+ const batch = batches[batchIndex];
288
+ progress.currentBatch = batchIndex + 1;
289
+
290
+ // Process batch items
291
+ await Promise.all(
292
+ batch.map(async (postId) => {
293
+ const itemStartTime = Date.now();
294
+
295
+ try {
296
+ const analysisResult = await this.processContentAnalysis(postId, params);
297
+ results.push(analysisResult);
298
+ progress.completed++;
299
+
300
+ // Update average processing time
301
+ const processingTime = Date.now() - itemStartTime;
302
+ progress.avgProcessingTime =
303
+ (progress.avgProcessingTime * progress.processed + processingTime) / (progress.processed + 1);
304
+ } catch (_error) {
305
+ const bulkError: BulkOperationError = {
306
+ postId,
307
+ error: _error instanceof Error ? _error.message : String(_error),
308
+ attempts: 1,
309
+ retryable: this.isRetryableError(_error),
310
+ };
311
+
312
+ // Attempt retries for analysis
313
+ if (bulkError.retryable) {
314
+ const retryResult = await this.retryOperation(
315
+ () => this.processContentAnalysis(postId, params),
316
+ bulkError,
317
+ );
318
+
319
+ if (retryResult.success) {
320
+ results.push(retryResult.result!);
321
+ progress.completed++;
322
+ } else {
323
+ progress.failed++;
324
+ errors.push(retryResult.error);
325
+ }
326
+ } else {
327
+ progress.failed++;
328
+ errors.push(bulkError);
329
+ }
330
+ }
331
+
332
+ progress.processed++;
333
+ }),
334
+ );
335
+
336
+ // Call progress callback
337
+ if (progressCallback && this.config.enableProgress) {
338
+ progressCallback(progress);
339
+ }
340
+ }
341
+
342
+ const summary: BulkOperationResult = {
343
+ total: params.postIds.length,
344
+ success: progress.completed,
345
+ failed: progress.failed,
346
+ skipped: progress.skipped,
347
+ errors: errors.map((e) => ({ postId: e.postId, error: e.error })),
348
+ processingTime: Date.now() - startTime,
349
+ dryRun: false,
350
+ };
351
+
352
+ this.logger.info("Bulk content analysis completed", {
353
+ ...summary,
354
+ resultsCount: results.length,
355
+ avgScore: results.length > 0 ? (results.reduce((sum, r) => sum + r.score, 0) / results.length).toFixed(1) : 0,
356
+ });
357
+
358
+ return { results, summary };
359
+ }
360
+
361
+ /**
362
+ * Process metadata update for a single post
363
+ */
364
+ private async processMetadataUpdate(postId: number, params: SEOToolParams): Promise<void> {
365
+ // Check cache first
366
+ const cacheKey = `bulk-meta-${postId}`;
367
+ if (this.cacheManager && !params.force) {
368
+ const cached = this.cacheManager.get(cacheKey);
369
+ if (cached) {
370
+ this.logger.debug("Using cached metadata", { postId });
371
+ return;
372
+ }
373
+ }
374
+
375
+ // Fetch post data
376
+ const post = await this.client.getPost(postId);
377
+ if (!post) {
378
+ throw new Error(`Post ${postId} not found`);
379
+ }
380
+
381
+ // Generate metadata
382
+ const metadataParams = {
383
+ postId,
384
+ ...(params.focusKeywords && { focusKeywords: params.focusKeywords }),
385
+ ...(params.site && { site: params.site }),
386
+ };
387
+ const metadata = await this.metaGenerator.generateMetadata(post, metadataParams);
388
+
389
+ if (!params.dryRun) {
390
+ // Apply updates to WordPress (this would need actual WordPress API calls)
391
+ // For now, we just simulate the update
392
+ this.logger.debug("Applying metadata updates", {
393
+ postId,
394
+ titleLength: metadata.title.length,
395
+ descriptionLength: metadata.description.length,
396
+ });
397
+
398
+ // In a real implementation, you would call:
399
+ // await this.client.updatePost(postId, { meta: metadata });
400
+ }
401
+
402
+ // Cache the result
403
+ if (this.cacheManager) {
404
+ this.cacheManager.set(cacheKey, metadata, 3600); // 1 hour
405
+ }
406
+ }
407
+
408
+ /**
409
+ * Process content analysis for a single post
410
+ */
411
+ private async processContentAnalysis(postId: number, params: SEOToolParams): Promise<SEOAnalysisResult> {
412
+ // Check cache first
413
+ const cacheKey = `bulk-analysis-${postId}-${params.analysisType || "full"}`;
414
+ if (this.cacheManager && !params.force) {
415
+ const cached = this.cacheManager.get(cacheKey);
416
+ if (cached) {
417
+ this.logger.debug("Using cached analysis", { postId });
418
+ return cached as SEOAnalysisResult;
419
+ }
420
+ }
421
+
422
+ // Fetch post data
423
+ const post = await this.client.getPost(postId);
424
+ if (!post) {
425
+ throw new Error(`Post ${postId} not found`);
426
+ }
427
+
428
+ // Analyze content
429
+ const analysisParams = {
430
+ postId,
431
+ analysisType: params.analysisType || ("full" as const),
432
+ ...(params.site && { site: params.site }),
433
+ ...(params.focusKeywords && { focusKeywords: params.focusKeywords }),
434
+ };
435
+ const analysisResult = await this.contentAnalyzer.analyzePost(post as WordPressPost, analysisParams);
436
+
437
+ // Cache the result
438
+ if (this.cacheManager) {
439
+ this.cacheManager.set(cacheKey, analysisResult, 21600); // 6 hours
440
+ }
441
+
442
+ return analysisResult;
443
+ }
444
+
445
+ /**
446
+ * Retry operation with exponential backoff
447
+ */
448
+ private async retryOperation<T>(
449
+ operation: () => Promise<T>,
450
+ error: BulkOperationError,
451
+ ): Promise<{ success: boolean; result?: T; error: BulkOperationError }> {
452
+ let delay = this.config.retryDelayMs;
453
+
454
+ for (let attempt = 2; attempt <= this.config.maxRetries + 1; attempt++) {
455
+ await this.delay(delay);
456
+
457
+ try {
458
+ const result = await operation();
459
+ this.logger.debug("Retry successful", {
460
+ postId: error.postId,
461
+ attempt,
462
+ delay,
463
+ });
464
+
465
+ return { success: true, result, error };
466
+ } catch (retryError) {
467
+ error.attempts = attempt;
468
+ error.error = retryError instanceof Error ? retryError.message : String(retryError);
469
+
470
+ // Exponential backoff
471
+ delay = Math.min(delay * 2, this.config.maxRetryDelayMs);
472
+
473
+ this.logger.debug("Retry failed", {
474
+ postId: error.postId,
475
+ attempt,
476
+ error: error.error,
477
+ nextDelay: delay,
478
+ });
479
+ }
480
+ }
481
+
482
+ return { success: false, error };
483
+ }
484
+
485
+ /**
486
+ * Check if an error is retryable
487
+ */
488
+ private isRetryableError(error: unknown): boolean {
489
+ if (!error) return false;
490
+
491
+ const errorMessage = error instanceof Error ? error.message : String(error);
492
+
493
+ // Network errors are retryable
494
+ if (
495
+ errorMessage.includes("ECONNREFUSED") ||
496
+ errorMessage.includes("timeout") ||
497
+ errorMessage.includes("503") ||
498
+ errorMessage.includes("502") ||
499
+ errorMessage.includes("504")
500
+ ) {
501
+ return true;
502
+ }
503
+
504
+ // Authentication errors are not retryable
505
+ if (errorMessage.includes("401") || errorMessage.includes("403")) {
506
+ return false;
507
+ }
508
+
509
+ // Not found errors are not retryable
510
+ if (errorMessage.includes("404")) {
511
+ return false;
512
+ }
513
+
514
+ // Rate limiting is retryable
515
+ if (errorMessage.includes("429")) {
516
+ return true;
517
+ }
518
+
519
+ // Default to non-retryable for safety
520
+ return false;
521
+ }
522
+
523
+ /**
524
+ * Create batches from an array of items
525
+ */
526
+ private createBatches<T>(items: T[], batchSize: number): T[][] {
527
+ const batches: T[][] = [];
528
+
529
+ for (let i = 0; i < items.length; i += batchSize) {
530
+ batches.push(items.slice(i, i + batchSize));
531
+ }
532
+
533
+ return batches;
534
+ }
535
+
536
+ /**
537
+ * Promise-based delay utility
538
+ */
539
+ private delay(ms: number): Promise<void> {
540
+ return new Promise((resolve) => setTimeout(resolve, ms));
541
+ }
542
+
543
+ /**
544
+ * Get current configuration
545
+ */
546
+ getConfig(): BulkOperationConfig {
547
+ return { ...this.config };
548
+ }
549
+
550
+ /**
551
+ * Update configuration
552
+ */
553
+ updateConfig(config: Partial<BulkOperationConfig>): void {
554
+ this.config = { ...this.config, ...config };
555
+ this.logger.debug("Configuration updated", { config: this.config });
556
+ }
557
+ }