@masonator/coolify-mcp 0.1.3 → 0.1.4

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.
@@ -1,469 +1,208 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const coolify_client_js_1 = require("../lib/coolify-client.js");
4
- // Mock fetch globally
1
+ import { jest } from '@jest/globals';
2
+ import { CoolifyClient } from '../lib/coolify-client.js';
5
3
  const mockFetch = jest.fn();
6
- global.fetch = mockFetch;
7
4
  describe('CoolifyClient', () => {
8
5
  let client;
9
- beforeEach(() => {
10
- client = new coolify_client_js_1.CoolifyClient({
11
- baseUrl: 'http://test.coolify.io',
12
- accessToken: 'test-token',
13
- });
14
- mockFetch.mockClear();
15
- // Reset any global mock implementations
16
- mockFetch.mockReset();
17
- });
18
- describe('listServers', () => {
19
- const mockServers = [
6
+ const mockServers = [
7
+ {
8
+ id: 1,
9
+ uuid: 'test-uuid',
10
+ name: 'test-server',
11
+ status: 'running',
12
+ },
13
+ ];
14
+ const mockServerInfo = {
15
+ id: 1,
16
+ uuid: 'test-uuid',
17
+ name: 'test-server',
18
+ status: 'running',
19
+ };
20
+ const mockServerResources = {
21
+ resources: [
20
22
  {
21
- uuid: 'test-id-1',
22
- name: 'test-server-1',
23
- status: 'running',
24
- version: '1.0.0',
25
- resources: {
26
- cpu: 50,
27
- memory: 60,
28
- disk: 70,
29
- },
23
+ name: 'memory',
24
+ value: '2GB',
30
25
  },
31
26
  {
32
- uuid: 'test-id-2',
33
- name: 'test-server-2',
34
- status: 'stopped',
35
- version: '1.0.0',
36
- resources: {
37
- cpu: 0,
38
- memory: 0,
39
- disk: 70,
40
- },
27
+ name: 'disk',
28
+ value: '20GB',
41
29
  },
42
- ];
43
- it('should fetch server list successfully', async () => {
44
- mockFetch.mockResolvedValueOnce({
30
+ ],
31
+ };
32
+ const mockService = {
33
+ id: 1,
34
+ uuid: 'test-uuid',
35
+ name: 'test-service',
36
+ type: 'code-server',
37
+ status: 'running',
38
+ created_at: '2024-01-01',
39
+ updated_at: '2024-01-01',
40
+ };
41
+ const errorResponse = {
42
+ message: 'Resource not found',
43
+ };
44
+ beforeEach(() => {
45
+ mockFetch.mockClear();
46
+ global.fetch = mockFetch;
47
+ client = new CoolifyClient({
48
+ baseUrl: 'http://localhost:3000',
49
+ accessToken: 'test-api-key',
50
+ });
51
+ });
52
+ describe('listServers', () => {
53
+ it('should return a list of servers', async () => {
54
+ mockFetch.mockImplementationOnce(async () => ({
45
55
  ok: true,
46
56
  json: async () => mockServers,
47
- });
48
- const result = await client.listServers();
49
- expect(result).toEqual(mockServers);
50
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers', expect.objectContaining({
51
- headers: expect.objectContaining({
52
- Authorization: 'Bearer test-token',
53
- 'Content-Type': 'application/json',
54
- }),
55
57
  }));
58
+ const servers = await client.listServers();
59
+ expect(servers).toEqual(mockServers);
60
+ expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/servers', {
61
+ headers: {
62
+ 'Content-Type': 'application/json',
63
+ Authorization: 'Bearer test-api-key',
64
+ },
65
+ });
56
66
  });
57
- it('should handle error responses', async () => {
58
- const errorResponse = {
59
- error: 'Unauthorized',
60
- status: 401,
61
- message: 'Invalid token',
62
- };
63
- mockFetch.mockResolvedValueOnce({
67
+ it('should handle errors', async () => {
68
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
64
69
  ok: false,
65
70
  json: async () => errorResponse,
66
- });
67
- await expect(client.listServers()).rejects.toThrow('Invalid token');
71
+ }));
72
+ await expect(client.listServers()).rejects.toThrow('Resource not found');
68
73
  });
69
74
  });
70
75
  describe('getServer', () => {
71
- const mockServerInfo = {
72
- uuid: 'test-id',
73
- name: 'test-server',
74
- status: 'running',
75
- version: '1.0.0',
76
- resources: {
77
- cpu: 50,
78
- memory: 60,
79
- disk: 70,
80
- },
81
- };
82
- it('should fetch server info successfully', async () => {
83
- mockFetch.mockResolvedValueOnce({
76
+ it('should get server info', async () => {
77
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
84
78
  ok: true,
85
79
  json: async () => mockServerInfo,
86
- });
87
- const result = await client.getServer('test-id');
80
+ }));
81
+ const result = await client.getServer('test-uuid');
88
82
  expect(result).toEqual(mockServerInfo);
89
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers/test-id', expect.objectContaining({
90
- headers: expect.objectContaining({
91
- Authorization: 'Bearer test-token',
83
+ expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/servers/test-uuid', {
84
+ headers: {
92
85
  'Content-Type': 'application/json',
93
- }),
94
- }));
95
- });
96
- it('should handle error responses', async () => {
97
- const errorResponse = {
98
- error: 'Not Found',
99
- status: 404,
100
- message: 'Server not found',
101
- };
102
- mockFetch.mockResolvedValueOnce({
103
- ok: false,
104
- json: async () => errorResponse,
86
+ Authorization: 'Bearer test-api-key',
87
+ },
105
88
  });
106
- await expect(client.getServer('invalid-id')).rejects.toThrow('Server not found');
107
89
  });
108
- });
109
- describe('getServerResources', () => {
110
- const mockServerResources = [
111
- {
112
- id: 1,
113
- uuid: 'test-id',
114
- name: 'test-app',
115
- type: 'application',
116
- created_at: '2024-03-19T12:00:00Z',
117
- updated_at: '2024-03-19T12:00:00Z',
118
- status: 'running:healthy',
119
- },
120
- ];
121
- it('should fetch server resources successfully', async () => {
122
- mockFetch.mockResolvedValueOnce({
123
- ok: true,
124
- json: async () => mockServerResources,
125
- });
126
- const result = await client.getServerResources('test-id');
127
- expect(result).toEqual(mockServerResources);
128
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers/test-id/resources', expect.objectContaining({
129
- headers: expect.objectContaining({
130
- Authorization: 'Bearer test-token',
131
- 'Content-Type': 'application/json',
132
- }),
133
- }));
134
- });
135
- it('should handle error responses', async () => {
136
- const errorResponse = {
137
- error: 'Server Error',
138
- status: 500,
139
- message: 'Internal server error',
140
- };
141
- mockFetch.mockResolvedValueOnce({
90
+ it('should handle errors', async () => {
91
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
142
92
  ok: false,
143
93
  json: async () => errorResponse,
144
- });
145
- await expect(client.getServerResources('test-id')).rejects.toThrow('Internal server error');
146
- });
147
- });
148
- test('getServer returns server info', async () => {
149
- const mockResponse = {
150
- uuid: 'test-uuid',
151
- name: 'test-server',
152
- status: 'running',
153
- version: '1.0.0',
154
- resources: {
155
- cpu: 50,
156
- memory: 60,
157
- disk: 70,
158
- },
159
- };
160
- mockFetch.mockResolvedValueOnce({
161
- ok: true,
162
- json: () => Promise.resolve(mockResponse),
163
- });
164
- const server = await client.getServer('test-uuid');
165
- expect(server).toEqual(mockResponse);
166
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers/test-uuid', expect.objectContaining({
167
- headers: {
168
- Authorization: 'Bearer test-token',
169
- 'Content-Type': 'application/json',
170
- },
171
- }));
172
- });
173
- test('getServerResources returns server resources', async () => {
174
- const mockResponse = [
175
- {
176
- id: 1,
177
- uuid: 'test-uuid',
178
- name: 'test-app',
179
- type: 'application',
180
- created_at: '2025-03-05T13:41:12.000Z',
181
- updated_at: '2025-03-05T13:41:12.000Z',
182
- status: 'running:healthy',
183
- },
184
- ];
185
- mockFetch.mockResolvedValueOnce({
186
- ok: true,
187
- json: () => Promise.resolve(mockResponse),
188
- });
189
- const resources = await client.getServerResources('test-uuid');
190
- expect(resources).toEqual(mockResponse);
191
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers/test-uuid/resources', expect.objectContaining({
192
- headers: {
193
- Authorization: 'Bearer test-token',
194
- 'Content-Type': 'application/json',
195
- },
196
- }));
197
- });
198
- describe('Environment Management', () => {
199
- const mockEnvironment = {
200
- id: 1,
201
- uuid: 'jw0gwo4sowkoowswssk0gkc4',
202
- name: 'production',
203
- project_uuid: 'ikokwc8sk00wk8sg8gkwoscw',
204
- created_at: '2025-02-11T11:37:33.000000Z',
205
- updated_at: '2025-02-11T11:37:33.000000Z',
206
- };
207
- beforeEach(() => {
208
- mockFetch.mockClear();
209
- });
210
- describe('getProjectEnvironment', () => {
211
- it('should fetch environment by project UUID and name/UUID successfully', async () => {
212
- mockFetch.mockResolvedValueOnce({
213
- ok: true,
214
- json: () => Promise.resolve(mockEnvironment),
215
- });
216
- const result = await client.getProjectEnvironment('ikokwc8sk00wk8sg8gkwoscw', 'production');
217
- expect(result).toEqual(mockEnvironment);
218
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/projects/ikokwc8sk00wk8sg8gkwoscw/production', expect.objectContaining({
219
- headers: expect.objectContaining({
220
- Authorization: 'Bearer test-token',
221
- 'Content-Type': 'application/json',
222
- }),
223
- }));
224
- });
225
- it('should handle not found error', async () => {
226
- const errorResponse = {
227
- error: 'Not Found',
228
- status: 404,
229
- message: 'Environment not found',
230
- };
231
- mockFetch.mockResolvedValueOnce({
232
- ok: false,
233
- json: () => Promise.resolve(errorResponse),
234
- });
235
- await expect(client.getProjectEnvironment('invalid-project', 'invalid-env')).rejects.toThrow('Environment not found');
236
- });
237
- });
238
- });
239
- describe('deployApplication', () => {
240
- it('should deploy an application', async () => {
241
- const mockDeployment = {
242
- id: 1,
243
- uuid: 'test-deployment-uuid',
244
- application_uuid: 'test-app-uuid',
245
- status: 'running',
246
- created_at: '2024-03-20T12:00:00Z',
247
- updated_at: '2024-03-20T12:00:00Z',
248
- };
249
- mockFetch.mockResolvedValueOnce({
250
- ok: true,
251
- json: () => Promise.resolve(mockDeployment),
252
- });
253
- const result = await client.deployApplication('test-app-uuid');
254
- expect(result).toEqual(mockDeployment);
255
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/applications/test-app-uuid/deploy', expect.objectContaining({
256
- method: 'POST',
257
- headers: expect.objectContaining({
258
- Authorization: 'Bearer test-token',
259
- 'Content-Type': 'application/json',
260
- }),
261
94
  }));
262
- });
263
- it('should handle errors when deploying an application', async () => {
264
- const errorResponse = {
265
- error: 'Error',
266
- status: 500,
267
- message: 'Failed to deploy application',
268
- };
269
- mockFetch.mockResolvedValueOnce({
270
- ok: false,
271
- json: () => Promise.resolve(errorResponse),
272
- });
273
- await expect(client.deployApplication('test-app-uuid')).rejects.toThrow('Failed to deploy application');
95
+ await expect(client.getServer('test-uuid')).rejects.toThrow('Resource not found');
274
96
  });
