@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.cjs
CHANGED
|
@@ -55,6 +55,7 @@ __export(lib_exports, {
|
|
|
55
55
|
consumeGen: () => consumeGen,
|
|
56
56
|
consumeStringGen: () => consumeStringGen,
|
|
57
57
|
createProgressBar: () => createProgressBar,
|
|
58
|
+
createRecurringTask: () => createRecurringTask,
|
|
58
59
|
darkenColor: () => darkenColor,
|
|
59
60
|
debounce: () => debounce,
|
|
60
61
|
decompress: () => decompress,
|
|
@@ -460,12 +461,45 @@ function getCallStack(asArray, lines = Infinity) {
|
|
|
460
461
|
if (typeof lines !== "number" || isNaN(lines) || lines < 0)
|
|
461
462
|
throw new TypeError("lines parameter must be a non-negative number");
|
|
462
463
|
try {
|
|
463
|
-
throw new
|
|
464
|
+
throw new CustomError("GetCallStack", "Capturing a stack trace with CoreUtils.getCallStack(). If you see this anywhere, you can safely ignore it.");
|
|
464
465
|
} catch (err) {
|
|
465
466
|
const stack = (err.stack ?? "").split("\n").map((line) => line.trim()).slice(2, lines + 2);
|
|
466
467
|
return asArray !== false ? stack : stack.join("\n");
|
|
467
468
|
}
|
|
468
469
|
}
|
|
470
|
+
function createRecurringTask(options) {
|
|
471
|
+
var _a;
|
|
472
|
+
let iterations = 0;
|
|
473
|
+
let aborted = false;
|
|
474
|
+
(_a = options.signal) == null ? void 0 : _a.addEventListener("abort", () => {
|
|
475
|
+
aborted = true;
|
|
476
|
+
}, { once: true });
|
|
477
|
+
const runRecurringTask = async (initial = false) => {
|
|
478
|
+
var _a2;
|
|
479
|
+
if (aborted)
|
|
480
|
+
return;
|
|
481
|
+
try {
|
|
482
|
+
if ((options.immediate ?? true) || !initial) {
|
|
483
|
+
iterations++;
|
|
484
|
+
if (await ((_a2 = options.condition) == null ? void 0 : _a2.call(options, iterations - 1)) ?? true) {
|
|
485
|
+
const val = await options.task(iterations - 1);
|
|
486
|
+
if (options.onSuccess)
|
|
487
|
+
await options.onSuccess(val, iterations - 1);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
} catch (err) {
|
|
491
|
+
if (options.onError)
|
|
492
|
+
await options.onError(err, iterations - 1);
|
|
493
|
+
if (options.abortOnError)
|
|
494
|
+
aborted = true;
|
|
495
|
+
if (!options.onError && !options.abortOnError)
|
|
496
|
+
throw err;
|
|
497
|
+
}
|
|
498
|
+
if (!aborted && (typeof options.maxIterations !== "number" || iterations < options.maxIterations))
|
|
499
|
+
setTimeout(runRecurringTask, options.timeout);
|
|
500
|
+
};
|
|
501
|
+
return runRecurringTask(true);
|
|
502
|
+
}
|
|
469
503
|
|
|
470
504
|
// lib/text.ts
|
|
471
505
|
function autoPlural(term, num, pluralType = "auto") {
|
|
@@ -555,9 +589,208 @@ function truncStr(input, length, endStr = "...") {
|
|
|
555
589
|
return finalStr.length > length ? finalStr.substring(0, length) : finalStr;
|
|
556
590
|
}
|
|
557
591
|
|
|
592
|
+
// node_modules/.pnpm/nanoevents@9.1.0/node_modules/nanoevents/index.js
|
|
593
|
+
var createNanoEvents = () => ({
|
|
594
|
+
emit(event, ...args) {
|
|
595
|
+
for (let callbacks = this.events[event] || [], i = 0, length = callbacks.length; i < length; i++) {
|
|
596
|
+
callbacks[i](...args);
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
events: {},
|
|
600
|
+
on(event, cb) {
|
|
601
|
+
;
|
|
602
|
+
(this.events[event] ||= []).push(cb);
|
|
603
|
+
return () => {
|
|
604
|
+
var _a;
|
|
605
|
+
this.events[event] = (_a = this.events[event]) == null ? void 0 : _a.filter((i) => cb !== i);
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
// lib/NanoEmitter.ts
|
|
611
|
+
var NanoEmitter = class {
|
|
612
|
+
events = createNanoEvents();
|
|
613
|
+
eventUnsubscribes = [];
|
|
614
|
+
emitterOptions;
|
|
615
|
+
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
616
|
+
constructor(options = {}) {
|
|
617
|
+
this.emitterOptions = {
|
|
618
|
+
publicEmit: false,
|
|
619
|
+
...options
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
//#region on
|
|
623
|
+
/**
|
|
624
|
+
* Subscribes to an event and calls the callback when it's emitted.
|
|
625
|
+
* @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 "_")
|
|
626
|
+
* @returns Returns a function that can be called to unsubscribe the event listener
|
|
627
|
+
* @example ```ts
|
|
628
|
+
* const emitter = new NanoEmitter<{
|
|
629
|
+
* foo: (bar: string) => void;
|
|
630
|
+
* }>({
|
|
631
|
+
* publicEmit: true,
|
|
632
|
+
* });
|
|
633
|
+
*
|
|
634
|
+
* let i = 0;
|
|
635
|
+
* const unsub = emitter.on("foo", (bar) => {
|
|
636
|
+
* // unsubscribe after 10 events:
|
|
637
|
+
* if(++i === 10) unsub();
|
|
638
|
+
* console.log(bar);
|
|
639
|
+
* });
|
|
640
|
+
*
|
|
641
|
+
* emitter.emit("foo", "bar");
|
|
642
|
+
* ```
|
|
643
|
+
*/
|
|
644
|
+
on(event, cb) {
|
|
645
|
+
let unsub;
|
|
646
|
+
const unsubProxy = () => {
|
|
647
|
+
if (!unsub)
|
|
648
|
+
return;
|
|
649
|
+
unsub();
|
|
650
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => u !== unsub);
|
|
651
|
+
};
|
|
652
|
+
unsub = this.events.on(event, cb);
|
|
653
|
+
this.eventUnsubscribes.push(unsub);
|
|
654
|
+
return unsubProxy;
|
|
655
|
+
}
|
|
656
|
+
//#region once
|
|
657
|
+
/**
|
|
658
|
+
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
659
|
+
* @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 "_")
|
|
660
|
+
* @param cb The callback to call when the event is emitted - if provided or not, the returned Promise will resolve with the event arguments
|
|
661
|
+
* @returns Returns a Promise that resolves with the event arguments when the event is emitted
|
|
662
|
+
* @example ```ts
|
|
663
|
+
* const emitter = new NanoEmitter<{
|
|
664
|
+
* foo: (bar: string) => void;
|
|
665
|
+
* }>();
|
|
666
|
+
*
|
|
667
|
+
* // Promise syntax:
|
|
668
|
+
* const [bar] = await emitter.once("foo");
|
|
669
|
+
* console.log(bar);
|
|
670
|
+
*
|
|
671
|
+
* // Callback syntax:
|
|
672
|
+
* emitter.once("foo", (bar) => console.log(bar));
|
|
673
|
+
* ```
|
|
674
|
+
*/
|
|
675
|
+
once(event, cb) {
|
|
676
|
+
return new Promise((resolve) => {
|
|
677
|
+
let unsub;
|
|
678
|
+
const onceProxy = ((...args) => {
|
|
679
|
+
cb == null ? void 0 : cb(...args);
|
|
680
|
+
unsub == null ? void 0 : unsub();
|
|
681
|
+
resolve(args);
|
|
682
|
+
});
|
|
683
|
+
unsub = this.events.on(event, onceProxy);
|
|
684
|
+
this.eventUnsubscribes.push(unsub);
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
//#region onMulti
|
|
688
|
+
/**
|
|
689
|
+
* 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.
|
|
690
|
+
* @param options An object or array of objects with the following properties:
|
|
691
|
+
* `callback` (required) is the function that will be called when the conditions are met.
|
|
692
|
+
*
|
|
693
|
+
* 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.
|
|
694
|
+
* If `signal` is provided, the subscription will be canceled when the given signal is aborted.
|
|
695
|
+
*
|
|
696
|
+
* If `oneOf` is used, the callback will be called when any of the matching events are emitted.
|
|
697
|
+
* 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.
|
|
698
|
+
* 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.
|
|
699
|
+
* At least one of `oneOf` or `allOf` must be provided.
|
|
700
|
+
*
|
|
701
|
+
* @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.
|
|
702
|
+
*/
|
|
703
|
+
onMulti(options) {
|
|
704
|
+
const allUnsubs = [];
|
|
705
|
+
const unsubAll = () => {
|
|
706
|
+
for (const unsub of allUnsubs)
|
|
707
|
+
unsub();
|
|
708
|
+
allUnsubs.splice(0, allUnsubs.length);
|
|
709
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !allUnsubs.includes(u));
|
|
710
|
+
};
|
|
711
|
+
for (const opts of Array.isArray(options) ? options : [options]) {
|
|
712
|
+
const optsWithDefaults = {
|
|
713
|
+
allOf: [],
|
|
714
|
+
oneOf: [],
|
|
715
|
+
once: false,
|
|
716
|
+
...opts
|
|
717
|
+
};
|
|
718
|
+
const {
|
|
719
|
+
oneOf,
|
|
720
|
+
allOf,
|
|
721
|
+
once,
|
|
722
|
+
signal,
|
|
723
|
+
callback
|
|
724
|
+
} = optsWithDefaults;
|
|
725
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
726
|
+
return unsubAll;
|
|
727
|
+
if (oneOf.length === 0 && allOf.length === 0)
|
|
728
|
+
throw new TypeError("NanoEmitter.onMulti(): Either `oneOf` or `allOf` or both must be provided in the options");
|
|
729
|
+
const curEvtUnsubs = [];
|
|
730
|
+
const checkUnsubAllEvt = (force = false) => {
|
|
731
|
+
if (!(signal == null ? void 0 : signal.aborted) && !force)
|
|
732
|
+
return;
|
|
733
|
+
for (const unsub of curEvtUnsubs)
|
|
734
|
+
unsub();
|
|
735
|
+
curEvtUnsubs.splice(0, curEvtUnsubs.length);
|
|
736
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !curEvtUnsubs.includes(u));
|
|
737
|
+
};
|
|
738
|
+
const allOfEmitted = /* @__PURE__ */ new Set();
|
|
739
|
+
const allOfConditionMet = () => allOf.length === 0 || allOfEmitted.size === allOf.length;
|
|
740
|
+
for (const event of oneOf) {
|
|
741
|
+
const unsub = this.events.on(event, ((...args) => {
|
|
742
|
+
checkUnsubAllEvt();
|
|
743
|
+
if (allOfConditionMet()) {
|
|
744
|
+
callback(event, ...args);
|
|
745
|
+
if (once)
|
|
746
|
+
checkUnsubAllEvt(true);
|
|
747
|
+
}
|
|
748
|
+
}));
|
|
749
|
+
curEvtUnsubs.push(unsub);
|
|
750
|
+
}
|
|
751
|
+
for (const event of allOf) {
|
|
752
|
+
const unsub = this.events.on(event, ((...args) => {
|
|
753
|
+
checkUnsubAllEvt();
|
|
754
|
+
allOfEmitted.add(event);
|
|
755
|
+
if (allOfConditionMet() && (oneOf.length === 0 || oneOf.includes(event))) {
|
|
756
|
+
callback(event, ...args);
|
|
757
|
+
if (once)
|
|
758
|
+
checkUnsubAllEvt(true);
|
|
759
|
+
}
|
|
760
|
+
}));
|
|
761
|
+
curEvtUnsubs.push(unsub);
|
|
762
|
+
}
|
|
763
|
+
allUnsubs.push(() => checkUnsubAllEvt(true));
|
|
764
|
+
}
|
|
765
|
+
return unsubAll;
|
|
766
|
+
}
|
|
767
|
+
//#region emit
|
|
768
|
+
/**
|
|
769
|
+
* Emits an event on this instance.
|
|
770
|
+
* - ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
771
|
+
* @param event The event to emit
|
|
772
|
+
* @param args The arguments to pass to the event listeners
|
|
773
|
+
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
774
|
+
*/
|
|
775
|
+
emit(event, ...args) {
|
|
776
|
+
if (this.emitterOptions.publicEmit) {
|
|
777
|
+
this.events.emit(event, ...args);
|
|
778
|
+
return true;
|
|
779
|
+
}
|
|
780
|
+
return false;
|
|
781
|
+
}
|
|
782
|
+
//#region unsubscribeAll
|
|
783
|
+
/** Unsubscribes all event listeners from this instance */
|
|
784
|
+
unsubscribeAll() {
|
|
785
|
+
for (const unsub of this.eventUnsubscribes)
|
|
786
|
+
unsub();
|
|
787
|
+
this.eventUnsubscribes = [];
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
|
|
558
791
|
// lib/DataStore.ts
|
|
559
792
|
var dsFmtVer = 1;
|
|
560
|
-
var DataStore = class {
|
|
793
|
+
var DataStore = class extends NanoEmitter {
|
|
561
794
|
id;
|
|
562
795
|
formatVersion;
|
|
563
796
|
defaultData;
|
|
@@ -589,6 +822,7 @@ var DataStore = class {
|
|
|
589
822
|
* @param opts The options for this DataStore instance
|
|
590
823
|
*/
|
|
591
824
|
constructor(opts) {
|
|
825
|
+
super(opts.nanoEmitterOptions);
|
|
592
826
|
this.id = opts.id;
|
|
593
827
|
this.formatVersion = opts.formatVersion;
|
|
594
828
|
this.defaultData = opts.defaultData;
|
|
@@ -659,30 +893,26 @@ var DataStore = class {
|
|
|
659
893
|
this.migrateIds = [];
|
|
660
894
|
}
|
|
661
895
|
const storedDataRaw = await this.engine.getValue(`${this.keyPrefix}${this.id}-dat`, null);
|
|
662
|
-
|
|
896
|
+
const storedFmtVer = Number(await this.engine.getValue(`${this.keyPrefix}${this.id}-ver`, NaN));
|
|
663
897
|
if (typeof storedDataRaw !== "string" && typeof storedDataRaw !== "object" || storedDataRaw === null || isNaN(storedFmtVer)) {
|
|
664
|
-
await this.saveDefaultData();
|
|
665
|
-
|
|
898
|
+
await this.saveDefaultData(false);
|
|
899
|
+
const data = this.engine.deepCopy(this.defaultData);
|
|
900
|
+
this.events.emit("loadData", data);
|
|
901
|
+
return data;
|
|
666
902
|
}
|
|
667
903
|
const storedData = storedDataRaw ?? JSON.stringify(this.defaultData);
|
|
668
904
|
const encodingFmt = String(await this.engine.getValue(`${this.keyPrefix}${this.id}-enf`, null));
|
|
669
905
|
const isEncoded = encodingFmt !== "null" && encodingFmt !== "false" && encodingFmt !== "0" && encodingFmt !== "" && encodingFmt !== null;
|
|
670
|
-
let saveData = false;
|
|
671
|
-
if (isNaN(storedFmtVer)) {
|
|
672
|
-
await this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, storedFmtVer = this.formatVersion);
|
|
673
|
-
saveData = true;
|
|
674
|
-
}
|
|
675
906
|
let parsed = typeof storedData === "string" ? await this.engine.deserializeData(storedData, isEncoded) : storedData;
|
|
676
907
|
if (storedFmtVer < this.formatVersion && this.migrations)
|
|
677
908
|
parsed = await this.runMigrations(parsed, storedFmtVer);
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
return this.cachedData = this.engine.deepCopy(parsed);
|
|
682
|
-
else
|
|
683
|
-
return this.engine.deepCopy(parsed);
|
|
909
|
+
const result = this.memoryCache ? this.cachedData = this.engine.deepCopy(parsed) : this.engine.deepCopy(parsed);
|
|
910
|
+
this.events.emit("loadData", result);
|
|
911
|
+
return result;
|
|
684
912
|
} catch (err) {
|
|
913
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
685
914
|
console.warn("Error while parsing JSON data, resetting it to the default value.", err);
|
|
915
|
+
this.events.emit("error", error);
|
|
686
916
|
await this.saveDefaultData();
|
|
687
917
|
return this.defaultData;
|
|
688
918
|
}
|
|
@@ -701,27 +931,47 @@ var DataStore = class {
|
|
|
701
931
|
//#region setData
|
|
702
932
|
/** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
|
|
703
933
|
setData(data) {
|
|
704
|
-
|
|
934
|
+
const dataCopy = this.engine.deepCopy(data);
|
|
935
|
+
if (this.memoryCache) {
|
|
705
936
|
this.cachedData = data;
|
|
937
|
+
this.events.emit("updateDataSync", dataCopy);
|
|
938
|
+
}
|
|
706
939
|
return new Promise(async (resolve) => {
|
|
707
|
-
await Promise.allSettled([
|
|
940
|
+
const results = await Promise.allSettled([
|
|
708
941
|
this.engine.setValue(`${this.keyPrefix}${this.id}-dat`, await this.engine.serializeData(data, this.encodingEnabled())),
|
|
709
942
|
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, this.formatVersion),
|
|
710
943
|
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
711
944
|
]);
|
|
945
|
+
if (results.every((r) => r.status === "fulfilled"))
|
|
946
|
+
this.events.emit("updateData", dataCopy);
|
|
947
|
+
else {
|
|
948
|
+
const error = new Error("Error while saving data to persistent storage: " + results.map((r) => r.status === "rejected" ? r.reason : null).filter(Boolean).join("; "));
|
|
949
|
+
console.error(error);
|
|
950
|
+
this.events.emit("error", error);
|
|
951
|
+
}
|
|
712
952
|
resolve();
|
|
713
953
|
});
|
|
714
954
|
}
|
|
715
955
|
//#region saveDefaultData
|
|
716
|
-
/**
|
|
717
|
-
|
|
956
|
+
/**
|
|
957
|
+
* Saves the default data passed in the constructor synchronously to the in-memory cache and asynchronously to persistent storage.
|
|
958
|
+
* @param emitEvent Whether to emit the `setDefaultData` event - set to `false` to prevent event emission (used internally during initial population in {@linkcode loadData()})
|
|
959
|
+
*/
|
|
960
|
+
async saveDefaultData(emitEvent = true) {
|
|
718
961
|
if (this.memoryCache)
|
|
719
962
|
this.cachedData = this.defaultData;
|
|
720
|
-
await Promise.allSettled([
|
|
963
|
+
const results = await Promise.allSettled([
|
|
721
964
|
this.engine.setValue(`${this.keyPrefix}${this.id}-dat`, await this.engine.serializeData(this.defaultData, this.encodingEnabled())),
|
|
722
965
|
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, this.formatVersion),
|
|
723
966
|
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
724
967
|
]);
|
|
968
|
+
if (results.every((r) => r.status === "fulfilled"))
|
|
969
|
+
emitEvent && this.events.emit("setDefaultData", this.defaultData);
|
|
970
|
+
else {
|
|
971
|
+
const error = new Error("Error while saving default data to persistent storage: " + results.map((r) => r.status === "rejected" ? r.reason : null).filter(Boolean).join("; "));
|
|
972
|
+
console.error(error);
|
|
973
|
+
this.events.emit("error", error);
|
|
974
|
+
}
|
|
725
975
|
}
|
|
726
976
|
//#region deleteData
|
|
727
977
|
/**
|
|
@@ -737,6 +987,7 @@ var DataStore = class {
|
|
|
737
987
|
this.engine.deleteValue(`${this.keyPrefix}${this.id}-enf`)
|
|
738
988
|
]);
|
|
739
989
|
await ((_b = (_a = this.engine).deleteStorage) == null ? void 0 : _b.call(_a));
|
|
990
|
+
this.events.emit("deleteData");
|
|
740
991
|
}
|
|
741
992
|
//#region encodingEnabled
|
|
742
993
|
/** Returns whether encoding and decoding are enabled for this DataStore instance */
|
|
@@ -757,16 +1008,22 @@ var DataStore = class {
|
|
|
757
1008
|
let newData = oldData;
|
|
758
1009
|
const sortedMigrations = Object.entries(this.migrations).sort(([a], [b]) => Number(a) - Number(b));
|
|
759
1010
|
let lastFmtVer = oldFmtVer;
|
|
760
|
-
for (
|
|
1011
|
+
for (let i = 0; i < sortedMigrations.length; i++) {
|
|
1012
|
+
const [fmtVer, migrationFunc] = sortedMigrations[i];
|
|
761
1013
|
const ver = Number(fmtVer);
|
|
762
1014
|
if (oldFmtVer < this.formatVersion && oldFmtVer < ver) {
|
|
763
1015
|
try {
|
|
764
1016
|
const migRes = migrationFunc(newData);
|
|
765
1017
|
newData = migRes instanceof Promise ? await migRes : migRes;
|
|
766
1018
|
lastFmtVer = oldFmtVer = ver;
|
|
1019
|
+
const isFinal = ver >= this.formatVersion || i === sortedMigrations.length - 1;
|
|
1020
|
+
this.events.emit("migrateData", ver, newData, isFinal);
|
|
767
1021
|
} catch (err) {
|
|
1022
|
+
const migError = new MigrationError(`Error while running migration function for format version '${fmtVer}'`, { cause: err });
|
|
1023
|
+
this.events.emit("migrationError", ver, migError);
|
|
1024
|
+
this.events.emit("error", migError);
|
|
768
1025
|
if (!resetOnError)
|
|
769
|
-
throw
|
|
1026
|
+
throw migError;
|
|
770
1027
|
await this.saveDefaultData();
|
|
771
1028
|
return this.engine.deepCopy(this.defaultData);
|
|
772
1029
|
}
|
|
@@ -777,10 +1034,9 @@ var DataStore = class {
|
|
|
777
1034
|
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, lastFmtVer),
|
|
778
1035
|
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
779
1036
|
]);
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
return this.engine.deepCopy(newData);
|
|
1037
|
+
const result = this.memoryCache ? this.cachedData = this.engine.deepCopy(newData) : this.engine.deepCopy(newData);
|
|
1038
|
+
this.events.emit("updateData", result);
|
|
1039
|
+
return result;
|
|
784
1040
|
}
|
|
785
1041
|
//#region migrateId
|
|
786
1042
|
/**
|
|
@@ -809,6 +1065,7 @@ var DataStore = class {
|
|
|
809
1065
|
this.engine.deleteValue(`${this.keyPrefix}${id}-ver`),
|
|
810
1066
|
this.engine.deleteValue(`${this.keyPrefix}${id}-enf`)
|
|
811
1067
|
]);
|
|
1068
|
+
this.events.emit("migrateId", id, this.id);
|
|
812
1069
|
}));
|
|
813
1070
|
}
|
|
814
1071
|
};
|
|
@@ -1053,7 +1310,10 @@ var DataStoreSerializer = class _DataStoreSerializer {
|
|
|
1053
1310
|
...options
|
|
1054
1311
|
};
|
|
1055
1312
|
}
|
|
1056
|
-
/**
|
|
1313
|
+
/**
|
|
1314
|
+
* Calculates the checksum of a string. Uses {@linkcode computeHash()} with SHA-256 and digests as a hex string by default.
|
|
1315
|
+
* Override this in a subclass if a custom checksum method is needed.
|
|
1316
|
+
*/
|
|
1057
1317
|
async calcChecksum(input) {
|
|
1058
1318
|
return computeHash(input, "SHA-256");
|
|
1059
1319
|
}
|
|
@@ -1177,205 +1437,6 @@ Has: ${checksum}`);
|
|
|
1177
1437
|
}
|
|
1178
1438
|
};
|
|
1179
1439
|
|
|
1180
|
-
// node_modules/.pnpm/nanoevents@9.1.0/node_modules/nanoevents/index.js
|
|
1181
|
-
var createNanoEvents = () => ({
|
|
1182
|
-
emit(event, ...args) {
|
|
1183
|
-
for (let callbacks = this.events[event] || [], i = 0, length = callbacks.length; i < length; i++) {
|
|
1184
|
-
callbacks[i](...args);
|
|
1185
|
-
}
|
|
1186
|
-
},
|
|
1187
|
-
events: {},
|
|
1188
|
-
on(event, cb) {
|
|
1189
|
-
;
|
|
1190
|
-
(this.events[event] ||= []).push(cb);
|
|
1191
|
-
return () => {
|
|
1192
|
-
var _a;
|
|
1193
|
-
this.events[event] = (_a = this.events[event]) == null ? void 0 : _a.filter((i) => cb !== i);
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
|
-
});
|
|
1197
|
-
|
|
1198
|
-
// lib/NanoEmitter.ts
|
|
1199
|
-
var NanoEmitter = class {
|
|
1200
|
-
events = createNanoEvents();
|
|
1201
|
-
eventUnsubscribes = [];
|
|
1202
|
-
emitterOptions;
|
|
1203
|
-
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
1204
|
-
constructor(options = {}) {
|
|
1205
|
-
this.emitterOptions = {
|
|
1206
|
-
publicEmit: false,
|
|
1207
|
-
...options
|
|
1208
|
-
};
|
|
1209
|
-
}
|
|
1210
|
-
//#region on
|
|
1211
|
-
/**
|
|
1212
|
-
* Subscribes to an event and calls the callback when it's emitted.
|
|
1213
|
-
* @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 "_")
|
|
1214
|
-
* @returns Returns a function that can be called to unsubscribe the event listener
|
|
1215
|
-
* @example ```ts
|
|
1216
|
-
* const emitter = new NanoEmitter<{
|
|
1217
|
-
* foo: (bar: string) => void;
|
|
1218
|
-
* }>({
|
|
1219
|
-
* publicEmit: true,
|
|
1220
|
-
* });
|
|
1221
|
-
*
|
|
1222
|
-
* let i = 0;
|
|
1223
|
-
* const unsub = emitter.on("foo", (bar) => {
|
|
1224
|
-
* // unsubscribe after 10 events:
|
|
1225
|
-
* if(++i === 10) unsub();
|
|
1226
|
-
* console.log(bar);
|
|
1227
|
-
* });
|
|
1228
|
-
*
|
|
1229
|
-
* emitter.emit("foo", "bar");
|
|
1230
|
-
* ```
|
|
1231
|
-
*/
|
|
1232
|
-
on(event, cb) {
|
|
1233
|
-
let unsub;
|
|
1234
|
-
const unsubProxy = () => {
|
|
1235
|
-
if (!unsub)
|
|
1236
|
-
return;
|
|
1237
|
-
unsub();
|
|
1238
|
-
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => u !== unsub);
|
|
1239
|
-
};
|
|
1240
|
-
unsub = this.events.on(event, cb);
|
|
1241
|
-
this.eventUnsubscribes.push(unsub);
|
|
1242
|
-
return unsubProxy;
|
|
1243
|
-
}
|
|
1244
|
-
//#region once
|
|
1245
|
-
/**
|
|
1246
|
-
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
1247
|
-
* @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 "_")
|
|
1248
|
-
* @param cb The callback to call when the event is emitted - if provided or not, the returned Promise will resolve with the event arguments
|
|
1249
|
-
* @returns Returns a Promise that resolves with the event arguments when the event is emitted
|
|
1250
|
-
* @example ```ts
|
|
1251
|
-
* const emitter = new NanoEmitter<{
|
|
1252
|
-
* foo: (bar: string) => void;
|
|
1253
|
-
* }>();
|
|
1254
|
-
*
|
|
1255
|
-
* // Promise syntax:
|
|
1256
|
-
* const [bar] = await emitter.once("foo");
|
|
1257
|
-
* console.log(bar);
|
|
1258
|
-
*
|
|
1259
|
-
* // Callback syntax:
|
|
1260
|
-
* emitter.once("foo", (bar) => console.log(bar));
|
|
1261
|
-
* ```
|
|
1262
|
-
*/
|
|
1263
|
-
once(event, cb) {
|
|
1264
|
-
return new Promise((resolve) => {
|
|
1265
|
-
let unsub;
|
|
1266
|
-
const onceProxy = ((...args) => {
|
|
1267
|
-
cb == null ? void 0 : cb(...args);
|
|
1268
|
-
unsub == null ? void 0 : unsub();
|
|
1269
|
-
resolve(args);
|
|
1270
|
-
});
|
|
1271
|
-
unsub = this.events.on(event, onceProxy);
|
|
1272
|
-
this.eventUnsubscribes.push(unsub);
|
|
1273
|
-
});
|
|
1274
|
-
}
|
|
1275
|
-
//#region onMulti
|
|
1276
|
-
/**
|
|
1277
|
-
* 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.
|
|
1278
|
-
* @param options An object or array of objects with the following properties:
|
|
1279
|
-
* `callback` (required) is the function that will be called when the conditions are met.
|
|
1280
|
-
*
|
|
1281
|
-
* 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.
|
|
1282
|
-
* If `signal` is provided, the subscription will be canceled when the given signal is aborted.
|
|
1283
|
-
*
|
|
1284
|
-
* If `oneOf` is used, the callback will be called when any of the matching events are emitted.
|
|
1285
|
-
* 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.
|
|
1286
|
-
* 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.
|
|
1287
|
-
* At least one of `oneOf` or `allOf` must be provided.
|
|
1288
|
-
*
|
|
1289
|
-
* @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.
|
|
1290
|
-
*/
|
|
1291
|
-
onMulti(options) {
|
|
1292
|
-
const allUnsubs = [];
|
|
1293
|
-
const unsubAll = () => {
|
|
1294
|
-
for (const unsub of allUnsubs)
|
|
1295
|
-
unsub();
|
|
1296
|
-
allUnsubs.splice(0, allUnsubs.length);
|
|
1297
|
-
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !allUnsubs.includes(u));
|
|
1298
|
-
};
|
|
1299
|
-
for (const opts of Array.isArray(options) ? options : [options]) {
|
|
1300
|
-
const optsWithDefaults = {
|
|
1301
|
-
allOf: [],
|
|
1302
|
-
oneOf: [],
|
|
1303
|
-
once: false,
|
|
1304
|
-
...opts
|
|
1305
|
-
};
|
|
1306
|
-
const {
|
|
1307
|
-
oneOf,
|
|
1308
|
-
allOf,
|
|
1309
|
-
once,
|
|
1310
|
-
signal,
|
|
1311
|
-
callback
|
|
1312
|
-
} = optsWithDefaults;
|
|
1313
|
-
if (signal == null ? void 0 : signal.aborted)
|
|
1314
|
-
return unsubAll;
|
|
1315
|
-
if (oneOf.length === 0 && allOf.length === 0)
|
|
1316
|
-
throw new TypeError("NanoEmitter.onMulti(): Either `oneOf` or `allOf` or both must be provided in the options");
|
|
1317
|
-
const curEvtUnsubs = [];
|
|
1318
|
-
const checkUnsubAllEvt = (force = false) => {
|
|
1319
|
-
if (!(signal == null ? void 0 : signal.aborted) && !force)
|
|
1320
|
-
return;
|
|
1321
|
-
for (const unsub of curEvtUnsubs)
|
|
1322
|
-
unsub();
|
|
1323
|
-
curEvtUnsubs.splice(0, curEvtUnsubs.length);
|
|
1324
|
-
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !curEvtUnsubs.includes(u));
|
|
1325
|
-
};
|
|
1326
|
-
const allOfEmitted = /* @__PURE__ */ new Set();
|
|
1327
|
-
const allOfConditionMet = () => allOf.length === 0 || allOfEmitted.size === allOf.length;
|
|
1328
|
-
for (const event of oneOf) {
|
|
1329
|
-
const unsub = this.events.on(event, ((...args) => {
|
|
1330
|
-
checkUnsubAllEvt();
|
|
1331
|
-
if (allOfConditionMet()) {
|
|
1332
|
-
callback(event, ...args);
|
|
1333
|
-
if (once)
|
|
1334
|
-
checkUnsubAllEvt(true);
|
|
1335
|
-
}
|
|
1336
|
-
}));
|
|
1337
|
-
curEvtUnsubs.push(unsub);
|
|
1338
|
-
}
|
|
1339
|
-
for (const event of allOf) {
|
|
1340
|
-
const unsub = this.events.on(event, ((...args) => {
|
|
1341
|
-
checkUnsubAllEvt();
|
|
1342
|
-
allOfEmitted.add(event);
|
|
1343
|
-
if (allOfConditionMet() && (oneOf.length === 0 || oneOf.includes(event))) {
|
|
1344
|
-
callback(event, ...args);
|
|
1345
|
-
if (once)
|
|
1346
|
-
checkUnsubAllEvt(true);
|
|
1347
|
-
}
|
|
1348
|
-
}));
|
|
1349
|
-
curEvtUnsubs.push(unsub);
|
|
1350
|
-
}
|
|
1351
|
-
allUnsubs.push(() => checkUnsubAllEvt(true));
|
|
1352
|
-
}
|
|
1353
|
-
return unsubAll;
|
|
1354
|
-
}
|
|
1355
|
-
//#region emit
|
|
1356
|
-
/**
|
|
1357
|
-
* Emits an event on this instance.
|
|
1358
|
-
* - ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
1359
|
-
* @param event The event to emit
|
|
1360
|
-
* @param args The arguments to pass to the event listeners
|
|
1361
|
-
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
1362
|
-
*/
|
|
1363
|
-
emit(event, ...args) {
|
|
1364
|
-
if (this.emitterOptions.publicEmit) {
|
|
1365
|
-
this.events.emit(event, ...args);
|
|
1366
|
-
return true;
|
|
1367
|
-
}
|
|
1368
|
-
return false;
|
|
1369
|
-
}
|
|
1370
|
-
//#region unsubscribeAll
|
|
1371
|
-
/** Unsubscribes all event listeners from this instance */
|
|
1372
|
-
unsubscribeAll() {
|
|
1373
|
-
for (const unsub of this.eventUnsubscribes)
|
|
1374
|
-
unsub();
|
|
1375
|
-
this.eventUnsubscribes = [];
|
|
1376
|
-
}
|
|
1377
|
-
};
|
|
1378
|
-
|
|
1379
1440
|
// lib/Debouncer.ts
|
|
1380
1441
|
var Debouncer = class extends NanoEmitter {
|
|
1381
1442
|
/**
|
|
@@ -1383,8 +1444,8 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1383
1444
|
* @param timeout Timeout in milliseconds between letting through calls - defaults to 200
|
|
1384
1445
|
* @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"
|
|
1385
1446
|
*/
|
|
1386
|
-
constructor(timeout = 200, type = "immediate") {
|
|
1387
|
-
super();
|
|
1447
|
+
constructor(timeout = 200, type = "immediate", nanoEmitterOptions) {
|
|
1448
|
+
super(nanoEmitterOptions);
|
|
1388
1449
|
this.timeout = timeout;
|
|
1389
1450
|
this.type = type;
|
|
1390
1451
|
}
|
|
@@ -1415,7 +1476,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1415
1476
|
//#region timeout
|
|
1416
1477
|
/** Sets the timeout for the debouncer */
|
|
1417
1478
|
setTimeout(timeout) {
|
|
1418
|
-
this.emit("change", this.timeout = timeout, this.type);
|
|
1479
|
+
this.events.emit("change", this.timeout = timeout, this.type);
|
|
1419
1480
|
}
|
|
1420
1481
|
/** Returns the current timeout */
|
|
1421
1482
|
getTimeout() {
|
|
@@ -1428,7 +1489,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1428
1489
|
//#region type
|
|
1429
1490
|
/** Sets the edge type for the debouncer */
|
|
1430
1491
|
setType(type) {
|
|
1431
|
-
this.emit("change", this.timeout, this.type = type);
|
|
1492
|
+
this.events.emit("change", this.timeout, this.type = type);
|
|
1432
1493
|
}
|
|
1433
1494
|
/** Returns the current edge type */
|
|
1434
1495
|
getType() {
|
|
@@ -1439,7 +1500,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1439
1500
|
call(...args) {
|
|
1440
1501
|
const cl = (...a) => {
|
|
1441
1502
|
this.queuedCall = void 0;
|
|
1442
|
-
this.emit("call", ...a);
|
|
1503
|
+
this.events.emit("call", ...a);
|
|
1443
1504
|
this.listeners.forEach((l) => l.call(this, ...a));
|
|
1444
1505
|
};
|
|
1445
1506
|
const setRepeatTimeout = () => {
|
|
@@ -1472,8 +1533,8 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1472
1533
|
}
|
|
1473
1534
|
}
|
|
1474
1535
|
};
|
|
1475
|
-
function debounce(fn, timeout = 200, type = "immediate") {
|
|
1476
|
-
const debouncer = new Debouncer(timeout, type);
|
|
1536
|
+
function debounce(fn, timeout = 200, type = "immediate", nanoEmitterOptions) {
|
|
1537
|
+
const debouncer = new Debouncer(timeout, type, nanoEmitterOptions);
|
|
1477
1538
|
debouncer.addListener(fn);
|
|
1478
1539
|
const func = ((...args) => debouncer.call(...args));
|
|
1479
1540
|
func.debouncer = debouncer;
|