@mks2508/coolify-mks-cli-mcp 0.5.0 → 0.6.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/coolify-state.d.ts +51 -0
- package/dist/cli/coolify-state.d.ts.map +1 -0
- package/dist/cli/index.js +2862 -631
- package/dist/coolify/config.d.ts +1 -1
- package/dist/coolify/config.d.ts.map +1 -1
- package/dist/coolify/index.d.ts +626 -12
- package/dist/coolify/index.d.ts.map +1 -1
- package/dist/coolify/types.d.ts +87 -3
- package/dist/coolify/types.d.ts.map +1 -1
- package/dist/dist-C4hIkHif.js +66 -0
- package/dist/dist-C4hIkHif.js.map +1 -0
- package/dist/dist-DEPvJhbP.js +3 -0
- package/dist/index.cjs +8511 -28542
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +32 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8470 -28506
- package/dist/index.js.map +1 -1
- package/dist/network.d.ts +75 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/sdk.d.ts +356 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/sse.js +3 -1
- package/dist/server/stdio.d.ts +0 -2
- package/dist/server/stdio.d.ts.map +1 -1
- package/dist/server/stdio.js +3307 -1618
- package/dist/tools/definitions.d.ts +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/handlers.d.ts +6 -7
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/trace.d.ts +71 -0
- package/dist/trace.d.ts.map +1 -0
- package/dist/utils/format.d.ts +1 -1
- package/dist/utils/format.d.ts.map +1 -1
- package/package.json +13 -7
- package/src/cli/actions.ts +162 -0
- package/src/cli/commands/active-deployments.ts +24 -0
- package/src/cli/commands/build-logs.ts +25 -22
- package/src/cli/commands/cancel-deploy.ts +35 -0
- package/src/cli/commands/config.ts +53 -47
- package/src/cli/commands/create.ts +74 -53
- package/src/cli/commands/databases.ts +63 -0
- package/src/cli/commands/db.ts +68 -0
- package/src/cli/commands/delete.ts +41 -29
- package/src/cli/commands/deploy.ts +42 -21
- package/src/cli/commands/deployments.ts +41 -31
- package/src/cli/commands/destinations.ts +19 -27
- package/src/cli/commands/diagnose.ts +139 -0
- package/src/cli/commands/env.ts +66 -41
- package/src/cli/commands/environments.ts +36 -32
- package/src/cli/commands/exec.ts +39 -0
- package/src/cli/commands/keys.ts +46 -0
- package/src/cli/commands/list.ts +29 -27
- package/src/cli/commands/logs.ts +33 -18
- package/src/cli/commands/network.ts +145 -0
- package/src/cli/commands/projects.ts +51 -39
- package/src/cli/commands/restart.ts +34 -18
- package/src/cli/commands/server-resources.ts +71 -0
- package/src/cli/commands/servers.ts +23 -23
- package/src/cli/commands/service-logs.ts +24 -16
- package/src/cli/commands/services.ts +63 -0
- package/src/cli/commands/show.ts +72 -41
- package/src/cli/commands/start.ts +34 -18
- package/src/cli/commands/stop.ts +34 -18
- package/src/cli/commands/svc.ts +68 -0
- package/src/cli/commands/teams.ts +60 -0
- package/src/cli/commands/update.ts +73 -49
- package/src/cli/commands/version.ts +37 -0
- package/src/cli/coolify-state.ts +88 -0
- package/src/cli/index.ts +383 -151
- package/src/coolify/config.ts +29 -27
- package/src/coolify/index.ts +1829 -123
- package/src/coolify/types.ts +217 -124
- package/src/index.ts +82 -868
- package/src/network.ts +298 -0
- package/src/sdk.ts +597 -0
- package/src/server/index.ts +13 -0
- package/src/server/sse.ts +33 -25
- package/src/server/stdio.ts +24 -27
- package/src/tools/definitions.ts +893 -264
- package/src/tools/handlers.ts +556 -748
- package/src/tools/index.ts +8 -0
- package/src/trace.ts +116 -0
- package/src/utils/format.ts +36 -33
package/src/coolify/index.ts
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
type ICoolifyAppOptions,
|
|
14
14
|
type ICoolifyAppResult,
|
|
15
15
|
type ICoolifyApplication,
|
|
16
|
+
type ICoolifyDatabase,
|
|
17
|
+
type ICoolifyDatabaseBackup,
|
|
16
18
|
type ICoolifyDeleteResult,
|
|
17
19
|
type ICoolifyDeployment,
|
|
18
20
|
type ICoolifyDeployOptions,
|
|
@@ -21,10 +23,15 @@ import {
|
|
|
21
23
|
type ICoolifyEnvironment,
|
|
22
24
|
type ICoolifyLogs,
|
|
23
25
|
type ICoolifyLogsOptions,
|
|
26
|
+
type ICoolifyPrivateKey,
|
|
24
27
|
type ICoolifyProject,
|
|
25
28
|
type ICoolifyServer,
|
|
29
|
+
type ICoolifyServerDomain,
|
|
30
|
+
type ICoolifyServerResource,
|
|
31
|
+
type ICoolifyService as ICoolifyServiceType,
|
|
26
32
|
type ICoolifyTeam,
|
|
27
33
|
type ICoolifyUpdateOptions,
|
|
34
|
+
type ICoolifyVersion,
|
|
28
35
|
type IProgressCallback,
|
|
29
36
|
} from "./types.js";
|
|
30
37
|
|
|
@@ -477,7 +484,7 @@ export class CoolifyService {
|
|
|
477
484
|
appUuid: string,
|
|
478
485
|
key: string,
|
|
479
486
|
value: string,
|
|
480
|
-
|
|
487
|
+
_isBuildTime: boolean = false,
|
|
481
488
|
): Promise<Result<void, Error>> {
|
|
482
489
|
log.info(`Setting environment variable ${key} for ${appUuid}`);
|
|
483
490
|
|
|
@@ -587,10 +594,23 @@ export class CoolifyService {
|
|
|
587
594
|
/**
|
|
588
595
|
* Lists available servers in Coolify.
|
|
589
596
|
*
|
|
597
|
+
* @param page - Optional page number for pagination
|
|
598
|
+
* @param perPage - Optional number of items per page
|
|
590
599
|
* @returns Result with servers or error
|
|
591
600
|
*/
|
|
592
|
-
async listServers(
|
|
593
|
-
|
|
601
|
+
async listServers(
|
|
602
|
+
page?: number,
|
|
603
|
+
perPage?: number,
|
|
604
|
+
): Promise<Result<ICoolifyServer[], Error>> {
|
|
605
|
+
let endpoint = "/servers";
|
|
606
|
+
const params = new URLSearchParams();
|
|
607
|
+
if (page) params.set("page", page.toString());
|
|
608
|
+
if (perPage) params.set("per_page", perPage.toString());
|
|
609
|
+
if (params.toString()) {
|
|
610
|
+
endpoint += `?${params.toString()}`;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const result = await this.request<ICoolifyServer[]>(endpoint);
|
|
594
614
|
|
|
595
615
|
if (result.error) {
|
|
596
616
|
return err(new Error(result.error));
|
|
@@ -622,18 +642,31 @@ export class CoolifyService {
|
|
|
622
642
|
/**
|
|
623
643
|
* Lists all GitHub Apps configured in Coolify.
|
|
624
644
|
*
|
|
645
|
+
* @param page - Optional page number for pagination
|
|
646
|
+
* @param perPage - Optional number of items per page
|
|
625
647
|
* @returns Result with GitHub Apps list or error
|
|
626
648
|
*/
|
|
627
|
-
async listGithubApps(
|
|
649
|
+
async listGithubApps(
|
|
650
|
+
page?: number,
|
|
651
|
+
perPage?: number,
|
|
652
|
+
): Promise<
|
|
628
653
|
Result<
|
|
629
654
|
Array<{ id: number; uuid: string; name: string; is_public: boolean }>,
|
|
630
655
|
Error
|
|
631
656
|
>
|
|
632
657
|
> {
|
|
658
|
+
let endpoint = "/github-apps";
|
|
659
|
+
const params = new URLSearchParams();
|
|
660
|
+
if (page) params.set("page", page.toString());
|
|
661
|
+
if (perPage) params.set("per_page", perPage.toString());
|
|
662
|
+
if (params.toString()) {
|
|
663
|
+
endpoint += `?${params.toString()}`;
|
|
664
|
+
}
|
|
665
|
+
|
|
633
666
|
const result =
|
|
634
667
|
await this.request<
|
|
635
668
|
Array<{ id: number; uuid: string; name: string; is_public: boolean }>
|
|
636
|
-
>(
|
|
669
|
+
>(endpoint);
|
|
637
670
|
if (result.error) return err(new Error(result.error));
|
|
638
671
|
return ok(result.data || []);
|
|
639
672
|
}
|
|
@@ -641,10 +674,23 @@ export class CoolifyService {
|
|
|
641
674
|
/**
|
|
642
675
|
* Lists all projects.
|
|
643
676
|
*
|
|
677
|
+
* @param page - Optional page number for pagination
|
|
678
|
+
* @param perPage - Optional number of items per page
|
|
644
679
|
* @returns Result with projects list or error
|
|
645
680
|
*/
|
|
646
|
-
async listProjects(
|
|
647
|
-
|
|
681
|
+
async listProjects(
|
|
682
|
+
page?: number,
|
|
683
|
+
perPage?: number,
|
|
684
|
+
): Promise<Result<ICoolifyProject[], Error>> {
|
|
685
|
+
let endpoint = "/projects";
|
|
686
|
+
const params = new URLSearchParams();
|
|
687
|
+
if (page) params.set("page", page.toString());
|
|
688
|
+
if (perPage) params.set("per_page", perPage.toString());
|
|
689
|
+
if (params.toString()) {
|
|
690
|
+
endpoint += `?${params.toString()}`;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const result = await this.request<ICoolifyProject[]>(endpoint);
|
|
648
694
|
|
|
649
695
|
if (result.error) {
|
|
650
696
|
return err(new Error(result.error));
|
|
@@ -707,10 +753,23 @@ export class CoolifyService {
|
|
|
707
753
|
/**
|
|
708
754
|
* Lists all teams.
|
|
709
755
|
*
|
|
756
|
+
* @param page - Optional page number for pagination
|
|
757
|
+
* @param perPage - Optional number of items per page
|
|
710
758
|
* @returns Result with teams list or error
|
|
711
759
|
*/
|
|
712
|
-
async listTeams(
|
|
713
|
-
|
|
760
|
+
async listTeams(
|
|
761
|
+
page?: number,
|
|
762
|
+
perPage?: number,
|
|
763
|
+
): Promise<Result<ICoolifyTeam[], Error>> {
|
|
764
|
+
let endpoint = "/teams";
|
|
765
|
+
const params = new URLSearchParams();
|
|
766
|
+
if (page) params.set("page", page.toString());
|
|
767
|
+
if (perPage) params.set("per_page", perPage.toString());
|
|
768
|
+
if (params.toString()) {
|
|
769
|
+
endpoint += `?${params.toString()}`;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
const result = await this.request<ICoolifyTeam[]>(endpoint);
|
|
714
773
|
|
|
715
774
|
if (result.error) {
|
|
716
775
|
return err(new Error(result.error));
|
|
@@ -744,11 +803,15 @@ export class CoolifyService {
|
|
|
744
803
|
*
|
|
745
804
|
* @param teamId - Optional team ID to filter by
|
|
746
805
|
* @param projectId - Optional project ID to filter by
|
|
806
|
+
* @param page - Optional page number for pagination
|
|
807
|
+
* @param perPage - Optional number of items per page
|
|
747
808
|
* @returns Result with applications list or error
|
|
748
809
|
*/
|
|
749
810
|
async listApplications(
|
|
750
811
|
teamId?: string,
|
|
751
812
|
projectId?: string,
|
|
813
|
+
page?: number,
|
|
814
|
+
perPage?: number,
|
|
752
815
|
): Promise<Result<ICoolifyApplication[], Error>> {
|
|
753
816
|
log.info("Listing applications");
|
|
754
817
|
|
|
@@ -756,6 +819,8 @@ export class CoolifyService {
|
|
|
756
819
|
const params = new URLSearchParams();
|
|
757
820
|
if (teamId) params.set("team_id", teamId);
|
|
758
821
|
if (projectId) params.set("project_id", projectId);
|
|
822
|
+
if (page) params.set("page", page.toString());
|
|
823
|
+
if (perPage) params.set("per_page", perPage.toString());
|
|
759
824
|
if (params.toString()) {
|
|
760
825
|
endpoint += `?${params.toString()}`;
|
|
761
826
|
}
|
|
@@ -775,19 +840,34 @@ export class CoolifyService {
|
|
|
775
840
|
* Deletes an application.
|
|
776
841
|
*
|
|
777
842
|
* @param appUuid - Application UUID
|
|
843
|
+
* @param options - Delete options for cascade deletion
|
|
778
844
|
* @returns Result indicating success or error
|
|
779
845
|
*/
|
|
780
846
|
async deleteApplication(
|
|
781
847
|
appUuid: string,
|
|
848
|
+
options?: {
|
|
849
|
+
deleteConfigurations?: boolean;
|
|
850
|
+
deleteVolumes?: boolean;
|
|
851
|
+
dockerCleanup?: boolean;
|
|
852
|
+
deleteConnectedNetworks?: boolean;
|
|
853
|
+
},
|
|
782
854
|
): Promise<Result<ICoolifyDeleteResult, Error>> {
|
|
783
855
|
log.info(`Deleting application ${appUuid}`);
|
|
784
856
|
|
|
785
|
-
const
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
)
|
|
857
|
+
const params = new URLSearchParams();
|
|
858
|
+
if (options?.deleteConfigurations)
|
|
859
|
+
params.set("delete_configurations", "true");
|
|
860
|
+
if (options?.deleteVolumes) params.set("delete_volumes", "true");
|
|
861
|
+
if (options?.dockerCleanup) params.set("docker_cleanup", "true");
|
|
862
|
+
if (options?.deleteConnectedNetworks)
|
|
863
|
+
params.set("delete_connected_networks", "true");
|
|
864
|
+
|
|
865
|
+
const queryString = params.toString();
|
|
866
|
+
const endpoint = `/applications/${appUuid}${queryString ? `?${queryString}` : ""}`;
|
|
867
|
+
|
|
868
|
+
const result = await this.request<ICoolifyDeleteResult>(endpoint, {
|
|
869
|
+
method: "DELETE",
|
|
870
|
+
});
|
|
791
871
|
|
|
792
872
|
if (result.error) {
|
|
793
873
|
log.error(`Failed to delete application: ${result.error}`);
|
|
@@ -891,6 +971,70 @@ export class CoolifyService {
|
|
|
891
971
|
});
|
|
892
972
|
}
|
|
893
973
|
|
|
974
|
+
/**
|
|
975
|
+
* Executes a command on an application's running container.
|
|
976
|
+
*
|
|
977
|
+
* @param appUuid - Application UUID
|
|
978
|
+
* @param command - Shell command to execute
|
|
979
|
+
* @returns Result with command output or error
|
|
980
|
+
*/
|
|
981
|
+
async executeCommand(
|
|
982
|
+
appUuid: string,
|
|
983
|
+
command: string,
|
|
984
|
+
): Promise<Result<{ message?: string; response?: string }, Error>> {
|
|
985
|
+
log.info(`Executing command on application ${appUuid}`);
|
|
986
|
+
|
|
987
|
+
const result = await this.request<{
|
|
988
|
+
message?: string;
|
|
989
|
+
response?: string;
|
|
990
|
+
}>(`/applications/${appUuid}/execute-command`, {
|
|
991
|
+
method: "POST",
|
|
992
|
+
body: JSON.stringify({ command }),
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
if (result.error) {
|
|
996
|
+
log.error(`Failed to execute command: ${result.error}`);
|
|
997
|
+
return err(new Error(result.error));
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
log.success(`Command executed on ${appUuid}`);
|
|
1001
|
+
return ok(result.data || { message: "Command executed" });
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Bulk updates environment variables for an application.
|
|
1006
|
+
*
|
|
1007
|
+
* @param appUuid - Application UUID
|
|
1008
|
+
* @param envVars - Array of { key, value, is_preview? } objects
|
|
1009
|
+
* @returns Result indicating success or error
|
|
1010
|
+
*/
|
|
1011
|
+
async bulkUpdateEnvironmentVariables(
|
|
1012
|
+
appUuid: string,
|
|
1013
|
+
envVars: Array<{
|
|
1014
|
+
key: string;
|
|
1015
|
+
value: string;
|
|
1016
|
+
is_preview?: boolean;
|
|
1017
|
+
}>,
|
|
1018
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1019
|
+
log.info(`Bulk updating ${envVars.length} env vars for ${appUuid}`);
|
|
1020
|
+
|
|
1021
|
+
const result = await this.request<{ message: string }>(
|
|
1022
|
+
`/applications/${appUuid}/envs/bulk`,
|
|
1023
|
+
{
|
|
1024
|
+
method: "PATCH",
|
|
1025
|
+
body: JSON.stringify(envVars),
|
|
1026
|
+
},
|
|
1027
|
+
);
|
|
1028
|
+
|
|
1029
|
+
if (result.error) {
|
|
1030
|
+
log.error(`Failed to bulk update env vars: ${result.error}`);
|
|
1031
|
+
return err(new Error(result.error));
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
log.success(`Bulk updated ${envVars.length} env vars for ${appUuid}`);
|
|
1035
|
+
return ok(result.data || { message: "Environment variables updated" });
|
|
1036
|
+
}
|
|
1037
|
+
|
|
894
1038
|
/**
|
|
895
1039
|
* Gets deployment history for an application.
|
|
896
1040
|
*
|
|
@@ -920,21 +1064,27 @@ export class CoolifyService {
|
|
|
920
1064
|
|
|
921
1065
|
/**
|
|
922
1066
|
* Starts a stopped application.
|
|
1067
|
+
* Note: Coolify API uses GET for application start/stop/restart.
|
|
923
1068
|
*
|
|
924
1069
|
* @param appUuid - Application UUID
|
|
1070
|
+
* @param options - Optional start options (force, instant_deploy)
|
|
925
1071
|
* @returns Result with application status or error
|
|
926
1072
|
*/
|
|
927
1073
|
async startApplication(
|
|
928
1074
|
appUuid: string,
|
|
1075
|
+
options?: { force?: boolean; instantDeploy?: boolean },
|
|
929
1076
|
): Promise<Result<ICoolifyApplication, Error>> {
|
|
930
1077
|
log.info(`Starting application ${appUuid}`);
|
|
931
1078
|
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1079
|
+
const params = new URLSearchParams();
|
|
1080
|
+
if (options?.force) params.set("force", "true");
|
|
1081
|
+
if (options?.instantDeploy) params.set("instant_deploy", "true");
|
|
1082
|
+
const queryString = params.toString();
|
|
1083
|
+
const endpoint = `/applications/${appUuid}/start${queryString ? `?${queryString}` : ""}`;
|
|
1084
|
+
|
|
1085
|
+
const result = await this.request<ICoolifyApplication>(endpoint, {
|
|
1086
|
+
method: "GET",
|
|
1087
|
+
});
|
|
938
1088
|
|
|
939
1089
|
if (result.error) {
|
|
940
1090
|
log.error(`Failed to start application: ${result.error}`);
|
|
@@ -947,6 +1097,7 @@ export class CoolifyService {
|
|
|
947
1097
|
|
|
948
1098
|
/**
|
|
949
1099
|
* Stops a running application.
|
|
1100
|
+
* Note: Coolify API uses GET for application start/stop/restart.
|
|
950
1101
|
*
|
|
951
1102
|
* @param appUuid - Application UUID
|
|
952
1103
|
* @returns Result with application status or error
|
|
@@ -958,9 +1109,7 @@ export class CoolifyService {
|
|
|
958
1109
|
|
|
959
1110
|
const result = await this.request<ICoolifyApplication>(
|
|
960
1111
|
`/applications/${appUuid}/stop`,
|
|
961
|
-
{
|
|
962
|
-
method: "POST",
|
|
963
|
-
},
|
|
1112
|
+
{ method: "GET" },
|
|
964
1113
|
);
|
|
965
1114
|
|
|
966
1115
|
if (result.error) {
|
|
@@ -974,6 +1123,7 @@ export class CoolifyService {
|
|
|
974
1123
|
|
|
975
1124
|
/**
|
|
976
1125
|
* Restarts an application.
|
|
1126
|
+
* Note: Coolify API uses GET for application start/stop/restart.
|
|
977
1127
|
*
|
|
978
1128
|
* @param appUuid - Application UUID
|
|
979
1129
|
* @returns Result with application status or error
|
|
@@ -985,9 +1135,7 @@ export class CoolifyService {
|
|
|
985
1135
|
|
|
986
1136
|
const result = await this.request<ICoolifyApplication>(
|
|
987
1137
|
`/applications/${appUuid}/restart`,
|
|
988
|
-
{
|
|
989
|
-
method: "POST",
|
|
990
|
-
},
|
|
1138
|
+
{ method: "GET" },
|
|
991
1139
|
);
|
|
992
1140
|
|
|
993
1141
|
if (result.error) {
|
|
@@ -999,145 +1147,1696 @@ export class CoolifyService {
|
|
|
999
1147
|
return ok(result.data as ICoolifyApplication);
|
|
1000
1148
|
}
|
|
1001
1149
|
|
|
1150
|
+
// ===========================================================================
|
|
1151
|
+
// Version / Health
|
|
1152
|
+
// ===========================================================================
|
|
1153
|
+
|
|
1002
1154
|
/**
|
|
1003
|
-
*
|
|
1155
|
+
* Gets the Coolify server version.
|
|
1004
1156
|
*
|
|
1005
|
-
* @returns Result with
|
|
1157
|
+
* @returns Result with version info or error
|
|
1006
1158
|
*/
|
|
1007
|
-
async
|
|
1008
|
-
log.info("
|
|
1159
|
+
async getVersion(): Promise<Result<ICoolifyVersion, Error>> {
|
|
1160
|
+
log.info("Getting Coolify version");
|
|
1009
1161
|
|
|
1010
|
-
|
|
1162
|
+
// /version returns plain text, not JSON
|
|
1163
|
+
if (!this.baseUrl || !this.token) {
|
|
1164
|
+
return err(new Error("Coolify not configured"));
|
|
1165
|
+
}
|
|
1011
1166
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1167
|
+
try {
|
|
1168
|
+
const baseUrl = this.baseUrl.replace(/\/+$/, "");
|
|
1169
|
+
const url = `${baseUrl}/api/v1/version`;
|
|
1170
|
+
const response = await fetch(url, {
|
|
1171
|
+
headers: {
|
|
1172
|
+
Authorization: `Bearer ${this.token}`,
|
|
1173
|
+
},
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
if (!response.ok) {
|
|
1177
|
+
return err(
|
|
1178
|
+
new Error(`HTTP ${response.status}: ${response.statusText}`),
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
const version = (await response.text()).trim();
|
|
1183
|
+
log.success(`Coolify version: ${version}`);
|
|
1184
|
+
return ok({ version });
|
|
1185
|
+
} catch (error) {
|
|
1186
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1187
|
+
return err(new Error(message));
|
|
1015
1188
|
}
|
|
1189
|
+
}
|
|
1016
1190
|
|
|
1017
|
-
|
|
1191
|
+
// ===========================================================================
|
|
1192
|
+
// Database endpoints
|
|
1193
|
+
// ===========================================================================
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* Lists all databases.
|
|
1197
|
+
*
|
|
1198
|
+
* @param page - Optional page number
|
|
1199
|
+
* @param perPage - Optional items per page
|
|
1200
|
+
* @returns Result with databases list or error
|
|
1201
|
+
*/
|
|
1202
|
+
async listDatabases(
|
|
1203
|
+
page?: number,
|
|
1204
|
+
perPage?: number,
|
|
1205
|
+
): Promise<Result<ICoolifyDatabase[], Error>> {
|
|
1206
|
+
log.info("Listing databases");
|
|
1207
|
+
|
|
1208
|
+
let endpoint = "/databases";
|
|
1209
|
+
const params = new URLSearchParams();
|
|
1210
|
+
if (page) params.set("page", page.toString());
|
|
1211
|
+
if (perPage) params.set("per_page", perPage.toString());
|
|
1212
|
+
if (params.toString()) endpoint += `?${params.toString()}`;
|
|
1213
|
+
|
|
1214
|
+
const result = await this.request<ICoolifyDatabase[]>(endpoint);
|
|
1215
|
+
if (result.error) return err(new Error(result.error));
|
|
1216
|
+
|
|
1217
|
+
log.success(`Listed ${result.data?.length || 0} databases`);
|
|
1018
1218
|
return ok(result.data || []);
|
|
1019
1219
|
}
|
|
1020
1220
|
|
|
1021
1221
|
/**
|
|
1022
|
-
* Gets
|
|
1222
|
+
* Gets details of a specific database.
|
|
1023
1223
|
*
|
|
1024
|
-
* @param
|
|
1025
|
-
* @returns Result with
|
|
1224
|
+
* @param uuid - Database UUID
|
|
1225
|
+
* @returns Result with database details or error
|
|
1026
1226
|
*/
|
|
1027
|
-
async
|
|
1028
|
-
|
|
1029
|
-
): Promise<Result<ICoolifyDeployment, Error>> {
|
|
1030
|
-
log.info(`Getting deployment details for ${deploymentUuid}`);
|
|
1227
|
+
async getDatabase(uuid: string): Promise<Result<ICoolifyDatabase, Error>> {
|
|
1228
|
+
log.info(`Getting database ${uuid}`);
|
|
1031
1229
|
|
|
1032
|
-
const result = await this.request<
|
|
1033
|
-
|
|
1034
|
-
);
|
|
1230
|
+
const result = await this.request<ICoolifyDatabase>(`/databases/${uuid}`);
|
|
1231
|
+
if (result.error) return err(new Error(result.error));
|
|
1035
1232
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
return err(new Error(result.error));
|
|
1039
|
-
}
|
|
1233
|
+
return ok(result.data as ICoolifyDatabase);
|
|
1234
|
+
}
|
|
1040
1235
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1236
|
+
/**
|
|
1237
|
+
* Creates a database of the specified type.
|
|
1238
|
+
*
|
|
1239
|
+
* @param dbType - Database type (postgresql, mysql, mariadb, mongodb, redis, keydb, clickhouse, dragonfly)
|
|
1240
|
+
* @param data - Database creation data
|
|
1241
|
+
* @returns Result with created database UUID or error
|
|
1242
|
+
*/
|
|
1243
|
+
async createDatabase(
|
|
1244
|
+
dbType: string,
|
|
1245
|
+
data: Record<string, unknown>,
|
|
1246
|
+
): Promise<Result<{ uuid: string }, Error>> {
|
|
1247
|
+
log.info(`Creating ${dbType} database`);
|
|
1248
|
+
|
|
1249
|
+
const result = await this.request<{ uuid: string }>(
|
|
1250
|
+
`/databases/${dbType}`,
|
|
1251
|
+
{
|
|
1252
|
+
method: "POST",
|
|
1253
|
+
body: JSON.stringify(data),
|
|
1254
|
+
},
|
|
1255
|
+
);
|
|
1256
|
+
if (result.error) return err(new Error(result.error));
|
|
1257
|
+
|
|
1258
|
+
log.success(`Database created: ${result.data?.uuid}`);
|
|
1259
|
+
return ok(result.data!);
|
|
1043
1260
|
}
|
|
1044
1261
|
|
|
1045
1262
|
/**
|
|
1046
|
-
*
|
|
1263
|
+
* Updates a database configuration.
|
|
1047
1264
|
*
|
|
1048
|
-
* @param
|
|
1049
|
-
* @
|
|
1265
|
+
* @param uuid - Database UUID
|
|
1266
|
+
* @param data - Update data
|
|
1267
|
+
* @returns Result with updated database or error
|
|
1050
1268
|
*/
|
|
1051
|
-
async
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1269
|
+
async updateDatabase(
|
|
1270
|
+
uuid: string,
|
|
1271
|
+
data: Record<string, unknown>,
|
|
1272
|
+
): Promise<Result<ICoolifyDatabase, Error>> {
|
|
1273
|
+
log.info(`Updating database ${uuid}`);
|
|
1274
|
+
|
|
1275
|
+
const result = await this.request<ICoolifyDatabase>(`/databases/${uuid}`, {
|
|
1276
|
+
method: "PATCH",
|
|
1277
|
+
body: JSON.stringify(data),
|
|
1278
|
+
});
|
|
1279
|
+
if (result.error) return err(new Error(result.error));
|
|
1057
1280
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
deployment_uuid: string;
|
|
1062
|
-
}>(`/deployments/${deploymentUuid}`);
|
|
1281
|
+
log.success(`Database updated: ${uuid}`);
|
|
1282
|
+
return ok(result.data as ICoolifyDatabase);
|
|
1283
|
+
}
|
|
1063
1284
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1285
|
+
/**
|
|
1286
|
+
* Deletes a database.
|
|
1287
|
+
*
|
|
1288
|
+
* @param uuid - Database UUID
|
|
1289
|
+
* @param options - Delete options for cascade deletion
|
|
1290
|
+
* @returns Result indicating success or error
|
|
1291
|
+
*/
|
|
1292
|
+
async deleteDatabase(
|
|
1293
|
+
uuid: string,
|
|
1294
|
+
options?: {
|
|
1295
|
+
deleteConfigurations?: boolean;
|
|
1296
|
+
deleteVolumes?: boolean;
|
|
1297
|
+
dockerCleanup?: boolean;
|
|
1298
|
+
deleteConnectedNetworks?: boolean;
|
|
1299
|
+
},
|
|
1300
|
+
): Promise<Result<ICoolifyDeleteResult, Error>> {
|
|
1301
|
+
log.info(`Deleting database ${uuid}`);
|
|
1068
1302
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1303
|
+
const params = new URLSearchParams();
|
|
1304
|
+
if (options?.deleteConfigurations)
|
|
1305
|
+
params.set("delete_configurations", "true");
|
|
1306
|
+
if (options?.deleteVolumes) params.set("delete_volumes", "true");
|
|
1307
|
+
if (options?.dockerCleanup) params.set("docker_cleanup", "true");
|
|
1308
|
+
if (options?.deleteConnectedNetworks)
|
|
1309
|
+
params.set("delete_connected_networks", "true");
|
|
1310
|
+
|
|
1311
|
+
const queryString = params.toString();
|
|
1312
|
+
const endpoint = `/databases/${uuid}${queryString ? `?${queryString}` : ""}`;
|
|
1313
|
+
|
|
1314
|
+
const result = await this.request<ICoolifyDeleteResult>(endpoint, {
|
|
1315
|
+
method: "DELETE",
|
|
1074
1316
|
});
|
|
1317
|
+
if (result.error) return err(new Error(result.error));
|
|
1318
|
+
|
|
1319
|
+
log.success(`Database deleted: ${uuid}`);
|
|
1320
|
+
return ok({ success: true, message: "Database deleted" });
|
|
1075
1321
|
}
|
|
1076
1322
|
|
|
1077
1323
|
/**
|
|
1078
|
-
*
|
|
1324
|
+
* Starts a database.
|
|
1079
1325
|
*
|
|
1080
|
-
* @param
|
|
1081
|
-
* @
|
|
1082
|
-
* @param take - Number of deployments to return
|
|
1083
|
-
* @returns Result with deployments list or error
|
|
1326
|
+
* @param uuid - Database UUID
|
|
1327
|
+
* @returns Result indicating success or error
|
|
1084
1328
|
*/
|
|
1085
|
-
async
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1329
|
+
async startDatabase(
|
|
1330
|
+
uuid: string,
|
|
1331
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1332
|
+
log.info(`Starting database ${uuid}`);
|
|
1333
|
+
|
|
1334
|
+
const result = await this.request<{ message: string }>(
|
|
1335
|
+
`/databases/${uuid}/start`,
|
|
1336
|
+
{ method: "GET" },
|
|
1337
|
+
);
|
|
1338
|
+
if (result.error) return err(new Error(result.error));
|
|
1091
1339
|
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1340
|
+
log.success(`Database started: ${uuid}`);
|
|
1341
|
+
return ok(result.data || { message: "Database started" });
|
|
1342
|
+
}
|
|
1095
1343
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1344
|
+
/**
|
|
1345
|
+
* Stops a database.
|
|
1346
|
+
*
|
|
1347
|
+
* @param uuid - Database UUID
|
|
1348
|
+
* @returns Result indicating success or error
|
|
1349
|
+
*/
|
|
1350
|
+
async stopDatabase(
|
|
1351
|
+
uuid: string,
|
|
1352
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1353
|
+
log.info(`Stopping database ${uuid}`);
|
|
1354
|
+
|
|
1355
|
+
const result = await this.request<{ message: string }>(
|
|
1356
|
+
`/databases/${uuid}/stop`,
|
|
1357
|
+
{ method: "GET" },
|
|
1358
|
+
);
|
|
1359
|
+
if (result.error) return err(new Error(result.error));
|
|
1101
1360
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
}
|
|
1361
|
+
log.success(`Database stopped: ${uuid}`);
|
|
1362
|
+
return ok(result.data || { message: "Database stopped" });
|
|
1363
|
+
}
|
|
1106
1364
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1365
|
+
/**
|
|
1366
|
+
* Restarts a database.
|
|
1367
|
+
*
|
|
1368
|
+
* @param uuid - Database UUID
|
|
1369
|
+
* @returns Result indicating success or error
|
|
1370
|
+
*/
|
|
1371
|
+
async restartDatabase(
|
|
1372
|
+
uuid: string,
|
|
1373
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1374
|
+
log.info(`Restarting database ${uuid}`);
|
|
1375
|
+
|
|
1376
|
+
const result = await this.request<{ message: string }>(
|
|
1377
|
+
`/databases/${uuid}/restart`,
|
|
1378
|
+
{ method: "GET" },
|
|
1379
|
+
);
|
|
1380
|
+
if (result.error) return err(new Error(result.error));
|
|
1381
|
+
|
|
1382
|
+
log.success(`Database restarted: ${uuid}`);
|
|
1383
|
+
return ok(result.data || { message: "Database restarted" });
|
|
1110
1384
|
}
|
|
1111
1385
|
|
|
1386
|
+
// ===========================================================================
|
|
1387
|
+
// Database Backup endpoints
|
|
1388
|
+
// ===========================================================================
|
|
1389
|
+
|
|
1112
1390
|
/**
|
|
1113
|
-
* Lists
|
|
1391
|
+
* Lists backups for a database.
|
|
1114
1392
|
*
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1117
|
-
|
|
1393
|
+
* @param databaseUuid - Database UUID
|
|
1394
|
+
* @returns Result with backups list or error
|
|
1395
|
+
*/
|
|
1396
|
+
async listDatabaseBackups(
|
|
1397
|
+
databaseUuid: string,
|
|
1398
|
+
): Promise<Result<ICoolifyDatabaseBackup[], Error>> {
|
|
1399
|
+
log.info(`Listing backups for database ${databaseUuid}`);
|
|
1400
|
+
|
|
1401
|
+
const result = await this.request<ICoolifyDatabaseBackup[]>(
|
|
1402
|
+
`/databases/${databaseUuid}/backups`,
|
|
1403
|
+
);
|
|
1404
|
+
if (result.error) return err(new Error(result.error));
|
|
1405
|
+
|
|
1406
|
+
return ok(result.data || []);
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
/**
|
|
1410
|
+
* Gets a specific database backup.
|
|
1118
1411
|
*
|
|
1119
|
-
* @param
|
|
1120
|
-
* @
|
|
1412
|
+
* @param databaseUuid - Database UUID
|
|
1413
|
+
* @param backupUuid - Backup UUID
|
|
1414
|
+
* @returns Result with backup details or error
|
|
1121
1415
|
*/
|
|
1122
|
-
async
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1416
|
+
async getDatabaseBackup(
|
|
1417
|
+
databaseUuid: string,
|
|
1418
|
+
backupUuid: string,
|
|
1419
|
+
): Promise<Result<ICoolifyDatabaseBackup, Error>> {
|
|
1420
|
+
const result = await this.request<ICoolifyDatabaseBackup>(
|
|
1421
|
+
`/databases/${databaseUuid}/backups/${backupUuid}`,
|
|
1422
|
+
);
|
|
1423
|
+
if (result.error) return err(new Error(result.error));
|
|
1126
1424
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
count: number;
|
|
1130
|
-
deployments: ICoolifyDeployment[];
|
|
1131
|
-
}>(`/deployments/applications/${appUuid}`);
|
|
1425
|
+
return ok(result.data as ICoolifyDatabaseBackup);
|
|
1426
|
+
}
|
|
1132
1427
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1428
|
+
/**
|
|
1429
|
+
* Creates a database backup.
|
|
1430
|
+
*
|
|
1431
|
+
* @param databaseUuid - Database UUID
|
|
1432
|
+
* @param data - Backup creation data
|
|
1433
|
+
* @returns Result with created backup or error
|
|
1434
|
+
*/
|
|
1435
|
+
async createDatabaseBackup(
|
|
1436
|
+
databaseUuid: string,
|
|
1437
|
+
data: Record<string, unknown>,
|
|
1438
|
+
): Promise<Result<ICoolifyDatabaseBackup, Error>> {
|
|
1439
|
+
log.info(`Creating backup for database ${databaseUuid}`);
|
|
1440
|
+
|
|
1441
|
+
const result = await this.request<ICoolifyDatabaseBackup>(
|
|
1442
|
+
`/databases/${databaseUuid}/backups`,
|
|
1443
|
+
{ method: "POST", body: JSON.stringify(data) },
|
|
1444
|
+
);
|
|
1445
|
+
if (result.error) return err(new Error(result.error));
|
|
1137
1446
|
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1447
|
+
log.success("Database backup created");
|
|
1448
|
+
return ok(result.data as ICoolifyDatabaseBackup);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
/**
|
|
1452
|
+
* Updates a database backup.
|
|
1453
|
+
*
|
|
1454
|
+
* @param databaseUuid - Database UUID
|
|
1455
|
+
* @param backupUuid - Backup UUID
|
|
1456
|
+
* @param data - Update data
|
|
1457
|
+
* @returns Result indicating success or error
|
|
1458
|
+
*/
|
|
1459
|
+
async updateDatabaseBackup(
|
|
1460
|
+
databaseUuid: string,
|
|
1461
|
+
backupUuid: string,
|
|
1462
|
+
data: Record<string, unknown>,
|
|
1463
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1464
|
+
const result = await this.request<{ message: string }>(
|
|
1465
|
+
`/databases/${databaseUuid}/backups/${backupUuid}`,
|
|
1466
|
+
{ method: "PATCH", body: JSON.stringify(data) },
|
|
1467
|
+
);
|
|
1468
|
+
if (result.error) return err(new Error(result.error));
|
|
1469
|
+
|
|
1470
|
+
return ok(result.data || { message: "Backup updated" });
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
/**
|
|
1474
|
+
* Deletes a database backup.
|
|
1475
|
+
*
|
|
1476
|
+
* @param databaseUuid - Database UUID
|
|
1477
|
+
* @param backupUuid - Backup UUID
|
|
1478
|
+
* @returns Result indicating success or error
|
|
1479
|
+
*/
|
|
1480
|
+
async deleteDatabaseBackup(
|
|
1481
|
+
databaseUuid: string,
|
|
1482
|
+
backupUuid: string,
|
|
1483
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1484
|
+
const result = await this.request<{ message: string }>(
|
|
1485
|
+
`/databases/${databaseUuid}/backups/${backupUuid}`,
|
|
1486
|
+
{ method: "DELETE" },
|
|
1487
|
+
);
|
|
1488
|
+
if (result.error) return err(new Error(result.error));
|
|
1489
|
+
|
|
1490
|
+
return ok(result.data || { message: "Backup deleted" });
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
// ===========================================================================
|
|
1494
|
+
// Service endpoints
|
|
1495
|
+
// ===========================================================================
|
|
1496
|
+
|
|
1497
|
+
/**
|
|
1498
|
+
* Lists all services.
|
|
1499
|
+
*
|
|
1500
|
+
* @param page - Optional page number
|
|
1501
|
+
* @param perPage - Optional items per page
|
|
1502
|
+
* @returns Result with services list or error
|
|
1503
|
+
*/
|
|
1504
|
+
async listServices(
|
|
1505
|
+
page?: number,
|
|
1506
|
+
perPage?: number,
|
|
1507
|
+
): Promise<Result<ICoolifyServiceType[], Error>> {
|
|
1508
|
+
log.info("Listing services");
|
|
1509
|
+
|
|
1510
|
+
let endpoint = "/services";
|
|
1511
|
+
const params = new URLSearchParams();
|
|
1512
|
+
if (page) params.set("page", page.toString());
|
|
1513
|
+
if (perPage) params.set("per_page", perPage.toString());
|
|
1514
|
+
if (params.toString()) endpoint += `?${params.toString()}`;
|
|
1515
|
+
|
|
1516
|
+
const result = await this.request<ICoolifyServiceType[]>(endpoint);
|
|
1517
|
+
if (result.error) return err(new Error(result.error));
|
|
1518
|
+
|
|
1519
|
+
log.success(`Listed ${result.data?.length || 0} services`);
|
|
1520
|
+
return ok(result.data || []);
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
* Gets details of a specific service.
|
|
1525
|
+
*
|
|
1526
|
+
* @param uuid - Service UUID
|
|
1527
|
+
* @returns Result with service details or error
|
|
1528
|
+
*/
|
|
1529
|
+
async getService(uuid: string): Promise<Result<ICoolifyServiceType, Error>> {
|
|
1530
|
+
log.info(`Getting service ${uuid}`);
|
|
1531
|
+
|
|
1532
|
+
const result = await this.request<ICoolifyServiceType>(`/services/${uuid}`);
|
|
1533
|
+
if (result.error) return err(new Error(result.error));
|
|
1534
|
+
|
|
1535
|
+
return ok(result.data as ICoolifyServiceType);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/**
|
|
1539
|
+
* Creates a new service.
|
|
1540
|
+
*
|
|
1541
|
+
* @param data - Service creation data
|
|
1542
|
+
* @returns Result with created service or error
|
|
1543
|
+
*/
|
|
1544
|
+
async createService(
|
|
1545
|
+
data: Record<string, unknown>,
|
|
1546
|
+
): Promise<Result<{ uuid: string }, Error>> {
|
|
1547
|
+
log.info("Creating service");
|
|
1548
|
+
|
|
1549
|
+
const result = await this.request<{ uuid: string }>("/services", {
|
|
1550
|
+
method: "POST",
|
|
1551
|
+
body: JSON.stringify(data),
|
|
1552
|
+
});
|
|
1553
|
+
if (result.error) return err(new Error(result.error));
|
|
1554
|
+
|
|
1555
|
+
log.success(`Service created: ${result.data?.uuid}`);
|
|
1556
|
+
return ok(result.data!);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
/**
|
|
1560
|
+
* Updates a service configuration.
|
|
1561
|
+
*
|
|
1562
|
+
* @param uuid - Service UUID
|
|
1563
|
+
* @param data - Update data
|
|
1564
|
+
* @returns Result with updated service or error
|
|
1565
|
+
*/
|
|
1566
|
+
async updateService(
|
|
1567
|
+
uuid: string,
|
|
1568
|
+
data: Record<string, unknown>,
|
|
1569
|
+
): Promise<Result<ICoolifyServiceType, Error>> {
|
|
1570
|
+
log.info(`Updating service ${uuid}`);
|
|
1571
|
+
|
|
1572
|
+
const result = await this.request<ICoolifyServiceType>(
|
|
1573
|
+
`/services/${uuid}`,
|
|
1574
|
+
{
|
|
1575
|
+
method: "PATCH",
|
|
1576
|
+
body: JSON.stringify(data),
|
|
1577
|
+
},
|
|
1578
|
+
);
|
|
1579
|
+
if (result.error) return err(new Error(result.error));
|
|
1580
|
+
|
|
1581
|
+
log.success(`Service updated: ${uuid}`);
|
|
1582
|
+
return ok(result.data as ICoolifyServiceType);
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* Deletes a service.
|
|
1587
|
+
*
|
|
1588
|
+
* @param uuid - Service UUID
|
|
1589
|
+
* @param options - Delete options for cascade deletion
|
|
1590
|
+
* @returns Result indicating success or error
|
|
1591
|
+
*/
|
|
1592
|
+
async deleteService(
|
|
1593
|
+
uuid: string,
|
|
1594
|
+
options?: {
|
|
1595
|
+
deleteConfigurations?: boolean;
|
|
1596
|
+
deleteVolumes?: boolean;
|
|
1597
|
+
dockerCleanup?: boolean;
|
|
1598
|
+
deleteConnectedNetworks?: boolean;
|
|
1599
|
+
},
|
|
1600
|
+
): Promise<Result<ICoolifyDeleteResult, Error>> {
|
|
1601
|
+
log.info(`Deleting service ${uuid}`);
|
|
1602
|
+
|
|
1603
|
+
const params = new URLSearchParams();
|
|
1604
|
+
if (options?.deleteConfigurations)
|
|
1605
|
+
params.set("delete_configurations", "true");
|
|
1606
|
+
if (options?.deleteVolumes) params.set("delete_volumes", "true");
|
|
1607
|
+
if (options?.dockerCleanup) params.set("docker_cleanup", "true");
|
|
1608
|
+
if (options?.deleteConnectedNetworks)
|
|
1609
|
+
params.set("delete_connected_networks", "true");
|
|
1610
|
+
|
|
1611
|
+
const queryString = params.toString();
|
|
1612
|
+
const endpoint = `/services/${uuid}${queryString ? `?${queryString}` : ""}`;
|
|
1613
|
+
|
|
1614
|
+
const result = await this.request<ICoolifyDeleteResult>(endpoint, {
|
|
1615
|
+
method: "DELETE",
|
|
1616
|
+
});
|
|
1617
|
+
if (result.error) return err(new Error(result.error));
|
|
1618
|
+
|
|
1619
|
+
log.success(`Service deleted: ${uuid}`);
|
|
1620
|
+
return ok({ success: true, message: "Service deleted" });
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
/**
|
|
1624
|
+
* Starts a service.
|
|
1625
|
+
* Note: Coolify API uses GET for service start/stop/restart.
|
|
1626
|
+
*
|
|
1627
|
+
* @param uuid - Service UUID
|
|
1628
|
+
* @returns Result indicating success or error
|
|
1629
|
+
*/
|
|
1630
|
+
async startService(
|
|
1631
|
+
uuid: string,
|
|
1632
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1633
|
+
log.info(`Starting service ${uuid}`);
|
|
1634
|
+
|
|
1635
|
+
const result = await this.request<{ message: string }>(
|
|
1636
|
+
`/services/${uuid}/start`,
|
|
1637
|
+
{ method: "GET" },
|
|
1638
|
+
);
|
|
1639
|
+
if (result.error) return err(new Error(result.error));
|
|
1640
|
+
|
|
1641
|
+
log.success(`Service started: ${uuid}`);
|
|
1642
|
+
return ok(result.data || { message: "Service started" });
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
/**
|
|
1646
|
+
* Stops a service.
|
|
1647
|
+
* Note: Coolify API uses GET for service start/stop/restart.
|
|
1648
|
+
*
|
|
1649
|
+
* @param uuid - Service UUID
|
|
1650
|
+
* @returns Result indicating success or error
|
|
1651
|
+
*/
|
|
1652
|
+
async stopService(uuid: string): Promise<Result<{ message: string }, Error>> {
|
|
1653
|
+
log.info(`Stopping service ${uuid}`);
|
|
1654
|
+
|
|
1655
|
+
const result = await this.request<{ message: string }>(
|
|
1656
|
+
`/services/${uuid}/stop`,
|
|
1657
|
+
{ method: "GET" },
|
|
1658
|
+
);
|
|
1659
|
+
if (result.error) return err(new Error(result.error));
|
|
1660
|
+
|
|
1661
|
+
log.success(`Service stopped: ${uuid}`);
|
|
1662
|
+
return ok(result.data || { message: "Service stopped" });
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* Restarts a service.
|
|
1667
|
+
* Note: Coolify API uses GET for service start/stop/restart.
|
|
1668
|
+
*
|
|
1669
|
+
* @param uuid - Service UUID
|
|
1670
|
+
* @returns Result indicating success or error
|
|
1671
|
+
*/
|
|
1672
|
+
async restartService(
|
|
1673
|
+
uuid: string,
|
|
1674
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1675
|
+
log.info(`Restarting service ${uuid}`);
|
|
1676
|
+
|
|
1677
|
+
const result = await this.request<{ message: string }>(
|
|
1678
|
+
`/services/${uuid}/restart`,
|
|
1679
|
+
{ method: "GET" },
|
|
1680
|
+
);
|
|
1681
|
+
if (result.error) return err(new Error(result.error));
|
|
1682
|
+
|
|
1683
|
+
log.success(`Service restarted: ${uuid}`);
|
|
1684
|
+
return ok(result.data || { message: "Service restarted" });
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
/**
|
|
1688
|
+
* Lists environment variables for a service.
|
|
1689
|
+
*
|
|
1690
|
+
* @param uuid - Service UUID
|
|
1691
|
+
* @returns Result with env vars list or error
|
|
1692
|
+
*/
|
|
1693
|
+
async listServiceEnvVars(
|
|
1694
|
+
uuid: string,
|
|
1695
|
+
): Promise<Result<ICoolifyEnvVar[], Error>> {
|
|
1696
|
+
const result = await this.request<ICoolifyEnvVar[]>(
|
|
1697
|
+
`/services/${uuid}/envs`,
|
|
1698
|
+
);
|
|
1699
|
+
if (result.error) return err(new Error(result.error));
|
|
1700
|
+
|
|
1701
|
+
return ok(result.data || []);
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
/**
|
|
1705
|
+
* Creates an environment variable for a service.
|
|
1706
|
+
*
|
|
1707
|
+
* @param uuid - Service UUID
|
|
1708
|
+
* @param data - Env var data (key, value, is_preview)
|
|
1709
|
+
* @returns Result with created env var UUID or error
|
|
1710
|
+
*/
|
|
1711
|
+
async createServiceEnvVar(
|
|
1712
|
+
uuid: string,
|
|
1713
|
+
data: { key: string; value: string; is_preview?: boolean },
|
|
1714
|
+
): Promise<Result<{ uuid: string }, Error>> {
|
|
1715
|
+
const result = await this.request<{ uuid: string }>(
|
|
1716
|
+
`/services/${uuid}/envs`,
|
|
1717
|
+
{ method: "POST", body: JSON.stringify(data) },
|
|
1718
|
+
);
|
|
1719
|
+
if (result.error) return err(new Error(result.error));
|
|
1720
|
+
|
|
1721
|
+
return ok(result.data!);
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// ===========================================================================
|
|
1725
|
+
// Additional Server endpoints
|
|
1726
|
+
// ===========================================================================
|
|
1727
|
+
|
|
1728
|
+
/**
|
|
1729
|
+
* Gets resources deployed on a server.
|
|
1730
|
+
*
|
|
1731
|
+
* @param serverUuid - Server UUID
|
|
1732
|
+
* @returns Result with server resources or error
|
|
1733
|
+
*/
|
|
1734
|
+
async getServerResources(
|
|
1735
|
+
serverUuid: string,
|
|
1736
|
+
): Promise<Result<ICoolifyServerResource[], Error>> {
|
|
1737
|
+
log.info(`Getting resources for server ${serverUuid}`);
|
|
1738
|
+
|
|
1739
|
+
const result = await this.request<ICoolifyServerResource[]>(
|
|
1740
|
+
`/servers/${serverUuid}/resources`,
|
|
1741
|
+
);
|
|
1742
|
+
if (result.error) return err(new Error(result.error));
|
|
1743
|
+
|
|
1744
|
+
return ok(result.data || []);
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
/**
|
|
1748
|
+
* Gets domains configured on a server.
|
|
1749
|
+
*
|
|
1750
|
+
* @param serverUuid - Server UUID
|
|
1751
|
+
* @returns Result with server domains or error
|
|
1752
|
+
*/
|
|
1753
|
+
async getServerDomains(
|
|
1754
|
+
serverUuid: string,
|
|
1755
|
+
): Promise<Result<ICoolifyServerDomain[], Error>> {
|
|
1756
|
+
log.info(`Getting domains for server ${serverUuid}`);
|
|
1757
|
+
|
|
1758
|
+
const result = await this.request<ICoolifyServerDomain[]>(
|
|
1759
|
+
`/servers/${serverUuid}/domains`,
|
|
1760
|
+
);
|
|
1761
|
+
if (result.error) return err(new Error(result.error));
|
|
1762
|
+
|
|
1763
|
+
return ok(result.data || []);
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
/**
|
|
1767
|
+
* Validates a server connection.
|
|
1768
|
+
*
|
|
1769
|
+
* @param serverUuid - Server UUID
|
|
1770
|
+
* @returns Result with validation status or error
|
|
1771
|
+
*/
|
|
1772
|
+
async validateServer(
|
|
1773
|
+
serverUuid: string,
|
|
1774
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1775
|
+
log.info(`Validating server ${serverUuid}`);
|
|
1776
|
+
|
|
1777
|
+
const result = await this.request<{ message: string }>(
|
|
1778
|
+
`/servers/${serverUuid}/validate`,
|
|
1779
|
+
);
|
|
1780
|
+
if (result.error) return err(new Error(result.error));
|
|
1781
|
+
|
|
1782
|
+
return ok(result.data || { message: "Server validated" });
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
/**
|
|
1786
|
+
* Creates a new server.
|
|
1787
|
+
*
|
|
1788
|
+
* @param data - Server creation data
|
|
1789
|
+
* @returns Result with created server UUID or error
|
|
1790
|
+
*/
|
|
1791
|
+
async createServer(
|
|
1792
|
+
data: Record<string, unknown>,
|
|
1793
|
+
): Promise<Result<{ uuid: string }, Error>> {
|
|
1794
|
+
log.info("Creating server");
|
|
1795
|
+
|
|
1796
|
+
const result = await this.request<{ uuid: string }>("/servers", {
|
|
1797
|
+
method: "POST",
|
|
1798
|
+
body: JSON.stringify(data),
|
|
1799
|
+
});
|
|
1800
|
+
if (result.error) return err(new Error(result.error));
|
|
1801
|
+
|
|
1802
|
+
log.success(`Server created: ${result.data?.uuid}`);
|
|
1803
|
+
return ok(result.data!);
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
/**
|
|
1807
|
+
* Deletes a server.
|
|
1808
|
+
*
|
|
1809
|
+
* @param serverUuid - Server UUID
|
|
1810
|
+
* @returns Result indicating success or error
|
|
1811
|
+
*/
|
|
1812
|
+
async deleteServer(
|
|
1813
|
+
serverUuid: string,
|
|
1814
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1815
|
+
log.info(`Deleting server ${serverUuid}`);
|
|
1816
|
+
|
|
1817
|
+
const result = await this.request<{ message: string }>(
|
|
1818
|
+
`/servers/${serverUuid}`,
|
|
1819
|
+
{ method: "DELETE" },
|
|
1820
|
+
);
|
|
1821
|
+
if (result.error) return err(new Error(result.error));
|
|
1822
|
+
|
|
1823
|
+
log.success(`Server deleted: ${serverUuid}`);
|
|
1824
|
+
return ok(result.data || { message: "Server deleted" });
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
// ===========================================================================
|
|
1828
|
+
// Additional Project endpoints
|
|
1829
|
+
// ===========================================================================
|
|
1830
|
+
|
|
1831
|
+
/**
|
|
1832
|
+
* Updates a project.
|
|
1833
|
+
*
|
|
1834
|
+
* @param uuid - Project UUID
|
|
1835
|
+
* @param data - Update data (name, description)
|
|
1836
|
+
* @returns Result with updated project or error
|
|
1837
|
+
*/
|
|
1838
|
+
async updateProject(
|
|
1839
|
+
uuid: string,
|
|
1840
|
+
data: { name?: string; description?: string },
|
|
1841
|
+
): Promise<Result<ICoolifyProject, Error>> {
|
|
1842
|
+
log.info(`Updating project ${uuid}`);
|
|
1843
|
+
|
|
1844
|
+
const result = await this.request<ICoolifyProject>(`/projects/${uuid}`, {
|
|
1845
|
+
method: "PATCH",
|
|
1846
|
+
body: JSON.stringify(data),
|
|
1847
|
+
});
|
|
1848
|
+
if (result.error) return err(new Error(result.error));
|
|
1849
|
+
|
|
1850
|
+
log.success(`Project updated: ${uuid}`);
|
|
1851
|
+
return ok(result.data as ICoolifyProject);
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
/**
|
|
1855
|
+
* Deletes a project.
|
|
1856
|
+
*
|
|
1857
|
+
* @param uuid - Project UUID
|
|
1858
|
+
* @returns Result indicating success or error
|
|
1859
|
+
*/
|
|
1860
|
+
async deleteProject(
|
|
1861
|
+
uuid: string,
|
|
1862
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1863
|
+
log.info(`Deleting project ${uuid}`);
|
|
1864
|
+
|
|
1865
|
+
const result = await this.request<{ message: string }>(
|
|
1866
|
+
`/projects/${uuid}`,
|
|
1867
|
+
{ method: "DELETE" },
|
|
1868
|
+
);
|
|
1869
|
+
if (result.error) return err(new Error(result.error));
|
|
1870
|
+
|
|
1871
|
+
log.success(`Project deleted: ${uuid}`);
|
|
1872
|
+
return ok(result.data || { message: "Project deleted" });
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
/**
|
|
1876
|
+
* Creates a new environment within a project.
|
|
1877
|
+
*
|
|
1878
|
+
* @param projectUuid - Project UUID
|
|
1879
|
+
* @param data - Environment creation data (name, description)
|
|
1880
|
+
* @returns Result with created environment UUID or error
|
|
1881
|
+
*/
|
|
1882
|
+
async createProjectEnvironment(
|
|
1883
|
+
projectUuid: string,
|
|
1884
|
+
data: { name: string; description?: string },
|
|
1885
|
+
): Promise<Result<{ uuid: string }, Error>> {
|
|
1886
|
+
log.info(`Creating environment in project ${projectUuid}`);
|
|
1887
|
+
|
|
1888
|
+
const result = await this.request<{ uuid: string }>(
|
|
1889
|
+
`/projects/${projectUuid}/environments`,
|
|
1890
|
+
{ method: "POST", body: JSON.stringify(data) },
|
|
1891
|
+
);
|
|
1892
|
+
if (result.error) return err(new Error(result.error));
|
|
1893
|
+
|
|
1894
|
+
log.success("Environment created");
|
|
1895
|
+
return ok(result.data!);
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// ===========================================================================
|
|
1899
|
+
// Additional Team endpoints
|
|
1900
|
+
// ===========================================================================
|
|
1901
|
+
|
|
1902
|
+
/**
|
|
1903
|
+
* Gets the current team.
|
|
1904
|
+
*
|
|
1905
|
+
* @returns Result with current team or error
|
|
1906
|
+
*/
|
|
1907
|
+
async getCurrentTeam(): Promise<Result<ICoolifyTeam, Error>> {
|
|
1908
|
+
log.info("Getting current team");
|
|
1909
|
+
|
|
1910
|
+
const result = await this.request<ICoolifyTeam>("/teams/current");
|
|
1911
|
+
if (result.error) return err(new Error(result.error));
|
|
1912
|
+
|
|
1913
|
+
return ok(result.data as ICoolifyTeam);
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
/**
|
|
1917
|
+
* Gets a specific team by ID.
|
|
1918
|
+
*
|
|
1919
|
+
* @param id - Team ID
|
|
1920
|
+
* @returns Result with team details or error
|
|
1921
|
+
*/
|
|
1922
|
+
async getTeam(id: number): Promise<Result<ICoolifyTeam, Error>> {
|
|
1923
|
+
log.info(`Getting team ${id}`);
|
|
1924
|
+
|
|
1925
|
+
const result = await this.request<ICoolifyTeam>(`/teams/${id}`);
|
|
1926
|
+
if (result.error) return err(new Error(result.error));
|
|
1927
|
+
|
|
1928
|
+
return ok(result.data as ICoolifyTeam);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
/**
|
|
1932
|
+
* Gets members of a specific team.
|
|
1933
|
+
*
|
|
1934
|
+
* @param id - Team ID
|
|
1935
|
+
* @returns Result with team members or error
|
|
1936
|
+
*/
|
|
1937
|
+
async getTeamMembers(
|
|
1938
|
+
id: number,
|
|
1939
|
+
): Promise<
|
|
1940
|
+
Result<Array<{ id: number; name: string; email: string }>, Error>
|
|
1941
|
+
> {
|
|
1942
|
+
log.info(`Getting members for team ${id}`);
|
|
1943
|
+
|
|
1944
|
+
const result = await this.request<
|
|
1945
|
+
Array<{ id: number; name: string; email: string }>
|
|
1946
|
+
>(`/teams/${id}/members`);
|
|
1947
|
+
if (result.error) return err(new Error(result.error));
|
|
1948
|
+
|
|
1949
|
+
return ok(result.data || []);
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
// ===========================================================================
|
|
1953
|
+
// Deployment Control
|
|
1954
|
+
// ===========================================================================
|
|
1955
|
+
|
|
1956
|
+
/**
|
|
1957
|
+
* Cancels a deployment.
|
|
1958
|
+
*
|
|
1959
|
+
* @param deploymentUuid - Deployment UUID
|
|
1960
|
+
* @returns Result indicating success or error
|
|
1961
|
+
*/
|
|
1962
|
+
async cancelDeployment(
|
|
1963
|
+
deploymentUuid: string,
|
|
1964
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
1965
|
+
log.info(`Cancelling deployment ${deploymentUuid}`);
|
|
1966
|
+
|
|
1967
|
+
const result = await this.request<{ message: string }>(
|
|
1968
|
+
`/deployments/${deploymentUuid}/cancel`,
|
|
1969
|
+
{ method: "POST" },
|
|
1970
|
+
);
|
|
1971
|
+
if (result.error) return err(new Error(result.error));
|
|
1972
|
+
|
|
1973
|
+
log.success(`Deployment cancelled: ${deploymentUuid}`);
|
|
1974
|
+
return ok(result.data || { message: "Deployment cancelled" });
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
// ===========================================================================
|
|
1978
|
+
// SSH / Private Key endpoints
|
|
1979
|
+
// ===========================================================================
|
|
1980
|
+
|
|
1981
|
+
/**
|
|
1982
|
+
* Lists all private keys.
|
|
1983
|
+
*
|
|
1984
|
+
* @returns Result with private keys list or error
|
|
1985
|
+
*/
|
|
1986
|
+
async listPrivateKeys(): Promise<Result<ICoolifyPrivateKey[], Error>> {
|
|
1987
|
+
log.info("Listing private keys");
|
|
1988
|
+
|
|
1989
|
+
const result = await this.request<ICoolifyPrivateKey[]>("/security/keys");
|
|
1990
|
+
if (result.error) return err(new Error(result.error));
|
|
1991
|
+
|
|
1992
|
+
return ok(result.data || []);
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
/**
|
|
1996
|
+
* Gets a specific private key.
|
|
1997
|
+
*
|
|
1998
|
+
* @param uuid - Private key UUID
|
|
1999
|
+
* @returns Result with private key details or error
|
|
2000
|
+
*/
|
|
2001
|
+
async getPrivateKey(
|
|
2002
|
+
uuid: string,
|
|
2003
|
+
): Promise<Result<ICoolifyPrivateKey, Error>> {
|
|
2004
|
+
const result = await this.request<ICoolifyPrivateKey>(
|
|
2005
|
+
`/security/keys/${uuid}`,
|
|
2006
|
+
);
|
|
2007
|
+
if (result.error) return err(new Error(result.error));
|
|
2008
|
+
|
|
2009
|
+
return ok(result.data as ICoolifyPrivateKey);
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
/**
|
|
2013
|
+
* Creates a new private key.
|
|
2014
|
+
*
|
|
2015
|
+
* @param data - Key creation data (name, private_key, description)
|
|
2016
|
+
* @returns Result with created key UUID or error
|
|
2017
|
+
*/
|
|
2018
|
+
async createPrivateKey(data: {
|
|
2019
|
+
name: string;
|
|
2020
|
+
private_key: string;
|
|
2021
|
+
description?: string;
|
|
2022
|
+
}): Promise<Result<{ uuid: string }, Error>> {
|
|
2023
|
+
log.info("Creating private key");
|
|
2024
|
+
|
|
2025
|
+
const result = await this.request<{ uuid: string }>("/security/keys", {
|
|
2026
|
+
method: "POST",
|
|
2027
|
+
body: JSON.stringify(data),
|
|
2028
|
+
});
|
|
2029
|
+
if (result.error) return err(new Error(result.error));
|
|
2030
|
+
|
|
2031
|
+
log.success(`Private key created: ${result.data?.uuid}`);
|
|
2032
|
+
return ok(result.data!);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
/**
|
|
2036
|
+
* Updates a private key.
|
|
2037
|
+
*
|
|
2038
|
+
* @param uuid - Private key UUID
|
|
2039
|
+
* @param data - Update data
|
|
2040
|
+
* @returns Result with updated key or error
|
|
2041
|
+
*/
|
|
2042
|
+
async updatePrivateKey(
|
|
2043
|
+
uuid: string,
|
|
2044
|
+
data: { name?: string; private_key?: string; description?: string },
|
|
2045
|
+
): Promise<Result<ICoolifyPrivateKey, Error>> {
|
|
2046
|
+
const result = await this.request<ICoolifyPrivateKey>(
|
|
2047
|
+
`/security/keys/${uuid}`,
|
|
2048
|
+
{ method: "PATCH", body: JSON.stringify(data) },
|
|
2049
|
+
);
|
|
2050
|
+
if (result.error) return err(new Error(result.error));
|
|
2051
|
+
|
|
2052
|
+
return ok(result.data as ICoolifyPrivateKey);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
/**
|
|
2056
|
+
* Deletes a private key.
|
|
2057
|
+
*
|
|
2058
|
+
* @param uuid - Private key UUID
|
|
2059
|
+
* @returns Result indicating success or error
|
|
2060
|
+
*/
|
|
2061
|
+
async deletePrivateKey(
|
|
2062
|
+
uuid: string,
|
|
2063
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
2064
|
+
log.info(`Deleting private key ${uuid}`);
|
|
2065
|
+
|
|
2066
|
+
const result = await this.request<{ message: string }>(
|
|
2067
|
+
`/security/keys/${uuid}`,
|
|
2068
|
+
{ method: "DELETE" },
|
|
2069
|
+
);
|
|
2070
|
+
if (result.error) return err(new Error(result.error));
|
|
2071
|
+
|
|
2072
|
+
log.success(`Private key deleted: ${uuid}`);
|
|
2073
|
+
return ok(result.data || { message: "Private key deleted" });
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
// ===========================================================================
|
|
2077
|
+
// GitHub App endpoints (additional)
|
|
2078
|
+
// ===========================================================================
|
|
2079
|
+
|
|
2080
|
+
/**
|
|
2081
|
+
* Creates a GitHub App configuration.
|
|
2082
|
+
*
|
|
2083
|
+
* @param data - GitHub App creation data
|
|
2084
|
+
* @returns Result with created app or error
|
|
2085
|
+
*/
|
|
2086
|
+
async createGitHubApp(
|
|
2087
|
+
data: Record<string, unknown>,
|
|
2088
|
+
): Promise<Result<{ id: number; uuid: string }, Error>> {
|
|
2089
|
+
log.info("Creating GitHub App");
|
|
2090
|
+
|
|
2091
|
+
const result = await this.request<{ id: number; uuid: string }>(
|
|
2092
|
+
"/github-apps",
|
|
2093
|
+
{ method: "POST", body: JSON.stringify(data) },
|
|
2094
|
+
);
|
|
2095
|
+
if (result.error) return err(new Error(result.error));
|
|
2096
|
+
|
|
2097
|
+
return ok(result.data!);
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/**
|
|
2101
|
+
* Updates a GitHub App configuration.
|
|
2102
|
+
*
|
|
2103
|
+
* @param id - GitHub App ID
|
|
2104
|
+
* @param data - Update data
|
|
2105
|
+
* @returns Result with updated app or error
|
|
2106
|
+
*/
|
|
2107
|
+
async updateGitHubApp(
|
|
2108
|
+
id: number,
|
|
2109
|
+
data: Record<string, unknown>,
|
|
2110
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
2111
|
+
const result = await this.request<{ message: string }>(
|
|
2112
|
+
`/github-apps/${id}`,
|
|
2113
|
+
{ method: "PATCH", body: JSON.stringify(data) },
|
|
2114
|
+
);
|
|
2115
|
+
if (result.error) return err(new Error(result.error));
|
|
2116
|
+
|
|
2117
|
+
return ok(result.data || { message: "GitHub App updated" });
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
/**
|
|
2121
|
+
* Deletes a GitHub App configuration.
|
|
2122
|
+
*
|
|
2123
|
+
* @param id - GitHub App ID
|
|
2124
|
+
* @returns Result indicating success or error
|
|
2125
|
+
*/
|
|
2126
|
+
async deleteGitHubApp(
|
|
2127
|
+
id: number,
|
|
2128
|
+
): Promise<Result<{ message: string }, Error>> {
|
|
2129
|
+
log.info(`Deleting GitHub App ${id}`);
|
|
2130
|
+
|
|
2131
|
+
const result = await this.request<{ message: string }>(
|
|
2132
|
+
`/github-apps/${id}`,
|
|
2133
|
+
{ method: "DELETE" },
|
|
2134
|
+
);
|
|
2135
|
+
if (result.error) return err(new Error(result.error));
|
|
2136
|
+
|
|
2137
|
+
return ok(result.data || { message: "GitHub App deleted" });
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
/**
|
|
2141
|
+
* Lists all active and queued deployments.
|
|
2142
|
+
*
|
|
2143
|
+
* @param page - Optional page number for pagination
|
|
2144
|
+
* @param perPage - Optional number of items per page
|
|
2145
|
+
* @returns Result with deployments list or error
|
|
2146
|
+
*/
|
|
2147
|
+
async listDeployments(
|
|
2148
|
+
page?: number,
|
|
2149
|
+
perPage?: number,
|
|
2150
|
+
): Promise<Result<ICoolifyDeployment[], Error>> {
|
|
2151
|
+
log.info("Listing active deployments");
|
|
2152
|
+
|
|
2153
|
+
let endpoint = "/deployments";
|
|
2154
|
+
const params = new URLSearchParams();
|
|
2155
|
+
if (page) params.set("page", page.toString());
|
|
2156
|
+
if (perPage) params.set("per_page", perPage.toString());
|
|
2157
|
+
if (params.toString()) {
|
|
2158
|
+
endpoint += `?${params.toString()}`;
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
const result = await this.request<ICoolifyDeployment[]>(endpoint);
|
|
2162
|
+
|
|
2163
|
+
if (result.error) {
|
|
2164
|
+
log.error(`Failed to list deployments: ${result.error}`);
|
|
2165
|
+
return err(new Error(result.error));
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
log.success(`Listed ${result.data?.length || 0} active deployments`);
|
|
2169
|
+
return ok(result.data || []);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
/**
|
|
2173
|
+
* Gets detailed information about a specific deployment.
|
|
2174
|
+
*
|
|
2175
|
+
* @param deploymentUuid - Deployment UUID
|
|
2176
|
+
* @returns Result with deployment details or error
|
|
2177
|
+
*/
|
|
2178
|
+
async getDeployment(
|
|
2179
|
+
deploymentUuid: string,
|
|
2180
|
+
): Promise<Result<ICoolifyDeployment, Error>> {
|
|
2181
|
+
log.info(`Getting deployment details for ${deploymentUuid}`);
|
|
2182
|
+
|
|
2183
|
+
const result = await this.request<ICoolifyDeployment>(
|
|
2184
|
+
`/deployments/${deploymentUuid}`,
|
|
2185
|
+
);
|
|
2186
|
+
|
|
2187
|
+
if (result.error) {
|
|
2188
|
+
log.error(`Failed to get deployment: ${result.error}`);
|
|
2189
|
+
return err(new Error(result.error));
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
log.success(`Deployment details retrieved: ${deploymentUuid}`);
|
|
2193
|
+
return ok(result.data as ICoolifyDeployment);
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
/**
|
|
2197
|
+
* Gets logs for a specific deployment.
|
|
2198
|
+
*
|
|
2199
|
+
* @param deploymentUuid - Deployment UUID
|
|
2200
|
+
* @returns Result with deployment status and logs or error
|
|
2201
|
+
*/
|
|
2202
|
+
async getDeploymentLogs(
|
|
2203
|
+
deploymentUuid: string,
|
|
2204
|
+
): Promise<
|
|
2205
|
+
Result<{ status: string; logs: string; deployment_uuid: string }, Error>
|
|
2206
|
+
> {
|
|
2207
|
+
log.info(`Getting deployment logs for ${deploymentUuid}`);
|
|
2208
|
+
|
|
2209
|
+
const result = await this.request<{
|
|
2210
|
+
status: string;
|
|
2211
|
+
logs: string;
|
|
2212
|
+
deployment_uuid: string;
|
|
2213
|
+
}>(`/deployments/${deploymentUuid}`);
|
|
2214
|
+
|
|
2215
|
+
if (result.error) {
|
|
2216
|
+
log.error(`Failed to get deployment logs: ${result.error}`);
|
|
2217
|
+
return err(new Error(result.error));
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
log.success(`Deployment logs retrieved: ${deploymentUuid}`);
|
|
2221
|
+
return ok({
|
|
2222
|
+
status: result.data?.status || "unknown",
|
|
2223
|
+
logs: result.data?.logs || "",
|
|
2224
|
+
deployment_uuid: result.data?.deployment_uuid || deploymentUuid,
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
/**
|
|
2229
|
+
* Gets deployment history for a specific application.
|
|
2230
|
+
*
|
|
2231
|
+
* @param appUuid - Application UUID
|
|
2232
|
+
* @param skip - Number of deployments to skip
|
|
2233
|
+
* @param take - Number of deployments to return
|
|
2234
|
+
* @returns Result with deployments list or error
|
|
2235
|
+
*/
|
|
2236
|
+
async getApplicationDeployments(
|
|
2237
|
+
appUuid: string,
|
|
2238
|
+
skip: number = 0,
|
|
2239
|
+
take: number = 10,
|
|
2240
|
+
): Promise<Result<ICoolifyDeployment[], Error>> {
|
|
2241
|
+
log.info(`Getting deployments for application ${appUuid}`);
|
|
2242
|
+
|
|
2243
|
+
const params = new URLSearchParams();
|
|
2244
|
+
if (skip > 0) params.set("skip", skip.toString());
|
|
2245
|
+
if (take !== 10) params.set("take", take.toString());
|
|
2246
|
+
|
|
2247
|
+
const endpoint = `/applications/${appUuid}/deployments${params.toString() ? `?${params.toString()}` : ""}`;
|
|
2248
|
+
const result = await this.request<{
|
|
2249
|
+
count: number;
|
|
2250
|
+
deployments: ICoolifyDeployment[];
|
|
2251
|
+
}>(endpoint);
|
|
2252
|
+
|
|
2253
|
+
if (result.error) {
|
|
2254
|
+
log.error(`Failed to get application deployments: ${result.error}`);
|
|
2255
|
+
return err(new Error(result.error));
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
const deployments = result.data?.deployments || [];
|
|
2259
|
+
log.success(`Retrieved ${deployments.length} deployments for ${appUuid}`);
|
|
2260
|
+
return ok(deployments);
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
/**
|
|
2264
|
+
* Lists deployments for a specific application.
|
|
2265
|
+
*
|
|
2266
|
+
* Uses the /deployments/applications/{appUuid} endpoint which returns
|
|
2267
|
+
* all deployments (active, queued, and completed) for a single application.
|
|
2268
|
+
* This differs from listDeployments() which returns ALL deployments globally.
|
|
2269
|
+
*
|
|
2270
|
+
* @param appUuid - Application UUID
|
|
2271
|
+
* @returns Result with deployments list or error
|
|
2272
|
+
*/
|
|
2273
|
+
async listApplicationDeployments(
|
|
2274
|
+
appUuid: string,
|
|
2275
|
+
): Promise<Result<ICoolifyDeployment[], Error>> {
|
|
2276
|
+
log.info(`Listing deployments for application ${appUuid}`);
|
|
2277
|
+
|
|
2278
|
+
// API returns { count: number, deployments: ICoolifyDeployment[] }
|
|
2279
|
+
const result = await this.request<{
|
|
2280
|
+
count: number;
|
|
2281
|
+
deployments: ICoolifyDeployment[];
|
|
2282
|
+
}>(`/deployments/applications/${appUuid}`);
|
|
2283
|
+
|
|
2284
|
+
if (result.error) {
|
|
2285
|
+
log.error(`Failed to list application deployments: ${result.error}`);
|
|
2286
|
+
return err(new Error(result.error));
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
const deployments = result.data?.deployments || [];
|
|
2290
|
+
log.success(`Listed ${deployments.length} deployments for ${appUuid}`);
|
|
2291
|
+
return ok(deployments);
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
// ===========================================================================
|
|
2295
|
+
// Smart Resolution Helpers
|
|
2296
|
+
// ===========================================================================
|
|
2297
|
+
|
|
2298
|
+
/**
|
|
2299
|
+
* Resolves an application by UUID, name, or domain (FQDN).
|
|
2300
|
+
*
|
|
2301
|
+
* @param query - UUID, name, or domain to search for
|
|
2302
|
+
* @returns Result with application or error
|
|
2303
|
+
*/
|
|
2304
|
+
async resolveApplication(
|
|
2305
|
+
query: string,
|
|
2306
|
+
): Promise<Result<ICoolifyApplication, Error>> {
|
|
2307
|
+
log.info(`Resolving application: ${query}`);
|
|
2308
|
+
|
|
2309
|
+
// If it looks like a UUID, try direct lookup first
|
|
2310
|
+
if (this.isLikelyUuid(query)) {
|
|
2311
|
+
const apps = await this.listApplications();
|
|
2312
|
+
if (isErr(apps)) return err(apps.error);
|
|
2313
|
+
const match = apps.value.find((a) => a.uuid === query);
|
|
2314
|
+
if (match) return ok(match);
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
// Search by name or domain
|
|
2318
|
+
const apps = await this.listApplications();
|
|
2319
|
+
if (isErr(apps)) return err(apps.error);
|
|
2320
|
+
|
|
2321
|
+
const lowerQuery = query.toLowerCase();
|
|
2322
|
+
const matches = apps.value.filter(
|
|
2323
|
+
(a) =>
|
|
2324
|
+
a.name?.toLowerCase() === lowerQuery ||
|
|
2325
|
+
a.fqdn?.toLowerCase().includes(lowerQuery) ||
|
|
2326
|
+
a.uuid.startsWith(query),
|
|
2327
|
+
);
|
|
2328
|
+
|
|
2329
|
+
if (matches.length === 1) return ok(matches[0]);
|
|
2330
|
+
if (matches.length === 0) {
|
|
2331
|
+
return err(
|
|
2332
|
+
new Error(
|
|
2333
|
+
`No application found matching "${query}". Use 'list' to see available applications.`,
|
|
2334
|
+
),
|
|
2335
|
+
);
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
const names = matches.map((a) => ` - ${a.name} (${a.uuid})`).join("\n");
|
|
2339
|
+
return err(
|
|
2340
|
+
new Error(
|
|
2341
|
+
`Multiple applications match "${query}":\n${names}\nPlease use the full UUID.`,
|
|
2342
|
+
),
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
/**
|
|
2347
|
+
* Resolves a server by UUID, name, or IP address.
|
|
2348
|
+
*
|
|
2349
|
+
* @param query - UUID, name, or IP to search for
|
|
2350
|
+
* @returns Result with server or error
|
|
2351
|
+
*/
|
|
2352
|
+
async resolveServer(query: string): Promise<Result<ICoolifyServer, Error>> {
|
|
2353
|
+
log.info(`Resolving server: ${query}`);
|
|
2354
|
+
|
|
2355
|
+
const servers = await this.listServers();
|
|
2356
|
+
if (isErr(servers)) return err(servers.error);
|
|
2357
|
+
|
|
2358
|
+
const lowerQuery = query.toLowerCase();
|
|
2359
|
+
const match = servers.value.find(
|
|
2360
|
+
(s) =>
|
|
2361
|
+
s.uuid === query ||
|
|
2362
|
+
s.name?.toLowerCase() === lowerQuery ||
|
|
2363
|
+
s.ip === query ||
|
|
2364
|
+
s.uuid.startsWith(query),
|
|
2365
|
+
);
|
|
2366
|
+
|
|
2367
|
+
if (match) return ok(match);
|
|
2368
|
+
return err(
|
|
2369
|
+
new Error(
|
|
2370
|
+
`No server found matching "${query}". Use 'servers' to see available servers.`,
|
|
2371
|
+
),
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
/**
|
|
2376
|
+
* Checks if a string looks like a UUID (Coolify or standard format).
|
|
2377
|
+
*
|
|
2378
|
+
* @param query - String to check
|
|
2379
|
+
* @returns true if it looks like a UUID
|
|
2380
|
+
*/
|
|
2381
|
+
private isLikelyUuid(query: string): boolean {
|
|
2382
|
+
if (/^[a-z0-9]{20,}$/i.test(query)) return true;
|
|
2383
|
+
if (
|
|
2384
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
|
|
2385
|
+
query,
|
|
2386
|
+
)
|
|
2387
|
+
)
|
|
2388
|
+
return true;
|
|
2389
|
+
return false;
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
// ===========================================================================
|
|
2393
|
+
// Diagnostics
|
|
2394
|
+
// ===========================================================================
|
|
2395
|
+
|
|
2396
|
+
/**
|
|
2397
|
+
* Diagnoses an application by aggregating health, logs, deployments, and env vars.
|
|
2398
|
+
*
|
|
2399
|
+
* @param query - Application UUID, name, or domain
|
|
2400
|
+
* @returns Result with diagnostic report or error
|
|
2401
|
+
*/
|
|
2402
|
+
async diagnoseApplication(query: string): Promise<
|
|
2403
|
+
Result<
|
|
2404
|
+
{
|
|
2405
|
+
application: ICoolifyApplication;
|
|
2406
|
+
recentDeployments: ICoolifyDeployment[];
|
|
2407
|
+
envVarCount: number;
|
|
2408
|
+
recentLogs: string[];
|
|
2409
|
+
issues: string[];
|
|
2410
|
+
},
|
|
2411
|
+
Error
|
|
2412
|
+
>
|
|
2413
|
+
> {
|
|
2414
|
+
log.info(`Diagnosing application: ${query}`);
|
|
2415
|
+
|
|
2416
|
+
const appResult = await this.resolveApplication(query);
|
|
2417
|
+
if (isErr(appResult)) return err(appResult.error);
|
|
2418
|
+
|
|
2419
|
+
const app = appResult.value;
|
|
2420
|
+
const issues: string[] = [];
|
|
2421
|
+
|
|
2422
|
+
// Gather data in parallel
|
|
2423
|
+
const [deploymentsResult, envResult, logsResult] = await Promise.all([
|
|
2424
|
+
this.getApplicationDeploymentHistory(app.uuid),
|
|
2425
|
+
this.getEnvironmentVariables(app.uuid),
|
|
2426
|
+
this.getApplicationLogs(app.uuid, { tail: 20 }),
|
|
2427
|
+
]);
|
|
2428
|
+
|
|
2429
|
+
const deployments = isErr(deploymentsResult) ? [] : deploymentsResult.value;
|
|
2430
|
+
const envVarCount = isErr(envResult) ? 0 : envResult.value.length;
|
|
2431
|
+
const recentLogs = isErr(logsResult) ? [] : logsResult.value.logs;
|
|
2432
|
+
|
|
2433
|
+
// Check for issues
|
|
2434
|
+
if (app.status?.includes("stopped")) {
|
|
2435
|
+
issues.push("Application is stopped");
|
|
2436
|
+
}
|
|
2437
|
+
if (!app.fqdn) {
|
|
2438
|
+
issues.push("No domain configured");
|
|
2439
|
+
}
|
|
2440
|
+
if (envVarCount === 0) {
|
|
2441
|
+
issues.push("No environment variables set");
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
const recentDeploys = deployments.slice(-5);
|
|
2445
|
+
const failedDeploys = recentDeploys.filter((d) =>
|
|
2446
|
+
d.status?.includes("failed"),
|
|
2447
|
+
);
|
|
2448
|
+
if (failedDeploys.length > 0) {
|
|
2449
|
+
issues.push(
|
|
2450
|
+
`${failedDeploys.length} of last ${recentDeploys.length} deployments failed`,
|
|
2451
|
+
);
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
log.success(`Diagnosis complete for ${app.name}`);
|
|
2455
|
+
return ok({
|
|
2456
|
+
application: app,
|
|
2457
|
+
recentDeployments: recentDeploys,
|
|
2458
|
+
envVarCount,
|
|
2459
|
+
recentLogs,
|
|
2460
|
+
issues,
|
|
2461
|
+
});
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
/**
|
|
2465
|
+
* Diagnoses a server by aggregating health, resources, and domains.
|
|
2466
|
+
*
|
|
2467
|
+
* @param query - Server UUID, name, or IP
|
|
2468
|
+
* @returns Result with diagnostic report or error
|
|
2469
|
+
*/
|
|
2470
|
+
async diagnoseServer(query: string): Promise<
|
|
2471
|
+
Result<
|
|
2472
|
+
{
|
|
2473
|
+
server: ICoolifyServer;
|
|
2474
|
+
resources: ICoolifyServerResource[];
|
|
2475
|
+
domains: ICoolifyServerDomain[];
|
|
2476
|
+
issues: string[];
|
|
2477
|
+
},
|
|
2478
|
+
Error
|
|
2479
|
+
>
|
|
2480
|
+
> {
|
|
2481
|
+
log.info(`Diagnosing server: ${query}`);
|
|
2482
|
+
|
|
2483
|
+
const serverResult = await this.resolveServer(query);
|
|
2484
|
+
if (isErr(serverResult)) return err(serverResult.error);
|
|
2485
|
+
|
|
2486
|
+
const server = serverResult.value;
|
|
2487
|
+
const issues: string[] = [];
|
|
2488
|
+
|
|
2489
|
+
const [resourcesResult, domainsResult] = await Promise.all([
|
|
2490
|
+
this.getServerResources(server.uuid),
|
|
2491
|
+
this.getServerDomains(server.uuid),
|
|
2492
|
+
]);
|
|
2493
|
+
|
|
2494
|
+
const resources = isErr(resourcesResult) ? [] : resourcesResult.value;
|
|
2495
|
+
const domains = isErr(domainsResult) ? [] : domainsResult.value;
|
|
2496
|
+
|
|
2497
|
+
if (!server.is_reachable) {
|
|
2498
|
+
issues.push("Server is not reachable");
|
|
2499
|
+
}
|
|
2500
|
+
if (!server.is_usable) {
|
|
2501
|
+
issues.push("Server is not usable");
|
|
2502
|
+
}
|
|
2503
|
+
if (resources.length === 0) {
|
|
2504
|
+
issues.push("No resources deployed on this server");
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
log.success(`Server diagnosis complete for ${server.name}`);
|
|
2508
|
+
return ok({ server, resources, domains, issues });
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
/**
|
|
2512
|
+
* Scans all infrastructure for potential issues.
|
|
2513
|
+
*
|
|
2514
|
+
* @returns Result with issues report or error
|
|
2515
|
+
*/
|
|
2516
|
+
async findInfrastructureIssues(): Promise<
|
|
2517
|
+
Result<
|
|
2518
|
+
{
|
|
2519
|
+
totalServers: number;
|
|
2520
|
+
totalApps: number;
|
|
2521
|
+
totalDatabases: number;
|
|
2522
|
+
totalServices: number;
|
|
2523
|
+
issues: Array<{
|
|
2524
|
+
type: string;
|
|
2525
|
+
resource: string;
|
|
2526
|
+
uuid: string;
|
|
2527
|
+
message: string;
|
|
2528
|
+
}>;
|
|
2529
|
+
},
|
|
2530
|
+
Error
|
|
2531
|
+
>
|
|
2532
|
+
> {
|
|
2533
|
+
log.info("Scanning infrastructure for issues");
|
|
2534
|
+
|
|
2535
|
+
const [serversR, appsR, dbsR, svcsR] = await Promise.all([
|
|
2536
|
+
this.listServers(),
|
|
2537
|
+
this.listApplications(),
|
|
2538
|
+
this.listDatabases(),
|
|
2539
|
+
this.listServices(),
|
|
2540
|
+
]);
|
|
2541
|
+
|
|
2542
|
+
const servers = isErr(serversR) ? [] : serversR.value;
|
|
2543
|
+
const apps = isErr(appsR) ? [] : appsR.value;
|
|
2544
|
+
const dbs = isErr(dbsR) ? [] : dbsR.value;
|
|
2545
|
+
const svcs = isErr(svcsR) ? [] : svcsR.value;
|
|
2546
|
+
|
|
2547
|
+
const issues: Array<{
|
|
2548
|
+
type: string;
|
|
2549
|
+
resource: string;
|
|
2550
|
+
uuid: string;
|
|
2551
|
+
message: string;
|
|
2552
|
+
}> = [];
|
|
2553
|
+
|
|
2554
|
+
for (const server of servers) {
|
|
2555
|
+
if (!server.is_reachable) {
|
|
2556
|
+
issues.push({
|
|
2557
|
+
type: "server",
|
|
2558
|
+
resource: server.name,
|
|
2559
|
+
uuid: server.uuid,
|
|
2560
|
+
message: "Server unreachable",
|
|
2561
|
+
});
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
for (const app of apps) {
|
|
2566
|
+
if (app.status?.includes("stopped")) {
|
|
2567
|
+
issues.push({
|
|
2568
|
+
type: "application",
|
|
2569
|
+
resource: app.name,
|
|
2570
|
+
uuid: app.uuid,
|
|
2571
|
+
message: "Application stopped",
|
|
2572
|
+
});
|
|
2573
|
+
}
|
|
2574
|
+
if (app.status?.includes("failed") || app.status?.includes("error")) {
|
|
2575
|
+
issues.push({
|
|
2576
|
+
type: "application",
|
|
2577
|
+
resource: app.name,
|
|
2578
|
+
uuid: app.uuid,
|
|
2579
|
+
message: `Status: ${app.status}`,
|
|
2580
|
+
});
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
for (const db of dbs) {
|
|
2585
|
+
if (db.status?.includes("stopped") || db.status?.includes("exited")) {
|
|
2586
|
+
issues.push({
|
|
2587
|
+
type: "database",
|
|
2588
|
+
resource: db.name,
|
|
2589
|
+
uuid: db.uuid,
|
|
2590
|
+
message: `Database stopped: ${db.status}`,
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
for (const svc of svcs) {
|
|
2596
|
+
if (svc.status?.includes("stopped") || svc.status?.includes("exited")) {
|
|
2597
|
+
issues.push({
|
|
2598
|
+
type: "service",
|
|
2599
|
+
resource: svc.name,
|
|
2600
|
+
uuid: svc.uuid,
|
|
2601
|
+
message: `Service stopped: ${svc.status}`,
|
|
2602
|
+
});
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
log.success(
|
|
2607
|
+
`Infrastructure scan complete: ${issues.length} issue(s) found`,
|
|
2608
|
+
);
|
|
2609
|
+
return ok({
|
|
2610
|
+
totalServers: servers.length,
|
|
2611
|
+
totalApps: apps.length,
|
|
2612
|
+
totalDatabases: dbs.length,
|
|
2613
|
+
totalServices: svcs.length,
|
|
2614
|
+
issues,
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
// ===========================================================================
|
|
2619
|
+
// Batch Operations
|
|
2620
|
+
// ===========================================================================
|
|
2621
|
+
|
|
2622
|
+
/**
|
|
2623
|
+
* Restarts all applications in a project.
|
|
2624
|
+
*
|
|
2625
|
+
* @param projectUuid - Project UUID
|
|
2626
|
+
* @returns Result with batch operation results
|
|
2627
|
+
*/
|
|
2628
|
+
async restartProjectApps(
|
|
2629
|
+
projectUuid: string,
|
|
2630
|
+
): Promise<
|
|
2631
|
+
Result<{ total: number; succeeded: number; failed: string[] }, Error>
|
|
2632
|
+
> {
|
|
2633
|
+
log.info(`Restarting all apps in project ${projectUuid}`);
|
|
2634
|
+
|
|
2635
|
+
const appsResult = await this.listApplications(undefined, projectUuid);
|
|
2636
|
+
if (isErr(appsResult)) return err(appsResult.error);
|
|
2637
|
+
|
|
2638
|
+
const apps = appsResult.value;
|
|
2639
|
+
const failed: string[] = [];
|
|
2640
|
+
let succeeded = 0;
|
|
2641
|
+
|
|
2642
|
+
for (const app of apps) {
|
|
2643
|
+
const result = await this.restartApplication(app.uuid);
|
|
2644
|
+
if (isErr(result)) {
|
|
2645
|
+
failed.push(`${app.name} (${app.uuid}): ${result.error.message}`);
|
|
2646
|
+
} else {
|
|
2647
|
+
succeeded++;
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
log.success(`Restarted ${succeeded}/${apps.length} apps in project`);
|
|
2652
|
+
return ok({ total: apps.length, succeeded, failed });
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
/**
|
|
2656
|
+
* Redeploys all applications in a project.
|
|
2657
|
+
*
|
|
2658
|
+
* @param projectUuid - Project UUID
|
|
2659
|
+
* @param force - Force rebuild
|
|
2660
|
+
* @returns Result with batch operation results
|
|
2661
|
+
*/
|
|
2662
|
+
async redeployProjectApps(
|
|
2663
|
+
projectUuid: string,
|
|
2664
|
+
force: boolean = false,
|
|
2665
|
+
): Promise<
|
|
2666
|
+
Result<{ total: number; succeeded: number; failed: string[] }, Error>
|
|
2667
|
+
> {
|
|
2668
|
+
log.info(`Redeploying all apps in project ${projectUuid}`);
|
|
2669
|
+
|
|
2670
|
+
const appsResult = await this.listApplications(undefined, projectUuid);
|
|
2671
|
+
if (isErr(appsResult)) return err(appsResult.error);
|
|
2672
|
+
|
|
2673
|
+
const apps = appsResult.value;
|
|
2674
|
+
const failed: string[] = [];
|
|
2675
|
+
let succeeded = 0;
|
|
2676
|
+
|
|
2677
|
+
for (const app of apps) {
|
|
2678
|
+
const result = await this.deploy({ uuid: app.uuid, force });
|
|
2679
|
+
if (isErr(result)) {
|
|
2680
|
+
failed.push(`${app.name} (${app.uuid}): ${result.error.message}`);
|
|
2681
|
+
} else {
|
|
2682
|
+
succeeded++;
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
log.success(`Redeployed ${succeeded}/${apps.length} apps in project`);
|
|
2687
|
+
return ok({ total: apps.length, succeeded, failed });
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
/**
|
|
2691
|
+
* Stops all running applications.
|
|
2692
|
+
*
|
|
2693
|
+
* @returns Result with batch operation results
|
|
2694
|
+
*/
|
|
2695
|
+
async stopAllApps(): Promise<
|
|
2696
|
+
Result<{ total: number; succeeded: number; failed: string[] }, Error>
|
|
2697
|
+
> {
|
|
2698
|
+
log.info("Stopping all applications");
|
|
2699
|
+
|
|
2700
|
+
const appsResult = await this.listApplications();
|
|
2701
|
+
if (isErr(appsResult)) return err(appsResult.error);
|
|
2702
|
+
|
|
2703
|
+
const running = appsResult.value.filter(
|
|
2704
|
+
(a) => !a.status?.includes("stopped"),
|
|
2705
|
+
);
|
|
2706
|
+
const failed: string[] = [];
|
|
2707
|
+
let succeeded = 0;
|
|
2708
|
+
|
|
2709
|
+
for (const app of running) {
|
|
2710
|
+
const result = await this.stopApplication(app.uuid);
|
|
2711
|
+
if (isErr(result)) {
|
|
2712
|
+
failed.push(`${app.name} (${app.uuid}): ${result.error.message}`);
|
|
2713
|
+
} else {
|
|
2714
|
+
succeeded++;
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
log.success(`Stopped ${succeeded}/${running.length} apps`);
|
|
2719
|
+
return ok({ total: running.length, succeeded, failed });
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
// ===========================================================================
|
|
2723
|
+
// Summary Types (Token Optimization for MCP)
|
|
2724
|
+
// ===========================================================================
|
|
2725
|
+
|
|
2726
|
+
/**
|
|
2727
|
+
* Lists applications with minimal fields for token efficiency.
|
|
2728
|
+
*
|
|
2729
|
+
* @returns Result with application summaries or error
|
|
2730
|
+
*/
|
|
2731
|
+
async listApplicationSummaries(): Promise<
|
|
2732
|
+
Result<
|
|
2733
|
+
Array<{
|
|
2734
|
+
uuid: string;
|
|
2735
|
+
name: string;
|
|
2736
|
+
status: string;
|
|
2737
|
+
fqdn: string | null;
|
|
2738
|
+
}>,
|
|
2739
|
+
Error
|
|
2740
|
+
>
|
|
2741
|
+
> {
|
|
2742
|
+
const result = await this.listApplications();
|
|
2743
|
+
if (isErr(result)) return err(result.error);
|
|
2744
|
+
|
|
2745
|
+
return ok(
|
|
2746
|
+
result.value.map((a) => ({
|
|
2747
|
+
uuid: a.uuid,
|
|
2748
|
+
name: a.name,
|
|
2749
|
+
status: a.status,
|
|
2750
|
+
fqdn: a.fqdn || null,
|
|
2751
|
+
})),
|
|
2752
|
+
);
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
/**
|
|
2756
|
+
* Lists servers with minimal fields for token efficiency.
|
|
2757
|
+
*
|
|
2758
|
+
* @returns Result with server summaries or error
|
|
2759
|
+
*/
|
|
2760
|
+
async listServerSummaries(): Promise<
|
|
2761
|
+
Result<
|
|
2762
|
+
Array<{
|
|
2763
|
+
uuid: string;
|
|
2764
|
+
name: string;
|
|
2765
|
+
ip: string;
|
|
2766
|
+
is_reachable: boolean;
|
|
2767
|
+
}>,
|
|
2768
|
+
Error
|
|
2769
|
+
>
|
|
2770
|
+
> {
|
|
2771
|
+
const result = await this.listServers();
|
|
2772
|
+
if (isErr(result)) return err(result.error);
|
|
2773
|
+
|
|
2774
|
+
return ok(
|
|
2775
|
+
result.value.map((s) => ({
|
|
2776
|
+
uuid: s.uuid,
|
|
2777
|
+
name: s.name,
|
|
2778
|
+
ip: s.ip || "",
|
|
2779
|
+
is_reachable: s.is_reachable || false,
|
|
2780
|
+
})),
|
|
2781
|
+
);
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
/**
|
|
2785
|
+
* Lists databases with minimal fields for token efficiency.
|
|
2786
|
+
*
|
|
2787
|
+
* @returns Result with database summaries or error
|
|
2788
|
+
*/
|
|
2789
|
+
async listDatabaseSummaries(): Promise<
|
|
2790
|
+
Result<
|
|
2791
|
+
Array<{
|
|
2792
|
+
uuid: string;
|
|
2793
|
+
name: string;
|
|
2794
|
+
type: string;
|
|
2795
|
+
status: string;
|
|
2796
|
+
}>,
|
|
2797
|
+
Error
|
|
2798
|
+
>
|
|
2799
|
+
> {
|
|
2800
|
+
const result = await this.listDatabases();
|
|
2801
|
+
if (isErr(result)) return err(result.error);
|
|
2802
|
+
|
|
2803
|
+
return ok(
|
|
2804
|
+
result.value.map((d) => ({
|
|
2805
|
+
uuid: d.uuid,
|
|
2806
|
+
name: d.name,
|
|
2807
|
+
type: d.type,
|
|
2808
|
+
status: d.status,
|
|
2809
|
+
})),
|
|
2810
|
+
);
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
/**
|
|
2814
|
+
* Lists services with minimal fields for token efficiency.
|
|
2815
|
+
*
|
|
2816
|
+
* @returns Result with service summaries or error
|
|
2817
|
+
*/
|
|
2818
|
+
async listServiceSummaries(): Promise<
|
|
2819
|
+
Result<
|
|
2820
|
+
Array<{
|
|
2821
|
+
uuid: string;
|
|
2822
|
+
name: string;
|
|
2823
|
+
type: string;
|
|
2824
|
+
status: string;
|
|
2825
|
+
}>,
|
|
2826
|
+
Error
|
|
2827
|
+
>
|
|
2828
|
+
> {
|
|
2829
|
+
const result = await this.listServices();
|
|
2830
|
+
if (isErr(result)) return err(result.error);
|
|
2831
|
+
|
|
2832
|
+
return ok(
|
|
2833
|
+
result.value.map((s) => ({
|
|
2834
|
+
uuid: s.uuid,
|
|
2835
|
+
name: s.name,
|
|
2836
|
+
type: s.type,
|
|
2837
|
+
status: s.status,
|
|
2838
|
+
})),
|
|
2839
|
+
);
|
|
1141
2840
|
}
|
|
1142
2841
|
}
|
|
1143
2842
|
|
|
@@ -1158,11 +2857,18 @@ export function getCoolifyService(): CoolifyService {
|
|
|
1158
2857
|
// Re-export types
|
|
1159
2858
|
export type {
|
|
1160
2859
|
ICoolifyServer,
|
|
2860
|
+
ICoolifyServerResource,
|
|
2861
|
+
ICoolifyServerDomain,
|
|
1161
2862
|
ICoolifyDestination,
|
|
1162
2863
|
ICoolifyProject,
|
|
1163
2864
|
ICoolifyTeam,
|
|
1164
2865
|
ICoolifyApplication,
|
|
2866
|
+
ICoolifyDatabase,
|
|
2867
|
+
ICoolifyDatabaseBackup,
|
|
2868
|
+
ICoolifyService as ICoolifyServiceType,
|
|
2869
|
+
ICoolifyPrivateKey,
|
|
1165
2870
|
ICoolifyDeployment,
|
|
2871
|
+
ICoolifyVersion,
|
|
1166
2872
|
ICoolifyAppOptions,
|
|
1167
2873
|
ICoolifyAppResult,
|
|
1168
2874
|
ICoolifyDeployOptions,
|