@akinon/next 1.96.0-snapshot-ZERO-35861-20250908151109 → 1.96.0-snapshot-ZERO-3620-20250915165755
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 +1395 -45
- package/__tests__/next-config.test.ts +1 -10
- package/__tests__/redirect.test.ts +319 -0
- package/api/cache.ts +5 -39
- 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 +50 -32
- package/data/server/flatpage.ts +17 -16
- package/data/server/form.ts +1 -4
- package/data/server/landingpage.ts +16 -12
- package/data/server/list.ts +24 -15
- package/data/server/menu.ts +2 -5
- package/data/server/product.ts +67 -41
- package/data/server/special-page.ts +16 -12
- package/data/server/widget.ts +1 -4
- 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 +87 -365
- package/lib/cache.ts +25 -252
- 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 +1 -2
- 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 +8 -14
- package/package.json +3 -4
- package/plugins.d.ts +8 -0
- package/plugins.js +3 -1
- package/redux/middlewares/checkout.ts +5 -1
- package/types/commerce/order.ts +1 -0
- package/types/index.ts +34 -2
- package/utils/app-fetch.ts +7 -2
- package/utils/redirect-ignore.ts +35 -0
- package/utils/redirect.ts +31 -6
- package/with-pz-config.js +1 -5
package/lib/cache.ts
CHANGED
|
@@ -3,65 +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 compressData = async (data: string): Promise<Uint8Array> => {
|
|
9
|
-
const stream = new CompressionStream('gzip');
|
|
10
|
-
const writer = stream.writable.getWriter();
|
|
11
|
-
const reader = stream.readable.getReader();
|
|
12
|
-
|
|
13
|
-
writer.write(new TextEncoder().encode(data));
|
|
14
|
-
writer.close();
|
|
15
|
-
|
|
16
|
-
const chunks: Uint8Array[] = [];
|
|
17
|
-
let done = false;
|
|
18
|
-
|
|
19
|
-
while (!done) {
|
|
20
|
-
const { value, done: readerDone } = await reader.read();
|
|
21
|
-
done = readerDone;
|
|
22
|
-
if (value) chunks.push(value);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
26
|
-
const result = new Uint8Array(totalLength);
|
|
27
|
-
let offset = 0;
|
|
28
|
-
|
|
29
|
-
for (const chunk of chunks) {
|
|
30
|
-
result.set(chunk, offset);
|
|
31
|
-
offset += chunk.length;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return result;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const decompressData = async (compressed: Uint8Array): Promise<string> => {
|
|
38
|
-
const stream = new DecompressionStream('gzip');
|
|
39
|
-
const writer = stream.writable.getWriter();
|
|
40
|
-
const reader = stream.readable.getReader();
|
|
41
|
-
|
|
42
|
-
writer.write(compressed);
|
|
43
|
-
writer.close();
|
|
44
|
-
|
|
45
|
-
const chunks: Uint8Array[] = [];
|
|
46
|
-
let done = false;
|
|
47
|
-
|
|
48
|
-
while (!done) {
|
|
49
|
-
const { value, done: readerDone } = await reader.read();
|
|
50
|
-
done = readerDone;
|
|
51
|
-
if (value) chunks.push(value);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
55
|
-
const result = new Uint8Array(totalLength);
|
|
56
|
-
let offset = 0;
|
|
57
|
-
|
|
58
|
-
for (const chunk of chunks) {
|
|
59
|
-
result.set(chunk, offset);
|
|
60
|
-
offset += chunk.length;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return new TextDecoder().decode(result);
|
|
64
|
-
};
|
|
65
6
|
|
|
66
7
|
const hashCacheKey = (object?: Record<string, string>) => {
|
|
67
8
|
if (!object) {
|
|
@@ -119,32 +60,8 @@ export const CacheKey = {
|
|
|
119
60
|
export class Cache {
|
|
120
61
|
static PROXY_URL = `${process.env.NEXT_PUBLIC_URL}/api/cache`;
|
|
121
62
|
|
|
122
|
-
private static serializeValue(value: any): string {
|
|
123
|
-
return typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private static validateKey(key: string): boolean {
|
|
127
|
-
return !(!key || key.trim() === '');
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private static validateKeyValuePairs(keyValuePairs: Record<string, any>): {
|
|
131
|
-
isValid: boolean;
|
|
132
|
-
invalidKeys: string[];
|
|
133
|
-
} {
|
|
134
|
-
if (!keyValuePairs || Object.keys(keyValuePairs).length === 0) {
|
|
135
|
-
return { isValid: false, invalidKeys: [] };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const invalidKeys = Object.keys(keyValuePairs).filter(
|
|
139
|
-
(key) => !this.validateKey(key)
|
|
140
|
-
);
|
|
141
|
-
return { isValid: invalidKeys.length === 0, invalidKeys };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
63
|
static formatKey(key: string, locale: string) {
|
|
145
|
-
return encodeURIComponent(
|
|
146
|
-
`${CACHE_VERSION}_${Settings.commerceUrl}_${locale}_${key}`
|
|
147
|
-
);
|
|
64
|
+
return encodeURIComponent(`${Settings.commerceUrl}_${locale}_${key}`);
|
|
148
65
|
}
|
|
149
66
|
|
|
150
67
|
static clientPool: Pool<RedisClientType> = createPool(
|
|
@@ -181,9 +98,9 @@ export class Cache {
|
|
|
181
98
|
return await Cache.clientPool.acquire();
|
|
182
99
|
}
|
|
183
100
|
|
|
184
|
-
static async get(key: string)
|
|
185
|
-
let value
|
|
186
|
-
let client
|
|
101
|
+
static async get(key: string) {
|
|
102
|
+
let value;
|
|
103
|
+
let client;
|
|
187
104
|
|
|
188
105
|
try {
|
|
189
106
|
client = await Cache.getClient();
|
|
@@ -193,7 +110,9 @@ export class Cache {
|
|
|
193
110
|
} else {
|
|
194
111
|
value = null;
|
|
195
112
|
}
|
|
113
|
+
logger.debug('Redis get success', { key, value });
|
|
196
114
|
} catch (error) {
|
|
115
|
+
logger.error('Redis get error', { key, error });
|
|
197
116
|
value = null;
|
|
198
117
|
} finally {
|
|
199
118
|
if (client) {
|
|
@@ -204,13 +123,14 @@ export class Cache {
|
|
|
204
123
|
return value;
|
|
205
124
|
}
|
|
206
125
|
|
|
207
|
-
static async set(key: string, value: any, expire?: number)
|
|
126
|
+
static async set(key: string, value: any, expire?: number) {
|
|
208
127
|
let success = false;
|
|
209
|
-
let client
|
|
128
|
+
let client;
|
|
210
129
|
|
|
211
130
|
try {
|
|
212
131
|
client = await Cache.getClient();
|
|
213
|
-
const serializedValue =
|
|
132
|
+
const serializedValue =
|
|
133
|
+
typeof value === 'object' ? JSON.stringify(value) : value;
|
|
214
134
|
|
|
215
135
|
if (expire) {
|
|
216
136
|
await client.set(key, serializedValue, { EX: expire });
|
|
@@ -219,7 +139,9 @@ export class Cache {
|
|
|
219
139
|
}
|
|
220
140
|
|
|
221
141
|
success = true;
|
|
142
|
+
logger.debug('Redis set success', { key, value });
|
|
222
143
|
} catch (error) {
|
|
144
|
+
logger.error('Redis set error', { key, error });
|
|
223
145
|
success = false;
|
|
224
146
|
} finally {
|
|
225
147
|
if (client) {
|
|
@@ -248,8 +170,7 @@ export class Cache {
|
|
|
248
170
|
|
|
249
171
|
const defaultOptions: CacheOptions = {
|
|
250
172
|
cache: true,
|
|
251
|
-
expire: Settings.redis.defaultExpirationTime
|
|
252
|
-
compressed: process.env.CACHE_COMPRESSION_ENABLED !== 'false'
|
|
173
|
+
expire: Settings.redis.defaultExpirationTime
|
|
253
174
|
};
|
|
254
175
|
|
|
255
176
|
const _options = Object.assign(defaultOptions, options);
|
|
@@ -259,22 +180,21 @@ export class Cache {
|
|
|
259
180
|
_options.expire = 120;
|
|
260
181
|
}
|
|
261
182
|
|
|
183
|
+
logger.debug('Cache wrap', { key, formattedKey, _options });
|
|
184
|
+
|
|
262
185
|
if (_options.cache) {
|
|
263
|
-
let cachedValue
|
|
186
|
+
let cachedValue;
|
|
264
187
|
|
|
265
188
|
if (_options.useProxy) {
|
|
266
189
|
const body = new URLSearchParams();
|
|
267
190
|
|
|
268
191
|
body.append('key', formattedKey);
|
|
269
|
-
if (_options.compressed) {
|
|
270
|
-
body.append('compressed', 'true');
|
|
271
|
-
}
|
|
272
192
|
|
|
273
193
|
cachedValue = await Cache.proxyRequest('POST', body);
|
|
194
|
+
logger.debug('Cache proxy request success', { key });
|
|
195
|
+
logger.trace('Cache proxy request', { key, cachedValue });
|
|
274
196
|
} else {
|
|
275
|
-
cachedValue =
|
|
276
|
-
? await Cache.getCompressed(formattedKey)
|
|
277
|
-
: await Cache.get(formattedKey);
|
|
197
|
+
cachedValue = await Cache.get(formattedKey);
|
|
278
198
|
}
|
|
279
199
|
|
|
280
200
|
if (cachedValue) {
|
|
@@ -282,6 +202,8 @@ export class Cache {
|
|
|
282
202
|
}
|
|
283
203
|
}
|
|
284
204
|
|
|
205
|
+
logger.debug('Redis cache miss. Setting new value...', { key });
|
|
206
|
+
|
|
285
207
|
const data = await handler();
|
|
286
208
|
|
|
287
209
|
if (data && _options.cache) {
|
|
@@ -295,19 +217,14 @@ export class Cache {
|
|
|
295
217
|
'expire',
|
|
296
218
|
String(_options?.expire ?? Settings.redis.defaultExpirationTime)
|
|
297
219
|
);
|
|
298
|
-
if (_options.compressed) {
|
|
299
|
-
body.append('compressed', 'true');
|
|
300
|
-
}
|
|
301
220
|
await Cache.proxyRequest('PUT', body);
|
|
221
|
+
|
|
222
|
+
logger.debug('Cache proxy request', { key, body: body.toString() });
|
|
302
223
|
} catch (error) {
|
|
303
224
|
logger.error('Cache proxy error', error);
|
|
304
225
|
}
|
|
305
226
|
} else {
|
|
306
|
-
|
|
307
|
-
await Cache.setCompressed(formattedKey, data, _options?.expire);
|
|
308
|
-
} else {
|
|
309
|
-
await Cache.set(formattedKey, JSON.stringify(data), _options?.expire);
|
|
310
|
-
}
|
|
227
|
+
await Cache.set(formattedKey, JSON.stringify(data), _options?.expire);
|
|
311
228
|
}
|
|
312
229
|
}
|
|
313
230
|
|
|
@@ -319,7 +236,7 @@ export class Cache {
|
|
|
319
236
|
await fetch(Cache.PROXY_URL, {
|
|
320
237
|
method,
|
|
321
238
|
headers: {
|
|
322
|
-
authorization: process.env.CACHE_SECRET
|
|
239
|
+
authorization: process.env.CACHE_SECRET
|
|
323
240
|
},
|
|
324
241
|
body
|
|
325
242
|
})
|
|
@@ -327,148 +244,4 @@ export class Cache {
|
|
|
327
244
|
|
|
328
245
|
return response;
|
|
329
246
|
}
|
|
330
|
-
|
|
331
|
-
static async mset(
|
|
332
|
-
keyValuePairs: Record<string, any>,
|
|
333
|
-
expire?: number
|
|
334
|
-
): Promise<boolean> {
|
|
335
|
-
const validation = Cache.validateKeyValuePairs(keyValuePairs);
|
|
336
|
-
if (!validation.isValid) {
|
|
337
|
-
if (validation.invalidKeys.length > 0) {
|
|
338
|
-
logger.error('Invalid keys in mset', {
|
|
339
|
-
invalidKeys: validation.invalidKeys
|
|
340
|
-
});
|
|
341
|
-
} else {
|
|
342
|
-
logger.warn('mset called with empty keyValuePairs');
|
|
343
|
-
}
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
let success = false;
|
|
348
|
-
let client: RedisClientType | undefined;
|
|
349
|
-
|
|
350
|
-
try {
|
|
351
|
-
client = await Cache.getClient();
|
|
352
|
-
const pipeline = client.multi();
|
|
353
|
-
|
|
354
|
-
Object.entries(keyValuePairs).forEach(([key, value]) => {
|
|
355
|
-
const serializedValue = Cache.serializeValue(value);
|
|
356
|
-
if (expire) {
|
|
357
|
-
pipeline.set(key, serializedValue, { EX: expire });
|
|
358
|
-
} else {
|
|
359
|
-
pipeline.set(key, serializedValue);
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
const results = await pipeline.exec();
|
|
364
|
-
|
|
365
|
-
const failures =
|
|
366
|
-
results?.filter((result) => result instanceof Error) || [];
|
|
367
|
-
|
|
368
|
-
if (failures.length > 0) {
|
|
369
|
-
success = false;
|
|
370
|
-
} else {
|
|
371
|
-
success = true;
|
|
372
|
-
}
|
|
373
|
-
} catch (error) {
|
|
374
|
-
success = false;
|
|
375
|
-
} finally {
|
|
376
|
-
if (client) {
|
|
377
|
-
await Cache.clientPool.release(client);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return success;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
static async setCompressed(
|
|
385
|
-
key: string,
|
|
386
|
-
value: any,
|
|
387
|
-
expire?: number
|
|
388
|
-
): Promise<boolean> {
|
|
389
|
-
if (!Cache.validateKey(key)) {
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
let success = false;
|
|
394
|
-
let client: RedisClientType | undefined;
|
|
395
|
-
|
|
396
|
-
try {
|
|
397
|
-
client = await Cache.getClient();
|
|
398
|
-
const serializedValue = Cache.serializeValue(value);
|
|
399
|
-
|
|
400
|
-
try {
|
|
401
|
-
const compressed = await compressData(serializedValue);
|
|
402
|
-
const compressedBase64 = Buffer.from(compressed).toString('base64');
|
|
403
|
-
|
|
404
|
-
if (expire) {
|
|
405
|
-
await client.set(key, compressedBase64, { EX: expire });
|
|
406
|
-
} else {
|
|
407
|
-
await client.set(key, compressedBase64);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
success = true;
|
|
411
|
-
} catch (compressionError) {
|
|
412
|
-
if (expire) {
|
|
413
|
-
await client.set(key, serializedValue, { EX: expire });
|
|
414
|
-
} else {
|
|
415
|
-
await client.set(key, serializedValue);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
success = true;
|
|
419
|
-
}
|
|
420
|
-
} catch (error) {
|
|
421
|
-
success = false;
|
|
422
|
-
} finally {
|
|
423
|
-
if (client) {
|
|
424
|
-
await Cache.clientPool.release(client);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
return success;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
static async getCompressed(key: string): Promise<unknown> {
|
|
432
|
-
if (!Cache.validateKey(key)) {
|
|
433
|
-
return null;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
let value: unknown;
|
|
437
|
-
let client: RedisClientType | undefined;
|
|
438
|
-
|
|
439
|
-
try {
|
|
440
|
-
client = await Cache.getClient();
|
|
441
|
-
const compressed = await client.get(key);
|
|
442
|
-
|
|
443
|
-
if (compressed) {
|
|
444
|
-
const compressedBuffer = Buffer.from(compressed, 'base64');
|
|
445
|
-
|
|
446
|
-
try {
|
|
447
|
-
const decompressedString = await decompressData(
|
|
448
|
-
new Uint8Array(compressedBuffer)
|
|
449
|
-
);
|
|
450
|
-
value = JSON.parse(decompressedString);
|
|
451
|
-
return value;
|
|
452
|
-
} catch (decompressionError) {
|
|
453
|
-
try {
|
|
454
|
-
const rawString = compressed;
|
|
455
|
-
const parsedData = JSON.parse(rawString);
|
|
456
|
-
return parsedData;
|
|
457
|
-
} catch (jsonError) {
|
|
458
|
-
return null;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
} else {
|
|
462
|
-
value = null;
|
|
463
|
-
}
|
|
464
|
-
} catch (error) {
|
|
465
|
-
value = null;
|
|
466
|
-
} finally {
|
|
467
|
-
if (client) {
|
|
468
|
-
await Cache.clientPool.release(client);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return value;
|
|
473
|
-
}
|
|
474
247
|
}
|
|
@@ -148,7 +148,8 @@ const withCompleteGpay =
|
|
|
148
148
|
logger.info('Redirecting to order success page', {
|
|
149
149
|
middleware: 'complete-gpay',
|
|
150
150
|
redirectUrlWithLocale,
|
|
151
|
-
ip
|
|
151
|
+
ip,
|
|
152
|
+
setCookie: request.headers.get('set-cookie')
|
|
152
153
|
});
|
|
153
154
|
|
|
154
155
|
// Using POST method while redirecting causes an error,
|
|
@@ -149,7 +149,8 @@ const withCompleteMasterpass =
|
|
|
149
149
|
logger.info('Redirecting to order success page', {
|
|
150
150
|
middleware: 'complete-masterpass',
|
|
151
151
|
redirectUrlWithLocale,
|
|
152
|
-
ip
|
|
152
|
+
ip,
|
|
153
|
+
setCookie: request.headers.get('set-cookie')
|
|
153
154
|
});
|
|
154
155
|
|
|
155
156
|
// Using POST method while redirecting causes an error,
|
package/middlewares/default.ts
CHANGED
|
@@ -302,19 +302,6 @@ 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
|
-
|
|
318
305
|
Settings.rewrites.forEach((rewrite) => {
|
|
319
306
|
url.pathname = url.pathname.replace(
|
|
320
307
|
rewrite.source,
|
|
@@ -352,6 +339,24 @@ const withPzDefault =
|
|
|
352
339
|
middlewareResult = NextResponse.rewrite(url);
|
|
353
340
|
}
|
|
354
341
|
|
|
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
|
+
|
|
355
360
|
const { localeUrlStrategy } =
|
|
356
361
|
Settings.localization;
|
|
357
362
|
|
|
@@ -401,6 +406,38 @@ const withPzDefault =
|
|
|
401
406
|
}
|
|
402
407
|
);
|
|
403
408
|
|
|
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
|
+
|
|
404
441
|
if (
|
|
405
442
|
req.cookies.get('pz-locale') &&
|
|
406
443
|
req.cookies.get('pz-locale').value !== locale
|
package/middlewares/locale.ts
CHANGED
|
@@ -23,7 +23,15 @@ const getMatchedLocale = (pathname: string, req: PzNextRequest) => {
|
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
if (subDomainLocaleMatched && subDomainLocaleMatched[0]) {
|
|
26
|
-
|
|
26
|
+
const subdomainLocale = subDomainLocaleMatched[0].slice(1);
|
|
27
|
+
|
|
28
|
+
const isValidSubdomainLocale = settings.localization.locales.find(
|
|
29
|
+
(l) => l.value === subdomainLocale
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (isValidSubdomainLocale) {
|
|
33
|
+
matchedLocale = subdomainLocale;
|
|
34
|
+
}
|
|
27
35
|
}
|
|
28
36
|
}
|
|
29
37
|
}
|
|
@@ -149,7 +149,8 @@ const withRedirectionPayment =
|
|
|
149
149
|
logger.info('Redirecting to order success page', {
|
|
150
150
|
middleware: 'redirection-payment',
|
|
151
151
|
redirectUrlWithLocale,
|
|
152
|
-
ip
|
|
152
|
+
ip,
|
|
153
|
+
setCookie: request.headers.get('set-cookie')
|
|
153
154
|
});
|
|
154
155
|
|
|
155
156
|
// Using POST method while redirecting causes an error,
|
|
@@ -149,7 +149,8 @@ const withSavedCardRedirection =
|
|
|
149
149
|
logger.info('Redirecting to order success page', {
|
|
150
150
|
middleware: 'saved-card-redirection',
|
|
151
151
|
redirectUrlWithLocale,
|
|
152
|
-
ip
|
|
152
|
+
ip,
|
|
153
|
+
setCookie: request.headers.get('set-cookie')
|
|
153
154
|
});
|
|
154
155
|
|
|
155
156
|
// Using POST method while redirecting causes an error,
|
|
@@ -149,7 +149,8 @@ const withThreeDRedirection =
|
|
|
149
149
|
logger.info('Redirecting to order success page', {
|
|
150
150
|
middleware: 'three-d-redirection',
|
|
151
151
|
redirectUrlWithLocale,
|
|
152
|
-
ip
|
|
152
|
+
ip,
|
|
153
|
+
setCookie: request.headers.get('set-cookie')
|
|
153
154
|
});
|
|
154
155
|
|
|
155
156
|
// Using POST method while redirecting causes an error,
|
|
@@ -4,6 +4,7 @@ import { PzNextRequest } from '.';
|
|
|
4
4
|
import logger from '../utils/log';
|
|
5
5
|
import { urlLocaleMatcherRegex } from '../utils';
|
|
6
6
|
import { getUrlPathWithLocale } from '../utils/localization';
|
|
7
|
+
import { shouldIgnoreRedirect } from '../utils/redirect-ignore';
|
|
7
8
|
import { ROUTES } from 'routes';
|
|
8
9
|
|
|
9
10
|
// This middleware is used to handle url redirections set in Omnitron
|
|
@@ -60,20 +61,13 @@ const withUrlRedirection =
|
|
|
60
61
|
|
|
61
62
|
const setCookies = request.headers.getSetCookie();
|
|
62
63
|
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
71
|
-
)
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
if (shouldIgnoreRedirect) {
|
|
75
|
-
return middleware(req, event);
|
|
76
|
-
}
|
|
64
|
+
if (
|
|
65
|
+
shouldIgnoreRedirect(
|
|
66
|
+
url.pathname,
|
|
67
|
+
req.middlewareParams.rewrites.locale
|
|
68
|
+
)
|
|
69
|
+
) {
|
|
70
|
+
return middleware(req, event);
|
|
77
71
|
}
|
|
78
72
|
|
|
79
73
|
const response = NextResponse.redirect(redirectUrl.toString(), {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/next",
|
|
3
3
|
"description": "Core package for Project Zero Next",
|
|
4
|
-
"version": "1.96.0-snapshot-ZERO-
|
|
4
|
+
"version": "1.96.0-snapshot-ZERO-3620-20250915165755",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -17,14 +17,13 @@
|
|
|
17
17
|
"test": "jest"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@mongodb-js/zstd": "^2.0.1",
|
|
21
|
-
"@neshca/cache-handler": "1.9.0",
|
|
22
20
|
"@opentelemetry/exporter-trace-otlp-http": "0.46.0",
|
|
23
21
|
"@opentelemetry/resources": "1.19.0",
|
|
24
22
|
"@opentelemetry/sdk-node": "0.46.0",
|
|
25
23
|
"@opentelemetry/sdk-trace-node": "1.19.0",
|
|
26
24
|
"@opentelemetry/semantic-conventions": "1.19.0",
|
|
27
25
|
"@reduxjs/toolkit": "1.9.7",
|
|
26
|
+
"@neshca/cache-handler": "1.9.0",
|
|
28
27
|
"@sentry/nextjs": "9.5.0",
|
|
29
28
|
"cross-spawn": "7.0.3",
|
|
30
29
|
"generic-pool": "3.9.0",
|
|
@@ -35,7 +34,7 @@
|
|
|
35
34
|
"set-cookie-parser": "2.6.0"
|
|
36
35
|
},
|
|
37
36
|
"devDependencies": {
|
|
38
|
-
"@akinon/eslint-plugin-projectzero": "1.96.0-snapshot-ZERO-
|
|
37
|
+
"@akinon/eslint-plugin-projectzero": "1.96.0-snapshot-ZERO-3620-20250915165755",
|
|
39
38
|
"@babel/core": "7.26.10",
|
|
40
39
|
"@babel/preset-env": "7.26.9",
|
|
41
40
|
"@babel/preset-typescript": "7.27.0",
|
package/plugins.d.ts
CHANGED
|
@@ -38,3 +38,11 @@ declare module '@akinon/pz-iyzico-saved-card' {
|
|
|
38
38
|
declare module '@akinon/pz-apple-pay' {}
|
|
39
39
|
|
|
40
40
|
declare module '@akinon/pz-flow-payment' {}
|
|
41
|
+
|
|
42
|
+
declare module '@akinon/pz-similar-products' {
|
|
43
|
+
export const SimilarProductsModal: any;
|
|
44
|
+
export const SimilarProductsFilterSidebar: any;
|
|
45
|
+
export const SimilarProductsResultsGrid: any;
|
|
46
|
+
export const SimilarProductsPlugin: any;
|
|
47
|
+
export const SimilarProductsButtonPlugin: any;
|
|
48
|
+
}
|
package/plugins.js
CHANGED
|
@@ -51,7 +51,11 @@ export const errorMiddleware: Middleware = ({ dispatch }: MiddlewareParams) => {
|
|
|
51
51
|
const result: CheckoutResult = next(action);
|
|
52
52
|
const errors = result?.payload?.errors;
|
|
53
53
|
|
|
54
|
-
if (
|
|
54
|
+
if (
|
|
55
|
+
!!errors &&
|
|
56
|
+
((typeof errors === 'object' && Object.keys(errors).length > 0) ||
|
|
57
|
+
(Array.isArray(errors) && errors.length > 0))
|
|
58
|
+
) {
|
|
55
59
|
dispatch(setErrors(errors));
|
|
56
60
|
}
|
|
57
61
|
|