kastell 1.7.0 → 1.8.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/README.md +1 -1
- package/README.tr.md +1 -1
- package/dist/adapters/coolify.d.ts +6 -5
- package/dist/adapters/coolify.d.ts.map +1 -1
- package/dist/adapters/coolify.js +31 -188
- package/dist/adapters/coolify.js.map +1 -1
- package/dist/adapters/dokploy.d.ts +6 -6
- package/dist/adapters/dokploy.d.ts.map +1 -1
- package/dist/adapters/dokploy.js +31 -197
- package/dist/adapters/dokploy.js.map +1 -1
- package/dist/adapters/shared.d.ts +50 -1
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/shared.js +190 -1
- package/dist/adapters/shared.js.map +1 -1
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +48 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/firewall.d.ts +2 -3
- package/dist/commands/firewall.d.ts.map +1 -1
- package/dist/commands/firewall.js +2 -42
- package/dist/commands/firewall.js.map +1 -1
- package/dist/commands/fleet.d.ts +3 -0
- package/dist/commands/fleet.d.ts.map +1 -0
- package/dist/commands/fleet.js +12 -0
- package/dist/commands/fleet.js.map +1 -0
- package/dist/commands/guard.d.ts.map +1 -1
- package/dist/commands/guard.js +2 -1
- package/dist/commands/guard.js.map +1 -1
- package/dist/commands/health.d.ts +1 -7
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +2 -42
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/notify.d.ts +3 -0
- package/dist/commands/notify.d.ts.map +1 -0
- package/dist/commands/notify.js +23 -0
- package/dist/commands/notify.js.map +1 -0
- package/dist/commands/secure.d.ts +2 -5
- package/dist/commands/secure.d.ts.map +1 -1
- package/dist/commands/secure.js +4 -129
- package/dist/commands/secure.js.map +1 -1
- package/dist/core/audit/history.js +1 -1
- package/dist/core/audit/history.js.map +1 -1
- package/dist/core/backup.d.ts.map +1 -1
- package/dist/core/backup.js +5 -0
- package/dist/core/backup.js.map +1 -1
- package/dist/core/completions.d.ts +1 -1
- package/dist/core/completions.d.ts.map +1 -1
- package/dist/core/completions.js +125 -5
- package/dist/core/completions.js.map +1 -1
- package/dist/core/deploy.d.ts.map +1 -1
- package/dist/core/deploy.js +103 -94
- package/dist/core/deploy.js.map +1 -1
- package/dist/core/doctor-fix.d.ts +31 -0
- package/dist/core/doctor-fix.d.ts.map +1 -0
- package/dist/core/doctor-fix.js +79 -0
- package/dist/core/doctor-fix.js.map +1 -0
- package/dist/core/doctor.d.ts +1 -0
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +3 -1
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/evidence.d.ts.map +1 -1
- package/dist/core/evidence.js +7 -1
- package/dist/core/evidence.js.map +1 -1
- package/dist/core/evidenceCommands.d.ts.map +1 -1
- package/dist/core/evidenceCommands.js +11 -3
- package/dist/core/evidenceCommands.js.map +1 -1
- package/dist/core/firewall.d.ts +1 -0
- package/dist/core/firewall.d.ts.map +1 -1
- package/dist/core/firewall.js +44 -0
- package/dist/core/firewall.js.map +1 -1
- package/dist/core/fleet.d.ts +20 -0
- package/dist/core/fleet.d.ts.map +1 -0
- package/dist/core/fleet.js +134 -0
- package/dist/core/fleet.js.map +1 -0
- package/dist/core/guard.d.ts +1 -0
- package/dist/core/guard.d.ts.map +1 -1
- package/dist/core/guard.js +22 -3
- package/dist/core/guard.js.map +1 -1
- package/dist/core/health.d.ts +8 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +41 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/notify.d.ts +49 -0
- package/dist/core/notify.d.ts.map +1 -0
- package/dist/core/notify.js +216 -0
- package/dist/core/notify.js.map +1 -0
- package/dist/core/secure.d.ts +3 -0
- package/dist/core/secure.d.ts.map +1 -1
- package/dist/core/secure.js +127 -12
- package/dist/core/secure.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +14 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/serverAudit.d.ts +1 -1
- package/dist/mcp/tools/serverDoctor.d.ts +1 -1
- package/dist/mcp/tools/serverFleet.d.ts +13 -0
- package/dist/mcp/tools/serverFleet.d.ts.map +1 -0
- package/dist/mcp/tools/serverFleet.js +28 -0
- package/dist/mcp/tools/serverFleet.js.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ Running `kastell` without any arguments launches an **interactive search menu**
|
|
|
45
45
|
██║ ██╗ ██║ ██║ ███████║ ██║ ███████╗███████╗███████╗
|
|
46
46
|
╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚══════╝╚══════╝╚══════╝
|
|
47
47
|
|
|
48
|
-
KASTELL v1.
|
|
48
|
+
KASTELL v1.8.0 · Your infrastructure, fortified.
|
|
49
49
|
|
|
50
50
|
$ kastell init --template production → deploy a new server
|
|
51
51
|
$ kastell status --all → check all servers
|
package/README.tr.md
CHANGED
|
@@ -45,7 +45,7 @@ npx kastell
|
|
|
45
45
|
██║ ██╗ ██║ ██║ ███████║ ██║ ███████╗███████╗███████╗
|
|
46
46
|
╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚══════╝╚══════╝╚══════╝
|
|
47
47
|
|
|
48
|
-
KASTELL v1.
|
|
48
|
+
KASTELL v1.8.0 · Your infrastructure, fortified.
|
|
49
49
|
|
|
50
50
|
$ kastell init --template production → deploy a new server
|
|
51
51
|
$ kastell status --all → check all servers
|
|
@@ -5,12 +5,13 @@ export declare class CoolifyAdapter implements PlatformAdapter {
|
|
|
5
5
|
getCloudInit(serverName: string): string;
|
|
6
6
|
healthCheck(ip: string, domain?: string): Promise<HealthResult>;
|
|
7
7
|
createBackup(ip: string, serverName: string, provider: string): Promise<PlatformBackupResult>;
|
|
8
|
-
restoreBackup(ip: string, backupPath: string,
|
|
8
|
+
restoreBackup(ip: string, backupPath: string, manifest: BackupManifest, options?: {
|
|
9
|
+
force?: boolean;
|
|
10
|
+
}): Promise<PlatformRestoreResult>;
|
|
9
11
|
getStatus(ip: string): Promise<PlatformStatusResult>;
|
|
10
12
|
update(ip: string): Promise<UpdateResult>;
|
|
11
|
-
private
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
-
private buildVersionCommand;
|
|
13
|
+
private versionCmd;
|
|
14
|
+
private backupConfig;
|
|
15
|
+
private restoreConfig;
|
|
15
16
|
}
|
|
16
17
|
//# sourceMappingURL=coolify.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coolify.d.ts","sourceRoot":"","sources":["../../src/adapters/coolify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"coolify.d.ts","sourceRoot":"","sources":["../../src/adapters/coolify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAKxD,qBAAa,cAAe,YAAW,eAAe;IACpD,QAAQ,CAAC,IAAI,aAAa;IAE1B,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAuElC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI/D,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC;IAI1B,aAAa,CACjB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAI3B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAIpD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAM/C,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,aAAa;CActB"}
|
package/dist/adapters/coolify.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
1
|
import { COOLIFY_UPDATE_CMD } from "../constants.js";
|
|
4
|
-
import {
|
|
5
|
-
import { formatTimestamp, getBackupDir, scpDownload, scpUpload, buildStopCoolifyCommand, buildStartCoolifyCommand, buildStartDbCommand, buildRestoreDbCommand, buildRestoreConfigCommand, buildCleanupCommand, tryRestartCoolify, } from "../core/backup.js";
|
|
6
|
-
import { getErrorMessage, mapSshError, sanitizeStderr } from "../utils/errorMapper.js";
|
|
7
|
-
import { sharedHealthCheck, sharedUpdate, sharedGetStatus } from "./shared.js";
|
|
2
|
+
import { sharedHealthCheck, sharedUpdate, sharedGetStatus, sharedCreateBackup, sharedRestoreBackup } from "./shared.js";
|
|
8
3
|
export class CoolifyAdapter {
|
|
9
4
|
name = "coolify";
|
|
10
5
|
getCloudInit(serverName) {
|
|
@@ -81,197 +76,45 @@ echo "Then access your instance at: http://YOUR_SERVER_IP:8000"
|
|
|
81
76
|
return sharedHealthCheck(ip, 8000, domain);
|
|
82
77
|
}
|
|
83
78
|
async createBackup(ip, serverName, provider) {
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
// Step 1: Get Coolify version (best-effort)
|
|
87
|
-
const versionResult = await sshExec(ip, this.buildVersionCommand());
|
|
88
|
-
const coolifyVersion = versionResult.code === 0 ? versionResult.stdout.trim() : "unknown";
|
|
89
|
-
// Step 2: Database backup
|
|
90
|
-
const dbResult = await sshExec(ip, this.buildPgDumpCommand());
|
|
91
|
-
if (dbResult.code !== 0) {
|
|
92
|
-
return {
|
|
93
|
-
success: false,
|
|
94
|
-
error: "Database backup failed",
|
|
95
|
-
hint: sanitizeStderr(dbResult.stderr) || undefined,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
// Step 3: Config backup
|
|
99
|
-
const configResult = await sshExec(ip, this.buildConfigTarCommand());
|
|
100
|
-
if (configResult.code !== 0) {
|
|
101
|
-
return {
|
|
102
|
-
success: false,
|
|
103
|
-
error: "Config backup failed",
|
|
104
|
-
hint: sanitizeStderr(configResult.stderr) || undefined,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
// Step 4: Create local directory and download
|
|
108
|
-
const timestamp = formatTimestamp(new Date());
|
|
109
|
-
const backupPath = join(getBackupDir(serverName), timestamp);
|
|
110
|
-
mkdirSync(backupPath, { recursive: true, mode: 0o700 });
|
|
111
|
-
const dbDl = await scpDownload(ip, "/tmp/coolify-backup.sql.gz", join(backupPath, "coolify-backup.sql.gz"));
|
|
112
|
-
if (dbDl.code !== 0) {
|
|
113
|
-
return {
|
|
114
|
-
success: false,
|
|
115
|
-
error: "Failed to download database backup",
|
|
116
|
-
hint: sanitizeStderr(dbDl.stderr) || undefined,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
const configDl = await scpDownload(ip, "/tmp/coolify-config.tar.gz", join(backupPath, "coolify-config.tar.gz"));
|
|
120
|
-
if (configDl.code !== 0) {
|
|
121
|
-
return {
|
|
122
|
-
success: false,
|
|
123
|
-
error: "Failed to download config backup",
|
|
124
|
-
hint: sanitizeStderr(configDl.stderr) || undefined,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
// Step 5: Write manifest
|
|
128
|
-
const manifest = {
|
|
129
|
-
serverName,
|
|
130
|
-
provider,
|
|
131
|
-
timestamp,
|
|
132
|
-
coolifyVersion,
|
|
133
|
-
files: ["coolify-backup.sql.gz", "coolify-config.tar.gz"],
|
|
134
|
-
};
|
|
135
|
-
writeFileSync(join(backupPath, "manifest.json"), JSON.stringify(manifest, null, 2), { mode: 0o600 });
|
|
136
|
-
// Step 6: Cleanup remote (best-effort)
|
|
137
|
-
await sshExec(ip, this.buildCleanupCommand()).catch(() => { });
|
|
138
|
-
return { success: true, backupPath, manifest };
|
|
139
|
-
}
|
|
140
|
-
catch (error) {
|
|
141
|
-
const hint = mapSshError(error, ip);
|
|
142
|
-
return {
|
|
143
|
-
success: false,
|
|
144
|
-
error: getErrorMessage(error),
|
|
145
|
-
...(hint ? { hint } : {}),
|
|
146
|
-
};
|
|
147
|
-
}
|
|
79
|
+
return sharedCreateBackup(ip, serverName, provider, this.backupConfig());
|
|
148
80
|
}
|
|
149
|
-
async restoreBackup(ip, backupPath,
|
|
150
|
-
|
|
151
|
-
const steps = [];
|
|
152
|
-
try {
|
|
153
|
-
// Upload backup files (before stopping Coolify -- safe to fail here)
|
|
154
|
-
const dbUpload = await scpUpload(ip, join(backupPath, "coolify-backup.sql.gz"), "/tmp/coolify-backup.sql.gz");
|
|
155
|
-
if (dbUpload.code !== 0) {
|
|
156
|
-
return {
|
|
157
|
-
success: false,
|
|
158
|
-
steps: [
|
|
159
|
-
{
|
|
160
|
-
name: "Upload database backup",
|
|
161
|
-
status: "failure",
|
|
162
|
-
error: sanitizeStderr(dbUpload.stderr),
|
|
163
|
-
},
|
|
164
|
-
],
|
|
165
|
-
error: "Failed to upload database backup",
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
steps.push({ name: "Upload database backup", status: "success" });
|
|
169
|
-
const configUpload = await scpUpload(ip, join(backupPath, "coolify-config.tar.gz"), "/tmp/coolify-config.tar.gz");
|
|
170
|
-
if (configUpload.code !== 0) {
|
|
171
|
-
return {
|
|
172
|
-
success: false,
|
|
173
|
-
steps: [
|
|
174
|
-
...steps,
|
|
175
|
-
{
|
|
176
|
-
name: "Upload config backup",
|
|
177
|
-
status: "failure",
|
|
178
|
-
error: sanitizeStderr(configUpload.stderr),
|
|
179
|
-
},
|
|
180
|
-
],
|
|
181
|
-
error: "Failed to upload config backup",
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
steps.push({ name: "Upload config backup", status: "success" });
|
|
185
|
-
// Step 1: Stop Coolify
|
|
186
|
-
const stopResult = await sshExec(ip, buildStopCoolifyCommand());
|
|
187
|
-
if (stopResult.code !== 0) {
|
|
188
|
-
steps.push({
|
|
189
|
-
name: "Stop Coolify",
|
|
190
|
-
status: "failure",
|
|
191
|
-
error: sanitizeStderr(stopResult.stderr),
|
|
192
|
-
});
|
|
193
|
-
return { success: false, steps, error: "Failed to stop Coolify" };
|
|
194
|
-
}
|
|
195
|
-
steps.push({ name: "Stop Coolify", status: "success" });
|
|
196
|
-
// Step 2: Start DB only
|
|
197
|
-
const dbStartResult = await sshExec(ip, buildStartDbCommand());
|
|
198
|
-
if (dbStartResult.code !== 0) {
|
|
199
|
-
steps.push({
|
|
200
|
-
name: "Start database",
|
|
201
|
-
status: "failure",
|
|
202
|
-
error: sanitizeStderr(dbStartResult.stderr),
|
|
203
|
-
});
|
|
204
|
-
await tryRestartCoolify(ip);
|
|
205
|
-
return { success: false, steps, error: "Failed to start database" };
|
|
206
|
-
}
|
|
207
|
-
steps.push({ name: "Start database", status: "success" });
|
|
208
|
-
// Step 3: Restore database
|
|
209
|
-
const restoreDbResult = await sshExec(ip, buildRestoreDbCommand());
|
|
210
|
-
if (restoreDbResult.code !== 0) {
|
|
211
|
-
steps.push({
|
|
212
|
-
name: "Restore database",
|
|
213
|
-
status: "failure",
|
|
214
|
-
error: sanitizeStderr(restoreDbResult.stderr),
|
|
215
|
-
});
|
|
216
|
-
await tryRestartCoolify(ip);
|
|
217
|
-
return { success: false, steps, error: "Database restore failed" };
|
|
218
|
-
}
|
|
219
|
-
steps.push({ name: "Restore database", status: "success" });
|
|
220
|
-
// Step 4: Restore config
|
|
221
|
-
const restoreConfigResult = await sshExec(ip, buildRestoreConfigCommand());
|
|
222
|
-
if (restoreConfigResult.code !== 0) {
|
|
223
|
-
steps.push({
|
|
224
|
-
name: "Restore config",
|
|
225
|
-
status: "failure",
|
|
226
|
-
error: sanitizeStderr(restoreConfigResult.stderr),
|
|
227
|
-
});
|
|
228
|
-
await tryRestartCoolify(ip);
|
|
229
|
-
return { success: false, steps, error: "Config restore failed" };
|
|
230
|
-
}
|
|
231
|
-
steps.push({ name: "Restore config", status: "success" });
|
|
232
|
-
// Step 5: Start Coolify
|
|
233
|
-
const startResult = await sshExec(ip, buildStartCoolifyCommand());
|
|
234
|
-
if (startResult.code !== 0) {
|
|
235
|
-
steps.push({
|
|
236
|
-
name: "Start Coolify",
|
|
237
|
-
status: "failure",
|
|
238
|
-
error: sanitizeStderr(startResult.stderr),
|
|
239
|
-
});
|
|
240
|
-
return { success: false, steps, error: "Failed to start Coolify" };
|
|
241
|
-
}
|
|
242
|
-
steps.push({ name: "Start Coolify", status: "success" });
|
|
243
|
-
// Cleanup remote (best-effort)
|
|
244
|
-
await sshExec(ip, buildCleanupCommand()).catch(() => { });
|
|
245
|
-
return { success: true, steps };
|
|
246
|
-
}
|
|
247
|
-
catch (error) {
|
|
248
|
-
const hint = mapSshError(error, ip);
|
|
249
|
-
return {
|
|
250
|
-
success: false,
|
|
251
|
-
steps,
|
|
252
|
-
error: getErrorMessage(error),
|
|
253
|
-
...(hint ? { hint } : {}),
|
|
254
|
-
};
|
|
255
|
-
}
|
|
81
|
+
async restoreBackup(ip, backupPath, manifest, options) {
|
|
82
|
+
return sharedRestoreBackup(ip, backupPath, manifest, this.restoreConfig(), options);
|
|
256
83
|
}
|
|
257
84
|
async getStatus(ip) {
|
|
258
|
-
return sharedGetStatus(ip, this.
|
|
85
|
+
return sharedGetStatus(ip, this.versionCmd(), 8000);
|
|
259
86
|
}
|
|
260
87
|
async update(ip) {
|
|
261
88
|
return sharedUpdate(ip, COOLIFY_UPDATE_CMD);
|
|
262
89
|
}
|
|
263
|
-
// ─── Private
|
|
264
|
-
|
|
265
|
-
return "
|
|
266
|
-
}
|
|
267
|
-
buildConfigTarCommand() {
|
|
268
|
-
return "tar czf /tmp/coolify-config.tar.gz -C /data/coolify/source .env docker-compose.yml docker-compose.prod.yml 2>/dev/null || tar czf /tmp/coolify-config.tar.gz -C /data/coolify/source .env docker-compose.yml";
|
|
90
|
+
// ─── Private Config Builders ─────────────────────────────────────────────────
|
|
91
|
+
versionCmd() {
|
|
92
|
+
return "docker inspect coolify --format '{{.Config.Image}}' 2>/dev/null | sed 's/.*://' || echo unknown";
|
|
269
93
|
}
|
|
270
|
-
|
|
271
|
-
return
|
|
94
|
+
backupConfig() {
|
|
95
|
+
return {
|
|
96
|
+
platform: "coolify",
|
|
97
|
+
pgDumpCmd: "set -o pipefail && docker exec coolify-db pg_dump -U coolify -d coolify | gzip > /tmp/coolify-backup.sql.gz",
|
|
98
|
+
configTarCmd: "tar czf /tmp/coolify-config.tar.gz -C /data/coolify/source .env docker-compose.yml docker-compose.prod.yml 2>/dev/null || tar czf /tmp/coolify-config.tar.gz -C /data/coolify/source .env docker-compose.yml",
|
|
99
|
+
versionCmd: this.versionCmd(),
|
|
100
|
+
cleanupCmd: "rm -f /tmp/coolify-backup.sql.gz /tmp/coolify-config.tar.gz",
|
|
101
|
+
dbFileName: "coolify-backup.sql.gz",
|
|
102
|
+
configFileName: "coolify-config.tar.gz",
|
|
103
|
+
};
|
|
272
104
|
}
|
|
273
|
-
|
|
274
|
-
return
|
|
105
|
+
restoreConfig() {
|
|
106
|
+
return {
|
|
107
|
+
platform: "coolify",
|
|
108
|
+
stopCmd: "cd /data/coolify/source && docker compose -f docker-compose.yml -f docker-compose.prod.yml stop",
|
|
109
|
+
startDbCmd: "cd /data/coolify/source && docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d postgres && sleep 3",
|
|
110
|
+
restoreDbCmd: "gunzip -c /tmp/coolify-backup.sql.gz | docker exec -i coolify-db psql -U coolify -d coolify",
|
|
111
|
+
restoreConfigCmd: "tar xzf /tmp/coolify-config.tar.gz -C /data/coolify/source",
|
|
112
|
+
startCmd: "cd /data/coolify/source && docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d",
|
|
113
|
+
cleanupCmd: "rm -f /tmp/coolify-backup.sql.gz /tmp/coolify-config.tar.gz",
|
|
114
|
+
tryRestartCmd: "cd /data/coolify/source && docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d",
|
|
115
|
+
dbFileName: "coolify-backup.sql.gz",
|
|
116
|
+
configFileName: "coolify-config.tar.gz",
|
|
117
|
+
};
|
|
275
118
|
}
|
|
276
119
|
}
|
|
277
120
|
//# sourceMappingURL=coolify.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coolify.js","sourceRoot":"","sources":["../../src/adapters/coolify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"coolify.js","sourceRoot":"","sources":["../../src/adapters/coolify.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGxH,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,SAAS,CAAC;IAE1B,YAAY,CAAC,UAAkB;QAC7B,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACvD,OAAO;;;;;;;;gBAQK,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0DvB,CAAC;IACA,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,EAAU,EAAE,MAAe;QAC3C,OAAO,iBAAiB,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,EAAU,EACV,UAAkB,EAClB,QAAgB;QAEhB,OAAO,kBAAkB,CAAC,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,EAAU,EACV,UAAkB,EAClB,QAAwB,EACxB,OAA6B;QAE7B,OAAO,mBAAmB,CAAC,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,OAAO,CAAC,CAAC;IACtF,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,OAAO,eAAe,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,OAAO,YAAY,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC;IAC9C,CAAC;IAED,gFAAgF;IAExE,UAAU;QAChB,OAAO,iGAAiG,CAAC;IAC3G,CAAC;IAEO,YAAY;QAClB,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,SAAS,EAAE,6GAA6G;YACxH,YAAY,EAAE,8MAA8M;YAC5N,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;YAC7B,UAAU,EAAE,6DAA6D;YACzE,UAAU,EAAE,uBAAuB;YACnC,cAAc,EAAE,uBAAuB;SACxC,CAAC;IACJ,CAAC;IAEO,aAAa;QACnB,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,iGAAiG;YAC1G,UAAU,EAAE,sHAAsH;YAClI,YAAY,EAAE,6FAA6F;YAC3G,gBAAgB,EAAE,4DAA4D;YAC9E,QAAQ,EAAE,kGAAkG;YAC5G,UAAU,EAAE,6DAA6D;YACzE,aAAa,EAAE,kGAAkG;YACjH,UAAU,EAAE,uBAAuB;YACnC,cAAc,EAAE,uBAAuB;SACxC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -5,13 +5,13 @@ export declare class DokployAdapter implements PlatformAdapter {
|
|
|
5
5
|
getCloudInit(serverName: string): string;
|
|
6
6
|
healthCheck(ip: string, domain?: string): Promise<HealthResult>;
|
|
7
7
|
createBackup(ip: string, serverName: string, provider: string): Promise<PlatformBackupResult>;
|
|
8
|
-
restoreBackup(ip: string, backupPath: string,
|
|
8
|
+
restoreBackup(ip: string, backupPath: string, manifest: BackupManifest, options?: {
|
|
9
|
+
force?: boolean;
|
|
10
|
+
}): Promise<PlatformRestoreResult>;
|
|
9
11
|
getStatus(ip: string): Promise<PlatformStatusResult>;
|
|
10
12
|
update(ip: string): Promise<UpdateResult>;
|
|
11
|
-
private
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
-
private buildCleanupCommand;
|
|
15
|
-
private buildVersionCommand;
|
|
13
|
+
private versionCmd;
|
|
14
|
+
private backupConfig;
|
|
15
|
+
private restoreConfig;
|
|
16
16
|
}
|
|
17
17
|
//# sourceMappingURL=dokploy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dokploy.d.ts","sourceRoot":"","sources":["../../src/adapters/dokploy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dokploy.d.ts","sourceRoot":"","sources":["../../src/adapters/dokploy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAKxD,qBAAa,cAAe,YAAW,eAAe;IACpD,QAAQ,CAAC,IAAI,aAAa;IAE1B,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IA4ElC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI/D,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC;IAI1B,aAAa,CACjB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAI3B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAIpD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAM/C,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,aAAa;CActB"}
|
package/dist/adapters/dokploy.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
1
|
import { DOKPLOY_UPDATE_CMD } from "../constants.js";
|
|
4
|
-
import {
|
|
5
|
-
import { formatTimestamp, getBackupDir, scpDownload, scpUpload, } from "../core/backup.js";
|
|
6
|
-
import { getErrorMessage, mapSshError, sanitizeStderr } from "../utils/errorMapper.js";
|
|
7
|
-
import { sharedHealthCheck, sharedUpdate, sharedGetStatus } from "./shared.js";
|
|
2
|
+
import { sharedHealthCheck, sharedUpdate, sharedGetStatus, sharedCreateBackup, sharedRestoreBackup } from "./shared.js";
|
|
8
3
|
export class DokployAdapter {
|
|
9
4
|
name = "dokploy";
|
|
10
5
|
getCloudInit(serverName) {
|
|
@@ -86,206 +81,45 @@ echo "Then access your instance at: http://YOUR_SERVER_IP:3000"
|
|
|
86
81
|
return sharedHealthCheck(ip, 3000, domain);
|
|
87
82
|
}
|
|
88
83
|
async createBackup(ip, serverName, provider) {
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
// Step 1: Get Dokploy version (best-effort)
|
|
92
|
-
const versionResult = await sshExec(ip, this.buildVersionCommand());
|
|
93
|
-
const dokployVersion = versionResult.code === 0 ? versionResult.stdout.trim() : "unknown";
|
|
94
|
-
// Step 2: Database backup
|
|
95
|
-
const dbResult = await sshExec(ip, this.buildPgDumpCommand());
|
|
96
|
-
if (dbResult.code !== 0) {
|
|
97
|
-
return {
|
|
98
|
-
success: false,
|
|
99
|
-
error: "Database backup failed",
|
|
100
|
-
hint: sanitizeStderr(dbResult.stderr) || undefined,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
// Step 3: Config backup
|
|
104
|
-
const configResult = await sshExec(ip, this.buildConfigTarCommand());
|
|
105
|
-
if (configResult.code !== 0) {
|
|
106
|
-
return {
|
|
107
|
-
success: false,
|
|
108
|
-
error: "Config backup failed",
|
|
109
|
-
hint: sanitizeStderr(configResult.stderr) || undefined,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
// Step 4: Create local directory and download
|
|
113
|
-
const timestamp = formatTimestamp(new Date());
|
|
114
|
-
const backupPath = join(getBackupDir(serverName), timestamp);
|
|
115
|
-
mkdirSync(backupPath, { recursive: true, mode: 0o700 });
|
|
116
|
-
const dbDl = await scpDownload(ip, "/tmp/dokploy-backup.sql.gz", join(backupPath, "dokploy-backup.sql.gz"));
|
|
117
|
-
if (dbDl.code !== 0) {
|
|
118
|
-
return {
|
|
119
|
-
success: false,
|
|
120
|
-
error: "Failed to download database backup",
|
|
121
|
-
hint: sanitizeStderr(dbDl.stderr) || undefined,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
const configDl = await scpDownload(ip, "/tmp/dokploy-config.tar.gz", join(backupPath, "dokploy-config.tar.gz"));
|
|
125
|
-
if (configDl.code !== 0) {
|
|
126
|
-
return {
|
|
127
|
-
success: false,
|
|
128
|
-
error: "Failed to download config backup",
|
|
129
|
-
hint: sanitizeStderr(configDl.stderr) || undefined,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
// Step 5: Write manifest
|
|
133
|
-
const manifest = {
|
|
134
|
-
serverName,
|
|
135
|
-
provider,
|
|
136
|
-
timestamp,
|
|
137
|
-
coolifyVersion: dokployVersion, // Reuse field for backward compat
|
|
138
|
-
files: ["dokploy-backup.sql.gz", "dokploy-config.tar.gz"],
|
|
139
|
-
platform: "dokploy",
|
|
140
|
-
};
|
|
141
|
-
writeFileSync(join(backupPath, "manifest.json"), JSON.stringify(manifest, null, 2), { mode: 0o600 });
|
|
142
|
-
// Step 6: Cleanup remote (best-effort)
|
|
143
|
-
await sshExec(ip, this.buildCleanupCommand()).catch(() => { });
|
|
144
|
-
return { success: true, backupPath, manifest };
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
const hint = mapSshError(error, ip);
|
|
148
|
-
return {
|
|
149
|
-
success: false,
|
|
150
|
-
error: getErrorMessage(error),
|
|
151
|
-
...(hint ? { hint } : {}),
|
|
152
|
-
};
|
|
153
|
-
}
|
|
84
|
+
return sharedCreateBackup(ip, serverName, provider, this.backupConfig());
|
|
154
85
|
}
|
|
155
|
-
async restoreBackup(ip, backupPath,
|
|
156
|
-
|
|
157
|
-
const steps = [];
|
|
158
|
-
try {
|
|
159
|
-
// Upload backup files (before stopping Dokploy -- safe to fail here)
|
|
160
|
-
const dbUpload = await scpUpload(ip, join(backupPath, "dokploy-backup.sql.gz"), "/tmp/dokploy-backup.sql.gz");
|
|
161
|
-
if (dbUpload.code !== 0) {
|
|
162
|
-
return {
|
|
163
|
-
success: false,
|
|
164
|
-
steps: [
|
|
165
|
-
{
|
|
166
|
-
name: "Upload database backup",
|
|
167
|
-
status: "failure",
|
|
168
|
-
error: sanitizeStderr(dbUpload.stderr),
|
|
169
|
-
},
|
|
170
|
-
],
|
|
171
|
-
error: "Failed to upload database backup",
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
steps.push({ name: "Upload database backup", status: "success" });
|
|
175
|
-
const configUpload = await scpUpload(ip, join(backupPath, "dokploy-config.tar.gz"), "/tmp/dokploy-config.tar.gz");
|
|
176
|
-
if (configUpload.code !== 0) {
|
|
177
|
-
return {
|
|
178
|
-
success: false,
|
|
179
|
-
steps: [
|
|
180
|
-
...steps,
|
|
181
|
-
{
|
|
182
|
-
name: "Upload config backup",
|
|
183
|
-
status: "failure",
|
|
184
|
-
error: sanitizeStderr(configUpload.stderr),
|
|
185
|
-
},
|
|
186
|
-
],
|
|
187
|
-
error: "Failed to upload config backup",
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
steps.push({ name: "Upload config backup", status: "success" });
|
|
191
|
-
// Step 1: Stop Dokploy (scale to 0)
|
|
192
|
-
const stopResult = await sshExec(ip, "docker service scale dokploy=0");
|
|
193
|
-
if (stopResult.code !== 0) {
|
|
194
|
-
steps.push({
|
|
195
|
-
name: "Stop Dokploy",
|
|
196
|
-
status: "failure",
|
|
197
|
-
error: sanitizeStderr(stopResult.stderr),
|
|
198
|
-
});
|
|
199
|
-
return { success: false, steps, error: "Failed to stop Dokploy" };
|
|
200
|
-
}
|
|
201
|
-
steps.push({ name: "Stop Dokploy", status: "success" });
|
|
202
|
-
// Step 2: Start postgres (ensure DB is running)
|
|
203
|
-
const dbStartResult = await sshExec(ip, "docker service scale dokploy-postgres=1 && sleep 5");
|
|
204
|
-
if (dbStartResult.code !== 0) {
|
|
205
|
-
steps.push({
|
|
206
|
-
name: "Start database",
|
|
207
|
-
status: "failure",
|
|
208
|
-
error: sanitizeStderr(dbStartResult.stderr),
|
|
209
|
-
});
|
|
210
|
-
await this.tryRestartDokploy(ip);
|
|
211
|
-
return { success: false, steps, error: "Failed to start database" };
|
|
212
|
-
}
|
|
213
|
-
steps.push({ name: "Start database", status: "success" });
|
|
214
|
-
// Step 3: Restore database
|
|
215
|
-
const restoreDbResult = await sshExec(ip, "gunzip -c /tmp/dokploy-backup.sql.gz | docker exec -i $(docker ps -qf name=dokploy-postgres --no-trunc | head -1) psql -U postgres -d dokploy");
|
|
216
|
-
if (restoreDbResult.code !== 0) {
|
|
217
|
-
steps.push({
|
|
218
|
-
name: "Restore database",
|
|
219
|
-
status: "failure",
|
|
220
|
-
error: sanitizeStderr(restoreDbResult.stderr),
|
|
221
|
-
});
|
|
222
|
-
await this.tryRestartDokploy(ip);
|
|
223
|
-
return { success: false, steps, error: "Database restore failed" };
|
|
224
|
-
}
|
|
225
|
-
steps.push({ name: "Restore database", status: "success" });
|
|
226
|
-
// Step 4: Restore config
|
|
227
|
-
const restoreConfigResult = await sshExec(ip, "tar xzf /tmp/dokploy-config.tar.gz -C /etc/dokploy");
|
|
228
|
-
if (restoreConfigResult.code !== 0) {
|
|
229
|
-
steps.push({
|
|
230
|
-
name: "Restore config",
|
|
231
|
-
status: "failure",
|
|
232
|
-
error: sanitizeStderr(restoreConfigResult.stderr),
|
|
233
|
-
});
|
|
234
|
-
await this.tryRestartDokploy(ip);
|
|
235
|
-
return { success: false, steps, error: "Config restore failed" };
|
|
236
|
-
}
|
|
237
|
-
steps.push({ name: "Restore config", status: "success" });
|
|
238
|
-
// Step 5: Start Dokploy
|
|
239
|
-
const startResult = await sshExec(ip, "docker service scale dokploy=1");
|
|
240
|
-
if (startResult.code !== 0) {
|
|
241
|
-
steps.push({
|
|
242
|
-
name: "Start Dokploy",
|
|
243
|
-
status: "failure",
|
|
244
|
-
error: sanitizeStderr(startResult.stderr),
|
|
245
|
-
});
|
|
246
|
-
return { success: false, steps, error: "Failed to start Dokploy" };
|
|
247
|
-
}
|
|
248
|
-
steps.push({ name: "Start Dokploy", status: "success" });
|
|
249
|
-
// Cleanup remote (best-effort)
|
|
250
|
-
await sshExec(ip, this.buildCleanupCommand()).catch(() => { });
|
|
251
|
-
return { success: true, steps };
|
|
252
|
-
}
|
|
253
|
-
catch (error) {
|
|
254
|
-
const hint = mapSshError(error, ip);
|
|
255
|
-
return {
|
|
256
|
-
success: false,
|
|
257
|
-
steps,
|
|
258
|
-
error: getErrorMessage(error),
|
|
259
|
-
...(hint ? { hint } : {}),
|
|
260
|
-
};
|
|
261
|
-
}
|
|
86
|
+
async restoreBackup(ip, backupPath, manifest, options) {
|
|
87
|
+
return sharedRestoreBackup(ip, backupPath, manifest, this.restoreConfig(), options);
|
|
262
88
|
}
|
|
263
89
|
async getStatus(ip) {
|
|
264
|
-
return sharedGetStatus(ip, this.
|
|
90
|
+
return sharedGetStatus(ip, this.versionCmd(), 3000);
|
|
265
91
|
}
|
|
266
92
|
async update(ip) {
|
|
267
93
|
return sharedUpdate(ip, DOKPLOY_UPDATE_CMD);
|
|
268
94
|
}
|
|
269
|
-
// --- Private
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
await sshExec(ip, "docker service scale dokploy=1");
|
|
273
|
-
}
|
|
274
|
-
catch {
|
|
275
|
-
// Best-effort -- swallow errors
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
buildPgDumpCommand() {
|
|
279
|
-
return "set -o pipefail && docker exec $(docker ps -qf name=dokploy-postgres --no-trunc | head -1) pg_dump -U postgres -d dokploy | gzip > /tmp/dokploy-backup.sql.gz";
|
|
280
|
-
}
|
|
281
|
-
buildConfigTarCommand() {
|
|
282
|
-
return "tar czf /tmp/dokploy-config.tar.gz -C /etc/dokploy .";
|
|
95
|
+
// --- Private Config Builders ------------------------------------------------
|
|
96
|
+
versionCmd() {
|
|
97
|
+
return "docker inspect dokploy --format '{{.Config.Image}}' 2>/dev/null | sed 's/.*://' || echo unknown";
|
|
283
98
|
}
|
|
284
|
-
|
|
285
|
-
return
|
|
99
|
+
backupConfig() {
|
|
100
|
+
return {
|
|
101
|
+
platform: "dokploy",
|
|
102
|
+
pgDumpCmd: "set -o pipefail && docker exec $(docker ps -qf name=dokploy-postgres --no-trunc | head -1) pg_dump -U postgres -d dokploy | gzip > /tmp/dokploy-backup.sql.gz",
|
|
103
|
+
configTarCmd: "tar czf /tmp/dokploy-config.tar.gz -C /etc/dokploy .",
|
|
104
|
+
versionCmd: this.versionCmd(),
|
|
105
|
+
cleanupCmd: "rm -f /tmp/dokploy-backup.sql.gz /tmp/dokploy-config.tar.gz",
|
|
106
|
+
dbFileName: "dokploy-backup.sql.gz",
|
|
107
|
+
configFileName: "dokploy-config.tar.gz",
|
|
108
|
+
};
|
|
286
109
|
}
|
|
287
|
-
|
|
288
|
-
return
|
|
110
|
+
restoreConfig() {
|
|
111
|
+
return {
|
|
112
|
+
platform: "dokploy",
|
|
113
|
+
stopCmd: "docker service scale dokploy=0",
|
|
114
|
+
startDbCmd: "docker service scale dokploy-postgres=1 && sleep 5",
|
|
115
|
+
restoreDbCmd: "gunzip -c /tmp/dokploy-backup.sql.gz | docker exec -i $(docker ps -qf name=dokploy-postgres --no-trunc | head -1) psql -U postgres -d dokploy",
|
|
116
|
+
restoreConfigCmd: "tar xzf /tmp/dokploy-config.tar.gz -C /etc/dokploy",
|
|
117
|
+
startCmd: "docker service scale dokploy=1",
|
|
118
|
+
cleanupCmd: "rm -f /tmp/dokploy-backup.sql.gz /tmp/dokploy-config.tar.gz",
|
|
119
|
+
tryRestartCmd: "docker service scale dokploy=1",
|
|
120
|
+
dbFileName: "dokploy-backup.sql.gz",
|
|
121
|
+
configFileName: "dokploy-config.tar.gz",
|
|
122
|
+
};
|
|
289
123
|
}
|
|
290
124
|
}
|
|
291
125
|
//# sourceMappingURL=dokploy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dokploy.js","sourceRoot":"","sources":["../../src/adapters/dokploy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dokploy.js","sourceRoot":"","sources":["../../src/adapters/dokploy.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGxH,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,SAAS,CAAC;IAE1B,YAAY,CAAC,UAAkB;QAC7B,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACvD,OAAO;;;;;;;;gBAQK,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+DvB,CAAC;IACA,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,EAAU,EAAE,MAAe;QAC3C,OAAO,iBAAiB,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,EAAU,EACV,UAAkB,EAClB,QAAgB;QAEhB,OAAO,kBAAkB,CAAC,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,EAAU,EACV,UAAkB,EAClB,QAAwB,EACxB,OAA6B;QAE7B,OAAO,mBAAmB,CAAC,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,OAAO,CAAC,CAAC;IACtF,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,OAAO,eAAe,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,OAAO,YAAY,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC;IAC9C,CAAC;IAED,+EAA+E;IAEvE,UAAU;QAChB,OAAO,iGAAiG,CAAC;IAC3G,CAAC;IAEO,YAAY;QAClB,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,SAAS,EAAE,+JAA+J;YAC1K,YAAY,EAAE,sDAAsD;YACpE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;YAC7B,UAAU,EAAE,6DAA6D;YACzE,UAAU,EAAE,uBAAuB;YACnC,cAAc,EAAE,uBAAuB;SACxC,CAAC;IACJ,CAAC;IAEO,aAAa;QACnB,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,gCAAgC;YACzC,UAAU,EAAE,oDAAoD;YAChE,YAAY,EAAE,+IAA+I;YAC7J,gBAAgB,EAAE,oDAAoD;YACtE,QAAQ,EAAE,gCAAgC;YAC1C,UAAU,EAAE,6DAA6D;YACzE,aAAa,EAAE,gCAAgC;YAC/C,UAAU,EAAE,uBAAuB;YACnC,cAAc,EAAE,uBAAuB;SACxC,CAAC;IACJ,CAAC;CACF"}
|