elestio 1.0.2 → 1.0.3
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 -21
- package/README.md +279 -264
- package/bin/elestio.js +5 -5
- package/package.json +42 -42
- package/src/api.js +105 -105
- package/src/cli.js +838 -829
- package/src/commands/access.js +132 -132
- package/src/commands/actions.js +427 -427
- package/src/commands/auth.js +146 -146
- package/src/commands/backups.js +215 -215
- package/src/commands/billing.js +106 -106
- package/src/commands/cicd.js +486 -484
- package/src/commands/projects.js +145 -145
- package/src/commands/services.js +294 -294
- package/src/commands/templates.js +188 -188
- package/src/commands/volumes.js +117 -117
- package/src/config.js +84 -84
- package/src/utils.js +162 -162
package/package.json
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "elestio",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Elestio CLI - Deploy and manage services on the Elestio DevOps platform",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "src/cli.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"elestio": "./bin/elestio.js"
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"start": "node bin/elestio.js"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"elestio",
|
|
15
|
-
"cli",
|
|
16
|
-
"devops",
|
|
17
|
-
"deploy",
|
|
18
|
-
"cloud",
|
|
19
|
-
"hosting",
|
|
20
|
-
"managed",
|
|
21
|
-
"open-source"
|
|
22
|
-
],
|
|
23
|
-
"author": "Elestio <support@elest.io>",
|
|
24
|
-
"license": "MIT",
|
|
25
|
-
"engines": {
|
|
26
|
-
"node": ">=18.0.0"
|
|
27
|
-
},
|
|
28
|
-
"files": [
|
|
29
|
-
"bin/",
|
|
30
|
-
"src/",
|
|
31
|
-
"README.md",
|
|
32
|
-
"LICENSE"
|
|
33
|
-
],
|
|
34
|
-
"repository": {
|
|
35
|
-
"type": "git",
|
|
36
|
-
"url": "https://github.com/elestio/elestio-cli"
|
|
37
|
-
},
|
|
38
|
-
"homepage": "https://elest.io",
|
|
39
|
-
"bugs": {
|
|
40
|
-
"url": "https://github.com/elestio/elestio-cli/issues"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "elestio",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "Elestio CLI - Deploy and manage services on the Elestio DevOps platform",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/cli.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"elestio": "./bin/elestio.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node bin/elestio.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"elestio",
|
|
15
|
+
"cli",
|
|
16
|
+
"devops",
|
|
17
|
+
"deploy",
|
|
18
|
+
"cloud",
|
|
19
|
+
"hosting",
|
|
20
|
+
"managed",
|
|
21
|
+
"open-source"
|
|
22
|
+
],
|
|
23
|
+
"author": "Elestio <support@elest.io>",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin/",
|
|
30
|
+
"src/",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/elestio/elestio-cli"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://elest.io",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/elestio/elestio-cli/issues"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/api.js
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
import { loadConfig, saveConfig, getCredentials } from './config.js';
|
|
2
|
-
import { log } from './utils.js';
|
|
3
|
-
|
|
4
|
-
const BASE_URL = 'https://api.elest.io';
|
|
5
|
-
|
|
6
|
-
// ── JWT management ──
|
|
7
|
-
|
|
8
|
-
function isJwtExpired(config) {
|
|
9
|
-
if (!config.jwt || !config.jwtExpiry) return true;
|
|
10
|
-
return Date.now() > (config.jwtExpiry - 300000); // 5 min buffer
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async function authenticate(email, token) {
|
|
14
|
-
const response = await fetch(`${BASE_URL}/api/auth/checkAPIToken`, {
|
|
15
|
-
method: 'POST',
|
|
16
|
-
headers: { 'Content-Type': 'application/json' },
|
|
17
|
-
body: JSON.stringify({ email, token })
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const data = await response.json();
|
|
21
|
-
|
|
22
|
-
if (data.status !== 'OK' || !data.jwt) {
|
|
23
|
-
throw new Error(data.message || 'Authentication failed');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
jwt: data.jwt,
|
|
28
|
-
jwtExpiry: Date.now() + (23 * 60 * 60 * 1000) // 23h
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function getJwt() {
|
|
33
|
-
const config = loadConfig();
|
|
34
|
-
|
|
35
|
-
if (!config.email || !config.apiToken) {
|
|
36
|
-
throw new Error('Not configured. Run: elestio login');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (isJwtExpired(config)) {
|
|
40
|
-
const auth = await authenticate(config.email, config.apiToken);
|
|
41
|
-
config.jwt = auth.jwt;
|
|
42
|
-
config.jwtExpiry = auth.jwtExpiry;
|
|
43
|
-
saveConfig(config);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return config.jwt;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ── API requests ──
|
|
50
|
-
|
|
51
|
-
export async function apiRequest(endpoint, method = 'POST', body = {}, retried = false) {
|
|
52
|
-
const jwt = await getJwt();
|
|
53
|
-
|
|
54
|
-
const options = {
|
|
55
|
-
method,
|
|
56
|
-
headers: { 'Content-Type': 'application/json' }
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
|
|
60
|
-
options.body = JSON.stringify({ jwt, ...body });
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const url = method === 'GET' && Object.keys(body).length > 0
|
|
64
|
-
? `${BASE_URL}${endpoint}?${new URLSearchParams({ jwt, ...body })}`
|
|
65
|
-
: `${BASE_URL}${endpoint}`;
|
|
66
|
-
|
|
67
|
-
const response = await fetch(url, options);
|
|
68
|
-
|
|
69
|
-
if (response.status === 401 && !retried) {
|
|
70
|
-
const config = loadConfig();
|
|
71
|
-
config.jwt = null;
|
|
72
|
-
config.jwtExpiry = null;
|
|
73
|
-
saveConfig(config);
|
|
74
|
-
return apiRequest(endpoint, method, body, true);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const data = await response.json();
|
|
78
|
-
|
|
79
|
-
const isAuthError = !retried && (
|
|
80
|
-
(data.status === 'error' && data.message?.toLowerCase().includes('auth')) ||
|
|
81
|
-
(data.code === 'InvalidToken') ||
|
|
82
|
-
(data.message?.toLowerCase().includes('invalid token'))
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
if (isAuthError) {
|
|
86
|
-
const config = loadConfig();
|
|
87
|
-
config.jwt = null;
|
|
88
|
-
config.jwtExpiry = null;
|
|
89
|
-
saveConfig(config);
|
|
90
|
-
return apiRequest(endpoint, method, body, true);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return data;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export async function apiRequestNoAuth(endpoint, method = 'GET') {
|
|
97
|
-
const url = `${BASE_URL}${endpoint}`;
|
|
98
|
-
const response = await fetch(url, {
|
|
99
|
-
method,
|
|
100
|
-
headers: { 'Content-Type': 'application/json' }
|
|
101
|
-
});
|
|
102
|
-
return response.json();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export { BASE_URL, authenticate };
|
|
1
|
+
import { loadConfig, saveConfig, getCredentials } from './config.js';
|
|
2
|
+
import { log } from './utils.js';
|
|
3
|
+
|
|
4
|
+
const BASE_URL = 'https://api.elest.io';
|
|
5
|
+
|
|
6
|
+
// ── JWT management ──
|
|
7
|
+
|
|
8
|
+
function isJwtExpired(config) {
|
|
9
|
+
if (!config.jwt || !config.jwtExpiry) return true;
|
|
10
|
+
return Date.now() > (config.jwtExpiry - 300000); // 5 min buffer
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function authenticate(email, token) {
|
|
14
|
+
const response = await fetch(`${BASE_URL}/api/auth/checkAPIToken`, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: { 'Content-Type': 'application/json' },
|
|
17
|
+
body: JSON.stringify({ email, token })
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const data = await response.json();
|
|
21
|
+
|
|
22
|
+
if (data.status !== 'OK' || !data.jwt) {
|
|
23
|
+
throw new Error(data.message || 'Authentication failed');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
jwt: data.jwt,
|
|
28
|
+
jwtExpiry: Date.now() + (23 * 60 * 60 * 1000) // 23h
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function getJwt() {
|
|
33
|
+
const config = loadConfig();
|
|
34
|
+
|
|
35
|
+
if (!config.email || !config.apiToken) {
|
|
36
|
+
throw new Error('Not configured. Run: elestio login');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (isJwtExpired(config)) {
|
|
40
|
+
const auth = await authenticate(config.email, config.apiToken);
|
|
41
|
+
config.jwt = auth.jwt;
|
|
42
|
+
config.jwtExpiry = auth.jwtExpiry;
|
|
43
|
+
saveConfig(config);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return config.jwt;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── API requests ──
|
|
50
|
+
|
|
51
|
+
export async function apiRequest(endpoint, method = 'POST', body = {}, retried = false) {
|
|
52
|
+
const jwt = await getJwt();
|
|
53
|
+
|
|
54
|
+
const options = {
|
|
55
|
+
method,
|
|
56
|
+
headers: { 'Content-Type': 'application/json' }
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
|
|
60
|
+
options.body = JSON.stringify({ jwt, ...body });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const url = method === 'GET' && Object.keys(body).length > 0
|
|
64
|
+
? `${BASE_URL}${endpoint}?${new URLSearchParams({ jwt, ...body })}`
|
|
65
|
+
: `${BASE_URL}${endpoint}`;
|
|
66
|
+
|
|
67
|
+
const response = await fetch(url, options);
|
|
68
|
+
|
|
69
|
+
if (response.status === 401 && !retried) {
|
|
70
|
+
const config = loadConfig();
|
|
71
|
+
config.jwt = null;
|
|
72
|
+
config.jwtExpiry = null;
|
|
73
|
+
saveConfig(config);
|
|
74
|
+
return apiRequest(endpoint, method, body, true);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const data = await response.json();
|
|
78
|
+
|
|
79
|
+
const isAuthError = !retried && (
|
|
80
|
+
(data.status === 'error' && data.message?.toLowerCase().includes('auth')) ||
|
|
81
|
+
(data.code === 'InvalidToken') ||
|
|
82
|
+
(data.message?.toLowerCase().includes('invalid token'))
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (isAuthError) {
|
|
86
|
+
const config = loadConfig();
|
|
87
|
+
config.jwt = null;
|
|
88
|
+
config.jwtExpiry = null;
|
|
89
|
+
saveConfig(config);
|
|
90
|
+
return apiRequest(endpoint, method, body, true);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return data;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function apiRequestNoAuth(endpoint, method = 'GET') {
|
|
97
|
+
const url = `${BASE_URL}${endpoint}`;
|
|
98
|
+
const response = await fetch(url, {
|
|
99
|
+
method,
|
|
100
|
+
headers: { 'Content-Type': 'application/json' }
|
|
101
|
+
});
|
|
102
|
+
return response.json();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { BASE_URL, authenticate };
|