@nxtedition/lib 26.0.11 → 26.0.14
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/cache.js +87 -49
- package/package.json +1 -1
- package/util/template/javascript.js +5 -2
package/cache.js
CHANGED
|
@@ -80,37 +80,43 @@ export class AsyncCache {
|
|
|
80
80
|
this.#lru =
|
|
81
81
|
opts?.lru === false || opts?.lru === null ? null : new LRUCache({ max: 4096, ...opts?.lru })
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
83
|
+
for (let n = 0; true; n++) {
|
|
84
|
+
try {
|
|
85
|
+
this.#db ??= new DatabaseSync(location, { timeout: 20, ...opts?.db })
|
|
86
|
+
|
|
87
|
+
this.#db.exec(`
|
|
88
|
+
PRAGMA journal_mode = WAL;
|
|
89
|
+
PRAGMA synchronous = NORMAL;
|
|
90
|
+
PRAGMA temp_store = memory;
|
|
91
|
+
PRAGMA optimize;
|
|
92
|
+
|
|
93
|
+
CREATE TABLE IF NOT EXISTS cache (
|
|
94
|
+
key TEXT PRIMARY KEY NOT NULL,
|
|
95
|
+
val TEXT NOT NULL,
|
|
96
|
+
ttl INTEGER NOT NULL,
|
|
97
|
+
stale INTEGER NOT NULL
|
|
98
|
+
);
|
|
99
|
+
`)
|
|
100
|
+
|
|
101
|
+
this.#getQuery = this.#db.prepare(`SELECT val, ttl, stale FROM cache WHERE key = ?`)
|
|
102
|
+
this.#setQuery = this.#db.prepare(
|
|
103
|
+
`INSERT OR REPLACE INTO cache (key, val, ttl, stale) VALUES (?, ?, ?, ?)`,
|
|
104
|
+
)
|
|
105
|
+
this.#delQuery = this.#db.prepare(`DELETE FROM cache WHERE key = ?`)
|
|
106
|
+
break
|
|
107
|
+
} catch (err) {
|
|
108
|
+
if (n >= 8) {
|
|
109
|
+
this.#db?.close()
|
|
110
|
+
this.#db = null
|
|
111
|
+
|
|
112
|
+
this.#getQuery = null
|
|
113
|
+
this.#setQuery = null
|
|
114
|
+
this.#delQuery = null
|
|
115
|
+
|
|
116
|
+
process.emitWarning(err)
|
|
117
|
+
break
|
|
118
|
+
}
|
|
119
|
+
}
|
|
114
120
|
}
|
|
115
121
|
}
|
|
116
122
|
|
|
@@ -123,6 +129,31 @@ export class AsyncCache {
|
|
|
123
129
|
* @returns {{ value: V|Promise<V>, async: boolean }}
|
|
124
130
|
*/
|
|
125
131
|
get(...args) {
|
|
132
|
+
return this.#load(args, true)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @param {...any} args
|
|
137
|
+
* @returns {{ value: V|Promise<V>, async: boolean }}
|
|
138
|
+
*/
|
|
139
|
+
peek(...args) {
|
|
140
|
+
return this.#load(args, false)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {...any} args
|
|
145
|
+
* @returns {Promise<V>}
|
|
146
|
+
*/
|
|
147
|
+
refresh(...args) {
|
|
148
|
+
return this.#refresh(args)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @param {any[]} args
|
|
153
|
+
* @param {boolean} refresh
|
|
154
|
+
* @returns {{ value: V|Promise<V>, async: boolean }}
|
|
155
|
+
*/
|
|
156
|
+
#load(args, refresh) {
|
|
126
157
|
const key = this.#keySelector(...args)
|
|
127
158
|
|
|
128
159
|
if (typeof key !== 'string' || key.length === 0) {
|
|
@@ -167,30 +198,37 @@ export class AsyncCache {
|
|
|
167
198
|
}
|
|
168
199
|
}
|
|
169
200
|
|
|
170
|
-
|
|
171
|
-
if (this.#valueSelector) {
|
|
172
|
-
promise = this.#dedupe.get(key)
|
|
173
|
-
if (promise === undefined) {
|
|
174
|
-
promise = this.#valueSelector(...args).then(
|
|
175
|
-
(value) => {
|
|
176
|
-
this.set(key, value)
|
|
177
|
-
return value
|
|
178
|
-
},
|
|
179
|
-
(err) => {
|
|
180
|
-
this.delete(key)
|
|
181
|
-
throw err
|
|
182
|
-
},
|
|
183
|
-
)
|
|
184
|
-
promise.catch(noop)
|
|
185
|
-
this.#dedupe.set(key, promise)
|
|
186
|
-
}
|
|
187
|
-
}
|
|
201
|
+
const promise = refresh ? this.#refresh(args, key) : null
|
|
188
202
|
|
|
189
203
|
return cached !== undefined
|
|
190
204
|
? { value: cached.value, async: false }
|
|
191
205
|
: { value: promise, async: true }
|
|
192
206
|
}
|
|
193
207
|
|
|
208
|
+
#refresh(args, key = this.#keySelector(...args)) {
|
|
209
|
+
if (typeof key !== 'string' || key.length === 0) {
|
|
210
|
+
throw new TypeError('keySelector must return a non-empty string')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let promise = this.#dedupe.get(key)
|
|
214
|
+
if (promise === undefined && this.#valueSelector) {
|
|
215
|
+
promise = this.#valueSelector(...args).then(
|
|
216
|
+
(value) => {
|
|
217
|
+
this.set(key, value)
|
|
218
|
+
return value
|
|
219
|
+
},
|
|
220
|
+
(err) => {
|
|
221
|
+
this.delete(key)
|
|
222
|
+
throw err
|
|
223
|
+
},
|
|
224
|
+
)
|
|
225
|
+
promise.catch(noop)
|
|
226
|
+
this.#dedupe.set(key, promise)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return promise
|
|
230
|
+
}
|
|
231
|
+
|
|
194
232
|
/**
|
|
195
233
|
* @param {string} key
|
|
196
234
|
* @param {V} value
|
package/package.json
CHANGED
|
@@ -71,12 +71,15 @@ class FetchEntry {
|
|
|
71
71
|
})
|
|
72
72
|
.catch((err) => {
|
|
73
73
|
if (this.refresh) {
|
|
74
|
-
this.error = Object.assign(
|
|
74
|
+
this.error = Object.assign(new Error('fetch failed'), {
|
|
75
|
+
data: { resource },
|
|
76
|
+
cause: err,
|
|
77
|
+
})
|
|
75
78
|
this.refresh()
|
|
76
79
|
}
|
|
77
80
|
})
|
|
78
81
|
} catch (err) {
|
|
79
|
-
this.error = Object.assign(
|
|
82
|
+
this.error = Object.assign(new Error('fetch failed'), { data: { resource }, cause: err })
|
|
80
83
|
this.refresh()
|
|
81
84
|
}
|
|
82
85
|
}
|