275
97
  });
276
- describe('Database Management', () => {
277
- const mockDatabase = {
278
- id: 1,
279
- uuid: 'test-db-uuid',
280
- name: 'test-db',
281
- description: 'Test database',
282
- type: 'postgresql',
283
- status: 'running',
284
- created_at: '2024-03-06T12:00:00Z',
285
- updated_at: '2024-03-06T12:00:00Z',
286
- is_public: false,
287
- image: 'postgres:latest',
288
- postgres_user: 'postgres',
289
- postgres_password: 'test123',
290
- postgres_db: 'testdb',
291
- };
292
- beforeEach(() => {
293
- mockFetch.mockClear();
294
- });
295
- it('should list databases', async () => {
296
- mockFetch.mockResolvedValueOnce({
98
+ describe('getServerResources', () => {
99
+ it('should get server resources', async () => {
100
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
297
101
  ok: true,
298
- json: () => Promise.resolve([mockDatabase]),
299
- });
300
- const result = await client.listDatabases();
301
- expect(result).toEqual([mockDatabase]);
302
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/databases', expect.objectContaining({
303
- headers: {
304
- 'Content-Type': 'application/json',
305
- Authorization: 'Bearer test-token',
306
- },
102
+ json: async () => mockServerResources,
307
103
  }));
308
- });
309
- it('should get database details', async () => {
310
- mockFetch.mockResolvedValueOnce({
311
- ok: true,
312
- json: () => Promise.resolve(mockDatabase),
313
- });
314
- const result = await client.getDatabase('test-db-uuid');
315
- expect(result).toEqual(mockDatabase);
316
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/databases/test-db-uuid', expect.objectContaining({
104
+ const result = await client.getServerResources('test-uuid');
105
+ expect(result).toEqual(mockServerResources);
106
+ expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/servers/test-uuid/resources', {
317
107
  headers: {
318
108
  'Content-Type': 'application/json',
319
- Authorization: 'Bearer test-token',
109
+ Authorization: 'Bearer test-api-key',
320
110
  },
321
- }));
322
- });
323
- it('should update database', async () => {
324
- const updateData = {
325
- name: 'updated-db',
326
- description: 'Updated description',
327
- };
328
- mockFetch.mockResolvedValueOnce({
329
- ok: true,
330
- json: () => Promise.resolve({ ...mockDatabase, ...updateData }),
331
111
  });
332
- const result = await client.updateDatabase('test-db-uuid', updateData);
333
- expect(result).toEqual({ ...mockDatabase, ...updateData });
334
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/databases/test-db-uuid', expect.objectContaining({
335
- method: 'PATCH',
336
- body: JSON.stringify(updateData),
337
- headers: {
338
- 'Content-Type': 'application/json',
339
- Authorization: 'Bearer test-token',
340
- },
341
- }));
342
112
  });
