@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.
@@ -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 = __pow(10, fractionDigits);
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 != null ? a : NaN})`;
293
- else if (color.startsWith("rgb"))
294
- return `rgb(${r}, ${g}, ${b})`;
257
+ return `rgba(${r}, ${g}, ${b}, ${a ?? NaN})`;
295
258
  else
296
- throw new TypeError("Unsupported color format");
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
- return __async(this, null, function* () {
330
- var _a;
331
- const byteArray = input instanceof ArrayBuffer ? input : new TextEncoder().encode((_a = input == null ? void 0 : input.toString()) != null ? _a : String(input));
332
- const comp = new CompressionStream(compressionFormat);
333
- const writer = comp.writable.getWriter();
334
- writer.write(byteArray);
335
- writer.close();
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
- return __async(this, null, function* () {
342
- var _a;
343
- const byteArray = input instanceof ArrayBuffer ? input : atoab((_a = input == null ? void 0 : input.toString()) != null ? _a : String(input));
344
- const decomp = new DecompressionStream(compressionFormat);
345
- const writer = decomp.writable.getWriter();
346
- writer.write(byteArray);
347
- writer.close();
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
- return __async(this, null, function* () {
354
- let data;
355
- if (typeof input === "string") {
356
- const encoder = new TextEncoder();
357
- data = encoder.encode(input);
358
- } else
359
- data = input;
360
- const hashBuffer = yield crypto.subtle.digest(algorithm, data);
361
- const hashArray = Array.from(new Uint8Array(hashBuffer));
362
- const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
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 __async(this, null, function* () {
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 __async(this, null, function* () {
399
- return typeof strGen === "string" ? strGen : String(
400
- typeof strGen === "function" ? yield strGen() : strGen
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(_0) {
405
- return __async(this, arguments, function* (input, options = {}) {
406
- const { timeout = 1e4 } = options;
407
- const ctl = new AbortController();
408
- const _a = options, { signal } = _a, restOpts = __objRest(_a, ["signal"]);
409
- signal == null ? void 0 : signal.addEventListener("abort", () => ctl.abort());
410
- let sigOpts = {}, id = void 0;
411
- if (timeout >= 0) {
412
- id = setTimeout(() => ctl.abort(), timeout);
413
- sigOpts = { signal: ctl.signal };
414
- }
415
- try {
416
- const res = yield fetch(input, __spreadValues(__spreadValues({}, restOpts), sigOpts));
417
- typeof id !== "undefined" && clearTimeout(id);
418
- return res;
419
- } catch (err) {
420
- typeof id !== "undefined" && clearTimeout(id);
421
- throw new Error("Error while calling fetch", { cause: err });
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 != 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 = () => __async(null, null, function* () {
407
+ const loop = async () => {
456
408
  if (signal == null ? void 0 : signal.aborted)
457
409
  return cleanup();
458
- yield callback();
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, _b;
479
+ var _a;
528
480
  const argIndex = Number(match.substring(1)) - 1;
529
- return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
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
- var _a;
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
- __publicField(this, "id");
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) => __async(this, null, function* () {
631
- return yield compress(data, opts.compressionFormat, "string");
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
- return __async(this, null, function* () {
654
- try {
655
- if (this.firstInit) {
656
- this.firstInit = false;
657
- const dsVer = Number(yield this.engine.getValue("__ds_fmt_ver", 0));
658
- if (isNaN(dsVer) || dsVer < 1) {
659
- const oldData = yield this.engine.getValue(`_uucfg-${this.id}`, null);
660
- if (oldData) {
661
- const oldVer = Number(yield this.engine.getValue(`_uucfgver-${this.id}`, NaN));
662
- const oldEnc = yield this.engine.getValue(`_uucfgenc-${this.id}`, null);
663
- const promises = [];
664
- const migrateFmt = (oldKey, newKey, value) => {
665
- promises.push(this.engine.setValue(newKey, value));
666
- promises.push(this.engine.deleteValue(oldKey));
667
- };
668
- oldData && migrateFmt(`_uucfg-${this.id}`, `__ds-${this.id}-dat`, oldData);
669
- !isNaN(oldVer) && migrateFmt(`_uucfgver-${this.id}`, `__ds-${this.id}-ver`, oldVer);
670
- typeof oldEnc === "boolean" && migrateFmt(`_uucfgenc-${this.id}`, `__ds-${this.id}-enc`, oldEnc === true ? this.compressionFormat : null);
671
- yield Promise.allSettled(promises);
672
- }
673
- yield this.engine.setValue("__ds_fmt_ver", dsFmtVer);
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
- const useEncoding = this.encodingEnabled();
716
- return new Promise((resolve) => __async(this, null, function* () {
717
- yield Promise.allSettled([
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}-enc`, useEncoding)
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
- return __async(this, null, function* () {
728
- this.cachedData = this.defaultData;
729
- const useEncoding = this.encodingEnabled();
730
- yield Promise.allSettled([
731
- this.engine.setValue(`__ds-${this.id}-dat`, yield this.engine.serializeData(this.defaultData, useEncoding)),
732
- this.engine.setValue(`__ds-${this.id}-ver`, this.formatVersion),
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
- return __async(this, null, function* () {
746
- yield Promise.allSettled([
747
- this.engine.deleteValue(`__ds-${this.id}-dat`),
748
- this.engine.deleteValue(`__ds-${this.id}-ver`),
749
- this.engine.deleteValue(`__ds-${this.id}-enc`)
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
- return __async(this, null, function* () {
767
- if (!this.migrations)
768
- return oldData;
769
- let newData = oldData;
770
- const sortedMigrations = Object.entries(this.migrations).sort(([a], [b]) => Number(a) - Number(b));
771
- let lastFmtVer = oldFmtVer;
772
- for (const [fmtVer, migrationFunc] of sortedMigrations) {
773
- const ver = Number(fmtVer);
774
- if (oldFmtVer < this.formatVersion && oldFmtVer < ver) {
775
- try {
776
- const migRes = migrationFunc(newData);
777
- newData = migRes instanceof Promise ? yield migRes : migRes;
778
- lastFmtVer = oldFmtVer = ver;
779
- } catch (err) {
780
- if (!resetOnError)
781
- throw new MigrationError(`Error while running migration function for format version '${fmtVer}'`, { cause: err });
782
- yield this.saveDefaultData();
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
- yield Promise.allSettled([
788
- this.engine.setValue(`__ds-${this.id}-dat`, yield this.engine.serializeData(newData)),
789
- this.engine.setValue(`__ds-${this.id}-ver`, lastFmtVer),
790
- this.engine.setValue(`__ds-${this.id}-enc`, this.encodingEnabled())
791
- ]);
792
- return this.cachedData = __spreadValues({}, newData);
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
- return __async(this, null, function* () {
801
- const ids = Array.isArray(oldIds) ? oldIds : [oldIds];
802
- yield Promise.all(ids.map((id) => __async(this, null, function* () {
803
- const data = yield this.engine.getValue(`__ds-${id}-dat`, JSON.stringify(this.defaultData));
804
- const fmtVer = Number(yield this.engine.getValue(`__ds-${id}-ver`, NaN));
805
- const isEncoded = Boolean(yield this.engine.getValue(`__ds-${id}-enc`, false));
806
- if (data === void 0 || isNaN(fmtVer))
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
- constructor() {
825
- __publicField(this, "dataStoreOptions");
826
- }
778
+ dataStoreOptions;
827
779
  // setDataStoreOptions() is called from inside the DataStore constructor to set this value
828
- /** Called by DataStore on creation, to pass its options */
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
- return __async(this, null, function* () {
836
- var _a, _b, _c, _d, _e;
837
- const stringData = JSON.stringify(data);
838
- if (!useEncoding || !((_a = this.dataStoreOptions) == null ? void 0 : _a.encodeData) || !((_b = this.dataStoreOptions) == null ? void 0 : _b.decodeData))
839
- return stringData;
840
- const encRes = (_e = (_d = (_c = this.dataStoreOptions) == null ? void 0 : _c.encodeData) == null ? void 0 : _d[1]) == null ? void 0 : _e.call(_d, stringData);
841
- if (encRes instanceof Promise)
842
- return yield encRes;
843
- return encRes;
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
- return __async(this, null, function* () {
849
- var _a, _b, _c;
850
- 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;
851
- if (decRes instanceof Promise)
852
- decRes = yield decRes;
853
- return JSON.parse(decRes != null ? decRes : data);
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 (e) {
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 this engine across multiple {@linkcode DataStore} instances
836
+ * - ⚠️ Requires a DOM environment
837
+ * - ⚠️ Don't reuse engines across multiple {@linkcode DataStore} instances
876
838
  */
877
839
  constructor(options) {
878
- super();
879
- __publicField(this, "options");
880
- this.options = __spreadValues({
881
- type: "localStorage"
882
- }, options);
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 __async(this, null, function* () {
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
- return __async(this, null, function* () {
895
- if (this.options.type === "localStorage")
896
- globalThis.localStorage.setItem(name, String(value));
897
- else
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
- return __async(this, null, function* () {
904
- if (this.options.type === "localStorage")
905
- globalThis.localStorage.removeItem(name);
906
- else
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 this engine across multiple {@linkcode DataStore} instances
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
- __publicField(this, "options");
922
- this.options = __spreadValues({
923
- filePath: (id) => `.ds-${id}`
924
- }, options);
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
- return __async(this, null, function* () {
930
- var _a, _b, _c, _d;
931
- try {
932
- if (!fs)
933
- fs = (yield import("fs/promises")).default;
934
- if (!fs)
935
- throw new DatedError("FileStorageEngine requires Node.js or Deno with Node compatibility (v1.31+)", { cause: new Error("'node:fs/promises' module not available") });
936
- const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id);
937
- const data = yield fs.readFile(path, "utf-8");
938
- return data ? JSON.parse((_d = yield (_c = (_b = (_a = this.dataStoreOptions) == null ? void 0 : _a.decodeData) == null ? void 0 : _b[1]) == null ? void 0 : _c.call(_b, data)) != null ? _d : data) : void 0;
939
- } catch (e) {
940
- return void 0;
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
- return __async(this, null, function* () {
947
- var _a, _b, _c, _d;
948
- try {
949
- if (!fs)
950
- fs = (yield import("fs/promises")).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
- yield fs.mkdir(path.slice(0, path.lastIndexOf("/")), { recursive: true });
955
- yield fs.writeFile(path, (_d = yield (_c = (_b = (_a = this.dataStoreOptions) == null ? void 0 : _a.encodeData) == null ? void 0 : _b[1]) == null ? void 0 : _c.call(_b, JSON.stringify(data))) != null ? _d : JSON.stringify(data, void 0, 2), "utf-8");
956
- } catch (err) {
957
- console.error("Error writing file:", err);
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
- return __async(this, null, function* () {
965
- const data = yield this.readFile();
966
- if (!data)
967
- return defaultValue;
968
- const value = data == null ? void 0 : data[name];
969
- if (value === void 0)
970
- return defaultValue;
971
- if (typeof value === "string")
972
- return value;
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
- return __async(this, null, function* () {
979
- let data = yield this.readFile();
980
- if (!data)
981
- data = {};
982
- data[name] = value;
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
- return __async(this, null, function* () {
989
- const data = yield this.readFile();
990
- if (!data)
991
- return;
992
- delete data[name];
993
- yield this.writeFile(data);
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 = __spreadValues({
969
+ this.options = {
1007
970
  addChecksum: true,
1008
- ensureIntegrity: true
1009
- }, options);
971
+ ensureIntegrity: true,
972
+ ...options
973
+ };
1010
974
  }
1011
975
  /** Calculates the checksum of a string */
1012
- calcChecksum(input) {
1013
- return __async(this, null, function* () {
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
- return __async(this, null, function* () {
1025
- const serData = [];
1026
- for (const storeInst of this.stores.filter((s) => typeof stores === "function" ? stores(s.id) : stores.includes(s.id))) {
1027
- const data = useEncoding && storeInst.encodingEnabled() ? yield storeInst.encodeData[1](JSON.stringify(storeInst.getData())) : JSON.stringify(storeInst.getData());
1028
- serData.push({
1029
- id: storeInst.id,
1030
- data,
1031
- formatVersion: storeInst.formatVersion,
1032
- encoded: useEncoding && storeInst.encodingEnabled(),
1033
- checksum: this.options.addChecksum ? yield this.calcChecksum(data) : void 0
1034
- });
1035
- }
1036
- return stringified ? JSON.stringify(serData) : serData;
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 __async(this, null, function* () {
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
- return __async(this, null, function* () {
1055
- const deserStores = typeof data === "string" ? JSON.parse(data) : data;
1056
- if (!Array.isArray(deserStores) || !deserStores.every(_DataStoreSerializer.isSerializedDataStoreObj))
1057
- throw new TypeError("Invalid serialized data format! Expected an array of SerializedDataStore objects.");
1058
- for (const storeData of deserStores.filter((s) => typeof stores === "function" ? stores(s.id) : stores.includes(s.id))) {
1059
- const storeInst = this.stores.find((s) => s.id === storeData.id);
1060
- if (!storeInst)
1061
- throw new Error(`DataStore instance with ID "${storeData.id}" not found! Make sure to provide it in the DataStoreSerializer constructor.`);
1062
- if (this.options.ensureIntegrity && typeof storeData.checksum === "string") {
1063
- const checksum = yield this.calcChecksum(storeData.data);
1064
- if (checksum !== storeData.checksum)
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 __async(this, null, function* () {
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 __async(this, null, function* () {
1094
- return Promise.allSettled(
1095
- this.getStoresFiltered(stores).map((store) => __async(this, null, function* () {
1096
- return {
1097
- id: store.id,
1098
- data: yield store.loadData()
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 __async(this, null, function* () {
1110
- return Promise.allSettled(
1111
- this.getStoresFiltered(stores).map((store) => store.saveDefaultData())
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 __async(this, null, function* () {
1122
- return Promise.allSettled(
1123
- this.getStoresFiltered(stores).map((store) => store.deleteData())
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
- ((_a = this.events)[event] || (_a[event] = [])).push(cb);
1099
+ (this.events[event] ||= []).push(cb);
1153
1100
  return () => {
1154
- var _a2;
1155
- this.events[event] = (_a2 = this.events[event]) == null ? void 0 : _a2.filter((i) => cb !== i);
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
- __publicField(this, "events", createNanoEvents());
1165
- __publicField(this, "eventUnsubscribes", []);
1166
- __publicField(this, "emitterOptions");
1167
- this.emitterOptions = __spreadValues({
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") {