@ztimson/utils 0.27.4 → 0.27.5

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/dist/cache.d.ts CHANGED
@@ -9,6 +9,8 @@ export type CacheOptions = {
9
9
  } | string;
10
10
  /** Keep or delete cached items once expired, defaults to delete */
11
11
  expiryPolicy?: 'delete' | 'keep';
12
+ /** Least Recently Used size limit */
13
+ sizeLimit?: number;
12
14
  };
13
15
  export type CachedValue<T> = T & {
14
16
  _expired?: boolean;
@@ -19,12 +21,14 @@ export type CachedValue<T> = T & {
19
21
  export declare class Cache<K extends string | number | symbol, T> {
20
22
  readonly key?: keyof T | undefined;
21
23
  readonly options: CacheOptions;
24
+ private _loading;
22
25
  private store;
26
+ private timers;
27
+ private lruOrder;
23
28
  /** Support index lookups */
24
29
  [key: string | number | symbol]: CachedValue<T> | any;
25
30
  /** Whether cache is complete */
26
31
  complete: boolean;
27
- private _loading;
28
32
  /** Await initial loading */
29
33
  loading: Promise<void>;
30
34
  /**
@@ -35,6 +39,8 @@ export declare class Cache<K extends string | number | symbol, T> {
35
39
  constructor(key?: keyof T | undefined, options?: CacheOptions);
36
40
  private getKey;
37
41
  private save;
42
+ private clearTimer;
43
+ private touchLRU;
38
44
  /**
39
45
  * Get all cached items
40
46
  * @return {T[]} Array of items
@@ -109,5 +115,5 @@ export declare class Cache<K extends string | number | symbol, T> {
109
115
  * Get all cached items
110
116
  * @return {T[]} Array of items
111
117
  */
112
- values: CachedValue<T>[];
118
+ values: (expired?: boolean) => CachedValue<T>[];
113
119
  }
package/dist/index.cjs CHANGED
@@ -456,17 +456,19 @@ ${opts.message || this.desc}`;
456
456
  * @param options
457
457
  */
458
458
  constructor(key, options = {}) {
459
- __publicField(this, "store", {});
459
+ __publicField(this, "_loading");
460
+ __publicField(this, "store", /* @__PURE__ */ new Map());
461
+ __publicField(this, "timers", /* @__PURE__ */ new Map());
462
+ __publicField(this, "lruOrder", []);
460
463
  /** Whether cache is complete */
461
464
  __publicField(this, "complete", false);
462
- __publicField(this, "_loading");
463
465
  /** Await initial loading */
464
466
  __publicField(this, "loading", new Promise((r) => this._loading = r));
465
467
  /**
466
468
  * Get all cached items
467
469
  * @return {T[]} Array of items
468
470
  */
469
- __publicField(this, "values", this.all());
471
+ __publicField(this, "values", this.all);
470
472
  var _a, _b, _c, _d;
471
473
  this.key = key;
472
474
  this.options = options;
@@ -478,14 +480,18 @@ ${opts.message || this.desc}`;
478
480
  const persists = this.options.persistentStorage;
479
481
  const table = await persists.storage.createTable({ name: persists.key, key: this.key });
480
482
  const rows = await table.getAll();
481
- Object.assign(this.store, rows.reduce((acc, row) => ({ ...acc, [this.getKey(row)]: row }), {}));
483
+ for (const row of rows) this.store.set(this.getKey(row), row);
482
484
  this._loading();
483
485
  })();
