utilitas 1990.1.28 → 1990.1.31

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.
@@ -0,0 +1,46 @@
1
+ # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2
+ # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
3
+
4
+ name: Node.js Package
5
+
6
+ on:
7
+ push:
8
+ branches: [ master ]
9
+ pull_request:
10
+ branches: [ master ]
11
+
12
+ jobs:
13
+ version:
14
+ runs-on: ubuntu-latest
15
+ if: "!startsWith(github.event.head_commit.message, '[RELEASE]')"
16
+ steps:
17
+ - uses: actions/checkout@v3
18
+ with:
19
+ token: ${{ secrets.GITHUB_TOKEN }}
20
+ - run: git config --global user.name 'Leask Wong'
21
+ - run: git config --global user.email 'i@leaskh.com'
22
+ - run: npm version patch -m "[RELEASE] %s"
23
+ - run: git push
24
+
25
+ build:
26
+ runs-on: ubuntu-latest
27
+ needs: version
28
+ steps:
29
+ - uses: actions/checkout@v3
30
+ - uses: actions/setup-node@v3
31
+ with:
32
+ node-version: 16
33
+ - run: npm test
34
+
35
+ publish-npm:
36
+ needs: build
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@v3
40
+ - uses: actions/setup-node@v3
41
+ with:
42
+ node-version: 16
43
+ registry-url: https://registry.npmjs.org/
44
+ - run: npm publish
45
+ env:
46
+ NODE_AUTH_TOKEN: ${{secrets.npm_token}}
package/README.md CHANGED
@@ -8,3 +8,5 @@ Works in Node.js and modern browsers.
8
8
 
9
9
  tbd...
10
10
  ## TOTO
11
+
12
+ tbd...
package/lib/bot.mjs CHANGED
@@ -4,9 +4,10 @@ import { ensureArray, insensitiveCompare, log as _log } from './utilitas.mjs';
4
4
  import { join } from 'path';
5
5
  import { readdirSync } from 'fs';
6
6
  import { Telegraf } from 'telegraf';
7
+ import cluster from 'cluster';
7
8
 
8
9
  const signals = ['SIGINT', 'SIGTERM'];
9
- const provider = 'TELEGRAM';
10
+ const [BOT_SEND, provider, MESSAGE] = ['BOT_SEND', 'TELEGRAM', 'message'];
10
11
  const iCmp = (strA, strB) => ~~insensitiveCompare(strA, strB, { w: true });
11
12
  const log = (cnt, opt) => _log(cnt, import.meta.url, { time: 1, ...opt || {} });
12
13
  const end = async (options) => bot && bot.stop(options?.signal);
@@ -56,34 +57,49 @@ const init = async (options) => {
56
57
  insensitiveCompare(options?.provider, provider),
57
58
  'Invalid bot provider.', 501
58
59
  );
