@sv443-network/coreutils 3.2.0 → 3.4.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 +34 -0
- package/README.md +3 -0
- package/dist/CoreUtils.cjs +295 -234
- package/dist/CoreUtils.min.cjs +3 -3
- package/dist/CoreUtils.min.mjs +3 -3
- package/dist/CoreUtils.min.umd.js +3 -3
- package/dist/CoreUtils.mjs +295 -234
- package/dist/CoreUtils.umd.js +297 -404
- package/dist/lib/DataStore.d.ts +34 -6
- package/dist/lib/DataStoreSerializer.d.ts +6 -2
- package/dist/lib/Debouncer.d.ts +3 -3
- package/dist/lib/misc.d.ts +36 -0
- package/package.json +23 -23
package/dist/CoreUtils.mjs
CHANGED
|
@@ -368,12 +368,45 @@ function getCallStack(asArray, lines = Infinity) {
|
|
|
368
368
|
if (typeof lines !== "number" || isNaN(lines) || lines < 0)
|
|
369
369
|
throw new TypeError("lines parameter must be a non-negative number");
|
|
370
370
|
try {
|
|
371
|
-
throw new
|
|
371
|
+
throw new CustomError("GetCallStack", "Capturing a stack trace with CoreUtils.getCallStack(). If you see this anywhere, you can safely ignore it.");
|
|
372
372
|
} catch (err) {
|
|
373
373
|
const stack = (err.stack ?? "").split("\n").map((line) => line.trim()).slice(2, lines + 2);
|
|
374
374
|
return asArray !== false ? stack : stack.join("\n");
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
|
+
function createRecurringTask(options) {
|
|
378
|
+
var _a;
|
|
379
|
+
let iterations = 0;
|
|
380
|
+
let aborted = false;
|
|
381
|
+
(_a = options.signal) == null ? void 0 : _a.addEventListener("abort", () => {
|
|
382
|
+
aborted = true;
|
|
383
|
+
}, { once: true });
|
|
384
|
+
const runRecurringTask = async (initial = false) => {
|
|
385
|
+
var _a2;
|
|
386
|
+
if (aborted)
|
|
387
|
+
return;
|
|
388
|
+
try {
|
|
389
|
+
if ((options.immediate ?? true) || !initial) {
|
|
390
|
+
iterations++;
|
|
391
|
+
if (await ((_a2 = options.condition) == null ? void 0 : _a2.call(options, iterations - 1)) ?? true) {
|
|
392
|
+
const val = await options.task(iterations - 1);
|
|
393
|
+
if (options.onSuccess)
|
|
394
|
+
await options.onSuccess(val, iterations - 1);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
} catch (err) {
|
|
398
|
+
if (options.onError)
|
|
399
|
+
await options.onError(err, iterations - 1);
|
|
400
|
+
if (options.abortOnError)
|
|
401
|
+
aborted = true;
|
|
402
|
+
if (!options.onError && !options.abortOnError)
|
|
403
|
+
throw err;
|
|
404
|
+
}
|
|
405
|
+
if (!aborted && (typeof options.maxIterations !== "number" || iterations < options.maxIterations))
|
|
406
|
+
setTimeout(runRecurringTask, options.timeout);
|
|
407
|
+
};
|
|
408
|
+
return runRecurringTask(true);
|
|
409
|
+
}
|
|
377
410
|
|
|
378
411
|
// lib/text.ts
|
|
379
412
|
function autoPlural(term, num, pluralType = "auto") {
|
|
@@ -463,9 +496,208 @@ function truncStr(input, length, endStr = "...") {
|
|
|
463
496
|
return finalStr.length > length ? finalStr.substring(0, length) : finalStr;
|
|
464
497
|
}
|
|
465
498
|
|
|
499
|
+
// node_modules/.pnpm/nanoevents@9.1.0/node_modules/nanoevents/index.js
|
|
500
|
+
var createNanoEvents = () => ({
|
|
501
|
+
emit(event, ...args) {
|
|
502
|
+
for (let callbacks = this.events[event] || [], i = 0, length = callbacks.length; i < length; i++) {
|
|
503
|
+
callbacks[i](...args);
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
events: {},
|
|
507
|
+
on(event, cb) {
|
|
508
|
+
;
|
|
509
|
+
(this.events[event] ||= []).push(cb);
|
|
510
|
+
return () => {
|
|
511
|
+
var _a;
|
|
512
|
+
this.events[event] = (_a = this.events[event]) == null ? void 0 : _a.filter((i) => cb !== i);
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// lib/NanoEmitter.ts
|
|
518
|
+
var NanoEmitter = class {
|
|
519
|
+
events = createNanoEvents();
|
|
520
|
+
eventUnsubscribes = [];
|
|
521
|
+
emitterOptions;
|
|
522
|
+
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
523
|
+
constructor(options = {}) {
|
|
524
|
+
this.emitterOptions = {
|
|
525
|
+
publicEmit: false,
|
|
526
|
+
...options
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
//#region on
|
|
530
|
+
/**
|
|
531
|
+
* Subscribes to an event and calls the callback when it's emitted.
|
|
532
|
+
* @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 "_")
|
|
533
|
+
* @returns Returns a function that can be called to unsubscribe the event listener
|
|
534
|
+
* @example ```ts
|
|
535
|
+
* const emitter = new NanoEmitter<{
|
|
536
|
+
* foo: (bar: string) => void;
|
|
537
|
+
* }>({
|
|
538
|
+
* publicEmit: true,
|
|
539
|
+
* });
|
|
540
|
+
*
|
|
541
|
+
* let i = 0;
|
|
542
|
+
* const unsub = emitter.on("foo", (bar) => {
|
|
543
|
+
* // unsubscribe after 10 events:
|
|
544
|
+
* if(++i === 10) unsub();
|
|
545
|
+
* console.log(bar);
|
|
546
|
+
* });
|
|
547
|
+
*
|
|
548
|
+
* emitter.emit("foo", "bar");
|
|
549
|
+
* ```
|
|
550
|
+
*/
|
|
551
|
+
on(event, cb) {
|
|
552
|
+
let unsub;
|
|
553
|
+
const unsubProxy = () => {
|
|
554
|
+
if (!unsub)
|
|
555
|
+
return;
|
|
556
|
+
unsub();
|
|
557
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => u !== unsub);
|
|
558
|
+
};
|
|
559
|
+
unsub = this.events.on(event, cb);
|
|
560
|
+
this.eventUnsubscribes.push(unsub);
|
|
561
|
+
return unsubProxy;
|
|
562
|
+
}
|
|
563
|
+
//#region once
|
|
564
|
+
/**
|
|
565
|
+
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
566
|
+
* @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 "_")
|
|
567
|
+
* @param cb The callback to call when the event is emitted - if provided or not, the returned Promise will resolve with the event arguments
|
|
568
|
+
* @returns Returns a Promise that resolves with the event arguments when the event is emitted
|
|
569
|
+
* @example ```ts
|
|
570
|
+
* const emitter = new NanoEmitter<{
|
|
571
|
+
* foo: (bar: string) => void;
|
|
572
|
+
* }>();
|
|
573
|
+
*
|
|
574
|
+
* // Promise syntax:
|
|
575
|
+
* const [bar] = await emitter.once("foo");
|
|
576
|
+
* console.log(bar);
|
|
577
|
+
*
|
|
578
|
+
* // Callback syntax:
|
|
579
|
+
* emitter.once("foo", (bar) => console.log(bar));
|
|
580
|
+
* ```
|
|
581
|
+
*/
|
|
582
|
+
once(event, cb) {
|
|
583
|
+
return new Promise((resolve) => {
|
|
584
|
+
let unsub;
|
|
585
|
+
const onceProxy = ((...args) => {
|
|
586
|
+
cb == null ? void 0 : cb(...args);
|
|
587
|
+
unsub == null ? void 0 : unsub();
|
|
588
|
+
resolve(args);
|
|
589
|
+
});
|
|
590
|
+
unsub = this.events.on(event, onceProxy);
|
|
591
|
+
this.eventUnsubscribes.push(unsub);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
//#region onMulti
|
|
595
|
+
/**
|
|
596
|
+
* 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.
|
|
597
|
+
* @param options An object or array of objects with the following properties:
|
|
598
|
+
* `callback` (required) is the function that will be called when the conditions are met.
|
|
599
|
+
*
|
|
600
|
+
* 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.
|
|
601
|
+
* If `signal` is provided, the subscription will be canceled when the given signal is aborted.
|
|
602
|
+
*
|
|
603
|
+
* If `oneOf` is used, the callback will be called when any of the matching events are emitted.
|
|
604
|
+
* 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.
|
|
605
|
+
* If both `oneOf` and `allOf` are used together, the callback will be called when any of the `oneOf` events are emitted AND all of the `allOf` events have been emitted at least once.
|
|
606
|
+
* At least one of `oneOf` or `allOf` must be provided.
|
|
607
|
+
*
|
|
608
|
+
* @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.
|
|
609
|
+
*/
|
|
610
|
+
onMulti(options) {
|
|
611
|
+
const allUnsubs = [];
|
|
612
|
+
const unsubAll = () => {
|
|
613
|
+
for (const unsub of allUnsubs)
|
|
614
|
+
unsub();
|
|
615
|
+
allUnsubs.splice(0, allUnsubs.length);
|
|
616
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !allUnsubs.includes(u));
|
|
617
|
+
};
|
|
618
|
+
for (const opts of Array.isArray(options) ? options : [options]) {
|
|
619
|
+
const optsWithDefaults = {
|
|
620
|
+
allOf: [],
|
|
621
|
+
oneOf: [],
|
|
622
|
+
once: false,
|
|
623
|
+
...opts
|
|
624
|
+
};
|
|
625
|
+
const {
|
|
626
|
+
oneOf,
|
|
627
|
+
allOf,
|
|
628
|
+
once,
|
|
629
|
+
signal,
|
|
630
|
+
callback
|
|
631
|
+
} = optsWithDefaults;
|
|
632
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
633
|
+
return unsubAll;
|
|
634
|
+
if (oneOf.length === 0 && allOf.length === 0)
|
|
635
|
+
throw new TypeError("NanoEmitter.onMulti(): Either `oneOf` or `allOf` or both must be provided in the options");
|
|
636
|
+
const curEvtUnsubs = [];
|
|
637
|
+
const checkUnsubAllEvt = (force = false) => {
|
|
638
|
+
if (!(signal == null ? void 0 : signal.aborted) && !force)
|
|
639
|
+
return;
|
|
640
|
+
for (const unsub of curEvtUnsubs)
|
|
641
|
+
unsub();
|
|
642
|
+
curEvtUnsubs.splice(0, curEvtUnsubs.length);
|
|
643
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !curEvtUnsubs.includes(u));
|
|
644
|
+
};
|
|
645
|
+
const allOfEmitted = /* @__PURE__ */ new Set();
|
|
646
|
+
const allOfConditionMet = () => allOf.length === 0 || allOfEmitted.size === allOf.length;
|
|
647
|
+
for (const event of oneOf) {
|
|
648
|
+
const unsub = this.events.on(event, ((...args) => {
|
|
649
|
+
checkUnsubAllEvt();
|
|
650
|
+
if (allOfConditionMet()) {
|
|
651
|
+
callback(event, ...args);
|
|
652
|
+
if (once)
|
|
653
|
+
checkUnsubAllEvt(true);
|
|
654
|
+
}
|
|
655
|
+
}));
|
|
656
|
+
curEvtUnsubs.push(unsub);
|
|
657
|
+
}
|
|
658
|
+
for (const event of allOf) {
|
|
659
|
+
const unsub = this.events.on(event, ((...args) => {
|
|
660
|
+
checkUnsubAllEvt();
|
|
661
|
+
allOfEmitted.add(event);
|
|
662
|
+
if (allOfConditionMet() && (oneOf.length === 0 || oneOf.includes(event))) {
|
|
663
|
+
callback(event, ...args);
|
|
664
|
+
if (once)
|
|
665
|
+
checkUnsubAllEvt(true);
|
|
666
|
+
}
|
|
667
|
+
}));
|
|
668
|
+
curEvtUnsubs.push(unsub);
|
|
669
|
+
}
|
|
670
|
+
allUnsubs.push(() => checkUnsubAllEvt(true));
|
|
671
|
+
}
|
|
672
|
+
return unsubAll;
|
|
673
|
+
}
|
|
674
|
+
//#region emit
|
|
675
|
+
/**
|
|
676
|
+
* Emits an event on this instance.
|
|
677
|
+
* - ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
678
|
+
* @param event The event to emit
|
|
679
|
+
* @param args The arguments to pass to the event listeners
|
|
680
|
+
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
681
|
+
*/
|
|
682
|
+
emit(event, ...args) {
|
|
683
|
+
if (this.emitterOptions.publicEmit) {
|
|
684
|
+
this.events.emit(event, ...args);
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
return false;
|
|
688
|
+
}
|
|
689
|
+
//#region unsubscribeAll
|
|
690
|
+
/** Unsubscribes all event listeners from this instance */
|
|
691
|
+
unsubscribeAll() {
|
|
692
|
+
for (const unsub of this.eventUnsubscribes)
|
|
693
|
+
unsub();
|
|
694
|
+
this.eventUnsubscribes = [];
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
|
|
466
698
|
// lib/DataStore.ts
|
|
467
699
|
var dsFmtVer = 1;
|
|
468
|
-
var DataStore = class {
|
|
700
|
+
var DataStore = class extends NanoEmitter {
|
|
469
701
|
id;
|
|
470
702
|
formatVersion;
|
|
471
703
|
defaultData;
|
|
@@ -497,6 +729,7 @@ var DataStore = class {
|
|
|
497
729
|
* @param opts The options for this DataStore instance
|
|
498
730
|
*/
|
|
499
731
|
constructor(opts) {
|
|
732
|
+
super(opts.nanoEmitterOptions);
|
|
500
733
|
this.id = opts.id;
|
|
501
734
|
this.formatVersion = opts.formatVersion;
|
|
502
735
|
this.defaultData = opts.defaultData;
|
|
@@ -567,30 +800,26 @@ var DataStore = class {
|
|
|
567
800
|
this.migrateIds = [];
|
|
568
801
|
}
|
|
569
802
|
const storedDataRaw = await this.engine.getValue(`${this.keyPrefix}${this.id}-dat`, null);
|
|
570
|
-
|
|
803
|
+
const storedFmtVer = Number(await this.engine.getValue(`${this.keyPrefix}${this.id}-ver`, NaN));
|
|
571
804
|
if (typeof storedDataRaw !== "string" && typeof storedDataRaw !== "object" || storedDataRaw === null || isNaN(storedFmtVer)) {
|
|
572
|
-
await this.saveDefaultData();
|
|
573
|
-
|
|
805
|
+
await this.saveDefaultData(false);
|
|
806
|
+
const data = this.engine.deepCopy(this.defaultData);
|
|
807
|
+
this.events.emit("loadData", data);
|
|
808
|
+
return data;
|
|
574
809
|
}
|
|
575
810
|
const storedData = storedDataRaw ?? JSON.stringify(this.defaultData);
|
|
576
811
|
const encodingFmt = String(await this.engine.getValue(`${this.keyPrefix}${this.id}-enf`, null));
|
|
577
812
|
const isEncoded = encodingFmt !== "null" && encodingFmt !== "false" && encodingFmt !== "0" && encodingFmt !== "" && encodingFmt !== null;
|
|
578
|
-
let saveData = false;
|
|
579
|
-
if (isNaN(storedFmtVer)) {
|
|
580
|
-
await this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, storedFmtVer = this.formatVersion);
|
|
581
|
-
saveData = true;
|
|
582
|
-
}
|
|
583
813
|
let parsed = typeof storedData === "string" ? await this.engine.deserializeData(storedData, isEncoded) : storedData;
|
|
584
814
|
if (storedFmtVer < this.formatVersion && this.migrations)
|
|
585
815
|
parsed = await this.runMigrations(parsed, storedFmtVer);
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
return this.cachedData = this.engine.deepCopy(parsed);
|
|
590
|
-
else
|
|
591
|
-
return this.engine.deepCopy(parsed);
|
|
816
|
+
const result = this.memoryCache ? this.cachedData = this.engine.deepCopy(parsed) : this.engine.deepCopy(parsed);
|
|
817
|
+
this.events.emit("loadData", result);
|
|
818
|
+
return result;
|
|
592
819
|
} catch (err) {
|
|
820
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
593
821
|
console.warn("Error while parsing JSON data, resetting it to the default value.", err);
|
|
822
|
+
this.events.emit("error", error);
|
|
594
823
|
await this.saveDefaultData();
|
|
595
824
|
return this.defaultData;
|
|
596
825
|
}
|
|
@@ -609,27 +838,47 @@ var DataStore = class {
|
|
|
609
838
|
//#region setData
|
|
610
839
|
/** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
|
|
611
840
|
setData(data) {
|
|
612
|
-
|
|
841
|
+
const dataCopy = this.engine.deepCopy(data);
|
|
842
|
+
if (this.memoryCache) {
|
|
613
843
|
this.cachedData = data;
|
|
844
|
+
this.events.emit("updateDataSync", dataCopy);
|
|
845
|
+
}
|
|
614
846
|
return new Promise(async (resolve) => {
|
|
615
|
-
await Promise.allSettled([
|
|
847
|
+
const results = await Promise.allSettled([
|
|
616
848
|
this.engine.setValue(`${this.keyPrefix}${this.id}-dat`, await this.engine.serializeData(data, this.encodingEnabled())),
|
|
617
849
|
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, this.formatVersion),
|
|
618
850
|
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
619
851
|
]);
|
|
852
|
+
if (results.every((r) => r.status === "fulfilled"))
|
|
853
|
+
this.events.emit("updateData", dataCopy);
|
|
854
|
+
else {
|
|
855
|
+
const error = new Error("Error while saving data to persistent storage: " + results.map((r) => r.status === "rejected" ? r.reason : null).filter(Boolean).join("; "));
|
|
856
|
+
console.error(error);
|
|
857
|
+
this.events.emit("error", error);
|
|
858
|
+
}
|
|
620
859
|
resolve();
|
|
621
860
|
});
|
|
622
861
|
}
|
|
623
862
|
//#region saveDefaultData
|
|
624
|
-
/**
|
|
625
|
-
|
|
863
|
+
/**
|
|
864
|
+
* Saves the default data passed in the constructor synchronously to the in-memory cache and asynchronously to persistent storage.
|
|
865
|
+
* @param emitEvent Whether to emit the `setDefaultData` event - set to `false` to prevent event emission (used internally during initial population in {@linkcode loadData()})
|
|
866
|
+
*/
|
|
867
|
+
async saveDefaultData(emitEvent = true) {
|
|
626
868
|
if (this.memoryCache)
|
|
627
869
|
this.cachedData = this.defaultData;
|
|
628
|
-
await Promise.allSettled([
|
|
870
|
+
const results = await Promise.allSettled([
|
|
629
871
|
this.engine.setValue(`${this.keyPrefix}${this.id}-dat`, await this.engine.serializeData(this.defaultData, this.encodingEnabled())),
|
|
630
872
|
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, this.formatVersion),
|
|
631
873
|
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
632
874
|
]);
|
|
875
|
+
if (results.every((r) => r.status === "fulfilled"))
|
|
876
|
+
emitEvent && this.events.emit("setDefaultData", this.defaultData);
|
|
877
|
+
else {
|
|
878
|
+
const error = new Error("Error while saving default data to persistent storage: " + results.map((r) => r.status === "rejected" ? r.reason : null).filter(Boolean).join("; "));
|
|
879
|
+
console.error(error);
|
|
880
|
+
this.events.emit("error", error);
|
|
881
|
+
}
|
|
633
882
|
}
|
|
634
883
|
//#region deleteData
|
|
635
884
|
/**
|
|
@@ -645,6 +894,7 @@ var DataStore = class {
|
|
|
645
894
|
this.engine.deleteValue(`${this.keyPrefix}${this.id}-enf`)
|
|
646
895
|
]);
|
|
647
896
|
await ((_b = (_a = this.engine).deleteStorage) == null ? void 0 : _b.call(_a));
|
|
897
|
+
this.events.emit("deleteData");
|
|
648
898
|
}
|
|
649
899
|
//#region encodingEnabled
|
|
650
900
|
/** Returns whether encoding and decoding are enabled for this DataStore instance */
|
|
@@ -665,16 +915,22 @@ var DataStore = class {
|
|
|
665
915
|
let newData = oldData;
|
|
666
916
|
const sortedMigrations = Object.entries(this.migrations).sort(([a], [b]) => Number(a) - Number(b));
|
|
667
917
|
let lastFmtVer = oldFmtVer;
|
|
668
|
-
for (
|
|
918
|
+
for (let i = 0; i < sortedMigrations.length; i++) {
|
|
919
|
+
const [fmtVer, migrationFunc] = sortedMigrations[i];
|
|
669
920
|
const ver = Number(fmtVer);
|
|
670
921
|
if (oldFmtVer < this.formatVersion && oldFmtVer < ver) {
|
|
671
922
|
try {
|
|
672
923
|
const migRes = migrationFunc(newData);
|
|
673
924
|
newData = migRes instanceof Promise ? await migRes : migRes;
|
|
674
925
|
lastFmtVer = oldFmtVer = ver;
|
|
926
|
+
const isFinal = ver >= this.formatVersion || i === sortedMigrations.length - 1;
|
|
927
|
+
this.events.emit("migrateData", ver, newData, isFinal);
|
|
675
928
|
} catch (err) {
|
|
929
|
+
const migError = new MigrationError(`Error while running migration function for format version '${fmtVer}'`, { cause: err });
|
|
930
|
+
this.events.emit("migrationError", ver, migError);
|
|
931
|
+
this.events.emit("error", migError);
|
|
676
932
|
if (!resetOnError)
|
|
677
|
-
throw
|
|
933
|
+
throw migError;
|
|
678
934
|
await this.saveDefaultData();
|
|
679
935
|
return this.engine.deepCopy(this.defaultData);
|
|
680
936
|
}
|
|
@@ -685,10 +941,9 @@ var DataStore = class {
|
|
|
685
941
|
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, lastFmtVer),
|
|
686
942
|
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
687
943
|
]);
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
return this.engine.deepCopy(newData);
|
|
944
|
+
const result = this.memoryCache ? this.cachedData = this.engine.deepCopy(newData) : this.engine.deepCopy(newData);
|
|
945
|
+
this.events.emit("updateData", result);
|
|
946
|
+
return result;
|
|
692
947
|
}
|
|
693
948
|
//#region migrateId
|
|
694
949
|
/**
|
|
@@ -717,6 +972,7 @@ var DataStore = class {
|
|
|
717
972
|
this.engine.deleteValue(`${this.keyPrefix}${id}-ver`),
|
|
718
973
|
this.engine.deleteValue(`${this.keyPrefix}${id}-enf`)
|
|
719
974
|
]);
|
|
975
|
+
this.events.emit("migrateId", id, this.id);
|
|
720
976
|
}));
|
|
721
977
|
}
|
|
722
978
|
};
|
|
@@ -961,7 +1217,10 @@ var DataStoreSerializer = class _DataStoreSerializer {
|
|
|
961
1217
|
...options
|
|
962
1218
|
};
|
|
963
1219
|
}
|
|
964
|
-
/**
|
|
1220
|
+
/**
|
|
1221
|
+
* Calculates the checksum of a string. Uses {@linkcode computeHash()} with SHA-256 and digests as a hex string by default.
|
|
1222
|
+
* Override this in a subclass if a custom checksum method is needed.
|
|
1223
|
+
*/
|
|
965
1224
|
async calcChecksum(input) {
|
|
966
1225
|
return computeHash(input, "SHA-256");
|
|
967
1226
|
}
|
|
@@ -1085,205 +1344,6 @@ Has: ${checksum}`);
|
|
|
1085
1344
|
}
|
|
1086
1345
|
};
|
|
1087
1346
|
|
|
1088
|
-
// node_modules/.pnpm/nanoevents@9.1.0/node_modules/nanoevents/index.js
|
|
1089
|
-
var createNanoEvents = () => ({
|
|
1090
|
-
emit(event, ...args) {
|
|
1091
|
-
for (let callbacks = this.events[event] || [], i = 0, length = callbacks.length; i < length; i++) {
|
|
1092
|
-
callbacks[i](...args);
|
|
1093
|
-
}
|
|
1094
|
-
},
|
|
1095
|
-
events: {},
|
|
1096
|
-
on(event, cb) {
|
|
1097
|
-
;
|
|
1098
|
-
(this.events[event] ||= []).push(cb);
|
|
1099
|
-
return () => {
|
|
1100
|
-
var _a;
|
|
1101
|
-
this.events[event] = (_a = this.events[event]) == null ? void 0 : _a.filter((i) => cb !== i);
|
|
1102
|
-
};
|
|
1103
|
-
}
|
|
1104
|
-
});
|
|
1105
|
-
|
|
1106
|
-
// lib/NanoEmitter.ts
|
|
1107
|
-
var NanoEmitter = class {
|
|
1108
|
-
events = createNanoEvents();
|
|
1109
|
-
eventUnsubscribes = [];
|
|
1110
|
-
emitterOptions;
|
|
1111
|
-
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
1112
|
-
constructor(options = {}) {
|
|
1113
|
-
this.emitterOptions = {
|
|
1114
|
-
publicEmit: false,
|
|
1115
|
-
...options
|
|
1116
|
-
};
|
|
1117
|
-
}
|
|
1118
|
-
//#region on
|
|
1119
|
-
/**
|
|
1120
|
-
* Subscribes to an event and calls the callback when it's emitted.
|
|
1121
|
-
* @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 "_")
|
|
1122
|
-
* @returns Returns a function that can be called to unsubscribe the event listener
|
|
1123
|
-
* @example ```ts
|
|
1124
|
-
* const emitter = new NanoEmitter<{
|
|
1125
|
-
* foo: (bar: string) => void;
|
|
1126
|
-
* }>({
|
|
1127
|
-
* publicEmit: true,
|
|
1128
|
-
* });
|
|
1129
|
-
*
|
|
1130
|
-
* let i = 0;
|
|
1131
|
-
* const unsub = emitter.on("foo", (bar) => {
|
|
1132
|
-
* // unsubscribe after 10 events:
|
|
1133
|
-
* if(++i === 10) unsub();
|
|
1134
|
-
* console.log(bar);
|
|
1135
|
-
* });
|
|
1136
|
-
*
|
|
1137
|
-
* emitter.emit("foo", "bar");
|
|
1138
|
-
* ```
|
|
1139
|
-
*/
|
|
1140
|
-
on(event, cb) {
|
|
1141
|
-
let unsub;
|
|
1142
|
-
const unsubProxy = () => {
|
|
1143
|
-
if (!unsub)
|
|
1144
|
-
return;
|
|
1145
|
-
unsub();
|
|
1146
|
-
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => u !== unsub);
|
|
1147
|
-
};
|
|
1148
|
-
unsub = this.events.on(event, cb);
|
|
1149
|
-
this.eventUnsubscribes.push(unsub);
|
|
1150
|
-
return unsubProxy;
|
|
1151
|
-
}
|
|
1152
|
-
//#region once
|
|
1153
|
-
/**
|
|
1154
|
-
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
1155
|
-
* @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 "_")
|
|
1156
|
-
* @param cb The callback to call when the event is emitted - if provided or not, the returned Promise will resolve with the event arguments
|
|
1157
|
-
* @returns Returns a Promise that resolves with the event arguments when the event is emitted
|
|
1158
|
-
* @example ```ts
|
|
1159
|
-
* const emitter = new NanoEmitter<{
|
|
1160
|
-
* foo: (bar: string) => void;
|
|
1161
|
-
* }>();
|
|
1162
|
-
*
|
|
1163
|
-
* // Promise syntax:
|
|
1164
|
-
* const [bar] = await emitter.once("foo");
|
|
1165
|
-
* console.log(bar);
|
|
1166
|
-
*
|
|
1167
|
-
* // Callback syntax:
|
|
1168
|
-
* emitter.once("foo", (bar) => console.log(bar));
|
|
1169
|
-
* ```
|
|
1170
|
-
*/
|
|
1171
|
-
once(event, cb) {
|
|
1172
|
-
return new Promise((resolve) => {
|
|
1173
|
-
let unsub;
|
|
1174
|
-
const onceProxy = ((...args) => {
|
|
1175
|
-
cb == null ? void 0 : cb(...args);
|
|
1176
|
-
unsub == null ? void 0 : unsub();
|
|
1177
|
-
resolve(args);
|
|
1178
|
-
});
|
|
1179
|
-
unsub = this.events.on(event, onceProxy);
|
|
1180
|
-
this.eventUnsubscribes.push(unsub);
|
|
1181
|
-
});
|
|
1182
|
-
}
|
|
1183
|
-
//#region onMulti
|
|
1184
|
-
/**
|
|
1185
|
-
* 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.
|
|
1186
|
-
* @param options An object or array of objects with the following properties:
|
|
1187
|
-
* `callback` (required) is the function that will be called when the conditions are met.
|
|
1188
|
-
*
|
|
1189
|
-
* 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.
|
|
1190
|
-
* If `signal` is provided, the subscription will be canceled when the given signal is aborted.
|
|
1191
|
-
*
|
|
1192
|
-
* If `oneOf` is used, the callback will be called when any of the matching events are emitted.
|
|
1193
|
-
* 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.
|
|
1194
|
-
* If both `oneOf` and `allOf` are used together, the callback will be called when any of the `oneOf` events are emitted AND all of the `allOf` events have been emitted at least once.
|
|
1195
|
-
* At least one of `oneOf` or `allOf` 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
|
-
if (oneOf.length === 0 && allOf.length === 0)
|
|
1224
|
-
throw new TypeError("NanoEmitter.onMulti(): Either `oneOf` or `allOf` or both must be provided in the options");
|
|
1225
|
-
const curEvtUnsubs = [];
|
|
1226
|
-
const checkUnsubAllEvt = (force = false) => {
|
|
1227
|
-
if (!(signal == null ? void 0 : signal.aborted) && !force)
|
|
1228
|
-
return;
|
|
1229
|
-
for (const unsub of curEvtUnsubs)
|
|
1230
|
-
unsub();
|
|
1231
|
-
curEvtUnsubs.splice(0, curEvtUnsubs.length);
|
|
1232
|
-
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !curEvtUnsubs.includes(u));
|
|
1233
|
-
};
|
|
1234
|
-
const allOfEmitted = /* @__PURE__ */ new Set();
|
|
1235
|
-
const allOfConditionMet = () => allOf.length === 0 || allOfEmitted.size === allOf.length;
|
|
1236
|
-
for (const event of oneOf) {
|
|
1237
|
-
const unsub = this.events.on(event, ((...args) => {
|
|
1238
|
-
checkUnsubAllEvt();
|
|
1239
|
-
if (allOfConditionMet()) {
|
|
1240
|
-
callback(event, ...args);
|
|
1241
|
-
if (once)
|
|
1242
|
-
checkUnsubAllEvt(true);
|
|
1243
|
-
}
|
|
1244
|
-
}));
|
|
1245
|
-
curEvtUnsubs.push(unsub);
|
|
1246
|
-
}
|
|
1247
|
-
for (const event of allOf) {
|
|
1248
|
-
const unsub = this.events.on(event, ((...args) => {
|
|
1249
|
-
checkUnsubAllEvt();
|
|
1250
|
-
allOfEmitted.add(event);
|
|
1251
|
-
if (allOfConditionMet() && (oneOf.length === 0 || oneOf.includes(event))) {
|
|
1252
|
-
callback(event, ...args);
|
|
1253
|
-
if (once)
|
|
1254
|
-
checkUnsubAllEvt(true);
|
|
1255
|
-
}
|
|
1256
|
-
}));
|
|
1257
|
-
curEvtUnsubs.push(unsub);
|
|
1258
|
-
}
|
|
1259
|
-
allUnsubs.push(() => checkUnsubAllEvt(true));
|
|
1260
|
-
}
|
|
1261
|
-
return unsubAll;
|
|
1262
|
-
}
|
|
1263
|
-
//#region emit
|
|
1264
|
-
/**
|
|
1265
|
-
* Emits an event on this instance.
|
|
1266
|
-
* - ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
1267
|
-
* @param event The event to emit
|
|
1268
|
-
* @param args The arguments to pass to the event listeners
|
|
1269
|
-
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
1270
|
-
*/
|
|
1271
|
-
emit(event, ...args) {
|
|
1272
|
-
if (this.emitterOptions.publicEmit) {
|
|
1273
|
-
this.events.emit(event, ...args);
|
|
1274
|
-
return true;
|
|
1275
|
-
}
|
|
1276
|
-
return false;
|
|
1277
|
-
}
|
|
1278
|
-
//#region unsubscribeAll
|
|
1279
|
-
/** Unsubscribes all event listeners from this instance */
|
|
1280
|
-
unsubscribeAll() {
|
|
1281
|
-
for (const unsub of this.eventUnsubscribes)
|
|
1282
|
-
unsub();
|
|
1283
|
-
this.eventUnsubscribes = [];
|
|
1284
|
-
}
|
|
1285
|
-
};
|
|
1286
|
-
|
|
1287
1347
|
// lib/Debouncer.ts
|
|
1288
1348
|
var Debouncer = class extends NanoEmitter {
|
|
1289
1349
|
/**
|
|
@@ -1291,8 +1351,8 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1291
1351
|
* @param timeout Timeout in milliseconds between letting through calls - defaults to 200
|
|
1292
1352
|
* @param type The edge type to use for the debouncer - see {@linkcode DebouncerType} for details or [the documentation for an explanation and diagram](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#debouncer) - defaults to "immediate"
|
|
1293
1353
|
*/
|
|
1294
|
-
constructor(timeout = 200, type = "immediate") {
|
|
1295
|
-
super();
|
|
1354
|
+
constructor(timeout = 200, type = "immediate", nanoEmitterOptions) {
|
|
1355
|
+
super(nanoEmitterOptions);
|
|
1296
1356
|
this.timeout = timeout;
|
|
1297
1357
|
this.type = type;
|
|
1298
1358
|
}
|
|
@@ -1323,7 +1383,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1323
1383
|
//#region timeout
|
|
1324
1384
|
/** Sets the timeout for the debouncer */
|
|
1325
1385
|
setTimeout(timeout) {
|
|
1326
|
-
this.emit("change", this.timeout = timeout, this.type);
|
|
1386
|
+
this.events.emit("change", this.timeout = timeout, this.type);
|
|
1327
1387
|
}
|
|
1328
1388
|
/** Returns the current timeout */
|
|
1329
1389
|
getTimeout() {
|
|
@@ -1336,7 +1396,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1336
1396
|
//#region type
|
|
1337
1397
|
/** Sets the edge type for the debouncer */
|
|
1338
1398
|
setType(type) {
|
|
1339
|
-
this.emit("change", this.timeout, this.type = type);
|
|
1399
|
+
this.events.emit("change", this.timeout, this.type = type);
|
|
1340
1400
|
}
|
|
1341
1401
|
/** Returns the current edge type */
|
|
1342
1402
|
getType() {
|
|
@@ -1347,7 +1407,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1347
1407
|
call(...args) {
|
|
1348
1408
|
const cl = (...a) => {
|
|
1349
1409
|
this.queuedCall = void 0;
|
|
1350
|
-
this.emit("call", ...a);
|
|
1410
|
+
this.events.emit("call", ...a);
|
|
1351
1411
|
this.listeners.forEach((l) => l.call(this, ...a));
|
|
1352
1412
|
};
|
|
1353
1413
|
const setRepeatTimeout = () => {
|
|
@@ -1380,8 +1440,8 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1380
1440
|
}
|
|
1381
1441
|
}
|
|
1382
1442
|
};
|
|
1383
|
-
function debounce(fn, timeout = 200, type = "immediate") {
|
|
1384
|
-
const debouncer = new Debouncer(timeout, type);
|
|
1443
|
+
function debounce(fn, timeout = 200, type = "immediate", nanoEmitterOptions) {
|
|
1444
|
+
const debouncer = new Debouncer(timeout, type, nanoEmitterOptions);
|
|
1385
1445
|
debouncer.addListener(fn);
|
|
1386
1446
|
const func = ((...args) => debouncer.call(...args));
|
|
1387
1447
|
func.debouncer = debouncer;
|
|
@@ -1413,6 +1473,7 @@ export {
|
|
|
1413
1473
|
consumeGen,
|
|
1414
1474
|
consumeStringGen,
|
|
1415
1475
|
createProgressBar,
|
|
1476
|
+
createRecurringTask,
|
|
1416
1477
|
darkenColor,
|
|
1417
1478
|
debounce,
|
|
1418
1479
|
decompress,
|