selfnify-host 1.0.1 → 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/host.js +41 -12
- package/package.json +1 -1
package/host.js
CHANGED
|
@@ -9,7 +9,7 @@ const https = require('https');
|
|
|
9
9
|
const crypto = require('crypto');
|
|
10
10
|
const readline = require('readline');
|
|
11
11
|
|
|
12
|
-
const VERSION = '1.0.
|
|
12
|
+
const VERSION = '1.0.2';
|
|
13
13
|
const DEFAULT_URL = 'https://host.lume.dpdns.org';
|
|
14
14
|
const CONFIG_DIR = path.join(os.homedir(), '.selfnify');
|
|
15
15
|
const CONFIG_FILE = path.join(CONFIG_DIR, 'host.json');
|
|
@@ -254,7 +254,7 @@ function request(method, apiPath, opts) {
|
|
|
254
254
|
});
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
const bp = (name, sub) => '/bots/' + encodeURIComponent(name) + (sub || '');
|
|
257
|
+
const bp = (name, sub) => '/bots/' + encodeURIComponent(String(name).toLowerCase()) + (sub || '');
|
|
258
258
|
|
|
259
259
|
// ----------------------------------------------------------------- helpers
|
|
260
260
|
|
|
@@ -283,7 +283,7 @@ function parseArgs(argv) {
|
|
|
283
283
|
|
|
284
284
|
function requireName(name, usage) {
|
|
285
285
|
if (!name) throw new CliError('which bot? usage: ' + usage);
|
|
286
|
-
return name;
|
|
286
|
+
return String(name).toLowerCase();
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
function parseEnvFile(file) {
|
|
@@ -315,14 +315,19 @@ function parseStart(str) {
|
|
|
315
315
|
let lang = null;
|
|
316
316
|
if (['python', 'python3', 'py'].includes(cmd)) lang = 'python';
|
|
317
317
|
else if (['node', 'nodejs'].includes(cmd)) lang = 'node';
|
|
318
|
+
else if (['ts', 'typescript', 'tsx', 'ts-node'].includes(cmd)) lang = 'typescript';
|
|
318
319
|
else if (['cargo', 'rust'].includes(cmd)) lang = 'rust';
|
|
319
|
-
if (!lang
|
|
320
|
+
if (!lang && ['npm', 'npx', 'pnpm', 'yarn', 'bun'].includes(cmd)) {
|
|
321
|
+
throw new CliError('"' + cmd + '" is not a start command here. Use: start node (JavaScript), start ts (TypeScript), start python or start cargo');
|
|
322
|
+
}
|
|
323
|
+
if (!lang) throw new CliError('don\'t know how to run "' + str + '". Use: python, node, ts or cargo');
|
|
320
324
|
return { lang, entry: tokens[1] || null };
|
|
321
325
|
}
|
|
322
326
|
|
|
323
327
|
function detectStart(dir) {
|
|
324
328
|
const has = (f) => fs.existsSync(path.join(dir, f));
|
|
325
329
|
if (has('Cargo.toml')) return 'cargo';
|
|
330
|
+
if (has('tsconfig.json')) return 'ts';
|
|
326
331
|
if (has('package.json')) return 'node';
|
|
327
332
|
if (has('requirements.txt') || has('main.py') || has('bot.py')) return 'python';
|
|
328
333
|
return null;
|
|
@@ -338,7 +343,26 @@ function nodeMain(dir) {
|
|
|
338
343
|
return 'index.js';
|
|
339
344
|
}
|
|
340
345
|
|
|
341
|
-
|
|
346
|
+
function readPkg(dir) {
|
|
347
|
+
try {
|
|
348
|
+
return JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
349
|
+
} catch (e) {
|
|
350
|
+
return {};
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function hasBuildScript(dir) {
|
|
355
|
+
const pkg = readPkg(dir);
|
|
356
|
+
return Boolean(pkg.scripts && pkg.scripts.build);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function tsMain(dir) {
|
|
360
|
+
const pkg = readPkg(dir);
|
|
361
|
+
if (pkg.main) return pkg.main;
|
|
362
|
+
return hasBuildScript(dir) ? 'dist/index.js' : 'src/index.ts';
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const defaultEntry = (lang) => ({ python: 'main.py', node: 'index.js', typescript: 'dist/index.js', rust: '' }[lang]);
|
|
342
366
|
const sanitizeName = (s) => s.toLowerCase().replace(/[^a-z0-9_-]/g, '-').replace(/^[-_]+/, '').slice(0, 32);
|
|
343
367
|
|
|
344
368
|
async function packDir(dir) {
|
|
@@ -387,7 +411,7 @@ async function installBot(name, lang, progress) {
|
|
|
387
411
|
}
|
|
388
412
|
return secs + 's';
|
|
389
413
|
}
|
|
390
|
-
progress((lang === 'rust' ? 'building, Rust is slow, relax ' : 'installing ') + secs + 's');
|
|
414
|
+
progress((lang === 'rust' ? 'building, Rust is slow, relax ' : lang === 'typescript' ? 'installing and building ' : 'installing ') + secs + 's');
|
|
391
415
|
if (secs > 3600) throw new CliError('install is taking over an hour. Check: host logs ' + name + ' --install');
|
|
392
416
|
}
|
|
393
417
|
}
|
|
@@ -617,10 +641,13 @@ async function deploy(opts, flags) {
|
|
|
617
641
|
if (!startStr) throw new CliError('could not tell the language. Add: start python | node | cargo');
|
|
618
642
|
const parsed = parseStart(startStr);
|
|
619
643
|
const lang = parsed.lang;
|
|
620
|
-
const main = opts.main || parsed.entry || (lang === 'node' ? nodeMain(dir) : defaultEntry(lang));
|
|
621
|
-
const name = opts.name || sanitizeName(path.basename(dir));
|
|
644
|
+
const main = opts.main || parsed.entry || (lang === 'node' ? nodeMain(dir) : lang === 'typescript' ? tsMain(dir) : defaultEntry(lang));
|
|
645
|
+
const name = String(opts.name || sanitizeName(path.basename(dir))).toLowerCase();
|
|
622
646
|
if (!NAME_RE.test(name)) throw new CliError('bad bot name "' + name + '": use a-z, 0-9, _ or -, max 32 characters');
|
|
623
|
-
|
|
647
|
+
const builtOnServer = lang === 'typescript' && !/\.(ts|mts|cts)$/.test(main) && hasBuildScript(dir);
|
|
648
|
+
if (lang !== 'rust' && !builtOnServer && !fs.existsSync(path.join(dir, main))) {
|
|
649
|
+
throw new CliError('main file "' + main + '" not found in ' + dir);
|
|
650
|
+
}
|
|
624
651
|
let mem;
|
|
625
652
|
if (flags.mem !== undefined) {
|
|
626
653
|
mem = parseInt(flags.mem, 10);
|
|
@@ -695,7 +722,7 @@ async function deploy(opts, flags) {
|
|
|
695
722
|
|
|
696
723
|
await next('Uploading', async ({ progress }) => {
|
|
697
724
|
if (bot.status === 'installing') throw new CliError('an install is already running for this bot, try again in a minute');
|
|
698
|
-
if (bot.status === 'running') {
|
|
725
|
+
if (bot.status === 'running' && lang !== 'rust') {
|
|
699
726
|
progress('stopping old version');
|
|
700
727
|
await request('POST', bp(name, '/stop'));
|
|
701
728
|
}
|
|
@@ -735,7 +762,8 @@ async function deploy(opts, flags) {
|
|
|
735
762
|
|
|
736
763
|
let finalLine = '';
|
|
737
764
|
await next('Starting', async () => {
|
|
738
|
-
|
|
765
|
+
const swap = bot.status === 'running' && lang === 'rust';
|
|
766
|
+
await request('POST', bp(name, swap ? '/restart' : '/start'));
|
|
739
767
|
await sleep(4000);
|
|
740
768
|
const now = await request('GET', bp(name));
|
|
741
769
|
if (now.status !== 'running') {
|
|
@@ -775,7 +803,8 @@ function printHelp() {
|
|
|
775
803
|
out(' host <path> start <cmd> main <file> name <bot>');
|
|
776
804
|
out(c.dim(' host ./mybot start node main index.js name mybot'));
|
|
777
805
|
out(c.dim(' host . start python main main.py name musicbot'));
|
|
778
|
-
out(c.dim(' start = python | node | cargo main = file to run name = bot name'));
|
|
806
|
+
out(c.dim(' start = python | node | ts | cargo main = file to run name = bot name'));
|
|
807
|
+
out(c.dim(' TypeScript: host ./mybot start ts name mybot (the server runs your "build" script)'));
|
|
779
808
|
out(c.dim(' leave out start/main/name and it guesses from your folder'));
|
|
780
809
|
out();
|
|
781
810
|
h(' Manage');
|