@e-mc/module 0.7.1 → 0.8.1

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.
Files changed (3) hide show
  1. package/index.js +275 -87
  2. package/lib-v4.js +2 -2
  3. package/package.json +3 -2
package/index.js CHANGED
@@ -9,6 +9,7 @@ const crypto = require("crypto");
9
9
  const url = require("url");
10
10
  const filetype = require("file-type");
11
11
  const mime = require("mime-types");
12
+ const pm = require("picomatch");
12
13
  const chalk = require("chalk");
13
14
  const stripansi = require("strip-ansi");
14
15
  const EventEmitter = require("events");
@@ -74,6 +75,7 @@ const SETTINGS = {
74
75
  session_id: 0,
75
76
  message: true,
76
77
  stack_trace: false,
78
+ abort: true,
77
79
  unknown: true,
78
80
  system: true,
79
81
  node: true,
@@ -117,6 +119,14 @@ const VALUES = {
117
119
  ["broadcast.out" /* KEY_NAME.BROADCAST_OUT */]: null,
118
120
  ["logger.level" /* KEY_NAME.LOGGER_LEVEL */]: -1
119
121
  };
122
+ const MEMORY_CACHE_DISK = {
123
+ enabled: false,
124
+ min_size: Infinity,
125
+ max_size: 0,
126
+ expires: Infinity,
127
+ include: null,
128
+ exclude: null
129
+ };
120
130
  const REGEXP_TORRENT = /^(?:magnet:\?xt=|(?:https?|s?ftp):\/\/[^/][^\n]*?\.(?:torrent|metalink|meta4)(?:\?[^\n]*)?$)/i;
121
131
  let LOG_NEWLINE = true;
122
132
  let LOG_EMPTYLINE = false;
@@ -302,14 +312,35 @@ function tryRemoveDir(value, empty, recursive) {
302
312
  }
303
313
  return failed;
304
314
  }
315
+ function tryIncrementDir(value, increment) {
316
+ const baseDir = trimDir(value);
317
+ let i = 0, outErr;
318
+ do {
319
+ try {
320
+ if (tryCreateDir(value)) {
321
+ return [value, i];
322
+ }
323
+ }
324
+ catch (err) {
325
+ if (increment === 0) {
326
+ outErr = err;
327
+ }
328
+ }
329
+ value = baseDir + '_' + ++i;
330
+ } while (increment-- > 0);
331
+ return [outErr, -1];
332
+ }
305
333
  function errorObject(message) {
334
+ if (message instanceof Error) {
335
+ return message;
336
+ }
306
337
  switch (typeof message) {
307
338
  case 'string':
308
339
  return new Error(message);
309
340
  case 'number':
310
341
  return (0, types_1.errorMessage)("Error code" /* ERR_MESSAGE.ERROR_CODE */, message.toString());
311
342
  default:
312
- return message instanceof Error ? message : new Error(Module.asString(message) || "Unknown" /* ERR_MESSAGE.UNKNOWN */);
343
+ return new Error(Module.asString(message) || "Unknown" /* ERR_MESSAGE.UNKNOWN */);
313
344
  }
314
345
  }
315
346
  function isFailed(options) {
@@ -321,17 +352,44 @@ function isFailed(options) {
321
352
  }
322
353
  return false;
323
354
  }
355
+ function recurseCause(err, out, visited) {
356
+ let message;
357
+ if (visited) {
358
+ message = SETTINGS.stack_trace && err.stack || err.message;
359
+ }
360
+ else {
361
+ visited = new WeakSet();
362
+ }
363
+ visited.add(err);
364
+ if (err.hasOwnProperty('cause')) { // eslint-disable-line no-prototype-builtins
365
+ const cause = err.cause;
366
+ if (cause instanceof Error) {
367
+ if (message) {
368
+ out.push(message);
369
+ }
370
+ if (!visited.has(cause)) {
371
+ recurseCause(cause, out, visited);
372
+ }
373
+ return;
374
+ }
375
+ if ((0, types_1.isString)(cause)) {
376
+ message = message ? message + ` (${cause})` : cause; // eslint-disable-line @typescript-eslint/restrict-template-expressions
377
+ }
378
+ }
379
+ if (message) {
380
+ out.push(message);
381
+ }
382
+ }
324
383
  function getErrorMessage(err) {
325
- return SETTINGS.stack_trace && err.stack || err.message || err.toString() || "Unknown" /* ERR_MESSAGE.UNKNOWN */;
384
+ const cause = [];
385
+ recurseCause(err, cause);
386
+ return (SETTINGS.stack_trace && err.stack || err.message || err.toString() || "Unknown" /* ERR_MESSAGE.UNKNOWN */) + (cause.length ? cause.map((value, index) => `\n\nCause #${cause.length - index}: ` + value).join('') : '');
326
387
  }
327
388
  function writeLine(value) {
328
389
  PROCESS_STDOUT.write((!LOG_NEWLINE ? '\n' : '') + value + '\n');
329
390
  LOG_NEWLINE = true;
330
391
  LOG_EMPTYLINE = false;
331
392
  }
