@nxtedition/lib 23.3.34 → 23.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.
Files changed (3) hide show
  1. package/cache.js +83 -0
  2. package/couch.js +1 -0
  3. package/package.json +2 -1
package/cache.js ADDED
@@ -0,0 +1,83 @@
1
+ import { LRU } from 'lru-cache'
2
+
3
+ export class AsyncCache {
4
+ #lru
5
+ #keySelector
6
+ #valueSelector
7
+ #dedupe = new Map()
8
+ #ttl
9
+ #stale
10
+
11
+ constructor(valueSelector, opts) {
12
+ this.#lru = new LRU({ max: 1024 })
13
+ this.#keySelector = opts?.keySelector ?? ((...args) => args[0])
14
+ this.#valueSelector = valueSelector
15
+
16
+ if (typeof opts?.ttl === 'number' || opts?.ttl === undefined) {
17
+ const ttl = opts.ttl
18
+ return (val, key) => ttl
19
+ } else if (typeof opts?.ttl === 'function') {
20
+ this.#ttl = opts.ttl
21
+ } else {
22
+ throw new TypeError('ttl must be a number or a function')
23
+ }
24
+
25
+ if (typeof opts?.stale === 'number' || opts?.stale === undefined) {
26
+ const stale = opts.stale
27
+ this.#stale = () => stale
28
+ } else if (typeof opts?.stale === 'function') {
29
+ this.#stale = opts.stale
30
+ } else {
31
+ throw new TypeError('stale must be a number or a function')
32
+ }
33
+ }
34
+
35
+ async get(...args) {
36
+ const key = this.#keySelector(...args)
37
+
38
+ let cached = this.#lru.get(key)
39
+
40
+ if (!cached) {
41
+ const raw = globalThis.localStorage.getItem(key)
42
+ cached = raw ? JSON.parse(raw) : null
43
+ }
44
+
45
+ if (cached) {
46
+ if (Date.now() < cached.expire) {
47
+ return cached.value
48
+ }
49
+
50
+ if (Date.now() - cached.expire >= this.#stale(cached.value, key)) {
51
+ // stale-while-revalidate has also expired, dont use cached value
52
+ cached = null
53
+ }
54
+ }
55
+
56
+ let promise = this.#dedupe.get(key)
57
+ if (!promise) {
58
+ promise = this.#valueSelector(...args).then(
59
+ (value) => {
60
+ this.#dedupe.delete(key)
61
+
62
+ cached = {
63
+ expire: Date.now() + this.#ttl(value, key),
64
+ value,
65
+ }
66
+
67
+ globalThis.localStorage.setItem(key, JSON.stringify(cached))
68
+ this.#lru.set(key, cached)
69
+
70
+ return value
71
+ },
72
+ (err) => {
73
+ this.#dedupe.delete(key)
74
+
75
+ throw err
76
+ },
77
+ )
78
+ this.#dedupe.set(key, promise)
79
+ }
80
+
81
+ return cached ? cached.value : promise
82
+ }
83
+ }
package/couch.js CHANGED
@@ -1091,6 +1091,7 @@ export function request(url, opts) {
1091
1091
  accept: 'application/json',
1092
1092
  ...opts.headers,
1093
1093
  },
1094
+ cache: false,
1094
1095
  body:
1095
1096
  opts.body != null && typeof opts.body === 'object' ? JSON.stringify(opts.body) : opts.body,
1096
1097
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "23.3.34",
3
+ "version": "23.4.0",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "type": "module",
@@ -9,6 +9,7 @@
9
9
  "ass.js",
10
10
  "rxjs/*",
11
11
  "util/*",
12
+ "cache.js",
12
13
  "http-client.js",
13
14
  "subtract-ranges.js",
14
15
  "serializers.js",