343
- it('should delete database', async () => {
344
- const mockResponse = { message: 'Database deleted' };
345
- mockFetch.mockResolvedValueOnce({
346
- ok: true,
347
- json: () => Promise.resolve(mockResponse),
348
- });
349
- const result = await client.deleteDatabase('test-db-uuid', {
350
- deleteConfigurations: true,
351
- deleteVolumes: true,
352
- });
353
- expect(result).toEqual(mockResponse);
354
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/databases/test-db-uuid?delete_configurations=true&delete_volumes=true', expect.objectContaining({
355
- method: 'DELETE',
356
- headers: {
357
- 'Content-Type': 'application/json',
358
- Authorization: 'Bearer test-token',
359
- },
113
+ it('should handle errors', async () => {
114
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
115
+ ok: false,
116
+ json: async () => errorResponse,
360
117
  }));
361
- });
362
- it('should handle database errors', async () => {
363
- const errorMessage = 'Database not found';
364
- mockFetch.mockRejectedValue(new Error(errorMessage));
365
- await expect(client.getDatabase('invalid-uuid')).rejects.toThrow(errorMessage);
118
+ await expect(client.getServerResources('test-uuid')).rejects.toThrow('Resource not found');
366
119
  });
367
120
  });
368
- describe('Service Management', () => {
369
- const mockService = {
370
- id: 1,
371
- uuid: 'test-service-uuid',
372
- name: 'test-service',
373
- description: 'Test service',
374
- type: 'code-server',
375
- status: 'running',
376
- created_at: '2024-03-06T12:00:00Z',
377
- updated_at: '2024-03-06T12:00:00Z',
378
- project_uuid: 'test-project-uuid',
379
- environment_name: 'production',
380
- environment_uuid: 'test-env-uuid',
381
- server_uuid: 'test-server-uuid',
382
- domains: ['test-service.example.com'],
383
- };
384
- beforeEach(() => {
385
- mockFetch.mockClear();
386
- });
121
+ describe('listServices', () => {
387
122
  it('should list services', async () => {
388
- mockFetch.mockResolvedValueOnce({
123
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
389
124
  ok: true,
390
125
  json: () => Promise.resolve([mockService]),
391
- });
126
+ }));
392
127
  const result = await client.listServices();
393
128
  expect(result).toEqual([mockService]);
394
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/services', expect.objectContaining({
129
+ expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/services', {
395
130
  headers: {
396
131
  'Content-Type': 'application/json',
397
- Authorization: 'Bearer test-token',
132
+ Authorization: 'Bearer test-api-key',
398
133
  },
399
- }));
134
+ });
400
135
  });