332
- function errorPermission(value) {
333
- return (0, types_1.errorValue)("Unsupported access" /* ERR_MESSAGE.UNSUPPORTED_ACCESS */, value);
334
- }
335
393
  function parseFileArgs(options = {}, callback) {
336
394
  let promises;
337
395
  if (typeof options === 'boolean') {
@@ -378,16 +436,40 @@ function getTimeStamp(options, include) {
378
436
  }
379
437
  function getCacheItem(map, key) {
380
438
  const item = map.get(key);
381
- if (item) {
382
- item[0] = Date.now();
383
- return item[1];
439
+ if (!item) {
440
+ return;
384
441
  }
442
+ const current = Date.now();
443
+ if (item[0] + MEMORY_CACHE_DISK.expires >= current) {
444
+ --CACHE_TOTAL;
445
+ map.delete(key);
446
+ return;
447
+ }
448
+ item[0] = current;
449
+ return item[1];
385
450
  }
386
- function addCacheItem(map, key, data) {
387
- if (!map.has(key)) {
388
- ++CACHE_TOTAL;
451
+ function addCacheItem(map, key, data, cache) {
452
+ const length = Buffer.byteLength(data);
453
+ if (length < MEMORY_CACHE_DISK.min_size || length > MEMORY_CACHE_DISK.max_size) {
454
+ return;
455
+ }
456
+ key = Module.toPosix(key, true);
457
+ if (!cache) {
458
+ if (MEMORY_CACHE_DISK.include) {
459
+ if (!MEMORY_CACHE_DISK.include.some(value => pm.isMatch(key, value, { nocase: PLATFORM_WIN32, matchBase: value.startsWith('*') }))) {
460
+ return;
461
+ }
462
+ }
463
+ else {
464
+ cache = true;
465
+ }
466
+ }
467
+ if (!(cache && MEMORY_CACHE_DISK.exclude?.some(value => pm.isMatch(key, value, { nocase: PLATFORM_WIN32, matchBase: value.startsWith('*') })))) {
468
+ if (!map.has(key)) {
469
+ ++CACHE_TOTAL;
470
+ }
471
+ map.set(key, [Date.now(), data]);
389
472
  }
390
- map.set(key, [Date.now(), data]);
391
473
  }
392
474
  function checkFunction(value) {
393
475
  if (typeof value === 'function') {
@@ -399,9 +481,7 @@ function checkFunction(value) {
399
481
  function encryptMessage(data, cipher, algorithm) {
400
482
  var _h;
401
483
  if (cipher?.key && cipher.iv) {
402
- if (!algorithm) {
403
- algorithm = cipher.algorithm || 'aes-256-gcm';
404
- }
484
+ algorithm || (algorithm = cipher.algorithm || 'aes-256-gcm');
405
485
  const result = (0, types_1.encryptUTF8)(algorithm, cipher.key, cipher.iv, data);
406
486
  if (result) {
407
487
  VALUES[_h = "process.cipher.algorithm" /* KEY_NAME.PROCESS_CIPHER_ALGORITHM */] || (VALUES[_h] = algorithm);
@@ -475,9 +555,7 @@ function hasFileSystem(type, value, options, ignoreExists, overwrite) {
475
555
  return result;
476
556
  }
477
557
  function applyLogId(options) {
478
- if (options.sessionId === undefined) {
479
- options.sessionId = this.sessionId;
480
- }
558
+ options.sessionId ?? (options.sessionId = this.sessionId);
481
559
  let value = options.broadcastId;
482
560
  if (value === undefined) {
483
561
  if (value = this.broadcastId) {
@@ -507,35 +585,20 @@ function formatPercent(value, precision = 3) {
507
585
  }
508
586
  return (value * 100).toPrecision(precision) + '%';
509
587
  }
510
- function tryIncrementDir(value, increment) {
511
- const baseDir = trimDir(value);
512
- let i = 0, outErr;
513
- do {
514
- try {
515
- if (tryCreateDir(value)) {
516
- return [value, i];
517
- }
518
- }
519
- catch (err) {
520
- if (increment === 0) {
521
- outErr = err;
522
- }
523
- }
524
- value = baseDir + '_' + ++i;
525
- } while (increment-- > 0);
526
- return [outErr, -1];
527
- }
588
+ const hideAbort = (err) => err.name === 'AbortError' && SETTINGS.abort === false;
528
589
  const asFile = (value) => value instanceof URL ? value.protocol === 'file:' ? url.fileURLToPath(value) : '' : value;
529
590
  const wrapQuote = (value) => '"' + value.replace(/"/g, '\\"') + '"';
530
591
  const isFunction = (value) => typeof value === 'function';
531
592
  const isFileURL = (value) => /^file:\/\//i.test(value);
532
- const errorDirectory = (value) => (0, types_1.errorValue)("Path is not a directory" /* ERR_MESSAGE.NOT_DIRECTORY */, value);
533
593
  const sanitizePath = (value) => (0, types_1.isString)(value) ? path.resolve(value.trim()) : '';
534
- const ensureDir = (value) => value[value.length - 1] !== path.sep ? value + path.sep : value;
535
- const trimDir = (value) => value[value.length - 1] === path.sep ? value.substring(0, value.length - 1) : value;
594
+ const ensureDir = (value) => value.endsWith(path.sep) ? value : value + path.sep;
595
+ const trimDir = (value) => value.endsWith(path.sep) ? value.substring(0, value.length - 1) : value;
536
596
  const getExtension = (value) => path.extname(value).toLowerCase().substring(1);
537
597
  const hasString = (item, value) => (0, types_1.isString)(value) && (item === value || Array.isArray(item) && item.includes(value));
538
598
  const getCpuTimes = () => os.cpus().reduce((a, b) => a + b.times.user + b.times.sys, 0) * 1000 /* TIME.S */;
599
+ const autoMemoryCache = () => MEMORY_CACHE_DISK.enabled && MEMORY_CACHE_DISK.max_size > 0;
600
+ const errorDirectory = (value) => (0, types_1.errorValue)("Path is not a directory" /* ERR_MESSAGE.NOT_DIRECTORY */, value);
601
+ const errorPermission = (value) => (0, types_1.errorValue)("Unsupported access" /* ERR_MESSAGE.UNSUPPORTED_ACCESS */, value);
539
602
  class Module extends EventEmitter {
540
603
  constructor() {
541
604
  super(...arguments);
@@ -558,7 +621,7 @@ class Module extends EventEmitter {
558
621
  this[_f] = new AbortController();
559
622
  this[_g] = null;
560
623
  }
561
- static get VERSION() { return "0.7.1" /* INTERNAL.VERSION */; }
624
+ static get VERSION() { return "0.8.1" /* INTERNAL.VERSION */; }
562
625
  static get LOG_TYPE() { return types_1.LOG_TYPE; }
563
626
  static get STATUS_TYPE() { return types_1.STATUS_TYPE; }
564
627
  static get MAX_TIMEOUT() { return 2147483647; }
@@ -586,6 +649,8 @@ class Module extends EventEmitter {
586
649
  }
587
650
  case "temp.dir" /* KEY_NAME.TEMP_DIR */:
588
651
  return VALUES[key] !== "tmp" /* INTERNAL.TEMP_DIR */;
652
+ case "memory.settings.cache_disk" /* KEY_NAME.MEMORY_SETTINGS_CACHE_DISK */:
653
+ return MEMORY_CACHE_DISK.enabled;
589
654
  case "node.require.npm" /* KEY_NAME.NODE_REQUIRE_NPM */:
590
655
  case "node.require.inline" /* KEY_NAME.NODE_REQUIRE_INLINE */:
591
656
  case "node.process.cpu_usage" /* KEY_NAME.NODE_PROCESS_CPUUSAGE */:
@@ -637,6 +702,10 @@ class Module extends EventEmitter {
637
702
  return true;
638
703
  }
639
704
  static formatMessage(type, title, value, message, options = {}) {
705
+ const error = !!message && message instanceof Error;
706
+ if (error && hideAbort(message)) {
707
+ return;
708
+ }
640
709
  if (options.type) {
641
710
  type |= options.type;
642
711
  }
@@ -675,14 +744,13 @@ class Module extends EventEmitter {
675
744
  const formatValue = format.value;
676
745
  const id = sessionId && SETTINGS.session_id ? ' ' + sessionId.padStart(SETTINGS.session_id, '0') + ' ' : '';
677
746
  const titleIndent = options.titleIndent ? typeof options.titleIndent === 'number' ? Math.max(options.titleIndent, 0) : 0 : -1;
678
- let output, error, hint, valueWidth = Math.max(formatValue.width - (id ? SETTINGS.session_id + 1 : 0), 1), titleJustify = options.titleJustify || ((type & 512 /* LOG_VALUE.FAIL */) || options.failed ? 'center' : formatTitle.justify);
747
+ let output, hint, valueWidth = Math.max(formatValue.width - (id ? SETTINGS.session_id + 1 : 0), 1), titleJustify = options.titleJustify || ((type & 512 /* LOG_VALUE.FAIL */) || options.failed ? 'center' : formatTitle.justify);
679
748
  if (Array.isArray(value)) {
680
749
  hint = value[1] ?? '';
681
750
  value = value[0];
682
751
  }
683
- if (message && message instanceof Error) {
752
+ if (error) {
684
753
  message = getErrorMessage(message);
685
- error = true;
686
754
  }
687
755
  if (messageUnitIndent) {
688
756
  let indentChar;
@@ -724,7 +792,7 @@ class Module extends EventEmitter {
724
792
  indent = match[1];
725
793
  if (bgAltColor) {
726
794
  try {
727
- indent = (bgAltColor[0] === '#' ? chalk.bgHex(bgAltColor) : chalk[bgAltColor])(indent);
795
+ indent = (bgAltColor.startsWith('#') ? chalk.bgHex(bgAltColor) : chalk[bgAltColor])(indent);
728
796
  }
729
797
  catch {
730
798
  }
@@ -747,10 +815,10 @@ class Module extends EventEmitter {
747
815
  try {
748
816
  let current = bold ? chalk.bold : chalk;
749
817
  if (typeof color === 'string' && color.length > 1) {
750
- current = color[0] === '#' ? current.hex(color) : current[color];
818
+ current = color.startsWith('#') ? current.hex(color) : current[color];
751
819
  }
752
820
  if (typeof bgColor === 'string' && bgColor.length > 1) {
753
- current = bgColor[0] === '#' ? current.bgHex(bgColor) : current[bgColor];
821
+ current = bgColor.startsWith('#') ? current.bgHex(bgColor) : current[bgColor];
754
822
  }
755
823
  return indent + current(content);
756
824
  }
@@ -1110,11 +1178,15 @@ class Module extends EventEmitter {
1110
1178
  }
1111
1179
  }
1112
1180
  static async readHash(value, options = {}) {
1113
- const { algorithm = "sha256" /* HASH_OUTPUT.ALGORITHM */, digest = "hex" /* HASH_OUTPUT.DIGEST */, minStreamSize = 0, chunkSize = 2097152000 /* HASH_OUTPUT.CHUNK_SIZE */ } = options;
1114
- const hash = crypto.createHash(algorithm);
1181
+ const { algorithm, digest, chunkSize = 2097152000 /* HASH_OUTPUT.CHUNK_SIZE */ } = options;
1182
+ const hash = crypto.createHash(algorithm || "sha256" /* HASH_OUTPUT.ALGORITHM */);
1115
1183
  try {
1184
+ let minStreamSize = options.minStreamSize || 0;
1185
+ if ((0, types_1.isString)(minStreamSize)) {
1186
+ minStreamSize = (0, types_1.formatSize)(minStreamSize);
1187
+ }
1116
1188
  if (fs.statSync(value).size <= Math.min(minStreamSize > 0 ? minStreamSize : Infinity, 2097152000 /* HASH_OUTPUT.CHUNK_SIZE */)) {
1117
- return hash.update(fs.readFileSync(value)).digest(digest);
1189
+ return hash.update(fs.readFileSync(value)).digest(digest || "hex" /* HASH_OUTPUT.DIGEST */);
1118
1190
  }
1119
1191
  }
1120
1192
  catch (err) {
@@ -1122,7 +1194,7 @@ class Module extends EventEmitter {
1122
1194
  throw err;
1123
1195
  }
1124
1196
  }
1125
- const readable = fs.createReadStream(value);
1197
+ const readable = fs.createReadStream(value, { signal: options.signal });
1126
1198
  const chunks = [];
1127
1199
  let length = 0;
1128
1200
  for await (const chunk of readable) {
@@ -1138,7 +1210,7 @@ class Module extends EventEmitter {
1138
1210
  if (chunks.length) {
1139
1211
  hash.update(Buffer.concat(chunks));
1140
1212
  }
1141
- return hash.digest(digest);
1213
+ return hash.digest(digest || "hex" /* HASH_OUTPUT.DIGEST */);
1142
1214
  }
1143
1215
  static toPosix(value, filename, normalize) {
1144
1216
  if (typeof filename === 'boolean') {
@@ -1291,7 +1363,7 @@ class Module extends EventEmitter {
1291
1363
  let result = paths[0] || '';
1292
1364
  for (let i = 1; i < paths.length; ++i) {
1293
1365
  const trailing = paths[i];
1294
- result += (trailing[0] !== '/' && result[result.length - 1] !== '/' ? '/' : '') + trailing;
1366
+ result += (!trailing.startsWith('/') && !result.endsWith('/') ? '/' : '') + trailing;
1295
1367
  }
1296
1368
  return result;
1297
1369
  }
@@ -1383,7 +1455,7 @@ class Module extends EventEmitter {
1383
1455
  }
1384
1456
  return false;
1385
1457
  }
1386
- static copyDir(src, dest, move, recursive = true) {
1458
+ static async copyDir(src, dest, move, recursive = true) {
1387
1459
  const srcOut = sanitizePath(asFile(src));
1388
1460
  if (!srcOut || !this.isDir(srcOut)) {
1389
1461
  return Promise.reject(errorDirectory(asFile(src) || "Unknown" /* ERR_MESSAGE.UNKNOWN */));
@@ -1539,21 +1611,64 @@ class Module extends EventEmitter {
1539
1611
  }
1540
1612
  return false;
1541
1613
  }
1614
+ static async streamFile(src, cache, options) {
1615
+ if ((0, types_1.isObject)(cache)) {
1616
+ options = cache;
1617
+ }
1618
+ let minStreamSize = 0, encoding, signal;
1619
+ if (options) {
1620
+ ({ minStreamSize = 0, encoding, signal, cache } = options);
1621
+ }
1622
+ return new Promise(async (resolve) => {
1623
+ if ((0, types_1.isString)(minStreamSize)) {
1624
+ minStreamSize = (0, types_1.formatSize)(minStreamSize);
1625
+ }
1626
+ const fileSize = fs.statSync(src).size;
1627
+ let data;
1628
+ if (fileSize >= minStreamSize || fileSize >= 2097152000 /* HASH_OUTPUT.CHUNK_SIZE */) {
1629
+ const readable = fs.createReadStream(src, { signal });
1630
+ const chunks = [];
1631
+ for await (const chunk of readable) {
1632
+ chunks.push(Buffer.from(chunk));
1633
+ }
1634
+ data = Buffer.concat(chunks);
1635
+ if (encoding) {
1636
+ data = data.toString(encoding);
1637
+ }
1638
+ }
1639
+ else {
1640
+ data = fs.readFileSync(src, encoding);
1641
+ }
1642
+ if (cache || cache !== false && autoMemoryCache()) {
1643
+ addCacheItem(encoding ? CACHE_READTEXT : CACHE_READBUFFER, src, data, cache);
1644
+ }
1645
+ resolve(data);
1646
+ });
1647
+ }
1542
1648
  static readText(value, encoding, cache) {
1649
+ let minStreamSize, options;
1543
1650
  if (typeof encoding === 'boolean') {
1544
1651
  cache = encoding;
1545
1652
  encoding = undefined;
1546
1653
  }
1654
+ else if ((0, types_1.isObject)(encoding)) {
1655
+ options = encoding;
1656
+ ({ minStreamSize, encoding, cache } = options);
1657
+ }
1547
1658
  const src = sanitizePath(asFile(value));
1548
1659
  if (src && this.isPath(src, true)) {
1549
1660
  let result;
1550
1661
  if (cache && (result = getCacheItem(CACHE_READTEXT, src))) {
1551
- return result;
1662
+ return (minStreamSize !== undefined ? Promise.resolve(result) : result);
1663
+ }
1664
+ encoding = (0, types_1.getEncoding)(encoding);
1665
+ if (minStreamSize !== undefined) {
1666
+ return this.streamFile(src, options);
1552
1667
  }
1553
1668
  try {
1554
- result = fs.readFileSync(value, (0, types_1.getEncoding)(encoding));
1555
- if (cache && result) {
1556
- addCacheItem(CACHE_READTEXT, src, result);
1669
+ result = fs.readFileSync(value, encoding);
1670
+ if (result && (cache || cache !== false && autoMemoryCache())) {
1671
+ addCacheItem(CACHE_READTEXT, src, result, cache);
1557
1672
  }
1558
1673
  return result;
1559
1674
  }
@@ -1561,19 +1676,27 @@ class Module extends EventEmitter {
1561
1676
  this.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(src)], err, 32 /* LOG_VALUE.FILE */);
1562
1677
  }
1563
1678
  }
1564
- return '';
1679
+ return (minStreamSize !== undefined ? Promise.resolve('') : '');
1565
1680
  }
1566
1681
  static readBuffer(value, cache) {
1682
+ let minStreamSize, options;
1683
+ if ((0, types_1.isObject)(cache)) {
1684
+ options = cache;
1685
+ ({ minStreamSize, cache } = options);
1686
+ }
1567
1687
  const src = sanitizePath(asFile(value));
1568
1688
  if (src && this.isPath(src, true)) {
1569
1689
  let result;
1570
1690
  if (cache && (result = getCacheItem(CACHE_READBUFFER, src))) {
1571
- return result;
1691
+ return (minStreamSize !== undefined ? Promise.resolve(result) : result);
1692
+ }
1693
+ if (minStreamSize !== undefined) {
1694
+ return this.streamFile(src, options);
1572
1695
  }
1573
1696
  try {
1574
1697
  result = fs.readFileSync(value);
1575
- if (cache && result) {
1576
- addCacheItem(CACHE_READBUFFER, src, result);
1698
+ if (result && (cache || cache !== false && autoMemoryCache())) {
1699
+ addCacheItem(CACHE_READBUFFER, src, result, cache);
1577
1700
  }
1578
1701
  return result;
1579
1702
  }
@@ -1581,9 +1704,9 @@ class Module extends EventEmitter {
1581
1704
  this.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(src)], err, 32 /* LOG_VALUE.FILE */);
1582
1705
  }
1583
1706
  }
1584
- return null;
1707
+ return (minStreamSize !== undefined ? Promise.resolve(null) : null);
1585
1708
  }
1586
- static resolveMime(data) {
1709
+ static async resolveMime(data) {
1587
1710
  return typeof data === 'string' ? filetype.fromFile(data) : filetype.fromBuffer(data);
1588
1711
  }
1589
1712
  static lookupMime(value, extension) {
@@ -1869,7 +1992,7 @@ class Module extends EventEmitter {
1869
1992
  return true;
1870
1993
  }
1871
1994
  static sanitizeCmd(value) {
1872
- if (value.indexOf(' ') !== -1) {
1995
+ if (value.includes(' ')) {
1873
1996
  return PLATFORM_WIN32 ? wrapQuote(value) : value.replace(/[ ]/g, '\\ ');
1874
1997
  }
1875
1998
  return value;
@@ -1900,7 +2023,7 @@ class Module extends EventEmitter {
1900
2023
  }
1901
2024
  value = quoted[2];
1902
2025
  }
1903
- if (value.indexOf(' ') !== -1) {
2026
+ if (value.includes(' ')) {
1904
2027
  value = wrapQuote(value);
1905
2028
  }
1906
2029
  }
@@ -1935,7 +2058,7 @@ class Module extends EventEmitter {
1935
2058
  }
1936
2059
  return (typeof values === 'string' ? result[0] : result);
1937
2060
  }
1938
- static purgeMemory(percent = 1, limit = 0) {
2061
+ static async purgeMemory(percent = 1, limit = 0) {
1939
2062
  if (typeof limit === 'boolean') {
1940
2063
  limit = 0;
1941
2064
  }
@@ -1954,9 +2077,15 @@ class Module extends EventEmitter {
1954
2077
  }
1955
2078
  else if (percent > 0) {
1956
2079
  const stored = [];
2080
+ const current = Date.now();
1957
2081
  for (const map of [CACHE_READTEXT, CACHE_READBUFFER, CACHE_READCJS]) {
1958
2082
  for (const [key, value] of map) {
1959
- stored.push([map, key, value[0]]);
2083
+ if (value[0] + MEMORY_CACHE_DISK.expires >= current) {
2084
+ map.delete(key);
2085
+ }
2086
+ else {
2087
+ stored.push([map, key, value[0]]);
2088
+ }
1960
2089
  }
1961
2090
  }
1962
2091
  stored.sort((a, b) => a[2] - b[2]);
@@ -1968,7 +2097,7 @@ class Module extends EventEmitter {
1968
2097
  CACHE_TOTAL = stored.length - result;
1969
2098
  }
1970
2099
  }
1971
- return Promise.resolve(result);
2100
+ return result;
1972
2101
  }
1973
2102
  static canWrite(name) {
1974
2103
  switch (name) {
@@ -2046,11 +2175,44 @@ class Module extends EventEmitter {
2046
2175
  VALUES[_h = "process.password" /* KEY_NAME.PROCESS_PASSWORD */] || (VALUES[_h] = encryptMessage(pwd, cipher));
2047
2176
  }
2048
2177
  }
2049
- if (memory && (0, types_1.isPlainObject)(memory.settings)) {
2050
- const users = memory.settings.users;
2178
+ if ((0, types_1.isPlainObject)(memory?.settings)) {
2179
+ const { users, cache_disk } = memory.settings;
2051
2180
  if (typeof users === 'boolean' || Array.isArray(users)) {
2052
2181
  VALUES["memory.settings.users" /* KEY_NAME.MEMORY_SETTINGS_USERS */] = users;
2053
2182
  }
2183
+ if ((0, types_1.isPlainObject)(cache_disk)) {
2184
+ let { enabled, min_size, max_size, expires, include, exclude } = cache_disk;
2185
+ MEMORY_CACHE_DISK.enabled = enabled === true;
2186
+ if (min_size !== undefined) {
2187
+ if ((0, types_1.isString)(min_size)) {
2188
+ min_size = (0, types_1.formatSize)(min_size);
2189
+ }
2190
+ else if (min_size > 0) {
2191
+ min_size *= 1024;
2192
+ }
2193
+ MEMORY_CACHE_DISK.min_size = min_size > 0 ? min_size : Infinity;
2194
+ }
2195
+ if (max_size !== undefined) {
2196
+ if ((0, types_1.isString)(max_size)) {
2197
+ max_size = (0, types_1.formatSize)(max_size);
2198
+ }
2199
+ else if (max_size > 0) {
2200
+ max_size *= 1024;
2201
+ }
2202
+ MEMORY_CACHE_DISK.max_size = max_size > 0 ? max_size : 0;
2203
+ }
2204
+ if (expires !== undefined && (expires = (0, types_1.parseExpires)(expires)) > 0) {
2205
+ MEMORY_CACHE_DISK.expires = expires;
2206
+ }
2207
+ MEMORY_CACHE_DISK.include = null;
2208
+ MEMORY_CACHE_DISK.exclude = null;
2209
+ if ((0, types_1.isArray)(include)) {
2210
+ MEMORY_CACHE_DISK.include = include.map(value => this.toPosix(value, true));
2211
+ }
2212
+ else if ((0, types_1.isArray)(exclude)) {
2213
+ MEMORY_CACHE_DISK.exclude = exclude.map(value => this.toPosix(value, true));
2214
+ }
2215
+ }
2054
2216
  }
2055
2217
  if ((0, types_1.isPlainObject)(logger)) {
2056
2218
  const { enabled, level, production, broadcast, stack_trace } = logger;
@@ -2176,11 +2338,13 @@ class Module extends EventEmitter {
2176
2338
  }
2177
2339
  break;
2178
2340
  }
2179
- default:
2180
- if (attr in SETTINGS) {
2181
- SETTINGS[attr] = logger[attr];
2341
+ default: {
2342
+ const value = logger[attr];
2343
+ if (attr in SETTINGS && value !== undefined) {
2344
+ SETTINGS[attr] = value;
2182
2345
  }
2183
2346
  break;
2347
+ }
2184
2348
  }
2185
2349
  }
2186
2350
  if (broadcast?.out) {
@@ -2190,7 +2354,7 @@ class Module extends EventEmitter {
2190
2354
  Error.stackTraceLimit = +stack_trace;
2191
2355
  }
2192
2356
  }
2193
- if (error) {
2357
+ if ((0, types_1.isPlainObject)(error)) {
2194
2358
  if (error.out) {
2195
2359
  VALUES["error.out" /* KEY_NAME.ERROR_OUT */] = this.parseFunction(error.out, { external: true, absolute: true });
2196
2360
  }
@@ -2198,7 +2362,7 @@ class Module extends EventEmitter {
2198
2362
  VALUES["error.fatal" /* KEY_NAME.ERROR_FATAL */] = error.fatal;
2199
2363
  }
2200
2364
  }
2201
- if (permission && Array.isArray(permission.process_exec)) {
2365
+ if (Array.isArray(permission?.process_exec)) {
2202
2366
  VALUES["permission.process_exec" /* KEY_NAME.PERMISSION_PROCESS_EXEC */] = permission.process_exec.filter(item => typeof item === 'string' || (0, types_1.isObject)(item) && typeof item.command === 'string').map(exec => {
2203
2367
  if (typeof exec === 'string') {
2204
2368
  return exec.trim();
@@ -2211,12 +2375,11 @@ class Module extends EventEmitter {
2211
2375
  });
2212
2376
  }
2213
2377
  {
2214
- let dir = settings.temp_dir, write;
2378
+ let dir = settings.temp_dir, write, modified;
2215
2379
  if ((0, types_1.isPlainObject)(temp)) {
2216
2380
  dir || (dir = temp.dir);
2217
2381
  write = temp.write;
2218
2382
  }
2219
- let modified;
2220
2383
  if ((0, types_1.isString)(dir) && path.isAbsolute(dir = path.normalize(dir).replace(/[\\/]$/, ''))) {
2221
2384
  if (withinDir(dir, PROCESS_CWD)) {
2222
2385
  dir = dir.substring(ensureDir(PROCESS_CWD).length);
@@ -2311,7 +2474,7 @@ class Module extends EventEmitter {
2311
2474
  result = output;
2312
2475
  }
2313
2476
  if (filename) {
2314
- const trailing = (filename[0] === '.' ? (0, types_1.generateUUID)() : '') + filename;
2477
+ const trailing = (filename.startsWith('.') ? (0, types_1.generateUUID)() : '') + filename;
2315
2478
  if (result) {
2316
2479
  return path.join(result, trailing);
2317
2480
  }
@@ -2365,12 +2528,12 @@ class Module extends EventEmitter {
2365
2528
  let promises, outSrc;
2366
2529
  [options, promises, callback] = parseFileArgs(options, callback);
2367
2530
  if (outSrc = hasFileSystem.call(this, 0 /* FILE_SYSTEM.READ */, src, options)) {
2368
- const { requireExt, cache } = options;
2531
+ let { requireExt, minStreamSize, cache } = options;
2369
2532
  const encoding = options.encoding && (0, types_1.getEncoding)(options.encoding);
2370
2533
  const setCache = (data, cjs) => {
2371
2534
  if (data) {
2372
- if (cache) {
2373
- addCacheItem(cjs ? CACHE_READCJS : encoding ? CACHE_READTEXT : CACHE_READBUFFER, outSrc, data);
2535
+ if (cache || cache !== false && autoMemoryCache()) {
2536
+ addCacheItem(cjs ? CACHE_READCJS : encoding ? CACHE_READTEXT : CACHE_READBUFFER, outSrc, data, cache);
2374
2537
  }
2375
2538
  this.emit('file:read', outSrc, data, options);
2376
2539
  }
@@ -2393,6 +2556,31 @@ class Module extends EventEmitter {
2393
2556
  if (cache) {
2394
2557
  result || (result = (encoding ? getCacheItem(CACHE_READTEXT, outSrc) : getCacheItem(CACHE_READBUFFER, outSrc)));
2395
2558
  }
2559
+ try {
2560
+ if ((0, types_1.isString)(minStreamSize)) {
2561
+ minStreamSize = (0, types_1.formatSize)(minStreamSize);
2562
+ }
2563
+ if (typeof minStreamSize === 'number' || promises && fs.statSync(outSrc).size >= 2097152000 /* HASH_OUTPUT.CHUNK_SIZE */) {
2564
+ if (result) {
2565
+ return Promise.resolve(result);
2566
+ }
2567
+ if (promises || fs.statSync(outSrc).size >= Math.min(minStreamSize || Infinity, 2097152000 /* HASH_OUTPUT.CHUNK_SIZE */)) {
2568
+ return new Promise(async (resolve) => {
2569
+ const readable = fs.createReadStream(outSrc, { signal: this.signal });
2570
+ const chunks = [];
2571
+ for await (const chunk of readable) {
2572
+ chunks.push(Buffer.from(chunk));
2573
+ }
2574
+ const data = Buffer.concat(chunks);
2575
+ resolve((encoding ? data.toString(encoding) : data));
2576
+ });
2577
+ }
2578
+ promises = true;
2579
+ }
2580
+ }
2581
+ catch {
2582
+ promises = true;
2583
+ }
2396
2584
  if (promises) {
2397
2585
  if (result) {
2398
2586
  return Promise.resolve(result);
@@ -2783,7 +2971,7 @@ class Module extends EventEmitter {
2783
2971
  }
2784
2972
  return false;
2785
2973
  }
2786
- allSettled(tasks, rejected, options) {
2974
+ async allSettled(tasks, rejected, options) {
2787
2975
  rejected || (rejected = "Unknown" /* ERR_MESSAGE.UNKNOWN */);
2788
2976
  return Promise.allSettled(tasks).then(result => {
2789
2977
  const items = [];
@@ -3004,7 +3192,7 @@ class Module extends EventEmitter {
3004
3192
  }
3005
3193
  }
3006
3194
  if (message) {
3007
- if (this._logEnabled) {
3195
+ if (this._logEnabled && !(message instanceof Error && hideAbort(message))) {
3008
3196
  if (fatal) {
3009
3197
  const timeStamp = Date.now();
3010
3198
  this.addLog(types_1.STATUS_TYPE.FATAL, message, timeStamp, options.startTime && getTimeOffset(options.startTime, timeStamp));
@@ -3221,9 +3409,9 @@ class Module extends EventEmitter {
3221
3409
  }
3222
3410
  this._host = null;
3223
3411
  }
3224
- abort() {
3412
+ abort(reason) {
3225
3413
  if (!this.aborted) {
3226
- this[kAbortHandler].abort();
3414
+ this[kAbortHandler].abort(reason);
3227
3415
  }
3228
3416
  }
3229
3417
  willAbort(value) {
@@ -3250,14 +3438,14 @@ class Module extends EventEmitter {
3250
3438
  const aborting = this._hostEvents.includes('abort');
3251
3439
  if (value.aborted) {
3252
3440
  if (aborting) {
3253
- this.abort();
3441
+ this.abort(new Error("Aborted by host" /* ERR_MESSAGE.ABORTED_HOST */));
3254
3442
  }
3255
3443
  }
3256
3444
  else if (!value.subProcesses.has(this)) {
3257
3445
  this.abortable = value.willAbort(this);
3258
3446
  value.modules.add(this);
3259
3447
  if (aborting) {
3260
- value.signal.addEventListener('abort', this[kAbortEvent] = () => this.abort(), { once: true });
3448
+ value.signal.addEventListener('abort', this[kAbortEvent] = () => this.abort(new Error("Aborted by host" /* ERR_MESSAGE.ABORTED_HOST */)), { once: true });
3261
3449
  }
3262
3450
  }
3263
3451
  }
package/lib-v4.js CHANGED
@@ -97,7 +97,7 @@ function isPathUNC(value) {
97
97
  return index_1.default.isPath(value, 'unc');
98
98
  }
99
99
  exports.isPathUNC = isPathUNC;
100
- function readFileSafe(value, encoding, cache) {
100
+ async function readFileSafe(value, encoding, cache) {
101
101
  return encoding === 'buffer' ? index_1.default.readBuffer(value, cache) : index_1.default.readText(value, encoding, cache);
102
102
  }
103
103
  exports.readFileSafe = readFileSafe;
@@ -135,7 +135,7 @@ function getFunctions(values, absolute, sync = true, outFailed) {
135
135
  return result;
136
136
  }
137
137
  exports.getFunctions = getFunctions;
138
- function allSettled(tasks, rejected, options) {
138
+ async function allSettled(tasks, rejected, options) {
139
139
  if (rejected) {
140
140
  return Promise.allSettled(tasks).then(result => {
141
141
  const items = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e-mc/module",
3
- "version": "0.7.1",
3
+ "version": "0.8.1",
4
4
  "description": "Module base class for E-mc.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -20,12 +20,13 @@
20
20
  "license": "BSD 3-Clause",
21
21
  "homepage": "https://github.com/anpham6/e-mc#readme",
22
22
  "dependencies": {
23
- "@e-mc/types": "0.7.1",
23
+ "@e-mc/types": "0.8.1",
24
24
  "abort-controller": "^3.0.0",
25
25
  "chalk": "4.1.2",
26
26
  "event-target-shim": "^5.0.1",
27
27
  "file-type": "16.5.4",
28
28
  "mime-types": "^2.1.35",
29
+ "picomatch": "^3.0.1",
29
30
  "strip-ansi": "6.0.1"
30
31
  }
31
32
  }