@akinon/next 2.0.33 → 2.0.34-rc.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 +28 -0
- package/bin/pz-generate-routes.js +4 -1
- package/components/plugin-module.tsx +0 -1
- package/data/client/checkout.ts +0 -1
- package/data/server/category.ts +13 -1
- package/data/server/list.ts +12 -0
- package/data/server/product.ts +10 -0
- package/data/server/special-page.ts +13 -0
- package/data/server/widget.ts +14 -1
- package/data/urls.ts +9 -4
- package/hooks/use-captcha.tsx +1 -1
- package/middlewares/default.ts +252 -205
- package/package.json +2 -2
- package/plugins.d.ts +10 -0
- package/plugins.js +1 -0
- package/redux/middlewares/checkout.ts +45 -3
- package/redux/middlewares/pre-order/installment-option.ts +9 -1
- package/types/index.ts +20 -9
- package/utils/csrf.ts +1 -1
- package/utils/payload-optimizer.ts +481 -0
- package/with-pz-config.js +3 -2
package/middlewares/default.ts
CHANGED
|
@@ -18,7 +18,11 @@ import {
|
|
|
18
18
|
withBfcacheHeaders
|
|
19
19
|
} from '.';
|
|
20
20
|
import { getCsrfCookieFlags, urlLocaleMatcherRegex } from '../utils';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
getPzSegmentsConfig,
|
|
23
|
+
encodePzValue,
|
|
24
|
+
isLegacyMode
|
|
25
|
+
} from '../utils/pz-segments';
|
|
22
26
|
import withCurrency from './currency';
|
|
23
27
|
import withLocale from './locale';
|
|
24
28
|
import logger from '../utils/log';
|
|
@@ -332,98 +336,98 @@ const withPzDefault =
|
|
|
332
336
|
req: PzNextRequest,
|
|
333
337
|
event: NextFetchEvent
|
|
334
338
|
) => {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
339
|
+
let middlewareResult: NextResponse | void =
|
|
340
|
+
NextResponse.next();
|
|
341
|
+
|
|
342
|
+
try {
|
|
343
|
+
const { locale, prettyUrl, currency } =
|
|
344
|
+
req.middlewareParams.rewrites;
|
|
345
|
+
const { defaultLocaleValue } =
|
|
346
|
+
Settings.localization;
|
|
347
|
+
const url = req.nextUrl.clone();
|
|
348
|
+
const pathnameWithoutLocale =
|
|
349
|
+
url.pathname.replace(
|
|
350
|
+
urlLocaleMatcherRegex,
|
|
351
|
+
''
|
|
352
|
+
);
|
|
349
353
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
+
middlewareResult = (await middleware(
|
|
355
|
+
req,
|
|
356
|
+
event
|
|
357
|
+
)) as NextResponse | void;
|
|
354
358
|
|
|
355
|
-
|
|
359
|
+
let customRewriteUrlDiff = '';
|
|
356
360
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
middlewareResult.headers.get(
|
|
364
|
-
'x-middleware-rewrite'
|
|
365
|
-
)
|
|
366
|
-
) {
|
|
367
|
-
const rewriteUrl = new URL(
|
|
361
|
+
if (
|
|
362
|
+
middlewareResult instanceof
|
|
363
|
+
NextResponse &&
|
|
364
|
+
middlewareResult.headers.get(
|
|
365
|
+
'pz-override-response'
|
|
366
|
+
) &&
|
|
368
367
|
middlewareResult.headers.get(
|
|
369
368
|
'x-middleware-rewrite'
|
|
370
369
|
)
|
|
371
|
-
)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
''
|
|
370
|
+
) {
|
|
371
|
+
const rewriteUrl = new URL(
|
|
372
|
+
middlewareResult.headers.get(
|
|
373
|
+
'x-middleware-rewrite'
|
|
374
|
+
)
|
|
377
375
|
);
|
|
378
|
-
|
|
376
|
+
const originalUrl = new URL(req.url);
|
|
377
|
+
customRewriteUrlDiff =
|
|
378
|
+
rewriteUrl.pathname.replace(
|
|
379
|
+
originalUrl.pathname,
|
|
380
|
+
''
|
|
381
|
+
);
|
|
382
|
+
}
|
|
379
383
|
|
|
380
|
-
|
|
384
|
+
let ordersPrefix: string;
|
|
381
385
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
}`.replace(/\/+/g, '/');
|
|
388
|
-
ordersPrefix = `/${currency}/orders`;
|
|
389
|
-
} else {
|
|
390
|
-
const pzConfig =
|
|
391
|
-
getPzSegmentsConfig(Settings);
|
|
392
|
-
const fullUrlPath =
|
|
393
|
-
`${customRewriteUrlDiff}${
|
|
386
|
+
if (isLegacyMode(Settings)) {
|
|
387
|
+
url.basePath = `/${commerceUrl}`;
|
|
388
|
+
url.pathname = `/${
|
|
389
|
+
locale.length ? `${locale}/` : ''
|
|
390
|
+
}${currency}/${customRewriteUrlDiff}${
|
|
394
391
|
prettyUrl ?? pathnameWithoutLocale
|
|
395
392
|
}`.replace(/\/+/g, '/');
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
393
|
+
ordersPrefix = `/${currency}/orders`;
|
|
394
|
+
} else {
|
|
395
|
+
const pzConfig =
|
|
396
|
+
getPzSegmentsConfig(Settings);
|
|
397
|
+
const fullUrlPath =
|
|
398
|
+
`${customRewriteUrlDiff}${
|
|
399
|
+
prettyUrl ?? pathnameWithoutLocale
|
|
400
|
+
}`.replace(/\/+/g, '/');
|
|
401
|
+
const fullUrl = `${req.nextUrl.origin}${fullUrlPath}`;
|
|
402
|
+
const resolvedLocale =
|
|
403
|
+
locale?.length > 0
|
|
404
|
+
? locale
|
|
405
|
+
: Settings.localization
|
|
406
|
+
.defaultLocaleValue;
|
|
407
|
+
const resolveContext = {
|
|
408
|
+
req,
|
|
409
|
+
event,
|
|
410
|
+
url,
|
|
411
|
+
locale: resolvedLocale,
|
|
412
|
+
currency,
|
|
413
|
+
pathname: pathnameWithoutLocale
|
|
414
|
+
};
|
|
415
|
+
const customSegments =
|
|
416
|
+
pzConfig.segments.filter(
|
|
417
|
+
(seg) =>
|
|
418
|
+
seg.name !== 'locale' &&
|
|
419
|
+
seg.name !== 'currency' &&
|
|
420
|
+
seg.name !== 'url'
|
|
421
|
+
);
|
|
422
|
+
const segmentValues: Record<
|
|
423
|
+
string,
|
|
424
|
+
string
|
|
425
|
+
> = {
|
|
426
|
+
locale: resolvedLocale,
|
|
427
|
+
currency,
|
|
428
|
+
url: encodeURIComponent(fullUrl),
|
|
429
|
+
...Object.fromEntries(
|
|
430
|
+
customSegments.map((seg) => [
|
|
427
431
|
seg.name,
|
|
428
432
|
req.middlewareParams.rewrites[
|
|
429
433
|
seg.name
|
|
@@ -432,105 +436,121 @@ const withPzDefault =
|
|
|
432
436
|
? seg.resolve(resolveContext)
|
|
433
437
|
: '')
|
|
434
438
|
])
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const pzValue = encodePzValue(
|
|
439
|
-
segmentValues,
|
|
440
|
-
pzConfig
|
|
441
|
-
);
|
|
439
|
+
)
|
|
440
|
+
};
|
|
442
441
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
'/'
|
|
442
|
+
const pzValue = encodePzValue(
|
|
443
|
+
segmentValues,
|
|
444
|
+
pzConfig
|
|
447
445
|
);
|
|
448
|
-
ordersPrefix = `/${pzValue}/orders`;
|
|
449
|
-
}
|
|
450
446
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
)
|
|
459
|
-
)
|
|
460
|
-
) {
|
|
461
|
-
url.pathname =
|
|
462
|
-
url.pathname +
|
|
463
|
-
(/\/$/.test(url.pathname) ? '' : '/') +
|
|
464
|
-
`searchparams|${encodeURIComponent(
|
|
465
|
-
url.searchParams.toString()
|
|
466
|
-
)}`;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
Settings.rewrites.forEach((rewrite) => {
|
|
470
|
-
url.pathname = url.pathname.replace(
|
|
471
|
-
rewrite.source,
|
|
472
|
-
rewrite.destination
|
|
473
|
-
);
|
|
474
|
-
});
|
|
447
|
+
url.pathname =
|
|
448
|
+
`/${pzValue}/${fullUrlPath}`.replace(
|
|
449
|
+
/\/+/g,
|
|
450
|
+
'/'
|
|
451
|
+
);
|
|
452
|
+
ordersPrefix = `/${pzValue}/orders`;
|
|
453
|
+
}
|
|
475
454
|
|
|
476
|
-
// if middleware.ts has a return value for current url
|
|
477
|
-
if (
|
|
478
|
-
middlewareResult instanceof NextResponse
|
|
479
|
-
) {
|
|
480
|
-
// pz-override-response header is used to prevent 404 page for custom responses.
|
|
481
455
|
if (
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
456
|
+
Settings.usePrettyUrlRoute &&
|
|
457
|
+
url.searchParams.toString().length >
|
|
458
|
+
0 &&
|
|
459
|
+
!Object.entries(ROUTES).find(
|
|
460
|
+
([, value]) =>
|
|
461
|
+
new RegExp(`^${value}/?$`).test(
|
|
462
|
+
pathnameWithoutLocale
|
|
463
|
+
)
|
|
464
|
+
)
|
|
485
465
|
) {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
url.
|
|
466
|
+
url.pathname =
|
|
467
|
+
url.pathname +
|
|
468
|
+
(/\/$/.test(url.pathname)
|
|
469
|
+
? ''
|
|
470
|
+
: '/') +
|
|
471
|
+
`searchparams|${encodeURIComponent(
|
|
472
|
+
url.searchParams.toString()
|
|
473
|
+
)}`;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
Settings.rewrites.forEach((rewrite) => {
|
|
477
|
+
url.pathname = url.pathname.replace(
|
|
478
|
+
rewrite.source,
|
|
479
|
+
rewrite.destination
|
|
489
480
|
);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
middlewareResult
|
|
495
|
-
'pz-override-response'
|
|
496
|
-
) === 'true'
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// if middleware.ts has a return value for current url
|
|
484
|
+
if (
|
|
485
|
+
middlewareResult instanceof NextResponse
|
|
497
486
|
) {
|
|
487
|
+
// pz-override-response header is used to prevent 404 page for custom responses.
|
|
488
|
+
if (
|
|
489
|
+
middlewareResult.headers.get(
|
|
490
|
+
'pz-override-response'
|
|
491
|
+
) !== 'true'
|
|
492
|
+
) {
|
|
493
|
+
middlewareResult.headers.set(
|
|
494
|
+
'x-middleware-rewrite',
|
|
495
|
+
url.href
|
|
496
|
+
);
|
|
497
|
+
} else if (
|
|
498
|
+
middlewareResult.headers.get(
|
|
499
|
+
'x-middleware-rewrite'
|
|
500
|
+
) &&
|
|
501
|
+
middlewareResult.headers.get(
|
|
502
|
+
'pz-override-response'
|
|
503
|
+
) === 'true'
|
|
504
|
+
) {
|
|
505
|
+
middlewareResult =
|
|
506
|
+
NextResponse.rewrite(url);
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
// if middleware.ts doesn't have a return value.
|
|
510
|
+
// e.g. NextResponse.next() doesn't exist in middleware.ts
|
|
511
|
+
|
|
498
512
|
middlewareResult =
|
|
499
513
|
NextResponse.rewrite(url);
|
|
500
514
|
}
|
|
501
|
-
} else {
|
|
502
|
-
// if middleware.ts doesn't have a return value.
|
|
503
|
-
// e.g. NextResponse.next() doesn't exist in middleware.ts
|
|
504
515
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
516
|
+
const { localeUrlStrategy } =
|
|
517
|
+
Settings.localization;
|
|
518
|
+
|
|
519
|
+
const fallbackHost =
|
|
520
|
+
req.headers.get('x-forwarded-host') ||
|
|
521
|
+
req.headers.get('host');
|
|
522
|
+
const hostname =
|
|
523
|
+
process.env.NEXT_PUBLIC_URL ||
|
|
524
|
+
`https://${fallbackHost}`;
|
|
525
|
+
const rootHostname =
|
|
526
|
+
localeUrlStrategy ===
|
|
527
|
+
LocaleUrlStrategy.Subdomain
|
|
528
|
+
? getRootHostname(hostname)
|
|
529
|
+
: null;
|
|
508
530
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
531
|
+
if (
|
|
532
|
+
!url.pathname.startsWith(ordersPrefix)
|
|
533
|
+
) {
|
|
534
|
+
middlewareResult.cookies.set(
|
|
535
|
+
'pz-locale',
|
|
536
|
+
locale?.length > 0
|
|
537
|
+
? locale
|
|
538
|
+
: defaultLocaleValue,
|
|
539
|
+
{
|
|
540
|
+
domain: rootHostname,
|
|
541
|
+
sameSite: 'none',
|
|
542
|
+
secure: true,
|
|
543
|
+
expires: new Date(
|
|
544
|
+
Date.now() +
|
|
545
|
+
1000 * 60 * 60 * 24 * 7
|
|
546
|
+
) // 7 days
|
|
547
|
+
}
|
|
548
|
+
);
|
|
549
|
+
}
|
|
523
550
|
|
|
524
|
-
if (
|
|
525
|
-
!url.pathname.startsWith(
|
|
526
|
-
ordersPrefix
|
|
527
|
-
)
|
|
528
|
-
) {
|
|
529
551
|
middlewareResult.cookies.set(
|
|
530
|
-
'pz-
|
|
531
|
-
|
|
532
|
-
? locale
|
|
533
|
-
: defaultLocaleValue,
|
|
552
|
+
'pz-currency',
|
|
553
|
+
currency,
|
|
534
554
|
{
|
|
535
555
|
domain: rootHostname,
|
|
536
556
|
sameSite: 'none',
|
|
@@ -540,7 +560,6 @@ const withPzDefault =
|
|
|
540
560
|
) // 7 days
|
|
541
561
|
}
|
|
542
562
|
);
|
|
543
|
-
}
|
|
544
563
|
|
|
545
564
|
middlewareResult.cookies.set(
|
|
546
565
|
'pz-currency',
|
|
@@ -583,59 +602,87 @@ const withPzDefault =
|
|
|
583
602
|
req.cookies.get('pz-post-checkout-flow')
|
|
584
603
|
) {
|
|
585
604
|
if (
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
pathnameWithoutLocale.startsWith(
|
|
590
|
-
'/basket'
|
|
591
|
-
)
|
|
605
|
+
req.cookies.get('pz-locale') &&
|
|
606
|
+
req.cookies.get('pz-locale').value !==
|
|
607
|
+
locale
|
|
592
608
|
) {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
609
|
+
logger.debug('Locale changed', {
|
|
610
|
+
locale,
|
|
611
|
+
oldLocale:
|
|
612
|
+
req.cookies.get('pz-locale')?.value,
|
|
613
|
+
ip
|
|
614
|
+
});
|
|
596
615
|
}
|
|
597
|
-
}
|
|
598
616
|
|
|
599
|
-
if (process.env.ACC_APP_VERSION) {
|
|
600
617
|
middlewareResult.headers.set(
|
|
601
|
-
'
|
|
602
|
-
|
|
618
|
+
'pz-url',
|
|
619
|
+
req.nextUrl.toString()
|
|
603
620
|
);
|
|
604
|
-
}
|
|
605
621
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
622
|
+
if (req.cookies.get('pz-set-currency')) {
|
|
623
|
+
middlewareResult.cookies.delete(
|
|
624
|
+
'pz-set-currency'
|
|
625
|
+
);
|
|
626
|
+
}
|
|
609
627
|
|
|
610
|
-
if (
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
628
|
+
if (
|
|
629
|
+
req.cookies.get('pz-post-checkout-flow')
|
|
630
|
+
) {
|
|
631
|
+
if (
|
|
632
|
+
pathnameWithoutLocale.startsWith(
|
|
633
|
+
'/orders/completed/'
|
|
634
|
+
) ||
|
|
635
|
+
pathnameWithoutLocale.startsWith(
|
|
636
|
+
'/basket'
|
|
637
|
+
)
|
|
638
|
+
) {
|
|
639
|
+
middlewareResult.cookies.delete(
|
|
640
|
+
'pz-post-checkout-flow'
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
if (process.env.ACC_APP_VERSION) {
|
|
646
|
+
middlewareResult.headers.set(
|
|
647
|
+
'acc-app-version',
|
|
648
|
+
process.env.ACC_APP_VERSION
|
|
622
649
|
);
|
|
623
650
|
}
|
|
651
|
+
|
|
652
|
+
// Set CSRF token if not set
|
|
653
|
+
try {
|
|
654
|
+
const url = `${Settings.commerceUrl}${user.csrfToken}`;
|
|
655
|
+
|
|
656
|
+
if (!req.cookies.get('csrftoken')) {
|
|
657
|
+
const { csrf_token } = await (
|
|
658
|
+
await fetch(url)
|
|
659
|
+
).json();
|
|
660
|
+
middlewareResult.cookies.set(
|
|
661
|
+
'csrftoken',
|
|
662
|
+
csrf_token,
|
|
663
|
+
{
|
|
664
|
+
path: '/',
|
|
665
|
+
domain: rootHostname,
|
|
666
|
+
...getCsrfCookieFlags()
|
|
667
|
+
}
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
} catch (error) {
|
|
671
|
+
logger.error('CSRF Error', {
|
|
672
|
+
error,
|
|
673
|
+
ip
|
|
674
|
+
});
|
|
675
|
+
}
|
|
624
676
|
} catch (error) {
|
|
625
|
-
logger.error('
|
|
677
|
+
logger.error('withPzDefault Error', {
|
|
626
678
|
error,
|
|
627
679
|
ip
|
|
628
680
|
});
|
|
629
681
|
}
|
|
630
|
-
} catch (error) {
|
|
631
|
-
logger.error('withPzDefault Error', {
|
|
632
|
-
error,
|
|
633
|
-
ip
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
682
|
|
|
637
|
-
|
|
638
|
-
|
|
683
|
+
return middlewareResult;
|
|
684
|
+
}
|
|
685
|
+
)
|
|
639
686
|
)
|
|
640
687
|
)
|
|
641
688
|
)
|
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": "2.0.
|
|
4
|
+
"version": "2.0.34-rc.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"set-cookie-parser": "2.6.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@akinon/eslint-plugin-projectzero": "2.0.
|
|
39
|
+
"@akinon/eslint-plugin-projectzero": "2.0.34-rc.0",
|
|
40
40
|
"@babel/core": "7.26.10",
|
|
41
41
|
"@babel/preset-env": "7.26.9",
|
|
42
42
|
"@babel/preset-typescript": "7.27.0",
|
package/plugins.d.ts
CHANGED
|
@@ -37,6 +37,16 @@ declare module '@akinon/pz-cybersource-uc/src/redux/middleware' {
|
|
|
37
37
|
export default middleware as any;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
declare module '@akinon/pz-apple-pay' {}
|
|
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
|
+
}
|
|
49
|
+
|
|
40
50
|
declare module '@akinon/pz-cybersource-uc/src/redux/reducer' {
|
|
41
51
|
export default reducer as any;
|
|
42
52
|
}
|