@nxtedition/lib 23.3.34 → 23.4.1

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 +107 -0
  2. package/couch.js +1 -0
  3. package/package.json +2 -1
package/cache.js ADDED
@@ -0,0 +1,107 @@
1
+ import { LRU } from 'lru-cache'
2
+
3
+ export class AsyncCache {
4
+ #lru
5
+ #prefix
6
+ #valueSelector
7
+ #keySelector
8
+ #dedupe = new Map()
9
+ #ttl
10
+ #stale
11
+
12
+ constructor(valueSelector, keySelector, opts) {
13
+ this.#lru = new LRU({ max: 1024 })
14
+ this.#valueSelector = valueSelector
15
+
16
+ if (typeof valueSelector === 'function') {
17
+ this.#valueSelector = valueSelector
18
+ } else {
19
+ throw new TypeError('valueSelector must be a function')
20
+ }
21
+
22
+ if (typeof keySelector === 'function' || keySelector === undefined) {
23
+ this.#keySelector = keySelector ?? ((...args) => JSON.stringify(args))
24
+ } else {
25
+ throw new TypeError('keySelector must be a function')
26
+ }
27
+
28
+ if (opts?.location === undefined) {
29
+ this.#prefix = (opts?.location ?? Math.random().toString(36)) + ':'
30
+ } else if (typeof opts?.location === 'string') {
31
+ this.#prefix = opts.location
32
+ } else {
33
+ throw new TypeError('location must be undefined or a string')
34
+ }
35
+
36
+ if (typeof opts?.ttl === 'number' || opts?.ttl === undefined) {
37
+ const ttl = opts.ttl
38
+ this.#ttl = (val, key) => ttl
39
+ } else if (typeof opts?.ttl === 'function') {
40
+ this.#ttl = opts.ttl
41
+ } else {
42
+ throw new TypeError('ttl must be a undefined, number or a function')
43
+ }
44
+
45
+ if (typeof opts?.stale === 'number' || opts?.stale === undefined) {
46
+ const stale = opts.stale
47
+ this.#stale = () => stale
48
+ } else if (typeof opts?.stale === 'function') {
49
+ this.#stale = opts.stale
50
+ } else {
51
+ throw new TypeError('stale must be a undefined, number or a function')
52
+ }
53
+ }
54
+
55
+ async get(...args) {
56
+ const key = this.#keySelector(...args)
57
+
58
+ if (typeof key !== 'string' || key.length === 0) {
59
+ throw new TypeError('keySelector must return a non-empty string')
60
+ }
61
+
62
+ let cached = this.#lru.get(key)
63
+
64
+ if (!cached) {
65
+ const raw = globalThis.localStorage.getItem(this.#prefix + key)
66
+ cached = raw ? JSON.parse(raw) : null
67
+ }
68
+
69
+ if (cached) {
70
+ if (Date.now() < cached.expire) {
71
+ return cached.value
72
+ }
73
+
74
+ if (Date.now() - cached.expire >= this.#stale(cached.value, key)) {
75
+ // stale-while-revalidate has also expired, dont use cached value
76
+ cached = null
77
+ }
78
+ }
79
+
80
+ let promise = this.#dedupe.get(key)
81
+ if (!promise) {
82
+ promise = this.#valueSelector(...args).then(
83
+ (value) => {
84
+ this.#dedupe.delete(key)
85
+
86
+ cached = {
87
+ expire: Date.now() + this.#ttl(value, key),
88
+ value,
89
+ }
90
+
91
+ globalThis.localStorage.setItem(this.#prefix + key, JSON.stringify(cached))
92
+ this.#lru.set(key, cached)
93
+
94
+ return value
95
+ },
96
+ (err) => {
97
+ this.#dedupe.delete(key)
98
+
99
+ throw err
100
+ },
101
+ )
102
+ this.#dedupe.set(key, promise)
103
+ }
104
+
105
+ return cached ? cached.value : promise
106
+ }
107
+ }
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.1",
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",