@sv443-network/coreutils 1.0.0 → 2.0.0
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/CHANGELOG.md +19 -2
- package/README.md +24 -8
- package/dist/CoreUtils.cjs +202 -57
- package/dist/CoreUtils.min.cjs +2 -2
- package/dist/CoreUtils.min.mjs +2 -2
- package/dist/CoreUtils.min.umd.js +2 -2
- package/dist/CoreUtils.mjs +202 -57
- package/dist/CoreUtils.umd.js +510 -480
- package/dist/lib/DataStore.d.ts +19 -11
- package/dist/lib/DataStoreEngine.d.ts +35 -14
- package/dist/lib/NanoEmitter.d.ts +33 -1
- package/dist/lib/TieredCache.d.ts +1 -1
- package/dist/lib/crypto.d.ts +15 -15
- package/dist/lib/math.d.ts +4 -0
- package/package.json +2 -1
package/dist/CoreUtils.umd.js
CHANGED
|
@@ -16,41 +16,13 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
(function(g,f){if(typeof exports=="object"&&typeof module<"u"){module.exports=f()}else if("function"==typeof define && define.amd){define("CoreUtils",f)}else {g["CoreUtils"]=f()}}(typeof globalThis < "u" ? globalThis : typeof self < "u" ? self : this,function(){var exports={};var __exports=exports;var module={exports};
|
|
20
19
|
"use strict";
|
|
21
20
|
var __create = Object.create;
|
|
22
21
|
var __defProp = Object.defineProperty;
|
|
23
22
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
24
23
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
25
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
26
24
|
var __getProtoOf = Object.getPrototypeOf;
|
|
27
25
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
28
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
29
|
-
var __pow = Math.pow;
|
|
30
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
31
|
-
var __spreadValues = (a, b) => {
|
|
32
|
-
for (var prop in b || (b = {}))
|
|
33
|
-
if (__hasOwnProp.call(b, prop))
|
|
34
|
-
__defNormalProp(a, prop, b[prop]);
|
|
35
|
-
if (__getOwnPropSymbols)
|
|
36
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
37
|
-
if (__propIsEnum.call(b, prop))
|
|
38
|
-
__defNormalProp(a, prop, b[prop]);
|
|
39
|
-
}
|
|
40
|
-
return a;
|
|
41
|
-
};
|
|
42
|
-
var __objRest = (source, exclude) => {
|
|
43
|
-
var target = {};
|
|
44
|
-
for (var prop in source)
|
|
45
|
-
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
46
|
-
target[prop] = source[prop];
|
|
47
|
-
if (source != null && __getOwnPropSymbols)
|
|
48
|
-
for (var prop of __getOwnPropSymbols(source)) {
|
|
49
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
50
|
-
target[prop] = source[prop];
|
|
51
|
-
}
|
|
52
|
-
return target;
|
|
53
|
-
};
|
|
54
26
|
var __export = (target, all) => {
|
|
55
27
|
for (var name in all)
|
|
56
28
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -72,27 +44,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
72
44
|
mod
|
|
73
45
|
));
|
|
74
46
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
75
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
76
|
-
var __async = (__this, __arguments, generator) => {
|
|
77
|
-
return new Promise((resolve, reject) => {
|
|
78
|
-
var fulfilled = (value) => {
|
|
79
|
-
try {
|
|
80
|
-
step(generator.next(value));
|
|
81
|
-
} catch (e) {
|
|
82
|
-
reject(e);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
var rejected = (value) => {
|
|
86
|
-
try {
|
|
87
|
-
step(generator.throw(value));
|
|
88
|
-
} catch (e) {
|
|
89
|
-
reject(e);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
93
|
-
step((generator = generator.apply(__this, __arguments)).next());
|
|
94
|
-
});
|
|
95
|
-
};
|
|
96
47
|
|
|
97
48
|
// lib/index.ts
|
|
98
49
|
var lib_exports = {};
|
|
@@ -132,6 +83,7 @@ __export(lib_exports, {
|
|
|
132
83
|
joinArrayReadable: () => joinArrayReadable,
|
|
133
84
|
lightenColor: () => lightenColor,
|
|
134
85
|
mapRange: () => mapRange,
|
|
86
|
+
overflowVal: () => overflowVal,
|
|
135
87
|
pauseFor: () => pauseFor,
|
|
136
88
|
pureObj: () => pureObj,
|
|
137
89
|
randRange: () => randRange,
|
|
@@ -195,6 +147,19 @@ function mapRange(value, range1min, range1max, range2min, range2max) {
|
|
|
195
147
|
return value * (range2max / range1max);
|
|
196
148
|
return (value - range1min) * ((range2max - range2min) / (range1max - range1min)) + range2min;
|
|
197
149
|
}
|
|
150
|
+
function overflowVal(value, minOrMax, max) {
|
|
151
|
+
const min = typeof max === "number" ? minOrMax : 0;
|
|
152
|
+
max = typeof max === "number" ? max : minOrMax;
|
|
153
|
+
if (min > max)
|
|
154
|
+
throw new RangeError(`Parameter "min" can't be bigger than "max"`);
|
|
155
|
+
if (isNaN(value) || isNaN(min) || isNaN(max) || !isFinite(value) || !isFinite(min) || !isFinite(max))
|
|
156
|
+
return NaN;
|
|
157
|
+
if (value >= min && value <= max)
|
|
158
|
+
return value;
|
|
159
|
+
const range = max - min + 1;
|
|
160
|
+
const wrappedValue = ((value - min) % range + range) % range + min;
|
|
161
|
+
return wrappedValue;
|
|
162
|
+
}
|
|
198
163
|
function randRange(...args) {
|
|
199
164
|
let min, max, enhancedEntropy = false;
|
|
200
165
|
if (typeof args[0] === "number" && typeof args[1] === "number")
|
|
@@ -225,7 +190,7 @@ function randRange(...args) {
|
|
|
225
190
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
226
191
|
}
|
|
227
192
|
function roundFixed(num, fractionDigits) {
|
|
228
|
-
const scale =
|
|
193
|
+
const scale = 10 ** fractionDigits;
|
|
229
194
|
return Math.round(num * scale) / scale;
|
|
230
195
|
}
|
|
231
196
|
function valsWithin(a, b, dec = 10, withinRange = 0.5) {
|
|
@@ -289,11 +254,9 @@ function darkenColor(color, percent, upperCase = false) {
|
|
|
289
254
|
if (isHexCol)
|
|
290
255
|
return rgbToHex(r, g, b, a, color.startsWith("#"), upperCase);
|
|
291
256
|
else if (color.startsWith("rgba"))
|
|
292
|
-
return `rgba(${r}, ${g}, ${b}, ${a
|
|
293
|
-
else if (color.startsWith("rgb"))
|
|
294
|
-
return `rgb(${r}, ${g}, ${b})`;
|
|
257
|
+
return `rgba(${r}, ${g}, ${b}, ${a ?? NaN})`;
|
|
295
258
|
else
|
|
296
|
-
|
|
259
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
297
260
|
}
|
|
298
261
|
function hexToRgb(hex) {
|
|
299
262
|
hex = (hex.startsWith("#") ? hex.slice(1) : hex).trim();
|
|
@@ -325,43 +288,35 @@ function abtoa(buf) {
|
|
|
325
288
|
function atoab(str) {
|
|
326
289
|
return Uint8Array.from(atob(str), (c) => c.charCodeAt(0));
|
|
327
290
|
}
|
|
328
|
-
function compress(input, compressionFormat, outputType = "string") {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const buf = yield new Response(comp.readable).arrayBuffer();
|
|
337
|
-
return outputType === "arrayBuffer" ? buf : abtoa(buf);
|
|
338
|
-
});
|
|
291
|
+
async function compress(input, compressionFormat, outputType = "string") {
|
|
292
|
+
const byteArray = input instanceof Uint8Array ? input : new TextEncoder().encode((input == null ? void 0 : input.toString()) ?? String(input));
|
|
293
|
+
const comp = new CompressionStream(compressionFormat);
|
|
294
|
+
const writer = comp.writable.getWriter();
|
|
295
|
+
writer.write(byteArray);
|
|
296
|
+
writer.close();
|
|
297
|
+
const uintArr = new Uint8Array(await new Response(comp.readable).arrayBuffer());
|
|
298
|
+
return outputType === "arrayBuffer" ? uintArr : abtoa(uintArr);
|
|
339
299
|
}
|
|
340
|
-
function decompress(input, compressionFormat, outputType = "string") {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
const buf = yield new Response(decomp.readable).arrayBuffer();
|
|
349
|
-
return outputType === "arrayBuffer" ? buf : new TextDecoder().decode(buf);
|
|
350
|
-
});
|
|
300
|
+
async function decompress(input, compressionFormat, outputType = "string") {
|
|
301
|
+
const byteArray = input instanceof Uint8Array ? input : atoab((input == null ? void 0 : input.toString()) ?? String(input));
|
|
302
|
+
const decomp = new DecompressionStream(compressionFormat);
|
|
303
|
+
const writer = decomp.writable.getWriter();
|
|
304
|
+
writer.write(byteArray);
|
|
305
|
+
writer.close();
|
|
306
|
+
const uintArr = new Uint8Array(await new Response(decomp.readable).arrayBuffer());
|
|
307
|
+
return outputType === "arrayBuffer" ? uintArr : new TextDecoder().decode(uintArr);
|
|
351
308
|
}
|
|
352
|
-
function computeHash(input, algorithm = "SHA-256") {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
return hashHex;
|
|
364
|
-
});
|
|
309
|
+
async function computeHash(input, algorithm = "SHA-256") {
|
|
310
|
+
let data;
|
|
311
|
+
if (typeof input === "string") {
|
|
312
|
+
const encoder = new TextEncoder();
|
|
313
|
+
data = encoder.encode(input);
|
|
314
|
+
} else
|
|
315
|
+
data = input;
|
|
316
|
+
const hashBuffer = await crypto.subtle.digest(algorithm, data);
|
|
317
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
318
|
+
const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
319
|
+
return hashHex;
|
|
365
320
|
}
|
|
366
321
|
function randomId(length = 16, radix = 16, enhancedEntropy = false, randomCase = true) {
|
|
367
322
|
if (length < 1)
|
|
@@ -389,38 +344,35 @@ function randomId(length = 16, radix = 16, enhancedEntropy = false, randomCase =
|
|
|
389
344
|
}
|
|
390
345
|
|
|
391
346
|
// lib/misc.ts
|
|
392
|
-
function consumeGen(valGen) {
|
|
393
|
-
return
|
|
394
|
-
return yield typeof valGen === "function" ? valGen() : valGen;
|
|
395
|
-
});
|
|
347
|
+
async function consumeGen(valGen) {
|
|
348
|
+
return await (typeof valGen === "function" ? valGen() : valGen);
|
|
396
349
|
}
|
|
397
|
-
function consumeStringGen(strGen) {
|
|
398
|
-
return
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
);
|
|
402
|
-
});
|
|
350
|
+
async function consumeStringGen(strGen) {
|
|
351
|
+
return typeof strGen === "string" ? strGen : String(
|
|
352
|
+
typeof strGen === "function" ? await strGen() : strGen
|
|
353
|
+
);
|
|
403
354
|
}
|
|
404
|
-
function fetchAdvanced(
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
355
|
+
async function fetchAdvanced(input, options = {}) {
|
|
356
|
+
const { timeout = 1e4 } = options;
|
|
357
|
+
const ctl = new AbortController();
|
|
358
|
+
const { signal, ...restOpts } = options;
|
|
359
|
+
signal == null ? void 0 : signal.addEventListener("abort", () => ctl.abort());
|
|
360
|
+
let sigOpts = {}, id = void 0;
|
|
361
|
+
if (timeout >= 0) {
|
|
362
|
+
id = setTimeout(() => ctl.abort(), timeout);
|
|
363
|
+
sigOpts = { signal: ctl.signal };
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
const res = await fetch(input, {
|
|
367
|
+
...restOpts,
|
|
368
|
+
...sigOpts
|
|
369
|
+
});
|
|
370
|
+
typeof id !== "undefined" && clearTimeout(id);
|
|
371
|
+
return res;
|
|
372
|
+
} catch (err) {
|
|
373
|
+
typeof id !== "undefined" && clearTimeout(id);
|
|
374
|
+
throw new Error("Error while calling fetch", { cause: err });
|
|
375
|
+
}
|
|
424
376
|
}
|
|
425
377
|
function getListLength(listLike, zeroOnInvalid = true) {
|
|
426
378
|
return "length" in listLike ? listLike.length : "size" in listLike ? listLike.size : "count" in listLike ? listLike.count : zeroOnInvalid ? 0 : NaN;
|
|
@@ -435,7 +387,7 @@ function pauseFor(time, signal, rejectOnAbort = false) {
|
|
|
435
387
|
});
|
|
436
388
|
}
|
|
437
389
|
function pureObj(obj) {
|
|
438
|
-
return Object.assign(/* @__PURE__ */ Object.create(null), obj
|
|
390
|
+
return Object.assign(/* @__PURE__ */ Object.create(null), obj ?? {});
|
|
439
391
|
}
|
|
440
392
|
function setImmediateInterval(callback, interval, signal) {
|
|
441
393
|
let intervalId;
|
|
@@ -452,12 +404,12 @@ function setImmediateInterval(callback, interval, signal) {
|
|
|
452
404
|
function setImmediateTimeoutLoop(callback, interval, signal) {
|
|
453
405
|
let timeout;
|
|
454
406
|
const cleanup = () => clearTimeout(timeout);
|
|
455
|
-
const loop = () =>
|
|
407
|
+
const loop = async () => {
|
|
456
408
|
if (signal == null ? void 0 : signal.aborted)
|
|
457
409
|
return cleanup();
|
|
458
|
-
|
|
410
|
+
await callback();
|
|
459
411
|
timeout = setTimeout(loop, interval);
|
|
460
|
-
}
|
|
412
|
+
};
|
|
461
413
|
signal == null ? void 0 : signal.addEventListener("abort", cleanup);
|
|
462
414
|
loop();
|
|
463
415
|
}
|
|
@@ -524,9 +476,9 @@ function createProgressBar(percentage, barLength, chars = defaultPbChars) {
|
|
|
524
476
|
}
|
|
525
477
|
function insertValues(input, ...values) {
|
|
526
478
|
return input.replace(/%\d/gm, (match) => {
|
|
527
|
-
var _a
|
|
479
|
+
var _a;
|
|
528
480
|
const argIndex = Number(match.substring(1)) - 1;
|
|
529
|
-
return (
|
|
481
|
+
return (_a = values[argIndex] ?? match) == null ? void 0 : _a.toString();
|
|
530
482
|
});
|
|
531
483
|
}
|
|
532
484
|
function joinArrayReadable(array, separators = ", ", lastSeparator = " and ") {
|
|
@@ -555,17 +507,16 @@ function secsToTimeStr(seconds) {
|
|
|
555
507
|
].join("");
|
|
556
508
|
}
|
|
557
509
|
function truncStr(input, length, endStr = "...") {
|
|
558
|
-
|
|
559
|
-
const str = (_a = input == null ? void 0 : input.toString()) != null ? _a : String(input);
|
|
510
|
+
const str = (input == null ? void 0 : input.toString()) ?? String(input);
|
|
560
511
|
const finalStr = str.length > length ? str.substring(0, length - endStr.length) + endStr : str;
|
|
561
512
|
return finalStr.length > length ? finalStr.substring(0, length) : finalStr;
|
|
562
513
|
}
|
|
563
514
|
|
|
564
515
|
// lib/Errors.ts
|
|
565
516
|
var DatedError = class extends Error {
|
|
517
|
+
date;
|
|
566
518
|
constructor(message, options) {
|
|
567
519
|
super(message, options);
|
|
568
|
-
__publicField(this, "date");
|
|
569
520
|
this.name = this.constructor.name;
|
|
570
521
|
this.date = /* @__PURE__ */ new Date();
|
|
571
522
|
}
|
|
@@ -592,28 +543,35 @@ var ValidationError = class extends DatedError {
|
|
|
592
543
|
// lib/DataStore.ts
|
|
593
544
|
var dsFmtVer = 1;
|
|
594
545
|
var DataStore = class {
|
|
546
|
+
id;
|
|
547
|
+
formatVersion;
|
|
548
|
+
defaultData;
|
|
549
|
+
encodeData;
|
|
550
|
+
decodeData;
|
|
551
|
+
compressionFormat = "deflate-raw";
|
|
552
|
+
engine;
|
|
553
|
+
options;
|
|
554
|
+
/**
|
|
555
|
+
* Whether all first-init checks should be done.
|
|
556
|
+
* This includes migrating the internal DataStore format, migrating data from the UserUtils format, and anything similar.
|
|
557
|
+
* This is set to `true` by default. Create a subclass and set it to `false` before calling {@linkcode loadData()} if you want to explicitly skip these checks.
|
|
558
|
+
*/
|
|
559
|
+
firstInit = true;
|
|
560
|
+
/** In-memory cached copy of the data that is saved in persistent storage used for synchronous read access. */
|
|
561
|
+
cachedData;
|
|
562
|
+
migrations;
|
|
563
|
+
migrateIds = [];
|
|
595
564
|
/**
|
|
596
565
|
* Creates an instance of DataStore to manage a sync & async database that is cached in memory and persistently saved across sessions.
|
|
597
566
|
* Supports migrating data from older versions to newer ones and populating the cache with default data if no persistent data is found.
|
|
598
567
|
*
|
|
599
|
-
* - ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue` if the storageMethod is left as the default of `"GM"`
|
|
600
568
|
* - ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
|
|
601
569
|
*
|
|
602
570
|
* @template TData The type of the data that is saved in persistent storage for the currently set format version (will be automatically inferred from `defaultData` if not provided) - **This has to be a JSON-compatible object!** (no undefined, circular references, etc.)
|
|
603
571
|
* @param opts The options for this DataStore instance
|
|
604
572
|
*/
|
|
605
573
|
constructor(opts) {
|
|
606
|
-
|
|
607
|
-
__publicField(this, "formatVersion");
|
|
608
|
-
__publicField(this, "defaultData");
|
|
609
|
-
__publicField(this, "encodeData");
|
|
610
|
-
__publicField(this, "decodeData");
|
|
611
|
-
__publicField(this, "compressionFormat", "deflate-raw");
|
|
612
|
-
__publicField(this, "engine");
|
|
613
|
-
__publicField(this, "firstInit", true);
|
|
614
|
-
__publicField(this, "cachedData");
|
|
615
|
-
__publicField(this, "migrations");
|
|
616
|
-
__publicField(this, "migrateIds", []);
|
|
574
|
+
var _a;
|
|
617
575
|
this.id = opts.id;
|
|
618
576
|
this.formatVersion = opts.formatVersion;
|
|
619
577
|
this.defaultData = opts.defaultData;
|
|
@@ -624,15 +582,12 @@ var DataStore = class {
|
|
|
624
582
|
this.encodeData = opts.encodeData;
|
|
625
583
|
this.decodeData = opts.decodeData;
|
|
626
584
|
this.engine = typeof opts.engine === "function" ? opts.engine() : opts.engine;
|
|
585
|
+
this.options = opts;
|
|
627
586
|
if (typeof opts.compressionFormat === "undefined")
|
|
628
|
-
opts.compressionFormat = "deflate-raw";
|
|
587
|
+
opts.compressionFormat = ((_a = opts.encodeData) == null ? void 0 : _a[0]) ?? "deflate-raw";
|
|
629
588
|
if (typeof opts.compressionFormat === "string") {
|
|
630
|
-
this.encodeData = [opts.compressionFormat, (data) =>
|
|
631
|
-
|
|
632
|
-
})];
|
|
633
|
-
this.decodeData = [opts.compressionFormat, (data) => __async(this, null, function* () {
|
|
634
|
-
return yield compress(data, opts.compressionFormat, "string");
|
|
635
|
-
})];
|
|
589
|
+
this.encodeData = [opts.compressionFormat, async (data) => await compress(data, opts.compressionFormat, "string")];
|
|
590
|
+
this.decodeData = [opts.compressionFormat, async (data) => await compress(data, opts.compressionFormat, "string")];
|
|
636
591
|
} else if ("encodeData" in opts && "decodeData" in opts && Array.isArray(opts.encodeData) && Array.isArray(opts.decodeData)) {
|
|
637
592
|
this.encodeData = [opts.encodeData[0], opts.encodeData[1]];
|
|
638
593
|
this.decodeData = [opts.decodeData[0], opts.decodeData[1]];
|
|
@@ -649,58 +604,62 @@ var DataStore = class {
|
|
|
649
604
|
* Automatically populates persistent storage with default data if it doesn't contain any data yet.
|
|
650
605
|
* Also runs all necessary migration functions if the data format has changed since the last time the data was saved.
|
|
651
606
|
*/
|
|
652
|
-
loadData() {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
607
|
+
async loadData() {
|
|
608
|
+
try {
|
|
609
|
+
if (this.firstInit) {
|
|
610
|
+
this.firstInit = false;
|
|
611
|
+
const dsVer = Number(await this.engine.getValue("__ds_fmt_ver", 0));
|
|
612
|
+
if (isNaN(dsVer) || dsVer < 1) {
|
|
613
|
+
const oldData = await this.engine.getValue(`_uucfg-${this.id}`, null);
|
|
614
|
+
if (oldData) {
|
|
615
|
+
const oldVer = Number(await this.engine.getValue(`_uucfgver-${this.id}`, NaN));
|
|
616
|
+
const oldEnc = await this.engine.getValue(`_uucfgenc-${this.id}`, null);
|
|
617
|
+
const promises = [];
|
|
618
|
+
const migrateFmt = (oldKey, newKey, value) => {
|
|
619
|
+
promises.push(this.engine.setValue(newKey, value));
|
|
620
|
+
promises.push(this.engine.deleteValue(oldKey));
|
|
621
|
+
};
|
|
622
|
+
if (oldData)
|
|
623
|
+
migrateFmt(`_uucfg-${this.id}`, `__ds-${this.id}-dat`, oldData);
|
|
624
|
+
if (!isNaN(oldVer))
|
|
625
|
+
migrateFmt(`_uucfgver-${this.id}`, `__ds-${this.id}-ver`, oldVer);
|
|
626
|
+
if (typeof oldEnc === "boolean")
|
|
627
|
+
migrateFmt(`_uucfgenc-${this.id}`, `__ds-${this.id}-enf`, oldEnc === true ? Boolean(this.compressionFormat) || null : null);
|
|
628
|
+
else
|
|
629
|
+
promises.push(this.engine.setValue(`__ds-${this.id}-enf`, this.compressionFormat));
|
|
630
|
+
await Promise.allSettled(promises);
|
|
674
631
|
}
|
|
632
|
+
await this.engine.setValue("__ds_fmt_ver", dsFmtVer);
|
|
675
633
|
}
|
|
676
|
-
if (this.migrateIds.length > 0) {
|
|
677
|
-
yield this.migrateId(this.migrateIds);
|
|
678
|
-
this.migrateIds = [];
|
|
679
|
-
}
|
|
680
|
-
const gmData = yield this.engine.getValue(`__ds-${this.id}-dat`, JSON.stringify(this.defaultData));
|
|
681
|
-
let gmFmtVer = Number(yield this.engine.getValue(`__ds-${this.id}-ver`, NaN));
|
|
682
|
-
if (typeof gmData !== "string") {
|
|
683
|
-
yield this.saveDefaultData();
|
|
684
|
-
return __spreadValues({}, this.defaultData);
|
|
685
|
-
}
|
|
686
|
-
const isEncoded = Boolean(yield this.engine.getValue(`__ds-${this.id}-enc`, false));
|
|
687
|
-
let saveData = false;
|
|
688
|
-
if (isNaN(gmFmtVer)) {
|
|
689
|
-
yield this.engine.setValue(`__ds-${this.id}-ver`, gmFmtVer = this.formatVersion);
|
|
690
|
-
saveData = true;
|
|
691
|
-
}
|
|
692
|
-
let parsed = yield this.engine.deserializeData(gmData, isEncoded);
|
|
693
|
-
if (gmFmtVer < this.formatVersion && this.migrations)
|
|
694
|
-
parsed = yield this.runMigrations(parsed, gmFmtVer);
|
|
695
|
-
if (saveData)
|
|
696
|
-
yield this.setData(parsed);
|
|
697
|
-
return this.cachedData = this.engine.deepCopy(parsed);
|
|
698
|
-
} catch (err) {
|
|
699
|
-
console.warn("Error while parsing JSON data, resetting it to the default value.", err);
|
|
700
|
-
yield this.saveDefaultData();
|
|
701
|
-
return this.defaultData;
|
|
702
634
|
}
|
|
703
|
-
|
|
635
|
+
if (this.migrateIds.length > 0) {
|
|
636
|
+
await this.migrateId(this.migrateIds);
|
|
637
|
+
this.migrateIds = [];
|
|
638
|
+
}
|
|
639
|
+
const storedData = await this.engine.getValue(`__ds-${this.id}-dat`, JSON.stringify(this.defaultData));
|
|
640
|
+
let storedFmtVer = Number(await this.engine.getValue(`__ds-${this.id}-ver`, NaN));
|
|
641
|
+
if (typeof storedData !== "string") {
|
|
642
|
+
await this.saveDefaultData();
|
|
643
|
+
return { ...this.defaultData };
|
|
644
|
+
}
|
|
645
|
+
const encodingFmt = String(await this.engine.getValue(`__ds-${this.id}-enf`, null));
|
|
646
|
+
const isEncoded = encodingFmt !== "null" && encodingFmt !== "false";
|
|
647
|
+
let saveData = false;
|
|
648
|
+
if (isNaN(storedFmtVer)) {
|
|
649
|
+
await this.engine.setValue(`__ds-${this.id}-ver`, storedFmtVer = this.formatVersion);
|
|
650
|
+
saveData = true;
|
|
651
|
+
}
|
|
652
|
+
let parsed = await this.engine.deserializeData(storedData, isEncoded);
|
|
653
|
+
if (storedFmtVer < this.formatVersion && this.migrations)
|
|
654
|
+
parsed = await this.runMigrations(parsed, storedFmtVer);
|
|
655
|
+
if (saveData)
|
|
656
|
+
await this.setData(parsed);
|
|
657
|
+
return this.cachedData = this.engine.deepCopy(parsed);
|
|
658
|
+
} catch (err) {
|
|
659
|
+
console.warn("Error while parsing JSON data, resetting it to the default value.", err);
|
|
660
|
+
await this.saveDefaultData();
|
|
661
|
+
return this.defaultData;
|
|
662
|
+
}
|
|
704
663
|
}
|
|
705
664
|
/**
|
|
706
665
|
* Returns a copy of the data from the in-memory cache.
|
|
@@ -712,47 +671,41 @@ var DataStore = class {
|
|
|
712
671
|
/** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
|
|
713
672
|
setData(data) {
|
|
714
673
|
this.cachedData = data;
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
this.engine.setValue(`__ds-${this.id}-dat`, yield this.engine.serializeData(data, useEncoding)),
|
|
674
|
+
return new Promise(async (resolve) => {
|
|
675
|
+
await Promise.allSettled([
|
|
676
|
+
this.engine.setValue(`__ds-${this.id}-dat`, await this.engine.serializeData(data, this.encodingEnabled())),
|
|
719
677
|
this.engine.setValue(`__ds-${this.id}-ver`, this.formatVersion),
|
|
720
|
-
this.engine.setValue(`__ds-${this.id}-
|
|
678
|
+
this.engine.setValue(`__ds-${this.id}-enf`, this.compressionFormat)
|
|
721
679
|
]);
|
|
722
680
|
resolve();
|
|
723
|
-
})
|
|
681
|
+
});
|
|
724
682
|
}
|
|
725
683
|
/** Saves the default data passed in the constructor synchronously to the in-memory cache and asynchronously to persistent storage */
|
|
726
|
-
saveDefaultData() {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
this.engine.setValue(`__ds-${this.id}-enc`, useEncoding)
|
|
734
|
-
]);
|
|
735
|
-
});
|
|
684
|
+
async saveDefaultData() {
|
|
685
|
+
this.cachedData = this.defaultData;
|
|
686
|
+
await Promise.allSettled([
|
|
687
|
+
this.engine.setValue(`__ds-${this.id}-dat`, await this.engine.serializeData(this.defaultData, this.encodingEnabled())),
|
|
688
|
+
this.engine.setValue(`__ds-${this.id}-ver`, this.formatVersion),
|
|
689
|
+
this.engine.setValue(`__ds-${this.id}-enf`, this.compressionFormat)
|
|
690
|
+
]);
|
|
736
691
|
}
|
|
737
692
|
/**
|
|
738
|
-
* Call this method to clear all persistently stored data associated with this DataStore instance.
|
|
693
|
+
* Call this method to clear all persistently stored data associated with this DataStore instance, including the storage container (if supported by the DataStoreEngine).
|
|
739
694
|
* The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
|
|
740
|
-
* Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
|
|
741
|
-
*
|
|
742
|
-
* - ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
|
|
695
|
+
* Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
|
|
743
696
|
*/
|
|
744
|
-
deleteData() {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
697
|
+
async deleteData() {
|
|
698
|
+
var _a, _b;
|
|
699
|
+
await Promise.allSettled([
|
|
700
|
+
this.engine.deleteValue(`__ds-${this.id}-dat`),
|
|
701
|
+
this.engine.deleteValue(`__ds-${this.id}-ver`),
|
|
702
|
+
this.engine.deleteValue(`__ds-${this.id}-enf`)
|
|
703
|
+
]);
|
|
704
|
+
await ((_b = (_a = this.engine).deleteStorage) == null ? void 0 : _b.call(_a));
|
|
752
705
|
}
|
|
753
706
|
/** Returns whether encoding and decoding are enabled for this DataStore instance */
|
|
754
707
|
encodingEnabled() {
|
|
755
|
-
return Boolean(this.encodeData && this.decodeData);
|
|
708
|
+
return Boolean(this.encodeData && this.decodeData) && this.compressionFormat !== null || Boolean(this.compressionFormat);
|
|
756
709
|
}
|
|
757
710
|
//#region migrations
|
|
758
711
|
/**
|
|
@@ -762,98 +715,106 @@ var DataStore = class {
|
|
|
762
715
|
*
|
|
763
716
|
* If one of the migrations fails, the data will be reset to the default value if `resetOnError` is set to `true` (default). Otherwise, an error will be thrown and no data will be saved.
|
|
764
717
|
*/
|
|
765
|
-
runMigrations(oldData, oldFmtVer, resetOnError = true) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
return this.getData();
|
|
784
|
-
}
|
|
718
|
+
async runMigrations(oldData, oldFmtVer, resetOnError = true) {
|
|
719
|
+
if (!this.migrations)
|
|
720
|
+
return oldData;
|
|
721
|
+
let newData = oldData;
|
|
722
|
+
const sortedMigrations = Object.entries(this.migrations).sort(([a], [b]) => Number(a) - Number(b));
|
|
723
|
+
let lastFmtVer = oldFmtVer;
|
|
724
|
+
for (const [fmtVer, migrationFunc] of sortedMigrations) {
|
|
725
|
+
const ver = Number(fmtVer);
|
|
726
|
+
if (oldFmtVer < this.formatVersion && oldFmtVer < ver) {
|
|
727
|
+
try {
|
|
728
|
+
const migRes = migrationFunc(newData);
|
|
729
|
+
newData = migRes instanceof Promise ? await migRes : migRes;
|
|
730
|
+
lastFmtVer = oldFmtVer = ver;
|
|
731
|
+
} catch (err) {
|
|
732
|
+
if (!resetOnError)
|
|
733
|
+
throw new MigrationError(`Error while running migration function for format version '${fmtVer}'`, { cause: err });
|
|
734
|
+
await this.saveDefaultData();
|
|
735
|
+
return this.getData();
|
|
785
736
|
}
|
|
786
737
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
}
|
|
738
|
+
}
|
|
739
|
+
await Promise.allSettled([
|
|
740
|
+
this.engine.setValue(`__ds-${this.id}-dat`, await this.engine.serializeData(newData)),
|
|
741
|
+
this.engine.setValue(`__ds-${this.id}-ver`, lastFmtVer),
|
|
742
|
+
this.engine.setValue(`__ds-${this.id}-enf`, this.compressionFormat)
|
|
743
|
+
]);
|
|
744
|
+
return this.cachedData = { ...newData };
|
|
794
745
|
}
|
|
795
746
|
/**
|
|
796
747
|
* Tries to migrate the currently saved persistent data from one or more old IDs to the ID set in the constructor.
|
|
797
748
|
* If no data exist for the old ID(s), nothing will be done, but some time may still pass trying to fetch the non-existent data.
|
|
798
749
|
*/
|
|
799
|
-
migrateId(oldIds) {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
return;
|
|
808
|
-
const parsed = yield this.engine.deserializeData(data, isEncoded);
|
|
809
|
-
yield Promise.allSettled([
|
|
810
|
-
this.engine.setValue(`__ds-${this.id}-dat`, yield this.engine.serializeData(parsed)),
|
|
811
|
-
this.engine.setValue(`__ds-${this.id}-ver`, fmtVer),
|
|
812
|
-
this.engine.setValue(`__ds-${this.id}-enc`, isEncoded),
|
|
813
|
-
this.engine.deleteValue(`__ds-${id}-dat`),
|
|
814
|
-
this.engine.deleteValue(`__ds-${id}-ver`),
|
|
815
|
-
this.engine.deleteValue(`__ds-${id}-enc`)
|
|
750
|
+
async migrateId(oldIds) {
|
|
751
|
+
const ids = Array.isArray(oldIds) ? oldIds : [oldIds];
|
|
752
|
+
await Promise.all(ids.map(async (id) => {
|
|
753
|
+
const [data, fmtVer, isEncoded] = await (async () => {
|
|
754
|
+
const [d, f, e] = await Promise.all([
|
|
755
|
+
this.engine.getValue(`__ds-${id}-dat`, JSON.stringify(this.defaultData)),
|
|
756
|
+
this.engine.getValue(`__ds-${id}-ver`, NaN),
|
|
757
|
+
this.engine.getValue(`__ds-${id}-enf`, null)
|
|
816
758
|
]);
|
|
817
|
-
|
|
818
|
-
|
|
759
|
+
return [d, Number(f), Boolean(e) && String(e) !== "null"];
|
|
760
|
+
})();
|
|
761
|
+
if (data === void 0 || isNaN(fmtVer))
|
|
762
|
+
return;
|
|
763
|
+
const parsed = await this.engine.deserializeData(data, isEncoded);
|
|
764
|
+
await Promise.allSettled([
|
|
765
|
+
this.engine.setValue(`__ds-${this.id}-dat`, await this.engine.serializeData(parsed)),
|
|
766
|
+
this.engine.setValue(`__ds-${this.id}-ver`, fmtVer),
|
|
767
|
+
this.engine.setValue(`__ds-${this.id}-enf`, this.compressionFormat),
|
|
768
|
+
this.engine.deleteValue(`__ds-${id}-dat`),
|
|
769
|
+
this.engine.deleteValue(`__ds-${id}-ver`),
|
|
770
|
+
this.engine.deleteValue(`__ds-${id}-enf`)
|
|
771
|
+
]);
|
|
772
|
+
}));
|
|
819
773
|
}
|
|
820
774
|
};
|
|
821
775
|
|
|
822
776
|
// lib/DataStoreEngine.ts
|
|
823
777
|
var DataStoreEngine = class {
|
|
824
|
-
|
|
825
|
-
__publicField(this, "dataStoreOptions");
|
|
826
|
-
}
|
|
778
|
+
dataStoreOptions;
|
|
827
779
|
// setDataStoreOptions() is called from inside the DataStore constructor to set this value
|
|
828
|
-
|
|
780
|
+
constructor(options) {
|
|
781
|
+
if (options)
|
|
782
|
+
this.dataStoreOptions = options;
|
|
783
|
+
}
|
|
784
|
+
/** Called by DataStore on creation, to pass its options. Only call this if you are using this instance standalone! */
|
|
829
785
|
setDataStoreOptions(dataStoreOptions) {
|
|
830
786
|
this.dataStoreOptions = dataStoreOptions;
|
|
831
787
|
}
|
|
832
788
|
//#region serialization api
|
|
833
789
|
/** Serializes the given object to a string, optionally encoded with `options.encodeData` if {@linkcode useEncoding} is set to true */
|
|
834
|
-
serializeData(data, useEncoding) {
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
});
|
|
790
|
+
async serializeData(data, useEncoding) {
|
|
791
|
+
var _a, _b, _c, _d, _e;
|
|
792
|
+
this.ensureDataStoreOptions();
|
|
793
|
+
const stringData = JSON.stringify(data);
|
|
794
|
+
if (!useEncoding || !((_a = this.dataStoreOptions) == null ? void 0 : _a.encodeData) || !((_b = this.dataStoreOptions) == null ? void 0 : _b.decodeData))
|
|
795
|
+
return stringData;
|
|
796
|
+
const encRes = (_e = (_d = (_c = this.dataStoreOptions) == null ? void 0 : _c.encodeData) == null ? void 0 : _d[1]) == null ? void 0 : _e.call(_d, stringData);
|
|
797
|
+
if (encRes instanceof Promise)
|
|
798
|
+
return await encRes;
|
|
799
|
+
return encRes;
|
|
845
800
|
}
|
|
846
801
|
/** Deserializes the given string to a JSON object, optionally decoded with `options.decodeData` if {@linkcode useEncoding} is set to true */
|
|
847
|
-
deserializeData(data, useEncoding) {
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
});
|
|
802
|
+
async deserializeData(data, useEncoding) {
|
|
803
|
+
var _a, _b, _c;
|
|
804
|
+
this.ensureDataStoreOptions();
|
|
805
|
+
let decRes = ((_a = this.dataStoreOptions) == null ? void 0 : _a.decodeData) && useEncoding ? (_c = (_b = this.dataStoreOptions.decodeData) == null ? void 0 : _b[1]) == null ? void 0 : _c.call(_b, data) : void 0;
|
|
806
|
+
if (decRes instanceof Promise)
|
|
807
|
+
decRes = await decRes;
|
|
808
|
+
return JSON.parse(decRes ?? data);
|
|
855
809
|
}
|
|
856
810
|
//#region misc api
|
|
811
|
+
/** Throws an error if the DataStoreOptions are not set or invalid */
|
|
812
|
+
ensureDataStoreOptions() {
|
|
813
|
+
if (!this.dataStoreOptions)
|
|
814
|
+
throw new DatedError("DataStoreEngine must be initialized with DataStore options before use. If you are using this instance standalone, set them in the constructor or call `setDataStoreOptions()` with the DataStore options.");
|
|
815
|
+
if (!this.dataStoreOptions.id)
|
|
816
|
+
throw new DatedError("DataStoreEngine must be initialized with a valid DataStore ID");
|
|
817
|
+
}
|
|
857
818
|
/**
|
|
858
819
|
* Copies a JSON-compatible object and loses all its internal references in the process.
|
|
859
820
|
* Uses [`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) if available, otherwise falls back to `JSON.parse(JSON.stringify(obj))`.
|
|
@@ -862,157 +823,158 @@ var DataStoreEngine = class {
|
|
|
862
823
|
try {
|
|
863
824
|
if ("structuredClone" in globalThis)
|
|
864
825
|
return structuredClone(obj);
|
|
865
|
-
} catch
|
|
826
|
+
} catch {
|
|
866
827
|
}
|
|
867
828
|
return JSON.parse(JSON.stringify(obj));
|
|
868
829
|
}
|
|
869
830
|
};
|
|
870
831
|
var BrowserStorageEngine = class extends DataStoreEngine {
|
|
832
|
+
options;
|
|
871
833
|
/**
|
|
872
834
|
* Creates an instance of `BrowserStorageEngine`.
|
|
873
835
|
*
|
|
874
|
-
* ⚠️ Requires a DOM environment
|
|
875
|
-
* ⚠️ Don't reuse
|
|
836
|
+
* - ⚠️ Requires a DOM environment
|
|
837
|
+
* - ⚠️ Don't reuse engines across multiple {@linkcode DataStore} instances
|
|
876
838
|
*/
|
|
877
839
|
constructor(options) {
|
|
878
|
-
super();
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
}
|
|
840
|
+
super(options == null ? void 0 : options.dataStoreOptions);
|
|
841
|
+
this.options = {
|
|
842
|
+
type: "localStorage",
|
|
843
|
+
...options
|
|
844
|
+
};
|
|
883
845
|
}
|
|
884
846
|
//#region storage api
|
|
885
847
|
/** Fetches a value from persistent storage */
|
|
886
|
-
getValue(name, defaultValue) {
|
|
887
|
-
return
|
|
888
|
-
var _a;
|
|
889
|
-
return (_a = this.options.type === "localStorage" ? globalThis.localStorage.getItem(name) : globalThis.sessionStorage.getItem(name)) != null ? _a : defaultValue;
|
|
890
|
-
});
|
|
848
|
+
async getValue(name, defaultValue) {
|
|
849
|
+
return (this.options.type === "localStorage" ? globalThis.localStorage.getItem(name) : globalThis.sessionStorage.getItem(name)) ?? defaultValue;
|
|
891
850
|
}
|
|
892
851
|
/** Sets a value in persistent storage */
|
|
893
|
-
setValue(name, value) {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
globalThis.sessionStorage.setItem(name, String(value));
|
|
899
|
-
});
|
|
852
|
+
async setValue(name, value) {
|
|
853
|
+
if (this.options.type === "localStorage")
|
|
854
|
+
globalThis.localStorage.setItem(name, String(value));
|
|
855
|
+
else
|
|
856
|
+
globalThis.sessionStorage.setItem(name, String(value));
|
|
900
857
|
}
|
|
901
858
|
/** Deletes a value from persistent storage */
|
|
902
|
-
deleteValue(name) {
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
globalThis.sessionStorage.removeItem(name);
|
|
908
|
-
});
|
|
859
|
+
async deleteValue(name) {
|
|
860
|
+
if (this.options.type === "localStorage")
|
|
861
|
+
globalThis.localStorage.removeItem(name);
|
|
862
|
+
else
|
|
863
|
+
globalThis.sessionStorage.removeItem(name);
|
|
909
864
|
}
|
|
910
865
|
};
|
|
911
866
|
var fs;
|
|
912
867
|
var FileStorageEngine = class extends DataStoreEngine {
|
|
868
|
+
options;
|
|
913
869
|
/**
|
|
914
870
|
* Creates an instance of `FileStorageEngine`.
|
|
915
871
|
*
|
|
916
|
-
* ⚠️ Requires Node.js or Deno with Node compatibility (v1.31+)
|
|
917
|
-
* ⚠️ Don't reuse
|
|
872
|
+
* - ⚠️ Requires Node.js or Deno with Node compatibility (v1.31+)
|
|
873
|
+
* - ⚠️ Don't reuse engines across multiple {@linkcode DataStore} instances
|
|
918
874
|
*/
|
|
919
875
|
constructor(options) {
|
|
920
|
-
super();
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
}
|
|
876
|
+
super(options == null ? void 0 : options.dataStoreOptions);
|
|
877
|
+
this.options = {
|
|
878
|
+
filePath: (id) => `.ds-${id}`,
|
|
879
|
+
...options
|
|
880
|
+
};
|
|
925
881
|
}
|
|
926
882
|
//#region json file
|
|
927
883
|
/** Reads the file contents */
|
|
928
|
-
readFile() {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
});
|
|
884
|
+
async readFile() {
|
|
885
|
+
var _a, _b, _c, _d;
|
|
886
|
+
this.ensureDataStoreOptions();
|
|
887
|
+
try {
|
|
888
|
+
if (!fs)
|
|
889
|
+
fs = (_a = await import("fs/promises")) == null ? void 0 : _a.default;
|
|
890
|
+
if (!fs)
|
|
891
|
+
throw new DatedError("FileStorageEngine requires Node.js or Deno with Node compatibility (v1.31+)", { cause: new Error("'node:fs/promises' module not available") });
|
|
892
|
+
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id);
|
|
893
|
+
const data = await fs.readFile(path, "utf-8");
|
|
894
|
+
return data ? JSON.parse(await ((_d = (_c = (_b = this.dataStoreOptions) == null ? void 0 : _b.decodeData) == null ? void 0 : _c[1]) == null ? void 0 : _d.call(_c, data)) ?? data) : void 0;
|
|
895
|
+
} catch {
|
|
896
|
+
return void 0;
|
|
897
|
+
}
|
|
943
898
|
}
|
|
944
899
|
/** Overwrites the file contents */
|
|
945
|
-
writeFile(data) {
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
});
|
|
900
|
+
async writeFile(data) {
|
|
901
|
+
var _a, _b, _c, _d;
|
|
902
|
+
this.ensureDataStoreOptions();
|
|
903
|
+
try {
|
|
904
|
+
if (!fs)
|
|
905
|
+
fs = (_a = await import("fs/promises")) == null ? void 0 : _a.default;
|
|
906
|
+
if (!fs)
|
|
907
|
+
throw new DatedError("FileStorageEngine requires Node.js or Deno with Node compatibility (v1.31+)", { cause: new Error("'node:fs/promises' module not available") });
|
|
908
|
+
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id);
|
|
909
|
+
await fs.mkdir(path.slice(0, path.lastIndexOf("/")), { recursive: true });
|
|
910
|
+
await fs.writeFile(path, await ((_d = (_c = (_b = this.dataStoreOptions) == null ? void 0 : _b.encodeData) == null ? void 0 : _c[1]) == null ? void 0 : _d.call(_c, JSON.stringify(data))) ?? JSON.stringify(data, void 0, 2), "utf-8");
|
|
911
|
+
} catch (err) {
|
|
912
|
+
console.error("Error writing file:", err);
|
|
913
|
+
}
|
|
960
914
|
}
|
|
961
915
|
//#region storage api
|
|
962
916
|
/** Fetches a value from persistent storage */
|
|
963
|
-
getValue(name, defaultValue) {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
return String(value != null ? value : defaultValue);
|
|
974
|
-
});
|
|
917
|
+
async getValue(name, defaultValue) {
|
|
918
|
+
const data = await this.readFile();
|
|
919
|
+
if (!data)
|
|
920
|
+
return defaultValue;
|
|
921
|
+
const value = data == null ? void 0 : data[name];
|
|
922
|
+
if (value === void 0)
|
|
923
|
+
return defaultValue;
|
|
924
|
+
if (typeof value === "string")
|
|
925
|
+
return value;
|
|
926
|
+
return String(value ?? defaultValue);
|
|
975
927
|
}
|
|
976
928
|
/** Sets a value in persistent storage */
|
|
977
|
-
setValue(name, value) {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
yield this.writeFile(data);
|
|
984
|
-
});
|
|
929
|
+
async setValue(name, value) {
|
|
930
|
+
let data = await this.readFile();
|
|
931
|
+
if (!data)
|
|
932
|
+
data = {};
|
|
933
|
+
data[name] = value;
|
|
934
|
+
await this.writeFile(data);
|
|
985
935
|
}
|
|
986
936
|
/** Deletes a value from persistent storage */
|
|
987
|
-
deleteValue(name) {
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
937
|
+
async deleteValue(name) {
|
|
938
|
+
const data = await this.readFile();
|
|
939
|
+
if (!data)
|
|
940
|
+
return;
|
|
941
|
+
delete data[name];
|
|
942
|
+
await this.writeFile(data);
|
|
943
|
+
}
|
|
944
|
+
/** Deletes the file that contains the data of this DataStore. */
|
|
945
|
+
async deleteStorage() {
|
|
946
|
+
var _a;
|
|
947
|
+
this.ensureDataStoreOptions();
|
|
948
|
+
try {
|
|
949
|
+
if (!fs)
|
|
950
|
+
fs = (_a = await import("fs/promises")) == null ? void 0 : _a.default;
|
|
951
|
+
if (!fs)
|
|
952
|
+
throw new DatedError("FileStorageEngine requires Node.js or Deno with Node compatibility (v1.31+)", { cause: new Error("'node:fs/promises' module not available") });
|
|
953
|
+
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id);
|
|
954
|
+
await fs.unlink(path);
|
|
955
|
+
} catch (err) {
|
|
956
|
+
console.error("Error deleting file:", err);
|
|
957
|
+
}
|
|
995
958
|
}
|
|
996
959
|
};
|
|
997
960
|
|
|
998
961
|
// lib/DataStoreSerializer.ts
|
|
999
962
|
var DataStoreSerializer = class _DataStoreSerializer {
|
|
963
|
+
stores;
|
|
964
|
+
options;
|
|
1000
965
|
constructor(stores, options = {}) {
|
|
1001
|
-
__publicField(this, "stores");
|
|
1002
|
-
__publicField(this, "options");
|
|
1003
966
|
if (!crypto || !crypto.subtle)
|
|
1004
967
|
throw new Error("DataStoreSerializer has to run in a secure context (HTTPS) or in another environment that implements the subtleCrypto API!");
|
|
1005
968
|
this.stores = stores;
|
|
1006
|
-
this.options =
|
|
969
|
+
this.options = {
|
|
1007
970
|
addChecksum: true,
|
|
1008
|
-
ensureIntegrity: true
|
|
1009
|
-
|
|
971
|
+
ensureIntegrity: true,
|
|
972
|
+
...options
|
|
973
|
+
};
|
|
1010
974
|
}
|
|
1011
975
|
/** Calculates the checksum of a string */
|
|
1012
|
-
calcChecksum(input) {
|
|
1013
|
-
return
|
|
1014
|
-
return computeHash(input, "SHA-256");
|
|
1015
|
-
});
|
|
976
|
+
async calcChecksum(input) {
|
|
977
|
+
return computeHash(input, "SHA-256");
|
|
1016
978
|
}
|
|
1017
979
|
/**
|
|
1018
980
|
* Serializes only a subset of the data stores into a string.
|
|
@@ -1020,68 +982,62 @@ var DataStoreSerializer = class _DataStoreSerializer {
|
|
|
1020
982
|
* @param useEncoding Whether to encode the data using each DataStore's `encodeData()` method
|
|
1021
983
|
* @param stringified Whether to return the result as a string or as an array of `SerializedDataStore` objects
|
|
1022
984
|
*/
|
|
1023
|
-
serializePartial(stores, useEncoding = true, stringified = true) {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
|
|
985
|
+
async serializePartial(stores, useEncoding = true, stringified = true) {
|
|
986
|
+
var _a;
|
|
987
|
+
const serData = [];
|
|
988
|
+
for (const storeInst of this.stores.filter((s) => typeof stores === "function" ? stores(s.id) : stores.includes(s.id))) {
|
|
989
|
+
const encoded = Boolean(useEncoding && storeInst.encodingEnabled() && ((_a = storeInst.encodeData) == null ? void 0 : _a[1]));
|
|
990
|
+
const data = encoded ? await storeInst.encodeData[1](JSON.stringify(storeInst.getData())) : JSON.stringify(storeInst.getData());
|
|
991
|
+
serData.push({
|
|
992
|
+
id: storeInst.id,
|
|
993
|
+
data,
|
|
994
|
+
formatVersion: storeInst.formatVersion,
|
|
995
|
+
encoded,
|
|
996
|
+
checksum: this.options.addChecksum ? await this.calcChecksum(data) : void 0
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
return stringified ? JSON.stringify(serData) : serData;
|
|
1038
1000
|
}
|
|
1039
1001
|
/**
|
|
1040
1002
|
* Serializes the data stores into a string.
|
|
1041
1003
|
* @param useEncoding Whether to encode the data using each DataStore's `encodeData()` method
|
|
1042
1004
|
* @param stringified Whether to return the result as a string or as an array of `SerializedDataStore` objects
|
|
1043
1005
|
*/
|
|
1044
|
-
serialize(useEncoding = true, stringified = true) {
|
|
1045
|
-
return
|
|
1046
|
-
return this.serializePartial(this.stores.map((s) => s.id), useEncoding, stringified);
|
|
1047
|
-
});
|
|
1006
|
+
async serialize(useEncoding = true, stringified = true) {
|
|
1007
|
+
return this.serializePartial(this.stores.map((s) => s.id), useEncoding, stringified);
|
|
1048
1008
|
}
|
|
1049
1009
|
/**
|
|
1050
1010
|
* Deserializes the data exported via {@linkcode serialize()} and imports only a subset into the DataStore instances.
|
|
1051
1011
|
* Also triggers the migration process if the data format has changed.
|
|
1052
1012
|
*/
|
|
1053
|
-
deserializePartial(stores, data) {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
throw new ChecksumMismatchError(`Checksum mismatch for DataStore with ID "${storeData.id}"!
|
|
1013
|
+
async deserializePartial(stores, data) {
|
|
1014
|
+
const deserStores = typeof data === "string" ? JSON.parse(data) : data;
|
|
1015
|
+
if (!Array.isArray(deserStores) || !deserStores.every(_DataStoreSerializer.isSerializedDataStoreObj))
|
|
1016
|
+
throw new TypeError("Invalid serialized data format! Expected an array of SerializedDataStore objects.");
|
|
1017
|
+
for (const storeData of deserStores.filter((s) => typeof stores === "function" ? stores(s.id) : stores.includes(s.id))) {
|
|
1018
|
+
const storeInst = this.stores.find((s) => s.id === storeData.id);
|
|
1019
|
+
if (!storeInst)
|
|
1020
|
+
throw new Error(`DataStore instance with ID "${storeData.id}" not found! Make sure to provide it in the DataStoreSerializer constructor.`);
|
|
1021
|
+
if (this.options.ensureIntegrity && typeof storeData.checksum === "string") {
|
|
1022
|
+
const checksum = await this.calcChecksum(storeData.data);
|
|
1023
|
+
if (checksum !== storeData.checksum)
|
|
1024
|
+
throw new ChecksumMismatchError(`Checksum mismatch for DataStore with ID "${storeData.id}"!
|
|
1066
1025
|
Expected: ${storeData.checksum}
|
|
1067
1026
|
Has: ${checksum}`);
|
|
1068
|
-
}
|
|
1069
|
-
const decodedData = storeData.encoded && storeInst.encodingEnabled() ? yield storeInst.decodeData[1](storeData.data) : storeData.data;
|
|
1070
|
-
if (storeData.formatVersion && !isNaN(Number(storeData.formatVersion)) && Number(storeData.formatVersion) < storeInst.formatVersion)
|
|
1071
|
-
yield storeInst.runMigrations(JSON.parse(decodedData), Number(storeData.formatVersion), false);
|
|
1072
|
-
else
|
|
1073
|
-
yield storeInst.setData(JSON.parse(decodedData));
|
|
1074
1027
|
}
|
|
1075
|
-
|
|
1028
|
+
const decodedData = storeData.encoded && storeInst.encodingEnabled() ? await storeInst.decodeData[1](storeData.data) : storeData.data;
|
|
1029
|
+
if (storeData.formatVersion && !isNaN(Number(storeData.formatVersion)) && Number(storeData.formatVersion) < storeInst.formatVersion)
|
|
1030
|
+
await storeInst.runMigrations(JSON.parse(decodedData), Number(storeData.formatVersion), false);
|
|
1031
|
+
else
|
|
1032
|
+
await storeInst.setData(JSON.parse(decodedData));
|
|
1033
|
+
}
|
|
1076
1034
|
}
|
|
1077
1035
|
/**
|
|
1078
1036
|
* Deserializes the data exported via {@linkcode serialize()} and imports the data into all matching DataStore instances.
|
|
1079
1037
|
* Also triggers the migration process if the data format has changed.
|
|
1080
1038
|
*/
|
|
1081
|
-
deserialize(data) {
|
|
1082
|
-
return
|
|
1083
|
-
return this.deserializePartial(this.stores.map((s) => s.id), data);
|
|
1084
|
-
});
|
|
1039
|
+
async deserialize(data) {
|
|
1040
|
+
return this.deserializePartial(this.stores.map((s) => s.id), data);
|
|
1085
1041
|
}
|
|
1086
1042
|
/**
|
|
1087
1043
|
* Loads the persistent data of the DataStore instances into the in-memory cache.
|
|
@@ -1089,40 +1045,32 @@ Has: ${checksum}`);
|
|
|
1089
1045
|
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be loaded
|
|
1090
1046
|
* @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
|
|
1091
1047
|
*/
|
|
1092
|
-
loadStoresData(stores) {
|
|
1093
|
-
return
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
};
|
|
1100
|
-
}))
|
|
1101
|
-
);
|
|
1102
|
-
});
|
|
1048
|
+
async loadStoresData(stores) {
|
|
1049
|
+
return Promise.allSettled(
|
|
1050
|
+
this.getStoresFiltered(stores).map(async (store) => ({
|
|
1051
|
+
id: store.id,
|
|
1052
|
+
data: await store.loadData()
|
|
1053
|
+
}))
|
|
1054
|
+
);
|
|
1103
1055
|
}
|
|
1104
1056
|
/**
|
|
1105
1057
|
* Resets the persistent and in-memory data of the DataStore instances to their default values.
|
|
1106
1058
|
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be affected
|
|
1107
1059
|
*/
|
|
1108
|
-
resetStoresData(stores) {
|
|
1109
|
-
return
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
);
|
|
1113
|
-
});
|
|
1060
|
+
async resetStoresData(stores) {
|
|
1061
|
+
return Promise.allSettled(
|
|
1062
|
+
this.getStoresFiltered(stores).map((store) => store.saveDefaultData())
|
|
1063
|
+
);
|
|
1114
1064
|
}
|
|
1115
1065
|
/**
|
|
1116
1066
|
* Deletes the persistent data of the DataStore instances.
|
|
1117
1067
|
* Leaves the in-memory data untouched.
|
|
1118
1068
|
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be affected
|
|
1119
1069
|
*/
|
|
1120
|
-
deleteStoresData(stores) {
|
|
1121
|
-
return
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
);
|
|
1125
|
-
});
|
|
1070
|
+
async deleteStoresData(stores) {
|
|
1071
|
+
return Promise.allSettled(
|
|
1072
|
+
this.getStoresFiltered(stores).map((store) => store.deleteData())
|
|
1073
|
+
);
|
|
1126
1074
|
}
|
|
1127
1075
|
/** Checks if a given value is an array of SerializedDataStore objects */
|
|
1128
1076
|
static isSerializedDataStoreObjArray(obj) {
|
|
@@ -1147,27 +1095,28 @@ var createNanoEvents = () => ({
|
|
|
1147
1095
|
},
|
|
1148
1096
|
events: {},
|
|
1149
1097
|
on(event, cb) {
|
|
1150
|
-
var _a;
|
|
1151
1098
|
;
|
|
1152
|
-
(
|
|
1099
|
+
(this.events[event] ||= []).push(cb);
|
|
1153
1100
|
return () => {
|
|
1154
|
-
var
|
|
1155
|
-
this.events[event] = (
|
|
1101
|
+
var _a;
|
|
1102
|
+
this.events[event] = (_a = this.events[event]) == null ? void 0 : _a.filter((i) => cb !== i);
|
|
1156
1103
|
};
|
|
1157
1104
|
}
|
|
1158
1105
|
});
|
|
1159
1106
|
|
|
1160
1107
|
// lib/NanoEmitter.ts
|
|
1161
1108
|
var NanoEmitter = class {
|
|
1109
|
+
events = createNanoEvents();
|
|
1110
|
+
eventUnsubscribes = [];
|
|
1111
|
+
emitterOptions;
|
|
1162
1112
|
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
1163
1113
|
constructor(options = {}) {
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
publicEmit: false
|
|
1169
|
-
}, options);
|
|
1114
|
+
this.emitterOptions = {
|
|
1115
|
+
publicEmit: false,
|
|
1116
|
+
...options
|
|
1117
|
+
};
|
|
1170
1118
|
}
|
|
1119
|
+
//#region on
|
|
1171
1120
|
/**
|
|
1172
1121
|
* Subscribes to an event and calls the callback when it's emitted.
|
|
1173
1122
|
* @param event The event to subscribe to. Use `as "_"` in case your event names aren't thoroughly typed (like when using a template literal, e.g. \`event-${val}\` as "_")
|
|
@@ -1201,6 +1150,7 @@ var NanoEmitter = class {
|
|
|
1201
1150
|
this.eventUnsubscribes.push(unsub);
|
|
1202
1151
|
return unsubProxy;
|
|
1203
1152
|
}
|
|
1153
|
+
//#region once
|
|
1204
1154
|
/**
|
|
1205
1155
|
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
1206
1156
|
* @param event The event to subscribe to. Use `as "_"` in case your event names aren't thoroughly typed (like when using a template literal, e.g. \`event-${val}\` as "_")
|
|
@@ -1231,9 +1181,90 @@ var NanoEmitter = class {
|
|
|
1231
1181
|
this.eventUnsubscribes.push(unsub);
|
|
1232
1182
|
});
|
|
1233
1183
|
}
|
|
1184
|
+
//#region onMulti
|
|
1185
|
+
/**
|
|
1186
|
+
* Allows subscribing to multiple events and calling the callback only when one of, all of, or a subset of the events are emitted, either continuously or only once.
|
|
1187
|
+
* @param options An object or array of objects with the following properties:
|
|
1188
|
+
* `callback` (required) is the function that will be called when the conditions are met.
|
|
1189
|
+
*
|
|
1190
|
+
* Set `once` to true to call the callback only once for the first event (or set of events) that match the criteria, then stop listening.
|
|
1191
|
+
* If `signal` is provided, the subscription will be aborted when the given signal is aborted.
|
|
1192
|
+
*
|
|
1193
|
+
* If `oneOf` is used, the callback will be called when any of the matching events are emitted.
|
|
1194
|
+
* If `allOf` is used, the callback will be called after all of the matching events are emitted at least once, then any time any of them are emitted.
|
|
1195
|
+
* You may use a combination of the above two options, but at least one of them must be provided.
|
|
1196
|
+
*
|
|
1197
|
+
* @returns Returns a function that can be called to unsubscribe all listeners created by this call. Alternatively, pass an `AbortSignal` to all options objects to achieve the same effect or for finer control.
|
|
1198
|
+
*/
|
|
1199
|
+
onMulti(options) {
|
|
1200
|
+
const allUnsubs = [];
|
|
1201
|
+
const unsubAll = () => {
|
|
1202
|
+
for (const unsub of allUnsubs)
|
|
1203
|
+
unsub();
|
|
1204
|
+
allUnsubs.splice(0, allUnsubs.length);
|
|
1205
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !allUnsubs.includes(u));
|
|
1206
|
+
};
|
|
1207
|
+
for (const opts of Array.isArray(options) ? options : [options]) {
|
|
1208
|
+
const optsWithDefaults = {
|
|
1209
|
+
allOf: [],
|
|
1210
|
+
oneOf: [],
|
|
1211
|
+
once: false,
|
|
1212
|
+
...opts
|
|
1213
|
+
};
|
|
1214
|
+
const {
|
|
1215
|
+
oneOf,
|
|
1216
|
+
allOf,
|
|
1217
|
+
once,
|
|
1218
|
+
signal,
|
|
1219
|
+
callback
|
|
1220
|
+
} = optsWithDefaults;
|
|
1221
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
1222
|
+
return unsubAll;
|
|
1223
|
+
const curEvtUnsubs = [];
|
|
1224
|
+
const checkUnsubAllEvt = (force = false) => {
|
|
1225
|
+
if (!(signal == null ? void 0 : signal.aborted) && !force)
|
|
1226
|
+
return;
|
|
1227
|
+
for (const unsub of curEvtUnsubs)
|
|
1228
|
+
unsub();
|
|
1229
|
+
curEvtUnsubs.splice(0, curEvtUnsubs.length);
|
|
1230
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !curEvtUnsubs.includes(u));
|
|
1231
|
+
};
|
|
1232
|
+
for (const event of oneOf) {
|
|
1233
|
+
const unsub = this.events.on(event, (...args) => {
|
|
1234
|
+
checkUnsubAllEvt();
|
|
1235
|
+
callback(event, ...args);
|
|
1236
|
+
if (once)
|
|
1237
|
+
checkUnsubAllEvt(true);
|
|
1238
|
+
});
|
|
1239
|
+
curEvtUnsubs.push(unsub);
|
|
1240
|
+
}
|
|
1241
|
+
const allOfEmitted = /* @__PURE__ */ new Set();
|
|
1242
|
+
const checkAllOf = (event, ...args) => {
|
|
1243
|
+
checkUnsubAllEvt();
|
|
1244
|
+
allOfEmitted.add(event);
|
|
1245
|
+
if (allOfEmitted.size === allOf.length) {
|
|
1246
|
+
callback(event, ...args);
|
|
1247
|
+
if (once)
|
|
1248
|
+
checkUnsubAllEvt(true);
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
for (const event of allOf) {
|
|
1252
|
+
const unsub = this.events.on(event, (...args) => {
|
|
1253
|
+
checkUnsubAllEvt();
|
|
1254
|
+
checkAllOf(event, ...args);
|
|
1255
|
+
});
|
|
1256
|
+
curEvtUnsubs.push(unsub);
|
|
1257
|
+
}
|
|
1258
|
+
if (oneOf.length === 0 && allOf.length === 0)
|
|
1259
|
+
throw new TypeError("NanoEmitter.onMulti(): Either `oneOf` or `allOf` or both must be provided in the options");
|
|
1260
|
+
allUnsubs.push(() => checkUnsubAllEvt(true));
|
|
1261
|
+
}
|
|
1262
|
+
return unsubAll;
|
|
1263
|
+
}
|
|
1264
|
+
//#region emit
|
|
1234
1265
|
/**
|
|
1235
1266
|
* Emits an event on this instance.
|
|
1236
|
-
* ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
1267
|
+
* - ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
1237
1268
|
* @param event The event to emit
|
|
1238
1269
|
* @param args The arguments to pass to the event listeners
|
|
1239
1270
|
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
@@ -1245,6 +1276,7 @@ var NanoEmitter = class {
|
|
|
1245
1276
|
}
|
|
1246
1277
|
return false;
|
|
1247
1278
|
}
|
|
1279
|
+
//#region unsubscribeAll
|
|
1248
1280
|
/** Unsubscribes all event listeners from this instance */
|
|
1249
1281
|
unsubscribeAll() {
|
|
1250
1282
|
for (const unsub of this.eventUnsubscribes)
|
|
@@ -1264,13 +1296,13 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1264
1296
|
super();
|
|
1265
1297
|
this.timeout = timeout;
|
|
1266
1298
|
this.type = type;
|
|
1267
|
-
/** All registered listener functions and the time they were attached */
|
|
1268
|
-
__publicField(this, "listeners", []);
|
|
1269
|
-
/** The currently active timeout */
|
|
1270
|
-
__publicField(this, "activeTimeout");
|
|
1271
|
-
/** The latest queued call */
|
|
1272
|
-
__publicField(this, "queuedCall");
|
|
1273
1299
|
}
|
|
1300
|
+
/** All registered listener functions and the time they were attached */
|
|
1301
|
+
listeners = [];
|
|
1302
|
+
/** The currently active timeout */
|
|
1303
|
+
activeTimeout;
|
|
1304
|
+
/** The latest queued call */
|
|
1305
|
+
queuedCall;
|
|
1274
1306
|
//#region listeners
|
|
1275
1307
|
/** Adds a listener function that will be called on timeout */
|
|
1276
1308
|
addListener(fn) {
|
|
@@ -1357,8 +1389,6 @@ function debounce(fn, timeout = 200, type = "immediate") {
|
|
|
1357
1389
|
return func;
|
|
1358
1390
|
}
|
|
1359
1391
|
|
|
1360
|
-
if(__exports != exports)module.exports = exports;return module.exports}));
|
|
1361
|
-
|
|
1362
1392
|
|
|
1363
1393
|
|
|
1364
1394
|
if (typeof module.exports == "object" && typeof exports == "object") {
|