401
- it('should get service details', async () => {
402
- mockFetch.mockResolvedValueOnce({
136
+ });
137
+ describe('getService', () => {
138
+ it('should get service info', async () => {
139
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
403
140
  ok: true,
404
141
  json: () => Promise.resolve(mockService),
405
- });
406
- const result = await client.getService('test-service-uuid');
142
+ }));
143
+ const result = await client.getService('test-uuid');
407
144
  expect(result).toEqual(mockService);
408
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/services/test-service-uuid', expect.objectContaining({
145
+ expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/services/test-uuid', {
409
146
  headers: {
410
147
  'Content-Type': 'application/json',
411
- Authorization: 'Bearer test-token',
148
+ Authorization: 'Bearer test-api-key',
412
149
  },
413
- }));
150
+ });
414
151
  });
415
- it('should create service', async () => {
152
+ });
153
+ describe('createService', () => {
154
+ it('should create a service', async () => {
155
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
156
+ ok: true,
157
+ json: () => Promise.resolve({
158
+ uuid: 'test-uuid',
159
+ domains: ['test.com'],
160
+ }),
161
+ }));
416
162
  const createData = {
417
- type: 'code-server',
418
163
  name: 'test-service',
419
- description: 'Test service',
420
- project_uuid: 'test-project-uuid',
421
- environment_name: 'production',
422
- server_uuid: 'test-server-uuid',
423
- instant_deploy: true,
424
- };
425
- const mockResponse = {
426
- uuid: 'test-service-uuid',
427
- domains: ['test-service.example.com'],
164
+ type: 'code-server',
165
+ project_uuid: 'project-uuid',
166
+ environment_uuid: 'env-uuid',
167
+ server_uuid: 'server-uuid',
428
168
  };
429
- mockFetch.mockResolvedValueOnce({
430
- ok: true,
431
- json: () => Promise.resolve(mockResponse),
432
- });
433
169
  const result = await client.createService(createData);
434
- expect(result).toEqual(mockResponse);
435
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/services', expect.objectContaining({
170
+ expect(result).toEqual({
171
+ uuid: 'test-uuid',
172
+ domains: ['test.com'],
173
+ });
174
+ expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/services', {
436
175
  method: 'POST',
437
- body: JSON.stringify(createData),
438
176
  headers: {
439
177
  'Content-Type': 'application/json',
440
- Authorization: 'Bearer test-token',
178
+ Authorization: 'Bearer test-api-key',
441
179
  },
442
- }));
180
+ body: JSON.stringify(createData),
181
+ });
443
182
  });
