@mks2508/coolify-mks-cli-mcp 0.4.2 → 0.5.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 +6 -5
- package/dist/coolify/index.d.ts.map +1 -1
- package/dist/index.cjs +6 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/server/stdio.js +6 -5
- package/package.json +1 -1
- package/src/cli/commands/build-logs.ts +55 -0
- package/src/cli/commands/restart.ts +44 -0
- package/src/cli/commands/service-logs.ts +51 -0
- package/src/cli/commands/start.ts +44 -0
- package/src/cli/commands/stop.ts +44 -0
- package/src/cli/index.ts +43 -0
- package/src/coolify/index.ts +514 -369
- package/src/coolify/types.ts +2 -0
package/src/coolify/index.ts
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { ok, err, isErr, type Result } from
|
|
10
|
-
import { component } from
|
|
11
|
-
import { loadConfig, type ICoolifyConfig } from
|
|
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
12
|
import {
|
|
13
13
|
type ICoolifyAppOptions,
|
|
14
14
|
type ICoolifyAppResult,
|
|
@@ -26,31 +26,31 @@ import {
|
|
|
26
26
|
type ICoolifyTeam,
|
|
27
27
|
type ICoolifyUpdateOptions,
|
|
28
28
|
type IProgressCallback,
|
|
29
|
-
} from
|
|
29
|
+
} from "./types.js";
|
|
30
30
|
|
|
31
|
-
const log = component(
|
|
31
|
+
const log = component("CoolifyService");
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Coolify API response type.
|
|
35
35
|
*/
|
|
36
36
|
interface ICoolifyApiResponse<T> {
|
|
37
|
-
data?: T
|
|
38
|
-
error?: string
|
|
39
|
-
status: number
|
|
40
|
-
durationMs?: number
|
|
37
|
+
data?: T;
|
|
38
|
+
error?: string;
|
|
39
|
+
status: number;
|
|
40
|
+
durationMs?: number;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Environment variable from Coolify API.
|
|
45
45
|
*/
|
|
46
46
|
export interface ICoolifyEnvVar {
|
|
47
|
-
uuid: string
|
|
48
|
-
key: string
|
|
49
|
-
value: string
|
|
50
|
-
real_value?: string
|
|
51
|
-
is_buildtime: boolean
|
|
52
|
-
is_runtime: boolean
|
|
53
|
-
is_required: boolean
|
|
47
|
+
uuid: string;
|
|
48
|
+
key: string;
|
|
49
|
+
value: string;
|
|
50
|
+
real_value?: string;
|
|
51
|
+
is_buildtime: boolean;
|
|
52
|
+
is_runtime: boolean;
|
|
53
|
+
is_required: boolean;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
@@ -72,9 +72,9 @@ export interface ICoolifyEnvVar {
|
|
|
72
72
|
* ```
|
|
73
73
|
*/
|
|
74
74
|
export class CoolifyService {
|
|
75
|
-
private baseUrl: string | undefined
|
|
76
|
-
private token: string | undefined
|
|
77
|
-
private config: ICoolifyConfig = {}
|
|
75
|
+
private baseUrl: string | undefined;
|
|
76
|
+
private token: string | undefined;
|
|
77
|
+
private config: ICoolifyConfig = {};
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* Checks if the service is configured with URL and token.
|
|
@@ -82,9 +82,9 @@ export class CoolifyService {
|
|
|
82
82
|
* @returns true if both URL and token are set
|
|
83
83
|
*/
|
|
84
84
|
isConfigured(): boolean {
|
|
85
|
-
const hasUrl = !!this.baseUrl || !!process.env.COOLIFY_URL
|
|
86
|
-
const hasToken = !!this.token || !!process.env.COOLIFY_TOKEN
|
|
87
|
-
return hasUrl && hasToken
|
|
85
|
+
const hasUrl = !!this.baseUrl || !!process.env.COOLIFY_URL;
|
|
86
|
+
const hasToken = !!this.token || !!process.env.COOLIFY_TOKEN;
|
|
87
|
+
return hasUrl && hasToken;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/**
|
|
@@ -93,31 +93,43 @@ export class CoolifyService {
|
|
|
93
93
|
* @returns Result indicating success or error
|
|
94
94
|
*/
|
|
95
95
|
async init(): Promise<Result<void, Error>> {
|
|
96
|
-
const configResult = await loadConfig()
|
|
96
|
+
const configResult = await loadConfig();
|
|
97
97
|
|
|
98
98
|
if (isErr(configResult)) {
|
|
99
|
-
log.error(
|
|
100
|
-
return err(configResult.error)
|
|
99
|
+
log.error("Failed to load config");
|
|
100
|
+
return err(configResult.error);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
this.config = configResult.value
|
|
104
|
-
this.baseUrl = this.config.url || process.env.COOLIFY_URL
|
|
105
|
-
this.token = this.config.token || process.env.COOLIFY_TOKEN
|
|
103
|
+
this.config = configResult.value;
|
|
104
|
+
this.baseUrl = this.config.url || process.env.COOLIFY_URL;
|
|
105
|
+
this.token = this.config.token || process.env.COOLIFY_TOKEN;
|
|
106
106
|
|
|
107
107
|
if (!this.baseUrl) {
|
|
108
|
-
log.error(
|
|
109
|
-
log.info(
|
|
110
|
-
|
|
108
|
+
log.error("No Coolify URL configured");
|
|
109
|
+
log.info(
|
|
110
|
+
"Set COOLIFY_URL environment variable or run: coolify-mcp config set url <url>",
|
|
111
|
+
);
|
|
112
|
+
return err(
|
|
113
|
+
new Error(
|
|
114
|
+
"No Coolify URL configured. Set COOLIFY_URL or use config command.",
|
|
115
|
+
),
|
|
116
|
+
);
|
|
111
117
|
}
|
|
112
118
|
|
|
113
119
|
if (!this.token) {
|
|
114
|
-
log.error(
|
|
115
|
-
log.info(
|
|
116
|
-
|
|
120
|
+
log.error("No Coolify token configured");
|
|
121
|
+
log.info(
|
|
122
|
+
"Set COOLIFY_TOKEN environment variable or run: coolify-mcp config set token <token>",
|
|
123
|
+
);
|
|
124
|
+
return err(
|
|
125
|
+
new Error(
|
|
126
|
+
"No Coolify token configured. Set COOLIFY_TOKEN or use config command.",
|
|
127
|
+
),
|
|
128
|
+
);
|
|
117
129
|
}
|
|
118
130
|
|
|
119
|
-
log.debug(
|
|
120
|
-
return ok(undefined)
|
|
131
|
+
log.debug("Coolify connection configured");
|
|
132
|
+
return ok(undefined);
|
|
121
133
|
}
|
|
122
134
|
|
|
123
135
|
/**
|
|
@@ -129,57 +141,70 @@ export class CoolifyService {
|
|
|
129
141
|
*/
|
|
130
142
|
private async request<T>(
|
|
131
143
|
endpoint: string,
|
|
132
|
-
options: RequestInit = {}
|
|
144
|
+
options: RequestInit = {},
|
|
133
145
|
): Promise<ICoolifyApiResponse<T>> {
|
|
134
|
-
const startTime = Date.now()
|
|
146
|
+
const startTime = Date.now();
|
|
135
147
|
|
|
136
148
|
if (!this.baseUrl || !this.token) {
|
|
137
|
-
return {
|
|
149
|
+
return {
|
|
150
|
+
error: "Coolify not configured",
|
|
151
|
+
status: 0,
|
|
152
|
+
durationMs: Date.now() - startTime,
|
|
153
|
+
};
|
|
138
154
|
}
|
|
139
155
|
|
|
140
156
|
try {
|
|
141
|
-
const baseUrl = this.baseUrl.replace(/\/+$/,
|
|
142
|
-
const url = `${baseUrl}/api/v1${endpoint}
|
|
157
|
+
const baseUrl = this.baseUrl.replace(/\/+$/, "");
|
|
158
|
+
const url = `${baseUrl}/api/v1${endpoint}`;
|
|
143
159
|
|
|
144
160
|
const response = await fetch(url, {
|
|
145
161
|
...options,
|
|
146
162
|
headers: {
|
|
147
163
|
Authorization: `Bearer ${this.token}`,
|
|
148
|
-
|
|
149
|
-
Accept:
|
|
164
|
+
"Content-Type": "application/json",
|
|
165
|
+
Accept: "application/json",
|
|
150
166
|
...options.headers,
|
|
151
167
|
},
|
|
152
|
-
})
|
|
168
|
+
});
|
|
153
169
|
|
|
154
|
-
const text = await response.text()
|
|
155
|
-
const durationMs = Date.now() - startTime
|
|
156
|
-
let data: T | undefined
|
|
170
|
+
const text = await response.text();
|
|
171
|
+
const durationMs = Date.now() - startTime;
|
|
172
|
+
let data: T | undefined;
|
|
157
173
|
|
|
158
174
|
try {
|
|
159
|
-
data = text ? JSON.parse(text) : undefined
|
|
175
|
+
data = text ? JSON.parse(text) : undefined;
|
|
160
176
|
} catch {
|
|
161
177
|
if (!response.ok) {
|
|
162
|
-
return {
|
|
178
|
+
return {
|
|
179
|
+
error: text || `HTTP ${response.status}`,
|
|
180
|
+
status: response.status,
|
|
181
|
+
durationMs,
|
|
182
|
+
};
|
|
163
183
|
}
|
|
164
184
|
}
|
|
165
185
|
|
|
166
186
|
if (!response.ok) {
|
|
167
|
-
const parsed = data as
|
|
168
|
-
|
|
187
|
+
const parsed = data as
|
|
188
|
+
| { message?: string; errors?: Record<string, string[]> }
|
|
189
|
+
| undefined;
|
|
190
|
+
let errorMessage = parsed?.message || `HTTP ${response.status}`;
|
|
169
191
|
// Include validation errors if present (Coolify returns { message, errors: { field: [reasons] } })
|
|
170
192
|
if (parsed?.errors) {
|
|
171
193
|
const details = Object.entries(parsed.errors)
|
|
172
|
-
.map(
|
|
173
|
-
|
|
174
|
-
|
|
194
|
+
.map(
|
|
195
|
+
([field, reasons]) =>
|
|
196
|
+
`${field}: ${Array.isArray(reasons) ? reasons.join(", ") : String(reasons)}`,
|
|
197
|
+
)
|
|
198
|
+
.join("; ");
|
|
199
|
+
errorMessage += ` — ${details}`;
|
|
175
200
|
}
|
|
176
|
-
return { error: errorMessage, status: response.status, durationMs }
|
|
201
|
+
return { error: errorMessage, status: response.status, durationMs };
|
|
177
202
|
}
|
|
178
203
|
|
|
179
|
-
return { data, status: response.status, durationMs }
|
|
204
|
+
return { data, status: response.status, durationMs };
|
|
180
205
|
} catch (error) {
|
|
181
|
-
const message = error instanceof Error ? error.message :
|
|
182
|
-
return { error: message, status: 0, durationMs: Date.now() - startTime }
|
|
206
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
207
|
+
return { error: message, status: 0, durationMs: Date.now() - startTime };
|
|
183
208
|
}
|
|
184
209
|
}
|
|
185
210
|
|
|
@@ -192,61 +217,63 @@ export class CoolifyService {
|
|
|
192
217
|
*/
|
|
193
218
|
async deploy(
|
|
194
219
|
options: ICoolifyDeployOptions,
|
|
195
|
-
onProgress?: IProgressCallback
|
|
220
|
+
onProgress?: IProgressCallback,
|
|
196
221
|
): Promise<Result<ICoolifyDeployResult, Error>> {
|
|
197
222
|
if (!options.uuid && !options.tag) {
|
|
198
|
-
return err(new Error(
|
|
223
|
+
return err(new Error("Either uuid or tag is required"));
|
|
199
224
|
}
|
|
200
225
|
|
|
201
|
-
const appId = options.uuid?.slice(0, 8) || options.tag ||
|
|
202
|
-
onProgress?.(5, `Preparing deployment for ${appId}...`)
|
|
226
|
+
const appId = options.uuid?.slice(0, 8) || options.tag || "unknown";
|
|
227
|
+
onProgress?.(5, `Preparing deployment for ${appId}...`);
|
|
203
228
|
|
|
204
|
-
log.info(`Deploying application ${options.uuid || options.tag}`)
|
|
229
|
+
log.info(`Deploying application ${options.uuid || options.tag}`);
|
|
205
230
|
|
|
206
|
-
onProgress?.(25,
|
|
207
|
-
onProgress?.(50,
|
|
231
|
+
onProgress?.(25, "Validating deployment configuration");
|
|
232
|
+
onProgress?.(50, "Triggering build pipeline...");
|
|
208
233
|
|
|
209
234
|
// Build query parameters for deploy endpoint
|
|
210
|
-
const params = new URLSearchParams()
|
|
211
|
-
if (options.uuid) params.set(
|
|
212
|
-
if (options.tag) params.set(
|
|
213
|
-
if (options.force) params.set(
|
|
235
|
+
const params = new URLSearchParams();
|
|
236
|
+
if (options.uuid) params.set("uuid", options.uuid);
|
|
237
|
+
if (options.tag) params.set("tag", options.tag);
|
|
238
|
+
if (options.force) params.set("force", "true");
|
|
214
239
|
|
|
215
|
-
const endpoint = `/deploy${params.toString() ? `?${params.toString()}` :
|
|
240
|
+
const endpoint = `/deploy${params.toString() ? `?${params.toString()}` : ""}`;
|
|
216
241
|
|
|
217
242
|
const result = await this.request<{
|
|
218
243
|
deployments: Array<{
|
|
219
|
-
message: string
|
|
220
|
-
resource_uuid: string
|
|
221
|
-
deployment_uuid: string
|
|
222
|
-
}
|
|
244
|
+
message: string;
|
|
245
|
+
resource_uuid: string;
|
|
246
|
+
deployment_uuid: string;
|
|
247
|
+
}>;
|
|
223
248
|
}>(endpoint, {
|
|
224
|
-
method:
|
|
225
|
-
})
|
|
249
|
+
method: "GET",
|
|
250
|
+
});
|
|
226
251
|
|
|
227
252
|
if (result.error) {
|
|
228
|
-
log.error(`Deployment failed: ${result.error}`)
|
|
229
|
-
return err(new Error(result.error))
|
|
253
|
+
log.error(`Deployment failed: ${result.error}`);
|
|
254
|
+
return err(new Error(result.error));
|
|
230
255
|
}
|
|
231
256
|
|
|
232
257
|
// Response is { deployments: [{ message, resource_uuid, deployment_uuid }] }
|
|
233
|
-
const deployments = result.data?.deployments || []
|
|
258
|
+
const deployments = result.data?.deployments || [];
|
|
234
259
|
if (deployments.length === 0) {
|
|
235
|
-
log.error(
|
|
236
|
-
return err(
|
|
260
|
+
log.error("No deployments started");
|
|
261
|
+
return err(
|
|
262
|
+
new Error("No deployments started - check application configuration"),
|
|
263
|
+
);
|
|
237
264
|
}
|
|
238
265
|
|
|
239
|
-
const deployment = deployments[0]
|
|
266
|
+
const deployment = deployments[0];
|
|
240
267
|
|
|
241
|
-
onProgress?.(90,
|
|
242
|
-
onProgress?.(100,
|
|
268
|
+
onProgress?.(90, "Build started on Coolify server");
|
|
269
|
+
onProgress?.(100, "Deployment triggered");
|
|
243
270
|
|
|
244
|
-
log.success(`Deployment started: ${deployment.deployment_uuid}`)
|
|
271
|
+
log.success(`Deployment started: ${deployment.deployment_uuid}`);
|
|
245
272
|
return ok({
|
|
246
273
|
success: true,
|
|
247
274
|
deploymentUuid: deployment.deployment_uuid,
|
|
248
275
|
resourceUuid: deployment.resource_uuid,
|
|
249
|
-
})
|
|
276
|
+
});
|
|
250
277
|
}
|
|
251
278
|
|
|
252
279
|
/**
|
|
@@ -266,27 +293,29 @@ export class CoolifyService {
|
|
|
266
293
|
*/
|
|
267
294
|
async createApplication(
|
|
268
295
|
options: ICoolifyAppOptions,
|
|
269
|
-
onProgress?: IProgressCallback
|
|
296
|
+
onProgress?: IProgressCallback,
|
|
270
297
|
): Promise<Result<ICoolifyAppResult, Error>> {
|
|
271
|
-
onProgress?.(5, `Preparing app "${options.name}"`)
|
|
298
|
+
onProgress?.(5, `Preparing app "${options.name}"`);
|
|
272
299
|
|
|
273
|
-
const appType = options.type ||
|
|
274
|
-
log.info(`Creating application ${options.name} (type: ${appType})`)
|
|
300
|
+
const appType = options.type || "public";
|
|
301
|
+
log.info(`Creating application ${options.name} (type: ${appType})`);
|
|
275
302
|
|
|
276
|
-
onProgress?.(25, `Validating server ${options.serverUuid.slice(0, 8)}...`)
|
|
277
|
-
onProgress?.(50,
|
|
303
|
+
onProgress?.(25, `Validating server ${options.serverUuid.slice(0, 8)}...`);
|
|
304
|
+
onProgress?.(50, "Sending creation request to Coolify API...");
|
|
278
305
|
|
|
279
306
|
// Determine endpoint based on application type
|
|
280
307
|
const endpointMap: Record<string, string> = {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
308
|
+
public: "/applications/public",
|
|
309
|
+
"private-github-app": "/applications/private-github-app",
|
|
310
|
+
"private-deploy-key": "/applications/private-deploy-key",
|
|
311
|
+
dockerfile: "/applications/dockerfile",
|
|
312
|
+
"docker-image": "/applications/docker-image",
|
|
313
|
+
"docker-compose": "/applications/docker-compose",
|
|
314
|
+
dockerimage: "/applications/dockerimage",
|
|
315
|
+
dockercompose: "/applications/dockercompose",
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const endpoint = endpointMap[appType] || "/applications/public";
|
|
290
319
|
|
|
291
320
|
// Build request body based on application type
|
|
292
321
|
const body: Record<string, unknown> = {
|
|
@@ -295,60 +324,64 @@ export class CoolifyService {
|
|
|
295
324
|
project_uuid: options.projectUuid,
|
|
296
325
|
environment_uuid: options.environmentUuid,
|
|
297
326
|
server_uuid: options.serverUuid,
|
|
298
|
-
}
|
|
327
|
+
};
|
|
299
328
|
|
|
300
329
|
// Type-specific fields
|
|
301
|
-
if (
|
|
330
|
+
if (
|
|
331
|
+
appType === "public" ||
|
|
332
|
+
appType === "private-github-app" ||
|
|
333
|
+
appType === "private-deploy-key"
|
|
334
|
+
) {
|
|
302
335
|
if (options.githubRepoUrl) {
|
|
303
336
|
// Coolify expects 'user/repo' format, not full URL
|
|
304
337
|
body.git_repository = options.githubRepoUrl
|
|
305
|
-
.replace(/^https?:\/\/github\.com\//,
|
|
306
|
-
.replace(/\.git$/,
|
|
338
|
+
.replace(/^https?:\/\/github\.com\//, "")
|
|
339
|
+
.replace(/\.git$/, "");
|
|
307
340
|
}
|
|
308
341
|
if (options.githubAppUuid) {
|
|
309
|
-
body.github_app_uuid = options.githubAppUuid
|
|
342
|
+
body.github_app_uuid = options.githubAppUuid;
|
|
310
343
|
}
|
|
311
|
-
body.git_branch = options.branch ||
|
|
312
|
-
body.build_pack = options.buildPack ||
|
|
344
|
+
body.git_branch = options.branch || "main";
|
|
345
|
+
body.build_pack = options.buildPack || "dockerfile";
|
|
313
346
|
if (options.portsExposes) {
|
|
314
|
-
body.ports_exposes = options.portsExposes
|
|
347
|
+
body.ports_exposes = options.portsExposes;
|
|
315
348
|
}
|
|
316
349
|
// Dockerfile / Docker Compose configuration
|
|
317
350
|
if (options.dockerfileLocation) {
|
|
318
|
-
body.dockerfile_location = options.dockerfileLocation
|
|
351
|
+
body.dockerfile_location = options.dockerfileLocation;
|
|
319
352
|
}
|
|
320
353
|
if (options.dockerComposeLocation) {
|
|
321
|
-
body.docker_compose_location = options.dockerComposeLocation
|
|
354
|
+
body.docker_compose_location = options.dockerComposeLocation;
|
|
322
355
|
}
|
|
323
356
|
if (options.baseDirectory) {
|
|
324
|
-
body.base_directory = options.baseDirectory
|
|
357
|
+
body.base_directory = options.baseDirectory;
|
|
325
358
|
}
|
|
326
|
-
} else if (appType ===
|
|
327
|
-
body.docker_image = options.dockerImage
|
|
328
|
-
} else if (appType ===
|
|
329
|
-
body.docker_compose = options.dockerCompose
|
|
359
|
+
} else if (appType === "docker-image" && options.dockerImage) {
|
|
360
|
+
body.docker_image = options.dockerImage;
|
|
361
|
+
} else if (appType === "docker-compose" && options.dockerCompose) {
|
|
362
|
+
body.docker_compose = options.dockerCompose;
|
|
330
363
|
}
|
|
331
364
|
|
|
332
|
-
log.debug(`Create application body: ${JSON.stringify(body, null, 2)}`)
|
|
333
|
-
log.debug(`Endpoint: POST ${endpoint}`)
|
|
365
|
+
log.debug(`Create application body: ${JSON.stringify(body, null, 2)}`);
|
|
366
|
+
log.debug(`Endpoint: POST ${endpoint}`);
|
|
334
367
|
|
|
335
368
|
const result = await this.request<{ uuid: string }>(endpoint, {
|
|
336
|
-
method:
|
|
369
|
+
method: "POST",
|
|
337
370
|
body: JSON.stringify(body),
|
|
338
|
-
})
|
|
371
|
+
});
|
|
339
372
|
|
|
340
373
|
if (result.error) {
|
|
341
|
-
log.error(`Failed to create application: ${result.error}`)
|
|
342
|
-
return err(new Error(result.error))
|
|
374
|
+
log.error(`Failed to create application: ${result.error}`);
|
|
375
|
+
return err(new Error(result.error));
|
|
343
376
|
}
|
|
344
377
|
|
|
345
|
-
onProgress?.(100, `Application "${options.name}" created`)
|
|
378
|
+
onProgress?.(100, `Application "${options.name}" created`);
|
|
346
379
|
|
|
347
|
-
log.success(`Application created: ${result.data?.uuid}`)
|
|
380
|
+
log.success(`Application created: ${result.data?.uuid}`);
|
|
348
381
|
return ok({
|
|
349
382
|
success: true,
|
|
350
383
|
uuid: result.data?.uuid,
|
|
351
|
-
})
|
|
384
|
+
});
|
|
352
385
|
}
|
|
353
386
|
|
|
354
387
|
/**
|
|
@@ -360,43 +393,50 @@ export class CoolifyService {
|
|
|
360
393
|
*/
|
|
361
394
|
async setEnvironmentVariables(
|
|
362
395
|
appUuid: string,
|
|
363
|
-
envVars: Record<string, string
|
|
396
|
+
envVars: Record<string, string>,
|
|
364
397
|
): Promise<Result<void, Error>> {
|
|
365
|
-
log.info(
|
|
398
|
+
log.info(
|
|
399
|
+
`Setting ${Object.keys(envVars).length} environment variables for ${appUuid}`,
|
|
400
|
+
);
|
|
366
401
|
|
|
367
402
|
// Coolify API: POST to create, PATCH to update existing
|
|
368
403
|
for (const [key, value] of Object.entries(envVars)) {
|
|
369
404
|
const result = await this.request(`/applications/${appUuid}/envs`, {
|
|
370
|
-
method:
|
|
405
|
+
method: "POST",
|
|
371
406
|
body: JSON.stringify({ key, value, is_preview: false }),
|
|
372
|
-
})
|
|
373
|
-
|
|
374
|
-
if (result.error && result.error.includes(
|
|
375
|
-
// Var exists —
|
|
376
|
-
const listResult = await this.request<
|
|
377
|
-
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
if (result.error && result.error.includes("already exists")) {
|
|
410
|
+
// Var exists — DELETE + re-POST (Coolify PATCH on envs returns 404)
|
|
411
|
+
const listResult = await this.request<
|
|
412
|
+
Array<{ uuid: string; key: string }>
|
|
413
|
+
>(`/applications/${appUuid}/envs`);
|
|
414
|
+
const existing = listResult.data?.find((v) => v.key === key);
|
|
378
415
|
if (existing) {
|
|
379
|
-
|
|
380
|
-
method:
|
|
416
|
+
await this.request(`/applications/${appUuid}/envs/${existing.uuid}`, {
|
|
417
|
+
method: "DELETE",
|
|
418
|
+
});
|
|
419
|
+
const repost = await this.request(`/applications/${appUuid}/envs`, {
|
|
420
|
+
method: "POST",
|
|
381
421
|
body: JSON.stringify({ key, value, is_preview: false }),
|
|
382
|
-
})
|
|
383
|
-
if (
|
|
384
|
-
log.error(`Failed to update env var ${key}: ${
|
|
385
|
-
return err(new Error(`Failed to update ${key}: ${
|
|
422
|
+
});
|
|
423
|
+
if (repost.error) {
|
|
424
|
+
log.error(`Failed to update env var ${key}: ${repost.error}`);
|
|
425
|
+
return err(new Error(`Failed to update ${key}: ${repost.error}`));
|
|
386
426
|
}
|
|
387
|
-
log.debug(`Updated existing env var: ${key}`)
|
|
427
|
+
log.debug(`Updated existing env var: ${key}`);
|
|
388
428
|
} else {
|
|
389
|
-
log.error(`Failed to set env var ${key}: ${result.error}`)
|
|
390
|
-
return err(new Error(`Failed to set ${key}: ${result.error}`))
|
|
429
|
+
log.error(`Failed to set env var ${key}: ${result.error}`);
|
|
430
|
+
return err(new Error(`Failed to set ${key}: ${result.error}`));
|
|
391
431
|
}
|
|
392
432
|
} else if (result.error) {
|
|
393
|
-
log.error(`Failed to set env var ${key}: ${result.error}`)
|
|
394
|
-
return err(new Error(`Failed to set ${key}: ${result.error}`))
|
|
433
|
+
log.error(`Failed to set env var ${key}: ${result.error}`);
|
|
434
|
+
return err(new Error(`Failed to set ${key}: ${result.error}`));
|
|
395
435
|
}
|
|
396
436
|
}
|
|
397
437
|
|
|
398
|
-
log.success(`${Object.keys(envVars).length} environment variables set`)
|
|
399
|
-
return ok(undefined)
|
|
438
|
+
log.success(`${Object.keys(envVars).length} environment variables set`);
|
|
439
|
+
return ok(undefined);
|
|
400
440
|
}
|
|
401
441
|
|
|
402
442
|
/**
|
|
@@ -406,21 +446,21 @@ export class CoolifyService {
|
|
|
406
446
|
* @returns Result with environment variables or error
|
|
407
447
|
*/
|
|
408
448
|
async getEnvironmentVariables(
|
|
409
|
-
appUuid: string
|
|
449
|
+
appUuid: string,
|
|
410
450
|
): Promise<Result<ICoolifyEnvVar[], Error>> {
|
|
411
|
-
log.info(`Getting environment variables for ${appUuid}`)
|
|
451
|
+
log.info(`Getting environment variables for ${appUuid}`);
|
|
412
452
|
|
|
413
453
|
const result = await this.request<ICoolifyEnvVar[]>(
|
|
414
|
-
`/applications/${appUuid}/envs
|
|
415
|
-
)
|
|
454
|
+
`/applications/${appUuid}/envs`,
|
|
455
|
+
);
|
|
416
456
|
|
|
417
457
|
if (result.error) {
|
|
418
|
-
log.error(`Failed to get env vars: ${result.error}`)
|
|
419
|
-
return err(new Error(result.error))
|
|
458
|
+
log.error(`Failed to get env vars: ${result.error}`);
|
|
459
|
+
return err(new Error(result.error));
|
|
420
460
|
}
|
|
421
461
|
|
|
422
|
-
log.success(`Environment variables retrieved for ${appUuid}`)
|
|
423
|
-
return ok(result.data || [])
|
|
462
|
+
log.success(`Environment variables retrieved for ${appUuid}`);
|
|
463
|
+
return ok(result.data || []);
|
|
424
464
|
}
|
|
425
465
|
|
|
426
466
|
/**
|
|
@@ -437,46 +477,52 @@ export class CoolifyService {
|
|
|
437
477
|
appUuid: string,
|
|
438
478
|
key: string,
|
|
439
479
|
value: string,
|
|
440
|
-
isBuildTime: boolean = false
|
|
480
|
+
isBuildTime: boolean = false,
|
|
441
481
|
): Promise<Result<void, Error>> {
|
|
442
|
-
log.info(`Setting environment variable ${key} for ${appUuid}`)
|
|
482
|
+
log.info(`Setting environment variable ${key} for ${appUuid}`);
|
|
443
483
|
|
|
444
484
|
// Check if variable already exists
|
|
445
|
-
const existingVars = await this.getEnvironmentVariables(appUuid)
|
|
485
|
+
const existingVars = await this.getEnvironmentVariables(appUuid);
|
|
446
486
|
if (isErr(existingVars)) {
|
|
447
|
-
return err(existingVars.error)
|
|
487
|
+
return err(existingVars.error);
|
|
448
488
|
}
|
|
449
489
|
|
|
450
|
-
const exists = existingVars.value.some(ev => ev.key === key)
|
|
490
|
+
const exists = existingVars.value.some((ev) => ev.key === key);
|
|
451
491
|
|
|
452
492
|
if (exists) {
|
|
453
493
|
// Use PATCH to update existing variable
|
|
454
|
-
log.debug(`Variable ${key} exists, using PATCH to update`)
|
|
455
|
-
const result = await this.request<{ uuid: string }>(
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
494
|
+
log.debug(`Variable ${key} exists, using PATCH to update`);
|
|
495
|
+
const result = await this.request<{ uuid: string }>(
|
|
496
|
+
`/applications/${appUuid}/envs`,
|
|
497
|
+
{
|
|
498
|
+
method: "PATCH",
|
|
499
|
+
body: JSON.stringify({ key, value }),
|
|
500
|
+
},
|
|
501
|
+
);
|
|
459
502
|
|
|
460
503
|
if (result.error) {
|
|
461
|
-
log.error(`Failed to update env var: ${result.error}`)
|
|
462
|
-
return err(new Error(result.error))
|
|
504
|
+
log.error(`Failed to update env var: ${result.error}`);
|
|
505
|
+
return err(new Error(result.error));
|
|
463
506
|
}
|
|
464
507
|
} else {
|
|
465
508
|
// Use POST to create new variable
|
|
466
|
-
log.debug(`Variable ${key} does not exist, using POST to create`)
|
|
467
|
-
const result = await this.request<{ uuid: string }>(
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
509
|
+
log.debug(`Variable ${key} does not exist, using POST to create`);
|
|
510
|
+
const result = await this.request<{ uuid: string }>(
|
|
511
|
+
`/applications/${appUuid}/envs`,
|
|
512
|
+
{
|
|
513
|
+
method: "POST",
|
|
514
|
+
body: JSON.stringify({ key, value }),
|
|
515
|
+
},
|
|
516
|
+
);
|
|
471
517
|
|
|
472
518
|
if (result.error) {
|
|
473
|
-
log.error(`Failed to create env var: ${result.error}`)
|
|
474
|
-
return err(new Error(result.error))
|
|
519
|
+
log.error(`Failed to create env var: ${result.error}`);
|
|
520
|
+
return err(new Error(result.error));
|
|
475
521
|
}
|
|
476
522
|
}
|
|
477
523
|
|
|
478
|
-
log.success(`Environment variable ${key} set for ${appUuid}`)
|
|
479
|
-
return ok(undefined)
|
|
524
|
+
log.success(`Environment variable ${key} set for ${appUuid}`);
|
|
525
|
+
return ok(undefined);
|
|
480
526
|
}
|
|
481
527
|
|
|
482
528
|
/**
|
|
@@ -488,33 +534,36 @@ export class CoolifyService {
|
|
|
488
534
|
*/
|
|
489
535
|
async deleteEnvironmentVariable(
|
|
490
536
|
appUuid: string,
|
|
491
|
-
key: string
|
|
537
|
+
key: string,
|
|
492
538
|
): Promise<Result<void, Error>> {
|
|
493
|
-
log.info(`Deleting environment variable ${key} from ${appUuid}`)
|
|
539
|
+
log.info(`Deleting environment variable ${key} from ${appUuid}`);
|
|
494
540
|
|
|
495
541
|
// First get all env vars to find the UUID of the one to delete
|
|
496
|
-
const envVarsResult = await this.getEnvironmentVariables(appUuid)
|
|
542
|
+
const envVarsResult = await this.getEnvironmentVariables(appUuid);
|
|
497
543
|
if (isErr(envVarsResult)) {
|
|
498
|
-
return err(envVarsResult.error)
|
|
544
|
+
return err(envVarsResult.error);
|
|
499
545
|
}
|
|
500
546
|
|
|
501
|
-
const envVar = envVarsResult.value.find(ev => ev.key === key)
|
|
547
|
+
const envVar = envVarsResult.value.find((ev) => ev.key === key);
|
|
502
548
|
if (!envVar) {
|
|
503
|
-
log.error(`Environment variable ${key} not found`)
|
|
504
|
-
return err(new Error(`Environment variable ${key} not found`))
|
|
549
|
+
log.error(`Environment variable ${key} not found`);
|
|
550
|
+
return err(new Error(`Environment variable ${key} not found`));
|
|
505
551
|
}
|
|
506
552
|
|
|
507
|
-
const result = await this.request(
|
|
508
|
-
|
|
509
|
-
|
|
553
|
+
const result = await this.request(
|
|
554
|
+
`/applications/${appUuid}/envs/${envVar.uuid}`,
|
|
555
|
+
{
|
|
556
|
+
method: "DELETE",
|
|
557
|
+
},
|
|
558
|
+
);
|
|
510
559
|
|
|
511
560
|
if (result.error) {
|
|
512
|
-
log.error(`Failed to delete env var: ${result.error}`)
|
|
513
|
-
return err(new Error(result.error))
|
|
561
|
+
log.error(`Failed to delete env var: ${result.error}`);
|
|
562
|
+
return err(new Error(result.error));
|
|
514
563
|
}
|
|
515
564
|
|
|
516
|
-
log.success(`Environment variable ${key} deleted from ${appUuid}`)
|
|
517
|
-
return ok(undefined)
|
|
565
|
+
log.success(`Environment variable ${key} deleted from ${appUuid}`);
|
|
566
|
+
return ok(undefined);
|
|
518
567
|
}
|
|
519
568
|
|
|
520
569
|
/**
|
|
@@ -523,18 +572,16 @@ export class CoolifyService {
|
|
|
523
572
|
* @param appUuid - Application UUID
|
|
524
573
|
* @returns Result with status or error
|
|
525
574
|
*/
|
|
526
|
-
async getApplicationStatus(
|
|
527
|
-
appUuid: string
|
|
528
|
-
): Promise<Result<string, Error>> {
|
|
575
|
+
async getApplicationStatus(appUuid: string): Promise<Result<string, Error>> {
|
|
529
576
|
const result = await this.request<{ status: string }>(
|
|
530
|
-
`/applications/${appUuid}
|
|
531
|
-
)
|
|
577
|
+
`/applications/${appUuid}`,
|
|
578
|
+
);
|
|
532
579
|
|
|
533
580
|
if (result.error) {
|
|
534
|
-
return err(new Error(result.error))
|
|
581
|
+
return err(new Error(result.error));
|
|
535
582
|
}
|
|
536
583
|
|
|
537
|
-
return ok(result.data?.status ||
|
|
584
|
+
return ok(result.data?.status || "unknown");
|
|
538
585
|
}
|
|
539
586
|
|
|
540
587
|
/**
|
|
@@ -543,13 +590,13 @@ export class CoolifyService {
|
|
|
543
590
|
* @returns Result with servers or error
|
|
544
591
|
*/
|
|
545
592
|
async listServers(): Promise<Result<ICoolifyServer[], Error>> {
|
|
546
|
-
const result = await this.request<ICoolifyServer[]>(
|
|
593
|
+
const result = await this.request<ICoolifyServer[]>("/servers");
|
|
547
594
|
|
|
548
595
|
if (result.error) {
|
|
549
|
-
return err(new Error(result.error))
|
|
596
|
+
return err(new Error(result.error));
|
|
550
597
|
}
|
|
551
598
|
|
|
552
|
-
return ok(result.data || [])
|
|
599
|
+
return ok(result.data || []);
|
|
553
600
|
}
|
|
554
601
|
|
|
555
602
|
/**
|
|
@@ -558,20 +605,18 @@ export class CoolifyService {
|
|
|
558
605
|
* @param serverUuid - Server UUID
|
|
559
606
|
* @returns Result with server details or error
|
|
560
607
|
*/
|
|
561
|
-
async getServer(
|
|
562
|
-
serverUuid
|
|
563
|
-
): Promise<Result<ICoolifyServer, Error>> {
|
|
564
|
-
log.info(`Getting server details for ${serverUuid}`)
|
|
608
|
+
async getServer(serverUuid: string): Promise<Result<ICoolifyServer, Error>> {
|
|
609
|
+
log.info(`Getting server details for ${serverUuid}`);
|
|
565
610
|
|
|
566
|
-
const result = await this.request<ICoolifyServer>(`/servers/${serverUuid}`)
|
|
611
|
+
const result = await this.request<ICoolifyServer>(`/servers/${serverUuid}`);
|
|
567
612
|
|
|
568
613
|
if (result.error) {
|
|
569
|
-
log.error(`Failed to get server: ${result.error}`)
|
|
570
|
-
return err(new Error(result.error))
|
|
614
|
+
log.error(`Failed to get server: ${result.error}`);
|
|
615
|
+
return err(new Error(result.error));
|
|
571
616
|
}
|
|
572
617
|
|
|
573
|
-
log.success(`Server details retrieved: ${serverUuid}`)
|
|
574
|
-
return ok(result.data as ICoolifyServer)
|
|
618
|
+
log.success(`Server details retrieved: ${serverUuid}`);
|
|
619
|
+
return ok(result.data as ICoolifyServer);
|
|
575
620
|
}
|
|
576
621
|
|
|
577
622
|
/**
|
|
@@ -579,10 +624,18 @@ export class CoolifyService {
|
|
|
579
624
|
*
|
|
580
625
|
* @returns Result with GitHub Apps list or error
|
|
581
626
|
*/
|
|
582
|
-
async listGithubApps(): Promise<
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
627
|
+
async listGithubApps(): Promise<
|
|
628
|
+
Result<
|
|
629
|
+
Array<{ id: number; uuid: string; name: string; is_public: boolean }>,
|
|
630
|
+
Error
|
|
631
|
+
>
|
|
632
|
+
> {
|
|
633
|
+
const result =
|
|
634
|
+
await this.request<
|
|
635
|
+
Array<{ id: number; uuid: string; name: string; is_public: boolean }>
|
|
636
|
+
>("/github-apps");
|
|
637
|
+
if (result.error) return err(new Error(result.error));
|
|
638
|
+
return ok(result.data || []);
|
|
586
639
|
}
|
|
587
640
|
|
|
588
641
|
/**
|
|
@@ -591,13 +644,13 @@ export class CoolifyService {
|
|
|
591
644
|
* @returns Result with projects list or error
|
|
592
645
|
*/
|
|
593
646
|
async listProjects(): Promise<Result<ICoolifyProject[], Error>> {
|
|
594
|
-
const result = await this.request<ICoolifyProject[]>(
|
|
647
|
+
const result = await this.request<ICoolifyProject[]>("/projects");
|
|
595
648
|
|
|
596
649
|
if (result.error) {
|
|
597
|
-
return err(new Error(result.error))
|
|
650
|
+
return err(new Error(result.error));
|
|
598
651
|
}
|
|
599
652
|
|
|
600
|
-
return ok(result.data || [])
|
|
653
|
+
return ok(result.data || []);
|
|
601
654
|
}
|
|
602
655
|
|
|
603
656
|
/**
|
|
@@ -609,22 +662,22 @@ export class CoolifyService {
|
|
|
609
662
|
*/
|
|
610
663
|
async createProject(
|
|
611
664
|
name: string,
|
|
612
|
-
description?: string
|
|
665
|
+
description?: string,
|
|
613
666
|
): Promise<Result<ICoolifyProject, Error>> {
|
|
614
|
-
log.info(`Creating project: ${name}`)
|
|
667
|
+
log.info(`Creating project: ${name}`);
|
|
615
668
|
|
|
616
|
-
const result = await this.request<ICoolifyProject>(
|
|
617
|
-
method:
|
|
618
|
-
body: JSON.stringify({ name, description: description ||
|
|
619
|
-
})
|
|
669
|
+
const result = await this.request<ICoolifyProject>("/projects", {
|
|
670
|
+
method: "POST",
|
|
671
|
+
body: JSON.stringify({ name, description: description || "" }),
|
|
672
|
+
});
|
|
620
673
|
|
|
621
674
|
if (result.error) {
|
|
622
|
-
log.error(`Failed to create project: ${result.error}`)
|
|
623
|
-
return err(new Error(result.error))
|
|
675
|
+
log.error(`Failed to create project: ${result.error}`);
|
|
676
|
+
return err(new Error(result.error));
|
|
624
677
|
}
|
|
625
678
|
|
|
626
|
-
log.success(`Project created: ${result.data?.uuid}`)
|
|
627
|
-
return ok(result.data!)
|
|
679
|
+
log.success(`Project created: ${result.data?.uuid}`);
|
|
680
|
+
return ok(result.data!);
|
|
628
681
|
}
|
|
629
682
|
|
|
630
683
|
/**
|
|
@@ -634,21 +687,21 @@ export class CoolifyService {
|
|
|
634
687
|
* @returns Result with environments list or error
|
|
635
688
|
*/
|
|
636
689
|
async getProjectEnvironments(
|
|
637
|
-
projectUuid: string
|
|
690
|
+
projectUuid: string,
|
|
638
691
|
): Promise<Result<ICoolifyEnvironment[], Error>> {
|
|
639
|
-
log.info(`Getting environments for project ${projectUuid}`)
|
|
692
|
+
log.info(`Getting environments for project ${projectUuid}`);
|
|
640
693
|
|
|
641
694
|
const result = await this.request<{ environments: ICoolifyEnvironment[] }>(
|
|
642
|
-
`/projects/${projectUuid}
|
|
643
|
-
)
|
|
695
|
+
`/projects/${projectUuid}`,
|
|
696
|
+
);
|
|
644
697
|
|
|
645
698
|
if (result.error) {
|
|
646
|
-
log.error(`Failed to get environments: ${result.error}`)
|
|
647
|
-
return err(new Error(result.error))
|
|
699
|
+
log.error(`Failed to get environments: ${result.error}`);
|
|
700
|
+
return err(new Error(result.error));
|
|
648
701
|
}
|
|
649
702
|
|
|
650
|
-
log.success(`Environments retrieved for project ${projectUuid}`)
|
|
651
|
-
return ok(result.data?.environments || [])
|
|
703
|
+
log.success(`Environments retrieved for project ${projectUuid}`);
|
|
704
|
+
return ok(result.data?.environments || []);
|
|
652
705
|
}
|
|
653
706
|
|
|
654
707
|
/**
|
|
@@ -657,13 +710,13 @@ export class CoolifyService {
|
|
|
657
710
|
* @returns Result with teams list or error
|
|
658
711
|
*/
|
|
659
712
|
async listTeams(): Promise<Result<ICoolifyTeam[], Error>> {
|
|
660
|
-
const result = await this.request<ICoolifyTeam[]>(
|
|
713
|
+
const result = await this.request<ICoolifyTeam[]>("/teams");
|
|
661
714
|
|
|
662
715
|
if (result.error) {
|
|
663
|
-
return err(new Error(result.error))
|
|
716
|
+
return err(new Error(result.error));
|
|
664
717
|
}
|
|
665
718
|
|
|
666
|
-
return ok(result.data || [])
|
|
719
|
+
return ok(result.data || []);
|
|
667
720
|
}
|
|
668
721
|
|
|
669
722
|
/**
|
|
@@ -673,17 +726,17 @@ export class CoolifyService {
|
|
|
673
726
|
* @returns Result with destinations or error
|
|
674
727
|
*/
|
|
675
728
|
async getServerDestinations(
|
|
676
|
-
serverUuid: string
|
|
729
|
+
serverUuid: string,
|
|
677
730
|
): Promise<Result<ICoolifyDestination[], Error>> {
|
|
678
731
|
const result = await this.request<{
|
|
679
|
-
destinations: ICoolifyDestination[]
|
|
680
|
-
}>(`/servers/${serverUuid}`)
|
|
732
|
+
destinations: ICoolifyDestination[];
|
|
733
|
+
}>(`/servers/${serverUuid}`);
|
|
681
734
|
|
|
682
735
|
if (result.error) {
|
|
683
|
-
return err(new Error(result.error))
|
|
736
|
+
return err(new Error(result.error));
|
|
684
737
|
}
|
|
685
738
|
|
|
686
|
-
return ok(result.data?.destinations || [])
|
|
739
|
+
return ok(result.data?.destinations || []);
|
|
687
740
|
}
|
|
688
741
|
|
|
689
742
|
/**
|
|
@@ -695,27 +748,27 @@ export class CoolifyService {
|
|
|
695
748
|
*/
|
|
696
749
|
async listApplications(
|
|
697
750
|
teamId?: string,
|
|
698
|
-
projectId?: string
|
|
751
|
+
projectId?: string,
|
|
699
752
|
): Promise<Result<ICoolifyApplication[], Error>> {
|
|
700
|
-
log.info(
|
|
753
|
+
log.info("Listing applications");
|
|
701
754
|
|
|
702
|
-
let endpoint =
|
|
703
|
-
const params = new URLSearchParams()
|
|
704
|
-
if (teamId) params.set(
|
|
705
|
-
if (projectId) params.set(
|
|
755
|
+
let endpoint = "/applications";
|
|
756
|
+
const params = new URLSearchParams();
|
|
757
|
+
if (teamId) params.set("team_id", teamId);
|
|
758
|
+
if (projectId) params.set("project_id", projectId);
|
|
706
759
|
if (params.toString()) {
|
|
707
|
-
endpoint += `?${params.toString()}
|
|
760
|
+
endpoint += `?${params.toString()}`;
|
|
708
761
|
}
|
|
709
762
|
|
|
710
|
-
const result = await this.request<ICoolifyApplication[]>(endpoint)
|
|
763
|
+
const result = await this.request<ICoolifyApplication[]>(endpoint);
|
|
711
764
|
|
|
712
765
|
if (result.error) {
|
|
713
|
-
log.error(`Failed to list applications: ${result.error}`)
|
|
714
|
-
return err(new Error(result.error))
|
|
766
|
+
log.error(`Failed to list applications: ${result.error}`);
|
|
767
|
+
return err(new Error(result.error));
|
|
715
768
|
}
|
|
716
769
|
|
|
717
|
-
log.success(`Listed ${result.data?.length || 0} applications`)
|
|
718
|
-
return ok(result.data || [])
|
|
770
|
+
log.success(`Listed ${result.data?.length || 0} applications`);
|
|
771
|
+
return ok(result.data || []);
|
|
719
772
|
}
|
|
720
773
|
|
|
721
774
|
/**
|
|
@@ -725,21 +778,24 @@ export class CoolifyService {
|
|
|
725
778
|
* @returns Result indicating success or error
|
|
726
779
|
*/
|
|
727
780
|
async deleteApplication(
|
|
728
|
-
appUuid: string
|
|
781
|
+
appUuid: string,
|
|
729
782
|
): Promise<Result<ICoolifyDeleteResult, Error>> {
|
|
730
|
-
log.info(`Deleting application ${appUuid}`)
|
|
783
|
+
log.info(`Deleting application ${appUuid}`);
|
|
731
784
|
|
|
732
|
-
const result = await this.request<ICoolifyDeleteResult>(
|
|
733
|
-
|
|
734
|
-
|
|
785
|
+
const result = await this.request<ICoolifyDeleteResult>(
|
|
786
|
+
`/applications/${appUuid}`,
|
|
787
|
+
{
|
|
788
|
+
method: "DELETE",
|
|
789
|
+
},
|
|
790
|
+
);
|
|
735
791
|
|
|
736
792
|
if (result.error) {
|
|
737
|
-
log.error(`Failed to delete application: ${result.error}`)
|
|
738
|
-
return err(new Error(result.error))
|
|
793
|
+
log.error(`Failed to delete application: ${result.error}`);
|
|
794
|
+
return err(new Error(result.error));
|
|
739
795
|
}
|
|
740
796
|
|
|
741
|
-
log.success(`Application deleted: ${appUuid}`)
|
|
742
|
-
return ok({ success: true, message:
|
|
797
|
+
log.success(`Application deleted: ${appUuid}`);
|
|
798
|
+
return ok({ success: true, message: "Application deleted" });
|
|
743
799
|
}
|
|
744
800
|
|
|
745
801
|
/**
|
|
@@ -751,38 +807,45 @@ export class CoolifyService {
|
|
|
751
807
|
*/
|
|
752
808
|
async updateApplication(
|
|
753
809
|
appUuid: string,
|
|
754
|
-
options: ICoolifyUpdateOptions
|
|
810
|
+
options: ICoolifyUpdateOptions,
|
|
755
811
|
): Promise<Result<ICoolifyApplication, Error>> {
|
|
756
|
-
log.info(`Updating application ${appUuid}`)
|
|
757
|
-
|
|
758
|
-
const body: Record<string, unknown> = {}
|
|
759
|
-
if (options.name) body.name = options.name
|
|
760
|
-
if (options.description) body.description = options.description
|
|
761
|
-
if (options.buildPack) body.build_pack = options.buildPack
|
|
762
|
-
if (options.gitBranch) body.git_branch = options.gitBranch
|
|
763
|
-
if (options.portsExposes) body.ports_exposes = options.portsExposes
|
|
764
|
-
if (options.installCommand) body.install_command = options.installCommand
|
|
765
|
-
if (options.buildCommand) body.build_command = options.buildCommand
|
|
766
|
-
if (options.startCommand) body.start_command = options.startCommand
|
|
767
|
-
if (options.dockerfileLocation)
|
|
768
|
-
|
|
769
|
-
if (options.
|
|
770
|
-
if (options.
|
|
771
|
-
if (options.
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
body
|
|
777
|
-
|
|
812
|
+
log.info(`Updating application ${appUuid}`);
|
|
813
|
+
|
|
814
|
+
const body: Record<string, unknown> = {};
|
|
815
|
+
if (options.name) body.name = options.name;
|
|
816
|
+
if (options.description) body.description = options.description;
|
|
817
|
+
if (options.buildPack) body.build_pack = options.buildPack;
|
|
818
|
+
if (options.gitBranch) body.git_branch = options.gitBranch;
|
|
819
|
+
if (options.portsExposes) body.ports_exposes = options.portsExposes;
|
|
820
|
+
if (options.installCommand) body.install_command = options.installCommand;
|
|
821
|
+
if (options.buildCommand) body.build_command = options.buildCommand;
|
|
822
|
+
if (options.startCommand) body.start_command = options.startCommand;
|
|
823
|
+
if (options.dockerfileLocation)
|
|
824
|
+
body.dockerfile_location = options.dockerfileLocation;
|
|
825
|
+
if (options.baseDirectory) body.base_directory = options.baseDirectory;
|
|
826
|
+
if (options.domains) body.domains = options.domains;
|
|
827
|
+
if (options.dockerComposeDomains)
|
|
828
|
+
body.docker_compose_domains = options.dockerComposeDomains;
|
|
829
|
+
if (options.isForceHttpsEnabled !== undefined)
|
|
830
|
+
body.is_force_https_enabled = options.isForceHttpsEnabled;
|
|
831
|
+
if (options.isAutoDeployEnabled !== undefined)
|
|
832
|
+
body.is_auto_deploy_enabled = options.isAutoDeployEnabled;
|
|
833
|
+
|
|
834
|
+
const result = await this.request<ICoolifyApplication>(
|
|
835
|
+
`/applications/${appUuid}`,
|
|
836
|
+
{
|
|
837
|
+
method: "PATCH",
|
|
838
|
+
body: JSON.stringify(body),
|
|
839
|
+
},
|
|
840
|
+
);
|
|
778
841
|
|
|
779
842
|
if (result.error) {
|
|
780
|
-
log.error(`Failed to update application: ${result.error}`)
|
|
781
|
-
return err(new Error(result.error))
|
|
843
|
+
log.error(`Failed to update application: ${result.error}`);
|
|
844
|
+
return err(new Error(result.error));
|
|
782
845
|
}
|
|
783
846
|
|
|
784
|
-
log.success(`Application updated: ${appUuid}`)
|
|
785
|
-
return ok(result.data as ICoolifyApplication)
|
|
847
|
+
log.success(`Application updated: ${appUuid}`);
|
|
848
|
+
return ok(result.data as ICoolifyApplication);
|
|
786
849
|
}
|
|
787
850
|
|
|
788
851
|
/**
|
|
@@ -794,37 +857,38 @@ export class CoolifyService {
|
|
|
794
857
|
*/
|
|
795
858
|
async getApplicationLogs(
|
|
796
859
|
appUuid: string,
|
|
797
|
-
options: ICoolifyLogsOptions = {}
|
|
860
|
+
options: ICoolifyLogsOptions = {},
|
|
798
861
|
): Promise<Result<ICoolifyLogs, Error>> {
|
|
799
|
-
log.info(`Getting logs for application ${appUuid}`)
|
|
862
|
+
log.info(`Getting logs for application ${appUuid}`);
|
|
800
863
|
|
|
801
|
-
const params = new URLSearchParams()
|
|
802
|
-
if (options.follow) params.set(
|
|
803
|
-
if (options.tail) params.set(
|
|
864
|
+
const params = new URLSearchParams();
|
|
865
|
+
if (options.follow) params.set("follow", "true");
|
|
866
|
+
if (options.tail) params.set("lines", options.tail.toString());
|
|
867
|
+
if (options.serviceName) params.set("service_name", options.serviceName);
|
|
804
868
|
|
|
805
|
-
const endpoint = `/applications/${appUuid}/logs${params.toString() ? `?${params.toString()}` :
|
|
869
|
+
const endpoint = `/applications/${appUuid}/logs${params.toString() ? `?${params.toString()}` : ""}`;
|
|
806
870
|
|
|
807
|
-
const result = await this.request<{ logs: string | string[] }>(endpoint)
|
|
871
|
+
const result = await this.request<{ logs: string | string[] }>(endpoint);
|
|
808
872
|
|
|
809
873
|
if (result.error) {
|
|
810
|
-
log.error(`Failed to get logs: ${result.error}`)
|
|
811
|
-
return err(new Error(result.error))
|
|
874
|
+
log.error(`Failed to get logs: ${result.error}`);
|
|
875
|
+
return err(new Error(result.error));
|
|
812
876
|
}
|
|
813
877
|
|
|
814
878
|
// Coolify API returns logs as a single newline-delimited string for
|
|
815
879
|
// docker-compose apps, but as string[] for single-container apps.
|
|
816
|
-
const rawLogs = result.data?.logs
|
|
880
|
+
const rawLogs = result.data?.logs;
|
|
817
881
|
const logsArray: string[] = Array.isArray(rawLogs)
|
|
818
882
|
? rawLogs
|
|
819
|
-
: typeof rawLogs ===
|
|
820
|
-
? rawLogs.split(
|
|
821
|
-
: []
|
|
883
|
+
: typeof rawLogs === "string"
|
|
884
|
+
? rawLogs.split("\n").filter((l: string) => l.length > 0)
|
|
885
|
+
: [];
|
|
822
886
|
|
|
823
|
-
log.success(`Logs retrieved for application: ${appUuid}`)
|
|
887
|
+
log.success(`Logs retrieved for application: ${appUuid}`);
|
|
824
888
|
return ok({
|
|
825
889
|
logs: logsArray,
|
|
826
890
|
timestamp: new Date().toISOString(),
|
|
827
|
-
})
|
|
891
|
+
});
|
|
828
892
|
}
|
|
829
893
|
|
|
830
894
|
/**
|
|
@@ -834,20 +898,24 @@ export class CoolifyService {
|
|
|
834
898
|
* @returns Result with deployment history or error
|
|
835
899
|
*/
|
|
836
900
|
async getApplicationDeploymentHistory(
|
|
837
|
-
appUuid: string
|
|
901
|
+
appUuid: string,
|
|
838
902
|
): Promise<Result<ICoolifyDeployment[], Error>> {
|
|
839
|
-
log.info(`Getting deployment history for ${appUuid}`)
|
|
903
|
+
log.info(`Getting deployment history for ${appUuid}`);
|
|
840
904
|
|
|
841
|
-
//
|
|
842
|
-
|
|
905
|
+
// Coolify API: /deployments/applications/{appUuid}
|
|
906
|
+
// Response: { count: number, deployments: ICoolifyDeployment[] }
|
|
907
|
+
const result = await this.request<{
|
|
908
|
+
count: number;
|
|
909
|
+
deployments: ICoolifyDeployment[];
|
|
910
|
+
}>(`/deployments/applications/${appUuid}`);
|
|
843
911
|
|
|
844
912
|
if (result.error) {
|
|
845
|
-
log.error(`Failed to get deployment history: ${result.error}`)
|
|
846
|
-
return err(new Error(result.error))
|
|
913
|
+
log.error(`Failed to get deployment history: ${result.error}`);
|
|
914
|
+
return err(new Error(result.error));
|
|
847
915
|
}
|
|
848
916
|
|
|
849
|
-
log.success(`Deployment history retrieved for ${appUuid}`)
|
|
850
|
-
return ok(result.data?.deployments || [])
|
|
917
|
+
log.success(`Deployment history retrieved for ${appUuid}`);
|
|
918
|
+
return ok(result.data?.deployments || []);
|
|
851
919
|
}
|
|
852
920
|
|
|
853
921
|
/**
|
|
@@ -857,21 +925,24 @@ export class CoolifyService {
|
|
|
857
925
|
* @returns Result with application status or error
|
|
858
926
|
*/
|
|
859
927
|
async startApplication(
|
|
860
|
-
appUuid: string
|
|
928
|
+
appUuid: string,
|
|
861
929
|
): Promise<Result<ICoolifyApplication, Error>> {
|
|
862
|
-
log.info(`Starting application ${appUuid}`)
|
|
930
|
+
log.info(`Starting application ${appUuid}`);
|
|
863
931
|
|
|
864
|
-
const result = await this.request<ICoolifyApplication>(
|
|
865
|
-
|
|
866
|
-
|
|
932
|
+
const result = await this.request<ICoolifyApplication>(
|
|
933
|
+
`/applications/${appUuid}/start`,
|
|
934
|
+
{
|
|
935
|
+
method: "POST",
|
|
936
|
+
},
|
|
937
|
+
);
|
|
867
938
|
|
|
868
939
|
if (result.error) {
|
|
869
|
-
log.error(`Failed to start application: ${result.error}`)
|
|
870
|
-
return err(new Error(result.error))
|
|
940
|
+
log.error(`Failed to start application: ${result.error}`);
|
|
941
|
+
return err(new Error(result.error));
|
|
871
942
|
}
|
|
872
943
|
|
|
873
|
-
log.success(`Application started: ${appUuid}`)
|
|
874
|
-
return ok(result.data as ICoolifyApplication)
|
|
944
|
+
log.success(`Application started: ${appUuid}`);
|
|
945
|
+
return ok(result.data as ICoolifyApplication);
|
|
875
946
|
}
|
|
876
947
|
|
|
877
948
|
/**
|
|
@@ -881,21 +952,24 @@ export class CoolifyService {
|
|
|
881
952
|
* @returns Result with application status or error
|
|
882
953
|
*/
|
|
883
954
|
async stopApplication(
|
|
884
|
-
appUuid: string
|
|
955
|
+
appUuid: string,
|
|
885
956
|
): Promise<Result<ICoolifyApplication, Error>> {
|
|
886
|
-
log.info(`Stopping application ${appUuid}`)
|
|
957
|
+
log.info(`Stopping application ${appUuid}`);
|
|
887
958
|
|
|
888
|
-
const result = await this.request<ICoolifyApplication>(
|
|
889
|
-
|
|
890
|
-
|
|
959
|
+
const result = await this.request<ICoolifyApplication>(
|
|
960
|
+
`/applications/${appUuid}/stop`,
|
|
961
|
+
{
|
|
962
|
+
method: "POST",
|
|
963
|
+
},
|
|
964
|
+
);
|
|
891
965
|
|
|
892
966
|
if (result.error) {
|
|
893
|
-
log.error(`Failed to stop application: ${result.error}`)
|
|
894
|
-
return err(new Error(result.error))
|
|
967
|
+
log.error(`Failed to stop application: ${result.error}`);
|
|
968
|
+
return err(new Error(result.error));
|
|
895
969
|
}
|
|
896
970
|
|
|
897
|
-
log.success(`Application stopped: ${appUuid}`)
|
|
898
|
-
return ok(result.data as ICoolifyApplication)
|
|
971
|
+
log.success(`Application stopped: ${appUuid}`);
|
|
972
|
+
return ok(result.data as ICoolifyApplication);
|
|
899
973
|
}
|
|
900
974
|
|
|
901
975
|
/**
|
|
@@ -905,21 +979,24 @@ export class CoolifyService {
|
|
|
905
979
|
* @returns Result with application status or error
|
|
906
980
|
*/
|
|
907
981
|
async restartApplication(
|
|
908
|
-
appUuid: string
|
|
982
|
+
appUuid: string,
|
|
909
983
|
): Promise<Result<ICoolifyApplication, Error>> {
|
|
910
|
-
log.info(`Restarting application ${appUuid}`)
|
|
984
|
+
log.info(`Restarting application ${appUuid}`);
|
|
911
985
|
|
|
912
|
-
const result = await this.request<ICoolifyApplication>(
|
|
913
|
-
|
|
914
|
-
|
|
986
|
+
const result = await this.request<ICoolifyApplication>(
|
|
987
|
+
`/applications/${appUuid}/restart`,
|
|
988
|
+
{
|
|
989
|
+
method: "POST",
|
|
990
|
+
},
|
|
991
|
+
);
|
|
915
992
|
|
|
916
993
|
if (result.error) {
|
|
917
|
-
log.error(`Failed to restart application: ${result.error}`)
|
|
918
|
-
return err(new Error(result.error))
|
|
994
|
+
log.error(`Failed to restart application: ${result.error}`);
|
|
995
|
+
return err(new Error(result.error));
|
|
919
996
|
}
|
|
920
997
|
|
|
921
|
-
log.success(`Application restarted: ${appUuid}`)
|
|
922
|
-
return ok(result.data as ICoolifyApplication)
|
|
998
|
+
log.success(`Application restarted: ${appUuid}`);
|
|
999
|
+
return ok(result.data as ICoolifyApplication);
|
|
923
1000
|
}
|
|
924
1001
|
|
|
925
1002
|
/**
|
|
@@ -928,17 +1005,17 @@ export class CoolifyService {
|
|
|
928
1005
|
* @returns Result with deployments list or error
|
|
929
1006
|
*/
|
|
930
1007
|
async listDeployments(): Promise<Result<ICoolifyDeployment[], Error>> {
|
|
931
|
-
log.info(
|
|
1008
|
+
log.info("Listing active deployments");
|
|
932
1009
|
|
|
933
|
-
const result = await this.request<ICoolifyDeployment[]>(
|
|
1010
|
+
const result = await this.request<ICoolifyDeployment[]>("/deployments");
|
|
934
1011
|
|
|
935
1012
|
if (result.error) {
|
|
936
|
-
log.error(`Failed to list deployments: ${result.error}`)
|
|
937
|
-
return err(new Error(result.error))
|
|
1013
|
+
log.error(`Failed to list deployments: ${result.error}`);
|
|
1014
|
+
return err(new Error(result.error));
|
|
938
1015
|
}
|
|
939
1016
|
|
|
940
|
-
log.success(`Listed ${result.data?.length || 0} active deployments`)
|
|
941
|
-
return ok(result.data || [])
|
|
1017
|
+
log.success(`Listed ${result.data?.length || 0} active deployments`);
|
|
1018
|
+
return ok(result.data || []);
|
|
942
1019
|
}
|
|
943
1020
|
|
|
944
1021
|
/**
|
|
@@ -948,19 +1025,53 @@ export class CoolifyService {
|
|
|
948
1025
|
* @returns Result with deployment details or error
|
|
949
1026
|
*/
|
|
950
1027
|
async getDeployment(
|
|
951
|
-
deploymentUuid: string
|
|
1028
|
+
deploymentUuid: string,
|
|
952
1029
|
): Promise<Result<ICoolifyDeployment, Error>> {
|
|
953
|
-
log.info(`Getting deployment details for ${deploymentUuid}`)
|
|
1030
|
+
log.info(`Getting deployment details for ${deploymentUuid}`);
|
|
954
1031
|
|
|
955
|
-
const result = await this.request<ICoolifyDeployment>(
|
|
1032
|
+
const result = await this.request<ICoolifyDeployment>(
|
|
1033
|
+
`/deployments/${deploymentUuid}`,
|
|
1034
|
+
);
|
|
956
1035
|
|
|
957
1036
|
if (result.error) {
|
|
958
|
-
log.error(`Failed to get deployment: ${result.error}`)
|
|
959
|
-
return err(new Error(result.error))
|
|
1037
|
+
log.error(`Failed to get deployment: ${result.error}`);
|
|
1038
|
+
return err(new Error(result.error));
|
|
960
1039
|
}
|
|
961
1040
|
|
|
962
|
-
log.success(`Deployment details retrieved: ${deploymentUuid}`)
|
|
963
|
-
return ok(result.data as ICoolifyDeployment)
|
|
1041
|
+
log.success(`Deployment details retrieved: ${deploymentUuid}`);
|
|
1042
|
+
return ok(result.data as ICoolifyDeployment);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Gets logs for a specific deployment.
|
|
1047
|
+
*
|
|
1048
|
+
* @param deploymentUuid - Deployment UUID
|
|
1049
|
+
* @returns Result with deployment status and logs or error
|
|
1050
|
+
*/
|
|
1051
|
+
async getDeploymentLogs(
|
|
1052
|
+
deploymentUuid: string,
|
|
1053
|
+
): Promise<
|
|
1054
|
+
Result<{ status: string; logs: string; deployment_uuid: string }, Error>
|
|
1055
|
+
> {
|
|
1056
|
+
log.info(`Getting deployment logs for ${deploymentUuid}`);
|
|
1057
|
+
|
|
1058
|
+
const result = await this.request<{
|
|
1059
|
+
status: string;
|
|
1060
|
+
logs: string;
|
|
1061
|
+
deployment_uuid: string;
|
|
1062
|
+
}>(`/deployments/${deploymentUuid}`);
|
|
1063
|
+
|
|
1064
|
+
if (result.error) {
|
|
1065
|
+
log.error(`Failed to get deployment logs: ${result.error}`);
|
|
1066
|
+
return err(new Error(result.error));
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
log.success(`Deployment logs retrieved: ${deploymentUuid}`);
|
|
1070
|
+
return ok({
|
|
1071
|
+
status: result.data?.status || "unknown",
|
|
1072
|
+
logs: result.data?.logs || "",
|
|
1073
|
+
deployment_uuid: result.data?.deployment_uuid || deploymentUuid,
|
|
1074
|
+
});
|
|
964
1075
|
}
|
|
965
1076
|
|
|
966
1077
|
/**
|
|
@@ -974,29 +1085,63 @@ export class CoolifyService {
|
|
|
974
1085
|
async getApplicationDeployments(
|
|
975
1086
|
appUuid: string,
|
|
976
1087
|
skip: number = 0,
|
|
977
|
-
take: number = 10
|
|
1088
|
+
take: number = 10,
|
|
978
1089
|
): Promise<Result<ICoolifyDeployment[], Error>> {
|
|
979
|
-
log.info(`Getting deployments for application ${appUuid}`)
|
|
1090
|
+
log.info(`Getting deployments for application ${appUuid}`);
|
|
1091
|
+
|
|
1092
|
+
const params = new URLSearchParams();
|
|
1093
|
+
if (skip > 0) params.set("skip", skip.toString());
|
|
1094
|
+
if (take !== 10) params.set("take", take.toString());
|
|
1095
|
+
|
|
1096
|
+
const endpoint = `/applications/${appUuid}/deployments${params.toString() ? `?${params.toString()}` : ""}`;
|
|
1097
|
+
const result = await this.request<{
|
|
1098
|
+
count: number;
|
|
1099
|
+
deployments: ICoolifyDeployment[];
|
|
1100
|
+
}>(endpoint);
|
|
1101
|
+
|
|
1102
|
+
if (result.error) {
|
|
1103
|
+
log.error(`Failed to get application deployments: ${result.error}`);
|
|
1104
|
+
return err(new Error(result.error));
|
|
1105
|
+
}
|
|
980
1106
|
|
|
981
|
-
const
|
|
982
|
-
|
|
983
|
-
|
|
1107
|
+
const deployments = result.data?.deployments || [];
|
|
1108
|
+
log.success(`Retrieved ${deployments.length} deployments for ${appUuid}`);
|
|
1109
|
+
return ok(deployments);
|
|
1110
|
+
}
|
|
984
1111
|
|
|
985
|
-
|
|
986
|
-
|
|
1112
|
+
/**
|
|
1113
|
+
* Lists deployments for a specific application.
|
|
1114
|
+
*
|
|
1115
|
+
* Uses the /deployments/applications/{appUuid} endpoint which returns
|
|
1116
|
+
* all deployments (active, queued, and completed) for a single application.
|
|
1117
|
+
* This differs from listDeployments() which returns ALL deployments globally.
|
|
1118
|
+
*
|
|
1119
|
+
* @param appUuid - Application UUID
|
|
1120
|
+
* @returns Result with deployments list or error
|
|
1121
|
+
*/
|
|
1122
|
+
async listApplicationDeployments(
|
|
1123
|
+
appUuid: string,
|
|
1124
|
+
): Promise<Result<ICoolifyDeployment[], Error>> {
|
|
1125
|
+
log.info(`Listing deployments for application ${appUuid}`);
|
|
1126
|
+
|
|
1127
|
+
// API returns { count: number, deployments: ICoolifyDeployment[] }
|
|
1128
|
+
const result = await this.request<{
|
|
1129
|
+
count: number;
|
|
1130
|
+
deployments: ICoolifyDeployment[];
|
|
1131
|
+
}>(`/deployments/applications/${appUuid}`);
|
|
987
1132
|
|
|
988
1133
|
if (result.error) {
|
|
989
|
-
log.error(`Failed to
|
|
990
|
-
return err(new Error(result.error))
|
|
1134
|
+
log.error(`Failed to list application deployments: ${result.error}`);
|
|
1135
|
+
return err(new Error(result.error));
|
|
991
1136
|
}
|
|
992
1137
|
|
|
993
|
-
const deployments = result.data?.deployments || []
|
|
994
|
-
log.success(`
|
|
995
|
-
return ok(deployments)
|
|
1138
|
+
const deployments = result.data?.deployments || [];
|
|
1139
|
+
log.success(`Listed ${deployments.length} deployments for ${appUuid}`);
|
|
1140
|
+
return ok(deployments);
|
|
996
1141
|
}
|
|
997
1142
|
}
|
|
998
1143
|
|
|
999
|
-
let instance: CoolifyService | null = null
|
|
1144
|
+
let instance: CoolifyService | null = null;
|
|
1000
1145
|
|
|
1001
1146
|
/**
|
|
1002
1147
|
* Gets the singleton CoolifyService instance.
|
|
@@ -1005,9 +1150,9 @@ let instance: CoolifyService | null = null
|
|
|
1005
1150
|
*/
|
|
1006
1151
|
export function getCoolifyService(): CoolifyService {
|
|
1007
1152
|
if (!instance) {
|
|
1008
|
-
instance = new CoolifyService()
|
|
1153
|
+
instance = new CoolifyService();
|
|
1009
1154
|
}
|
|
1010
|
-
return instance
|
|
1155
|
+
return instance;
|
|
1011
1156
|
}
|
|
1012
1157
|
|
|
1013
1158
|
// Re-export types
|
|
@@ -1027,4 +1172,4 @@ export type {
|
|
|
1027
1172
|
ICoolifyLogsOptions,
|
|
1028
1173
|
ICoolifyLogs,
|
|
1029
1174
|
IProgressCallback,
|
|
1030
|
-
} from
|
|
1175
|
+
} from "./types.js";
|