@akinon/next 1.94.0 → 1.95.0-snapshot-ZERO-3586-20250901132537
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/CHANGELOG.md +1330 -49
- package/__tests__/next-config.test.ts +1 -10
- package/__tests__/redirect.test.ts +319 -0
- package/api/cache.ts +41 -5
- package/api/image-proxy.ts +75 -0
- package/api/similar-product-list.ts +84 -0
- package/api/similar-products.ts +120 -0
- package/components/accordion.tsx +20 -5
- package/components/file-input.tsx +65 -3
- package/components/input.tsx +2 -0
- package/components/link.tsx +16 -12
- package/components/modal.tsx +32 -16
- package/components/plugin-module.tsx +30 -3
- package/data/client/checkout.ts +5 -4
- package/data/server/basket.ts +72 -0
- package/data/server/category.ts +52 -30
- package/data/server/flatpage.ts +20 -13
- package/data/server/form.ts +4 -1
- package/data/server/landingpage.ts +20 -13
- package/data/server/list.ts +25 -14
- package/data/server/menu.ts +4 -1
- package/data/server/product.ts +68 -40
- package/data/server/seo.ts +4 -1
- package/data/server/special-page.ts +18 -13
- package/data/server/widget.ts +4 -1
- package/data/urls.ts +5 -1
- package/hocs/server/with-segment-defaults.tsx +5 -2
- package/hooks/use-localization.ts +2 -3
- package/jest.config.js +7 -1
- package/lib/cache-handler.mjs +359 -85
- package/lib/cache.ts +254 -25
- package/middlewares/checkout-provider.ts +1 -1
- package/middlewares/complete-gpay.ts +2 -1
- package/middlewares/complete-masterpass.ts +2 -1
- package/middlewares/default.ts +50 -13
- package/middlewares/locale.ts +9 -1
- package/middlewares/pretty-url.ts +2 -1
- package/middlewares/redirection-payment.ts +2 -1
- package/middlewares/saved-card-redirection.ts +2 -1
- package/middlewares/three-d-redirection.ts +2 -1
- package/middlewares/url-redirection.ts +9 -15
- package/package.json +4 -3
- package/plugins.d.ts +8 -0
- package/plugins.js +3 -1
- package/redux/middlewares/checkout.ts +5 -1
- package/sentry/index.ts +54 -17
- package/types/commerce/order.ts +1 -0
- package/types/index.ts +43 -1
- package/utils/app-fetch.ts +7 -2
- package/utils/index.ts +34 -10
- package/utils/redirect-ignore.ts +35 -0
- package/utils/redirect.ts +31 -6
- package/with-pz-config.js +2 -5
package/lib/cache-handler.mjs
CHANGED
|
@@ -2,8 +2,236 @@ import { CacheHandler } from '@neshca/cache-handler';
|
|
|
2
2
|
import createLruHandler from '@neshca/cache-handler/local-lru';
|
|
3
3
|
import createRedisHandler from '@neshca/cache-handler/redis-strings';
|
|
4
4
|
import { createClient } from 'redis';
|
|
5
|
+
import * as zstdWasm from '@bokuweb/zstd-wasm';
|
|
6
|
+
|
|
7
|
+
let zstd;
|
|
8
|
+
|
|
9
|
+
(async () => {
|
|
10
|
+
try {
|
|
11
|
+
await zstdWasm.init();
|
|
12
|
+
zstd = zstdWasm;
|
|
13
|
+
} catch (error) {
|
|
14
|
+
zstd = false;
|
|
15
|
+
}
|
|
16
|
+
})();
|
|
17
|
+
|
|
18
|
+
const getZstd = () => {
|
|
19
|
+
return zstd;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const compressValue = async (value) => {
|
|
23
|
+
try {
|
|
24
|
+
if (value && typeof value === 'object' && value.value !== undefined) {
|
|
25
|
+
const nestedValue = value.value;
|
|
26
|
+
const serializedNestedValue =
|
|
27
|
+
typeof nestedValue === 'string'
|
|
28
|
+
? nestedValue
|
|
29
|
+
: JSON.stringify(nestedValue);
|
|
30
|
+
const originalSize = Buffer.byteLength(serializedNestedValue, 'utf8');
|
|
31
|
+
|
|
32
|
+
if (originalSize < 1024) {
|
|
33
|
+
const result = {
|
|
34
|
+
...value,
|
|
35
|
+
tags: Array.isArray(value.tags) ? value.tags : []
|
|
36
|
+
};
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const zstdLib = getZstd();
|
|
41
|
+
let compressed;
|
|
42
|
+
|
|
43
|
+
if (zstdLib && zstdLib !== false) {
|
|
44
|
+
compressed = zstdLib.compress(
|
|
45
|
+
Buffer.from(serializedNestedValue, 'utf8'),
|
|
46
|
+
3
|
|
47
|
+
);
|
|
48
|
+
} else {
|
|
49
|
+
return {
|
|
50
|
+
...value,
|
|
51
|
+
tags: Array.isArray(value.tags) ? value.tags : []
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const compressedBase64 = Buffer.from(compressed).toString('base64');
|
|
56
|
+
|
|
57
|
+
const result = {
|
|
58
|
+
...value,
|
|
59
|
+
tags: Array.isArray(value.tags) ? value.tags : [],
|
|
60
|
+
lifespan: {
|
|
61
|
+
...value.lifespan,
|
|
62
|
+
expireAge: value.lifespan?.revalidate || value.lifespan?.expireAge,
|
|
63
|
+
expireAt:
|
|
64
|
+
value.lifespan?.lastModifiedAt && value.lifespan?.revalidate
|
|
65
|
+
? value.lifespan.lastModifiedAt + value.lifespan.revalidate
|
|
66
|
+
: value.lifespan?.expireAt
|
|
67
|
+
},
|
|
68
|
+
value: {
|
|
69
|
+
__compressed: true,
|
|
70
|
+
__method: 'zstd',
|
|
71
|
+
__originalSize: originalSize,
|
|
72
|
+
__compressedSize: compressed.length,
|
|
73
|
+
__data: compressedBase64
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const serializedValue =
|
|
81
|
+
typeof value === 'string' ? value : JSON.stringify(value);
|
|
82
|
+
const originalSize = Buffer.byteLength(serializedValue, 'utf8');
|
|
83
|
+
|
|
84
|
+
if (originalSize < 1024) {
|
|
85
|
+
if (
|
|
86
|
+
value &&
|
|
87
|
+
typeof value === 'object' &&
|
|
88
|
+
value.lastModified === undefined &&
|
|
89
|
+
value.lifespan === undefined &&
|
|
90
|
+
value.value === undefined
|
|
91
|
+
) {
|
|
92
|
+
return {
|
|
93
|
+
...value,
|
|
94
|
+
tags: value.tags || [],
|
|
95
|
+
lastModified: Date.now(),
|
|
96
|
+
lifespan: {
|
|
97
|
+
expireAt: Math.floor(Date.now() / 1000) + 3600
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (
|
|
102
|
+
value &&
|
|
103
|
+
typeof value === 'object' &&
|
|
104
|
+
value.lifespan &&
|
|
105
|
+
value.lifespan.revalidate
|
|
106
|
+
) {
|
|
107
|
+
return {
|
|
108
|
+
...value,
|
|
109
|
+
lifespan: {
|
|
110
|
+
...value.lifespan,
|
|
111
|
+
expireAge: value.lifespan.revalidate,
|
|
112
|
+
expireAt:
|
|
113
|
+
value.lifespan.lastModifiedAt && value.lifespan.revalidate
|
|
114
|
+
? value.lifespan.lastModifiedAt + value.lifespan.revalidate
|
|
115
|
+
: value.lifespan.expireAt
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const zstdLib = getZstd();
|
|
123
|
+
let compressed;
|
|
124
|
+
|
|
125
|
+
if (zstdLib && zstdLib !== false) {
|
|
126
|
+
compressed = zstdLib.compress(Buffer.from(serializedValue, 'utf8'), 3);
|
|
127
|
+
} else {
|
|
128
|
+
if (
|
|
129
|
+
value &&
|
|
130
|
+
typeof value === 'object' &&
|
|
131
|
+
value.lastModified === undefined &&
|
|
132
|
+
value.lifespan === undefined &&
|
|
133
|
+
value.value === undefined
|
|
134
|
+
) {
|
|
135
|
+
return {
|
|
136
|
+
...value,
|
|
137
|
+
tags: value.tags || [],
|
|
138
|
+
lastModified: Date.now(),
|
|
139
|
+
lifespan: {
|
|
140
|
+
expireAt: Math.floor(Date.now() / 1000) + 3600
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const compressedBase64 = Buffer.from(compressed).toString('base64');
|
|
148
|
+
|
|
149
|
+
const compressedResult = {
|
|
150
|
+
__compressed: true,
|
|
151
|
+
__method: 'zstd',
|
|
152
|
+
__originalSize: originalSize,
|
|
153
|
+
__compressedSize: compressed.length,
|
|
154
|
+
__data: compressedBase64,
|
|
155
|
+
tags: [],
|
|
156
|
+
lastModified: Date.now(),
|
|
157
|
+
lifespan: { expireAt: Math.floor(Date.now() / 1000) + 3600 }
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return compressedResult;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.warn(
|
|
163
|
+
'[Cache Handler] Compression failed, storing uncompressed:',
|
|
164
|
+
error.message
|
|
165
|
+
);
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const decompressValue = async (compressedData) => {
|
|
171
|
+
try {
|
|
172
|
+
if (
|
|
173
|
+
compressedData &&
|
|
174
|
+
typeof compressedData === 'object' &&
|
|
175
|
+
compressedData.value &&
|
|
176
|
+
typeof compressedData.value === 'object' &&
|
|
177
|
+
compressedData.value.__compressed
|
|
178
|
+
) {
|
|
179
|
+
const compressedNestedValue = compressedData.value;
|
|
180
|
+
const compressedBuffer = Buffer.from(
|
|
181
|
+
compressedNestedValue.__data,
|
|
182
|
+
'base64'
|
|
183
|
+
);
|
|
184
|
+
let decompressed;
|
|
185
|
+
|
|
186
|
+
if (compressedNestedValue.__method === 'zstd') {
|
|
187
|
+
const zstdLib = getZstd();
|
|
188
|
+
if (zstdLib && zstdLib !== false) {
|
|
189
|
+
decompressed = zstdLib.decompress(compressedBuffer).toString('utf8');
|
|
190
|
+
} else {
|
|
191
|
+
throw new Error('zstd not available for decompression');
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
throw new Error(
|
|
195
|
+
'gzip decompression no longer supported - please invalidate cache'
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
...compressedData,
|
|
201
|
+
value: JSON.parse(decompressed)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (
|
|
206
|
+
compressedData &&
|
|
207
|
+
typeof compressedData === 'object' &&
|
|
208
|
+
compressedData.__compressed
|
|
209
|
+
) {
|
|
210
|
+
const compressedBuffer = Buffer.from(compressedData.__data, 'base64');
|
|
211
|
+
let decompressed;
|
|
212
|
+
|
|
213
|
+
if (compressedData.__method === 'zstd') {
|
|
214
|
+
const zstdLib = getZstd();
|
|
215
|
+
if (zstdLib && zstdLib !== false) {
|
|
216
|
+
decompressed = zstdLib.decompress(compressedBuffer).toString('utf8');
|
|
217
|
+
} else {
|
|
218
|
+
throw new Error('zstd not available for decompression');
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
throw new Error(
|
|
222
|
+
'gzip decompression no longer supported - please invalidate cache'
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return JSON.parse(decompressed);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return compressedData;
|
|
230
|
+
} catch (error) {
|
|
231
|
+
return compressedData;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
5
234
|
|
|
6
|
-
// Cache configuration
|
|
7
235
|
const CACHE_CONFIG = {
|
|
8
236
|
lru: {
|
|
9
237
|
maxItemCount: 2000
|
|
@@ -22,7 +250,6 @@ const CACHE_CONFIG = {
|
|
|
22
250
|
version: process.env.ACC_APP_VERSION || ''
|
|
23
251
|
};
|
|
24
252
|
|
|
25
|
-
// Use global to persist across module reloads in development
|
|
26
253
|
const globalForRedis = global;
|
|
27
254
|
if (!globalForRedis.redisClient) {
|
|
28
255
|
globalForRedis.redisClient = null;
|
|
@@ -31,42 +258,22 @@ if (!globalForRedis.redisClient) {
|
|
|
31
258
|
globalForRedis.connectionAttempts = 0;
|
|
32
259
|
}
|
|
33
260
|
|
|
34
|
-
// Logging configuration
|
|
35
|
-
const debugValue = process.env.NEXT_PRIVATE_DEBUG_CACHE;
|
|
36
|
-
const debug = debugValue === 'true' || debugValue === '1';
|
|
37
|
-
|
|
38
|
-
let console_log;
|
|
39
|
-
if (debug) {
|
|
40
|
-
// eslint-disable-next-line no-console
|
|
41
|
-
console_log = (...args) => console.log('[Cache Handler]', ...args);
|
|
42
|
-
} else {
|
|
43
|
-
console_log = () => {};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
261
|
async function getRedisClient() {
|
|
47
|
-
// If client exists and is ready, return it
|
|
48
262
|
if (globalForRedis.redisClient?.isReady) {
|
|
49
|
-
console_log('Reusing existing Redis connection');
|
|
50
263
|
return globalForRedis.redisClient;
|
|
51
264
|
}
|
|
52
265
|
|
|
53
|
-
// If we're already connecting, wait a bit and retry
|
|
54
266
|
if (globalForRedis.isConnecting) {
|
|
55
267
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
56
268
|
return getRedisClient();
|
|
57
269
|
}
|
|
58
270
|
|
|
59
|
-
// Start new connection
|
|
60
271
|
globalForRedis.isConnecting = true;
|
|
61
272
|
globalForRedis.connectionAttempts++;
|
|
62
273
|
|
|
63
274
|
try {
|
|
64
275
|
const redisUrl = `redis://${CACHE_CONFIG.host}:${CACHE_CONFIG.port}/${CACHE_CONFIG.bucket}`;
|
|
65
276
|
|
|
66
|
-
if (globalForRedis.connectionAttempts === 1) {
|
|
67
|
-
console_log('Creating Redis connection:', redisUrl);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
277
|
const redisClient = createClient({
|
|
71
278
|
url: redisUrl,
|
|
72
279
|
socket: {
|
|
@@ -87,7 +294,6 @@ async function getRedisClient() {
|
|
|
87
294
|
});
|
|
88
295
|
|
|
89
296
|
redisClient.on('error', (error) => {
|
|
90
|
-
// Only log the first connection error to avoid spam
|
|
91
297
|
if (!globalForRedis.hasLoggedConnectionError) {
|
|
92
298
|
if (error.code === 'ECONNREFUSED') {
|
|
93
299
|
console.warn(
|
|
@@ -101,12 +307,10 @@ async function getRedisClient() {
|
|
|
101
307
|
});
|
|
102
308
|
|
|
103
309
|
redisClient.on('connect', () => {
|
|
104
|
-
console_log('Redis connected');
|
|
105
310
|
globalForRedis.hasLoggedConnectionError = false;
|
|
106
311
|
});
|
|
107
312
|
|
|
108
313
|
redisClient.on('ready', () => {
|
|
109
|
-
console_log('Redis ready');
|
|
110
314
|
globalForRedis.hasLoggedConnectionError = false;
|
|
111
315
|
});
|
|
112
316
|
|
|
@@ -115,16 +319,6 @@ async function getRedisClient() {
|
|
|
115
319
|
return redisClient;
|
|
116
320
|
} catch (error) {
|
|
117
321
|
if (!globalForRedis.hasLoggedConnectionError) {
|
|
118
|
-
if (error.code === 'ECONNREFUSED') {
|
|
119
|
-
console.warn(
|
|
120
|
-
'[Cache Handler] Could not connect to Redis - using local cache only'
|
|
121
|
-
);
|
|
122
|
-
} else {
|
|
123
|
-
console.error(
|
|
124
|
-
'[Cache Handler] Failed to connect to Redis:',
|
|
125
|
-
error.message
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
322
|
globalForRedis.hasLoggedConnectionError = true;
|
|
129
323
|
}
|
|
130
324
|
globalForRedis.redisClient = null;
|
|
@@ -135,13 +329,10 @@ async function getRedisClient() {
|
|
|
135
329
|
}
|
|
136
330
|
|
|
137
331
|
CacheHandler.onCreation(async () => {
|
|
138
|
-
console_log('Initializing cache handlers...');
|
|
139
|
-
|
|
140
332
|
let client;
|
|
141
333
|
try {
|
|
142
334
|
client = await getRedisClient();
|
|
143
335
|
} catch (error) {
|
|
144
|
-
// Error already logged in getRedisClient, just return local handler
|
|
145
336
|
return {
|
|
146
337
|
handlers: [createLruHandler(CACHE_CONFIG.lru)]
|
|
147
338
|
};
|
|
@@ -150,98 +341,183 @@ CacheHandler.onCreation(async () => {
|
|
|
150
341
|
const redisHandler = createRedisHandler({
|
|
151
342
|
client,
|
|
152
343
|
timeoutMs: CACHE_CONFIG.redis.timeoutMs,
|
|
153
|
-
keyExpirationStrategy: '
|
|
344
|
+
keyExpirationStrategy: 'EXPIREAT'
|
|
154
345
|
});
|
|
155
346
|
|
|
156
347
|
const localHandler = createLruHandler(CACHE_CONFIG.lru);
|
|
157
348
|
|
|
158
|
-
|
|
159
|
-
const versionPrefix =
|
|
349
|
+
const CACHE_VERSION = 'v2';
|
|
350
|
+
const versionPrefix = `${CACHE_VERSION}_`;
|
|
160
351
|
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
:
|
|
165
|
-
|
|
166
|
-
const versionKeyObject = versionPrefix
|
|
167
|
-
? (key) => ({ ...key, key: `${versionPrefix}${key.key}` })
|
|
168
|
-
: (key) => key;
|
|
352
|
+
const versionKeyString = (key) => `${versionPrefix}${key}`;
|
|
353
|
+
const versionKeyObject = (key) => ({
|
|
354
|
+
...key,
|
|
355
|
+
key: `${versionPrefix}${key.key}`
|
|
356
|
+
});
|
|
169
357
|
|
|
170
|
-
// Main version key function that routes to optimized paths
|
|
171
358
|
const versionKey = (key) => {
|
|
172
359
|
return typeof key === 'string'
|
|
173
360
|
? versionKeyString(key)
|
|
174
361
|
: versionKeyObject(key);
|
|
175
362
|
};
|
|
176
363
|
|
|
177
|
-
// Create a custom handler that checks local first, then Redis
|
|
178
364
|
const customHandler = {
|
|
179
365
|
name: 'custom-local-then-redis',
|
|
180
366
|
get: async (key, context) => {
|
|
181
367
|
const vKey = versionKey(key);
|
|
182
|
-
console_log(
|
|
183
|
-
'GET called for key:',
|
|
184
|
-
typeof vKey === 'string' ? vKey : vKey?.key
|
|
185
|
-
);
|
|
186
368
|
|
|
187
|
-
// Check local cache first
|
|
188
|
-
console_log('Checking local cache...');
|
|
189
369
|
const localResult = await localHandler.get(vKey, context);
|
|
190
370
|
|
|
191
371
|
if (localResult) {
|
|
192
|
-
|
|
372
|
+
if (
|
|
373
|
+
localResult &&
|
|
374
|
+
typeof localResult === 'object' &&
|
|
375
|
+
(localResult.__compressed ||
|
|
376
|
+
(localResult.value && localResult.value.__compressed) ||
|
|
377
|
+
localResult.compressed !== undefined)
|
|
378
|
+
) {
|
|
379
|
+
try {
|
|
380
|
+
const decompressed = await decompressValue(localResult);
|
|
381
|
+
return typeof decompressed === 'string'
|
|
382
|
+
? JSON.parse(decompressed)
|
|
383
|
+
: decompressed;
|
|
384
|
+
} catch (error) {
|
|
385
|
+
console.warn(
|
|
386
|
+
'[Cache Handler] Failed to decompress local cache value:',
|
|
387
|
+
error.message
|
|
388
|
+
);
|
|
389
|
+
return localResult;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
193
393
|
return localResult;
|
|
194
394
|
}
|
|
195
395
|
|
|
196
|
-
console_log('Not found in local, checking Redis...');
|
|
197
396
|
try {
|
|
198
397
|
const redisResult = await redisHandler.get(vKey, context);
|
|
199
398
|
|
|
200
399
|
if (redisResult) {
|
|
201
|
-
|
|
202
|
-
|
|
400
|
+
let finalResult = redisResult;
|
|
401
|
+
|
|
402
|
+
if (typeof redisResult === 'string') {
|
|
403
|
+
try {
|
|
404
|
+
finalResult = JSON.parse(redisResult);
|
|
405
|
+
} catch (parseError) {
|
|
406
|
+
finalResult = redisResult;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (
|
|
411
|
+
finalResult &&
|
|
412
|
+
typeof finalResult === 'object' &&
|
|
413
|
+
(finalResult.__compressed ||
|
|
414
|
+
(finalResult.value && finalResult.value.__compressed) ||
|
|
415
|
+
finalResult.compressed !== undefined)
|
|
416
|
+
) {
|
|
417
|
+
try {
|
|
418
|
+
const decompressed = await decompressValue(finalResult);
|
|
419
|
+
finalResult =
|
|
420
|
+
typeof decompressed === 'string'
|
|
421
|
+
? JSON.parse(decompressed)
|
|
422
|
+
: decompressed;
|
|
423
|
+
} catch (error) {
|
|
424
|
+
console.warn(
|
|
425
|
+
'[Cache Handler] Failed to decompress Redis cache value:',
|
|
426
|
+
error.message
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
203
431
|
try {
|
|
204
|
-
await localHandler.set(vKey,
|
|
205
|
-
console_log('Synced to local cache');
|
|
432
|
+
await localHandler.set(vKey, finalResult, context);
|
|
206
433
|
} catch (error) {
|
|
207
|
-
|
|
434
|
+
console.warn(
|
|
435
|
+
'[Cache Handler] Failed to sync to local:',
|
|
436
|
+
error.message
|
|
437
|
+
);
|
|
208
438
|
}
|
|
209
|
-
return
|
|
439
|
+
return finalResult;
|
|
210
440
|
}
|
|
211
441
|
} catch (error) {
|
|
212
|
-
|
|
442
|
+
console.warn('[Cache Handler] Redis error:', error.message);
|
|
213
443
|
}
|
|
214
444
|
|
|
215
|
-
console_log('Not found in any cache');
|
|
216
445
|
return undefined;
|
|
217
446
|
},
|
|
218
447
|
set: async (key, value, context) => {
|
|
219
448
|
const vKey = versionKey(key);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
449
|
+
|
|
450
|
+
let compressedValue;
|
|
451
|
+
let shouldUseCompressed = false;
|
|
452
|
+
|
|
453
|
+
try {
|
|
454
|
+
compressedValue = await compressValue(value);
|
|
455
|
+
|
|
456
|
+
shouldUseCompressed =
|
|
457
|
+
compressedValue !== value &&
|
|
458
|
+
(compressedValue?.__compressed ||
|
|
459
|
+
compressedValue?.value?.__compressed);
|
|
460
|
+
} catch (error) {
|
|
461
|
+
console.warn(
|
|
462
|
+
'[Cache Handler] Compression failed, using original value:',
|
|
463
|
+
error.message
|
|
464
|
+
);
|
|
465
|
+
compressedValue = value;
|
|
466
|
+
shouldUseCompressed = false;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
let redisSetResult;
|
|
470
|
+
|
|
471
|
+
if (shouldUseCompressed) {
|
|
472
|
+
try {
|
|
473
|
+
await redisHandler.set(vKey, compressedValue, context);
|
|
474
|
+
|
|
475
|
+
redisSetResult = { status: 'fulfilled' };
|
|
476
|
+
} catch (compressionError) {
|
|
477
|
+
try {
|
|
478
|
+
await redisHandler.set(vKey, value, context);
|
|
479
|
+
|
|
480
|
+
redisSetResult = { status: 'fulfilled' };
|
|
481
|
+
} catch (fallbackError) {
|
|
482
|
+
redisSetResult = { status: 'rejected', reason: fallbackError };
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
try {
|
|
487
|
+
await redisHandler.set(vKey, value, context);
|
|
488
|
+
redisSetResult = { status: 'fulfilled' };
|
|
489
|
+
} catch (error) {
|
|
490
|
+
redisSetResult = { status: 'rejected', reason: error };
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
let localSetResult;
|
|
495
|
+
try {
|
|
496
|
+
await localHandler.set(vKey, value, context);
|
|
497
|
+
localSetResult = { status: 'fulfilled' };
|
|
498
|
+
} catch (error) {
|
|
499
|
+
localSetResult = { status: 'rejected', reason: error };
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const results = [localSetResult, redisSetResult];
|
|
503
|
+
|
|
504
|
+
console.warn('SET Results:', {
|
|
505
|
+
local: results[0].status,
|
|
506
|
+
redis: results[1].status,
|
|
507
|
+
localError: results[0].reason?.message,
|
|
508
|
+
redisError: results[1].reason?.message,
|
|
509
|
+
compressionUsed: shouldUseCompressed
|
|
510
|
+
});
|
|
231
511
|
},
|
|
232
512
|
delete: async (key, context) => {
|
|
233
513
|
const vKey = versionKey(key);
|
|
234
|
-
|
|
235
|
-
'DELETE called for key:',
|
|
236
|
-
typeof vKey === 'string' ? vKey : vKey?.key
|
|
237
|
-
);
|
|
514
|
+
|
|
238
515
|
await Promise.allSettled([
|
|
239
516
|
localHandler.delete?.(vKey, context),
|
|
240
517
|
redisHandler.delete?.(vKey, context)
|
|
241
518
|
]);
|
|
242
519
|
},
|
|
243
520
|
revalidateTag: async (tags, context) => {
|
|
244
|
-
console_log('REVALIDATE_TAG called for tags:', tags);
|
|
245
521
|
await Promise.allSettled([
|
|
246
522
|
localHandler.revalidateTag?.(tags, context),
|
|
247
523
|
redisHandler.revalidateTag?.(tags, context)
|
|
@@ -249,8 +525,6 @@ CacheHandler.onCreation(async () => {
|
|
|
249
525
|
}
|
|
250
526
|
};
|
|
251
527
|
|
|
252
|
-
console_log('[Cache Handler] Handlers initialized successfully');
|
|
253
|
-
|
|
254
528
|
return {
|
|
255
529
|
handlers: [customHandler]
|
|
256
530
|
};
|