elestio 1.0.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/LICENSE +21 -0
- package/README.md +262 -0
- package/bin/elestio.js +5 -0
- package/package.json +42 -0
- package/src/api.js +105 -0
- package/src/cli.js +828 -0
- package/src/commands/access.js +132 -0
- package/src/commands/actions.js +427 -0
- package/src/commands/auth.js +146 -0
- package/src/commands/backups.js +215 -0
- package/src/commands/billing.js +106 -0
- package/src/commands/cicd.js +403 -0
- package/src/commands/projects.js +145 -0
- package/src/commands/services.js +294 -0
- package/src/commands/templates.js +188 -0
- package/src/commands/volumes.js +117 -0
- package/src/config.js +84 -0
- package/src/utils.js +162 -0
package/src/utils.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// ── ANSI Colors ──
|
|
2
|
+
|
|
3
|
+
export const colors = {
|
|
4
|
+
reset: '\x1b[0m',
|
|
5
|
+
bold: '\x1b[1m',
|
|
6
|
+
dim: '\x1b[2m',
|
|
7
|
+
red: '\x1b[31m',
|
|
8
|
+
green: '\x1b[32m',
|
|
9
|
+
yellow: '\x1b[33m',
|
|
10
|
+
blue: '\x1b[34m',
|
|
11
|
+
magenta: '\x1b[35m',
|
|
12
|
+
cyan: '\x1b[36m',
|
|
13
|
+
white: '\x1b[37m',
|
|
14
|
+
gray: '\x1b[90m'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// ── Logging ──
|
|
18
|
+
|
|
19
|
+
export function log(type, message) {
|
|
20
|
+
const prefix = {
|
|
21
|
+
info: `${colors.blue}[INFO]${colors.reset}`,
|
|
22
|
+
success: `${colors.green}[SUCCESS]${colors.reset}`,
|
|
23
|
+
error: `${colors.red}[ERROR]${colors.reset}`,
|
|
24
|
+
warn: `${colors.yellow}[WARN]${colors.reset}`,
|
|
25
|
+
debug: `${colors.gray}[DEBUG]${colors.reset}`
|
|
26
|
+
};
|
|
27
|
+
console.log(`${prefix[type] || ''} ${message}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ── Argument parsing ──
|
|
31
|
+
|
|
32
|
+
export function parseArgs(argv) {
|
|
33
|
+
const args = { _: [] };
|
|
34
|
+
let i = 0;
|
|
35
|
+
|
|
36
|
+
while (i < argv.length) {
|
|
37
|
+
const arg = argv[i];
|
|
38
|
+
|
|
39
|
+
if (arg.startsWith('--')) {
|
|
40
|
+
const key = arg.slice(2);
|
|
41
|
+
const next = argv[i + 1];
|
|
42
|
+
|
|
43
|
+
if (next && !next.startsWith('-')) {
|
|
44
|
+
args[key] = next;
|
|
45
|
+
i += 2;
|
|
46
|
+
} else {
|
|
47
|
+
args[key] = true;
|
|
48
|
+
i++;
|
|
49
|
+
}
|
|
50
|
+
} else if (arg.startsWith('-') && arg.length === 2) {
|
|
51
|
+
const key = arg.slice(1);
|
|
52
|
+
const next = argv[i + 1];
|
|
53
|
+
|
|
54
|
+
if (next && !next.startsWith('-')) {
|
|
55
|
+
args[key] = next;
|
|
56
|
+
i += 2;
|
|
57
|
+
} else {
|
|
58
|
+
args[key] = true;
|
|
59
|
+
i++;
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
args._.push(arg);
|
|
63
|
+
i++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return args;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ── Table formatting ──
|
|
71
|
+
|
|
72
|
+
export function formatTable(data, columns) {
|
|
73
|
+
if (!data || data.length === 0) return 'No data';
|
|
74
|
+
|
|
75
|
+
const widths = {};
|
|
76
|
+
columns.forEach(col => { widths[col.key] = col.label.length; });
|
|
77
|
+
|
|
78
|
+
data.forEach(row => {
|
|
79
|
+
columns.forEach(col => {
|
|
80
|
+
const val = String(row[col.key] ?? '');
|
|
81
|
+
widths[col.key] = Math.max(widths[col.key], val.length);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const header = columns.map(col => col.label.padEnd(widths[col.key])).join(' ');
|
|
86
|
+
const separator = columns.map(col => '-'.repeat(widths[col.key])).join(' ');
|
|
87
|
+
const rows = data.map(row =>
|
|
88
|
+
columns.map(col => String(row[col.key] ?? '').padEnd(widths[col.key])).join(' ')
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return [header, separator, ...rows].join('\n');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── Helpers ──
|
|
95
|
+
|
|
96
|
+
export function formatBytes(bytes) {
|
|
97
|
+
if (bytes === 0) return '0 B';
|
|
98
|
+
const k = 1024;
|
|
99
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
100
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
101
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function formatPrice(pricePerHour) {
|
|
105
|
+
const hourly = parseFloat(pricePerHour);
|
|
106
|
+
const monthly = (hourly * 24 * 30).toFixed(2);
|
|
107
|
+
return `$${monthly}/mo`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function validateServerName(name) {
|
|
111
|
+
if (!name) return { valid: false, error: 'Server name is required' };
|
|
112
|
+
if (name.length < 3) return { valid: false, error: 'Server name must be at least 3 characters' };
|
|
113
|
+
if (name.length > 50) return { valid: false, error: 'Server name must be at most 50 characters' };
|
|
114
|
+
if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(name) && name.length > 1) {
|
|
115
|
+
return { valid: false, error: 'Server name must be lowercase alphanumeric with hyphens, cannot start/end with hyphen' };
|
|
116
|
+
}
|
|
117
|
+
return { valid: true };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function sleep(ms) {
|
|
121
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function formatService(svc) {
|
|
125
|
+
const status = svc.status === 'running'
|
|
126
|
+
? `${colors.green}running${colors.reset}`
|
|
127
|
+
: `${colors.yellow}${svc.status}${colors.reset}`;
|
|
128
|
+
|
|
129
|
+
const deployment = svc.deploymentStatus === 'Deployed'
|
|
130
|
+
? `${colors.green}Deployed${colors.reset}`
|
|
131
|
+
: `${colors.yellow}${svc.deploymentStatus}${colors.reset}`;
|
|
132
|
+
|
|
133
|
+
return `
|
|
134
|
+
${colors.bold}${svc.displayName}${colors.reset} (${svc.templateName || 'CI/CD'})
|
|
135
|
+
Status: ${status} | Deployment: ${deployment}
|
|
136
|
+
IP: ${svc.ipv4 || 'pending'}
|
|
137
|
+
URL: https://${svc.cname || 'pending'}/
|
|
138
|
+
vmID: ${svc.vmID} | serverID: ${svc.id}
|
|
139
|
+
Size: ${svc.serverType} (${svc.cores} cores, ${svc.ramGB}GB RAM)
|
|
140
|
+
Provider: ${svc.provider} / ${svc.datacenter || 'N/A'}
|
|
141
|
+
Cost: ${formatPrice(svc.pricePerHour)}`.trim();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function showHelp(command, subcommands) {
|
|
145
|
+
console.log(`\n${colors.bold}Usage:${colors.reset} elestio ${command} <action> [options]\n`);
|
|
146
|
+
console.log(`${colors.bold}Actions:${colors.reset}`);
|
|
147
|
+
Object.entries(subcommands).forEach(([name, desc]) => {
|
|
148
|
+
console.log(` ${colors.cyan}${name.padEnd(25)}${colors.reset} ${desc}`);
|
|
149
|
+
});
|
|
150
|
+
console.log('');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function truncate(str, maxLen = 30) {
|
|
154
|
+
if (!str) return '';
|
|
155
|
+
return str.length > maxLen ? str.slice(0, maxLen - 3) + '...' : str;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ── JSON output helper ──
|
|
159
|
+
|
|
160
|
+
export function outputJson(data) {
|
|
161
|
+
console.log(JSON.stringify(data, null, 2));
|
|
162
|
+
}
|