484
486
  } else if (((_d = (_c = this.options.persistentStorage) == null ? void 0 : _c.storage) == null ? void 0 : _d.getItem) != void 0) {
485
- const stored = this.options.persistentStorage.storage.getItem(this.options.persistentStorage.key);
486
- if (stored != null) try {
487
- Object.assign(this.store, JSON.parse(stored));
488
- } catch {
487
+ const { storage, key: key2 } = this.options.persistentStorage;
488
+ const stored = storage.getItem(key2);
489
+ if (stored != null) {
490
+ try {
491
+ const obj = JSON.parse(stored);
492
+ for (const k of Object.keys(obj)) this.store.set(k, obj[k]);
493
+ } catch {
494
+ }
489
495
  }
490
496
  this._loading();
491
497
  }
@@ -515,26 +521,50 @@ ${opts.message || this.desc}`;
515
521
  if (!!(persists == null ? void 0 : persists.storage)) {
516
522
  if (((_a = persists.storage) == null ? void 0 : _a.database) != void 0) {
517
523
  persists.storage.createTable({ name: persists.key, key: this.key }).then((table) => {
518
- if (key) {
519
- const value = this.get(key);
524
+ if (key !== void 0) {
525
+ const value = this.get(key, true);
520
526
  if (value != null) table.set(value, key);
521
527
  else table.delete(key);
522
528
  } else {
523
529
  table.clear();
524
- this.all().forEach((row) => table.add(row));
530
+ this.all(true).forEach((row) => table.add(row));
525
531
  }
526
532
  });
527
533
  } else if (((_b = persists.storage) == null ? void 0 : _b.setItem) != void 0) {
528
- persists.storage.setItem(persists.storage.key, JSONSanitize(this.all(true)));
534
+ const obj = {};
535
+ for (const [k, v] of this.store.entries()) obj[k] = v;
536
+ persists.storage.setItem(persists.key, JSONSanitize(obj));
529
537
  }
530
538
  }
531
539
  }
540
+ clearTimer(key) {
541
+ const t = this.timers.get(key);
542
+ if (t) {
543
+ clearTimeout(t);
544
+ this.timers.delete(key);
545
+ }
546
+ }
547
+ touchLRU(key) {
548
+ if (!this.options.sizeLimit || this.options.sizeLimit <= 0) return;
549
+ const idx = this.lruOrder.indexOf(key);
550
+ if (idx >= 0) this.lruOrder.splice(idx, 1);
551
+ this.lruOrder.push(key);
552
+ while (this.lruOrder.length > (this.options.sizeLimit || 0)) {
553
+ const lru = this.lruOrder.shift();
554
+ if (lru !== void 0) this.delete(lru);
555
+ }
556
+ }
532
557
  /**
533
558
  * Get all cached items
534
559
  * @return {T[]} Array of items
535
560
  */
536
561
  all(expired) {
537
- return deepCopy(Object.values(this.store).filter((v) => expired || !v._expired));
562
+ const out = [];
563
+ for (const v of this.store.values()) {
564
+ const val = v;
565
+ if (expired || !(val == null ? void 0 : val._expired)) out.push(deepCopy(val));
566
+ }
567
+ return out;
538
568
  }
539
569
  /**
540
570
  * Add a new item to the cache. Like set, but finds key automatically
@@ -564,7 +594,10 @@ ${opts.message || this.desc}`;
564
594
  */
565
595
  clear() {
566
596
  this.complete = false;
567
- this.store = {};
597
+ for (const [k, t] of this.timers) clearTimeout(t);
598
+ this.timers.clear();
599
+ this.lruOrder = [];
600
+ this.store.clear();
568
601
  this.save();
569
602
  return this;
570
603
  }
@@ -573,7 +606,10 @@ ${opts.message || this.desc}`;
573
606
  * @param {K} key Item's primary key
574
607
  */
575
608
  delete(key) {
576
- delete this.store[key];
609
+ this.clearTimer(key);
610
+ const idx = this.lruOrder.indexOf(key);
611
+ if (idx >= 0) this.lruOrder.splice(idx, 1);
612
+ this.store.delete(key);
577
613
  this.save(key);
578
614
  return this;
579
615
  }
@@ -582,7 +618,12 @@ ${opts.message || this.desc}`;
582
618
  * @return {[K, T][]} Key-value pairs array
583
619
  */
584
620
  entries(expired) {
585
- return deepCopy(Object.entries(this.store).filter((v) => expired || !(v == null ? void 0 : v._expired)));
621
+ const out = [];
622
+ for (const [k, v] of this.store.entries()) {
623
+ const val = v;
624
+ if (expired || !(val == null ? void 0 : val._expired)) out.push([k, deepCopy(val)]);
625
+ }
626
+ return out;
586
627
  }
587
628
  /**
588
629
  * Manually expire a cached item
@@ -591,8 +632,12 @@ ${opts.message || this.desc}`;
591
632
  expire(key) {
592
633
  this.complete = false;
593
634
  if (this.options.expiryPolicy == "keep") {
594
- this.store[key]._expired = true;
595
- this.save(key);
635
+ const v = this.store.get(key);
636
+ if (v) {
637
+ v._expired = true;
638
+ this.store.set(key, v);
639
+ this.save(key);
640
+ }
596
641
  } else this.delete(key);
597
642
  return this;
598
643
  }
@@ -603,7 +648,11 @@ ${opts.message || this.desc}`;
603
648
  * @returns {T | undefined} Cached item or undefined if nothing matched
604
649
  */
605
650
  find(filter, expired) {
606
- return Object.values(this.store).find((row) => (expired || !row._expired) && includes(row, filter));
651
+ for (const v of this.store.values()) {
652
+ const row = v;
653
+ if ((expired || !row._expired) && includes(row, filter)) return deepCopy(row);
654
+ }
655
+ return void 0;
607
656
  }
608
657
  /**
609
658
  * Get item from the cache
@@ -612,7 +661,10 @@ ${opts.message || this.desc}`;
612
661
  * @return {T} Cached item
613
662
  */
614
663
  get(key, expired) {
615
- const cached = deepCopy(this.store[key] ?? null);
664
+ const raw = this.store.get(key);
665
+ if (raw == null) return null;
666
+ const cached = deepCopy(raw);
667
+ this.touchLRU(key);
616
668
  if (expired || !(cached == null ? void 0 : cached._expired)) return cached;
617
669
  return null;
618
670
  }
@@ -621,17 +673,23 @@ ${opts.message || this.desc}`;
621
673
  * @return {K[]} Array of keys
622
674
  */
623
675
  keys(expired) {
624
- return Object.keys(this.store).filter((k) => expired || !this.store[k]._expired);
676
+ const out = [];
677
+ for (const [k, v] of this.store.entries()) {
678
+ const val = v;
679
+ if (expired || !(val == null ? void 0 : val._expired)) out.push(k);
680
+ }
681
+ return out;
625
682
  }
626
683
  /**
627
684
  * Get map of cached items
628
685
  * @return {Record<K, T>}
629
686
  */
630
687
  map(expired) {
631
- const copy = deepCopy(this.store);
632
- if (!expired) Object.keys(copy).forEach((k) => {
633
- if (copy[k]._expired) delete copy[k];
634
- });
688
+ const copy = {};
689
+ for (const [k, v] of this.store.entries()) {
690
+ const val = v;
691
+ if (expired || !(val == null ? void 0 : val._expired)) copy[k] = deepCopy(val);
692
+ }
635
693
  return copy;
636
694
  }
637
695
  /**
@@ -643,12 +701,17 @@ ${opts.message || this.desc}`;
643
701
  */
644
702
  set(key, value, ttl = this.options.ttl) {
645
703
  if (this.options.expiryPolicy == "keep") delete value._expired;
646
- this.store[key] = value;
704
+ this.clearTimer(key);
705
+ this.store.set(key, value);
706
+ this.touchLRU(key);
647
707
  this.save(key);
648
- if (ttl) setTimeout(() => {
649
- this.expire(key);
650
- this.save(key);
651
- }, (ttl || 0) * 1e3);
708
+ if (ttl) {
709
+ const t = setTimeout(() => {
710
+ this.expire(key);
711
+ this.save(key);
712
+ }, (ttl || 0) * 1e3);
713
+ this.timers.set(key, t);
714
+ }
652
715
  return this;
653
716
  }
654
717
  }