@e-mc/core 0.13.10 → 0.14.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.
- package/README.md +14 -12
- package/index.js +150 -108
- package/package.json +3 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @e-mc/core
|
|
2
2
|
|
|
3
|
-
* NodeJS
|
|
3
|
+
* NodeJS 20 (Minimum 18)
|
|
4
4
|
* ES2022
|
|
5
5
|
|
|
6
6
|
## General Usage
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## Interface
|
|
11
11
|
|
|
12
|
-
* [View Source](https://www.unpkg.com/@e-mc/types@0.
|
|
12
|
+
* [View Source](https://www.unpkg.com/@e-mc/types@0.14.1/lib/index.d.ts)
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import type { DataSource, LogStatus, WorkerAction } from "./squared";
|
|
@@ -84,6 +84,7 @@ interface IClient extends IModule<IHost> {
|
|
|
84
84
|
module: ClientModule;
|
|
85
85
|
init(...args: unknown[]): this;
|
|
86
86
|
getUserSettings(): unknown;
|
|
87
|
+
extensionsOf(type?: string, cache?: boolean): Function[];
|
|
87
88
|
get settings(): ClientSettings;
|
|
88
89
|
set cacheDir(value: string);
|
|
89
90
|
get cacheDir(): string;
|
|
@@ -111,9 +112,9 @@ interface IClientDb extends IClient<IHost, ClientModule<ClientDbSettings>> {
|
|
|
111
112
|
getCacheResult(source: string, credential: unknown, queryString: string, cacheValue: CacheOptions, ignoreCache?: unknown): QueryResult | undefined;
|
|
112
113
|
applyState(items: DataSource | DataSource[], value: number, as?: boolean): void;
|
|
113
114
|
commit(items?: DataSource[]): Promise<boolean>;
|
|
114
|
-
valueOfKey(credential: unknown, name: keyof DbSourceOptions, component?:
|
|
115
|
-
settingsOf(source: string, name: keyof DbSourceOptions, component?:
|
|
116
|
-
settingsKey(uuidKey: string, name: keyof DbSourceOptions, component?:
|
|
115
|
+
valueOfKey(credential: unknown, name: keyof DbSourceOptions, component?: string): unknown;
|
|
116
|
+
settingsOf(source: string, name: keyof DbSourceOptions, component?: string): unknown;
|
|
117
|
+
settingsKey(uuidKey: string, name: keyof DbSourceOptions, component?: string): unknown;
|
|
117
118
|
get pending(): DataSource[];
|
|
118
119
|
get committed(): DataSource[];
|
|
119
120
|
get failed(): DataSource[];
|
|
@@ -128,6 +129,7 @@ interface ClientDbConstructor extends ClientConstructor<IHost, ClientModule> {
|
|
|
128
129
|
readonly TRANSACTION_TERMINATE: number;
|
|
129
130
|
readonly TRANSACTION_ABORT: number;
|
|
130
131
|
readonly TRANSACTION_FAIL: number;
|
|
132
|
+
readonly HASH_ALGORITHM: string | undefined;
|
|
131
133
|
loadSettings(settings: Pick<Settings, "process" | "memory">, password?: string): boolean;
|
|
132
134
|
getTimeout(value: number | string | TimeoutAction | undefined): number;
|
|
133
135
|
convertTime(value: number | string): number;
|
|
@@ -324,13 +326,13 @@ NOTE: **@e-mc/core** is mostly a collection of abstract base classes which canno
|
|
|
324
326
|
|
|
325
327
|
## References
|
|
326
328
|
|
|
327
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
328
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
329
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
330
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
331
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
332
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
333
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
329
|
+
- https://www.unpkg.com/@e-mc/types@0.14.1/lib/squared.d.ts
|
|
330
|
+
- https://www.unpkg.com/@e-mc/types@0.14.1/lib/core.d.ts
|
|
331
|
+
- https://www.unpkg.com/@e-mc/types@0.14.1/lib/db.d.ts
|
|
332
|
+
- https://www.unpkg.com/@e-mc/types@0.14.1/lib/dom.d.ts
|
|
333
|
+
- https://www.unpkg.com/@e-mc/types@0.14.1/lib/logger.d.ts
|
|
334
|
+
- https://www.unpkg.com/@e-mc/types@0.14.1/lib/node.d.ts
|
|
335
|
+
- https://www.unpkg.com/@e-mc/types@0.14.1/lib/settings.d.ts
|
|
334
336
|
|
|
335
337
|
* https://www.npmjs.com/package/@types/node
|
|
336
338
|
* https://www.npmjs.com/package/@types/picomatch
|
package/index.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
|
|
2
3
|
var _a;
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const module_1 = require("@e-mc/module");
|
|
13
|
-
exports.Module = module_1;
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const pm = require('picomatch');
|
|
7
|
+
const ipaddr = require('ipaddr.js');
|
|
8
|
+
const EventEmitter = require('node:events');
|
|
9
|
+
const { MessageChannel, Worker } = require('node:worker_threads');
|
|
10
|
+
const { fileURLToPath } = require('node:url');
|
|
11
|
+
const { decryptUTF8, encryptUTF8, errorValue, formatTime, hasBit, hashKey, isArray, isError, isObject, isPlainObject, isString, parseExpires, parseTime, requireESM, validateUUID } = require('@e-mc/types');
|
|
12
|
+
const Module = require('@e-mc/module');
|
|
14
13
|
const kHost = Symbol.for('host:constructor');
|
|
15
14
|
const kClient = Symbol.for('client:constructor');
|
|
16
15
|
const kClientDb = Symbol.for('clientdb:constructor');
|
|
@@ -31,7 +30,7 @@ const HOST = {
|
|
|
31
30
|
PRIORITY_BYPASS: undefined
|
|
32
31
|
};
|
|
33
32
|
const WORKER_GROUP = {
|
|
34
|
-
MAX:
|
|
33
|
+
MAX: Module.availableParallelism(),
|
|
35
34
|
TIMEOUT: Infinity,
|
|
36
35
|
LOCKED: true
|
|
37
36
|
};
|
|
@@ -48,27 +47,27 @@ const GC = {
|
|
|
48
47
|
INTERVAL: 60000
|
|
49
48
|
};
|
|
50
49
|
let STORE_RESULT_COUNT = 0;
|
|
51
|
-
let PICOMATCH_OPTIONS = { nocase:
|
|
50
|
+
let PICOMATCH_OPTIONS = { nocase: Module.PLATFORM_WIN32 };
|
|
52
51
|
let MINIMATCH_OPTIONS = {};
|
|
53
52
|
let MINIMATCH;
|
|
54
53
|
let PERMISSION;
|
|
55
54
|
function encryptText(data, iv) {
|
|
56
|
-
return HOST.CIPHER &&
|
|
55
|
+
return HOST.CIPHER && isString(data) && encryptUTF8(HOST.CIPHER.algorithm, HOST.CIPHER.key, iv, data) || '';
|
|
57
56
|
}
|
|
58
57
|
function isInvalidRange(result, range) {
|
|
59
58
|
const [lower, upper = 0] = range;
|
|
60
59
|
return Array.isArray(result) && (result.length <= lower || upper > 0 && result.length > upper);
|
|
61
60
|
}
|
|
62
61
|
function asPosix(value) {
|
|
63
|
-
if (
|
|
62
|
+
if (Module.PLATFORM_WIN32) {
|
|
64
63
|
value = path.normalize(value.trim());
|
|
65
64
|
return value.replace(/(?:^\\|\\+)/g, '/');
|
|
66
65
|
}
|
|
67
66
|
return path.normalize(value);
|
|
68
67
|
}
|
|
69
|
-
const readable = (value) =>
|
|
68
|
+
const readable = (value) => isString(value) || isArray(value);
|
|
70
69
|
const expireTime = (value) => Date.now() + Math.min(Math.trunc(value * 1000), GC.EXPIRES_LIMIT);
|
|
71
|
-
const convertSeconds = (value) => typeof value === 'string' && Math.ceil(
|
|
70
|
+
const convertSeconds = (value) => typeof value === 'string' && Math.ceil(parseTime(value) / 1000) || 0;
|
|
72
71
|
class DbLRU {
|
|
73
72
|
static get(source) {
|
|
74
73
|
return CACHE_SOURCE[source] ||= new DbLRU();
|
|
@@ -321,7 +320,7 @@ class HostQueue {
|
|
|
321
320
|
}
|
|
322
321
|
}
|
|
323
322
|
}
|
|
324
|
-
host.writeTimeElapsed('JOIN', ['Thread restarting...', HOST.THREAD_LIMIT > 1 ? `Availability: ${thread.size} / ${HOST.THREAD_LIMIT}` : ''], startTime, { type: 2, ...
|
|
323
|
+
host.writeTimeElapsed('JOIN', ['Thread restarting...', HOST.THREAD_LIMIT > 1 ? `Availability: ${thread.size} / ${HOST.THREAD_LIMIT}` : ''], startTime, { type: 2, ...Module.LOG_STYLE_WARN });
|
|
325
324
|
}
|
|
326
325
|
thread.foreground.delete(host);
|
|
327
326
|
if (typeof host.resumeThread === 'function') {
|
|
@@ -331,7 +330,7 @@ class HostQueue {
|
|
|
331
330
|
notify(broadcast, position = this.position) {
|
|
332
331
|
const host = this.host;
|
|
333
332
|
if (!broadcast || host.broadcastId) {
|
|
334
|
-
host.formatMessage(2, 'QUEUE', ["Thread limit exceeded" + ` (position #${position + 1})`, host.username], 'Priority: ' + this.priority, { type: 2, ...
|
|
333
|
+
host.formatMessage(2, 'QUEUE', ["Thread limit exceeded" + ` (position #${position + 1})`, host.username], 'Priority: ' + this.priority, { type: 2, ...Module.LOG_STYLE_WARN });
|
|
335
334
|
}
|
|
336
335
|
}
|
|
337
336
|
get position() {
|
|
@@ -372,7 +371,7 @@ class HostThread {
|
|
|
372
371
|
this.paused.add(host);
|
|
373
372
|
}
|
|
374
373
|
cancel(host, hint, rejected = false) {
|
|
375
|
-
host.writeFail(["Transaction was cancelled", host.username],
|
|
374
|
+
host.writeFail(["Transaction was cancelled", host.username], errorValue("Thread was killed", hint), { type: 2, fatal: true });
|
|
376
375
|
host.abort();
|
|
377
376
|
this.resetLog(host);
|
|
378
377
|
if (rejected) {
|
|
@@ -391,7 +390,7 @@ class HostThread {
|
|
|
391
390
|
for (let i = 0; i < queue.length; ++i) {
|
|
392
391
|
const item = queue[i];
|
|
393
392
|
if (current >= item.startTime + HOST.QUEUE_EXPIRES) {
|
|
394
|
-
this.cancel(item.host, 'expired: ' +
|
|
393
|
+
this.cancel(item.host, 'expired: ' + formatTime(item.startTime, true));
|
|
395
394
|
item.resume(true);
|
|
396
395
|
queue.splice(i--, 1);
|
|
397
396
|
}
|
|
@@ -417,7 +416,7 @@ class HostThread {
|
|
|
417
416
|
this.close(host);
|
|
418
417
|
}
|
|
419
418
|
else if (host.startTime + HOST.THREAD_EXPIRES >= current) {
|
|
420
|
-
host.writeFail(["Transaction was cancelled", host.username],
|
|
419
|
+
host.writeFail(["Transaction was cancelled", host.username], errorValue("Timeout was exceeded", formatTime(HOST.THREAD_EXPIRES)), { fatal: true });
|
|
421
420
|
host.abort();
|
|
422
421
|
this.close(host);
|
|
423
422
|
}
|
|
@@ -483,7 +482,7 @@ class HostThread {
|
|
|
483
482
|
}
|
|
484
483
|
}
|
|
485
484
|
const HOST_MAIN = new HostThread();
|
|
486
|
-
class Host extends
|
|
485
|
+
class Host extends Module {
|
|
487
486
|
static [kHost] = true;
|
|
488
487
|
static async purgeMemory(percent = 1, limit = 0, parent) {
|
|
489
488
|
return parent ? super.purgeMemory(percent, limit) : 0;
|
|
@@ -517,14 +516,14 @@ class Host extends module_1 {
|
|
|
517
516
|
}
|
|
518
517
|
if (perm.settings) {
|
|
519
518
|
const { picomatch: pico, minimatch: mini } = perm.settings;
|
|
520
|
-
if (
|
|
521
|
-
PICOMATCH_OPTIONS = { nocase:
|
|
519
|
+
if (isPlainObject(pico)) {
|
|
520
|
+
PICOMATCH_OPTIONS = { nocase: Module.PLATFORM_WIN32, ...pico };
|
|
522
521
|
}
|
|
523
|
-
if (
|
|
522
|
+
if (isPlainObject(mini)) {
|
|
524
523
|
try {
|
|
525
524
|
const { minimatch } = require('minimatch');
|
|
526
525
|
MINIMATCH = minimatch;
|
|
527
|
-
MINIMATCH_OPTIONS = { nocase:
|
|
526
|
+
MINIMATCH_OPTIONS = { nocase: Module.PLATFORM_WIN32, ...mini };
|
|
528
527
|
}
|
|
529
528
|
catch {
|
|
530
529
|
}
|
|
@@ -543,7 +542,7 @@ class Host extends module_1 {
|
|
|
543
542
|
if (limit && (limit = Math.floor(+limit)) > 0) {
|
|
544
543
|
HOST.THREAD_LIMIT = limit;
|
|
545
544
|
}
|
|
546
|
-
if (expires && (expires =
|
|
545
|
+
if (expires && (expires = parseTime(expires)) > 0) {
|
|
547
546
|
HOST.THREAD_EXPIRES = expires;
|
|
548
547
|
}
|
|
549
548
|
}
|
|
@@ -552,7 +551,7 @@ class Host extends module_1 {
|
|
|
552
551
|
if (limit !== undefined && (limit = Math.floor(+limit)) >= -1) {
|
|
553
552
|
HOST.QUEUE_LIMIT = limit >= 0 ? limit : Infinity;
|
|
554
553
|
}
|
|
555
|
-
if (expires && (expires =
|
|
554
|
+
if (expires && (expires = parseTime(expires)) > 0) {
|
|
556
555
|
HOST.QUEUE_EXPIRES = expires;
|
|
557
556
|
}
|
|
558
557
|
if (priority) {
|
|
@@ -578,9 +577,9 @@ class Host extends module_1 {
|
|
|
578
577
|
}
|
|
579
578
|
}
|
|
580
579
|
if (admin) {
|
|
581
|
-
if (HOST.CIPHER &&
|
|
580
|
+
if (HOST.CIPHER && isArray(admin.users)) {
|
|
582
581
|
const { algorithm, key, iv } = HOST.CIPHER;
|
|
583
|
-
HOST.ADMIN_USERS = admin.users.map(value =>
|
|
582
|
+
HOST.ADMIN_USERS = admin.users.map(value => encryptUTF8(algorithm, key, iv, value)).filter(value => value);
|
|
584
583
|
}
|
|
585
584
|
if (typeof admin.private === 'boolean') {
|
|
586
585
|
HOST.ADMIN_PRIVATE = admin.private;
|
|
@@ -591,7 +590,7 @@ class Host extends module_1 {
|
|
|
591
590
|
if ((max = Math.floor(+max)) > 1) {
|
|
592
591
|
WORKER_GROUP.MAX = max;
|
|
593
592
|
}
|
|
594
|
-
if (max_expires && (max_expires =
|
|
593
|
+
if (max_expires && (max_expires = parseExpires(max_expires)) > 0) {
|
|
595
594
|
WORKER_GROUP.TIMEOUT = WorkerGroup.checkTimeout(max_expires, false);
|
|
596
595
|
}
|
|
597
596
|
if (typeof locked === 'boolean') {
|
|
@@ -606,7 +605,7 @@ class Host extends module_1 {
|
|
|
606
605
|
WORKER_CHANNEL.MAX = b;
|
|
607
606
|
WORKER_CHANNEL.MIN = Math.min(WORKER_CHANNEL.MIN, b);
|
|
608
607
|
}
|
|
609
|
-
if (expires && (expires =
|
|
608
|
+
if (expires && (expires = parseExpires(expires)) > 0) {
|
|
610
609
|
WORKER_CHANNEL.TIMEOUT = WorkerGroup.checkTimeout(expires, false);
|
|
611
610
|
}
|
|
612
611
|
if (typeof verbose === 'boolean') {
|
|
@@ -629,7 +628,7 @@ class Host extends module_1 {
|
|
|
629
628
|
return permission;
|
|
630
629
|
}
|
|
631
630
|
static isPermission(value) {
|
|
632
|
-
return value instanceof Permission ||
|
|
631
|
+
return value instanceof Permission || isObject(value) && typeof value.diskRead === 'boolean' && typeof value.diskWrite === 'boolean';
|
|
633
632
|
}
|
|
634
633
|
static kill(username, iv, pid) {
|
|
635
634
|
if (typeof iv === 'boolean' || typeof iv === 'number' || Array.isArray(iv)) {
|
|
@@ -703,7 +702,7 @@ class Host extends module_1 {
|
|
|
703
702
|
return count;
|
|
704
703
|
}
|
|
705
704
|
static parseIp(value, kind) {
|
|
706
|
-
if (
|
|
705
|
+
if (isString(value)) {
|
|
707
706
|
try {
|
|
708
707
|
let ip = ipaddr.parse(value);
|
|
709
708
|
if (kind) {
|
|
@@ -749,16 +748,16 @@ class Host extends module_1 {
|
|
|
749
748
|
#config;
|
|
750
749
|
constructor(config = {}) {
|
|
751
750
|
super();
|
|
752
|
-
if (
|
|
751
|
+
if (isString(config.username)) {
|
|
753
752
|
const cipher = HOST.CIPHER;
|
|
754
|
-
this.#username = cipher ?
|
|
753
|
+
this.#username = cipher ? decryptUTF8(cipher.algorithm, cipher.key, cipher.iv, config.username) || '' : config.username;
|
|
755
754
|
}
|
|
756
755
|
if (config.broadcastId) {
|
|
757
756
|
this.broadcastId = config.broadcastId;
|
|
758
757
|
}
|
|
759
758
|
const { log, priority } = config;
|
|
760
759
|
let showProgress;
|
|
761
|
-
if (
|
|
760
|
+
if (isPlainObject(log)) {
|
|
762
761
|
const { enabled, level, exclude, useColor, silent } = log;
|
|
763
762
|
if (level !== undefined) {
|
|
764
763
|
this.logLevel = level;
|
|
@@ -797,7 +796,7 @@ class Host extends module_1 {
|
|
|
797
796
|
restart(...args) { }
|
|
798
797
|
updateProgress(name, ...args) { }
|
|
799
798
|
isFatal(err) {
|
|
800
|
-
if (err
|
|
799
|
+
if (isError(err)) {
|
|
801
800
|
const fatal = this.config.error?.fatal;
|
|
802
801
|
return fatal ?? super.isFatal(err);
|
|
803
802
|
}
|
|
@@ -970,6 +969,14 @@ class Host extends module_1 {
|
|
|
970
969
|
joinQueue(options) {
|
|
971
970
|
return HOST_MAIN.join(this, options);
|
|
972
971
|
}
|
|
972
|
+
relayMessage(args) {
|
|
973
|
+
if (this.logState === 0) {
|
|
974
|
+
this.delayMessage(args);
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
Module.formatMessage(...args);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
973
980
|
set host(value) { }
|
|
974
981
|
get host() {
|
|
975
982
|
return null;
|
|
@@ -1005,18 +1012,21 @@ class Host extends module_1 {
|
|
|
1005
1012
|
return Array.from(this.modules).reduce((a, b) => a + b.errors.length, this.errors.length);
|
|
1006
1013
|
}
|
|
1007
1014
|
}
|
|
1008
|
-
|
|
1009
|
-
class Client extends module_1 {
|
|
1015
|
+
class Client extends Module {
|
|
1010
1016
|
static [kClient] = true;
|
|
1011
1017
|
static async purgeMemory(percent = 1, limit = 0, parent) {
|
|
1012
1018
|
return parent ? super.purgeMemory(percent, limit) : 0;
|
|
1013
1019
|
}
|
|
1020
|
+
static signExtensionType(method, ...type) {
|
|
1021
|
+
return Object.defineProperty(method, "__type__", { value: type, writable: false, enumerable: false });
|
|
1022
|
+
}
|
|
1014
1023
|
module;
|
|
1015
1024
|
_extensions = null;
|
|
1025
|
+
_extensionsType = {};
|
|
1016
1026
|
#cacheDir = '';
|
|
1017
1027
|
constructor(data) {
|
|
1018
1028
|
super();
|
|
1019
|
-
this.module =
|
|
1029
|
+
this.module = isPlainObject(data) ? data : {};
|
|
1020
1030
|
}
|
|
1021
1031
|
init(...args) {
|
|
1022
1032
|
const { permission, extensions } = this.module;
|
|
@@ -1027,7 +1037,7 @@ class Client extends module_1 {
|
|
|
1027
1037
|
this.permission = result;
|
|
1028
1038
|
}
|
|
1029
1039
|
}
|
|
1030
|
-
if (
|
|
1040
|
+
if (isArray(extensions)) {
|
|
1031
1041
|
this._extensions ||= extensions.slice(0);
|
|
1032
1042
|
}
|
|
1033
1043
|
if (cache_dir) {
|
|
@@ -1038,29 +1048,55 @@ class Client extends module_1 {
|
|
|
1038
1048
|
getUserSettings() {
|
|
1039
1049
|
const username = this.host?.username;
|
|
1040
1050
|
let result;
|
|
1041
|
-
return username &&
|
|
1051
|
+
return username && isPlainObject(result = this.settings.users?.[username]) ? result : null;
|
|
1042
1052
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1053
|
+
extensionsOf(type, cache = true) {
|
|
1054
|
+
let result;
|
|
1055
|
+
if (type && cache && (result = this._extensionsType[type])) {
|
|
1056
|
+
return result;
|
|
1046
1057
|
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1058
|
+
result = [];
|
|
1059
|
+
const extensions = this._extensions;
|
|
1060
|
+
if (extensions) {
|
|
1061
|
+
for (let i = 0, length = extensions.length; i < length; ++i) {
|
|
1062
|
+
const value = extensions[i];
|
|
1063
|
+
let method;
|
|
1064
|
+
if (typeof value === 'string') {
|
|
1065
|
+
if (value.startsWith('npm:')) {
|
|
1066
|
+
try {
|
|
1067
|
+
method = requireESM(value.slice(4));
|
|
1068
|
+
}
|
|
1069
|
+
catch (err) {
|
|
1070
|
+
this.addLog(3, err, this.moduleName, type || value);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
method = Module.parseFunction(value, { external: true, absolute: true, sync: true, default: true });
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
else if (typeof value === 'function') {
|
|
1078
|
+
method = value;
|
|
1079
|
+
}
|
|
1080
|
+
if (method) {
|
|
1081
|
+
const prop = Object.getOwnPropertyDescriptor(method, "__type__");
|
|
1082
|
+
if (prop) {
|
|
1083
|
+
if (type && Array.isArray(prop.value) && prop.value.includes(type)) {
|
|
1084
|
+
result.push(method);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
else if (!type) {
|
|
1088
|
+
result.push(method);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1055
1091
|
}
|
|
1056
|
-
if (
|
|
1057
|
-
result
|
|
1092
|
+
if (type && cache) {
|
|
1093
|
+
this._extensionsType[type] = result;
|
|
1058
1094
|
}
|
|
1059
1095
|
}
|
|
1060
1096
|
return result;
|
|
1061
1097
|
}
|
|
1062
1098
|
set cacheDir(value) {
|
|
1063
|
-
if (path.isAbsolute(value) &&
|
|
1099
|
+
if (path.isAbsolute(value) && Module.isDir(value) && this.supportsProperty('cacheDir')) {
|
|
1064
1100
|
this.#cacheDir = value;
|
|
1065
1101
|
}
|
|
1066
1102
|
}
|
|
@@ -1076,10 +1112,9 @@ class Client extends module_1 {
|
|
|
1076
1112
|
}
|
|
1077
1113
|
}
|
|
1078
1114
|
get extensions() {
|
|
1079
|
-
return this._extensions ? this.
|
|
1115
|
+
return this._extensions ? this.extensionsOf() : [];
|
|
1080
1116
|
}
|
|
1081
1117
|
}
|
|
1082
|
-
exports.Client = Client;
|
|
1083
1118
|
class ClientDb extends Client {
|
|
1084
1119
|
database;
|
|
1085
1120
|
static [kClientDb] = true;
|
|
@@ -1103,6 +1138,9 @@ class ClientDb extends Client {
|
|
|
1103
1138
|
static get TRANSACTION_FAIL() {
|
|
1104
1139
|
return 32;
|
|
1105
1140
|
}
|
|
1141
|
+
static get HASH_ALGORITHM() {
|
|
1142
|
+
return undefined;
|
|
1143
|
+
}
|
|
1106
1144
|
static loadSettings(settings, password) {
|
|
1107
1145
|
if (!super.loadSettings({ process: settings.process }, password)) {
|
|
1108
1146
|
return false;
|
|
@@ -1113,29 +1151,29 @@ class ClientDb extends Client {
|
|
|
1113
1151
|
const gc = memory.settings?.gc;
|
|
1114
1152
|
if (gc) {
|
|
1115
1153
|
let { expires, interval, expires_limit } = gc;
|
|
1116
|
-
if (expires_limit !== undefined && (expires_limit =
|
|
1154
|
+
if (expires_limit !== undefined && (expires_limit = parseExpires(expires_limit) / 1000) >= 1) {
|
|
1117
1155
|
GC.EXPIRES_LIMIT = expires_limit;
|
|
1118
1156
|
}
|
|
1119
|
-
if (expires !== undefined && (expires =
|
|
1157
|
+
if (expires !== undefined && (expires = parseExpires(expires) / 1000) > 0) {
|
|
1120
1158
|
GC.EXPIRES = Math.min(expires, GC.EXPIRES_LIMIT);
|
|
1121
1159
|
GC.EXPIRES_DEFAULT = true;
|
|
1122
1160
|
}
|
|
1123
|
-
if (interval !== undefined && (interval =
|
|
1161
|
+
if (interval !== undefined && (interval = parseExpires(interval)) > 0) {
|
|
1124
1162
|
GC.INTERVAL = interval;
|
|
1125
1163
|
}
|
|
1126
1164
|
}
|
|
1127
1165
|
}
|
|
1128
1166
|
else {
|
|
1129
1167
|
const client = memory[name];
|
|
1130
|
-
if (
|
|
1168
|
+
if (isPlainObject(client)) {
|
|
1131
1169
|
for (const source in client) {
|
|
1132
1170
|
const item = client[source];
|
|
1133
|
-
if (
|
|
1171
|
+
if (isObject(item) && 'enabled' in item) {
|
|
1134
1172
|
const key = name + '_' + source;
|
|
1135
1173
|
const { enabled, limit = 0, min = 0, max = 0, type = 'lru' } = item;
|
|
1136
1174
|
if (enabled && +limit > 0) {
|
|
1137
1175
|
let percent = item.percent || 0;
|
|
1138
|
-
if (
|
|
1176
|
+
if (isString(percent)) {
|
|
1139
1177
|
percent = percent.includes('%') ? parseFloat(percent) / 100 : parseFloat(percent);
|
|
1140
1178
|
}
|
|
1141
1179
|
else if ((percent = Math.max(percent, 0)) > 1) {
|
|
@@ -1192,22 +1230,22 @@ class ClientDb extends Client {
|
|
|
1192
1230
|
result = value * 1000;
|
|
1193
1231
|
break;
|
|
1194
1232
|
case 'string':
|
|
1195
|
-
result =
|
|
1233
|
+
result = parseTime(value);
|
|
1196
1234
|
break;
|
|
1197
1235
|
}
|
|
1198
1236
|
return result > 0 ? result : 0;
|
|
1199
1237
|
}
|
|
1200
1238
|
static findResult(source, credential, queryString, timeout, sessionKey, renewCache) {
|
|
1201
|
-
const userKey = credential ? this.extractUUID(credential) ||
|
|
1239
|
+
const userKey = credential ? this.extractUUID(credential) || hashKey(this.asString(credential), this.HASH_ALGORITHM) : undefined;
|
|
1202
1240
|
if (userKey) {
|
|
1203
1241
|
if (timeout > 0) {
|
|
1204
|
-
const stored = CACHE_USER[source]?.get(userKey)?.[(
|
|
1242
|
+
const stored = CACHE_USER[source]?.get(userKey)?.[hashKey(queryString, this.HASH_ALGORITHM)];
|
|
1205
1243
|
if (stored) {
|
|
1206
1244
|
return stored.get(renewCache ? timeout : 0);
|
|
1207
1245
|
}
|
|
1208
1246
|
}
|
|
1209
1247
|
else if (sessionKey) {
|
|
1210
|
-
return this.findSession(source, userKey + sessionKey, (
|
|
1248
|
+
return this.findSession(source, userKey + sessionKey, hashKey(queryString, this.HASH_ALGORITHM));
|
|
1211
1249
|
}
|
|
1212
1250
|
}
|
|
1213
1251
|
}
|
|
@@ -1216,10 +1254,10 @@ class ClientDb extends Client {
|
|
|
1216
1254
|
return result;
|
|
1217
1255
|
}
|
|
1218
1256
|
let cacheDir;
|
|
1219
|
-
if (
|
|
1257
|
+
if (isObject(sessionKey)) {
|
|
1220
1258
|
({ cacheDir, sessionKey, sessionExpires } = sessionKey);
|
|
1221
1259
|
}
|
|
1222
|
-
else if (
|
|
1260
|
+
else if (isObject(cache) && 'cache' in cache) {
|
|
1223
1261
|
({ cache, cacheDir, sessionKey, sessionExpires } = cache);
|
|
1224
1262
|
}
|
|
1225
1263
|
let timeout = 0, userKey, whenEmpty, partition = false;
|
|
@@ -1228,7 +1266,7 @@ class ClientDb extends Client {
|
|
|
1228
1266
|
if (cache) {
|
|
1229
1267
|
let seconds, dir;
|
|
1230
1268
|
({ timeout: seconds, when_empty: whenEmpty, dir } = cache);
|
|
1231
|
-
if (dir && (!cacheDir ||
|
|
1269
|
+
if (dir && (!cacheDir || Module.isDir(dir))) {
|
|
1232
1270
|
cacheDir = dir;
|
|
1233
1271
|
partition = true;
|
|
1234
1272
|
}
|
|
@@ -1252,16 +1290,16 @@ class ClientDb extends Client {
|
|
|
1252
1290
|
timeout = convertSeconds(cache);
|
|
1253
1291
|
break;
|
|
1254
1292
|
}
|
|
1255
|
-
if ((result.length > 0 || whenEmpty) && (userKey = this.extractUUID(credential) ||
|
|
1293
|
+
if ((result.length > 0 || whenEmpty) && (userKey = this.extractUUID(credential) || hashKey(this.asString(credential), this.HASH_ALGORITHM))) {
|
|
1256
1294
|
if (timeout > 0) {
|
|
1257
|
-
queryString = (
|
|
1295
|
+
queryString = hashKey(queryString, this.HASH_ALGORITHM);
|
|
1258
1296
|
const item = new DbCache(source, userKey, queryString, result, timeout);
|
|
1259
1297
|
if (cacheDir) {
|
|
1260
1298
|
if (partition) {
|
|
1261
1299
|
if (STORE_RESULT_COUNT === this.STORE_RESULT_PARTITION_SIZE) {
|
|
1262
1300
|
STORE_RESULT_COUNT = 0;
|
|
1263
1301
|
}
|
|
1264
|
-
const subDir = path.join(cacheDir, (STORE_RESULT_COUNT++).toString(), queryString.
|
|
1302
|
+
const subDir = path.join(cacheDir, (STORE_RESULT_COUNT++).toString(), queryString.slice(0, this.STORE_RESULT_PARTITION_MULT));
|
|
1265
1303
|
if (this.createDir(subDir)) {
|
|
1266
1304
|
cacheDir = subDir;
|
|
1267
1305
|
}
|
|
@@ -1275,7 +1313,7 @@ class ClientDb extends Client {
|
|
|
1275
1313
|
}
|
|
1276
1314
|
}
|
|
1277
1315
|
else if (typeof sessionKey === 'string') {
|
|
1278
|
-
this.storeSession(source, userKey + sessionKey, (
|
|
1316
|
+
this.storeSession(source, userKey + sessionKey, hashKey(queryString, this.HASH_ALGORITHM), result, sessionExpires);
|
|
1279
1317
|
}
|
|
1280
1318
|
}
|
|
1281
1319
|
return result;
|
|
@@ -1345,10 +1383,10 @@ class ClientDb extends Client {
|
|
|
1345
1383
|
static getPoolConfig(source) { }
|
|
1346
1384
|
static extractUUID(credential) {
|
|
1347
1385
|
if (typeof credential === 'string') {
|
|
1348
|
-
return
|
|
1386
|
+
return validateUUID(credential) ? credential : '';
|
|
1349
1387
|
}
|
|
1350
1388
|
let result;
|
|
1351
|
-
return
|
|
1389
|
+
return isObject(credential) && (result = credential.uuidKey) && validateUUID(result) ? result : '';
|
|
1352
1390
|
}
|
|
1353
1391
|
static keyOfResult(source, credential, uuidOnly) {
|
|
1354
1392
|
const result = this.extractUUID(credential);
|
|
@@ -1363,12 +1401,12 @@ class ClientDb extends Client {
|
|
|
1363
1401
|
this.database = database;
|
|
1364
1402
|
}
|
|
1365
1403
|
init(config) {
|
|
1366
|
-
let { cache_dir, session_expires: expires } = this.settings;
|
|
1367
|
-
if (cache_dir) {
|
|
1404
|
+
let { cache_dir, cache, session_expires: expires } = this.settings;
|
|
1405
|
+
if (cache_dir ||= cache?.dir) {
|
|
1368
1406
|
this.cacheDir = cache_dir;
|
|
1369
1407
|
}
|
|
1370
1408
|
if (expires !== undefined) {
|
|
1371
|
-
if (typeof expires === 'string' && !isNaN(expires =
|
|
1409
|
+
if (typeof expires === 'string' && !isNaN(expires = parseTime(expires))) {
|
|
1372
1410
|
this.settings.session_expires = expires;
|
|
1373
1411
|
}
|
|
1374
1412
|
if (expires >= 0) {
|
|
@@ -1386,17 +1424,17 @@ class ClientDb extends Client {
|
|
|
1386
1424
|
}
|
|
1387
1425
|
}
|
|
1388
1426
|
hasCache(source, sessionKey) {
|
|
1389
|
-
return
|
|
1427
|
+
return isString(sessionKey) || ClientDb.getTimeout(this.settingsOf(source, 'cache')) > 0;
|
|
1390
1428
|
}
|
|
1391
1429
|
hasCoerce(source, component, credential) {
|
|
1392
1430
|
let uuidKey;
|
|
1393
|
-
if (credential && (
|
|
1431
|
+
if (credential && (validateUUID(credential) ? uuidKey = credential : uuidKey = ClientDb.extractUUID(credential))) {
|
|
1394
1432
|
const value = this.settingsKey(uuidKey, 'coerce', component);
|
|
1395
1433
|
if (value !== undefined) {
|
|
1396
1434
|
if (typeof value === 'boolean') {
|
|
1397
1435
|
return value && component === 'options';
|
|
1398
1436
|
}
|
|
1399
|
-
if (
|
|
1437
|
+
if (isPlainObject(value) && component in value) {
|
|
1400
1438
|
return value[component] === true;
|
|
1401
1439
|
}
|
|
1402
1440
|
}
|
|
@@ -1451,12 +1489,12 @@ class ClientDb extends Client {
|
|
|
1451
1489
|
if (!Array.isArray(result)) {
|
|
1452
1490
|
result = result === undefined ? [] : [result];
|
|
1453
1491
|
}
|
|
1454
|
-
if (!credential || !
|
|
1492
|
+
if (!credential || !isString(queryString)) {
|
|
1455
1493
|
return result;
|
|
1456
1494
|
}
|
|
1457
1495
|
const uuidKey = ClientDb.extractUUID(credential);
|
|
1458
1496
|
let value, exclusiveOf;
|
|
1459
|
-
if (
|
|
1497
|
+
if (isObject(sessionKey)) {
|
|
1460
1498
|
({ value, sessionKey, exclusiveOf } = sessionKey);
|
|
1461
1499
|
}
|
|
1462
1500
|
if (Array.isArray(exclusiveOf)) {
|
|
@@ -1482,7 +1520,7 @@ class ClientDb extends Client {
|
|
|
1482
1520
|
else if (cacheDir) {
|
|
1483
1521
|
options = { cacheDir };
|
|
1484
1522
|
}
|
|
1485
|
-
else if (!
|
|
1523
|
+
else if (!isObject(value) || !isString(value.dir)) {
|
|
1486
1524
|
return result;
|
|
1487
1525
|
}
|
|
1488
1526
|
return value || options ? ClientDb.storeResult(this.getSourceName(source), uuidKey || credential, queryString, result, value, options) : result;
|
|
@@ -1495,13 +1533,13 @@ class ClientDb extends Client {
|
|
|
1495
1533
|
}
|
|
1496
1534
|
applyState(items, value, as) {
|
|
1497
1535
|
for (const item of Array.isArray(items) ? items : [items]) {
|
|
1498
|
-
if (
|
|
1536
|
+
if (hasBit(value, 8)) {
|
|
1499
1537
|
const state = item.transactionState ||= 0;
|
|
1500
|
-
if (
|
|
1538
|
+
if (hasBit(state, 4) || hasBit(state, 32)) {
|
|
1501
1539
|
item.transactionState |= value;
|
|
1502
1540
|
}
|
|
1503
1541
|
}
|
|
1504
|
-
else if (
|
|
1542
|
+
else if (hasBit(value, 16)) {
|
|
1505
1543
|
item.transactionState ||= value;
|
|
1506
1544
|
}
|
|
1507
1545
|
else if (as) {
|
|
@@ -1520,13 +1558,13 @@ class ClientDb extends Client {
|
|
|
1520
1558
|
}
|
|
1521
1559
|
settingsOf(source, name, component) {
|
|
1522
1560
|
const data = this.settings[source];
|
|
1523
|
-
if (
|
|
1561
|
+
if (isObject(data)) {
|
|
1524
1562
|
return this.#settingsValue(data, name, component);
|
|
1525
1563
|
}
|
|
1526
1564
|
}
|
|
1527
1565
|
settingsKey(uuidKey, name, component) {
|
|
1528
1566
|
const data = this.settings.user_key?.[uuidKey];
|
|
1529
|
-
if (
|
|
1567
|
+
if (isObject(data)) {
|
|
1530
1568
|
return this.#settingsValue(data, name, component);
|
|
1531
1569
|
}
|
|
1532
1570
|
}
|
|
@@ -1538,7 +1576,7 @@ class ClientDb extends Client {
|
|
|
1538
1576
|
if (!component) {
|
|
1539
1577
|
return result;
|
|
1540
1578
|
}
|
|
1541
|
-
if (
|
|
1579
|
+
if (isObject(result)) {
|
|
1542
1580
|
return result[component];
|
|
1543
1581
|
}
|
|
1544
1582
|
}
|
|
@@ -1555,13 +1593,12 @@ class ClientDb extends Client {
|
|
|
1555
1593
|
return this.database.filter(item => (item.transactionState & 32) === 32);
|
|
1556
1594
|
}
|
|
1557
1595
|
}
|
|
1558
|
-
exports.ClientDb = ClientDb;
|
|
1559
1596
|
class WorkerGroup {
|
|
1560
1597
|
static checkTimeout(value, active = true) {
|
|
1561
1598
|
if (value === Infinity && WORKER_GROUP.TIMEOUT === Infinity) {
|
|
1562
|
-
return active ?
|
|
1599
|
+
return active ? Module.MAX_TIMEOUT : Infinity;
|
|
1563
1600
|
}
|
|
1564
|
-
return Math.min(value, WORKER_GROUP.TIMEOUT,
|
|
1601
|
+
return Math.min(value, WORKER_GROUP.TIMEOUT, Module.MAX_TIMEOUT);
|
|
1565
1602
|
}
|
|
1566
1603
|
#max = WORKER_GROUP.MAX;
|
|
1567
1604
|
#map = new Map();
|
|
@@ -1704,7 +1741,6 @@ class WorkerGroup {
|
|
|
1704
1741
|
return this.#workers.length;
|
|
1705
1742
|
}
|
|
1706
1743
|
}
|
|
1707
|
-
exports.WorkerGroup = WorkerGroup;
|
|
1708
1744
|
class WorkerChannel extends EventEmitter {
|
|
1709
1745
|
static create(filename, options, name) {
|
|
1710
1746
|
if (typeof options === 'string') {
|
|
@@ -1748,7 +1784,7 @@ class WorkerChannel extends EventEmitter {
|
|
|
1748
1784
|
#timeout = new WeakMap();
|
|
1749
1785
|
constructor(filename, options = {}, { max = -1, idleTimeout = 0, verbose } = {}) {
|
|
1750
1786
|
super();
|
|
1751
|
-
this.#filename = filename instanceof URL ?
|
|
1787
|
+
this.#filename = filename instanceof URL ? fileURLToPath(filename) : options.eval ? filename : path.resolve(filename);
|
|
1752
1788
|
if ('workerData' in options) {
|
|
1753
1789
|
this.#workerData = options.workerData;
|
|
1754
1790
|
options = { ...options };
|
|
@@ -1778,10 +1814,10 @@ class WorkerChannel extends EventEmitter {
|
|
|
1778
1814
|
this.#clearTimeout(worker);
|
|
1779
1815
|
}
|
|
1780
1816
|
else {
|
|
1781
|
-
channel = new
|
|
1817
|
+
channel = new MessageChannel();
|
|
1782
1818
|
const options = { ...this.#options, transferList: [channel.port1] };
|
|
1783
1819
|
options.workerData = [channel.port1, this.#workerData];
|
|
1784
|
-
worker = new
|
|
1820
|
+
worker = new Worker(this.filename, options);
|
|
1785
1821
|
worker
|
|
1786
1822
|
.on('exit', exitCode => {
|
|
1787
1823
|
const index = this.#findIndex(worker);
|
|
@@ -2029,7 +2065,6 @@ class WorkerChannel extends EventEmitter {
|
|
|
2029
2065
|
return this.#workers.length;
|
|
2030
2066
|
}
|
|
2031
2067
|
}
|
|
2032
|
-
exports.WorkerChannel = WorkerChannel;
|
|
2033
2068
|
class AbortComponent {
|
|
2034
2069
|
static attach(instance, signal, options) {
|
|
2035
2070
|
let map = ABORT_LISTENER.get(instance);
|
|
@@ -2071,7 +2106,6 @@ class AbortComponent {
|
|
|
2071
2106
|
return this.signal.aborted;
|
|
2072
2107
|
}
|
|
2073
2108
|
}
|
|
2074
|
-
exports.AbortComponent = AbortComponent;
|
|
2075
2109
|
class Permission {
|
|
2076
2110
|
static create(settings, parent, freeze) {
|
|
2077
2111
|
if (this.validate(settings)) {
|
|
@@ -2120,7 +2154,7 @@ class Permission {
|
|
|
2120
2154
|
return null;
|
|
2121
2155
|
}
|
|
2122
2156
|
static validate(settings) {
|
|
2123
|
-
return
|
|
2157
|
+
return isPlainObject(settings) && (readable(settings.disk_read) || readable(settings.disk_write) || readable(settings.unc_read) || readable(settings.unc_write));
|
|
2124
2158
|
}
|
|
2125
2159
|
static clone(permission, freeze) {
|
|
2126
2160
|
const result = new _a(freeze);
|
|
@@ -2147,11 +2181,11 @@ class Permission {
|
|
|
2147
2181
|
}
|
|
2148
2182
|
static toPosix(value) {
|
|
2149
2183
|
if (value) {
|
|
2150
|
-
if (
|
|
2184
|
+
if (isString(value)) {
|
|
2151
2185
|
return asPosix(value);
|
|
2152
2186
|
}
|
|
2153
2187
|
if (Array.isArray(value)) {
|
|
2154
|
-
const items = value.filter(item =>
|
|
2188
|
+
const items = value.filter(item => isString(item));
|
|
2155
2189
|
if (items.length > 0) {
|
|
2156
2190
|
return items.map(item => asPosix(item));
|
|
2157
2191
|
}
|
|
@@ -2240,7 +2274,7 @@ class Permission {
|
|
|
2240
2274
|
}
|
|
2241
2275
|
#permitted(permission, pathname) {
|
|
2242
2276
|
const { enabled, value } = permission;
|
|
2243
|
-
return enabled === true &&
|
|
2277
|
+
return enabled === true && isString(pathname) && (value === '**/*' || value === '**' || _a.match(pathname, value));
|
|
2244
2278
|
}
|
|
2245
2279
|
get diskRead() {
|
|
2246
2280
|
return this.#diskRead.enabled === true;
|
|
@@ -2255,7 +2289,15 @@ class Permission {
|
|
|
2255
2289
|
return this.#uncWrite.enabled === true;
|
|
2256
2290
|
}
|
|
2257
2291
|
}
|
|
2258
|
-
exports.Permission = Permission;
|
|
2259
2292
|
_a = Permission;
|
|
2260
2293
|
PERMISSION = Host.createPermission(true, true);
|
|
2261
2294
|
Object.freeze(PERMISSION);
|
|
2295
|
+
|
|
2296
|
+
exports.AbortComponent = AbortComponent;
|
|
2297
|
+
exports.Client = Client;
|
|
2298
|
+
exports.ClientDb = ClientDb;
|
|
2299
|
+
exports.Host = Host;
|
|
2300
|
+
exports.Module = Module;
|
|
2301
|
+
exports.Permission = Permission;
|
|
2302
|
+
exports.WorkerChannel = WorkerChannel;
|
|
2303
|
+
exports.WorkerGroup = WorkerGroup;
|
package/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Core modules for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
7
|
-
"publishConfig": {
|
|
8
|
-
"access": "public"
|
|
9
|
-
},
|
|
10
7
|
"repository": {
|
|
11
8
|
"type": "git",
|
|
12
9
|
"url": "git+https://github.com/anpham6/e-mc.git",
|
|
@@ -19,8 +16,8 @@
|
|
|
19
16
|
"license": "BSD-3-Clause",
|
|
20
17
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
21
18
|
"dependencies": {
|
|
22
|
-
"@e-mc/module": "0.
|
|
23
|
-
"@e-mc/types": "0.
|
|
19
|
+
"@e-mc/module": "0.14.1",
|
|
20
|
+
"@e-mc/types": "0.14.1",
|
|
24
21
|
"ipaddr.js": "^2.3.0",
|
|
25
22
|
"picomatch": "^4.0.4"
|
|
26
23
|
}
|