@akinon/next 1.93.0-snapshot-ZERO-3586-20250828143733 → 1.94.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/CHANGELOG.md +39 -1337
- package/__tests__/next-config.test.ts +10 -1
- package/api/cache.ts +5 -41
- package/components/accordion.tsx +5 -20
- package/components/file-input.tsx +3 -65
- package/components/input.tsx +0 -2
- package/components/link.tsx +12 -16
- package/components/modal.tsx +16 -32
- package/components/plugin-module.tsx +3 -30
- package/data/client/checkout.ts +4 -5
- package/data/server/category.ts +30 -52
- package/data/server/flatpage.ts +13 -20
- package/data/server/form.ts +1 -4
- package/data/server/landingpage.ts +13 -20
- package/data/server/list.ts +14 -25
- package/data/server/menu.ts +1 -4
- package/data/server/product.ts +40 -68
- package/data/server/seo.ts +1 -4
- package/data/server/special-page.ts +13 -18
- package/data/server/widget.ts +1 -4
- package/data/urls.ts +1 -5
- package/hocs/server/with-segment-defaults.tsx +2 -5
- package/hooks/use-localization.ts +3 -2
- package/jest.config.js +1 -7
- package/lib/cache-handler.mjs +26 -850
- package/lib/cache.ts +13 -432
- package/middlewares/checkout-provider.ts +1 -1
- package/middlewares/complete-gpay.ts +1 -2
- package/middlewares/complete-masterpass.ts +1 -2
- package/middlewares/default.ts +13 -50
- package/middlewares/locale.ts +1 -9
- package/middlewares/pretty-url.ts +1 -2
- package/middlewares/redirection-payment.ts +1 -2
- package/middlewares/saved-card-redirection.ts +1 -2
- package/middlewares/three-d-redirection.ts +1 -2
- package/middlewares/url-redirection.ts +15 -9
- package/package.json +3 -4
- package/plugins.d.ts +0 -8
- package/plugins.js +1 -3
- package/redux/middlewares/checkout.ts +1 -5
- package/sentry/index.ts +17 -54
- package/types/commerce/order.ts +0 -1
- package/types/index.ts +1 -43
- package/utils/app-fetch.ts +2 -7
- package/utils/index.ts +10 -34
- package/utils/redirect.ts +6 -31
- package/with-pz-config.js +5 -2
- package/__tests__/redirect.test.ts +0 -319
- package/api/image-proxy.ts +0 -75
- package/api/similar-product-list.ts +0 -84
- package/api/similar-products.ts +0 -120
- package/data/server/basket.ts +0 -72
- package/utils/redirect-ignore.ts +0 -35
package/lib/cache.ts
CHANGED
|
@@ -3,127 +3,6 @@ import { RedisClientType } from 'redis';
|
|
|
3
3
|
import Settings from 'settings';
|
|
4
4
|
import { CacheOptions } from '../types';
|
|
5
5
|
import logger from '../utils/log';
|
|
6
|
-
const CACHE_VERSION = 'v2';
|
|
7
|
-
|
|
8
|
-
const colors = {
|
|
9
|
-
red: '\x1b[31m',
|
|
10
|
-
green: '\x1b[32m',
|
|
11
|
-
yellow: '\x1b[33m',
|
|
12
|
-
blue: '\x1b[34m',
|
|
13
|
-
magenta: '\x1b[35m',
|
|
14
|
-
cyan: '\x1b[36m',
|
|
15
|
-
white: '\x1b[37m',
|
|
16
|
-
reset: '\x1b[0m',
|
|
17
|
-
bright: '\x1b[1m'
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const colorLog = (color: string, prefix: string, ...args: any[]) => {
|
|
21
|
-
// eslint-disable-next-line no-console
|
|
22
|
-
console.log(`${colors.bright}${color}${prefix}${colors.reset}`, ...args);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
colorLog(
|
|
26
|
-
colors.green,
|
|
27
|
-
'[Cache] 🚀 ',
|
|
28
|
-
'Web API compression initialized successfully at module load'
|
|
29
|
-
);
|
|
30
|
-
logger.debug('Web API compression initialized successfully at module load');
|
|
31
|
-
|
|
32
|
-
const extractUrlFromKey = (key: string): string => {
|
|
33
|
-
try {
|
|
34
|
-
const decoded = decodeURIComponent(key);
|
|
35
|
-
const urlMatch =
|
|
36
|
-
decoded.match(/https?:\/\/[^\s]+/) || decoded.match(/\/[^\s]*/);
|
|
37
|
-
return urlMatch ? urlMatch[0] : 'unknown';
|
|
38
|
-
} catch {
|
|
39
|
-
return 'unknown';
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// Web API compression for edge runtime compatibility
|
|
44
|
-
const compressData = async (data: string): Promise<Uint8Array> => {
|
|
45
|
-
if (typeof CompressionStream !== 'undefined') {
|
|
46
|
-
// Use Web API compression (edge runtime)
|
|
47
|
-
const stream = new CompressionStream('gzip');
|
|
48
|
-
const writer = stream.writable.getWriter();
|
|
49
|
-
const reader = stream.readable.getReader();
|
|
50
|
-
|
|
51
|
-
writer.write(new TextEncoder().encode(data));
|
|
52
|
-
writer.close();
|
|
53
|
-
|
|
54
|
-
const chunks: Uint8Array[] = [];
|
|
55
|
-
let done = false;
|
|
56
|
-
|
|
57
|
-
while (!done) {
|
|
58
|
-
const { value, done: readerDone } = await reader.read();
|
|
59
|
-
done = readerDone;
|
|
60
|
-
if (value) chunks.push(value);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
64
|
-
const result = new Uint8Array(totalLength);
|
|
65
|
-
let offset = 0;
|
|
66
|
-
|
|
67
|
-
for (const chunk of chunks) {
|
|
68
|
-
result.set(chunk, offset);
|
|
69
|
-
offset += chunk.length;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return result;
|
|
73
|
-
} else {
|
|
74
|
-
// Node.js fallback (server runtime)
|
|
75
|
-
const { deflate } = await import('zlib');
|
|
76
|
-
const { promisify } = await import('util');
|
|
77
|
-
const deflateAsync = promisify(deflate);
|
|
78
|
-
const inputBuffer = Buffer.from(data, 'utf8');
|
|
79
|
-
const compressed = await deflateAsync(inputBuffer);
|
|
80
|
-
return new Uint8Array(
|
|
81
|
-
compressed.buffer,
|
|
82
|
-
compressed.byteOffset,
|
|
83
|
-
compressed.byteLength
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// Web API decompression for edge runtime compatibility
|
|
89
|
-
const decompressData = async (compressed: Uint8Array): Promise<string> => {
|
|
90
|
-
if (typeof DecompressionStream !== 'undefined') {
|
|
91
|
-
// Use Web API decompression (edge runtime)
|
|
92
|
-
const stream = new DecompressionStream('gzip');
|
|
93
|
-
const writer = stream.writable.getWriter();
|
|
94
|
-
const reader = stream.readable.getReader();
|
|
95
|
-
|
|
96
|
-
writer.write(compressed);
|
|
97
|
-
writer.close();
|
|
98
|
-
|
|
99
|
-
const chunks: Uint8Array[] = [];
|
|
100
|
-
let done = false;
|
|
101
|
-
|
|
102
|
-
while (!done) {
|
|
103
|
-
const { value, done: readerDone } = await reader.read();
|
|
104
|
-
done = readerDone;
|
|
105
|
-
if (value) chunks.push(value);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
109
|
-
const result = new Uint8Array(totalLength);
|
|
110
|
-
let offset = 0;
|
|
111
|
-
|
|
112
|
-
for (const chunk of chunks) {
|
|
113
|
-
result.set(chunk, offset);
|
|
114
|
-
offset += chunk.length;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return new TextDecoder().decode(result);
|
|
118
|
-
} else {
|
|
119
|
-
// Node.js fallback (server runtime)
|
|
120
|
-
const { inflate } = await import('zlib');
|
|
121
|
-
const { promisify } = await import('util');
|
|
122
|
-
const inflateAsync = promisify(inflate);
|
|
123
|
-
const decompressed = await inflateAsync(Buffer.from(compressed));
|
|
124
|
-
return decompressed.toString('utf8');
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
6
|
|
|
128
7
|
const hashCacheKey = (object?: Record<string, string>) => {
|
|
129
8
|
if (!object) {
|
|
@@ -152,8 +31,6 @@ export const CacheKey = {
|
|
|
152
31
|
`category_${pk}_${encodeURIComponent(
|
|
153
32
|
JSON.stringify(searchParams)
|
|
154
33
|
)}${hashCacheKey(headers)}`,
|
|
155
|
-
Basket: (namespace?: string) => `basket${namespace ? `_${namespace}` : ''}`,
|
|
156
|
-
AllBaskets: () => 'all_baskets',
|
|
157
34
|
CategorySlug: (slug: string) => `category_${slug}`,
|
|
158
35
|
SpecialPage: (
|
|
159
36
|
pk: number,
|
|
@@ -181,32 +58,8 @@ export const CacheKey = {
|
|
|
181
58
|
export class Cache {
|
|
182
59
|
static PROXY_URL = `${process.env.NEXT_PUBLIC_URL}/api/cache`;
|
|
183
60
|
|
|
184
|
-
private static serializeValue(value: any): string {
|
|
185
|
-
return typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
private static validateKey(key: string): boolean {
|
|
189
|
-
return !(!key || key.trim() === '');
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
private static validateKeyValuePairs(keyValuePairs: Record<string, any>): {
|
|
193
|
-
isValid: boolean;
|
|
194
|
-
invalidKeys: string[];
|
|
195
|
-
} {
|
|
196
|
-
if (!keyValuePairs || Object.keys(keyValuePairs).length === 0) {
|
|
197
|
-
return { isValid: false, invalidKeys: [] };
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const invalidKeys = Object.keys(keyValuePairs).filter(
|
|
201
|
-
(key) => !this.validateKey(key)
|
|
202
|
-
);
|
|
203
|
-
return { isValid: invalidKeys.length === 0, invalidKeys };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
61
|
static formatKey(key: string, locale: string) {
|
|
207
|
-
return encodeURIComponent(
|
|
208
|
-
`${CACHE_VERSION}_${Settings.commerceUrl}_${locale}_${key}`
|
|
209
|
-
);
|
|
62
|
+
return encodeURIComponent(`${Settings.commerceUrl}_${locale}_${key}`);
|
|
210
63
|
}
|
|
211
64
|
|
|
212
65
|
static clientPool: Pool<RedisClientType> = createPool(
|
|
@@ -243,9 +96,9 @@ export class Cache {
|
|
|
243
96
|
return await Cache.clientPool.acquire();
|
|
244
97
|
}
|
|
245
98
|
|
|
246
|
-
static async get(key: string)
|
|
247
|
-
let value
|
|
248
|
-
let client
|
|
99
|
+
static async get(key: string) {
|
|
100
|
+
let value;
|
|
101
|
+
let client;
|
|
249
102
|
|
|
250
103
|
try {
|
|
251
104
|
client = await Cache.getClient();
|
|
@@ -268,13 +121,14 @@ export class Cache {
|
|
|
268
121
|
return value;
|
|
269
122
|
}
|
|
270
123
|
|
|
271
|
-
static async set(key: string, value: any, expire?: number)
|
|
124
|
+
static async set(key: string, value: any, expire?: number) {
|
|
272
125
|
let success = false;
|
|
273
|
-
let client
|
|
126
|
+
let client;
|
|
274
127
|
|
|
275
128
|
try {
|
|
276
129
|
client = await Cache.getClient();
|
|
277
|
-
const serializedValue =
|
|
130
|
+
const serializedValue =
|
|
131
|
+
typeof value === 'object' ? JSON.stringify(value) : value;
|
|
278
132
|
|
|
279
133
|
if (expire) {
|
|
280
134
|
await client.set(key, serializedValue, { EX: expire });
|
|
@@ -314,8 +168,7 @@ export class Cache {
|
|
|
314
168
|
|
|
315
169
|
const defaultOptions: CacheOptions = {
|
|
316
170
|
cache: true,
|
|
317
|
-
expire: Settings.redis.defaultExpirationTime
|
|
318
|
-
compressed: process.env.CACHE_COMPRESSION_ENABLED !== 'false'
|
|
171
|
+
expire: Settings.redis.defaultExpirationTime
|
|
319
172
|
};
|
|
320
173
|
|
|
321
174
|
const _options = Object.assign(defaultOptions, options);
|
|
@@ -328,23 +181,18 @@ export class Cache {
|
|
|
328
181
|
logger.debug('Cache wrap', { key, formattedKey, _options });
|
|
329
182
|
|
|
330
183
|
if (_options.cache) {
|
|
331
|
-
let cachedValue
|
|
184
|
+
let cachedValue;
|
|
332
185
|
|
|
333
186
|
if (_options.useProxy) {
|
|
334
187
|
const body = new URLSearchParams();
|
|
335
188
|
|
|
336
189
|
body.append('key', formattedKey);
|
|
337
|
-
if (_options.compressed) {
|
|
338
|
-
body.append('compressed', 'true');
|
|
339
|
-
}
|
|
340
190
|
|
|
341
191
|
cachedValue = await Cache.proxyRequest('POST', body);
|
|
342
192
|
logger.debug('Cache proxy request success', { key });
|
|
343
193
|
logger.trace('Cache proxy request', { key, cachedValue });
|
|
344
194
|
} else {
|
|
345
|
-
cachedValue =
|
|
346
|
-
? await Cache.getCompressed(formattedKey)
|
|
347
|
-
: await Cache.get(formattedKey);
|
|
195
|
+
cachedValue = await Cache.get(formattedKey);
|
|
348
196
|
}
|
|
349
197
|
|
|
350
198
|
if (cachedValue) {
|
|
@@ -367,9 +215,6 @@ export class Cache {
|
|
|
367
215
|
'expire',
|
|
368
216
|
String(_options?.expire ?? Settings.redis.defaultExpirationTime)
|
|
369
217
|
);
|
|
370
|
-
if (_options.compressed) {
|
|
371
|
-
body.append('compressed', 'true');
|
|
372
|
-
}
|
|
373
218
|
await Cache.proxyRequest('PUT', body);
|
|
374
219
|
|
|
375
220
|
logger.debug('Cache proxy request', { key, body: body.toString() });
|
|
@@ -377,11 +222,7 @@ export class Cache {
|
|
|
377
222
|
logger.error('Cache proxy error', error);
|
|
378
223
|
}
|
|
379
224
|
} else {
|
|
380
|
-
|
|
381
|
-
await Cache.setCompressed(formattedKey, data, _options?.expire);
|
|
382
|
-
} else {
|
|
383
|
-
await Cache.set(formattedKey, JSON.stringify(data), _options?.expire);
|
|
384
|
-
}
|
|
225
|
+
await Cache.set(formattedKey, JSON.stringify(data), _options?.expire);
|
|
385
226
|
}
|
|
386
227
|
}
|
|
387
228
|
|
|
@@ -393,7 +234,7 @@ export class Cache {
|
|
|
393
234
|
await fetch(Cache.PROXY_URL, {
|
|
394
235
|
method,
|
|
395
236
|
headers: {
|
|
396
|
-
authorization: process.env.CACHE_SECRET
|
|
237
|
+
authorization: process.env.CACHE_SECRET
|
|
397
238
|
},
|
|
398
239
|
body
|
|
399
240
|
})
|
|
@@ -401,264 +242,4 @@ export class Cache {
|
|
|
401
242
|
|
|
402
243
|
return response;
|
|
403
244
|
}
|
|
404
|
-
|
|
405
|
-
static async mset(
|
|
406
|
-
keyValuePairs: Record<string, any>,
|
|
407
|
-
expire?: number
|
|
408
|
-
): Promise<boolean> {
|
|
409
|
-
const validation = Cache.validateKeyValuePairs(keyValuePairs);
|
|
410
|
-
if (!validation.isValid) {
|
|
411
|
-
if (validation.invalidKeys.length > 0) {
|
|
412
|
-
logger.error('Invalid keys in mset', {
|
|
413
|
-
invalidKeys: validation.invalidKeys
|
|
414
|
-
});
|
|
415
|
-
} else {
|
|
416
|
-
logger.warn('mset called with empty keyValuePairs');
|
|
417
|
-
}
|
|
418
|
-
return false;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
let success = false;
|
|
422
|
-
let client: RedisClientType | undefined;
|
|
423
|
-
|
|
424
|
-
try {
|
|
425
|
-
client = await Cache.getClient();
|
|
426
|
-
const pipeline = client.multi();
|
|
427
|
-
|
|
428
|
-
Object.entries(keyValuePairs).forEach(([key, value]) => {
|
|
429
|
-
const serializedValue = Cache.serializeValue(value);
|
|
430
|
-
if (expire) {
|
|
431
|
-
pipeline.set(key, serializedValue, { EX: expire });
|
|
432
|
-
} else {
|
|
433
|
-
pipeline.set(key, serializedValue);
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
const results = await pipeline.exec();
|
|
438
|
-
|
|
439
|
-
const failures =
|
|
440
|
-
results?.filter((result) => result instanceof Error) || [];
|
|
441
|
-
|
|
442
|
-
if (failures.length > 0) {
|
|
443
|
-
logger.warn('Some mset operations failed', {
|
|
444
|
-
totalOperations: results?.length || 0,
|
|
445
|
-
failures: failures.length,
|
|
446
|
-
keys: Object.keys(keyValuePairs)
|
|
447
|
-
});
|
|
448
|
-
success = false;
|
|
449
|
-
} else {
|
|
450
|
-
success = true;
|
|
451
|
-
|
|
452
|
-
logger.debug('Redis mset success', {
|
|
453
|
-
keys: Object.keys(keyValuePairs),
|
|
454
|
-
expire,
|
|
455
|
-
operationsCount: Object.keys(keyValuePairs).length
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
} catch (error) {
|
|
459
|
-
logger.error('Redis mset error', {
|
|
460
|
-
keys: Object.keys(keyValuePairs),
|
|
461
|
-
error
|
|
462
|
-
});
|
|
463
|
-
success = false;
|
|
464
|
-
} finally {
|
|
465
|
-
if (client) {
|
|
466
|
-
await Cache.clientPool.release(client);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
return success;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
static async setCompressed(
|
|
474
|
-
key: string,
|
|
475
|
-
value: any,
|
|
476
|
-
expire?: number
|
|
477
|
-
): Promise<boolean> {
|
|
478
|
-
if (!Cache.validateKey(key)) {
|
|
479
|
-
logger.error('Invalid key in setCompressed', { key });
|
|
480
|
-
return false;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
let success = false;
|
|
484
|
-
let client: RedisClientType | undefined;
|
|
485
|
-
|
|
486
|
-
try {
|
|
487
|
-
client = await Cache.getClient();
|
|
488
|
-
const serializedValue = Cache.serializeValue(value);
|
|
489
|
-
|
|
490
|
-
if (serializedValue.length > 1024 * 1024) {
|
|
491
|
-
logger.warn('Large data being compressed', {
|
|
492
|
-
key,
|
|
493
|
-
size: serializedValue.length
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
const url = extractUrlFromKey(key);
|
|
498
|
-
|
|
499
|
-
logger.debug('setCompressed called', {
|
|
500
|
-
key,
|
|
501
|
-
url,
|
|
502
|
-
dataSize: serializedValue.length
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
try {
|
|
506
|
-
colorLog(
|
|
507
|
-
colors.magenta,
|
|
508
|
-
'[Cache] 🟣 ',
|
|
509
|
-
`Using GZIP compression for: ${url}`
|
|
510
|
-
);
|
|
511
|
-
const compressed = await compressData(serializedValue);
|
|
512
|
-
const compressedBase64 = Buffer.from(compressed).toString('base64');
|
|
513
|
-
|
|
514
|
-
if (expire) {
|
|
515
|
-
await client.set(key, compressedBase64, { EX: expire });
|
|
516
|
-
} else {
|
|
517
|
-
await client.set(key, compressedBase64);
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
success = true;
|
|
521
|
-
const compressionRatio = (
|
|
522
|
-
(1 - compressed.length / serializedValue.length) *
|
|
523
|
-
100
|
|
524
|
-
).toFixed(1);
|
|
525
|
-
colorLog(
|
|
526
|
-
colors.magenta,
|
|
527
|
-
'[Cache] 🟣 ',
|
|
528
|
-
`Compressed ${serializedValue.length} → ${compressed.length} bytes (${compressionRatio}% reduction) for: ${url}`
|
|
529
|
-
);
|
|
530
|
-
logger.debug('Redis setCompressed success', {
|
|
531
|
-
key,
|
|
532
|
-
url,
|
|
533
|
-
originalSize: serializedValue.length,
|
|
534
|
-
compressedSize: compressed.length,
|
|
535
|
-
compressionRatio: `${compressionRatio}%`,
|
|
536
|
-
method: 'gzip'
|
|
537
|
-
});
|
|
538
|
-
} catch (compressionError) {
|
|
539
|
-
colorLog(
|
|
540
|
-
colors.yellow,
|
|
541
|
-
'[Cache] ⚠️ ',
|
|
542
|
-
`Compression failed, storing uncompressed for: ${url}`
|
|
543
|
-
);
|
|
544
|
-
logger.warn('Compression failed, storing uncompressed', {
|
|
545
|
-
key,
|
|
546
|
-
url,
|
|
547
|
-
error: compressionError
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
if (expire) {
|
|
551
|
-
await client.set(key, serializedValue, { EX: expire });
|
|
552
|
-
} else {
|
|
553
|
-
await client.set(key, serializedValue);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
success = true;
|
|
557
|
-
logger.debug('Redis set success (uncompressed)', {
|
|
558
|
-
key,
|
|
559
|
-
url,
|
|
560
|
-
size: serializedValue.length
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
} catch (error) {
|
|
564
|
-
logger.error('Redis setCompressed error', { key, error });
|
|
565
|
-
success = false;
|
|
566
|
-
} finally {
|
|
567
|
-
if (client) {
|
|
568
|
-
await Cache.clientPool.release(client);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
return success;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
static async getCompressed(
|
|
576
|
-
key: string,
|
|
577
|
-
maxDecompressedSize: number = 10 * 1024 * 1024
|
|
578
|
-
): Promise<unknown> {
|
|
579
|
-
if (!Cache.validateKey(key)) {
|
|
580
|
-
logger.error('Invalid key in getCompressed', { key });
|
|
581
|
-
return null;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
let value: unknown;
|
|
585
|
-
let client: RedisClientType | undefined;
|
|
586
|
-
|
|
587
|
-
try {
|
|
588
|
-
client = await Cache.getClient();
|
|
589
|
-
const compressed = await client.get(key);
|
|
590
|
-
|
|
591
|
-
if (compressed) {
|
|
592
|
-
const compressedBuffer = Buffer.from(compressed, 'base64');
|
|
593
|
-
|
|
594
|
-
const url = extractUrlFromKey(key);
|
|
595
|
-
|
|
596
|
-
try {
|
|
597
|
-
colorLog(
|
|
598
|
-
colors.magenta,
|
|
599
|
-
'[Cache] 🟣 ',
|
|
600
|
-
`Using GZIP decompression for: ${url}`
|
|
601
|
-
);
|
|
602
|
-
const decompressedString = await decompressData(
|
|
603
|
-
new Uint8Array(compressedBuffer)
|
|
604
|
-
);
|
|
605
|
-
value = JSON.parse(decompressedString);
|
|
606
|
-
colorLog(
|
|
607
|
-
colors.magenta,
|
|
608
|
-
'[Cache] 🟣 ',
|
|
609
|
-
`Decompressed ${compressedBuffer.length} → ${decompressedString.length} bytes for: ${url}`
|
|
610
|
-
);
|
|
611
|
-
logger.debug('Redis getCompressed success', {
|
|
612
|
-
key,
|
|
613
|
-
url,
|
|
614
|
-
compressedSize: compressedBuffer.length,
|
|
615
|
-
decompressedSize: decompressedString.length,
|
|
616
|
-
method: 'gzip'
|
|
617
|
-
});
|
|
618
|
-
return value;
|
|
619
|
-
} catch (decompressionError) {
|
|
620
|
-
colorLog(
|
|
621
|
-
colors.yellow,
|
|
622
|
-
'[Cache] ⚠️ ',
|
|
623
|
-
`Decompression failed, trying uncompressed for: ${url}`
|
|
624
|
-
);
|
|
625
|
-
logger.debug('Decompression failed, trying direct JSON parse', {
|
|
626
|
-
key,
|
|
627
|
-
url,
|
|
628
|
-
error: decompressionError
|
|
629
|
-
});
|
|
630
|
-
|
|
631
|
-
try {
|
|
632
|
-
const rawString = compressed;
|
|
633
|
-
const parsedData = JSON.parse(rawString);
|
|
634
|
-
logger.debug('Data read as uncompressed', {
|
|
635
|
-
key,
|
|
636
|
-
url
|
|
637
|
-
});
|
|
638
|
-
return parsedData;
|
|
639
|
-
} catch (jsonError) {
|
|
640
|
-
logger.error('Failed to parse data in all formats', {
|
|
641
|
-
key,
|
|
642
|
-
url,
|
|
643
|
-
decompressionError,
|
|
644
|
-
jsonError
|
|
645
|
-
});
|
|
646
|
-
return null;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
} else {
|
|
650
|
-
value = null;
|
|
651
|
-
logger.debug('Redis getCompressed: key not found', { key });
|
|
652
|
-
}
|
|
653
|
-
} catch (error) {
|
|
654
|
-
logger.error('Redis getCompressed error', { key, error });
|
|
655
|
-
value = null;
|
|
656
|
-
} finally {
|
|
657
|
-
if (client) {
|
|
658
|
-
await Cache.clientPool.release(client);
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
return value;
|
|
663
|
-
}
|
|
664
245
|
}
|
|
@@ -64,7 +64,7 @@ const withCheckoutProvider =
|
|
|
64
64
|
const location = request.headers.get('location');
|
|
65
65
|
const redirectUrl = new URL(
|
|
66
66
|
request.headers.get('location'),
|
|
67
|
-
location.startsWith('http') ? '' :
|
|
67
|
+
location.startsWith('http') ? '' : process.env.NEXT_PUBLIC_URL
|
|
68
68
|
);
|
|
69
69
|
|
|
70
70
|
redirectUrl.pathname = getUrlPathWithLocale(
|
|
@@ -148,8 +148,7 @@ const withCompleteGpay =
|
|
|
148
148
|
logger.info('Redirecting to order success page', {
|
|
149
149
|
middleware: 'complete-gpay',
|
|
150
150
|
redirectUrlWithLocale,
|
|
151
|
-
ip
|
|
152
|
-
setCookie: request.headers.get('set-cookie')
|
|
151
|
+
ip
|
|
153
152
|
});
|
|
154
153
|
|
|
155
154
|
// Using POST method while redirecting causes an error,
|
|
@@ -149,8 +149,7 @@ const withCompleteMasterpass =
|
|
|
149
149
|
logger.info('Redirecting to order success page', {
|
|
150
150
|
middleware: 'complete-masterpass',
|
|
151
151
|
redirectUrlWithLocale,
|
|
152
|
-
ip
|
|
153
|
-
setCookie: request.headers.get('set-cookie')
|
|
152
|
+
ip
|
|
154
153
|
});
|
|
155
154
|
|
|
156
155
|
// Using POST method while redirecting causes an error,
|
package/middlewares/default.ts
CHANGED
|
@@ -302,6 +302,19 @@ const withPzDefault =
|
|
|
302
302
|
)}`;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
if (
|
|
306
|
+
!req.middlewareParams.found &&
|
|
307
|
+
Settings.customNotFoundEnabled
|
|
308
|
+
) {
|
|
309
|
+
const pathname = url.pathname
|
|
310
|
+
.replace(/\/+$/, '')
|
|
311
|
+
.split('/');
|
|
312
|
+
url.pathname = url.pathname.replace(
|
|
313
|
+
pathname.pop(),
|
|
314
|
+
'pz-not-found'
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
305
318
|
Settings.rewrites.forEach((rewrite) => {
|
|
306
319
|
url.pathname = url.pathname.replace(
|
|
307
320
|
rewrite.source,
|
|
@@ -339,24 +352,6 @@ const withPzDefault =
|
|
|
339
352
|
middlewareResult = NextResponse.rewrite(url);
|
|
340
353
|
}
|
|
341
354
|
|
|
342
|
-
if (
|
|
343
|
-
!req.middlewareParams.found &&
|
|
344
|
-
Settings.customNotFoundEnabled
|
|
345
|
-
) {
|
|
346
|
-
const pathSegments = url.pathname
|
|
347
|
-
.replace(/\/+$/, '')
|
|
348
|
-
.split('/');
|
|
349
|
-
if (pathSegments.length >= 3) {
|
|
350
|
-
url.pathname = `/${pathSegments[1]}/${pathSegments[2]}/pz-not-found`;
|
|
351
|
-
} else {
|
|
352
|
-
url.pathname = '/pz-not-found';
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
middlewareResult = NextResponse.rewrite(url, {
|
|
356
|
-
status: 404
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
|
|
360
355
|
const { localeUrlStrategy } =
|
|
361
356
|
Settings.localization;
|
|
362
357
|
|
|
@@ -406,38 +401,6 @@ const withPzDefault =
|
|
|
406
401
|
}
|
|
407
402
|
);
|
|
408
403
|
|
|
409
|
-
if (
|
|
410
|
-
!url.pathname.startsWith(
|
|
411
|
-
`/${currency}/orders`
|
|
412
|
-
)
|
|
413
|
-
) {
|
|
414
|
-
const currentCookieLocale =
|
|
415
|
-
req.cookies.get('pz-locale')?.value;
|
|
416
|
-
|
|
417
|
-
const urlHasExplicitLocale =
|
|
418
|
-
url.pathname.match(urlLocaleMatcherRegex);
|
|
419
|
-
const shouldUpdateCookie =
|
|
420
|
-
!currentCookieLocale ||
|
|
421
|
-
urlHasExplicitLocale;
|
|
422
|
-
|
|
423
|
-
if (shouldUpdateCookie) {
|
|
424
|
-
middlewareResult.cookies.set(
|
|
425
|
-
'pz-locale',
|
|
426
|
-
locale?.length > 0
|
|
427
|
-
? locale
|
|
428
|
-
: defaultLocaleValue,
|
|
429
|
-
{
|
|
430
|
-
domain: rootHostname,
|
|
431
|
-
sameSite: 'none',
|
|
432
|
-
secure: true,
|
|
433
|
-
expires: new Date(
|
|
434
|
-
Date.now() + 1000 * 60 * 60 * 24 * 7
|
|
435
|
-
) // 7 days
|
|
436
|
-
}
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
404
|
if (
|
|
442
405
|
req.cookies.get('pz-locale') &&
|
|
443
406
|
req.cookies.get('pz-locale').value !== locale
|
package/middlewares/locale.ts
CHANGED
|
@@ -23,15 +23,7 @@ const getMatchedLocale = (pathname: string, req: PzNextRequest) => {
|
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
if (subDomainLocaleMatched && subDomainLocaleMatched[0]) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const isValidSubdomainLocale = settings.localization.locales.find(
|
|
29
|
-
(l) => l.value === subdomainLocale
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
if (isValidSubdomainLocale) {
|
|
33
|
-
matchedLocale = subdomainLocale;
|
|
34
|
-
}
|
|
26
|
+
matchedLocale = subDomainLocaleMatched[0].slice(1);
|
|
35
27
|
}
|
|
36
28
|
}
|
|
37
29
|
}
|
|
@@ -149,8 +149,7 @@ const withRedirectionPayment =
|
|
|
149
149
|
logger.info('Redirecting to order success page', {
|
|
150
150
|
middleware: 'redirection-payment',
|
|
151
151
|
redirectUrlWithLocale,
|
|
152
|
-
ip
|
|
153
|
-
setCookie: request.headers.get('set-cookie')
|
|
152
|
+
ip
|
|
154
153
|
});
|
|
155
154
|
|
|
156
155
|
// Using POST method while redirecting causes an error,
|
|
@@ -149,8 +149,7 @@ const withSavedCardRedirection =
|
|
|
149
149
|
logger.info('Redirecting to order success page', {
|
|
150
150
|
middleware: 'saved-card-redirection',
|
|
151
151
|
redirectUrlWithLocale,
|
|
152
|
-
ip
|
|
153
|
-
setCookie: request.headers.get('set-cookie')
|
|
152
|
+
ip
|
|
154
153
|
});
|
|
155
154
|
|
|
156
155
|
// Using POST method while redirecting causes an error,
|