@platformatic/next 2.20.0 → 2.21.0-alpha.2
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/lib/caching/valkey.js +108 -13
- package/package.json +6 -6
- package/schema.json +1 -1
package/lib/caching/valkey.js
CHANGED
|
@@ -42,20 +42,50 @@ export class CacheHandler {
|
|
|
42
42
|
#logger
|
|
43
43
|
#store
|
|
44
44
|
#subprefix
|
|
45
|
+
#meta
|
|
45
46
|
#maxTTL
|
|
46
47
|
|
|
47
|
-
constructor () {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.#
|
|
51
|
-
this.#
|
|
52
|
-
this.#
|
|
48
|
+
constructor (options) {
|
|
49
|
+
options ??= {}
|
|
50
|
+
|
|
51
|
+
this.#config = options.config
|
|
52
|
+
this.#logger = options.logger
|
|
53
|
+
this.#store = options.store
|
|
54
|
+
this.#maxTTL = options.maxTTL
|
|
55
|
+
this.#subprefix = options.subprefix
|
|
56
|
+
this.#meta = options.meta
|
|
57
|
+
|
|
58
|
+
if (globalThis.platformatic) {
|
|
59
|
+
this.#config ??= globalThis.platformatic.config.cache
|
|
60
|
+
this.#logger ??= this.#createPlatformaticLogger()
|
|
61
|
+
this.#store ??= getConnection(this.#config.url)
|
|
62
|
+
this.#maxTTL ??= this.#config.maxTTL
|
|
63
|
+
this.#subprefix ??= this.#getPlatformaticSubprefix()
|
|
64
|
+
this.#meta ??= this.#getPlatformaticMeta()
|
|
65
|
+
} else {
|
|
66
|
+
this.#config ??= {}
|
|
67
|
+
this.#maxTTL ??= 86_400
|
|
68
|
+
this.#subprefix ??= ''
|
|
69
|
+
this.#meta ??= {}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!this.#config) {
|
|
73
|
+
throw new Error('Please provide a the "config" option.')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!this.#logger) {
|
|
77
|
+
throw new Error('Please provide a the "logger" option.')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!this.#store) {
|
|
81
|
+
throw new Error('Please provide a the "store" option.')
|
|
82
|
+
}
|
|
53
83
|
}
|
|
54
84
|
|
|
55
|
-
async get (cacheKey) {
|
|
85
|
+
async get (cacheKey, _, isRedisKey) {
|
|
56
86
|
this.#logger.trace({ key: cacheKey }, 'get')
|
|
57
87
|
|
|
58
|
-
const key = this.#keyFor(cacheKey, sections.values)
|
|
88
|
+
const key = isRedisKey ? cacheKey : this.#keyFor(cacheKey, sections.values)
|
|
59
89
|
|
|
60
90
|
let rawValue
|
|
61
91
|
try {
|
|
@@ -96,13 +126,21 @@ export class CacheHandler {
|
|
|
96
126
|
return value
|
|
97
127
|
}
|
|
98
128
|
|
|
99
|
-
async set (cacheKey, value, { tags, revalidate }) {
|
|
129
|
+
async set (cacheKey, value, { tags, revalidate }, isRedisKey) {
|
|
100
130
|
this.#logger.trace({ key: cacheKey, value, tags, revalidate }, 'set')
|
|
101
131
|
|
|
132
|
+
const key = isRedisKey ? cacheKey : this.#keyFor(cacheKey, sections.values)
|
|
133
|
+
|
|
102
134
|
try {
|
|
103
135
|
// Compute the parameters to save
|
|
104
|
-
const
|
|
105
|
-
|
|
136
|
+
const data = this.#serialize({
|
|
137
|
+
value,
|
|
138
|
+
tags,
|
|
139
|
+
lastModified: Date.now(),
|
|
140
|
+
revalidate,
|
|
141
|
+
maxTTL: this.#maxTTL,
|
|
142
|
+
...this.#meta
|
|
143
|
+
})
|
|
106
144
|
const expire = Math.min(revalidate, this.#maxTTL)
|
|
107
145
|
|
|
108
146
|
if (expire < 1) {
|
|
@@ -131,6 +169,56 @@ export class CacheHandler {
|
|
|
131
169
|
}
|
|
132
170
|
}
|
|
133
171
|
|
|
172
|
+
async remove (cacheKey, isRedisKey) {
|
|
173
|
+
this.#logger.trace({ key: cacheKey }, 'remove')
|
|
174
|
+
|
|
175
|
+
const key = isRedisKey ? cacheKey : this.#keyFor(cacheKey, sections.values)
|
|
176
|
+
|
|
177
|
+
let rawValue
|
|
178
|
+
try {
|
|
179
|
+
rawValue = await this.#store.get(key)
|
|
180
|
+
|
|
181
|
+
if (!rawValue) {
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
} catch (e) {
|
|
185
|
+
this.#logger.error({ err: ensureLoggableError(e) }, 'Cannot read cache value from Valkey')
|
|
186
|
+
throw new Error('Cannot read cache value from Valkey', { cause: e })
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
let value
|
|
190
|
+
try {
|
|
191
|
+
value = this.#deserialize(rawValue)
|
|
192
|
+
} catch (e) {
|
|
193
|
+
this.#logger.error({ err: ensureLoggableError(e) }, 'Cannot deserialize cache value from Valkey')
|
|
194
|
+
|
|
195
|
+
// Avoid useless reads the next time
|
|
196
|
+
// Note that since the value was unserializable, we don't know its tags and thus
|
|
197
|
+
// we cannot remove it from the tags sets. TTL will take care of them.
|
|
198
|
+
await this.#store.del(key)
|
|
199
|
+
|
|
200
|
+
throw new Error('Cannot deserialize cache value from Valkey', { cause: e })
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
const promises = []
|
|
205
|
+
promises.push(this.#store.del(key))
|
|
206
|
+
|
|
207
|
+
if (Array.isArray(value.tags)) {
|
|
208
|
+
for (const tag of value.tags) {
|
|
209
|
+
const tagsKey = this.#keyFor(tag, sections.tags)
|
|
210
|
+
this.#store.srem(tagsKey, key, 'gt')
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Execute all the operations
|
|
215
|
+
await Promise.all(promises)
|
|
216
|
+
} catch (e) {
|
|
217
|
+
this.#logger.error({ err: ensureLoggableError(e) }, 'Cannot remove cache value from Valkey')
|
|
218
|
+
throw new Error('Cannot remove cache value from Valkey', { cause: e })
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
134
222
|
async revalidateTag (tags) {
|
|
135
223
|
this.#logger.trace({ tags }, 'revalidateTag')
|
|
136
224
|
|
|
@@ -189,7 +277,7 @@ export class CacheHandler {
|
|
|
189
277
|
await Promise.all(promises)
|
|
190
278
|
}
|
|
191
279
|
|
|
192
|
-
#
|
|
280
|
+
#createPlatformaticLogger () {
|
|
193
281
|
const pinoOptions = {
|
|
194
282
|
level: globalThis.platformatic?.logLevel ?? 'info'
|
|
195
283
|
}
|
|
@@ -205,7 +293,7 @@ export class CacheHandler {
|
|
|
205
293
|
return pino(pinoOptions)
|
|
206
294
|
}
|
|
207
295
|
|
|
208
|
-
#
|
|
296
|
+
#getPlatformaticSubprefix () {
|
|
209
297
|
const root = fileURLToPath(globalThis.platformatic.root)
|
|
210
298
|
|
|
211
299
|
return existsSync(resolve(root, '.next/BUILD_ID'))
|
|
@@ -213,6 +301,13 @@ export class CacheHandler {
|
|
|
213
301
|
: 'development'
|
|
214
302
|
}
|
|
215
303
|
|
|
304
|
+
#getPlatformaticMeta () {
|
|
305
|
+
return {
|
|
306
|
+
serviceId: globalThis.platformatic.serviceId,
|
|
307
|
+
workerId: globalThis.platformatic.workerId
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
216
311
|
#keyFor (key, section) {
|
|
217
312
|
return keyFor(this.#config.prefix, this.#subprefix, section, key)
|
|
218
313
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/next",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.0-alpha.2",
|
|
4
4
|
"description": "Platformatic Next.js Stackable",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"iovalkey": "^0.2.1",
|
|
24
24
|
"msgpackr": "^1.11.2",
|
|
25
25
|
"semver": "^7.6.3",
|
|
26
|
-
"@platformatic/basic": "2.
|
|
27
|
-
"@platformatic/utils": "2.
|
|
28
|
-
"@platformatic/config": "2.
|
|
26
|
+
"@platformatic/basic": "2.21.0-alpha.2",
|
|
27
|
+
"@platformatic/utils": "2.21.0-alpha.2",
|
|
28
|
+
"@platformatic/config": "2.21.0-alpha.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@fastify/reply-from": "^11.0.0",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"react-dom": "^18.3.1",
|
|
42
42
|
"typescript": "^5.5.4",
|
|
43
43
|
"ws": "^8.18.0",
|
|
44
|
-
"@platformatic/composer": "2.
|
|
45
|
-
"@platformatic/service": "2.
|
|
44
|
+
"@platformatic/composer": "2.21.0-alpha.2",
|
|
45
|
+
"@platformatic/service": "2.21.0-alpha.2"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"test": "npm run lint && borp --concurrency=1 --no-timeout",
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/next/2.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/next/2.21.0-alpha.2.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Next.js Stackable",
|
|
5
5
|
"type": "object",
|