@akinon/next 1.76.0 → 1.77.0-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.
@@ -1,6 +1,8 @@
1
1
  import clsx from 'clsx';
2
2
  import { forwardRef, FocusEvent, useState, Ref } from 'react';
3
3
  import { Controller } from 'react-hook-form';
4
+
5
+ // @ts-ignore
4
6
  import { PatternFormat, PatternFormatProps } from 'react-number-format';
5
7
  import { InputProps } from '../types';
6
8
  import { twMerge } from 'tailwind-merge';
@@ -10,7 +10,9 @@ type LinkProps = Omit<
10
10
  React.AnchorHTMLAttributes<HTMLAnchorElement>,
11
11
  keyof NextLinkProps
12
12
  > &
13
- NextLinkProps;
13
+ NextLinkProps & {
14
+ href: string;
15
+ };
14
16
 
15
17
  export const Link = ({ children, href, ...rest }: LinkProps) => {
16
18
  const { locale, defaultLocaleValue, localeUrlStrategy } = useLocalization();
@@ -26,19 +28,21 @@ export const Link = ({ children, href, ...rest }: LinkProps) => {
26
28
  return href;
27
29
  }
28
30
 
29
- const pathnameWithoutLocale = href.replace(urlLocaleMatcherRegex, '');
30
- const hrefWithLocale = `/${locale}${pathnameWithoutLocale}`;
31
-
32
- if (localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales) {
33
- return hrefWithLocale;
34
- } else if (
35
- localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale &&
36
- locale !== defaultLocaleValue
37
- ) {
38
- return hrefWithLocale;
31
+ if (typeof href === 'string' && !href.startsWith('http')) {
32
+ const pathnameWithoutLocale = href.replace(urlLocaleMatcherRegex, '');
33
+ const hrefWithLocale = `/${locale}${pathnameWithoutLocale}`;
34
+
35
+ if (localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales) {
36
+ return hrefWithLocale;
37
+ } else if (
38
+ localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale &&
39
+ locale !== defaultLocaleValue
40
+ ) {
41
+ return hrefWithLocale;
42
+ }
39
43
  }
40
44
 
41
- return href || '#';
45
+ return href;
42
46
  }, [href, defaultLocaleValue, locale, localeUrlStrategy]);
43
47
 