59
- bot = new Telegraf(options?.botToken);
60
- const [mods, pmsTrain] = [[{
61
- ...subconscious, run: !options?.silent
62
- }, ...ensureArray(options?.skill)], []];
63
- for (let skillPath of ensureArray(options?.skillPath)) {
64
- log(`SKILLS: ${skillPath}`);
65
- const files = (readdirSync(skillPath) || []).filter(
66
- file => /\.mjs$/i.test(file) && !file.startsWith('.')
67
- );
68
- for (let f of files) {
69
- const m = await import(join(skillPath, f));
70
- mods.push({ ...m, name: m.name || f.replace(/^(.*)\.mjs$/i, '$1') });
60
+ if (cluster.isPrimary) {
61
+ bot = new Telegraf(options?.botToken);
62
+ const [mods, pmsTrain] = [[{
63
+ ...subconscious, run: !options?.silent
64
+ }, ...ensureArray(options?.skill)], []];
65
+ for (let skillPath of ensureArray(options?.skillPath)) {
66
+ log(`SKILLS: ${skillPath}`);
67
+ const files = (readdirSync(skillPath) || []).filter(
68
+ file => /\.mjs$/i.test(file) && !file.startsWith('.')
69
+ );
70
+ for (let f of files) {
71
+ const m = await import(join(skillPath, f));
72
+ mods.push({ ...m, name: m.name || f.replace(/^(.*)\.mjs$/i, '$1') });
73
+ }
71
74
  }
75
+ mods.map(mod => { mod.run && pmsTrain.push(load(bot, mod, options)) });
76
+ assert(pmsTrain.length, 'Invalid skill set.', 501);
77
+ await Promise.all(pmsTrain);
78
+ bot.launch();
79
+ cluster.on(MESSAGE, (worker, msg) => eventHandler(msg));
80
+ // Graceful stop
81
+ signals.map(signal => process.once(signal, () => bot.stop(signal)));
82
+ } else {
83
+ bot = {
84
+ telegram: {
85
+ sendMessage: (...args) =>
86
+ process.send({ action: BOT_SEND, data: args })
87
+ }
88
+ };
72
89
  }
73
- mods.map(mod => { mod.run && pmsTrain.push(load(bot, mod, options)) });
74
- assert(pmsTrain.length, 'Invalid skill set.', 501);
75
- await Promise.all(pmsTrain);
76
- bot.launch();
77
- // Graceful stop
78
- signals.map(signal => process.once(signal, () => bot.stop(signal)));
79
90
  }
80
91
  assert(bot, 'Bot have not been initialized.', 501);
81
92
  return bot;
82
93
  };
83
94
 
84
- const send = async (chatId, content, options) => (
85
- await init()
86
- ).telegram.sendMessage(chatId, content);
95
+ const send = async (chatId, content, options) =>
96
+ (await init()).telegram.sendMessage(chatId, content);
97
+
98
+ const eventHandler = async (msg) => {
99
+ switch (msg?.action) {
100
+ case BOT_SEND: return await send(...msg?.data || []);
101
+ }
102
+ };
87
103
 
88
104
  export default init;