444
- it('should delete service', async () => {
445
- const mockResponse = { message: 'Service deleted' };
446
- mockFetch.mockResolvedValueOnce({
183
+ });
184
+ describe('deleteService', () => {
185
+ it('should delete a service', async () => {
186
+ mockFetch.mockImplementationOnce(() => Promise.resolve({
447
187
  ok: true,
448
- json: () => Promise.resolve(mockResponse),
449
- });
450
- const result = await client.deleteService('test-service-uuid', {
451
- deleteConfigurations: true,
452
- deleteVolumes: true,
453
- });
454
- expect(result).toEqual(mockResponse);
455
- expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/services/test-service-uuid?delete_configurations=true&delete_volumes=true', expect.objectContaining({
188
+ json: () => Promise.resolve({ message: 'Service deleted' }),
189
+ }));
190
+ const result = await client.deleteService('test-uuid');
191
+ expect(result).toEqual({ message: 'Service deleted' });
192
+ expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/services/test-uuid', {
456
193
  method: 'DELETE',
457
194
  headers: {
458
195
  'Content-Type': 'application/json',
459
- Authorization: 'Bearer test-token',
196
+ Authorization: 'Bearer test-api-key',
460
197
  },
461
- }));
198
+ });
462
199
  });
463
- it('should handle service errors', async () => {
464
- const errorMessage = 'Service not found';
465
- mockFetch.mockRejectedValue(new Error(errorMessage));
466
- await expect(client.getService('invalid-uuid')).rejects.toThrow(errorMessage);
200
+ });
201
+ describe('error handling', () => {
202
+ it('should handle network errors', async () => {
203
+ const errorMessage = 'Network error';
204
+ mockFetch.mockImplementationOnce(() => Promise.reject(new Error(errorMessage)));
205
+ await expect(client.listServers()).rejects.toThrow(errorMessage);
467
206
  });
468
207
  });
469
208
  });