@platformatic/next 3.49.1 → 3.51.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.
- package/config.d.ts +6 -0
- package/index.js +9 -0
- package/lib/caching/valkey-components-remote.js +22 -0
- package/lib/caching/valkey-components.js +28 -14
- package/lib/caching/valkey-isr.js +3 -1
- package/lib/capability.js +20 -0
- package/lib/schema.js +23 -0
- package/package.json +5 -5
- package/schema.json +27 -1
package/config.d.ts
CHANGED
|
@@ -122,6 +122,7 @@ export interface PlatformaticNextJsConfig {
|
|
|
122
122
|
entrypointPort?: number;
|
|
123
123
|
changeDirectoryBeforeExecution?: boolean;
|
|
124
124
|
preferLocalCommands?: boolean;
|
|
125
|
+
processSpawner?: string;
|
|
125
126
|
};
|
|
126
127
|
runtime?: {
|
|
127
128
|
preload?: string | string[];
|
|
@@ -703,5 +704,10 @@ export interface PlatformaticNextJsConfig {
|
|
|
703
704
|
cacheComponents?: boolean;
|
|
704
705
|
maxTTL?: number | string;
|
|
705
706
|
ignoreNextConfig?: boolean | string;
|
|
707
|
+
remote?: {
|
|
708
|
+
url?: string;
|
|
709
|
+
prefix?: string;
|
|
710
|
+
maxTTL?: number | string;
|
|
711
|
+
};
|
|
706
712
|
};
|
|
707
713
|
}
|
package/index.js
CHANGED
|
@@ -48,8 +48,17 @@ function enhanceNextCacheConfig (nextConfig, modifications) {
|
|
|
48
48
|
nextConfig.cacheComponents = true
|
|
49
49
|
nextConfig.cacheHandler = getCacheHandlerPath('null-isr')
|
|
50
50
|
nextConfig.cacheHandlers = { default: getCacheHandlerPath(`${config.cache.adapter}-components`) }
|
|
51
|
+
|
|
52
|
+
if (config.cache.remote) {
|
|
53
|
+
nextConfig.cacheHandlers.remote = getCacheHandlerPath(`${config.cache.adapter}-components-remote`)
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
nextConfig.cacheMaxMemorySize = 0
|
|
52
57
|
modifications.push(['componentsCache', config.cache.adapter])
|
|
58
|
+
|
|
59
|
+
if (config.cache.remote) {
|
|
60
|
+
modifications.push(['remoteComponentsCache', config.cache.adapter])
|
|
61
|
+
}
|
|
53
62
|
} else {
|
|
54
63
|
delete nextConfig.cacheHandlers
|
|
55
64
|
nextConfig.cacheHandler = getCacheHandlerPath(`${config.cache.adapter}-isr`)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CacheHandler } from './valkey-components.js'
|
|
2
|
+
|
|
3
|
+
export const CACHE_HIT_METRIC = {
|
|
4
|
+
name: 'next_remote_components_cache_valkey_hit_count',
|
|
5
|
+
help: 'Next.js Remote Components Cache (Valkey) Hit Count'
|
|
6
|
+
}
|
|
7
|
+
export const CACHE_MISS_METRIC = {
|
|
8
|
+
name: 'next_remote_components_cache_valkey_miss_count',
|
|
9
|
+
help: 'Next.js Remote Components Cache (Valkey) Miss Count'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const sections = {
|
|
13
|
+
values: 'remote:components:values',
|
|
14
|
+
tags: 'remote:components:tags'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default new CacheHandler({
|
|
18
|
+
configKey: 'remote',
|
|
19
|
+
sections,
|
|
20
|
+
cacheHitMetric: CACHE_HIT_METRIC,
|
|
21
|
+
cacheMissMetric: CACHE_MISS_METRIC
|
|
22
|
+
})
|
|
@@ -35,20 +35,30 @@ export class CacheHandler {
|
|
|
35
35
|
#subprefix
|
|
36
36
|
#meta
|
|
37
37
|
#maxTTL
|
|
38
|
+
#sections
|
|
38
39
|
#cacheHitMetric
|
|
39
40
|
#cacheMissMetric
|
|
41
|
+
#cacheHitMetricDef
|
|
42
|
+
#cacheMissMetricDef
|
|
40
43
|
|
|
41
|
-
constructor () {
|
|
44
|
+
constructor (options) {
|
|
45
|
+
options ??= {}
|
|
42
46
|
ensureRedis()
|
|
43
47
|
ensureMsgpackr()
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
const baseConfig = globalThis.platformatic.config.cache
|
|
50
|
+
const resolvedConfig = options.configKey ? { ...baseConfig, ...baseConfig[options.configKey] } : baseConfig
|
|
51
|
+
|
|
52
|
+
this.#config ??= resolvedConfig
|
|
46
53
|
this.#logger ??= createPlatformaticLogger()
|
|
47
54
|
this.#store ??= getConnection(this.#config.url)
|
|
48
55
|
this.#maxTTL ??= this.#config.maxTTL
|
|
49
56
|
this.#prefix ??= this.#config.prefix
|
|
50
57
|
this.#subprefix ??= getPlatformaticSubprefix()
|
|
51
58
|
this.#meta ??= getPlatformaticMeta()
|
|
59
|
+
this.#sections = options.sections ?? sections
|
|
60
|
+
this.#cacheHitMetricDef = options.cacheHitMetric ?? CACHE_HIT_METRIC
|
|
61
|
+
this.#cacheMissMetricDef = options.cacheMissMetric ?? CACHE_MISS_METRIC
|
|
52
62
|
|
|
53
63
|
if (!this.#config) {
|
|
54
64
|
throw new Error('Please provide a the "config" option.')
|
|
@@ -70,7 +80,7 @@ export class CacheHandler {
|
|
|
70
80
|
async get (cacheKey, _, isRedisKey) {
|
|
71
81
|
this.#logger.trace({ key: cacheKey }, 'cache get')
|
|
72
82
|
|
|
73
|
-
const key = isRedisKey ? cacheKey : this.#keyFor(cacheKey, sections.values)
|
|
83
|
+
const key = isRedisKey ? cacheKey : this.#keyFor(cacheKey, this.#sections.values)
|
|
74
84
|
|
|
75
85
|
let rawValue
|
|
76
86
|
try {
|
|
@@ -131,7 +141,7 @@ export class CacheHandler {
|
|
|
131
141
|
|
|
132
142
|
this.#logger.trace({ key: cacheKey, value, tags, revalidate }, 'cache set')
|
|
133
143
|
|
|
134
|
-
const key = isRedisKey ? cacheKey : this.#keyFor(cacheKey, sections.values)
|
|
144
|
+
const key = isRedisKey ? cacheKey : this.#keyFor(cacheKey, this.#sections.values)
|
|
135
145
|
|
|
136
146
|
try {
|
|
137
147
|
// Gather the value
|
|
@@ -147,7 +157,11 @@ export class CacheHandler {
|
|
|
147
157
|
value: Buffer.concat(chunks),
|
|
148
158
|
...data
|
|
149
159
|
})
|
|
150
|
-
|
|
160
|
+
// revalidate === false means "cache forever" in Next.js (SSG/force-static pages).
|
|
161
|
+
// Use maxTTL as the expiration in that case.
|
|
162
|
+
const effectiveRevalidate = revalidate === false ? this.#maxTTL : revalidate
|
|
163
|
+
const effectiveExpire = expireSec === false ? this.#maxTTL : expireSec
|
|
164
|
+
const expire = Math.min(effectiveRevalidate, effectiveExpire, this.#maxTTL)
|
|
151
165
|
|
|
152
166
|
if (expire < 1) {
|
|
153
167
|
return
|
|
@@ -160,7 +174,7 @@ export class CacheHandler {
|
|
|
160
174
|
// As Next.js limits tags to 64, we don't need to manage batches here
|
|
161
175
|
if (Array.isArray(tags)) {
|
|
162
176
|
for (const tag of tags) {
|
|
163
|
-
const tagsKey = this.#keyFor(tag, sections.tags)
|
|
177
|
+
const tagsKey = this.#keyFor(tag, this.#sections.tags)
|
|
164
178
|
promises.push(this.#store.sadd(tagsKey, key))
|
|
165
179
|
promises.push(this.#store.expire(tagsKey, expire))
|
|
166
180
|
}
|
|
@@ -191,7 +205,7 @@ export class CacheHandler {
|
|
|
191
205
|
const toDelete = new Set()
|
|
192
206
|
|
|
193
207
|
for (const tag of tags) {
|
|
194
|
-
const tagsKey = this.#keyFor(tag, sections.tags)
|
|
208
|
+
const tagsKey = this.#keyFor(tag, this.#sections.tags)
|
|
195
209
|
|
|
196
210
|
// For each key in the tag set, expire the key
|
|
197
211
|
for await (const keys of this.#store.sscanStream(tagsKey)) {
|
|
@@ -228,7 +242,7 @@ export class CacheHandler {
|
|
|
228
242
|
|
|
229
243
|
if (Array.isArray(value.tags)) {
|
|
230
244
|
for (const tag of value.tags) {
|
|
231
|
-
const tagsKey = this.#keyFor(tag, sections.tags)
|
|
245
|
+
const tagsKey = this.#keyFor(tag, this.#sections.tags)
|
|
232
246
|
promises.push(this.#store.expire(tagsKey, expire, 'gt'))
|
|
233
247
|
}
|
|
234
248
|
}
|
|
@@ -244,18 +258,18 @@ export class CacheHandler {
|
|
|
244
258
|
const { client, registry } = globalThis.platformatic.prometheus
|
|
245
259
|
|
|
246
260
|
this.#cacheHitMetric =
|
|
247
|
-
registry.getSingleMetric(
|
|
261
|
+
registry.getSingleMetric(this.#cacheHitMetricDef.name) ??
|
|
248
262
|
new client.Counter({
|
|
249
|
-
name:
|
|
250
|
-
help:
|
|
263
|
+
name: this.#cacheHitMetricDef.name,
|
|
264
|
+
help: this.#cacheHitMetricDef.help,
|
|
251
265
|
registers: [registry]
|
|
252
266
|
})
|
|
253
267
|
|
|
254
268
|
this.#cacheMissMetric =
|
|
255
|
-
registry.getSingleMetric(
|
|
269
|
+
registry.getSingleMetric(this.#cacheMissMetricDef.name) ??
|
|
256
270
|
new client.Counter({
|
|
257
|
-
name:
|
|
258
|
-
help:
|
|
271
|
+
name: this.#cacheMissMetricDef.name,
|
|
272
|
+
help: this.#cacheMissMetricDef.help,
|
|
259
273
|
registers: [registry]
|
|
260
274
|
})
|
|
261
275
|
}
|
|
@@ -146,7 +146,9 @@ export class CacheHandler {
|
|
|
146
146
|
maxTTL: this.#maxTTL,
|
|
147
147
|
...this.#meta
|
|
148
148
|
})
|
|
149
|
-
|
|
149
|
+
// revalidate === false means "cache forever" in Next.js (SSG/force-static pages).
|
|
150
|
+
// Use maxTTL as the expiration in that case.
|
|
151
|
+
const expire = revalidate === false ? this.#maxTTL : Math.min(revalidate, this.#maxTTL)
|
|
150
152
|
|
|
151
153
|
if (expire < 1) {
|
|
152
154
|
return
|
package/lib/capability.js
CHANGED
|
@@ -400,6 +400,10 @@ export class NextCapability extends BaseCapability {
|
|
|
400
400
|
} else if (pltNextModifications.componentsCache) {
|
|
401
401
|
nextConfig.cacheHandler = getCacheHandlerPath('null-isr')
|
|
402
402
|
nextConfig.cacheHandlers.default = getCacheHandlerPath(`${pltNextModifications.componentsCache}-components`)
|
|
403
|
+
|
|
404
|
+
if (pltNextModifications.remoteComponentsCache) {
|
|
405
|
+
nextConfig.cacheHandlers.remote = getCacheHandlerPath(`${pltNextModifications.remoteComponentsCache}-components-remote`)
|
|
406
|
+
}
|
|
403
407
|
}
|
|
404
408
|
}
|
|
405
409
|
|
|
@@ -501,8 +505,24 @@ export class NextCapability extends BaseCapability {
|
|
|
501
505
|
const requiredServerFilesPath = resolvePath(distDir, 'required-server-files.json')
|
|
502
506
|
const requiredServerFiles = JSON.parse(await readFile(requiredServerFilesPath, 'utf-8'))
|
|
503
507
|
|
|
508
|
+
let modified = false
|
|
509
|
+
|
|
504
510
|
if (requiredServerFiles.config.cacheHandler) {
|
|
505
511
|
requiredServerFiles.config.cacheHandler = resolvePath(distDir, requiredServerFiles.config.cacheHandler)
|
|
512
|
+
modified = true
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (requiredServerFiles.config.cacheHandlers?.default) {
|
|
516
|
+
requiredServerFiles.config.cacheHandlers.default = resolvePath(distDir, requiredServerFiles.config.cacheHandlers.default)
|
|
517
|
+
modified = true
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (requiredServerFiles.config.cacheHandlers?.remote) {
|
|
521
|
+
requiredServerFiles.config.cacheHandlers.remote = resolvePath(distDir, requiredServerFiles.config.cacheHandlers.remote)
|
|
522
|
+
modified = true
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (modified) {
|
|
506
526
|
await writeFile(requiredServerFilesPath, JSON.stringify(requiredServerFiles, null, 2))
|
|
507
527
|
}
|
|
508
528
|
}
|
package/lib/schema.js
CHANGED
|
@@ -53,6 +53,29 @@ export const cache = {
|
|
|
53
53
|
type: 'string'
|
|
54
54
|
}
|
|
55
55
|
]
|
|
56
|
+
},
|
|
57
|
+
remote: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
url: {
|
|
61
|
+
type: 'string'
|
|
62
|
+
},
|
|
63
|
+
prefix: {
|
|
64
|
+
type: 'string'
|
|
65
|
+
},
|
|
66
|
+
maxTTL: {
|
|
67
|
+
anyOf: [
|
|
68
|
+
{
|
|
69
|
+
type: 'number',
|
|
70
|
+
minimum: 0
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: 'string'
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
additionalProperties: false
|
|
56
79
|
}
|
|
57
80
|
},
|
|
58
81
|
required: ['adapter', 'url'],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/next",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.51.0",
|
|
4
4
|
"description": "Platformatic Next.js Capability",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"light-my-request": "^6.0.0",
|
|
26
26
|
"msgpackr": "^1.11.2",
|
|
27
27
|
"semver": "^7.6.3",
|
|
28
|
-
"@platformatic/basic": "3.
|
|
29
|
-
"@platformatic/foundation": "3.
|
|
28
|
+
"@platformatic/basic": "3.51.0",
|
|
29
|
+
"@platformatic/foundation": "3.51.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@fastify/reply-from": "^12.0.0",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"next": "^16.1.0",
|
|
44
44
|
"typescript": "^5.5.4",
|
|
45
45
|
"ws": "^8.18.0",
|
|
46
|
-
"@platformatic/gateway": "3.
|
|
47
|
-
"@platformatic/service": "3.
|
|
46
|
+
"@platformatic/gateway": "3.51.0",
|
|
47
|
+
"@platformatic/service": "3.51.0"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=22.19.0"
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/next/3.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/next/3.51.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Next.js Config",
|
|
5
5
|
"type": "object",
|
|
@@ -393,6 +393,9 @@
|
|
|
393
393
|
"preferLocalCommands": {
|
|
394
394
|
"type": "boolean",
|
|
395
395
|
"default": true
|
|
396
|
+
},
|
|
397
|
+
"processSpawner": {
|
|
398
|
+
"type": "string"
|
|
396
399
|
}
|
|
397
400
|
},
|
|
398
401
|
"additionalProperties": false,
|
|
@@ -2682,6 +2685,29 @@
|
|
|
2682
2685
|
"type": "string"
|
|
2683
2686
|
}
|
|
2684
2687
|
]
|
|
2688
|
+
},
|
|
2689
|
+
"remote": {
|
|
2690
|
+
"type": "object",
|
|
2691
|
+
"properties": {
|
|
2692
|
+
"url": {
|
|
2693
|
+
"type": "string"
|
|
2694
|
+
},
|
|
2695
|
+
"prefix": {
|
|
2696
|
+
"type": "string"
|
|
2697
|
+
},
|
|
2698
|
+
"maxTTL": {
|
|
2699
|
+
"anyOf": [
|
|
2700
|
+
{
|
|
2701
|
+
"type": "number",
|
|
2702
|
+
"minimum": 0
|
|
2703
|
+
},
|
|
2704
|
+
{
|
|
2705
|
+
"type": "string"
|
|
2706
|
+
}
|
|
2707
|
+
]
|
|
2708
|
+
}
|
|
2709
|
+
},
|
|
2710
|
+
"additionalProperties": false
|
|
2685
2711
|
}
|
|
2686
2712
|
},
|
|
2687
2713
|
"required": [
|