89
105
  export {
package/lib/manifest.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  const manifest = {
2
2
  "name": "utilitas",
3
3
  "description": "Just another common utility for JavaScript.",
4
- "version": "1990.1.28",
4
+ "version": "1990.1.29",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
@@ -16,7 +16,7 @@ const manifest = {
16
16
  "url": "https://github.com/Leask/utilitas.git"
17
17
  },
18
18
  "dependencies": {
19
- "@sentry/node": "^6.19.6",
19
+ "@sentry/node": "^6.19.7",
20
20
  "base64url": "^3.0.1",
21
21
  "buffer": "^6.0.3",
22
22
  "fast-geoip": "^1.1.68",
package/lib/network.mjs CHANGED
@@ -4,7 +4,8 @@ import { ensureArray, log as _log, throwError } from './utilitas.mjs';
4
4
  import { getCurrentIp } from './shot.mjs';
5
5
  import { lookup } from 'fast-geoip';
6
6
 
7
- const log = (content) => _log(content, import.meta.url);
7
+ const isLocalhost = host => ['127.0.0.1', '::1', 'localhost'].includes(host);
8
+ const log = content => _log(content, import.meta.url);
8
9
 
9
10
  const ping = async (host, options = { timeout: 3, min_reply: 3 }) => {
10
11
  await assertExist('ping');
@@ -94,6 +95,7 @@ const getCurrentPosition = async () => {
94
95
  export {
95
96
  getCurrentPosition,
96
97
  httping,
98
+ isLocalhost,
97
99
  pickFastestHost,
98
100
  pickFastestHttpServer,
99
101
  ping,
package/lib/shot.mjs CHANGED
@@ -63,7 +63,7 @@ const get = async (url, options) => {
63
63
  ) : [];
64
64
  const meta = options?.refresh || !base ? null : await readJson(cacheMeta);
65
65
  const cache = options?.refresh || !base ? null : await ignoreErrFunc(
66
- async () => { return await fs.readFile(cacheCont); }
66
+ () => fs.readFile(cacheCont)
67
67
  );
68
68
  const headers = meta?.responseHeaders && cache ? {
69
69
  'cache-control': 'max-age=0',
@@ -75,7 +75,7 @@ const get = async (url, options) => {
75
75
  if (options.timeout) {
76
76
  const controller = new AbortController();
77
77
  fetchOptions.signal = controller.signal;
78
- timer = setTimeout(() => { controller.abort(); }, options.timeout);
78
+ timer = setTimeout(() => controller.abort(), options.timeout);
79
79
  }
80
80
  try { r = await fetch(url, fetchOptions); } catch (e) {
81
81
  throwError(e.message.includes('aborted') ? 'Timed out.' : e.message, 500);
package/lib/storage.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { constants, promises as fs, readSync } from 'fs';
1
+ import { constants as consts, promises as fs, readSync } from 'fs';
2
2
  import { ensureString, mergeAtoB, throwError, trim, which } from './utilitas.mjs';
3
3
  import { join } from 'path';
4
4
  import { parse as iniParse, stringify as iniStringify } from 'ini';
@@ -45,42 +45,27 @@ const writeTempFile = async (data, options) => {
45
45
  return filepath;
46
46
  };
47
47
 
48
- const assertPath = async (path, type, mode, message, status = 500, options = {}) => {
49
- let [stat, typeErr, modeErr] = [null, null, null];
50
- try { stat = await fs.stat(path); } catch (err) {
51
- throwError(message || err.message, status, options);
52
- }
48
+ const assertPath = async (path, type, mode, msg, code, options) => {
49
+ var [code, b, E, s, err] = [code || 500, 'Path is not', m => err = msg || m];
50
+ try { s = await fs.stat(path); }
51
+ catch (e) { throwError(msg || e.message, code, options); }
53
52
  switch (String(type || '').toUpperCase()) {
54
- case '*': case '':
55
- break;
56
- case 'F':
57
- typeErr = stat.isFile()
58
- ? null : (message || `Path is not a file: '${path}'.`);
59
- break;
60
- case 'D':
61
- typeErr = stat.isDirectory()
62
- ? null : (message || `Path is not a directory: '${path}'.`);
63
- break;
64
- default:
65
- typeErr = message || `Unsupported path type: '${type}'.`;
53
+ case '*': case '': break;
54
+ case 'F': s.isFile() || E(`${b} a file: '${path}'.`); break;
55
+ case 'D': s.isDirectory() || E(`${b} a directory: '${path}'.`); break;
56
+ default: E(`Unsupported path type: '${type}'.`);
66
57
  }
67
- assert(!typeErr, typeErr, status, options);
58
+ assert(!err, err, code, options);
68
59
  try {
69
60
  switch (String(mode || '').toUpperCase()) {
70
- case '*': case '':
71
- break;
72
- case 'R':
73
- await fs.access(path, constants.R_OK);
74
- break;
75
- case 'W':
76
- await fs.access(path, constants.R_OK | constants.W_OK);
77
- break;
78
- default:
79
- modeErr = message || `Unsupported access mode: '${mode}'.`;
61
+ case '*': case '': break;
62
+ case 'R': await fs.access(path, consts.R_OK); break;
63
+ case 'W': await fs.access(path, consts.R_OK | consts.W_OK); break;
64
+ default: E(`Unsupported access mode: '${mode}'.`);
80
65
  };
81
- } catch (err) { modeErr = message || err.message; }
82
- assert(!modeErr, modeErr, status, options);
83
- return stat;
66
+ } catch (e) { E(e.message); }
67
+ assert(!err, err, code, options);
68
+ return s;
84
69
  };
85
70
 
86
71
  const isTextFile = async (filename, options) => {
package/lib/tape.mjs CHANGED
@@ -10,10 +10,10 @@ const consoleMap = ['log', 'info', 'debug', 'warn', 'error'];
10
10
  const trace = { trace: true };
11
11
  const [TAPE, BOT] = ['TAPE', 'BOT'];
12
12
  const [maxLength, defBufCycle, maxBufCycle] = [4096, 10, 100];
13
- const stdout = (message) => process.stdout.write(`${message}\n`);
13
+ const stdout = message => process.stdout.write(`${message}\n`);
14
14
  const log = (cnt, opt) => _log(cnt, import.meta.url, { time: 1, ...opt || {} });
15
- const getSendTxt = (arr) => arr.map(x => x[1]).join('\n');
16
- const getSndSize = (arr) => getSendTxt(arr).length;
15
+ const getSendTxt = arr => arr.map(x => x[1]).join('\n');
16
+ const getSndSize = arr => getSendTxt(arr).length;
17
17
  const getBufSize = () => maxLength * bufferCycle;
18
18
  const nextLen = () => botBuffer?.[0]?.[1].length || (maxLength + 1);
19
19
  const stringify = any => ensureString(any, trace);
package/lib/utilitas.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { basename as _basename, dirname, join } from 'path';
2
- import { readJson } from './storage.mjs';
1
+ import { assertPath, readJson, } from './storage.mjs';
2
+ import { basename as _basename, dirname, join, sep } from 'path';
3
3
  import { validate as verifyUuid } from 'uuid';
4
4
  import color from './color.mjs';
5
5
 
@@ -292,15 +292,21 @@ const log = (content, filename, options) => {
292
292
 
293
293
  const which = async (any) => {
294
294
  if (!Object.isObject(any)) {
295
- any = any || process.argv[1];
295
+ any = any || import.meta.url;
296
296
  any = any.startsWith('file://') ? fileURLToPath(any) : any;
297
297
  if (!any?.endsWith?.('.json')) {
298
- any = /\.[mc]?js$/i.test(any) ? dirname(any) : any;
299
- any = join(any, 'package.json');
298
+ any = ['/', ...any.split(sep).slice(1)];
299
+ const arrPath = [];
300
+ for (let sub of any) {
301
+ arrPath.push(sub);
302
+ const curPath = join(...arrPath, 'package.json');
303
+ try { await assertPath(curPath, 'F', 'R'); any = curPath; break; }
304
+ catch (e) { }
305
+ }
300
306
  }
301
307
  any = await readJson(any);
302
308
  }
303
- any.name = any.name || _basename(dirname(process.argv[1])) || '';
309
+ any.name = any.name || '';
304
310
  any.versionNormalized = parseVersion(any.version = any.version || '');
305
311
  any.title = `${any.name}${any.version ? (' v' + any.version) : ''}`;
306
312
  any.userAgent = `${any.name}${any.version ? `/${any.version}` : ''}`;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "utilitas",
3
3
  "description": "Just another common utility for JavaScript.",
4
- "version": "1990.1.28",
4
+ "version": "1990.1.31",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
@@ -17,7 +17,7 @@
17
17
  "gitsync": "( git commit -am \"Released @ `date`\" || true ) && git pull && git push",
18
18
  "pack": "./node_modules/.bin/webpack-cli --config webpack.config.mjs",
19
19
  "build": "npm run updep && ( git commit -am 'update dependencies' || true ) && npm version patch && node build.mjs && npm run pack",
20
- "prepublishOnly": "npm run build && npm run gitsync",
20
+ "xprepublishOnly": "npm run build && npm run gitsync",
21
21
  "beta": "npm publish --tag beta"
22
22
  },
23
23
  "author": "Leask Wong <i@leaskh.com>",
@@ -27,7 +27,7 @@
27
27
  "url": "https://github.com/Leask/utilitas.git"
28
28
  },
29
29
  "dependencies": {
30
- "@sentry/node": "^6.19.6",
30
+ "@sentry/node": "^6.19.7",
31
31
  "base64url": "^3.0.1",
32
32
  "buffer": "^6.0.3",
33
33
  "fast-geoip": "^1.1.68",