@akinon/next 2.0.32-rc.0 → 2.0.33-beta.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.
@@ -18,11 +18,7 @@ import {
18
18
  withBfcacheHeaders
19
19
  } from '.';
20
20
  import { getCsrfCookieFlags, urlLocaleMatcherRegex } from '../utils';
21
- import {
22
- getPzSegmentsConfig,
23
- encodePzValue,
24
- isLegacyMode
25
- } from '../utils/pz-segments';
21
+ import { getPzSegmentsConfig, encodePzValue, isLegacyMode } from '../utils/pz-segments';
26
22
  import withCurrency from './currency';
27
23
  import withLocale from './locale';
28
24
  import logger from '../utils/log';
@@ -106,9 +102,79 @@ const withPzDefault =
106
102
  }
107
103
  }
108
104
 
105
+ if (req.nextUrl.pathname.includes('/orders/checkout-with-token/')) {
106
+ const queryString = searchParams.toString();
107
+ const currency = searchParams.get('currency')?.toLowerCase();
108
+ const commercePath = req.nextUrl.pathname.replace(
109
+ urlLocaleMatcherRegex,
110
+ ''
111
+ );
112
+ const targetUrl = `${Settings.commerceUrl}${commercePath}${
113
+ queryString ? `?${queryString}` : ''
114
+ }`;
115
+
116
+ try {
117
+ const commerceResponse = await fetch(targetUrl, {
118
+ redirect: 'manual',
119
+ headers: {
120
+ cookie: req.headers.get('cookie') || ''
121
+ }
122
+ });
123
+
124
+ const location = commerceResponse.headers.get('location');
125
+
126
+ if (location) {
127
+ const locationUrl = new URL(location, Settings.commerceUrl);
128
+ locationUrl.searchParams.set('source', 'instore');
129
+ const redirectTarget = `${req.nextUrl.origin}${locationUrl.pathname}${locationUrl.search}`;
130
+ const response = NextResponse.redirect(redirectTarget);
131
+
132
+ // Set pz-currency FIRST via cookies API — NextResponse.cookies.set()
133
+ // overwrites manually appended Set-Cookie headers, so it must run
134
+ // before headers.append('Set-Cookie', ...) calls.
135
+ if (currency) {
136
+ response.cookies.set('pz-currency', currency, {
137
+ sameSite: 'none',
138
+ secure: true,
139
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7)
140
+ });
141
+ }
142
+
143
+ // Forward set-cookie headers from the upstream response
144
+ const setCookies =
145
+ commerceResponse.headers.getSetCookie?.() ?? [];
146
+ setCookies.forEach((cookie) => {
147
+ response.headers.append('Set-Cookie', cookie);
148
+ });
149
+
150
+ return response;
151
+ }
152
+
153
+ logger.warn('checkout-with-token: no redirect from commerce', {
154
+ ip,
155
+ url: targetUrl
156
+ });
157
+ } catch {
158
+ logger.warn(
159
+ 'checkout-with-token: fetch failed, falling back to rewrite',
160
+ { ip, url: targetUrl }
161
+ );
162
+ }
163
+ const response = NextResponse.rewrite(new URL(targetUrl));
164
+
165
+ if (currency) {
166
+ response.cookies.set('pz-currency', currency, {
167
+ sameSite: 'none',
168
+ secure: true,
169
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7)
170
+ });
171
+ }
172
+
173
+ return response;
174
+ }
175
+
109
176
  if (
110
177
  req.nextUrl.pathname.includes('/orders/hooks/') ||
111
- req.nextUrl.pathname.includes('/orders/checkout-with-token/') ||
112
178
  req.nextUrl.pathname.includes('/orders/post-checkout-redirect/') ||
113
179
  req.nextUrl.pathname.includes('/hooks/cash_register/complete/') ||
114
180
  req.nextUrl.pathname.includes('/hooks/cash_register/pre_order/')
@@ -266,98 +332,98 @@ const withPzDefault =
266
332
  req: PzNextRequest,
267
333
  event: NextFetchEvent
268
334
  ) => {
269
- let middlewareResult: NextResponse | void =
270
- NextResponse.next();
271
-
272
- try {
273
- const { locale, prettyUrl, currency } =
274
- req.middlewareParams.rewrites;
275
- const { defaultLocaleValue } =
276
- Settings.localization;
277
- const url = req.nextUrl.clone();
278
- const pathnameWithoutLocale =
279
- url.pathname.replace(
280
- urlLocaleMatcherRegex,
281
- ''
282
- );
283
-
284
- middlewareResult = (await middleware(
285
- req,
286
- event
287
- )) as NextResponse | void;
288
-
289
- let customRewriteUrlDiff = '';
335
+ let middlewareResult: NextResponse | void =
336
+ NextResponse.next();
337
+
338
+ try {
339
+ const { locale, prettyUrl, currency } =
340
+ req.middlewareParams.rewrites;
341
+ const { defaultLocaleValue } =
342
+ Settings.localization;
343
+ const url = req.nextUrl.clone();
344
+ const pathnameWithoutLocale =
345
+ url.pathname.replace(
346
+ urlLocaleMatcherRegex,
347
+ ''
348
+ );
290
349
 
291
- if (
292
- middlewareResult instanceof
293
- NextResponse &&
294
- middlewareResult.headers.get(
295
- 'pz-override-response'
296
- ) &&
350
+ middlewareResult = (await middleware(
351
+ req,
352
+ event
353
+ )) as NextResponse | void;
354
+
355
+ let customRewriteUrlDiff = '';
356
+
357
+ if (
358
+ middlewareResult instanceof
359
+ NextResponse &&
360
+ middlewareResult.headers.get(
361
+ 'pz-override-response'
362
+ ) &&
363
+ middlewareResult.headers.get(
364
+ 'x-middleware-rewrite'
365
+ )
366
+ ) {
367
+ const rewriteUrl = new URL(
297
368
  middlewareResult.headers.get(
298
369
  'x-middleware-rewrite'
299
370
  )
300
- ) {
301
- const rewriteUrl = new URL(
302
- middlewareResult.headers.get(
303
- 'x-middleware-rewrite'
304
- )
371
+ );
372
+ const originalUrl = new URL(req.url);
373
+ customRewriteUrlDiff =
374
+ rewriteUrl.pathname.replace(
375
+ originalUrl.pathname,
376
+ ''
305
377
  );
306
- const originalUrl = new URL(req.url);
307
- customRewriteUrlDiff =
308
- rewriteUrl.pathname.replace(
309
- originalUrl.pathname,
310
- ''
311
- );
312
- }
378
+ }
313
379
 
314
- let ordersPrefix: string;
380
+ let ordersPrefix: string;
315
381
 
316
- if (isLegacyMode(Settings)) {
317
- url.basePath = `/${commerceUrl}`;
318
- url.pathname = `/${
319
- locale.length ? `${locale}/` : ''
320
- }${currency}/${customRewriteUrlDiff}${
382
+ if (isLegacyMode(Settings)) {
383
+ url.basePath = `/${commerceUrl}`;
384
+ url.pathname =
385
+ `/${locale.length ? `${locale}/` : ''}${currency}/${customRewriteUrlDiff}${
321
386
  prettyUrl ?? pathnameWithoutLocale
322
387
  }`.replace(/\/+/g, '/');
323
- ordersPrefix = `/${currency}/orders`;
324
- } else {
325
- const pzConfig =
326
- getPzSegmentsConfig(Settings);
327
- const fullUrlPath =
328
- `${customRewriteUrlDiff}${
329
- prettyUrl ?? pathnameWithoutLocale
330
- }`.replace(/\/+/g, '/');
331
- const fullUrl = `${req.nextUrl.origin}${fullUrlPath}`;
332
- const resolvedLocale =
333
- locale?.length > 0
334
- ? locale
335
- : Settings.localization
336
- .defaultLocaleValue;
337
- const resolveContext = {
338
- req,
339
- event,
340
- url,
341
- locale: resolvedLocale,
342
- currency,
343
- pathname: pathnameWithoutLocale
344
- };
345
- const customSegments =
346
- pzConfig.segments.filter(
347
- (seg) =>
348
- seg.name !== 'locale' &&
349
- seg.name !== 'currency' &&
350
- seg.name !== 'url'
351
- );
352
- const segmentValues: Record<
353
- string,
354
- string
355
- > = {
356
- locale: resolvedLocale,
357
- currency,
358
- url: encodeURIComponent(fullUrl),
359
- ...Object.fromEntries(
360
- customSegments.map((seg) => [
388
+ ordersPrefix = `/${currency}/orders`;
389
+ } else {
390
+ const pzConfig =
391
+ getPzSegmentsConfig(Settings);
392
+ const fullUrlPath =
393
+ `${customRewriteUrlDiff}${
394
+ prettyUrl ?? pathnameWithoutLocale
395
+ }`.replace(/\/+/g, '/');
396
+ const fullUrl = `${req.nextUrl.origin}${fullUrlPath}`;
397
+ const resolvedLocale =
398
+ locale?.length > 0
399
+ ? locale
400
+ : Settings.localization
401
+ .defaultLocaleValue;
402
+ const resolveContext = {
403
+ req,
404
+ event,
405
+ url,
406
+ locale: resolvedLocale,
407
+ currency,
408
+ pathname: pathnameWithoutLocale
409
+ };
410
+ const customSegments = pzConfig.segments
411
+ .filter(
412
+ (seg) =>
413
+ seg.name !== 'locale' &&
414
+ seg.name !== 'currency' &&
415
+ seg.name !== 'url'
416
+ );
417
+ const segmentValues: Record<
418
+ string,
419
+ string
420
+ > = {
421
+ locale: resolvedLocale,
422
+ currency,
423
+ url: encodeURIComponent(fullUrl),
424
+ ...Object.fromEntries(
425
+ customSegments
426
+ .map((seg) => [
361
427
  seg.name,
362
428
  req.middlewareParams.rewrites[
363
429
  seg.name
@@ -366,121 +432,105 @@ const withPzDefault =
366
432
  ? seg.resolve(resolveContext)
367
433
  : '')
368
434
  ])
369
- )
370
- };
435
+ )
436
+ };
371
437
 
372
- const pzValue = encodePzValue(
373
- segmentValues,
374
- pzConfig
438
+ const pzValue = encodePzValue(
439
+ segmentValues,
440
+ pzConfig
441
+ );
442
+
443
+ url.pathname =
444
+ `/${pzValue}/${fullUrlPath}`.replace(
445
+ /\/+/g,
446
+ '/'
375
447
  );
448
+ ordersPrefix = `/${pzValue}/orders`;
449
+ }
376
450
 
377
- url.pathname =
378
- `/${pzValue}/${fullUrlPath}`.replace(
379
- /\/+/g,
380
- '/'
381
- );
382
- ordersPrefix = `/${pzValue}/orders`;
383
- }
451
+ if (
452
+ Settings.usePrettyUrlRoute &&
453
+ url.searchParams.toString().length > 0 &&
454
+ !Object.entries(ROUTES).find(
455
+ ([, value]) =>
456
+ new RegExp(`^${value}/?$`).test(
457
+ pathnameWithoutLocale
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
+ });
384
475
 
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.
385
481
  if (
386
- Settings.usePrettyUrlRoute &&
387
- url.searchParams.toString().length >
388
- 0 &&
389
- !Object.entries(ROUTES).find(
390
- ([, value]) =>
391
- new RegExp(`^${value}/?$`).test(
392
- pathnameWithoutLocale
393
- )
394
- )
482
+ middlewareResult.headers.get(
483
+ 'pz-override-response'
484
+ ) !== 'true'
395
485
  ) {
396
- url.pathname =
397
- url.pathname +
398
- (/\/$/.test(url.pathname)
399
- ? ''
400
- : '/') +
401
- `searchparams|${encodeURIComponent(
402
- url.searchParams.toString()
403
- )}`;
404
- }
405
-
406
- Settings.rewrites.forEach((rewrite) => {
407
- url.pathname = url.pathname.replace(
408
- rewrite.source,
409
- rewrite.destination
486
+ middlewareResult.headers.set(
487
+ 'x-middleware-rewrite',
488
+ url.href
410
489
  );
411
- });
412
-
413
- // if middleware.ts has a return value for current url
414
- if (
415
- middlewareResult instanceof NextResponse
490
+ } else if (
491
+ middlewareResult.headers.get(
492
+ 'x-middleware-rewrite'
493
+ ) &&
494
+ middlewareResult.headers.get(
495
+ 'pz-override-response'
496
+ ) === 'true'
416
497
  ) {
417
- // pz-override-response header is used to prevent 404 page for custom responses.
418
- if (
419
- middlewareResult.headers.get(
420
- 'pz-override-response'
421
- ) !== 'true'
422
- ) {
423
- middlewareResult.headers.set(
424
- 'x-middleware-rewrite',
425
- url.href
426
- );
427
- } else if (
428
- middlewareResult.headers.get(
429
- 'x-middleware-rewrite'
430
- ) &&
431
- middlewareResult.headers.get(
432
- 'pz-override-response'
433
- ) === 'true'
434
- ) {
435
- middlewareResult =
436
- NextResponse.rewrite(url);
437
- }
438
- } else {
439
- // if middleware.ts doesn't have a return value.
440
- // e.g. NextResponse.next() doesn't exist in middleware.ts
441
-
442
498
  middlewareResult =
443
499
  NextResponse.rewrite(url);
444
500
  }
501
+ } else {
502
+ // if middleware.ts doesn't have a return value.
503
+ // e.g. NextResponse.next() doesn't exist in middleware.ts
445
504
 
446
- const { localeUrlStrategy } =
447
- Settings.localization;
448
-
449
- const fallbackHost =
450
- req.headers.get('x-forwarded-host') ||
451
- req.headers.get('host');
452
- const hostname =
453
- process.env.NEXT_PUBLIC_URL ||
454
- `https://${fallbackHost}`;
455
- const rootHostname =
456
- localeUrlStrategy ===
457
- LocaleUrlStrategy.Subdomain
458
- ? getRootHostname(hostname)
459
- : null;
460
-
461
- if (
462
- !url.pathname.startsWith(ordersPrefix)
463
- ) {
464
- middlewareResult.cookies.set(
465
- 'pz-locale',
466
- locale?.length > 0
467
- ? locale
468
- : defaultLocaleValue,
469
- {
470
- domain: rootHostname,
471
- sameSite: 'none',
472
- secure: true,
473
- expires: new Date(
474
- Date.now() +
475
- 1000 * 60 * 60 * 24 * 7
476
- ) // 7 days
477
- }
478
- );
479
- }
505
+ middlewareResult =
506
+ NextResponse.rewrite(url);
507
+ }
480
508
 
509
+ const { localeUrlStrategy } =
510
+ Settings.localization;
511
+
512
+ const fallbackHost =
513
+ req.headers.get('x-forwarded-host') ||
514
+ req.headers.get('host');
515
+ const hostname =
516
+ process.env.NEXT_PUBLIC_URL ||
517
+ `https://${fallbackHost}`;
518
+ const rootHostname =
519
+ localeUrlStrategy ===
520
+ LocaleUrlStrategy.Subdomain
521
+ ? getRootHostname(hostname)
522
+ : null;
523
+
524
+ if (
525
+ !url.pathname.startsWith(
526
+ ordersPrefix
527
+ )
528
+ ) {
481
529
  middlewareResult.cookies.set(
482
- 'pz-currency',
483
- currency,
530
+ 'pz-locale',
531
+ locale?.length > 0
532
+ ? locale
533
+ : defaultLocaleValue,
484
534
  {
485
535
  domain: rootHostname,
486
536
  sameSite: 'none',
@@ -490,89 +540,102 @@ const withPzDefault =
490
540
  ) // 7 days
491
541
  }
492
542
  );
543
+ }
493
544
 
494
- if (
495
- req.cookies.get('pz-locale') &&
496
- req.cookies.get('pz-locale').value !==
497
- locale
498
- ) {
499
- logger.debug('Locale changed', {
500
- locale,
501
- oldLocale:
502
- req.cookies.get('pz-locale')?.value,
503
- ip
504
- });
545
+ middlewareResult.cookies.set(
546
+ 'pz-currency',
547
+ currency,
548
+ {
549
+ domain: rootHostname,
550
+ sameSite: 'none',
551
+ secure: true,
552
+ expires: new Date(
553
+ Date.now() + 1000 * 60 * 60 * 24 * 7
554
+ ) // 7 days
505
555
  }
556
+ );
557
+
558
+ if (
559
+ req.cookies.get('pz-locale') &&
560
+ req.cookies.get('pz-locale').value !==
561
+ locale
562
+ ) {
563
+ logger.debug('Locale changed', {
564
+ locale,
565
+ oldLocale:
566
+ req.cookies.get('pz-locale')?.value,
567
+ ip
568
+ });
569
+ }
506
570
 
507
- middlewareResult.headers.set(
508
- 'pz-url',
509
- req.nextUrl.toString()
571
+ middlewareResult.headers.set(
572
+ 'pz-url',
573
+ req.nextUrl.toString()
574
+ );
575
+
576
+ if (req.cookies.get('pz-set-currency')) {
577
+ middlewareResult.cookies.delete(
578
+ 'pz-set-currency'
510
579
  );
580
+ }
511
581
 
512
- if (req.cookies.get('pz-set-currency')) {
582
+ if (
583
+ req.cookies.get('pz-post-checkout-flow')
584
+ ) {
585
+ if (
586
+ pathnameWithoutLocale.startsWith(
587
+ '/orders/completed/'
588
+ ) ||
589
+ pathnameWithoutLocale.startsWith(
590
+ '/basket'
591
+ )
592
+ ) {
513
593
  middlewareResult.cookies.delete(
514
- 'pz-set-currency'
594
+ 'pz-post-checkout-flow'
515
595
  );
516
596
  }
597
+ }
517
598
 
518
- if (
519
- req.cookies.get('pz-post-checkout-flow')
520
- ) {
521
- if (
522
- pathnameWithoutLocale.startsWith(
523
- '/orders/completed/'
524
- ) ||
525
- pathnameWithoutLocale.startsWith(
526
- '/basket'
527
- )
528
- ) {
529
- middlewareResult.cookies.delete(
530
- 'pz-post-checkout-flow'
531
- );
532
- }
533
- }
599
+ if (process.env.ACC_APP_VERSION) {
600
+ middlewareResult.headers.set(
601
+ 'acc-app-version',
602
+ process.env.ACC_APP_VERSION
603
+ );
604
+ }
534
605
 
535
- if (process.env.ACC_APP_VERSION) {
536
- middlewareResult.headers.set(
537
- 'acc-app-version',
538
- process.env.ACC_APP_VERSION
539
- );
540
- }
606
+ // Set CSRF token if not set
607
+ try {
608
+ const url = `${Settings.commerceUrl}${user.csrfToken}`;
541
609
 
542
- // Set CSRF token if not set
543
- try {
544
- const url = `${Settings.commerceUrl}${user.csrfToken}`;
545
-
546
- if (!req.cookies.get('csrftoken')) {
547
- const { csrf_token } = await (
548
- await fetch(url)
549
- ).json();
550
- middlewareResult.cookies.set(
551
- 'csrftoken',
552
- csrf_token,
553
- {
554
- path: '/',
555
- domain: rootHostname,
556
- ...getCsrfCookieFlags()
557
- }
558
- );
559
- }
560
- } catch (error) {
561
- logger.error('CSRF Error', {
562
- error,
563
- ip
564
- });
610
+ if (!req.cookies.get('csrftoken')) {
611
+ const { csrf_token } = await (
612
+ await fetch(url)
613
+ ).json();
614
+ middlewareResult.cookies.set(
615
+ 'csrftoken',
616
+ csrf_token,
617
+ {
618
+ path: '/',
619
+ domain: rootHostname,
620
+ ...getCsrfCookieFlags()
621
+ }
622
+ );
565
623
  }
566
624
  } catch (error) {
567
- logger.error('withPzDefault Error', {
625
+ logger.error('CSRF Error', {
568
626
  error,
569
627
  ip
570
628
  });
571
629
  }
572
-
573
- return middlewareResult;
630
+ } catch (error) {
631
+ logger.error('withPzDefault Error', {
632
+ error,
633
+ ip
634
+ });
574
635
  }
575
- )
636
+
637
+ return middlewareResult;
638
+ })
576
639
  )
577
640
  )
578
641
  )