@mks2508/coolify-mks-cli-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +11788 -0
- package/dist/coolify/config.d.ts +64 -0
- package/dist/coolify/config.d.ts.map +1 -0
- package/dist/coolify/index.d.ts +201 -0
- package/dist/coolify/index.d.ts.map +1 -0
- package/dist/coolify/types.d.ts +282 -0
- package/dist/coolify/types.d.ts.map +1 -0
- package/dist/index.cjs +29150 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29127 -0
- package/dist/index.js.map +1 -0
- package/dist/server/sse.d.ts +11 -0
- package/dist/server/sse.d.ts.map +1 -0
- package/dist/server/sse.js +32 -0
- package/dist/server/stdio.d.ts +13 -0
- package/dist/server/stdio.d.ts.map +1 -0
- package/dist/server/stdio.js +18326 -0
- package/dist/tools/definitions.d.ts +13 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/handlers.d.ts +19 -0
- package/dist/tools/handlers.d.ts.map +1 -0
- package/dist/utils/format.d.ts +38 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/package.json +67 -0
- package/src/cli/commands/config.ts +83 -0
- package/src/cli/commands/deploy.ts +56 -0
- package/src/cli/commands/env.ts +60 -0
- package/src/cli/commands/list.ts +63 -0
- package/src/cli/commands/logs.ts +49 -0
- package/src/cli/commands/servers.ts +52 -0
- package/src/cli/index.ts +81 -0
- package/src/coolify/config.ts +113 -0
- package/src/coolify/index.ts +688 -0
- package/src/coolify/types.ts +297 -0
- package/src/index.ts +864 -0
- package/src/server/sse.ts +50 -0
- package/src/server/stdio.ts +52 -0
- package/src/tools/definitions.ts +435 -0
- package/src/tools/handlers.ts +605 -0
- package/src/utils/format.ts +104 -0
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coolify service for MCP server and CLI.
|
|
3
|
+
*
|
|
4
|
+
* Provides all Coolify API operations for deployment management.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ok, err, isErr, type Result } from '@mks2508/no-throw'
|
|
10
|
+
import { component } from '@mks2508/better-logger'
|
|
11
|
+
import { loadConfig, type ICoolifyConfig } from './config.js'
|
|
12
|
+
import {
|
|
13
|
+
type ICoolifyAppOptions,
|
|
14
|
+
type ICoolifyAppResult,
|
|
15
|
+
type ICoolifyApplication,
|
|
16
|
+
type ICoolifyDeleteResult,
|
|
17
|
+
type ICoolifyDeployment,
|
|
18
|
+
type ICoolifyDeployOptions,
|
|
19
|
+
type ICoolifyDeployResult,
|
|
20
|
+
type ICoolifyDestination,
|
|
21
|
+
type ICoolifyLogs,
|
|
22
|
+
type ICoolifyLogsOptions,
|
|
23
|
+
type ICoolifyProject,
|
|
24
|
+
type ICoolifyServer,
|
|
25
|
+
type ICoolifyTeam,
|
|
26
|
+
type ICoolifyUpdateOptions,
|
|
27
|
+
type IProgressCallback,
|
|
28
|
+
} from './types.js'
|
|
29
|
+
|
|
30
|
+
const log = component('CoolifyService')
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Coolify API response type.
|
|
34
|
+
*/
|
|
35
|
+
interface ICoolifyApiResponse<T> {
|
|
36
|
+
data?: T
|
|
37
|
+
error?: string
|
|
38
|
+
status: number
|
|
39
|
+
durationMs?: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Environment variable from Coolify API.
|
|
44
|
+
*/
|
|
45
|
+
export interface ICoolifyEnvVar {
|
|
46
|
+
uuid: string
|
|
47
|
+
key: string
|
|
48
|
+
value: string
|
|
49
|
+
real_value?: string
|
|
50
|
+
is_buildtime: boolean
|
|
51
|
+
is_runtime: boolean
|
|
52
|
+
is_required: boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Coolify service for deployment operations.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const coolify = new CoolifyService()
|
|
61
|
+
* const initResult = await coolify.init()
|
|
62
|
+
* if (initResult.isErr()) {
|
|
63
|
+
* console.error(initResult.error.message)
|
|
64
|
+
* return
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* const deployResult = await coolify.deploy({ uuid: 'app-uuid' })
|
|
68
|
+
* if (deployResult.isOk()) {
|
|
69
|
+
* console.log('Deployment UUID:', deployResult.value.deploymentUuid)
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export class CoolifyService {
|
|
74
|
+
private baseUrl: string | undefined
|
|
75
|
+
private token: string | undefined
|
|
76
|
+
private config: ICoolifyConfig = {}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Checks if the service is configured with URL and token.
|
|
80
|
+
*
|
|
81
|
+
* @returns true if both URL and token are set
|
|
82
|
+
*/
|
|
83
|
+
isConfigured(): boolean {
|
|
84
|
+
const hasUrl = !!this.baseUrl || !!process.env.COOLIFY_URL
|
|
85
|
+
const hasToken = !!this.token || !!process.env.COOLIFY_TOKEN
|
|
86
|
+
return hasUrl && hasToken
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Initializes the Coolify service by loading configuration.
|
|
91
|
+
*
|
|
92
|
+
* @returns Result indicating success or error
|
|
93
|
+
*/
|
|
94
|
+
async init(): Promise<Result<void, Error>> {
|
|
95
|
+
const configResult = await loadConfig()
|
|
96
|
+
|
|
97
|
+
if (isErr(configResult)) {
|
|
98
|
+
log.error('Failed to load config')
|
|
99
|
+
return err(configResult.error)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.config = configResult.value
|
|
103
|
+
this.baseUrl = this.config.url || process.env.COOLIFY_URL
|
|
104
|
+
this.token = this.config.token || process.env.COOLIFY_TOKEN
|
|
105
|
+
|
|
106
|
+
if (!this.baseUrl) {
|
|
107
|
+
log.error('No Coolify URL configured')
|
|
108
|
+
log.info('Set COOLIFY_URL environment variable or run: coolify-mcp config set url <url>')
|
|
109
|
+
return err(new Error('No Coolify URL configured. Set COOLIFY_URL or use config command.'))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!this.token) {
|
|
113
|
+
log.error('No Coolify token configured')
|
|
114
|
+
log.info('Set COOLIFY_TOKEN environment variable or run: coolify-mcp config set token <token>')
|
|
115
|
+
return err(new Error('No Coolify token configured. Set COOLIFY_TOKEN or use config command.'))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
log.debug('Coolify connection configured')
|
|
119
|
+
return ok(undefined)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Makes a request to the Coolify API.
|
|
124
|
+
*
|
|
125
|
+
* @param endpoint - API endpoint
|
|
126
|
+
* @param options - Fetch options
|
|
127
|
+
* @returns API response with data or error
|
|
128
|
+
*/
|
|
129
|
+
private async request<T>(
|
|
130
|
+
endpoint: string,
|
|
131
|
+
options: RequestInit = {}
|
|
132
|
+
): Promise<ICoolifyApiResponse<T>> {
|
|
133
|
+
const startTime = Date.now()
|
|
134
|
+
|
|
135
|
+
if (!this.baseUrl || !this.token) {
|
|
136
|
+
return { error: 'Coolify not configured', status: 0, durationMs: Date.now() - startTime }
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const url = `${this.baseUrl}/api/v1${endpoint}`
|
|
141
|
+
const response = await fetch(url, {
|
|
142
|
+
...options,
|
|
143
|
+
headers: {
|
|
144
|
+
Authorization: `Bearer ${this.token}`,
|
|
145
|
+
'Content-Type': 'application/json',
|
|
146
|
+
Accept: 'application/json',
|
|
147
|
+
...options.headers,
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
const text = await response.text()
|
|
152
|
+
const durationMs = Date.now() - startTime
|
|
153
|
+
let data: T | undefined
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
data = text ? JSON.parse(text) : undefined
|
|
157
|
+
} catch {
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
return { error: text || `HTTP ${response.status}`, status: response.status, durationMs }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!response.ok) {
|
|
164
|
+
const errorMessage =
|
|
165
|
+
(data as { message?: string } | undefined)?.message ||
|
|
166
|
+
`HTTP ${response.status}`
|
|
167
|
+
return { error: errorMessage, status: response.status, durationMs }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return { data, status: response.status, durationMs }
|
|
171
|
+
} catch (error) {
|
|
172
|
+
const message = error instanceof Error ? error.message : 'Unknown error'
|
|
173
|
+
return { error: message, status: 0, durationMs: Date.now() - startTime }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Deploys an application.
|
|
179
|
+
*
|
|
180
|
+
* @param options - Deployment options
|
|
181
|
+
* @param onProgress - Optional progress callback (0-100, message, step)
|
|
182
|
+
* @returns Result with deployment info or error
|
|
183
|
+
*/
|
|
184
|
+
async deploy(
|
|
185
|
+
options: ICoolifyDeployOptions,
|
|
186
|
+
onProgress?: IProgressCallback
|
|
187
|
+
): Promise<Result<ICoolifyDeployResult, Error>> {
|
|
188
|
+
if (!options.uuid && !options.tag) {
|
|
189
|
+
return err(new Error('Either uuid or tag is required'))
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const appId = options.uuid?.slice(0, 8) || options.tag || 'unknown'
|
|
193
|
+
onProgress?.(5, `Preparing deployment for ${appId}...`)
|
|
194
|
+
|
|
195
|
+
log.info(`Deploying application ${options.uuid || options.tag}`)
|
|
196
|
+
|
|
197
|
+
onProgress?.(25, 'Validating deployment configuration')
|
|
198
|
+
onProgress?.(50, 'Triggering build pipeline...')
|
|
199
|
+
|
|
200
|
+
const result = await this.request<{
|
|
201
|
+
resource_uuid: string
|
|
202
|
+
deployment_uuid: string
|
|
203
|
+
}>('/deploy', {
|
|
204
|
+
method: 'POST',
|
|
205
|
+
body: JSON.stringify({
|
|
206
|
+
uuid: options.uuid,
|
|
207
|
+
tag: options.tag,
|
|
208
|
+
force: options.force ?? false,
|
|
209
|
+
}),
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
if (result.error) {
|
|
213
|
+
log.error(`Deployment failed: ${result.error}`)
|
|
214
|
+
return err(new Error(result.error))
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
onProgress?.(90, 'Build started on Coolify server')
|
|
218
|
+
onProgress?.(100, 'Deployment triggered')
|
|
219
|
+
|
|
220
|
+
log.success(`Deployment started: ${result.data?.deployment_uuid}`)
|
|
221
|
+
return ok({
|
|
222
|
+
success: true,
|
|
223
|
+
deploymentUuid: result.data?.deployment_uuid,
|
|
224
|
+
resourceUuid: result.data?.resource_uuid,
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Creates a new application in Coolify.
|
|
230
|
+
*
|
|
231
|
+
* @param options - Application options
|
|
232
|
+
* @param onProgress - Optional progress callback (0-100, message, step)
|
|
233
|
+
* @returns Result with application UUID or error
|
|
234
|
+
*/
|
|
235
|
+
async createApplication(
|
|
236
|
+
options: ICoolifyAppOptions,
|
|
237
|
+
onProgress?: IProgressCallback
|
|
238
|
+
): Promise<Result<ICoolifyAppResult, Error>> {
|
|
239
|
+
onProgress?.(5, `Preparing app "${options.name}"`)
|
|
240
|
+
|
|
241
|
+
log.info(`Creating application ${options.name}`)
|
|
242
|
+
|
|
243
|
+
onProgress?.(25, `Validating server ${options.serverUuid.slice(0, 8)}...`)
|
|
244
|
+
onProgress?.(50, 'Sending creation request to Coolify API...')
|
|
245
|
+
|
|
246
|
+
const result = await this.request<{ uuid: string }>('/applications', {
|
|
247
|
+
method: 'POST',
|
|
248
|
+
body: JSON.stringify({
|
|
249
|
+
name: options.name,
|
|
250
|
+
description: options.description,
|
|
251
|
+
server_uuid: options.serverUuid,
|
|
252
|
+
destination_uuid: options.destinationUuid,
|
|
253
|
+
project_uuid: options.serverUuid,
|
|
254
|
+
environment_name: 'production',
|
|
255
|
+
git_repository: options.githubRepoUrl,
|
|
256
|
+
git_branch: options.branch || 'main',
|
|
257
|
+
build_pack: options.buildPack || 'nixpacks',
|
|
258
|
+
ports_exposes: '3000',
|
|
259
|
+
instant_deploy: false,
|
|
260
|
+
}),
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
if (result.error) {
|
|
264
|
+
log.error(`Failed to create application: ${result.error}`)
|
|
265
|
+
return err(new Error(result.error))
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
onProgress?.(100, `Application "${options.name}" created`)
|
|
269
|
+
|
|
270
|
+
log.success(`Application created: ${result.data?.uuid}`)
|
|
271
|
+
return ok({
|
|
272
|
+
success: true,
|
|
273
|
+
uuid: result.data?.uuid,
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Sets environment variables for an application.
|
|
279
|
+
*
|
|
280
|
+
* @param appUuid - Application UUID
|
|
281
|
+
* @param envVars - Environment variables to set
|
|
282
|
+
* @returns Result indicating success or error
|
|
283
|
+
*/
|
|
284
|
+
async setEnvironmentVariables(
|
|
285
|
+
appUuid: string,
|
|
286
|
+
envVars: Record<string, string>
|
|
287
|
+
): Promise<Result<void, Error>> {
|
|
288
|
+
log.info(`Setting environment variables for ${appUuid}`)
|
|
289
|
+
|
|
290
|
+
const envArray = Object.entries(envVars).map(([key, value]) => ({
|
|
291
|
+
key,
|
|
292
|
+
value,
|
|
293
|
+
is_build_time: false,
|
|
294
|
+
}))
|
|
295
|
+
|
|
296
|
+
const result = await this.request(`/applications/${appUuid}/envs`, {
|
|
297
|
+
method: 'POST',
|
|
298
|
+
body: JSON.stringify({ data: envArray }),
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
if (result.error) {
|
|
302
|
+
log.error(`Failed to set env vars: ${result.error}`)
|
|
303
|
+
return err(new Error(result.error))
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
log.success('Environment variables set')
|
|
307
|
+
return ok(undefined)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Gets environment variables for an application.
|
|
312
|
+
*
|
|
313
|
+
* @param appUuid - Application UUID
|
|
314
|
+
* @returns Result with environment variables or error
|
|
315
|
+
*/
|
|
316
|
+
async getEnvironmentVariables(
|
|
317
|
+
appUuid: string
|
|
318
|
+
): Promise<Result<ICoolifyEnvVar[], Error>> {
|
|
319
|
+
log.info(`Getting environment variables for ${appUuid}`)
|
|
320
|
+
|
|
321
|
+
const result = await this.request<ICoolifyEnvVar[]>(
|
|
322
|
+
`/applications/${appUuid}/envs`
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
if (result.error) {
|
|
326
|
+
log.error(`Failed to get env vars: ${result.error}`)
|
|
327
|
+
return err(new Error(result.error))
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
log.success(`Environment variables retrieved for ${appUuid}`)
|
|
331
|
+
return ok(result.data || [])
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Gets the status of an application.
|
|
336
|
+
*
|
|
337
|
+
* @param appUuid - Application UUID
|
|
338
|
+
* @returns Result with status or error
|
|
339
|
+
*/
|
|
340
|
+
async getApplicationStatus(
|
|
341
|
+
appUuid: string
|
|
342
|
+
): Promise<Result<string, Error>> {
|
|
343
|
+
const result = await this.request<{ status: string }>(
|
|
344
|
+
`/applications/${appUuid}`
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
if (result.error) {
|
|
348
|
+
return err(new Error(result.error))
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return ok(result.data?.status || 'unknown')
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Lists available servers in Coolify.
|
|
356
|
+
*
|
|
357
|
+
* @returns Result with servers or error
|
|
358
|
+
*/
|
|
359
|
+
async listServers(): Promise<Result<ICoolifyServer[], Error>> {
|
|
360
|
+
const result = await this.request<ICoolifyServer[]>('/servers')
|
|
361
|
+
|
|
362
|
+
if (result.error) {
|
|
363
|
+
return err(new Error(result.error))
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return ok(result.data || [])
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Gets details of a specific server.
|
|
371
|
+
*
|
|
372
|
+
* @param serverUuid - Server UUID
|
|
373
|
+
* @returns Result with server details or error
|
|
374
|
+
*/
|
|
375
|
+
async getServer(
|
|
376
|
+
serverUuid: string
|
|
377
|
+
): Promise<Result<ICoolifyServer, Error>> {
|
|
378
|
+
log.info(`Getting server details for ${serverUuid}`)
|
|
379
|
+
|
|
380
|
+
const result = await this.request<ICoolifyServer>(`/servers/${serverUuid}`)
|
|
381
|
+
|
|
382
|
+
if (result.error) {
|
|
383
|
+
log.error(`Failed to get server: ${result.error}`)
|
|
384
|
+
return err(new Error(result.error))
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
log.success(`Server details retrieved: ${serverUuid}`)
|
|
388
|
+
return ok(result.data as ICoolifyServer)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Lists all projects.
|
|
393
|
+
*
|
|
394
|
+
* @returns Result with projects list or error
|
|
395
|
+
*/
|
|
396
|
+
async listProjects(): Promise<Result<ICoolifyProject[], Error>> {
|
|
397
|
+
const result = await this.request<ICoolifyProject[]>('/projects')
|
|
398
|
+
|
|
399
|
+
if (result.error) {
|
|
400
|
+
return err(new Error(result.error))
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return ok(result.data || [])
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Lists all teams.
|
|
408
|
+
*
|
|
409
|
+
* @returns Result with teams list or error
|
|
410
|
+
*/
|
|
411
|
+
async listTeams(): Promise<Result<ICoolifyTeam[], Error>> {
|
|
412
|
+
const result = await this.request<ICoolifyTeam[]>('/teams')
|
|
413
|
+
|
|
414
|
+
if (result.error) {
|
|
415
|
+
return err(new Error(result.error))
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return ok(result.data || [])
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Gets available destinations for a server.
|
|
423
|
+
*
|
|
424
|
+
* @param serverUuid - Server UUID
|
|
425
|
+
* @returns Result with destinations or error
|
|
426
|
+
*/
|
|
427
|
+
async getServerDestinations(
|
|
428
|
+
serverUuid: string
|
|
429
|
+
): Promise<Result<ICoolifyDestination[], Error>> {
|
|
430
|
+
const result = await this.request<{
|
|
431
|
+
destinations: ICoolifyDestination[]
|
|
432
|
+
}>(`/servers/${serverUuid}`)
|
|
433
|
+
|
|
434
|
+
if (result.error) {
|
|
435
|
+
return err(new Error(result.error))
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return ok(result.data?.destinations || [])
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Lists all applications.
|
|
443
|
+
*
|
|
444
|
+
* @param teamId - Optional team ID to filter by
|
|
445
|
+
* @param projectId - Optional project ID to filter by
|
|
446
|
+
* @returns Result with applications list or error
|
|
447
|
+
*/
|
|
448
|
+
async listApplications(
|
|
449
|
+
teamId?: string,
|
|
450
|
+
projectId?: string
|
|
451
|
+
): Promise<Result<ICoolifyApplication[], Error>> {
|
|
452
|
+
log.info('Listing applications')
|
|
453
|
+
|
|
454
|
+
let endpoint = '/applications'
|
|
455
|
+
const params = new URLSearchParams()
|
|
456
|
+
if (teamId) params.set('team_id', teamId)
|
|
457
|
+
if (projectId) params.set('project_id', projectId)
|
|
458
|
+
if (params.toString()) {
|
|
459
|
+
endpoint += `?${params.toString()}`
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const result = await this.request<ICoolifyApplication[]>(endpoint)
|
|
463
|
+
|
|
464
|
+
if (result.error) {
|
|
465
|
+
log.error(`Failed to list applications: ${result.error}`)
|
|
466
|
+
return err(new Error(result.error))
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
log.success(`Listed ${result.data?.length || 0} applications`)
|
|
470
|
+
return ok(result.data || [])
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Deletes an application.
|
|
475
|
+
*
|
|
476
|
+
* @param appUuid - Application UUID
|
|
477
|
+
* @returns Result indicating success or error
|
|
478
|
+
*/
|
|
479
|
+
async deleteApplication(
|
|
480
|
+
appUuid: string
|
|
481
|
+
): Promise<Result<ICoolifyDeleteResult, Error>> {
|
|
482
|
+
log.info(`Deleting application ${appUuid}`)
|
|
483
|
+
|
|
484
|
+
const result = await this.request<ICoolifyDeleteResult>(`/applications/${appUuid}`, {
|
|
485
|
+
method: 'DELETE',
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
if (result.error) {
|
|
489
|
+
log.error(`Failed to delete application: ${result.error}`)
|
|
490
|
+
return err(new Error(result.error))
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
log.success(`Application deleted: ${appUuid}`)
|
|
494
|
+
return ok({ success: true, message: 'Application deleted' })
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Updates an application configuration.
|
|
499
|
+
*
|
|
500
|
+
* @param appUuid - Application UUID
|
|
501
|
+
* @param options - Update options
|
|
502
|
+
* @returns Result with updated application or error
|
|
503
|
+
*/
|
|
504
|
+
async updateApplication(
|
|
505
|
+
appUuid: string,
|
|
506
|
+
options: ICoolifyUpdateOptions
|
|
507
|
+
): Promise<Result<ICoolifyApplication, Error>> {
|
|
508
|
+
log.info(`Updating application ${appUuid}`)
|
|
509
|
+
|
|
510
|
+
const body: Record<string, unknown> = {}
|
|
511
|
+
if (options.name) body.name = options.name
|
|
512
|
+
if (options.description) body.description = options.description
|
|
513
|
+
if (options.buildPack) body.build_pack = options.buildPack
|
|
514
|
+
if (options.gitBranch) body.git_branch = options.gitBranch
|
|
515
|
+
if (options.portsExposes) body.ports_exposes = options.portsExposes
|
|
516
|
+
if (options.installCommand) body.install_command = options.installCommand
|
|
517
|
+
if (options.buildCommand) body.build_command = options.buildCommand
|
|
518
|
+
if (options.startCommand) body.start_command = options.startCommand
|
|
519
|
+
|
|
520
|
+
const result = await this.request<ICoolifyApplication>(`/applications/${appUuid}`, {
|
|
521
|
+
method: 'PATCH',
|
|
522
|
+
body: JSON.stringify(body),
|
|
523
|
+
})
|
|
524
|
+
|
|
525
|
+
if (result.error) {
|
|
526
|
+
log.error(`Failed to update application: ${result.error}`)
|
|
527
|
+
return err(new Error(result.error))
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
log.success(`Application updated: ${appUuid}`)
|
|
531
|
+
return ok(result.data as ICoolifyApplication)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Gets application logs.
|
|
536
|
+
*
|
|
537
|
+
* @param appUuid - Application UUID
|
|
538
|
+
* @param options - Log retrieval options
|
|
539
|
+
* @returns Result with logs or error
|
|
540
|
+
*/
|
|
541
|
+
async getApplicationLogs(
|
|
542
|
+
appUuid: string,
|
|
543
|
+
options: ICoolifyLogsOptions = {}
|
|
544
|
+
): Promise<Result<ICoolifyLogs, Error>> {
|
|
545
|
+
log.info(`Getting logs for application ${appUuid}`)
|
|
546
|
+
|
|
547
|
+
const params = new URLSearchParams()
|
|
548
|
+
if (options.follow) params.set('follow', 'true')
|
|
549
|
+
if (options.tail) params.set('tail', options.tail.toString())
|
|
550
|
+
|
|
551
|
+
const endpoint = `/applications/${appUuid}/logs${params.toString() ? `?${params.toString()}` : ''}`
|
|
552
|
+
|
|
553
|
+
const result = await this.request<{ logs: string[] }>(endpoint)
|
|
554
|
+
|
|
555
|
+
if (result.error) {
|
|
556
|
+
log.error(`Failed to get logs: ${result.error}`)
|
|
557
|
+
return err(new Error(result.error))
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
log.success(`Logs retrieved for application: ${appUuid}`)
|
|
561
|
+
return ok({
|
|
562
|
+
logs: result.data?.logs || [],
|
|
563
|
+
timestamp: new Date().toISOString(),
|
|
564
|
+
})
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Gets deployment history for an application.
|
|
569
|
+
*
|
|
570
|
+
* @param appUuid - Application UUID
|
|
571
|
+
* @returns Result with deployment history or error
|
|
572
|
+
*/
|
|
573
|
+
async getApplicationDeploymentHistory(
|
|
574
|
+
appUuid: string
|
|
575
|
+
): Promise<Result<ICoolifyDeployment[], Error>> {
|
|
576
|
+
log.info(`Getting deployment history for ${appUuid}`)
|
|
577
|
+
|
|
578
|
+
const result = await this.request<ICoolifyDeployment[]>(`/applications/${appUuid}/deployments`)
|
|
579
|
+
|
|
580
|
+
if (result.error) {
|
|
581
|
+
log.error(`Failed to get deployment history: ${result.error}`)
|
|
582
|
+
return err(new Error(result.error))
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
log.success(`Deployment history retrieved for ${appUuid}`)
|
|
586
|
+
return ok(result.data || [])
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Starts a stopped application.
|
|
591
|
+
*
|
|
592
|
+
* @param appUuid - Application UUID
|
|
593
|
+
* @returns Result with application status or error
|
|
594
|
+
*/
|
|
595
|
+
async startApplication(
|
|
596
|
+
appUuid: string
|
|
597
|
+
): Promise<Result<ICoolifyApplication, Error>> {
|
|
598
|
+
log.info(`Starting application ${appUuid}`)
|
|
599
|
+
|
|
600
|
+
const result = await this.request<ICoolifyApplication>(`/applications/${appUuid}/start`, {
|
|
601
|
+
method: 'POST',
|
|
602
|
+
})
|
|
603
|
+
|
|
604
|
+
if (result.error) {
|
|
605
|
+
log.error(`Failed to start application: ${result.error}`)
|
|
606
|
+
return err(new Error(result.error))
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
log.success(`Application started: ${appUuid}`)
|
|
610
|
+
return ok(result.data as ICoolifyApplication)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Stops a running application.
|
|
615
|
+
*
|
|
616
|
+
* @param appUuid - Application UUID
|
|
617
|
+
* @returns Result with application status or error
|
|
618
|
+
*/
|
|
619
|
+
async stopApplication(
|
|
620
|
+
appUuid: string
|
|
621
|
+
): Promise<Result<ICoolifyApplication, Error>> {
|
|
622
|
+
log.info(`Stopping application ${appUuid}`)
|
|
623
|
+
|
|
624
|
+
const result = await this.request<ICoolifyApplication>(`/applications/${appUuid}/stop`, {
|
|
625
|
+
method: 'POST',
|
|
626
|
+
})
|
|
627
|
+
|
|
628
|
+
if (result.error) {
|
|
629
|
+
log.error(`Failed to stop application: ${result.error}`)
|
|
630
|
+
return err(new Error(result.error))
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
log.success(`Application stopped: ${appUuid}`)
|
|
634
|
+
return ok(result.data as ICoolifyApplication)
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Restarts an application.
|
|
639
|
+
*
|
|
640
|
+
* @param appUuid - Application UUID
|
|
641
|
+
* @returns Result with application status or error
|
|
642
|
+
*/
|
|
643
|
+
async restartApplication(
|
|
644
|
+
appUuid: string
|
|
645
|
+
): Promise<Result<ICoolifyApplication, Error>> {
|
|
646
|
+
log.info(`Restarting application ${appUuid}`)
|
|
647
|
+
|
|
648
|
+
const result = await this.request<ICoolifyApplication>(`/applications/${appUuid}/restart`, {
|
|
649
|
+
method: 'POST',
|
|
650
|
+
})
|
|
651
|
+
|
|
652
|
+
if (result.error) {
|
|
653
|
+
log.error(`Failed to restart application: ${result.error}`)
|
|
654
|
+
return err(new Error(result.error))
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
log.success(`Application restarted: ${appUuid}`)
|
|
658
|
+
return ok(result.data as ICoolifyApplication)
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
let instance: CoolifyService | null = null
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Gets the singleton CoolifyService instance.
|
|
666
|
+
*
|
|
667
|
+
* @returns The CoolifyService instance
|
|
668
|
+
*/
|
|
669
|
+
export function getCoolifyService(): CoolifyService {
|
|
670
|
+
if (!instance) {
|
|
671
|
+
instance = new CoolifyService()
|
|
672
|
+
}
|
|
673
|
+
return instance
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// Re-export types
|
|
677
|
+
export type {
|
|
678
|
+
ICoolifyServer,
|
|
679
|
+
ICoolifyDestination,
|
|
680
|
+
ICoolifyProject,
|
|
681
|
+
ICoolifyTeam,
|
|
682
|
+
ICoolifyApplication,
|
|
683
|
+
ICoolifyDeployment,
|
|
684
|
+
ICoolifyAppOptions,
|
|
685
|
+
ICoolifyDeployOptions,
|
|
686
|
+
ICoolifyUpdateOptions,
|
|
687
|
+
ICoolifyLogsOptions,
|
|
688
|
+
}
|