@powernukkitx/cli 1.0.0 → 1.0.2
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 +186 -203
- package/dist/cli.js +34 -46
- package/dist/commands/backup.d.ts +2 -2
- package/dist/commands/backup.js +23 -24
- package/dist/commands/config.d.ts +1 -1
- package/dist/commands/config.js +60 -61
- package/dist/commands/console.d.ts +2 -2
- package/dist/commands/console.js +98 -99
- package/dist/commands/doctor.d.ts +2 -2
- package/dist/commands/doctor.js +97 -98
- package/dist/commands/info.d.ts +2 -2
- package/dist/commands/info.js +41 -42
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.js +87 -66
- package/dist/commands/install.js +45 -0
- package/dist/commands/logs.d.ts +2 -2
- package/dist/commands/logs.js +60 -61
- package/dist/commands/menu.js +94 -86
- package/dist/commands/plugin/index.d.ts +2 -2
- package/dist/commands/plugin/index.js +13 -13
- package/dist/commands/plugin/info.d.ts +2 -2
- package/dist/commands/plugin/info.js +39 -40
- package/dist/commands/plugin/install.d.ts +2 -2
- package/dist/commands/plugin/install.js +56 -57
- package/dist/commands/plugin/installed.d.ts +2 -2
- package/dist/commands/plugin/installed.js +41 -42
- package/dist/commands/plugin/list.d.ts +2 -2
- package/dist/commands/plugin/list.js +47 -49
- package/dist/commands/plugin/remove.d.ts +2 -2
- package/dist/commands/plugin/remove.js +44 -45
- package/dist/commands/plugin/search.d.ts +2 -2
- package/dist/commands/plugin/search.js +11 -12
- package/dist/commands/plugin/update.d.ts +2 -2
- package/dist/commands/plugin/update.js +52 -53
- package/dist/commands/start.d.ts +2 -2
- package/dist/commands/start.js +74 -75
- package/dist/commands/stop.d.ts +2 -2
- package/dist/commands/stop.js +26 -27
- package/dist/commands/update.d.ts +2 -2
- package/dist/commands/update.js +34 -35
- package/dist/commands/use.d.ts +2 -2
- package/dist/commands/use.js +39 -40
- package/dist/infra/http.js +119 -121
- package/dist/infra/paths.js +15 -20
- package/dist/infra/store.js +24 -27
- package/dist/services/backup.js +34 -40
- package/dist/services/plugins.js +139 -111
- package/dist/services/process.js +41 -43
- package/dist/services/release.js +51 -38
- package/dist/services/server.js +81 -89
- package/dist/ui/output.js +67 -71
- package/dist/ui/prompts.js +26 -30
- package/dist/ui/theme.js +16 -18
- package/package.json +44 -46
- package/dist/bundle.js +0 -18
- package/dist/commands/cfg.d.ts +0 -2
- package/dist/commands/cfg.js +0 -61
- package/dist/commands/lang.d.ts +0 -2
- package/dist/commands/lang.js +0 -28
- package/dist/commands/plugin.d.ts +0 -1
- package/dist/commands/plugin.js +0 -1
- package/dist/core/config.d.ts +0 -13
- package/dist/core/config.js +0 -31
- package/dist/core/network.d.ts +0 -13
- package/dist/core/network.js +0 -139
- package/dist/core/output.d.ts +0 -33
- package/dist/core/output.js +0 -75
- package/dist/core/process.d.ts +0 -10
- package/dist/core/process.js +0 -53
- package/dist/i18n/en.json +0 -174
- package/dist/i18n/fr.json +0 -174
- package/dist/i18n/index.js +0 -58
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/lang/en.json +0 -146
- package/dist/lang/fr.json +0 -146
- package/dist/lang/index.d.ts +0 -7
- package/dist/lang/index.js +0 -83
- package/dist/main.d.ts +0 -2
- package/dist/main.js +0 -28
- package/dist/plugins.json +0 -66
- package/dist/types.d.ts +0 -61
- package/dist/types.js +0 -1
- package/dist/utils/api.d.ts +0 -9
- package/dist/utils/api.js +0 -24
- package/dist/utils/github.d.ts +0 -20
- package/dist/utils/github.js +0 -60
- package/dist/utils/logger.d.ts +0 -15
- package/dist/utils/logger.js +0 -72
- package/dist/utils/pause.d.ts +0 -1
- package/dist/utils/pause.js +0 -6
- package/dist/utils/plugins.d.ts +0 -4
- package/dist/utils/plugins.js +0 -34
- package/dist/utils/server.d.ts +0 -3
- package/dist/utils/server.js +0 -32
- package/dist/utils/updater.d.ts +0 -1
- package/dist/utils/updater.js +0 -86
package/dist/infra/http.js
CHANGED
|
@@ -1,121 +1,119 @@
|
|
|
1
|
-
import https from 'node:https';
|
|
2
|
-
import http from 'node:http';
|
|
3
|
-
import { createWriteStream } from 'node:fs';
|
|
4
|
-
const REDIRECT_CODES = [301, 302, 303, 307, 308];
|
|
5
|
-
export class NetworkError extends Error {
|
|
6
|
-
statusCode;
|
|
7
|
-
constructor(message, statusCode) {
|
|
8
|
-
super(message);
|
|
9
|
-
this.statusCode = statusCode;
|
|
10
|
-
this.name = 'NetworkError';
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
14
|
-
function get(url, timeoutMs, headers) {
|
|
15
|
-
return new Promise((resolve, reject) => {
|
|
16
|
-
const mod = url.startsWith('https') ? https : http;
|
|
17
|
-
const req = mod.get(url, { timeout: timeoutMs, headers }, (res) => {
|
|
18
|
-
let body = '';
|
|
19
|
-
res.on('data', (chunk) => (body += chunk.toString()));
|
|
20
|
-
res.on('end', () => resolve({ statusCode: res.statusCode ?? 0, location: res.headers.location, body }));
|
|
21
|
-
res.on('error', reject);
|
|
22
|
-
});
|
|
23
|
-
req.on('error', reject);
|
|
24
|
-
req.on('timeout', function () {
|
|
25
|
-
this.destroy();
|
|
26
|
-
reject(new NetworkError('Request timed out'));
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
async function getFollow(url, timeout, headers, redirects = 5) {
|
|
31
|
-
if (redirects <= 0)
|
|
32
|
-
throw new NetworkError('Too many redirects');
|
|
33
|
-
const res = await get(url, timeout, { 'User-Agent': 'pnx-cli', ...headers });
|
|
34
|
-
if (REDIRECT_CODES.includes(res.statusCode) && res.location) {
|
|
35
|
-
return getFollow(res.location, timeout, headers, redirects - 1);
|
|
36
|
-
}
|
|
37
|
-
if (res.statusCode !== 200)
|
|
38
|
-
throw new NetworkError(`HTTP ${res.statusCode}`, res.statusCode);
|
|
39
|
-
return res.body;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
res.
|
|
79
|
-
|
|
80
|
-
file.on('
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
req.on('
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
throw lastErr;
|
|
121
|
-
}
|
|
1
|
+
import https from 'node:https';
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
import { createWriteStream } from 'node:fs';
|
|
4
|
+
const REDIRECT_CODES = [301, 302, 303, 307, 308];
|
|
5
|
+
export class NetworkError extends Error {
|
|
6
|
+
statusCode;
|
|
7
|
+
constructor(message, statusCode) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
this.name = 'NetworkError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
14
|
+
function get(url, timeoutMs, headers) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const mod = url.startsWith('https') ? https : http;
|
|
17
|
+
const req = mod.get(url, { timeout: timeoutMs, headers }, (res) => {
|
|
18
|
+
let body = '';
|
|
19
|
+
res.on('data', (chunk) => (body += chunk.toString()));
|
|
20
|
+
res.on('end', () => resolve({ statusCode: res.statusCode ?? 0, location: res.headers.location, body }));
|
|
21
|
+
res.on('error', reject);
|
|
22
|
+
});
|
|
23
|
+
req.on('error', reject);
|
|
24
|
+
req.on('timeout', function () {
|
|
25
|
+
this.destroy();
|
|
26
|
+
reject(new NetworkError('Request timed out'));
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async function getFollow(url, timeout, headers, redirects = 5) {
|
|
31
|
+
if (redirects <= 0)
|
|
32
|
+
throw new NetworkError('Too many redirects');
|
|
33
|
+
const res = await get(url, timeout, { 'User-Agent': 'pnx-cli', ...headers });
|
|
34
|
+
if (REDIRECT_CODES.includes(res.statusCode) && res.location) {
|
|
35
|
+
return getFollow(res.location, timeout, headers, redirects - 1);
|
|
36
|
+
}
|
|
37
|
+
if (res.statusCode !== 200)
|
|
38
|
+
throw new NetworkError(`HTTP ${res.statusCode}`, res.statusCode);
|
|
39
|
+
return res.body;
|
|
40
|
+
}
|
|
41
|
+
export async function fetchJSON(url, opts) {
|
|
42
|
+
const retries = opts?.retries ?? 3;
|
|
43
|
+
const timeout = opts?.timeout ?? 15_000;
|
|
44
|
+
const headers = opts?.headers ?? {};
|
|
45
|
+
let lastErr = new Error('Unknown error');
|
|
46
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(await getFollow(url, timeout, headers));
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
lastErr = err;
|
|
52
|
+
if (attempt < retries) {
|
|
53
|
+
opts?.onRetry?.(lastErr.message, attempt, retries);
|
|
54
|
+
await sleep(2 ** (attempt - 1) * 1000);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
throw lastErr;
|
|
59
|
+
}
|
|
60
|
+
function stream(url, dest, timeout, onData) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
const mod = url.startsWith('https') ? https : http;
|
|
63
|
+
const file = createWriteStream(dest);
|
|
64
|
+
const req = mod.get(url, { timeout, headers: { 'User-Agent': 'pnx-cli' } }, (res) => {
|
|
65
|
+
const code = res.statusCode ?? 0;
|
|
66
|
+
if (REDIRECT_CODES.includes(code) && res.headers.location) {
|
|
67
|
+
file.close();
|
|
68
|
+
resolve(stream(res.headers.location, dest, timeout, onData));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (code !== 200) {
|
|
72
|
+
file.close();
|
|
73
|
+
reject(new NetworkError(`HTTP ${code}`, code));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const total = parseInt(res.headers['content-length'] || '0', 10);
|
|
77
|
+
res.on('data', (chunk) => onData(chunk, total));
|
|
78
|
+
res.pipe(file);
|
|
79
|
+
file.on('finish', () => { file.close(); resolve(); });
|
|
80
|
+
file.on('error', reject);
|
|
81
|
+
});
|
|
82
|
+
req.on('error', err => { file.close(); reject(err); });
|
|
83
|
+
req.on('timeout', function () {
|
|
84
|
+
this.destroy();
|
|
85
|
+
file.close();
|
|
86
|
+
reject(new NetworkError('Download timed out'));
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export async function downloadFile(url, dest, opts) {
|
|
91
|
+
const retries = opts?.retries ?? 3;
|
|
92
|
+
const timeout = opts?.timeout ?? 120_000;
|
|
93
|
+
let lastErr = new Error('Unknown error');
|
|
94
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
95
|
+
try {
|
|
96
|
+
let downloaded = 0;
|
|
97
|
+
let lastPct = -1;
|
|
98
|
+
await stream(url, dest, timeout, (chunk, total) => {
|
|
99
|
+
downloaded += chunk.length;
|
|
100
|
+
if (opts?.onProgress && total > 0) {
|
|
101
|
+
const pct = Math.round((downloaded / total) * 100);
|
|
102
|
+
if (pct !== lastPct && pct % 5 === 0) {
|
|
103
|
+
opts.onProgress(pct, downloaded, total);
|
|
104
|
+
lastPct = pct;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
lastErr = err;
|
|
112
|
+
if (attempt < retries) {
|
|
113
|
+
opts?.onRetry?.(lastErr.message, attempt, retries);
|
|
114
|
+
await sleep(2 ** (attempt - 1) * 1000);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
throw lastErr;
|
|
119
|
+
}
|
package/dist/infra/paths.js
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import { homedir } from 'node:os';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export const SCRIPTS_BASE = 'https://raw.githubusercontent.com/PowerNukkitX/scripts/master';
|
|
17
|
-
/** Base de l'API marketplace, surchargeable via PNX_API_URL. */
|
|
18
|
-
export function apiBase() {
|
|
19
|
-
return (process.env.PNX_API_URL ?? 'https://api.powernukkitx.org').replace(/\/$/, '');
|
|
20
|
-
}
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export function pnxHome() {
|
|
4
|
+
return process.env.PNX_HOME || join(homedir(), '.pnx-cli');
|
|
5
|
+
}
|
|
6
|
+
export function storePath(name) {
|
|
7
|
+
return join(pnxHome(), name);
|
|
8
|
+
}
|
|
9
|
+
export const JAR_NAME = 'powernukkitx.jar';
|
|
10
|
+
export const GITHUB_LATEST_RELEASE = 'https://api.github.com/repos/PowerNukkitX/PowerNukkitX/releases/latest';
|
|
11
|
+
export const GITHUB_RELEASES = 'https://api.github.com/repos/PowerNukkitX/PowerNukkitX/releases';
|
|
12
|
+
export const SCRIPTS_BASE = 'https://raw.githubusercontent.com/PowerNukkitX/scripts/master';
|
|
13
|
+
export function apiBase() {
|
|
14
|
+
return (process.env.PNX_API_URL ?? 'https://api.powernukkitx.org').replace(/\/$/, '');
|
|
15
|
+
}
|
package/dist/infra/store.js
CHANGED
|
@@ -1,27 +1,24 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile, writeFile, mkdir, rm } from 'node:fs/promises';
|
|
3
|
-
import { dirname } from 'node:path';
|
|
4
|
-
import { storePath } from './paths.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
catch { /* absent */ }
|
|
27
|
-
}
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readFile, writeFile, mkdir, rm } from 'node:fs/promises';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
import { storePath } from './paths.js';
|
|
5
|
+
export async function readJson(name, fallback) {
|
|
6
|
+
try {
|
|
7
|
+
const file = storePath(name);
|
|
8
|
+
if (existsSync(file))
|
|
9
|
+
return JSON.parse(await readFile(file, 'utf-8'));
|
|
10
|
+
}
|
|
11
|
+
catch { }
|
|
12
|
+
return fallback;
|
|
13
|
+
}
|
|
14
|
+
export async function writeJson(name, data) {
|
|
15
|
+
const file = storePath(name);
|
|
16
|
+
await mkdir(dirname(file), { recursive: true });
|
|
17
|
+
await writeFile(file, JSON.stringify(data, null, 2), 'utf-8');
|
|
18
|
+
}
|
|
19
|
+
export async function removeFile(name) {
|
|
20
|
+
try {
|
|
21
|
+
await rm(storePath(name));
|
|
22
|
+
}
|
|
23
|
+
catch { }
|
|
24
|
+
}
|
package/dist/services/backup.js
CHANGED
|
@@ -1,40 +1,34 @@
|
|
|
1
|
-
import { readdirSync, statSync } from 'node:fs';
|
|
2
|
-
import { mkdir, cp, readdir } from 'node:fs/promises';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
const IGNORE = new Set(['logs', 'cache', 'crash-reports', 'backups', '.git']);
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (b < 1024)
|
|
21
|
-
return `${b}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (IGNORE.has(item) || item.startsWith('.'))
|
|
36
|
-
continue;
|
|
37
|
-
await cp(join(serverDir, item), join(destDir, item), { recursive: true, force: true });
|
|
38
|
-
}
|
|
39
|
-
return { path: destDir, size: dirSize(destDir) };
|
|
40
|
-
}
|
|
1
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { mkdir, cp, readdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const IGNORE = new Set(['logs', 'cache', 'crash-reports', 'backups', '.git']);
|
|
5
|
+
export function dirSize(dir) {
|
|
6
|
+
let total = 0;
|
|
7
|
+
try {
|
|
8
|
+
for (const f of readdirSync(dir)) {
|
|
9
|
+
const full = join(dir, f);
|
|
10
|
+
const s = statSync(full);
|
|
11
|
+
total += s.isDirectory() ? dirSize(full) : s.size;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
catch { }
|
|
15
|
+
return total;
|
|
16
|
+
}
|
|
17
|
+
export function fmtSize(b) {
|
|
18
|
+
if (b < 1024)
|
|
19
|
+
return `${b} B`;
|
|
20
|
+
if (b < 1024 ** 2)
|
|
21
|
+
return `${(b / 1024).toFixed(1)} KB`;
|
|
22
|
+
return `${(b / 1024 / 1024).toFixed(1)} MB`;
|
|
23
|
+
}
|
|
24
|
+
export async function createBackup(serverDir) {
|
|
25
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
26
|
+
const destDir = join(serverDir, 'backups', `pnx-backup-${ts}`);
|
|
27
|
+
await mkdir(destDir, { recursive: true });
|
|
28
|
+
for (const item of await readdir(serverDir)) {
|
|
29
|
+
if (IGNORE.has(item) || item.startsWith('.'))
|
|
30
|
+
continue;
|
|
31
|
+
await cp(join(serverDir, item), join(destDir, item), { recursive: true, force: true });
|
|
32
|
+
}
|
|
33
|
+
return { path: destDir, size: dirSize(destDir) };
|
|
34
|
+
}
|