@akinon/next 2.0.0-beta.11 → 2.0.0-beta.13
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 +286 -27
- package/api/auth.ts +99 -77
- package/api/cache.ts +41 -5
- package/api/client.ts +3 -3
- package/api/form.ts +85 -0
- package/api/image-proxy.ts +75 -0
- package/api/product-categories.ts +53 -0
- package/api/similar-product-list.ts +63 -0
- package/api/similar-products.ts +111 -0
- package/api/virtual-try-on.ts +382 -0
- package/bin/pz-generate-routes.js +105 -0
- package/bin/pz-prebuild.js +1 -1
- package/bin/pz-predev.js +1 -0
- package/components/accordion.tsx +21 -6
- package/components/button.tsx +1 -1
- package/components/file-input.tsx +65 -3
- package/components/input.tsx +2 -2
- package/components/modal.tsx +32 -16
- package/components/plugin-module.tsx +61 -3
- package/components/select.tsx +2 -2
- package/components/selected-payment-option-view.tsx +21 -0
- package/data/client/checkout.ts +130 -74
- package/data/server/category.ts +11 -9
- package/data/server/flatpage.ts +4 -1
- package/data/server/form.ts +4 -1
- package/data/server/landingpage.ts +4 -1
- package/data/server/list.ts +5 -4
- package/data/server/menu.ts +4 -1
- package/data/server/product.ts +97 -52
- package/data/server/seo.ts +4 -1
- package/data/server/special-page.ts +5 -4
- package/data/server/widget.ts +4 -1
- package/data/urls.ts +3 -2
- package/hocs/client/with-segment-defaults.tsx +2 -2
- package/hocs/server/with-segment-defaults.tsx +65 -20
- package/hooks/index.ts +1 -0
- package/hooks/use-loyalty-availability.ts +21 -0
- package/hooks/use-payment-options.ts +2 -1
- package/hooks/use-pz-params.ts +37 -0
- package/instrumentation/index.ts +0 -1
- package/instrumentation/node.ts +2 -20
- package/jest.config.js +7 -1
- package/lib/cache-handler.mjs +527 -15
- package/lib/cache.ts +260 -31
- package/localization/provider.tsx +2 -5
- package/middlewares/checkout-provider.ts +1 -1
- package/middlewares/complete-gpay.ts +33 -26
- package/middlewares/complete-masterpass.ts +34 -26
- package/middlewares/complete-wallet.ts +183 -0
- package/middlewares/default.ts +346 -235
- package/middlewares/index.ts +8 -2
- package/middlewares/locale.ts +0 -1
- package/middlewares/masterpass-rest-callback.ts +220 -0
- package/middlewares/pretty-url.ts +21 -8
- package/middlewares/redirection-payment.ts +33 -26
- package/middlewares/saved-card-redirection.ts +34 -26
- package/middlewares/three-d-redirection.ts +33 -26
- package/middlewares/url-redirection.ts +9 -15
- package/middlewares/wallet-complete-redirection.ts +207 -0
- package/package.json +20 -11
- package/plugins.d.ts +19 -4
- package/plugins.js +9 -1
- package/redux/actions.ts +47 -0
- package/redux/middlewares/checkout.ts +20 -8
- package/redux/middlewares/index.ts +12 -10
- package/redux/middlewares/pre-order/address.ts +1 -1
- package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/data-source-shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/delivery-option.ts +1 -1
- package/redux/middlewares/pre-order/index.ts +3 -1
- package/redux/middlewares/pre-order/installment-option.ts +2 -1
- package/redux/middlewares/pre-order/payment-option-reset.ts +37 -0
- package/redux/middlewares/pre-order/payment-option.ts +1 -1
- package/redux/middlewares/pre-order/pre-order-validation.ts +4 -3
- package/redux/middlewares/pre-order/redirection.ts +2 -2
- package/redux/middlewares/pre-order/set-pre-order.ts +2 -2
- package/redux/middlewares/pre-order/shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/shipping-step.ts +1 -1
- package/redux/reducers/checkout.ts +9 -1
- package/redux/reducers/index.ts +5 -1
- package/sentry/index.ts +54 -17
- package/types/commerce/checkout.ts +11 -1
- package/types/index.ts +96 -6
- package/types/next-auth.d.ts +2 -2
- package/utils/app-fetch.ts +2 -2
- package/utils/generate-commerce-search-params.ts +3 -2
- package/utils/get-checkout-path.ts +3 -0
- package/utils/index.ts +38 -11
- package/utils/override-middleware.ts +1 -0
- package/utils/pz-segments.ts +92 -0
- package/utils/redirect-ignore.ts +35 -0
- package/utils/redirect.ts +9 -3
- package/with-pz-config.js +10 -4
package/lib/cache-handler.mjs
CHANGED
|
@@ -1,32 +1,544 @@
|
|
|
1
1
|
import { CacheHandler } from '@neshca/cache-handler';
|
|
2
2
|
import createLruHandler from '@neshca/cache-handler/local-lru';
|
|
3
|
-
import createRedisHandler from '@neshca/cache-handler/redis-
|
|
3
|
+
import createRedisHandler from '@neshca/cache-handler/redis-strings';
|
|
4
4
|
import { createClient } from 'redis';
|
|
5
5
|
|
|
6
|
+
let zstd;
|
|
7
|
+
|
|
8
|
+
(async () => {
|
|
9
|
+
try {
|
|
10
|
+
const { compress, decompress } = await import('@mongodb-js/zstd');
|
|
11
|
+
zstd = { compress, decompress, type: 'native' };
|
|
12
|
+
} catch (_) {
|
|
13
|
+
zstd = false;
|
|
14
|
+
}
|
|
15
|
+
})();
|
|
16
|
+
|
|
17
|
+
const getZstd = () => {
|
|
18
|
+
return zstd;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const compressValue = async (value) => {
|
|
22
|
+
try {
|
|
23
|
+
if (value && typeof value === 'object' && value.value !== undefined) {
|
|
24
|
+
const nestedValue = value.value;
|
|
25
|
+
const serializedNestedValue =
|
|
26
|
+
typeof nestedValue === 'string'
|
|
27
|
+
? nestedValue
|
|
28
|
+
: JSON.stringify(nestedValue);
|
|
29
|
+
const originalSize = Buffer.byteLength(serializedNestedValue, 'utf8');
|
|
30
|
+
|
|
31
|
+
if (originalSize < 1024) {
|
|
32
|
+
const result = {
|
|
33
|
+
...value,
|
|
34
|
+
tags: Array.isArray(value.tags) ? value.tags : []
|
|
35
|
+
};
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const zstdLib = getZstd();
|
|
40
|
+
let compressed;
|
|
41
|
+
|
|
42
|
+
if (zstdLib && zstdLib !== false) {
|
|
43
|
+
const inputBuffer = Buffer.from(serializedNestedValue, 'utf8');
|
|
44
|
+
|
|
45
|
+
if (
|
|
46
|
+
typeof zstdLib.compress === 'function' &&
|
|
47
|
+
zstdLib.compress.constructor.name === 'AsyncFunction'
|
|
48
|
+
) {
|
|
49
|
+
compressed = await zstdLib.compress(inputBuffer, 3);
|
|
50
|
+
} else {
|
|
51
|
+
compressed = zstdLib.compress(inputBuffer, 3);
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
return {
|
|
55
|
+
...value,
|
|
56
|
+
tags: Array.isArray(value.tags) ? value.tags : []
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const compressedBase64 = Buffer.from(compressed).toString('base64');
|
|
61
|
+
|
|
62
|
+
const result = {
|
|
63
|
+
...value,
|
|
64
|
+
tags: Array.isArray(value.tags) ? value.tags : [],
|
|
65
|
+
lifespan: {
|
|
66
|
+
...value.lifespan,
|
|
67
|
+
expireAge: value.lifespan?.revalidate || value.lifespan?.expireAge,
|
|
68
|
+
expireAt:
|
|
69
|
+
value.lifespan?.lastModifiedAt && value.lifespan?.revalidate
|
|
70
|
+
? value.lifespan.lastModifiedAt + value.lifespan.revalidate
|
|
71
|
+
: value.lifespan?.expireAt
|
|
72
|
+
},
|
|
73
|
+
value: {
|
|
74
|
+
__compressed: true,
|
|
75
|
+
__method: 'zstd',
|
|
76
|
+
__originalSize: originalSize,
|
|
77
|
+
__compressedSize: compressed.length,
|
|
78
|
+
__data: compressedBase64
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const serializedValue =
|
|
86
|
+
typeof value === 'string' ? value : JSON.stringify(value);
|
|
87
|
+
const originalSize = Buffer.byteLength(serializedValue, 'utf8');
|
|
88
|
+
|
|
89
|
+
if (originalSize < 1024) {
|
|
90
|
+
if (
|
|
91
|
+
value &&
|
|
92
|
+
typeof value === 'object' &&
|
|
93
|
+
value.lastModified === undefined &&
|
|
94
|
+
value.lifespan === undefined &&
|
|
95
|
+
value.value === undefined
|
|
96
|
+
) {
|
|
97
|
+
return {
|
|
98
|
+
...value,
|
|
99
|
+
tags: value.tags || [],
|
|
100
|
+
lastModified: Date.now(),
|
|
101
|
+
lifespan: {
|
|
102
|
+
expireAt: Math.floor(Date.now() / 1000) + 3600
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (
|
|
107
|
+
value &&
|
|
108
|
+
typeof value === 'object' &&
|
|
109
|
+
value.lifespan &&
|
|
110
|
+
value.lifespan.revalidate
|
|
111
|
+
) {
|
|
112
|
+
return {
|
|
113
|
+
...value,
|
|
114
|
+
lifespan: {
|
|
115
|
+
...value.lifespan,
|
|
116
|
+
expireAge: value.lifespan.revalidate,
|
|
117
|
+
expireAt:
|
|
118
|
+
value.lifespan.lastModifiedAt && value.lifespan.revalidate
|
|
119
|
+
? value.lifespan.lastModifiedAt + value.lifespan.revalidate
|
|
120
|
+
: value.lifespan.expireAt
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const zstdLib = getZstd();
|
|
128
|
+
let compressed;
|
|
129
|
+
|
|
130
|
+
if (zstdLib && zstdLib !== false) {
|
|
131
|
+
const inputBuffer = Buffer.from(serializedValue, 'utf8');
|
|
132
|
+
|
|
133
|
+
if (
|
|
134
|
+
typeof zstdLib.compress === 'function' &&
|
|
135
|
+
zstdLib.compress.constructor.name === 'AsyncFunction'
|
|
136
|
+
) {
|
|
137
|
+
compressed = await zstdLib.compress(inputBuffer, 3);
|
|
138
|
+
} else {
|
|
139
|
+
compressed = zstdLib.compress(inputBuffer, 3);
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
if (
|
|
143
|
+
value &&
|
|
144
|
+
typeof value === 'object' &&
|
|
145
|
+
value.lastModified === undefined &&
|
|
146
|
+
value.lifespan === undefined &&
|
|
147
|
+
value.value === undefined
|
|
148
|
+
) {
|
|
149
|
+
return {
|
|
150
|
+
...value,
|
|
151
|
+
tags: value.tags || [],
|
|
152
|
+
lastModified: Date.now(),
|
|
153
|
+
lifespan: {
|
|
154
|
+
expireAt: Math.floor(Date.now() / 1000) + 3600
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const compressedBase64 = Buffer.from(compressed).toString('base64');
|
|
162
|
+
|
|
163
|
+
const compressedResult = {
|
|
164
|
+
__compressed: true,
|
|
165
|
+
__method: 'zstd',
|
|
166
|
+
__originalSize: originalSize,
|
|
167
|
+
__compressedSize: compressed.length,
|
|
168
|
+
__data: compressedBase64,
|
|
169
|
+
tags: [],
|
|
170
|
+
lastModified: Date.now(),
|
|
171
|
+
lifespan: { expireAt: Math.floor(Date.now() / 1000) + 3600 }
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
return compressedResult;
|
|
175
|
+
} catch (_) {
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const decompressValue = async (compressedData) => {
|
|
181
|
+
try {
|
|
182
|
+
if (
|
|
183
|
+
compressedData &&
|
|
184
|
+
typeof compressedData === 'object' &&
|
|
185
|
+
compressedData.value &&
|
|
186
|
+
typeof compressedData.value === 'object' &&
|
|
187
|
+
compressedData.value.__compressed
|
|
188
|
+
) {
|
|
189
|
+
const compressedNestedValue = compressedData.value;
|
|
190
|
+
const compressedBuffer = Buffer.from(
|
|
191
|
+
compressedNestedValue.__data,
|
|
192
|
+
'base64'
|
|
193
|
+
);
|
|
194
|
+
let decompressed;
|
|
195
|
+
|
|
196
|
+
if (compressedNestedValue.__method === 'zstd') {
|
|
197
|
+
const zstdLib = getZstd();
|
|
198
|
+
if (zstdLib && zstdLib !== false) {
|
|
199
|
+
if (
|
|
200
|
+
typeof zstdLib.decompress === 'function' &&
|
|
201
|
+
zstdLib.decompress.constructor.name === 'AsyncFunction'
|
|
202
|
+
) {
|
|
203
|
+
const decompressedBuffer = await zstdLib.decompress(
|
|
204
|
+
compressedBuffer
|
|
205
|
+
);
|
|
206
|
+
decompressed = decompressedBuffer.toString('utf8');
|
|
207
|
+
} else {
|
|
208
|
+
decompressed = zstdLib
|
|
209
|
+
.decompress(compressedBuffer)
|
|
210
|
+
.toString('utf8');
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
throw new Error('zstd not available for decompression');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
...compressedData,
|
|
219
|
+
value: JSON.parse(decompressed)
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (
|
|
224
|
+
compressedData &&
|
|
225
|
+
typeof compressedData === 'object' &&
|
|
226
|
+
compressedData.__compressed
|
|
227
|
+
) {
|
|
228
|
+
const compressedBuffer = Buffer.from(compressedData.__data, 'base64');
|
|
229
|
+
let decompressed;
|
|
230
|
+
|
|
231
|
+
if (compressedData.__method === 'zstd') {
|
|
232
|
+
const zstdLib = getZstd();
|
|
233
|
+
if (zstdLib && zstdLib !== false) {
|
|
234
|
+
if (
|
|
235
|
+
typeof zstdLib.decompress === 'function' &&
|
|
236
|
+
zstdLib.decompress.constructor.name === 'AsyncFunction'
|
|
237
|
+
) {
|
|
238
|
+
const decompressedBuffer = await zstdLib.decompress(
|
|
239
|
+
compressedBuffer
|
|
240
|
+
);
|
|
241
|
+
decompressed = decompressedBuffer.toString('utf8');
|
|
242
|
+
} else {
|
|
243
|
+
decompressed = zstdLib
|
|
244
|
+
.decompress(compressedBuffer)
|
|
245
|
+
.toString('utf8');
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
throw new Error('zstd not available for decompression');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return JSON.parse(decompressed);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return compressedData;
|
|
256
|
+
} catch (error) {
|
|
257
|
+
return compressedData;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const CACHE_CONFIG = {
|
|
262
|
+
lru: {
|
|
263
|
+
maxItemCount: 2000
|
|
264
|
+
},
|
|
265
|
+
redis: {
|
|
266
|
+
timeoutMs: 5000,
|
|
267
|
+
reconnectStrategy: {
|
|
268
|
+
maxRetries: 3,
|
|
269
|
+
retryDelay: (retries) => Math.min(retries * 100, 3000)
|
|
270
|
+
},
|
|
271
|
+
connectTimeout: 500
|
|
272
|
+
},
|
|
273
|
+
host: process.env.CACHE_HOST || 'localhost',
|
|
274
|
+
port: process.env.CACHE_PORT || '6379',
|
|
275
|
+
bucket: process.env.CACHE_BUCKET ?? '0',
|
|
276
|
+
version: process.env.ACC_APP_VERSION || ''
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const globalForRedis = global;
|
|
280
|
+
if (!globalForRedis.redisClient) {
|
|
281
|
+
globalForRedis.redisClient = null;
|
|
282
|
+
globalForRedis.isConnecting = false;
|
|
283
|
+
globalForRedis.hasLoggedConnectionError = false;
|
|
284
|
+
globalForRedis.connectionAttempts = 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function getRedisClient() {
|
|
288
|
+
if (globalForRedis.redisClient?.isReady) {
|
|
289
|
+
return globalForRedis.redisClient;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (globalForRedis.isConnecting) {
|
|
293
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
294
|
+
return getRedisClient();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
globalForRedis.isConnecting = true;
|
|
298
|
+
globalForRedis.connectionAttempts++;
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
const redisUrl = `redis://${CACHE_CONFIG.host}:${CACHE_CONFIG.port}/${CACHE_CONFIG.bucket}`;
|
|
302
|
+
|
|
303
|
+
const redisClient = createClient({
|
|
304
|
+
url: redisUrl,
|
|
305
|
+
socket: {
|
|
306
|
+
reconnectStrategy: (retries) => {
|
|
307
|
+
if (retries > CACHE_CONFIG.redis.reconnectStrategy.maxRetries) {
|
|
308
|
+
if (!globalForRedis.hasLoggedConnectionError) {
|
|
309
|
+
console.warn(
|
|
310
|
+
'[Cache Handler] Redis is not available, falling back to local cache only'
|
|
311
|
+
);
|
|
312
|
+
globalForRedis.hasLoggedConnectionError = true;
|
|
313
|
+
}
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
return CACHE_CONFIG.redis.reconnectStrategy.retryDelay(retries);
|
|
317
|
+
},
|
|
318
|
+
connectTimeout: CACHE_CONFIG.redis.connectTimeout
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
redisClient.on('error', (error) => {
|
|
323
|
+
if (!globalForRedis.hasLoggedConnectionError) {
|
|
324
|
+
if (error.code === 'ECONNREFUSED') {
|
|
325
|
+
console.warn(
|
|
326
|
+
'[Cache Handler] Redis connection refused. Is Redis running? Falling back to local cache.'
|
|
327
|
+
);
|
|
328
|
+
} else {
|
|
329
|
+
console.error('[Cache Handler] Redis client error:', error.message);
|
|
330
|
+
}
|
|
331
|
+
globalForRedis.hasLoggedConnectionError = true;
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
redisClient.on('connect', () => {
|
|
336
|
+
globalForRedis.hasLoggedConnectionError = false;
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
redisClient.on('ready', () => {
|
|
340
|
+
globalForRedis.hasLoggedConnectionError = false;
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
await redisClient.connect();
|
|
344
|
+
globalForRedis.redisClient = redisClient;
|
|
345
|
+
return redisClient;
|
|
346
|
+
} catch (error) {
|
|
347
|
+
if (!globalForRedis.hasLoggedConnectionError) {
|
|
348
|
+
globalForRedis.hasLoggedConnectionError = true;
|
|
349
|
+
}
|
|
350
|
+
globalForRedis.redisClient = null;
|
|
351
|
+
throw error;
|
|
352
|
+
} finally {
|
|
353
|
+
globalForRedis.isConnecting = false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
6
357
|
CacheHandler.onCreation(async () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
358
|
+
let client;
|
|
359
|
+
try {
|
|
360
|
+
client = await getRedisClient();
|
|
361
|
+
} catch (error) {
|
|
362
|
+
return {
|
|
363
|
+
handlers: [createLruHandler(CACHE_CONFIG.lru)]
|
|
364
|
+
};
|
|
365
|
+
}
|
|
10
366
|
|
|
11
|
-
const
|
|
12
|
-
|
|
367
|
+
const redisHandler = createRedisHandler({
|
|
368
|
+
client,
|
|
369
|
+
timeoutMs: CACHE_CONFIG.redis.timeoutMs,
|
|
370
|
+
keyExpirationStrategy: 'EXPIREAT'
|
|
13
371
|
});
|
|
14
372
|
|
|
15
|
-
|
|
16
|
-
console.error('Redis client error', { redisUrl, error });
|
|
17
|
-
});
|
|
373
|
+
const localHandler = createLruHandler(CACHE_CONFIG.lru);
|
|
18
374
|
|
|
19
|
-
|
|
375
|
+
const CACHE_VERSION = 'v2';
|
|
376
|
+
const versionPrefix = `${CACHE_VERSION}_`;
|
|
20
377
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
378
|
+
const versionKeyString = (key) => `${versionPrefix}${key}`;
|
|
379
|
+
const versionKeyObject = (key) => ({
|
|
380
|
+
...key,
|
|
381
|
+
key: `${versionPrefix}${key.key}`
|
|
24
382
|
});
|
|
25
383
|
|
|
26
|
-
|
|
384
|
+
const versionKey = (key) => {
|
|
385
|
+
return typeof key === 'string'
|
|
386
|
+
? versionKeyString(key)
|
|
387
|
+
: versionKeyObject(key);
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const customHandler = {
|
|
391
|
+
name: 'custom-local-then-redis',
|
|
392
|
+
get: async (key, context) => {
|
|
393
|
+
const vKey = versionKey(key);
|
|
394
|
+
|
|
395
|
+
const localResult = await localHandler.get(vKey, context);
|
|
396
|
+
|
|
397
|
+
if (localResult) {
|
|
398
|
+
if (
|
|
399
|
+
localResult &&
|
|
400
|
+
typeof localResult === 'object' &&
|
|
401
|
+
(localResult.__compressed ||
|
|
402
|
+
(localResult.value && localResult.value.__compressed) ||
|
|
403
|
+
localResult.compressed !== undefined)
|
|
404
|
+
) {
|
|
405
|
+
try {
|
|
406
|
+
const decompressed = await decompressValue(localResult);
|
|
407
|
+
return typeof decompressed === 'string'
|
|
408
|
+
? JSON.parse(decompressed)
|
|
409
|
+
: decompressed;
|
|
410
|
+
} catch (_) {
|
|
411
|
+
return localResult;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return localResult;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
try {
|
|
419
|
+
const redisResult = await redisHandler.get(vKey, context);
|
|
420
|
+
|
|
421
|
+
if (redisResult) {
|
|
422
|
+
let finalResult = redisResult;
|
|
423
|
+
|
|
424
|
+
if (typeof redisResult === 'string') {
|
|
425
|
+
try {
|
|
426
|
+
finalResult = JSON.parse(redisResult);
|
|
427
|
+
} catch (parseError) {
|
|
428
|
+
finalResult = redisResult;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (
|
|
433
|
+
finalResult &&
|
|
434
|
+
typeof finalResult === 'object' &&
|
|
435
|
+
(finalResult.__compressed ||
|
|
436
|
+
(finalResult.value && finalResult.value.__compressed) ||
|
|
437
|
+
finalResult.compressed !== undefined)
|
|
438
|
+
) {
|
|
439
|
+
try {
|
|
440
|
+
const decompressed = await decompressValue(finalResult);
|
|
441
|
+
finalResult =
|
|
442
|
+
typeof decompressed === 'string'
|
|
443
|
+
? JSON.parse(decompressed)
|
|
444
|
+
: decompressed;
|
|
445
|
+
} catch (_) {
|
|
446
|
+
return finalResult;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
try {
|
|
451
|
+
await localHandler.set(vKey, finalResult, context);
|
|
452
|
+
} catch (_) {
|
|
453
|
+
return finalResult;
|
|
454
|
+
}
|
|
455
|
+
return finalResult;
|
|
456
|
+
}
|
|
457
|
+
} catch (_) {
|
|
458
|
+
return undefined;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return undefined;
|
|
462
|
+
},
|
|
463
|
+
set: async (key, value, context) => {
|
|
464
|
+
const vKey = versionKey(key);
|
|
465
|
+
|
|
466
|
+
const stripTags = (val) => {
|
|
467
|
+
if (val && typeof val === 'object') {
|
|
468
|
+
const { tags, ...rest } = val;
|
|
469
|
+
return { ...rest, tags: [] };
|
|
470
|
+
}
|
|
471
|
+
return val;
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
let compressedValue;
|
|
475
|
+
let shouldUseCompressed = false;
|
|
476
|
+
|
|
477
|
+
try {
|
|
478
|
+
compressedValue = await compressValue(value);
|
|
479
|
+
|
|
480
|
+
shouldUseCompressed =
|
|
481
|
+
compressedValue !== value &&
|
|
482
|
+
(compressedValue?.__compressed ||
|
|
483
|
+
compressedValue?.value?.__compressed);
|
|
484
|
+
} catch (error) {
|
|
485
|
+
compressedValue = value;
|
|
486
|
+
shouldUseCompressed = false;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
let redisSetResult;
|
|
490
|
+
|
|
491
|
+
if (shouldUseCompressed) {
|
|
492
|
+
try {
|
|
493
|
+
await redisHandler.set(vKey, stripTags(compressedValue), context);
|
|
494
|
+
|
|
495
|
+
redisSetResult = { status: 'fulfilled' };
|
|
496
|
+
} catch (compressionError) {
|
|
497
|
+
try {
|
|
498
|
+
await redisHandler.set(vKey, stripTags(value), context);
|
|
499
|
+
|
|
500
|
+
redisSetResult = { status: 'fulfilled' };
|
|
501
|
+
} catch (fallbackError) {
|
|
502
|
+
redisSetResult = { status: 'rejected', reason: fallbackError };
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
} else {
|
|
506
|
+
try {
|
|
507
|
+
await redisHandler.set(vKey, stripTags(value), context);
|
|
508
|
+
redisSetResult = { status: 'fulfilled' };
|
|
509
|
+
} catch (error) {
|
|
510
|
+
redisSetResult = { status: 'rejected', reason: error };
|
|
511
|
+
return redisSetResult;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
let localSetResult;
|
|
516
|
+
try {
|
|
517
|
+
await localHandler.set(vKey, value, context);
|
|
518
|
+
localSetResult = { status: 'fulfilled' };
|
|
519
|
+
} catch (error) {
|
|
520
|
+
localSetResult = { status: 'rejected', reason: error };
|
|
521
|
+
}
|
|
522
|
+
return localSetResult;
|
|
523
|
+
},
|
|
524
|
+
delete: async (key, context) => {
|
|
525
|
+
const vKey = versionKey(key);
|
|
526
|
+
|
|
527
|
+
await Promise.allSettled([
|
|
528
|
+
localHandler.delete?.(vKey, context),
|
|
529
|
+
redisHandler.delete?.(vKey, context)
|
|
530
|
+
]);
|
|
531
|
+
},
|
|
532
|
+
revalidateTag: async (tags, context) => {
|
|
533
|
+
await Promise.allSettled([
|
|
534
|
+
localHandler.revalidateTag?.(tags, context),
|
|
535
|
+
redisHandler.revalidateTag?.(tags, context)
|
|
536
|
+
]);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
27
539
|
|
|
28
540
|
return {
|
|
29
|
-
handlers: [
|
|
541
|
+
handlers: [customHandler]
|
|
30
542
|
};
|
|
31
543
|
});
|
|
32
544
|
|