mcp-wordpress 1.1.7 → 1.2.2
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 +388 -66
- package/dist/cache/CacheInvalidation.d.ts +118 -0
- package/dist/cache/CacheInvalidation.d.ts.map +1 -0
- package/dist/cache/CacheInvalidation.js +349 -0
- package/dist/cache/CacheInvalidation.js.map +1 -0
- package/dist/cache/CacheManager.d.ts +143 -0
- package/dist/cache/CacheManager.d.ts.map +1 -0
- package/dist/cache/CacheManager.js +308 -0
- package/dist/cache/CacheManager.js.map +1 -0
- package/dist/cache/HttpCacheWrapper.d.ts +121 -0
- package/dist/cache/HttpCacheWrapper.d.ts.map +1 -0
- package/dist/cache/HttpCacheWrapper.js +280 -0
- package/dist/cache/HttpCacheWrapper.js.map +1 -0
- package/dist/cache/__tests__/CacheInvalidation.test.d.ts +5 -0
- package/dist/cache/__tests__/CacheInvalidation.test.d.ts.map +1 -0
- package/dist/cache/__tests__/CacheInvalidation.test.js +236 -0
- package/dist/cache/__tests__/CacheInvalidation.test.js.map +1 -0
- package/dist/cache/__tests__/CacheManager.test.d.ts +5 -0
- package/dist/cache/__tests__/CacheManager.test.d.ts.map +1 -0
- package/dist/cache/__tests__/CacheManager.test.js +233 -0
- package/dist/cache/__tests__/CacheManager.test.js.map +1 -0
- package/dist/cache/__tests__/CachedWordPressClient.test.d.ts +5 -0
- package/dist/cache/__tests__/CachedWordPressClient.test.d.ts.map +1 -0
- package/dist/cache/__tests__/CachedWordPressClient.test.js +228 -0
- package/dist/cache/__tests__/CachedWordPressClient.test.js.map +1 -0
- package/dist/cache/__tests__/HttpCacheWrapper.test.d.ts +5 -0
- package/dist/cache/__tests__/HttpCacheWrapper.test.d.ts.map +1 -0
- package/dist/cache/__tests__/HttpCacheWrapper.test.js +296 -0
- package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -0
- package/dist/cache/index.d.ts +12 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +9 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/client/CachedWordPressClient.d.ts +160 -0
- package/dist/client/CachedWordPressClient.d.ts.map +1 -0
- package/dist/client/CachedWordPressClient.js +338 -0
- package/dist/client/CachedWordPressClient.js.map +1 -0
- package/dist/client/WordPressClient.d.ts +81 -0
- package/dist/client/WordPressClient.d.ts.map +1 -0
- package/dist/client/WordPressClient.js +354 -0
- package/dist/client/WordPressClient.js.map +1 -0
- package/dist/config/ConfigurationSchema.d.ts +281 -0
- package/dist/config/ConfigurationSchema.d.ts.map +1 -0
- package/dist/config/ConfigurationSchema.js +205 -0
- package/dist/config/ConfigurationSchema.js.map +1 -0
- package/dist/config/ServerConfiguration.d.ts +38 -0
- package/dist/config/ServerConfiguration.d.ts.map +1 -0
- package/dist/config/ServerConfiguration.js +158 -0
- package/dist/config/ServerConfiguration.js.map +1 -0
- package/dist/docs/DocumentationGenerator.d.ts +184 -0
- package/dist/docs/DocumentationGenerator.d.ts.map +1 -0
- package/dist/docs/DocumentationGenerator.js +735 -0
- package/dist/docs/DocumentationGenerator.js.map +1 -0
- package/dist/docs/MarkdownFormatter.d.ts +84 -0
- package/dist/docs/MarkdownFormatter.d.ts.map +1 -0
- package/dist/docs/MarkdownFormatter.js +448 -0
- package/dist/docs/MarkdownFormatter.js.map +1 -0
- package/dist/docs/index.d.ts +8 -0
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +7 -0
- package/dist/docs/index.js.map +1 -0
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -212
- package/dist/index.js.map +1 -1
- package/dist/performance/AnomalyDetector.d.ts +63 -0
- package/dist/performance/AnomalyDetector.d.ts.map +1 -0
- package/dist/performance/AnomalyDetector.js +222 -0
- package/dist/performance/AnomalyDetector.js.map +1 -0
- package/dist/performance/BenchmarkAnalyzer.d.ts +67 -0
- package/dist/performance/BenchmarkAnalyzer.d.ts.map +1 -0
- package/dist/performance/BenchmarkAnalyzer.js +301 -0
- package/dist/performance/BenchmarkAnalyzer.js.map +1 -0
- package/dist/performance/MetricsCollector.d.ts +139 -0
- package/dist/performance/MetricsCollector.d.ts.map +1 -0
- package/dist/performance/MetricsCollector.js +320 -0
- package/dist/performance/MetricsCollector.js.map +1 -0
- package/dist/performance/PerformanceAnalytics.d.ts +162 -0
- package/dist/performance/PerformanceAnalytics.d.ts.map +1 -0
- package/dist/performance/PerformanceAnalytics.js +554 -0
- package/dist/performance/PerformanceAnalytics.js.map +1 -0
- package/dist/performance/PerformanceMonitor.d.ts +202 -0
- package/dist/performance/PerformanceMonitor.d.ts.map +1 -0
- package/dist/performance/PerformanceMonitor.js +478 -0
- package/dist/performance/PerformanceMonitor.js.map +1 -0
- package/dist/performance/TrendAnalyzer.d.ts +69 -0
- package/dist/performance/TrendAnalyzer.d.ts.map +1 -0
- package/dist/performance/TrendAnalyzer.js +203 -0
- package/dist/performance/TrendAnalyzer.js.map +1 -0
- package/dist/performance/index.d.ts +11 -0
- package/dist/performance/index.d.ts.map +1 -0
- package/dist/performance/index.js +8 -0
- package/dist/performance/index.js.map +1 -0
- package/dist/security/InputValidator.d.ts +215 -0
- package/dist/security/InputValidator.d.ts.map +1 -0
- package/dist/security/InputValidator.js +278 -0
- package/dist/security/InputValidator.js.map +1 -0
- package/dist/security/SecurityConfig.d.ts +129 -0
- package/dist/security/SecurityConfig.d.ts.map +1 -0
- package/dist/security/SecurityConfig.js +262 -0
- package/dist/security/SecurityConfig.js.map +1 -0
- package/dist/server/ConnectionTester.d.ts +24 -0
- package/dist/server/ConnectionTester.d.ts.map +1 -0
- package/dist/server/ConnectionTester.js +61 -0
- package/dist/server/ConnectionTester.js.map +1 -0
- package/dist/server/ToolRegistry.d.ts +46 -0
- package/dist/server/ToolRegistry.d.ts.map +1 -0
- package/dist/server/ToolRegistry.js +148 -0
- package/dist/server/ToolRegistry.js.map +1 -0
- package/dist/tools/BaseToolClass.d.ts +76 -0
- package/dist/tools/BaseToolClass.d.ts.map +1 -0
- package/dist/tools/BaseToolClass.js +104 -0
- package/dist/tools/BaseToolClass.js.map +1 -0
- package/dist/tools/BaseToolManager.d.ts +26 -0
- package/dist/tools/BaseToolManager.d.ts.map +1 -0
- package/dist/tools/BaseToolManager.js +56 -0
- package/dist/tools/BaseToolManager.js.map +1 -0
- package/dist/tools/base.d.ts +37 -0
- package/dist/tools/base.d.ts.map +1 -0
- package/dist/tools/base.js +60 -0
- package/dist/tools/base.js.map +1 -0
- package/dist/tools/cache.d.ts +260 -0
- package/dist/tools/cache.d.ts.map +1 -0
- package/dist/tools/cache.js +237 -0
- package/dist/tools/cache.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/performance.d.ts +63 -0
- package/dist/tools/performance.d.ts.map +1 -0
- package/dist/tools/performance.js +865 -0
- package/dist/tools/performance.js.map +1 -0
- package/dist/types/client.d.ts +1 -0
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/client.js.map +1 -1
- package/dist/utils/toolWrapper.d.ts +4 -0
- package/dist/utils/toolWrapper.d.ts.map +1 -1
- package/dist/utils/toolWrapper.js +11 -0
- package/dist/utils/toolWrapper.js.map +1 -1
- package/dist/utils/validation.d.ts +68 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +185 -0
- package/dist/utils/validation.js.map +1 -0
- package/docs/CACHING.md +340 -0
- package/docs/DOCKER.md +451 -0
- package/docs/PERFORMANCE_MONITORING.md +471 -0
- package/docs/SECURITY_TESTING.md +393 -0
- package/docs/api/README.md +200 -0
- package/docs/api/categories/auth.md +40 -0
- package/docs/api/categories/cache.md +41 -0
- package/docs/api/categories/comment.md +44 -0
- package/docs/api/categories/media.md +43 -0
- package/docs/api/categories/page.md +43 -0
- package/docs/api/categories/performance.md +44 -0
- package/docs/api/categories/post.md +43 -0
- package/docs/api/categories/site.md +43 -0
- package/docs/api/categories/taxonomy.md +47 -0
- package/docs/api/categories/user.md +43 -0
- package/docs/api/openapi.json +3305 -0
- package/docs/api/summary.json +12 -0
- package/docs/api/tools/wp_approve_comment.md +98 -0
- package/docs/api/tools/wp_cache_clear.md +120 -0
- package/docs/api/tools/wp_cache_info.md +119 -0
- package/docs/api/tools/wp_cache_stats.md +119 -0
- package/docs/api/tools/wp_cache_warm.md +119 -0
- package/docs/api/tools/wp_create_application_password.md +102 -0
- package/docs/api/tools/wp_create_category.md +102 -0
- package/docs/api/tools/wp_create_comment.md +128 -0
- package/docs/api/tools/wp_create_page.md +135 -0
- package/docs/api/tools/wp_create_post.md +147 -0
- package/docs/api/tools/wp_create_tag.md +101 -0
- package/docs/api/tools/wp_create_user.md +135 -0
- package/docs/api/tools/wp_delete_application_password.md +101 -0
- package/docs/api/tools/wp_delete_category.md +100 -0
- package/docs/api/tools/wp_delete_comment.md +101 -0
- package/docs/api/tools/wp_delete_media.md +108 -0
- package/docs/api/tools/wp_delete_page.md +108 -0
- package/docs/api/tools/wp_delete_post.md +117 -0
- package/docs/api/tools/wp_delete_tag.md +100 -0
- package/docs/api/tools/wp_delete_user.md +108 -0
- package/docs/api/tools/wp_get_application_passwords.md +103 -0
- package/docs/api/tools/wp_get_auth_status.md +101 -0
- package/docs/api/tools/wp_get_category.md +103 -0
- package/docs/api/tools/wp_get_comment.md +103 -0
- package/docs/api/tools/wp_get_current_user.md +101 -0
- package/docs/api/tools/wp_get_media.md +103 -0
- package/docs/api/tools/wp_get_page.md +103 -0
- package/docs/api/tools/wp_get_page_revisions.md +103 -0
- package/docs/api/tools/wp_get_post.md +112 -0
- package/docs/api/tools/wp_get_post_revisions.md +103 -0
- package/docs/api/tools/wp_get_site_settings.md +108 -0
- package/docs/api/tools/wp_get_tag.md +103 -0
- package/docs/api/tools/wp_get_user.md +103 -0
- package/docs/api/tools/wp_list_categories.md +111 -0
- package/docs/api/tools/wp_list_comments.md +111 -0
- package/docs/api/tools/wp_list_media.md +145 -0
- package/docs/api/tools/wp_list_pages.md +145 -0
- package/docs/api/tools/wp_list_posts.md +156 -0
- package/docs/api/tools/wp_list_tags.md +110 -0
- package/docs/api/tools/wp_list_users.md +111 -0
- package/docs/api/tools/wp_performance_alerts.md +162 -0
- package/docs/api/tools/wp_performance_benchmark.md +160 -0
- package/docs/api/tools/wp_performance_export.md +162 -0
- package/docs/api/tools/wp_performance_history.md +161 -0
- package/docs/api/tools/wp_performance_optimize.md +162 -0
- package/docs/api/tools/wp_performance_stats.md +160 -0
- package/docs/api/tools/wp_search_site.md +99 -0
- package/docs/api/tools/wp_spam_comment.md +98 -0
- package/docs/api/tools/wp_switch_auth_method.md +122 -0
- package/docs/api/tools/wp_test_auth.md +96 -0
- package/docs/api/tools/wp_update_category.md +102 -0
- package/docs/api/tools/wp_update_comment.md +127 -0
- package/docs/api/tools/wp_update_media.md +129 -0
- package/docs/api/tools/wp_update_page.md +135 -0
- package/docs/api/tools/wp_update_post.md +144 -0
- package/docs/api/tools/wp_update_site_settings.md +127 -0
- package/docs/api/tools/wp_update_tag.md +102 -0
- package/docs/api/tools/wp_update_user.md +134 -0
- package/docs/api/tools/wp_upload_media.md +131 -0
- package/docs/api/types/WordPressPost.md +39 -0
- package/docs/contract-testing.md +183 -0
- package/docs/developer/NPM_AUTH_SETUP.md +3 -3
- package/docs/wordpress-rest-api-authentication-troubleshooting.md +218 -0
- package/package.json +84 -64
- package/src/cache/CacheInvalidation.ts +421 -0
- package/src/cache/CacheManager.ts +391 -0
- package/src/cache/HttpCacheWrapper.ts +372 -0
- package/src/cache/__tests__/CacheInvalidation.test.ts +299 -0
- package/src/cache/__tests__/CacheManager.test.ts +300 -0
- package/src/cache/__tests__/CachedWordPressClient.test.ts +304 -0
- package/src/cache/__tests__/HttpCacheWrapper.test.ts +359 -0
- package/src/cache/index.ts +26 -0
- package/src/client/CachedWordPressClient.ts +442 -0
- package/src/config/ConfigurationSchema.ts +246 -0
- package/src/config/ServerConfiguration.ts +215 -0
- package/src/docs/DocumentationGenerator.ts +952 -0
- package/src/docs/MarkdownFormatter.ts +494 -0
- package/src/docs/index.ts +21 -0
- package/src/index.ts +14 -274
- package/src/performance/MetricsCollector.ts +447 -0
- package/src/performance/PerformanceAnalytics.ts +762 -0
- package/src/performance/PerformanceMonitor.ts +649 -0
- package/src/performance/index.ts +28 -0
- package/src/security/InputValidator.ts +319 -0
- package/src/security/SecurityConfig.ts +301 -0
- package/src/server/ConnectionTester.ts +74 -0
- package/src/server/ToolRegistry.ts +194 -0
- package/src/tools/BaseToolManager.ts +66 -0
- package/src/tools/cache.ts +259 -0
- package/src/tools/index.ts +2 -0
- package/src/tools/performance.ts +948 -0
- package/src/types/client.ts +1 -0
- package/src/utils/toolWrapper.ts +11 -0
- package/src/utils/validation.ts +259 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Contract Testing with Live WordPress
|
|
2
|
+
|
|
3
|
+
This guide explains how to run contract tests against a live WordPress instance using the automated testing setup.
|
|
4
|
+
|
|
5
|
+
## 🚀 Quick Start (Automated)
|
|
6
|
+
|
|
7
|
+
The easiest way to test against a live WordPress instance:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm run test:contracts:live
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This command will:
|
|
14
|
+
1. 🐳 Start isolated WordPress + MySQL containers (port 8081)
|
|
15
|
+
2. ⚙️ Auto-configure WordPress with test data
|
|
16
|
+
3. 🧪 Run contract tests against the live instance
|
|
17
|
+
4. 🧹 Clean up automatically when done
|
|
18
|
+
|
|
19
|
+
**No conflicts with existing services** - uses isolated Docker containers with different ports.
|
|
20
|
+
|
|
21
|
+
## 📋 What the Automated Setup Includes
|
|
22
|
+
|
|
23
|
+
### WordPress Configuration
|
|
24
|
+
- **URL**: `http://localhost:8081`
|
|
25
|
+
- **Admin User**: `testuser` / `test-password-123`
|
|
26
|
+
- **App Password**: Auto-generated for API access
|
|
27
|
+
- **Test Content**: Pre-created posts and media for testing
|
|
28
|
+
|
|
29
|
+
### Docker Services
|
|
30
|
+
- **WordPress**: Latest WordPress with auto-setup
|
|
31
|
+
- **MySQL**: 8.0 with optimized configuration
|
|
32
|
+
- **WP-CLI**: For automated WordPress configuration
|
|
33
|
+
|
|
34
|
+
### Network Isolation
|
|
35
|
+
- Uses separate Docker network: `wordpress-test-network`
|
|
36
|
+
- Port 8081 (different from main development environment)
|
|
37
|
+
- Isolated volumes: `wordpress_test_data`, `db_test_data`
|
|
38
|
+
|
|
39
|
+
## 🔧 Manual Setup (Alternative)
|
|
40
|
+
|
|
41
|
+
If you prefer manual setup or need custom configuration:
|
|
42
|
+
|
|
43
|
+
### 1. Start Services
|
|
44
|
+
```bash
|
|
45
|
+
docker-compose -f docker-compose.test.yml up -d
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Check Status
|
|
49
|
+
```bash
|
|
50
|
+
docker-compose -f docker-compose.test.yml ps
|
|
51
|
+
docker-compose -f docker-compose.test.yml logs -f wordpress-test
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 3. Access WordPress
|
|
55
|
+
- WordPress: http://localhost:8081
|
|
56
|
+
- Admin Panel: http://localhost:8081/wp-admin
|
|
57
|
+
|
|
58
|
+
### 4. Run Tests
|
|
59
|
+
```bash
|
|
60
|
+
# Set environment variables
|
|
61
|
+
export WORDPRESS_TEST_URL="http://localhost:8081"
|
|
62
|
+
export WORDPRESS_USERNAME="testuser"
|
|
63
|
+
export WORDPRESS_APP_PASSWORD="your-app-password"
|
|
64
|
+
export PACT_LIVE_TESTING="true"
|
|
65
|
+
|
|
66
|
+
# Run contract tests
|
|
67
|
+
npm run test:contracts
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 5. Cleanup
|
|
71
|
+
```bash
|
|
72
|
+
docker-compose -f docker-compose.test.yml down -v
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 🧪 Test Modes
|
|
76
|
+
|
|
77
|
+
### Mock Testing (Default)
|
|
78
|
+
```bash
|
|
79
|
+
npm run test:contracts
|
|
80
|
+
```
|
|
81
|
+
- Uses Pact mock provider
|
|
82
|
+
- No external dependencies
|
|
83
|
+
- Fast execution
|
|
84
|
+
- Good for CI/CD
|
|
85
|
+
|
|
86
|
+
### Live Testing
|
|
87
|
+
```bash
|
|
88
|
+
npm run test:contracts:live
|
|
89
|
+
```
|
|
90
|
+
- Tests against real WordPress
|
|
91
|
+
- Validates actual API behavior
|
|
92
|
+
- Comprehensive integration testing
|
|
93
|
+
- Auto-setup and cleanup
|
|
94
|
+
|
|
95
|
+
## 📊 Test Coverage
|
|
96
|
+
|
|
97
|
+
The contract tests verify:
|
|
98
|
+
|
|
99
|
+
### ✅ Posts API
|
|
100
|
+
- Create posts with proper structure
|
|
101
|
+
- Retrieve posts with pagination
|
|
102
|
+
- Response format validation
|
|
103
|
+
|
|
104
|
+
### ✅ Media API
|
|
105
|
+
- File upload handling
|
|
106
|
+
- Multipart form data
|
|
107
|
+
- Media library integration
|
|
108
|
+
|
|
109
|
+
### ✅ Users API
|
|
110
|
+
- User information retrieval
|
|
111
|
+
- Authentication validation
|
|
112
|
+
- Permission handling
|
|
113
|
+
|
|
114
|
+
### ✅ Authentication
|
|
115
|
+
- App password authentication
|
|
116
|
+
- Authorization headers
|
|
117
|
+
- Error handling
|
|
118
|
+
|
|
119
|
+
## 🛠️ Troubleshooting
|
|
120
|
+
|
|
121
|
+
### Port Already in Use
|
|
122
|
+
```bash
|
|
123
|
+
# Check what's using port 8081
|
|
124
|
+
lsof -i :8081
|
|
125
|
+
|
|
126
|
+
# Kill process if needed
|
|
127
|
+
kill -9 <PID>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Docker Issues
|
|
131
|
+
```bash
|
|
132
|
+
# Clean up Docker resources
|
|
133
|
+
docker system prune -f
|
|
134
|
+
docker volume prune -f
|
|
135
|
+
|
|
136
|
+
# Restart Docker daemon
|
|
137
|
+
sudo service docker restart # Linux
|
|
138
|
+
# Or restart Docker Desktop # macOS/Windows
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### WordPress Not Ready
|
|
142
|
+
```bash
|
|
143
|
+
# Check WordPress logs
|
|
144
|
+
docker-compose -f docker-compose.test.yml logs wordpress-test
|
|
145
|
+
|
|
146
|
+
# Check database logs
|
|
147
|
+
docker-compose -f docker-compose.test.yml logs db-test
|
|
148
|
+
|
|
149
|
+
# Manual health check
|
|
150
|
+
curl http://localhost:8081/wp-json/wp/v2/
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Test Failures
|
|
154
|
+
```bash
|
|
155
|
+
# Run with debug output
|
|
156
|
+
DEBUG=true npm run test:contracts:live
|
|
157
|
+
|
|
158
|
+
# Check WordPress configuration
|
|
159
|
+
docker-compose -f docker-compose.test.yml exec wordpress-test cat /var/www/html/test-config.json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 🔒 Security Notes
|
|
163
|
+
|
|
164
|
+
- Test environment uses isolated containers
|
|
165
|
+
- Default credentials are for testing only
|
|
166
|
+
- Auto-cleanup removes all test data
|
|
167
|
+
- No persistent storage outside containers
|
|
168
|
+
|
|
169
|
+
## 📈 CI/CD Integration
|
|
170
|
+
|
|
171
|
+
To use in CI/CD pipelines:
|
|
172
|
+
|
|
173
|
+
```yaml
|
|
174
|
+
# GitHub Actions example
|
|
175
|
+
- name: Install Docker Compose
|
|
176
|
+
run: sudo apt-get install docker-compose
|
|
177
|
+
|
|
178
|
+
- name: Run Contract Tests
|
|
179
|
+
run: npm run test:contracts:live
|
|
180
|
+
timeout-minutes: 10
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The automated setup is designed to work in CI environments with proper Docker support.
|
|
@@ -6,13 +6,13 @@ The project includes a pre-configured `.npmrc` file that uses environment variab
|
|
|
6
6
|
|
|
7
7
|
1. **Set your NPM token as environment variable:**
|
|
8
8
|
```bash
|
|
9
|
-
export NPM_TOKEN="
|
|
9
|
+
export NPM_TOKEN="npm_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
2. **Or add to your shell profile:**
|
|
13
13
|
```bash
|
|
14
14
|
# Add to ~/.bashrc, ~/.zshrc, or ~/.profile
|
|
15
|
-
echo 'export NPM_TOKEN="
|
|
15
|
+
echo 'export NPM_TOKEN="npm_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"' >> ~/.zshrc
|
|
16
16
|
source ~/.zshrc
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -55,7 +55,7 @@ The project includes a pre-configured `.npmrc` file that uses environment variab
|
|
|
55
55
|
3. **Using environment variable** (more secure):
|
|
56
56
|
```bash
|
|
57
57
|
# Add to ~/.bashrc or ~/.zshrc
|
|
58
|
-
export NPM_TOKEN="
|
|
58
|
+
export NPM_TOKEN="npm_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
|
59
59
|
|
|
60
60
|
# Then in .npmrc:
|
|
61
61
|
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# WordPress REST API Authentication Troubleshooting Guide
|
|
2
|
+
|
|
3
|
+
## Issue: POST Requests Return 401 Unauthorized with Application Passwords
|
|
4
|
+
|
|
5
|
+
This document addresses the common issue where WordPress REST API POST/PUT/DELETE requests fail with 401 Unauthorized errors, while GET requests work fine with the same application password credentials.
|
|
6
|
+
|
|
7
|
+
## Symptoms
|
|
8
|
+
|
|
9
|
+
- ✅ GET requests work perfectly with application passwords
|
|
10
|
+
- ✅ WP-CLI commands work with the same credentials
|
|
11
|
+
- ✅ User has administrator role and all necessary capabilities
|
|
12
|
+
- ❌ POST/PUT/DELETE requests return 401 Unauthorized
|
|
13
|
+
- ❌ Error: `rest_cannot_create` or similar permission errors
|
|
14
|
+
|
|
15
|
+
## Root Causes
|
|
16
|
+
|
|
17
|
+
### 1. Authorization Header Stripping (.htaccess)
|
|
18
|
+
|
|
19
|
+
**Most Common Cause:** Apache strips the `Authorization` header by default, particularly affecting write operations.
|
|
20
|
+
|
|
21
|
+
**Solution:** Add to your `.htaccess` file:
|
|
22
|
+
```apache
|
|
23
|
+
# WordPress REST API - Preserve Authorization Header
|
|
24
|
+
RewriteCond %{HTTP:Authorization} ^(.*)
|
|
25
|
+
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Alternative approach:
|
|
29
|
+
```apache
|
|
30
|
+
RewriteEngine On
|
|
31
|
+
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Docker Environment Configuration
|
|
35
|
+
|
|
36
|
+
**Issue:** WordPress requires HTTPS for application passwords by default, but Docker development environments typically use HTTP.
|
|
37
|
+
|
|
38
|
+
**Solution:** Add to your `docker-compose.yml`:
|
|
39
|
+
```yaml
|
|
40
|
+
services:
|
|
41
|
+
wordpress:
|
|
42
|
+
environment:
|
|
43
|
+
WORDPRESS_CONFIG_EXTRA: |
|
|
44
|
+
define('WP_ENVIRONMENT_TYPE', 'local');
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Wrong Application Password Source
|
|
48
|
+
|
|
49
|
+
**Issue:** WordPress has multiple places to generate passwords, and using the wrong one causes failures.
|
|
50
|
+
|
|
51
|
+
**Solution:** Generate application passwords from:
|
|
52
|
+
- ✅ `/wp-admin/profile.php` - User Profile page
|
|
53
|
+
- ❌ NOT from 2FA/Security plugin settings
|
|
54
|
+
|
|
55
|
+
### 4. HTTP Authentication Interference
|
|
56
|
+
|
|
57
|
+
**Issue:** Server-level HTTP authentication interferes with WordPress authentication.
|
|
58
|
+
|
|
59
|
+
**Solution:** Configure server to exclude `/wp-json/` from HTTP auth, or temporarily disable.
|
|
60
|
+
|
|
61
|
+
## Technical Differences: WP-CLI vs REST API
|
|
62
|
+
|
|
63
|
+
| Aspect | WP-CLI | REST API |
|
|
64
|
+
|--------|--------|----------|
|
|
65
|
+
| Access Method | Direct file system | HTTP requests |
|
|
66
|
+
| Authentication | Bypasses web server | Requires HTTP headers |
|
|
67
|
+
| Configuration Impact | Not affected | Subject to .htaccess rules |
|
|
68
|
+
| Proxy Impact | Not affected | Can be blocked by proxies |
|
|
69
|
+
|
|
70
|
+
## Docker-Specific Solutions
|
|
71
|
+
|
|
72
|
+
### Complete Docker Configuration
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
version: '3.8'
|
|
76
|
+
services:
|
|
77
|
+
wordpress:
|
|
78
|
+
image: wordpress:latest
|
|
79
|
+
environment:
|
|
80
|
+
WORDPRESS_DB_HOST: db
|
|
81
|
+
WORDPRESS_DB_USER: wordpress
|
|
82
|
+
WORDPRESS_DB_PASSWORD: wordpress
|
|
83
|
+
WORDPRESS_DB_NAME: wordpress
|
|
84
|
+
# Enable application passwords in local development
|
|
85
|
+
WORDPRESS_CONFIG_EXTRA: |
|
|
86
|
+
define('WP_ENVIRONMENT_TYPE', 'local');
|
|
87
|
+
volumes:
|
|
88
|
+
- ./wp-htaccess.conf:/var/www/html/.htaccess
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### WordPress .htaccess Template
|
|
92
|
+
|
|
93
|
+
Create `wp-htaccess.conf`:
|
|
94
|
+
```apache
|
|
95
|
+
# BEGIN WordPress
|
|
96
|
+
RewriteEngine On
|
|
97
|
+
|
|
98
|
+
# REST API Authorization Header Fix
|
|
99
|
+
RewriteCond %{HTTP:Authorization} ^(.*)
|
|
100
|
+
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
|
|
101
|
+
|
|
102
|
+
# Standard WordPress Rules
|
|
103
|
+
RewriteRule ^index\.php$ - [L]
|
|
104
|
+
RewriteCond %{REQUEST_FILENAME} !-f
|
|
105
|
+
RewriteCond %{REQUEST_FILENAME} !-d
|
|
106
|
+
RewriteRule . /index.php [L]
|
|
107
|
+
# END WordPress
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Debugging Steps
|
|
111
|
+
|
|
112
|
+
### 1. Test Authorization Header Passing
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Test if headers reach WordPress
|
|
116
|
+
curl -v -H "Authorization: Basic $(echo -n 'username:app_password' | base64)" \
|
|
117
|
+
https://your-site.com/wp-json/wp/v2/posts
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Look for `Authorization` header in the request output.
|
|
121
|
+
|
|
122
|
+
### 2. WordPress Debug Information
|
|
123
|
+
|
|
124
|
+
Add to `wp-config.php`:
|
|
125
|
+
```php
|
|
126
|
+
define('WP_DEBUG', true);
|
|
127
|
+
define('WP_DEBUG_LOG', true);
|
|
128
|
+
define('WP_DEBUG_DISPLAY', false);
|
|
129
|
+
|
|
130
|
+
// Log REST API authentication attempts
|
|
131
|
+
add_action('rest_authentication_errors', function($result) {
|
|
132
|
+
error_log('REST Auth Result: ' . print_r($result, true));
|
|
133
|
+
return $result;
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 3. Test Script
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
const testAuth = async () => {
|
|
141
|
+
const username = 'your_username';
|
|
142
|
+
const appPassword = 'xxxx xxxx xxxx xxxx xxxx xxxx'; // Preserve spaces
|
|
143
|
+
const siteUrl = 'http://localhost:8081';
|
|
144
|
+
|
|
145
|
+
const auth = Buffer.from(`${username}:${appPassword}`).toString('base64');
|
|
146
|
+
|
|
147
|
+
console.log('Testing GET request...');
|
|
148
|
+
const getResponse = await fetch(`${siteUrl}/wp-json/wp/v2/posts?per_page=1`, {
|
|
149
|
+
headers: { 'Authorization': `Basic ${auth}` }
|
|
150
|
+
});
|
|
151
|
+
console.log('GET Status:', getResponse.status);
|
|
152
|
+
|
|
153
|
+
console.log('Testing POST request...');
|
|
154
|
+
const postResponse = await fetch(`${siteUrl}/wp-json/wp/v2/posts`, {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
headers: {
|
|
157
|
+
'Authorization': `Basic ${auth}`,
|
|
158
|
+
'Content-Type': 'application/json'
|
|
159
|
+
},
|
|
160
|
+
body: JSON.stringify({
|
|
161
|
+
title: 'Auth Test Post',
|
|
162
|
+
content: 'Testing authentication',
|
|
163
|
+
status: 'draft'
|
|
164
|
+
})
|
|
165
|
+
});
|
|
166
|
+
console.log('POST Status:', postResponse.status);
|
|
167
|
+
|
|
168
|
+
if (!postResponse.ok) {
|
|
169
|
+
const error = await postResponse.json();
|
|
170
|
+
console.log('Error:', error);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
testAuth();
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Common Security Plugin Issues
|
|
178
|
+
|
|
179
|
+
### Wordfence
|
|
180
|
+
- Check if REST API is blocked in Wordfence settings
|
|
181
|
+
- Temporarily disable to test
|
|
182
|
+
|
|
183
|
+
### iThemes Security
|
|
184
|
+
- May block REST API requests
|
|
185
|
+
- Check "WordPress Tweaks" → "Disable REST API"
|
|
186
|
+
|
|
187
|
+
### Jetpack
|
|
188
|
+
- May interfere with authentication
|
|
189
|
+
- Check Jetpack security settings
|
|
190
|
+
|
|
191
|
+
## Production Considerations
|
|
192
|
+
|
|
193
|
+
1. **Always use HTTPS** in production
|
|
194
|
+
2. **Remove WP_ENVIRONMENT_TYPE override** in production
|
|
195
|
+
3. **Monitor failed authentication attempts**
|
|
196
|
+
4. **Use strong application passwords**
|
|
197
|
+
5. **Regularly rotate application passwords**
|
|
198
|
+
|
|
199
|
+
## Verification Checklist
|
|
200
|
+
|
|
201
|
+
- [ ] `.htaccess` includes Authorization header preservation
|
|
202
|
+
- [ ] Docker environment sets `WP_ENVIRONMENT_TYPE` to `local`
|
|
203
|
+
- [ ] Application password generated from correct location
|
|
204
|
+
- [ ] No HTTP authentication conflicts
|
|
205
|
+
- [ ] User has administrator role
|
|
206
|
+
- [ ] Security plugins allow REST API access
|
|
207
|
+
- [ ] WordPress debug logging enabled for testing
|
|
208
|
+
|
|
209
|
+
## Alternative Authentication Methods
|
|
210
|
+
|
|
211
|
+
If application passwords continue to fail:
|
|
212
|
+
|
|
213
|
+
1. **JWT Authentication Plugin**
|
|
214
|
+
2. **OAuth 2.0 Plugin**
|
|
215
|
+
3. **Custom nonce-based authentication**
|
|
216
|
+
4. **API Key plugins**
|
|
217
|
+
|
|
218
|
+
Remember: The goal is to achieve the same level of functionality that WP-CLI provides, but through the REST API interface.
|
package/package.json
CHANGED
|
@@ -1,116 +1,136 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-wordpress",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Comprehensive Model Context Protocol server for WordPress management with
|
|
5
|
-
"
|
|
3
|
+
"version": "1.2.2",
|
|
4
|
+
"description": "Comprehensive Model Context Protocol server for WordPress management with 59 tools, performance monitoring, intelligent caching, auto-generated documentation, Docker support, TypeScript, and production-ready authentication",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"wordpress",
|
|
9
|
+
"cms",
|
|
10
|
+
"rest-api",
|
|
11
|
+
"ai",
|
|
12
|
+
"assistant"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/thomasdyhr/mcp-wordpress#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/thomasdyhr/mcp-wordpress/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/thomasdyhr/mcp-wordpress.git"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "Thomas Dyhr",
|
|
6
24
|
"type": "module",
|
|
25
|
+
"main": "dist/index.js",
|
|
7
26
|
"bin": {
|
|
8
27
|
"mcp-wordpress": "bin/mcp-wordpress.js",
|
|
9
28
|
"wordpress-setup": "bin/setup.js",
|
|
10
29
|
"wordpress-status": "bin/status.js"
|
|
11
30
|
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist/",
|
|
33
|
+
"src/",
|
|
34
|
+
"bin/",
|
|
35
|
+
"docs/",
|
|
36
|
+
"examples/",
|
|
37
|
+
"cache/",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
12
41
|
"scripts": {
|
|
13
42
|
"build": "tsc",
|
|
14
43
|
"build:watch": "tsc --watch",
|
|
15
|
-
"
|
|
44
|
+
"check:ignore": "node scripts/sync-ignore-files.js",
|
|
45
|
+
"check:npm": "node scripts/test-npm-config.js",
|
|
16
46
|
"dev": "npm run build && DEBUG=true node dist/index.js",
|
|
47
|
+
"docs:check": "node scripts/validate-docs.js",
|
|
48
|
+
"docs:generate": "npm run build && node scripts/generate-docs.js",
|
|
49
|
+
"docs:serve": "npm run docs:generate && node scripts/serve-docs.js",
|
|
50
|
+
"docs:validate": "npm run docs:generate && node scripts/validate-docs.js",
|
|
51
|
+
"docs:watch": "npm run docs:generate && echo 'Watching for changes...' && npm run docs:serve",
|
|
52
|
+
"fix:rest-auth": "bash scripts/fix-rest-api-auth.sh",
|
|
53
|
+
"health": "node scripts/health-check.js",
|
|
54
|
+
"lint": "eslint src/ tests/",
|
|
55
|
+
"lint:fix": "eslint src/ tests/ --fix",
|
|
56
|
+
"pre-commit": "lint-staged",
|
|
57
|
+
"prepare": "husky",
|
|
58
|
+
"prepublishOnly": "npm run build && npm run check:ignore",
|
|
59
|
+
"security:audit": "npm audit --production",
|
|
60
|
+
"security:check": "node scripts/security-check.js",
|
|
61
|
+
"security:fix": "npm audit fix",
|
|
62
|
+
"security:test": "node scripts/security-test.js",
|
|
17
63
|
"setup": "node bin/setup.js",
|
|
64
|
+
"start": "npm run build && node dist/index.js",
|
|
18
65
|
"status": "node bin/status.js",
|
|
19
66
|
"test": "npm run test:typescript",
|
|
20
|
-
"test:
|
|
21
|
-
"test:
|
|
22
|
-
"test:
|
|
23
|
-
"test:
|
|
67
|
+
"test:auth": "node scripts/test-auth.js",
|
|
68
|
+
"test:config": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest tests/config/ --config=jest.typescript.config.json",
|
|
69
|
+
"test:contracts": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest tests/contracts/ --config=jest.typescript.config.json",
|
|
70
|
+
"test:contracts:live": "bash scripts/test-contracts-live.sh",
|
|
24
71
|
"test:coverage": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest --coverage --collectCoverageFrom='dist/**/*.js' --coverageThreshold='{\"global\":{\"branches\":50,\"functions\":50,\"lines\":50,\"statements\":50}}' --config=jest.typescript.config.json",
|
|
25
72
|
"test:fast": "npm run test:typescript",
|
|
26
|
-
"test:mcp": "node scripts/test-mcp.js",
|
|
27
73
|
"test:integration": "node scripts/test-integration.js",
|
|
28
|
-
"test:
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
74
|
+
"test:legacy": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest",
|
|
75
|
+
"test:mcp": "node scripts/test-mcp.js",
|
|
76
|
+
"test:performance": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest tests/performance/ --config=jest.typescript.config.json",
|
|
77
|
+
"test:property": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest tests/property/ --config=jest.typescript.config.json",
|
|
78
|
+
"test:security": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest tests/security/ --config=jest.typescript.config.json",
|
|
79
|
+
"test:security:penetration": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest tests/security/penetration-tests.test.js --config=jest.typescript.config.json",
|
|
80
|
+
"test:security:validation": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest tests/security/security-validation.test.js --config=jest.typescript.config.json",
|
|
81
|
+
"test:tools": "node scripts/test-all-tools-fixed.js",
|
|
82
|
+
"test:multisite": "node scripts/test-multisite-quick.js",
|
|
83
|
+
"test:typescript": "npm run build && NODE_OPTIONS=\"--experimental-vm-modules\" jest --config=jest.typescript.config.json",
|
|
84
|
+
"test:watch": "NODE_OPTIONS=\"--experimental-vm-modules\" jest --watch --config=jest.typescript.config.json",
|
|
85
|
+
"test:with-env": "bash scripts/start-test-env.sh && npm run test:typescript",
|
|
33
86
|
"typecheck": "tsc --noEmit",
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
87
|
+
"verify-claude": "node scripts/verify-claude-integration.js"
|
|
88
|
+
},
|
|
89
|
+
"lint-staged": {
|
|
90
|
+
"*.{ts,js}": [
|
|
91
|
+
"eslint --fix",
|
|
92
|
+
"prettier --write"
|
|
93
|
+
],
|
|
94
|
+
"*.md": [
|
|
95
|
+
"markdownlint --fix"
|
|
96
|
+
],
|
|
97
|
+
"package.json": [
|
|
98
|
+
"sort-package-json"
|
|
99
|
+
]
|
|
39
100
|
},
|
|
40
|
-
"keywords": [
|
|
41
|
-
"mcp",
|
|
42
|
-
"model-context-protocol",
|
|
43
|
-
"wordpress",
|
|
44
|
-
"cms",
|
|
45
|
-
"rest-api",
|
|
46
|
-
"ai",
|
|
47
|
-
"assistant"
|
|
48
|
-
],
|
|
49
|
-
"author": "AiondaDotCom",
|
|
50
|
-
"license": "MIT",
|
|
51
101
|
"dependencies": {
|
|
52
102
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
53
103
|
"dotenv": "^16.3.1",
|
|
54
104
|
"form-data": "^4.0.0",
|
|
55
105
|
"node-fetch": "^3.3.2",
|
|
56
|
-
"open": "^9.1.0",
|
|
57
106
|
"zod": "^3.25.67"
|
|
58
107
|
},
|
|
59
108
|
"devDependencies": {
|
|
60
109
|
"@eslint/js": "^9.29.0",
|
|
61
110
|
"@jest/globals": "^30.0.0",
|
|
111
|
+
"@pact-foundation/pact": "^15.0.1",
|
|
112
|
+
"@pact-foundation/pact-node": "^10.18.0",
|
|
62
113
|
"@types/jest": "^30.0.0",
|
|
63
|
-
"@types/nock": "^10.0.3",
|
|
64
114
|
"@types/node": "^20.19.1",
|
|
65
115
|
"@typescript-eslint/parser": "^8.35.0",
|
|
66
116
|
"eslint": "^9.29.0",
|
|
67
117
|
"eslint-plugin-jest": "^29.0.1",
|
|
68
118
|
"eslint-plugin-node": "^11.1.0",
|
|
119
|
+
"fast-check": "^4.1.1",
|
|
69
120
|
"husky": "^9.1.7",
|
|
70
121
|
"jest": "^30.0.0",
|
|
71
122
|
"lint-staged": "^16.1.2",
|
|
72
123
|
"markdownlint-cli": "^0.45.0",
|
|
73
124
|
"nock": "^14.0.5",
|
|
125
|
+
"open": "^9.1.0",
|
|
74
126
|
"prettier": "^3.6.2",
|
|
75
127
|
"sort-package-json": "^3.3.1",
|
|
76
|
-
"ts-jest": "^29.4.0",
|
|
77
|
-
"ts-node": "^10.9.2",
|
|
78
128
|
"typescript": "^5.8.3"
|
|
79
129
|
},
|
|
80
130
|
"engines": {
|
|
81
131
|
"node": ">=18.0.0"
|
|
82
132
|
},
|
|
83
|
-
"files": [
|
|
84
|
-
"dist/",
|
|
85
|
-
"src/",
|
|
86
|
-
"bin/",
|
|
87
|
-
"docs/",
|
|
88
|
-
"examples/",
|
|
89
|
-
"cache/",
|
|
90
|
-
"README.md",
|
|
91
|
-
"LICENSE"
|
|
92
|
-
],
|
|
93
|
-
"repository": {
|
|
94
|
-
"type": "git",
|
|
95
|
-
"url": "git+https://github.com/AiondaDotCom/mcp-wordpress.git"
|
|
96
|
-
},
|
|
97
|
-
"bugs": {
|
|
98
|
-
"url": "https://github.com/AiondaDotCom/mcp-wordpress/issues"
|
|
99
|
-
},
|
|
100
|
-
"homepage": "https://github.com/AiondaDotCom/mcp-wordpress#readme",
|
|
101
133
|
"publishConfig": {
|
|
102
134
|
"access": "public"
|
|
103
|
-
},
|
|
104
|
-
"lint-staged": {
|
|
105
|
-
"*.{ts,js}": [
|
|
106
|
-
"eslint --fix",
|
|
107
|
-
"prettier --write"
|
|
108
|
-
],
|
|
109
|
-
"*.md": [
|
|
110
|
-
"markdownlint --fix"
|
|
111
|
-
],
|
|
112
|
-
"package.json": [
|
|
113
|
-
"sort-package-json"
|
|
114
|
-
]
|
|
115
135
|
}
|
|
116
136
|
}
|