44
48
  return (
@@ -0,0 +1,72 @@
1
+ import { Cache, CacheKey } from '../../lib/cache';
2
+ import { basket } from '../../data/urls';
3
+ import { Basket } from '../../types';
4
+ import appFetch from '../../utils/app-fetch';
5
+ import { ServerVariables } from '../../utils/server-variables';
6
+ import logger from '../../utils/log';
7
+
8
+ type GetBasketParams = {
9
+ locale?: string;
10
+ currency?: string;
11
+ namespace?: string;
12
+ };
13
+
14
+ const getBasketDataHandler = ({
15
+ locale,
16
+ currency,
17
+ namespace
18
+ }: GetBasketParams) => {
19
+ return async function () {
20
+ try {
21
+ const url = namespace
22
+ ? basket.getBasketDetail(namespace)
23
+ : basket.getBasket;
24
+
25
+ const basketData = await appFetch<{ basket: Basket }>({
26
+ url,
27
+ locale,
28
+ currency,
29
+ init: {
30
+ headers: {
31
+ Accept: 'application/json',
32
+ 'Content-Type': 'application/json'
33
+ }
34
+ }
35
+ });
36
+
37
+ if (!basketData?.basket) {
38
+ logger.warn('Basket data is undefined', {
39
+ handler: 'getBasketDataHandler',
40
+ namespace
41
+ });
42
+ }
43
+
44
+ return basketData;
45
+ } catch (error) {
46
+ logger.error('Error fetching basket data', {
47
+ handler: 'getBasketDataHandler',
48
+ error,
49
+ namespace
50
+ });
51
+ throw error;
52
+ }
53
+ };
54
+ };
55
+
56
+ export const getBasketData = async ({
57
+ locale = ServerVariables.locale,
58
+ currency = ServerVariables.currency,
59
+ namespace
60
+ }: GetBasketParams = {}) => {
61
+ return Cache.wrap(
62
+ CacheKey.Basket(namespace),
63
+ locale,
64
+ getBasketDataHandler({ locale, currency, namespace }),
65
+ {
66
+ expire: 0,
67
+ cache: false
68
+ }
69
+ );
70
+ };
71
+
72
+
@@ -7,7 +7,8 @@ import { ServerVariables } from '../../utils/server-variables';
7
7
  const getFlatPageDataHandler = (
8
8
  pk: number,
9
9
  locale: string,
10
- currency: string
10
+ currency: string,
11
+ headers?: Record<string, string>
11
12
  ) => {
12
13
  return async function () {
13
14
  const data = await appFetch<FlatPage>({
@@ -17,7 +18,8 @@ const getFlatPageDataHandler = (
17
18
  init: {
18
19
  headers: {
19
20
  Accept: 'application/json',
20
- 'Content-Type': 'application/json'
21
+ 'Content-Type': 'application/json',
22
+ ...(headers ?? {})
21
23
  }
22
24
  }
23
25
  });
@@ -29,15 +31,17 @@ const getFlatPageDataHandler = (
29
31
  export const getFlatPageData = ({
30
32
  pk,
31
33
  locale = ServerVariables.locale,
32
- currency = ServerVariables.currency
34
+ currency = ServerVariables.currency,
35
+ headers
33
36
  }: {
34
37
  pk: number;
35
38
  locale?: string;
36
39
  currency?: string;
40
+ headers?: Record<string, string>;
37
41
  }) => {
38
42
  return Cache.wrap(
39
43
  CacheKey.FlatPage(pk),
40
44
  locale,
41
- getFlatPageDataHandler(pk, locale, currency)
45
+ getFlatPageDataHandler(pk, locale, currency, headers)
42
46
  );
43
47
  };
@@ -5,7 +5,12 @@ import appFetch from '../../utils/app-fetch';
5
5
  import { ServerVariables } from '../../utils/server-variables';
6
6
  import { form } from '../urls';
7
7
 
8
- const getFormDataHandler = (pk: number, locale: string, currency: string) => {
8
+ const getFormDataHandler = (
9
+ pk: number,
10
+ locale: string,
11
+ currency: string,
12
+ headers?: Record<string, string>
13
+ ) => {
9
14
  return async function () {
10
15
  const data = await appFetch<FormType>({
11
16
  url: form.getForm(pk),
@@ -14,7 +19,8 @@ const getFormDataHandler = (pk: number, locale: string, currency: string) => {
14
19
  init: {
15
20
  headers: {
16
21
  Accept: 'application/json',
17
- 'Content-Type': 'application/json'
22
+ 'Content-Type': 'application/json',
23
+ ...(headers ?? {})
18
24
  }
19
25
  }
20
26
  });
@@ -26,15 +32,17 @@ const getFormDataHandler = (pk: number, locale: string, currency: string) => {
26
32
  export const getFormData = ({
27
33
  pk,
28
34
  locale = ServerVariables.locale,
29
- currency = ServerVariables.currency
35
+ currency = ServerVariables.currency,
36
+ headers
30
37
  }: {
31
38
  pk: number;
32
39
  locale?: string;
33
40
  currency?: string;
41
+ headers?: Record<string, string>;
34
42
  }) => {
35
43
  return Cache.wrap(
36
44
  CacheKey.Form(pk),
37
45
  locale,
38
- getFormDataHandler(pk, locale, currency)
46
+ getFormDataHandler(pk, locale, currency, headers)
39
47
  );
40
48
  };
@@ -7,7 +7,8 @@ import { ServerVariables } from '../../utils/server-variables';
7
7
  const getLandingPageHandler = (
8
8
  pk: number,
9
9
  locale: string,
10
- currency: string
10
+ currency: string,
11
+ headers?: Record<string, string>
11
12
  ) => {
12
13
  return async function () {
13
14
  const data = await appFetch<LandingPage>({
@@ -17,7 +18,8 @@ const getLandingPageHandler = (
17
18
  init: {
18
19
  headers: {
19
20
  Accept: 'application/json',
20
- 'Content-Type': 'application/json'
21
+ 'Content-Type': 'application/json',
22
+ ...(headers ?? {})
21
23
  }
22
24
  }
23
25
  });
@@ -29,15 +31,17 @@ const getLandingPageHandler = (
29
31
  export const getLandingPageData = ({
30
32
  pk,
31
33
  locale = ServerVariables.locale,
32
- currency = ServerVariables.currency
34
+ currency = ServerVariables.currency,
35
+ headers
33
36
  }: {
34
37
  pk: number;
35
38
  locale?: string;
36
39
  currency?: string;
40
+ headers?: Record<string, string>;
37
41
  }) => {
38
42
  return Cache.wrap(
39
43
  CacheKey.LandingPage(pk),
40
44
  locale,
41
- getLandingPageHandler(pk, locale, currency)
45
+ getLandingPageHandler(pk, locale, currency, headers)
42
46
  );
43
47
  };
@@ -13,6 +13,7 @@ interface MenuHandlerParams {
13
13
  currency?: string;
14
14
  depth?: number;
15
15
  parent?: string;
16
+ headers?: Record<string, string>;
16
17
  }
17
18
 
18
19
  const DEFAULT_DEPTH = 3;
@@ -22,13 +23,17 @@ const getMenuHandler =
22
23
  locale = ServerVariables.locale,
23
24
  currency = ServerVariables.currency,
24
25
  depth,
25
- parent
26
+ parent,
27
+ headers
26
28
  }: MenuHandlerParams = {}) =>
27
29
  async () => {
28
30
  const response = await appFetch<MenuResponse>({
29
31
  url: misc.menus(depth ?? DEFAULT_DEPTH, parent),
30
32
  locale,
31
- currency
33
+ currency,
34
+ init: {
35
+ headers
36
+ }
32
37
  });
33
38
 
34
39
  return response?.menu;
@@ -11,6 +11,7 @@ type GetProduct = {
11
11
  currency?: string;
12
12
  searchParams?: URLSearchParams;
13
13
  groupProduct?: boolean;
14
+ headers?: Record<string, string>;
14
15
  };
15
16
 
16
17
  const getProductDataHandler = ({
@@ -18,7 +19,8 @@ const getProductDataHandler = ({
18
19
  locale,
19
20
  currency,
20
21
  searchParams,
21
- groupProduct
22
+ groupProduct,
23
+ headers
22
24
  }: GetProduct) => {
23
25
  return async function () {
24
26
  let url = groupProduct
@@ -40,7 +42,8 @@ const getProductDataHandler = ({
40
42
  init: {
41
43
  headers: {
42
44
  Accept: 'application/json',
43
- 'Content-Type': 'application/json'
45
+ 'Content-Type': 'application/json',
46
+ ...(headers ?? {})
44
47
  }
45
48
  }
46
49
  });
@@ -95,7 +98,8 @@ export const getProductData = async ({
95
98
  locale = ServerVariables.locale,
96
99
  currency = ServerVariables.currency,
97
100
  searchParams,
98
- groupProduct
101
+ groupProduct,
102
+ headers
99
103
  }: GetProduct) => {
100
104
  return Cache.wrap(
101
105
  CacheKey[groupProduct ? 'GroupProduct' : 'Product'](
@@ -103,7 +107,14 @@ export const getProductData = async ({
103
107
  searchParams ?? new URLSearchParams()
104
108
  ),
105
109
  locale,
106
- getProductDataHandler({ pk, locale, currency, searchParams, groupProduct }),
110
+ getProductDataHandler({
111
+ pk,
112
+ locale,
113
+ currency,
114
+ searchParams,
115
+ groupProduct,
116
+ headers
117
+ }),
107
118
  {
108
119
  expire: 300
109
120
  }
@@ -7,9 +7,10 @@ interface SeoDataParams {
7
7
  url: string;
8
8
  locale?: string;
9
9
  currency?: string;
10
+ headers?: Record<string, string>;
10
11
  }
11
12
 
12
- function getSeoDataHandler({ url, locale, currency }: SeoDataParams) {
13
+ function getSeoDataHandler({ url, locale, currency, headers }: SeoDataParams) {
13
14
  return async function () {
14
15
  let data = {} as {
15
16
  title: string;
@@ -19,7 +20,12 @@ function getSeoDataHandler({ url, locale, currency }: SeoDataParams) {
19
20
  };
20
21
 
21
22
  try {
22
- data = await appFetch({ url: misc.cmsSeo(url), locale, currency });
23
+ data = await appFetch({
24
+ url: misc.cmsSeo(url),
25
+ locale,
26
+ currency,
27
+ init: { headers }
28
+ });
23
29
  } catch (error) {
24
30
  // logger.error('Error while fetching seo data', { url, error });
25
31
  }
@@ -31,11 +37,12 @@ function getSeoDataHandler({ url, locale, currency }: SeoDataParams) {
31
37
  export const getSeoData = async (
32
38
  url,
33
39
  locale = ServerVariables.locale,
34
- currency = ServerVariables.currency
40
+ currency = ServerVariables.currency,
41
+ headers?: Record<string, string>
35
42
  ) => {
36
43
  return Cache.wrap(
37
44
  CacheKey.Seo(url),
38
45
  locale,
39
- getSeoDataHandler({ url, locale, currency })
46
+ getSeoDataHandler({ url, locale, currency, headers })
40
47
  );
41
48
  };
@@ -6,29 +6,44 @@ import { widgets } from '../urls';
6
6
  import { ServerVariables } from '../../utils/server-variables';
7
7
 
8
8
  const getWidgetDataHandler =
9
- (slug: string, locale: string, currency: string) => async () => {
9
+ (
10
+ slug: string,
11
+ locale: string,
12
+ currency: string,
13
+ headers?: Record<string, string>
14
+ ) =>
15
+ async () => {
10
16
  if (!slug) {
11
17
  return null;
12
18
  }
13
19
 
14
- return await appFetch({ url: widgets.getWidget(slug), locale, currency });
20
+ return await appFetch({
21
+ url: widgets.getWidget(slug),
22
+ locale,
23
+ currency,
24
+ init: {
25
+ headers
26
+ }
27
+ });
15
28
  };
16
29
 
17
30
  export const getWidgetData = async <T>({
18
31
  slug,
19
32
  locale = ServerVariables.locale,
20
33
  currency = ServerVariables.currency,
21
- cacheOptions
34
+ cacheOptions,
35
+ headers
22
36
  }: {
23
37
  slug: string;
24
38
  locale?: string;
25
39
  currency?: string;
26
40
  cacheOptions?: CacheOptions;
41
+ headers?: Record<string, string>;
27
42
  }): Promise<WidgetResultType<T>> => {
28
43
  return Cache.wrap(
29
44
  CacheKey.Widget(slug),
30
45
  locale,
31
- getWidgetDataHandler(slug, locale, currency),
46
+ getWidgetDataHandler(slug, locale, currency, headers),
32
47
  cacheOptions
33
48
  );
34
49
  };
@@ -72,10 +72,13 @@ const addRootLayoutProps = async (componentProps: RootLayoutProps) => {
72
72
  const checkRedisVariables = () => {
73
73
  const requiredVariableValues = [
74
74
  process.env.CACHE_HOST,
75
- process.env.CACHE_PORT,
76
- process.env.CACHE_SECRET
75
+ process.env.CACHE_PORT
77
76
  ];
78
77
 
78
+ if (!settings.usePrettyUrlRoute) {
79
+ requiredVariableValues.push(process.env.CACHE_SECRET);
80
+ }
81
+
79
82
  if (
80
83
  !requiredVariableValues.every((v) => v) &&
81
84
  process.env.NODE_ENV === 'production'
@@ -1,5 +1,12 @@
1
+ import { initSentry } from '../sentry';
2
+
1
3
  export async function register() {
2
4
  if (process.env.NEXT_RUNTIME === 'nodejs') {
3
5
  await import('./node');
6
+ initSentry('Server');
7
+ }
8
+
9
+ if (process.env.NEXT_RUNTIME === 'edge') {
10
+ initSentry('Edge');
4
11
  }
5
12
  }
@@ -23,10 +23,10 @@ CacheHandler.onCreation(async () => {
23
23
  timeoutMs: 5000
24
24
  });
25
25
 
26
- const localHandler = createLruHandler();
26
+ // const localHandler = createLruHandler();
27
27
 
28
28
  return {
29
- handlers: [redisHandler, localHandler]
29
+ handlers: [redisHandler]
30
30
  };
31
31
  });
32
32
 
package/lib/cache.ts CHANGED
@@ -31,6 +31,8 @@ export const CacheKey = {
31
31
  `category_${pk}_${encodeURIComponent(
32
32
  JSON.stringify(searchParams)
33
33
  )}${hashCacheKey(headers)}`,
34
+ Basket: (namespace?: string) => `basket${namespace ? `_${namespace}` : ''}`,
35
+ AllBaskets: () => 'all_baskets',
34
36
  CategorySlug: (slug: string) => `category_${slug}`,
35
37
  SpecialPage: (
36
38
  pk: number,
@@ -145,7 +145,8 @@ const withCompleteGpay =
145
145
  logger.info('Redirecting to order success page', {
146
146
  middleware: 'complete-gpay',
147
147
  redirectUrlWithLocale,
148
- ip
148
+ ip,
149
+ setCookie: request.headers.get('set-cookie')
149
150
  });
150
151
 
151
152
  // Using POST method while redirecting causes an error,
@@ -145,7 +145,8 @@ const withCompleteMasterpass =
145
145
  logger.info('Redirecting to order success page', {
146
146
  middleware: 'complete-masterpass',
147
147
  redirectUrlWithLocale,
148
- ip
148
+ ip,
149
+ setCookie: request.headers.get('set-cookie')
149
150
  });
150
151
 
151
152
  // Using POST method while redirecting causes an error,
@@ -285,7 +285,9 @@ const withPzDefault =
285
285
  url.pathname =
286
286
  url.pathname +
287
287
  (/\/$/.test(url.pathname) ? '' : '/') +
288
- `searchparams|${url.searchParams.toString()}`;
288
+ `searchparams|${url.searchParams
289
+ .toString()
290
+ .replace(/%26/g, '--amp--')}`;
289
291
  }
290
292
 
291
293
  if (
@@ -146,7 +146,8 @@ const withRedirectionPayment =
146
146
  logger.info('Redirecting to order success page', {
147
147
  middleware: 'redirection-payment',
148
148
  redirectUrlWithLocale,
149
- ip
149
+ ip,
150
+ setCookie: request.headers.get('set-cookie')
150
151
  });
151
152
 
152
153
  // Using POST method while redirecting causes an error,
@@ -145,7 +145,8 @@ const withSavedCardRedirection =
145
145
  logger.info('Redirecting to order success page', {
146
146
  middleware: 'saved-card-redirection',
147
147
  redirectUrlWithLocale,
148
- ip
148
+ ip,
149
+ setCookie: request.headers.get('set-cookie')
149
150
  });
150
151
 
151
152
  // Using POST method while redirecting causes an error,
@@ -145,7 +145,8 @@ const withThreeDRedirection =
145
145
  logger.info('Redirecting to order success page', {
146
146
  middleware: 'three-d-redirection',
147
147
  redirectUrlWithLocale,
148
- ip
148
+ ip,
149
+ setCookie: request.headers.get('set-cookie')
149
150
  });
150
151
 
151
152
  // Using POST method while redirecting causes an error,
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.76.0",
4
+ "version": "1.77.0-rc.0",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -20,7 +20,7 @@
20
20
  "@opentelemetry/sdk-trace-node": "1.19.0",
21
21
  "@opentelemetry/semantic-conventions": "1.19.0",
22
22
  "@reduxjs/toolkit": "1.9.7",
23
- "@neshca/cache-handler": "1.5.1",
23
+ "@neshca/cache-handler": "1.9.0",
24
24
  "cross-spawn": "7.0.3",
25
25
  "generic-pool": "3.9.0",
26
26
  "react-redux": "8.1.3",
@@ -30,7 +30,7 @@
30
30
  "set-cookie-parser": "2.6.0"
31
31
  },
32
32
  "devDependencies": {
33
- "@akinon/eslint-plugin-projectzero": "1.76.0",
33
+ "@akinon/eslint-plugin-projectzero": "1.77.0-rc.0",
34
34
  "@types/react-redux": "7.1.30",
35
35
  "@types/set-cookie-parser": "2.4.7",
36
36
  "@typescript-eslint/eslint-plugin": "6.7.4",
@@ -114,6 +114,7 @@ export interface Order {
114
114
  pk: number;
115
115
  name: string;
116
116
  slug: string;
117
+ logo: string;
117
118
  [key: string]: any;
118
119
  };
119
120
  }
@@ -43,12 +43,12 @@ const appFetch = async <T>({
43
43
  const requestURL = `${decodeURIComponent(commerceUrl)}${url}`;
44
44
 
45
45
  init.headers = {
46
+ cookie: nextCookies.toString(),
46
47
  ...(init.headers ?? {}),
47
48
  ...(ServerVariables.globalHeaders ?? {}),
48
49
  'Accept-Language': currentLocale.apiValue,
49
50
  'x-currency': currency,
50
- 'x-forwarded-for': ip,
51
- cookie: nextCookies.toString()
51
+ 'x-forwarded-for': ip
52
52
  };
53
53
 
54
54
  init.next = {
package/with-pz-config.js CHANGED
@@ -64,7 +64,7 @@ const defaultConfig = {
64
64
  },
65
65
  sentry: {
66
66
  hideSourceMaps: true
67
- }
67
+ } // TODO: This section will be reviewed again in the Sentry 8 update.
68
68
  };
69
69
 
70
70
  const withPzConfig = (