@hypnosis/docker-mcp-server 1.0.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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +242 -0
  3. package/dist/adapters/adapter-registry.d.ts +29 -0
  4. package/dist/adapters/adapter-registry.d.ts.map +1 -0
  5. package/dist/adapters/adapter-registry.js +47 -0
  6. package/dist/adapters/adapter-registry.js.map +1 -0
  7. package/dist/adapters/database-adapter.d.ts +33 -0
  8. package/dist/adapters/database-adapter.d.ts.map +1 -0
  9. package/dist/adapters/database-adapter.js +6 -0
  10. package/dist/adapters/database-adapter.js.map +1 -0
  11. package/dist/adapters/postgresql.d.ts +42 -0
  12. package/dist/adapters/postgresql.d.ts.map +1 -0
  13. package/dist/adapters/postgresql.js +202 -0
  14. package/dist/adapters/postgresql.js.map +1 -0
  15. package/dist/adapters/redis.d.ts +46 -0
  16. package/dist/adapters/redis.d.ts.map +1 -0
  17. package/dist/adapters/redis.js +202 -0
  18. package/dist/adapters/redis.js.map +1 -0
  19. package/dist/adapters/sqlite.d.ts +34 -0
  20. package/dist/adapters/sqlite.d.ts.map +1 -0
  21. package/dist/adapters/sqlite.js +126 -0
  22. package/dist/adapters/sqlite.js.map +1 -0
  23. package/dist/adapters/types.d.ts +53 -0
  24. package/dist/adapters/types.d.ts.map +1 -0
  25. package/dist/adapters/types.js +5 -0
  26. package/dist/adapters/types.js.map +1 -0
  27. package/dist/cli.d.ts +7 -0
  28. package/dist/cli.d.ts.map +1 -0
  29. package/dist/cli.js +319 -0
  30. package/dist/cli.js.map +1 -0
  31. package/dist/discovery/compose-parser.d.ts +35 -0
  32. package/dist/discovery/compose-parser.d.ts.map +1 -0
  33. package/dist/discovery/compose-parser.js +126 -0
  34. package/dist/discovery/compose-parser.js.map +1 -0
  35. package/dist/discovery/config-merger.d.ts +19 -0
  36. package/dist/discovery/config-merger.d.ts.map +1 -0
  37. package/dist/discovery/config-merger.js +60 -0
  38. package/dist/discovery/config-merger.js.map +1 -0
  39. package/dist/discovery/project-discovery.d.ts +53 -0
  40. package/dist/discovery/project-discovery.d.ts.map +1 -0
  41. package/dist/discovery/project-discovery.js +252 -0
  42. package/dist/discovery/project-discovery.js.map +1 -0
  43. package/dist/discovery/types.d.ts +47 -0
  44. package/dist/discovery/types.d.ts.map +1 -0
  45. package/dist/discovery/types.js +6 -0
  46. package/dist/discovery/types.js.map +1 -0
  47. package/dist/index.d.ts +6 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +109 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/managers/compose-manager.d.ts +30 -0
  52. package/dist/managers/compose-manager.d.ts.map +1 -0
  53. package/dist/managers/compose-manager.js +70 -0
  54. package/dist/managers/compose-manager.js.map +1 -0
  55. package/dist/managers/container-manager.d.ts +81 -0
  56. package/dist/managers/container-manager.d.ts.map +1 -0
  57. package/dist/managers/container-manager.js +278 -0
  58. package/dist/managers/container-manager.js.map +1 -0
  59. package/dist/managers/env-manager.d.ts +37 -0
  60. package/dist/managers/env-manager.d.ts.map +1 -0
  61. package/dist/managers/env-manager.js +124 -0
  62. package/dist/managers/env-manager.js.map +1 -0
  63. package/dist/security/sql-validator.d.ts +23 -0
  64. package/dist/security/sql-validator.d.ts.map +1 -0
  65. package/dist/security/sql-validator.js +44 -0
  66. package/dist/security/sql-validator.js.map +1 -0
  67. package/dist/tools/container-tools.d.ts +31 -0
  68. package/dist/tools/container-tools.d.ts.map +1 -0
  69. package/dist/tools/container-tools.js +366 -0
  70. package/dist/tools/container-tools.js.map +1 -0
  71. package/dist/tools/database-tools.d.ts +22 -0
  72. package/dist/tools/database-tools.d.ts.map +1 -0
  73. package/dist/tools/database-tools.js +264 -0
  74. package/dist/tools/database-tools.js.map +1 -0
  75. package/dist/tools/env-tools.d.ts +52 -0
  76. package/dist/tools/env-tools.d.ts.map +1 -0
  77. package/dist/tools/env-tools.js +318 -0
  78. package/dist/tools/env-tools.js.map +1 -0
  79. package/dist/tools/executor-tool.d.ts +18 -0
  80. package/dist/tools/executor-tool.d.ts.map +1 -0
  81. package/dist/tools/executor-tool.js +95 -0
  82. package/dist/tools/executor-tool.js.map +1 -0
  83. package/dist/tools/mcp-health-tool.d.ts +65 -0
  84. package/dist/tools/mcp-health-tool.d.ts.map +1 -0
  85. package/dist/tools/mcp-health-tool.js +126 -0
  86. package/dist/tools/mcp-health-tool.js.map +1 -0
  87. package/dist/utils/cache.d.ts +43 -0
  88. package/dist/utils/cache.d.ts.map +1 -0
  89. package/dist/utils/cache.js +77 -0
  90. package/dist/utils/cache.js.map +1 -0
  91. package/dist/utils/compose-exec.d.ts +13 -0
  92. package/dist/utils/compose-exec.d.ts.map +1 -0
  93. package/dist/utils/compose-exec.js +33 -0
  94. package/dist/utils/compose-exec.js.map +1 -0
  95. package/dist/utils/docker-client.d.ts +33 -0
  96. package/dist/utils/docker-client.d.ts.map +1 -0
  97. package/dist/utils/docker-client.js +59 -0
  98. package/dist/utils/docker-client.js.map +1 -0
  99. package/dist/utils/logger.d.ts +18 -0
  100. package/dist/utils/logger.d.ts.map +1 -0
  101. package/dist/utils/logger.js +38 -0
  102. package/dist/utils/logger.js.map +1 -0
  103. package/package.json +65 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Danila Susak
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # Docker MCP Server
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@hypnosis/docker-mcp-server.svg)](https://www.npmjs.com/package/@hypnosis/docker-mcp-server)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Universal Docker MCP server for AI assistants (Cursor, Claude Desktop). Manage Docker containers, execute commands, query databases, and handle environment configurations — all through natural language.
7
+
8
+ ## ✨ Features
9
+
10
+ - ✅ **16 MCP Commands** — Container management, database operations, environment handling
11
+ - ✅ **Database Support** — PostgreSQL, Redis, SQLite with extensible adapter pattern
12
+ - ✅ **Auto-Discovery** — Automatically finds and parses `docker-compose.yml` files
13
+ - ✅ **Security** — Automatic secrets masking in environment variables
14
+ - ✅ **Follow Logs** — Real-time log streaming with `follow` mode
15
+ - ✅ **Type-Safe** — Written in TypeScript with full type definitions
16
+ - ✅ **Universal** — Works with any Docker project
17
+
18
+ ## 📦 Installation
19
+
20
+ ### Global Installation (Recommended)
21
+
22
+ ```bash
23
+ npm install -g @hypnosis/docker-mcp-server
24
+ ```
25
+
26
+ ### NPX (No Installation)
27
+
28
+ ```bash
29
+ npx @hypnosis/docker-mcp-server
30
+ ```
31
+
32
+ ### Local Installation
33
+
34
+ ```bash
35
+ npm install @hypnosis/docker-mcp-server
36
+ ```
37
+
38
+ ## 🚀 Quick Start
39
+
40
+ ### Configuration for Cursor
41
+
42
+ Add to `~/.cursor/mcp.json` (or `~/.config/cursor/mcp.json`):
43
+
44
+ ```json
45
+ {
46
+ "mcpServers": {
47
+ "docker": {
48
+ "command": "npx",
49
+ "args": ["-y", "@hypnosis/docker-mcp-server"],
50
+ "env": {
51
+ "DOCKER_MCP_AUTO_DISCOVER": "true",
52
+ "DOCKER_MCP_MASK_SECRETS": "true"
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### Configuration for Claude Desktop
60
+
61
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "docker": {
67
+ "command": "npx",
68
+ "args": ["-y", "@hypnosis/docker-mcp-server"]
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ ### First Steps
75
+
76
+ 1. **Restart your AI assistant** (Cursor or Claude Desktop)
77
+ 2. **Navigate to your Docker project** directory (with `docker-compose.yml`)
78
+ 3. **Ask your AI assistant:**
79
+ - "Show me the status of all containers"
80
+ - "Restart the web service"
81
+ - "Show me the last 50 lines of logs from the database"
82
+
83
+ ## 📚 Available Commands
84
+
85
+ ### Container Management (7 commands)
86
+
87
+ | Command | Description | Example |
88
+ |---------|-------------|---------|
89
+ | `docker_container_list` | List all containers in project | `docker_container_list()` |
90
+ | `docker_container_start` | Start a container | `docker_container_start("web")` |
91
+ | `docker_container_stop` | Stop a container | `docker_container_stop("web")` |
92
+ | `docker_container_restart` | Restart a container | `docker_container_restart("web")` |
93
+ | `docker_container_logs` | View container logs | `docker_container_logs("web", {follow: true, lines: 100})` |
94
+ | `docker_compose_up` | Start entire stack | `docker_compose_up({build: true})` |
95
+ | `docker_compose_down` | Stop entire stack | `docker_compose_down({volumes: false})` |
96
+
97
+ ### Database Operations (4 commands)
98
+
99
+ | Command | Description | Example |
100
+ |---------|-------------|---------|
101
+ | `docker_db_query` | Execute SQL query | `docker_db_query("postgres", "SELECT * FROM users LIMIT 5;")` |
102
+ | `docker_db_backup` | Create database backup | `docker_db_backup("postgres", "./backup.sql")` |
103
+ | `docker_db_restore` | Restore from backup | `docker_db_restore("postgres", "./backup.sql")` |
104
+ | `docker_db_status` | Show database status | `docker_db_status("postgres")` |
105
+
106
+ ### Environment & Config (3 commands)
107
+
108
+ | Command | Description | Example |
109
+ |---------|-------------|---------|
110
+ | `docker_env_list` | List environment variables | `docker_env_list()` |
111
+ | `docker_compose_config` | Show parsed compose config | `docker_compose_config()` |
112
+ | `docker_healthcheck` | Check health of all services | `docker_healthcheck()` |
113
+
114
+ ### Universal Executor (1 command)
115
+
116
+ | Command | Description | Example |
117
+ |---------|-------------|---------|
118
+ | `docker_exec` | Execute any command in container | `docker_exec("web", "npm test")` |
119
+
120
+ ## 💡 Usage Examples
121
+
122
+ ### Example 1: Web Development (Next.js + Redis)
123
+
124
+ ```typescript
125
+ // Start the entire stack
126
+ docker_compose_up({build: true, detach: true})
127
+
128
+ // Check if services are healthy
129
+ docker_healthcheck()
130
+
131
+ // View logs in real-time
132
+ docker_container_logs("web", {follow: true, lines: 50})
133
+
134
+ // Check Redis cache
135
+ docker_db_query("redis", "KEYS *")
136
+
137
+ // Run tests
138
+ docker_exec("web", "npm test")
139
+ ```
140
+
141
+ ### Example 2: Backend Development (Django + PostgreSQL)
142
+
143
+ ```typescript
144
+ // Restart backend after code changes
145
+ docker_container_restart("web")
146
+
147
+ // Run database migrations
148
+ docker_exec("web", "python manage.py migrate")
149
+
150
+ // Query database
151
+ docker_db_query("postgres", "SELECT COUNT(*) FROM auth_user;")
152
+
153
+ // Create backup before deployment
154
+ docker_db_backup("postgres", "./backups/pre-deploy.sql")
155
+
156
+ // View application logs
157
+ docker_container_logs("web", {lines: 100, timestamps: true})
158
+ ```
159
+
160
+ ## 🏗️ How It Works
161
+
162
+ ### Project Discovery
163
+
164
+ The server automatically discovers your project structure:
165
+
166
+ 1. **Finds `docker-compose.yml`** in current directory or parent directories
167
+ 2. **Parses project configuration** (services, networks, volumes)
168
+ 3. **Detects database types** (PostgreSQL, Redis, SQLite)
169
+ 4. **Loads environment files** (`.env`, `.env.local`)
170
+ 5. **Masks secrets** automatically (PASSWORD, TOKEN, KEY, etc.)
171
+
172
+ ### Database Adapters
173
+
174
+ Extensible adapter pattern for different databases:
175
+
176
+ - **PostgreSQL** — `psql`, `pg_dump`, `pg_restore`
177
+ - **Redis** — `redis-cli`, `SAVE`, `BGSAVE`
178
+ - **SQLite** — `.dump`, `.restore`
179
+ - More databases can be added via adapters
180
+
181
+ ## 🔒 Security
182
+
183
+ ### Automatic Secrets Masking
184
+
185
+ Environment variables containing sensitive data are automatically masked:
186
+
187
+ ```typescript
188
+ // Original .env
189
+ DATABASE_PASSWORD=super_secret_123
190
+ API_TOKEN=abc123xyz
191
+
192
+ // Output from docker_env_list()
193
+ DATABASE_PASSWORD=***MASKED***
194
+ API_TOKEN=***MASKED***
195
+ ```
196
+
197
+ Keywords that trigger masking: `PASSWORD`, `TOKEN`, `KEY`, `SECRET`, `API_KEY`
198
+
199
+ ## 📖 Documentation
200
+
201
+ - **[Quick Start Guide](docs/QUICK_START.md)** — Detailed setup instructions
202
+ - **[API Reference](docs/API_REFERENCE.md)** — Complete command documentation
203
+ - **[Examples](docs/EXAMPLES.md)** — Real-world usage scenarios
204
+ - **[Troubleshooting](docs/TROUBLESHOOTING.md)** — Common issues and solutions
205
+ - **[FAQ](docs/FAQ.md)** — Frequently asked questions
206
+
207
+ For developer documentation, see [docs/DEV/README.md](docs/DEV/README.md)
208
+
209
+ ## 🤝 Contributing
210
+
211
+ We welcome contributions! This is an open-source project built for the community.
212
+
213
+ ### How to Contribute
214
+
215
+ 1. Fork the repository
216
+ 2. Create a feature branch
217
+ 3. Make your changes
218
+ 4. Add tests if applicable
219
+ 5. Submit a pull request
220
+
221
+ See [docs/DEV/README.md](docs/DEV/README.md) for development setup and guidelines.
222
+
223
+ ## 📝 License
224
+
225
+ MIT License - see [LICENSE](LICENSE) for details
226
+
227
+ Copyright (c) 2025 Danila Susak
228
+
229
+ ## 🙏 Acknowledgments
230
+
231
+ - [Model Context Protocol](https://modelcontextprotocol.io/) by Anthropic
232
+ - [Docker](https://www.docker.com/) for containerization
233
+ - Community feedback and contributions
234
+
235
+ ## 📬 Support
236
+
237
+ - **Issues:** [GitHub Issues](https://github.com/hypnosis/docker-mcp-server/issues)
238
+ - **Discussions:** [GitHub Discussions](https://github.com/hypnosis/docker-mcp-server/discussions)
239
+
240
+ ---
241
+
242
+ **Made with ❤️ for the AI-powered development community**
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Adapter Registry
3
+ * Регистрация и получение Database Adapters по типу БД
4
+ */
5
+ import type { DatabaseAdapter } from './database-adapter.js';
6
+ export declare class AdapterRegistry {
7
+ private adapters;
8
+ /**
9
+ * Регистрировать адаптер
10
+ */
11
+ register(type: string, adapter: DatabaseAdapter): void;
12
+ /**
13
+ * Получить адаптер по типу
14
+ */
15
+ get(serviceType: string): DatabaseAdapter;
16
+ /**
17
+ * Проверить наличие адаптера
18
+ */
19
+ has(serviceType: string): boolean;
20
+ /**
21
+ * Получить список всех зарегистрированных типов
22
+ */
23
+ getRegisteredTypes(): string[];
24
+ }
25
+ /**
26
+ * Singleton registry
27
+ */
28
+ export declare const adapterRegistry: AdapterRegistry;
29
+ //# sourceMappingURL=adapter-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-registry.d.ts","sourceRoot":"","sources":["../../src/adapters/adapter-registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAsC;IAEtD;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAMtD;;OAEG;IACH,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe;IAgBzC;;OAEG;IACH,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAIjC;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;CAG/B;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Adapter Registry
3
+ * Регистрация и получение Database Adapters по типу БД
4
+ */
5
+ import { logger } from '../utils/logger.js';
6
+ export class AdapterRegistry {
7
+ adapters = new Map();
8
+ /**
9
+ * Регистрировать адаптер
10
+ */
11
+ register(type, adapter) {
12
+ const normalizedType = type.toLowerCase();
13
+ this.adapters.set(normalizedType, adapter);
14
+ logger.debug(`Registered adapter for: ${type}`);
15
+ }
16
+ /**
17
+ * Получить адаптер по типу
18
+ */
19
+ get(serviceType) {
20
+ const type = serviceType.toLowerCase();
21
+ const adapter = this.adapters.get(type);
22
+ if (!adapter) {
23
+ const available = Array.from(this.adapters.keys()).join(', ');
24
+ throw new Error(`No adapter found for database type: ${serviceType}\n` +
25
+ `Available adapters: ${available || 'none'}`);
26
+ }
27
+ logger.debug(`Using adapter for: ${serviceType}`);
28
+ return adapter;
29
+ }
30
+ /**
31
+ * Проверить наличие адаптера
32
+ */
33
+ has(serviceType) {
34
+ return this.adapters.has(serviceType.toLowerCase());
35
+ }
36
+ /**
37
+ * Получить список всех зарегистрированных типов
38
+ */
39
+ getRegisteredTypes() {
40
+ return Array.from(this.adapters.keys());
41
+ }
42
+ }
43
+ /**
44
+ * Singleton registry
45
+ */
46
+ export const adapterRegistry = new AdapterRegistry();
47
+ //# sourceMappingURL=adapter-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-registry.js","sourceRoot":"","sources":["../../src/adapters/adapter-registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,OAAO,eAAe;IAClB,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEtD;;OAEG;IACH,QAAQ,CAAC,IAAY,EAAE,OAAwB;QAC7C,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,WAAmB;QACrB,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAExC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9D,MAAM,IAAI,KAAK,CACb,uCAAuC,WAAW,IAAI;gBACtD,uBAAuB,SAAS,IAAI,MAAM,EAAE,CAC7C,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC;QAClD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,WAAmB;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Database Adapter Interface
3
+ * Интерфейс для работы с разными типами БД
4
+ */
5
+ import type { ServiceConfig } from '../discovery/types.js';
6
+ import type { QueryOptions, BackupOptions, RestoreOptions, DBStatus, ConnectionInfo } from './types.js';
7
+ /**
8
+ * Интерфейс для Database Adapters
9
+ * Все адаптеры должны реализовать этот интерфейс
10
+ */
11
+ export interface DatabaseAdapter {
12
+ /**
13
+ * Выполнить query или команду
14
+ */
15
+ query(service: string, query: string, options?: QueryOptions): Promise<string>;
16
+ /**
17
+ * Создать backup
18
+ */
19
+ backup(service: string, options: BackupOptions): Promise<string>;
20
+ /**
21
+ * Восстановить из backup
22
+ */
23
+ restore(service: string, backupPath: string, options?: RestoreOptions): Promise<void>;
24
+ /**
25
+ * Получить статус БД
26
+ */
27
+ status(service: string): Promise<DBStatus>;
28
+ /**
29
+ * Получить connection info из environment
30
+ */
31
+ getConnectionInfo(service: ServiceConfig, env: Record<string, string>): ConnectionInfo;
32
+ }
33
+ //# sourceMappingURL=database-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/database-adapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,QAAQ,EACR,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,KAAK,CACH,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEjE;;OAEG;IACH,OAAO,CACL,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3C;;OAEG;IACH,iBAAiB,CACf,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,cAAc,CAAC;CACnB"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Database Adapter Interface
3
+ * Интерфейс для работы с разными типами БД
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=database-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-adapter.js","sourceRoot":"","sources":["../../src/adapters/database-adapter.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * PostgreSQL Adapter
3
+ * Реализация DatabaseAdapter для PostgreSQL
4
+ */
5
+ import type { DatabaseAdapter } from './database-adapter.js';
6
+ import type { QueryOptions, BackupOptions, RestoreOptions, DBStatus, ConnectionInfo } from './types.js';
7
+ import type { ServiceConfig } from '../discovery/types.js';
8
+ export declare class PostgreSQLAdapter implements DatabaseAdapter {
9
+ private containerManager;
10
+ private projectDiscovery;
11
+ private envManager;
12
+ constructor();
13
+ /**
14
+ * Выполнить SQL query
15
+ */
16
+ query(service: string, query: string, options?: QueryOptions): Promise<string>;
17
+ /**
18
+ * Создать backup
19
+ */
20
+ backup(service: string, options: BackupOptions): Promise<string>;
21
+ /**
22
+ * Восстановить из backup
23
+ */
24
+ restore(service: string, backupPath: string, options?: RestoreOptions): Promise<void>;
25
+ /**
26
+ * Получить статус БД
27
+ */
28
+ status(service: string): Promise<DBStatus>;
29
+ /**
30
+ * Получить connection info из environment
31
+ */
32
+ getConnectionInfo(service: ServiceConfig, env: Record<string, string>): ConnectionInfo;
33
+ /**
34
+ * Парсит версию PostgreSQL из output
35
+ */
36
+ private parseVersion;
37
+ /**
38
+ * Парсит одно значение из SQL output (первая строка, первый столбец)
39
+ */
40
+ private parseSingleValue;
41
+ }
42
+ //# sourceMappingURL=postgresql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgresql.d.ts","sourceRoot":"","sources":["../../src/adapters/postgresql.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,QAAQ,EACR,cAAc,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAO3D,qBAAa,iBAAkB,YAAW,eAAe;IACvD,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,UAAU,CAAa;;IAQ/B;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA0CpF;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAgDtE;;OAEG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC;IA8ChB;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IA6ChD;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,cAAc;IAUtF;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAWzB"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * PostgreSQL Adapter
3
+ * Реализация DatabaseAdapter для PostgreSQL
4
+ */
5
+ import { ContainerManager } from '../managers/container-manager.js';
6
+ import { ProjectDiscovery } from '../discovery/project-discovery.js';
7
+ import { EnvManager } from '../managers/env-manager.js';
8
+ import { sqlValidator } from '../security/sql-validator.js';
9
+ import { logger } from '../utils/logger.js';
10
+ export class PostgreSQLAdapter {
11
+ containerManager;
12
+ projectDiscovery;
13
+ envManager;
14
+ constructor() {
15
+ this.containerManager = new ContainerManager();
16
+ this.projectDiscovery = new ProjectDiscovery();
17
+ this.envManager = new EnvManager();
18
+ }
19
+ /**
20
+ * Выполнить SQL query
21
+ */
22
+ async query(service, query, options) {
23
+ // Валидация SQL (если включена)
24
+ sqlValidator.validate(query);
25
+ const project = await this.projectDiscovery.findProject();
26
+ const serviceConfig = project.services[service];
27
+ if (!serviceConfig) {
28
+ throw new Error(`Service '${service}' not found in project`);
29
+ }
30
+ const env = this.envManager.loadEnv(project.projectDir, service, serviceConfig);
31
+ const conn = this.getConnectionInfo(serviceConfig, env);
32
+ const db = options?.database || conn.database;
33
+ const user = options?.user || conn.user;
34
+ // Строим команду psql
35
+ const format = options?.format || 'table';
36
+ let cmd = ['psql', '-U', user, '-d', db];
37
+ // Формат вывода
38
+ if (format === 'json') {
39
+ cmd.push('--json');
40
+ }
41
+ else if (format === 'csv') {
42
+ cmd.push('--csv');
43
+ }
44
+ // SQL query
45
+ cmd.push('-c', query);
46
+ // Пароль через PGPASSWORD env var
47
+ const envVars = conn.password ? [`PGPASSWORD=${conn.password}`] : [];
48
+ logger.debug(`Executing PostgreSQL query in ${service}: ${query}`);
49
+ const output = await this.containerManager.exec(service, project.name, cmd, {
50
+ env: envVars,
51
+ });
52
+ return output;
53
+ }
54
+ /**
55
+ * Создать backup
56
+ */
57
+ async backup(service, options) {
58
+ const project = await this.projectDiscovery.findProject();
59
+ const serviceConfig = project.services[service];
60
+ if (!serviceConfig) {
61
+ throw new Error(`Service '${service}' not found in project`);
62
+ }
63
+ const env = this.envManager.loadEnv(project.projectDir, service, serviceConfig);
64
+ const conn = this.getConnectionInfo(serviceConfig, env);
65
+ const format = options.format || 'custom';
66
+ const output = options.output || `/backups/postgres-backup-${Date.now()}.dump`;
67
+ // Строим команду pg_dump
68
+ let cmd = ['pg_dump', '-U', conn.user, '-d', conn.database];
69
+ // Формат backup
70
+ if (format === 'custom') {
71
+ cmd.push('-Fc'); // Custom format (compressed)
72
+ }
73
+ else if (format === 'tar') {
74
+ cmd.push('-Ft'); // Tar format
75
+ }
76
+ else if (format === 'directory') {
77
+ cmd.push('-Fd'); // Directory format
78
+ }
79
+ // 'sql' format - по умолчанию (plain SQL)
80
+ // Backup конкретных таблиц
81
+ if (options.tables && options.tables.length > 0) {
82
+ for (const table of options.tables) {
83
+ cmd.push('-t', table);
84
+ }
85
+ }
86
+ // Output file
87
+ cmd.push('-f', output);
88
+ // Пароль через PGPASSWORD
89
+ const envVars = conn.password ? [`PGPASSWORD=${conn.password}`] : [];
90
+ logger.info(`Creating PostgreSQL backup: ${output}`);
91
+ await this.containerManager.exec(service, project.name, cmd, {
92
+ env: envVars,
93
+ });
94
+ return output;
95
+ }
96
+ /**
97
+ * Восстановить из backup
98
+ */
99
+ async restore(service, backupPath, options) {
100
+ const project = await this.projectDiscovery.findProject();
101
+ const serviceConfig = project.services[service];
102
+ if (!serviceConfig) {
103
+ throw new Error(`Service '${service}' not found in project`);
104
+ }
105
+ const env = this.envManager.loadEnv(project.projectDir, service, serviceConfig);
106
+ const conn = this.getConnectionInfo(serviceConfig, env);
107
+ const db = options?.database || conn.database;
108
+ // Определяем формат backup по расширению
109
+ const isCustomFormat = backupPath.endsWith('.dump') || backupPath.endsWith('.backup');
110
+ let cmd;
111
+ if (isCustomFormat) {
112
+ // Custom format → pg_restore
113
+ cmd = ['pg_restore', '-U', conn.user, '-d', db];
114
+ if (options?.clean) {
115
+ cmd.push('--clean');
116
+ }
117
+ if (options?.dataOnly) {
118
+ cmd.push('--data-only');
119
+ }
120
+ if (options?.schemaOnly) {
121
+ cmd.push('--schema-only');
122
+ }
123
+ cmd.push(backupPath);
124
+ }
125
+ else {
126
+ // SQL format → psql
127
+ cmd = ['psql', '-U', conn.user, '-d', db, '-f', backupPath];
128
+ }
129
+ // Пароль через PGPASSWORD
130
+ const envVars = conn.password ? [`PGPASSWORD=${conn.password}`] : [];
131
+ logger.info(`Restoring PostgreSQL from backup: ${backupPath}`);
132
+ await this.containerManager.exec(service, project.name, cmd, {
133
+ env: envVars,
134
+ });
135
+ }
136
+ /**
137
+ * Получить статус БД
138
+ */
139
+ async status(service) {
140
+ const project = await this.projectDiscovery.findProject();
141
+ const serviceConfig = project.services[service];
142
+ if (!serviceConfig) {
143
+ throw new Error(`Service '${service}' not found in project`);
144
+ }
145
+ const env = this.envManager.loadEnv(project.projectDir, service, serviceConfig);
146
+ const conn = this.getConnectionInfo(serviceConfig, env);
147
+ // Получаем версию
148
+ const versionOutput = await this.query(service, 'SELECT version();');
149
+ const version = this.parseVersion(versionOutput);
150
+ // Получаем размер БД
151
+ const sizeOutput = await this.query(service, "SELECT pg_size_pretty(pg_database_size(current_database())) as size;");
152
+ const size = this.parseSingleValue(sizeOutput);
153
+ // Получаем количество подключений
154
+ const connectionsOutput = await this.query(service, "SELECT count(*) as connections FROM pg_stat_activity WHERE datname = current_database();");
155
+ const connections = parseInt(this.parseSingleValue(connectionsOutput) || '0');
156
+ // Получаем uptime
157
+ const uptimeOutput = await this.query(service, "SELECT date_trunc('second', current_timestamp - pg_postmaster_start_time()) as uptime;");
158
+ const uptime = this.parseSingleValue(uptimeOutput);
159
+ return {
160
+ type: 'postgresql',
161
+ version,
162
+ status: 'healthy',
163
+ size,
164
+ connections,
165
+ uptime,
166
+ };
167
+ }
168
+ /**
169
+ * Получить connection info из environment
170
+ */
171
+ getConnectionInfo(service, env) {
172
+ return {
173
+ host: 'localhost',
174
+ port: 5432,
175
+ user: env.POSTGRES_USER || 'postgres',
176
+ password: env.POSTGRES_PASSWORD,
177
+ database: env.POSTGRES_DB || 'postgres',
178
+ };
179
+ }
180
+ /**
181
+ * Парсит версию PostgreSQL из output
182
+ */
183
+ parseVersion(versionOutput) {
184
+ const match = versionOutput.match(/PostgreSQL\s+(\d+\.\d+)/i);
185
+ return match ? match[1] : 'unknown';
186
+ }
187
+ /**
188
+ * Парсит одно значение из SQL output (первая строка, первый столбец)
189
+ */
190
+ parseSingleValue(output) {
191
+ // Простой парсинг: берем первую строку после заголовка
192
+ const lines = output.split('\n').filter((line) => line.trim().length > 0);
193
+ if (lines.length < 2) {
194
+ return '';
195
+ }
196
+ // Пропускаем заголовок, берем первую строку данных
197
+ const dataLine = lines[1];
198
+ // Убираем лишние пробелы
199
+ return dataLine.trim();
200
+ }
201
+ }
202
+ //# sourceMappingURL=postgresql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgresql.js","sourceRoot":"","sources":["../../src/adapters/postgresql.ts"],"names":[],"mappings":"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"}