@akinon/next 1.0.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.
Files changed (98) hide show
  1. package/.prettierrc +13 -0
  2. package/api/auth.ts +217 -0
  3. package/api/cache.ts +44 -0
  4. package/api/client.ts +157 -0
  5. package/api/logout.ts +42 -0
  6. package/assets/styles/index.scss +24 -0
  7. package/bin/pz-install-plugins.js +33 -0
  8. package/components/client-root.tsx +69 -0
  9. package/components/image.tsx +133 -0
  10. package/components/mobile-app-toggler.tsx +15 -0
  11. package/components/oauth-login.tsx +24 -0
  12. package/components/plugin-module.tsx +78 -0
  13. package/components/pz-providers.tsx +24 -0
  14. package/components/pz-root.tsx +21 -0
  15. package/components/redirect-three-d/content/index.tsx +64 -0
  16. package/components/redirect-three-d/index.tsx +17 -0
  17. package/components/selected-payment-option-view.tsx +66 -0
  18. package/components/trans.tsx +39 -0
  19. package/data/client/account.ts +188 -0
  20. package/data/client/address.ts +107 -0
  21. package/data/client/api.ts +42 -0
  22. package/data/client/basket.ts +85 -0
  23. package/data/client/checkout.ts +477 -0
  24. package/data/client/misc.ts +101 -0
  25. package/data/client/product.ts +90 -0
  26. package/data/client/user.ts +83 -0
  27. package/data/client/wishlist.ts +79 -0
  28. package/data/server/category.ts +121 -0
  29. package/data/server/flatpage.ts +21 -0
  30. package/data/server/index.ts +8 -0
  31. package/data/server/list.ts +56 -0
  32. package/data/server/menu.ts +35 -0
  33. package/data/server/product.ts +86 -0
  34. package/data/server/seo.ts +48 -0
  35. package/data/server/special-page.ts +42 -0
  36. package/data/server/widget.ts +27 -0
  37. package/data/urls.ts +184 -0
  38. package/hocs/client/index.ts +1 -0
  39. package/hocs/client/with-segment-defaults.tsx +26 -0
  40. package/hocs/server/index.ts +1 -0
  41. package/hocs/server/with-segment-defaults.tsx +83 -0
  42. package/hooks/index.ts +8 -0
  43. package/hooks/use-captcha.tsx +76 -0
  44. package/hooks/use-common-product-attributes.ts +36 -0
  45. package/hooks/use-debounce.ts +20 -0
  46. package/hooks/use-localization.ts +63 -0
  47. package/hooks/use-media-query.ts +36 -0
  48. package/hooks/use-on-click-outside.tsx +28 -0
  49. package/hooks/use-router.ts +45 -0
  50. package/hooks/use-translation.ts +14 -0
  51. package/lib/cache.ts +185 -0
  52. package/localization/index.ts +5 -0
  53. package/localization/provider.tsx +58 -0
  54. package/middlewares/currency.ts +55 -0
  55. package/middlewares/default.ts +224 -0
  56. package/middlewares/index.ts +29 -0
  57. package/middlewares/locale.ts +61 -0
  58. package/middlewares/oauth-login.ts +78 -0
  59. package/middlewares/pretty-url.ts +94 -0
  60. package/middlewares/redirection-payment.ts +117 -0
  61. package/middlewares/three-d-redirection.ts +122 -0
  62. package/middlewares/url-redirection.ts +61 -0
  63. package/package.json +20 -0
  64. package/plugins.js +7 -0
  65. package/redux/hooks.ts +7 -0
  66. package/redux/middlewares/checkout.ts +231 -0
  67. package/redux/middlewares/index.ts +50 -0
  68. package/redux/reducers/checkout.ts +164 -0
  69. package/redux/reducers/config.ts +28 -0
  70. package/redux/reducers/header.ts +59 -0
  71. package/redux/reducers/index.ts +15 -0
  72. package/redux/reducers/root.ts +61 -0
  73. package/tailwind/rtl.js +137 -0
  74. package/types/commerce/account.ts +68 -0
  75. package/types/commerce/address.ts +94 -0
  76. package/types/commerce/basket.ts +43 -0
  77. package/types/commerce/category.ts +114 -0
  78. package/types/commerce/checkout.ts +132 -0
  79. package/types/commerce/flatpage.ts +7 -0
  80. package/types/commerce/index.ts +10 -0
  81. package/types/commerce/misc.ts +127 -0
  82. package/types/commerce/order.ts +108 -0
  83. package/types/commerce/product.ts +110 -0
  84. package/types/commerce/widget.ts +28 -0
  85. package/types/gtm.ts +16 -0
  86. package/types/index.ts +207 -0
  87. package/types/next-auth.d.ts +24 -0
  88. package/utils/app-fetch.ts +62 -0
  89. package/utils/generate-commerce-search-params.ts +22 -0
  90. package/utils/get-currency.ts +29 -0
  91. package/utils/image-loader.ts +31 -0
  92. package/utils/index.ts +132 -0
  93. package/utils/localization.ts +29 -0
  94. package/utils/log.ts +138 -0
  95. package/utils/menu-generator.ts +27 -0
  96. package/utils/mobile-3d-iframe.ts +58 -0
  97. package/utils/server-translation.ts +57 -0
  98. package/utils/server-variables.ts +9 -0
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+
3
+ import { useRouter as _useRouter } from 'next/navigation';
4
+ import { urlLocaleMatcherRegex } from '../utils';
5
+ import { useLocalization } from './use-localization';
6
+ import { LocaleUrlStrategy } from '../localization';
7
+
8
+ export const useRouter = () => {
9
+ const { locale, locales, localeUrlStrategy, defaultLocaleValue } =
10
+ useLocalization();
11
+ const defaultLocale = locales.find((l) => l.value === defaultLocaleValue);
12
+ const router = _useRouter();
13
+
14
+ const pushOrReplace = (
15
+ fn: (href: string, options?) => void,
16
+ href: string,
17
+ options?
18
+ ) => {
19
+ if (href.startsWith('http')) {
20
+ return fn(href, options);
21
+ }
22
+
23
+ const url = new URL(href, window.location.origin);
24
+ const pathnameWithoutLocale = url.pathname.replace(
25
+ urlLocaleMatcherRegex,
26
+ ''
27
+ );
28
+
29
+ url.pathname = `${
30
+ locale === defaultLocale?.value &&
31
+ localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale
32
+ ? ''
33
+ : `/${locale}`
34
+ }${pathnameWithoutLocale}`;
35
+
36
+ return fn(url.href, options);
37
+ };
38
+
39
+ return {
40
+ ...router,
41
+ push: (href: string, options?) => pushOrReplace(router.push, href, options),
42
+ replace: (href: string, options?) =>
43
+ pushOrReplace(router.replace, href, options)
44
+ } as typeof router;
45
+ };
@@ -0,0 +1,14 @@
1
+ import { LocalizationContext } from '../localization/provider';
2
+ import { useContext } from 'react';
3
+
4
+ /**
5
+ * @deprecated Use useLocalization instead.
6
+ */
7
+ export const useTranslation = (namespace?: string) => {
8
+ const { translate, locale } = useContext(LocalizationContext);
9
+
10
+ return {
11
+ t: (path: string) => translate(namespace ? `${namespace}.${path}` : path),
12
+ locale
13
+ };
14
+ };
package/lib/cache.ts ADDED
@@ -0,0 +1,185 @@
1
+ import { RedisClientType } from 'redis';
2
+ import Settings from 'settings';
3
+ import { CacheOptions } from '../types';
4
+ import logger from '../utils/log';
5
+ import { ServerVariables } from '../utils/server-variables';
6
+
7
+ export const CacheKey = {
8
+ List: (searchParams: URLSearchParams) =>
9
+ `list_${encodeURIComponent(JSON.stringify(searchParams))}`,
10
+ Category: (pk: number, searchParams?: URLSearchParams) =>
11
+ `category_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
12
+ CategorySlug: (slug: string) => `category_${slug}`,
13
+ SpecialPage: (pk: number, searchParams: URLSearchParams) =>
14
+ `special_page_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
15
+ Product: (pk: number, searchParams: URLSearchParams) =>
16
+ `product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
17
+ GroupProduct: (pk: number, searchParams: URLSearchParams) =>
18
+ `group_product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
19
+ FlatPage: (pk: number) => `flat_page_${pk}`,
20
+ Widget: (slug: string) => `widget_${slug}`,
21
+ PrettyUrl: (pathname: string) => `pretty_url_${pathname}`,
22
+ Menu: (depth: number, parent?: string) =>
23
+ `menu_${depth}${parent ? `_${parent}` : ''}`,
24
+ Seo: (url: string) => `seo_${url}`,
25
+ RootSeo: 'root_seo'
26
+ };
27
+
28
+ export class Cache {
29
+ static PROXY_URL = `${process.env.NEXT_PUBLIC_URL}/api/cache`;
30
+
31
+ static formatKey(key: string) {
32
+ return encodeURIComponent(
33
+ `${Settings.commerceUrl}_${ServerVariables.locale}_${key}`
34
+ );
35
+ }
36
+
37
+ static async getClient() {
38
+ const { createClient } = await import('redis');
39
+ const redisUrl = `redis://${process.env.CACHE_HOST}:${
40
+ process.env.CACHE_PORT
41
+ }/${process.env.CACHE_BUCKET ?? '0'}`;
42
+
43
+ const client: RedisClientType = createClient({
44
+ url: redisUrl
45
+ });
46
+
47
+ client.on('error', (error) => {
48
+ logger.error('Redis client error', { redisUrl, error });
49
+ });
50
+
51
+ return client;
52
+ }
53
+
54
+ static async get(key: string) {
55
+ let value;
56
+ let client;
57
+
58
+ try {
59
+ client = await Cache.getClient();
60
+ await client.connect();
61
+ value = JSON.parse(await client.get(key));
62
+
63
+ logger.debug('Redis get success', { key });
64
+ logger.trace('Redis get success', { key, value });
65
+ } catch (error) {
66
+ logger.error('Redis get error', { key, error });
67
+ } finally {
68
+ await client?.disconnect();
69
+ }
70
+
71
+ return value;
72
+ }
73
+
74
+ static async set(key: string, value: string, expire?: number) {
75
+ let success = false;
76
+ let client;
77
+
78
+ try {
79
+ client = await Cache.getClient();
80
+ await client.connect();
81
+ await client.set(key, value, {
82
+ EX: expire
83
+ });
84
+
85
+ success = true;
86
+
87
+ logger.debug('Redis set success', { key });
88
+ logger.trace('Redis set success', { key, value });
89
+ } catch (error) {
90
+ logger.error('Redis set error', { key, error });
91
+ } finally {
92
+ await client?.disconnect();
93
+ }
94
+
95
+ return success;
96
+ }
97
+
98
+ static async wrap<T = any>(
99
+ key: string,
100
+ handler: () => Promise<T>,
101
+ options?: CacheOptions
102
+ ): Promise<T> {
103
+ const requiredVariables = [
104
+ process.env.CACHE_HOST,
105
+ process.env.CACHE_PORT,
106
+ process.env.CACHE_SECRET
107
+ ];
108
+
109
+ if (!requiredVariables.every((v) => v)) {
110
+ return await handler();
111
+ }
112
+
113
+ const defaultOptions: CacheOptions = {
114
+ cache: true,
115
+ expire: Settings.redis.defaultExpirationTime
116
+ };
117
+
118
+ const _options = Object.assign(defaultOptions, options);
119
+ const formattedKey = Cache.formatKey(key);
120
+
121
+ logger.debug('Cache wrap', { key, formattedKey, _options });
122
+
123
+ if (_options.cache) {
124
+ let cachedValue;
125
+
126
+ if (_options.useProxy) {
127
+ const body = new URLSearchParams();
128
+
129
+ body.append('key', formattedKey);
130
+
131
+ cachedValue = await Cache.proxyRequest('POST', body);
132
+ logger.debug('Cache proxy request success', { key });
133
+ logger.trace('Cache proxy request', { key, cachedValue });
134
+ } else {
135
+ cachedValue = await Cache.get(formattedKey);
136
+ }
137
+
138
+ if (cachedValue) {
139
+ return cachedValue;
140
+ }
141
+ }
142
+
143
+ logger.info('Redis cache miss. Setting new value...', { key });
144
+
145
+ const data = await handler();
146
+
147
+ if (data && _options.cache) {
148
+ if (_options.useProxy) {
149
+ try {
150
+ const body = new URLSearchParams();
151
+
152
+ body.append('key', formattedKey);
153
+ body.append('value', JSON.stringify(data));
154
+ body.append(
155
+ 'expire',
156
+ String(_options?.expire ?? Settings.redis.defaultExpirationTime)
157
+ );
158
+ await Cache.proxyRequest('PUT', body);
159
+
160
+ logger.debug('Cache proxy request', { key, body: body.toString() });
161
+ } catch (error) {
162
+ logger.error('Cache proxy error', error);
163
+ }
164
+ } else {
165
+ await Cache.set(formattedKey, JSON.stringify(data), _options?.expire);
166
+ }
167
+ }
168
+
169
+ return data;
170
+ }
171
+
172
+ static async proxyRequest(method: 'POST' | 'PUT', body: URLSearchParams) {
173
+ const response = await (
174
+ await fetch(Cache.PROXY_URL, {
175
+ method,
176
+ headers: {
177
+ authorization: process.env.CACHE_SECRET
178
+ },
179
+ body
180
+ })
181
+ ).json();
182
+
183
+ return response;
184
+ }
185
+ }
@@ -0,0 +1,5 @@
1
+ export enum LocaleUrlStrategy {
2
+ HideAllLocales = 'hide-all-locales',
3
+ HideDefaultLocale = 'hide-default-locale',
4
+ ShowAllLocales = 'show-all-locales'
5
+ }
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+
3
+ import React, { createContext } from 'react';
4
+ import { getTranslateFn } from '../utils';
5
+ import { useParams } from 'next/navigation';
6
+ import { Currency, Locale } from '../types';
7
+ import settings from 'settings';
8
+
9
+ export const LocalizationContext = createContext(
10
+ {} as {
11
+ translate: (path: string) => string;
12
+ locale: string;
13
+ currency: string;
14
+ locales: Locale[];
15
+ currencies: Currency[];
16
+ defaultLocaleValue: string;
17
+ defaultCurrencyCode: string;
18
+ localeUrlStrategy?: string;
19
+ }
20
+ );
21
+
22
+ export default function LocalizationProvider({
23
+ children,
24
+ translations
25
+ }: {
26
+ children: React.ReactNode;
27
+ translations: any;
28
+ }) {
29
+ const {
30
+ locales,
31
+ currencies,
32
+ defaultLocaleValue,
33
+ defaultCurrencyCode,
34
+ localeUrlStrategy
35
+ } = settings.localization;
36
+
37
+ const { locale, currency } = useParams() as {
38
+ locale: string;
39
+ currency: string;
40
+ };
41
+
42
+ return (
43
+ <LocalizationContext.Provider
44
+ value={{
45
+ translate: (path: string) => getTranslateFn(path, translations),
46
+ locale,
47
+ currency,
48
+ locales,
49
+ currencies,
50
+ defaultLocaleValue,
51
+ defaultCurrencyCode,
52
+ localeUrlStrategy
53
+ }}
54
+ >
55
+ {children}
56
+ </LocalizationContext.Provider>
57
+ );
58
+ }
@@ -0,0 +1,55 @@
1
+ import { NextFetchEvent, NextMiddleware } from 'next/server';
2
+ import { ROUTES } from 'routes';
3
+ import settings from 'settings';
4
+ import { PzNextRequest } from '.';
5
+ import logger from '../utils/log';
6
+
7
+ const withCurrency =
8
+ (middleware: NextMiddleware) =>
9
+ async (req: PzNextRequest, event: NextFetchEvent) => {
10
+ try {
11
+ const { currencies, defaultCurrencyCode, defaultLocaleValue } =
12
+ settings.localization;
13
+ const locale = req.middlewareParams.rewrites.locale ?? defaultLocaleValue;
14
+
15
+ if (!defaultCurrencyCode) {
16
+ logger.error('Default currency code is not defined in settings.');
17
+ throw new Error(
18
+ 'Default currency code is not defined. Use `defaultCurrencyCode` property in `localization` object in `settings.js` file.'
19
+ );
20
+ }
21
+
22
+ const getActiveCurrencyCode =
23
+ settings.localization.getActiveCurrencyCode ??
24
+ (({ req }) => {
25
+ return (
26
+ req.cookies.get('pz-currency')?.value ??
27
+ settings.localization.defaultCurrencyCode
28
+ );
29
+ });
30
+
31
+ let activeCurrency = getActiveCurrencyCode({
32
+ req,
33
+ locale,
34
+ defaultCurrencyCode
35
+ });
36
+
37
+ if (
38
+ !activeCurrency ||
39
+ !currencies.find((c) => c.code === activeCurrency)
40
+ ) {
41
+ logger.warn(
42
+ `Currency ${activeCurrency} is not defined in settings. Using default currency ${defaultCurrencyCode} instead.`
43
+ );
44
+ activeCurrency = defaultCurrencyCode;
45
+ }
46
+
47
+ req.middlewareParams.rewrites.currency = activeCurrency;
48
+ } catch (error) {
49
+ logger.error('withCurrency error', error);
50
+ }
51
+
52
+ return middleware(req, event);
53
+ };
54
+
55
+ export default withCurrency;
@@ -0,0 +1,224 @@
1
+ import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
2
+ import Settings from 'settings';
3
+ import {
4
+ PzNextRequest,
5
+ withOauthLogin,
6
+ withPrettyUrl,
7
+ withRedirectionPayment,
8
+ withThreeDRedirection,
9
+ withUrlRedirection
10
+ } from '.';
11
+ import { urlLocaleMatcherRegex } from '../utils';
12
+ import withCurrency from './currency';
13
+ import withLocale from './locale';
14
+ import logger from '../utils/log';
15
+ import { user } from '../data/urls';
16
+
17
+ const withPzDefault =
18
+ (middleware: NextMiddleware) =>
19
+ async (req: PzNextRequest, event: NextFetchEvent) => {
20
+ const url = req.nextUrl.clone();
21
+ const commerceUrl = encodeURIComponent(decodeURI(Settings.commerceUrl)); // encodeURI doesn't work as expected in middleware
22
+ const searchParams = new URLSearchParams(url.search);
23
+
24
+ logger.debug('withPzDefault', {
25
+ url: url.href,
26
+ middlewareParams: req.middlewareParams
27
+ });
28
+
29
+ // Support legacy ?format=json query param
30
+ if (searchParams.has('json') || searchParams.get('format') === 'json') {
31
+ try {
32
+ searchParams.set('format', 'json');
33
+
34
+ const request = await fetch(
35
+ `${encodeURI(Settings.commerceUrl)}${url.pathname.replace(
36
+ urlLocaleMatcherRegex,
37
+ ''
38
+ )}?${searchParams.toString()}`,
39
+ {
40
+ next: {
41
+ revalidate: 0
42
+ },
43
+ headers: {
44
+ Cookie: req.headers.get('cookie') || '',
45
+ Accept: 'application/json',
46
+ 'X-Requested-With': 'XMLHttpRequest'
47
+ }
48
+ }
49
+ );
50
+
51
+ return NextResponse.json(await request.json());
52
+ } catch (error) {
53
+ logger.error('?format=json error', error);
54
+ return NextResponse.next();
55
+ }
56
+ }
57
+
58
+ if (url.pathname === '/healthz') {
59
+ return NextResponse.json({ status: 'ok' });
60
+ }
61
+
62
+ if (req.nextUrl.pathname.startsWith('/.well-known')) {
63
+ const url = new URL(`${Settings.commerceUrl}${req.nextUrl.pathname}`);
64
+ const req_ = await fetch(url.toString());
65
+
66
+ if (req_.ok) {
67
+ return NextResponse.rewrite(url);
68
+ } else {
69
+ return NextResponse.next();
70
+ }
71
+ }
72
+
73
+ if (req.nextUrl.pathname.includes('/orders/hooks/')) {
74
+ return NextResponse.rewrite(
75
+ new URL(
76
+ `${Settings.commerceUrl}${req.nextUrl.pathname.replace(
77
+ urlLocaleMatcherRegex,
78
+ ''
79
+ )}`
80
+ )
81
+ );
82
+ }
83
+
84
+ if (req.nextUrl.pathname.startsWith('/orders/redirection/')) {
85
+ return NextResponse.rewrite(
86
+ new URL(`${encodeURI(Settings.commerceUrl)}/orders/redirection/`)
87
+ );
88
+ }
89
+
90
+ req.middlewareParams = {
91
+ commerceUrl,
92
+ rewrites: {}
93
+ };
94
+
95
+ return withOauthLogin(
96
+ withLocale(
97
+ withCurrency(
98
+ withPrettyUrl(
99
+ withRedirectionPayment(
100
+ withThreeDRedirection(
101
+ withUrlRedirection(
102
+ async (req: PzNextRequest, event: NextFetchEvent) => {
103
+ let middlewareResult: NextResponse | void =
104
+ NextResponse.next();
105
+
106
+ try {
107
+ const { locale, prettyUrl, currency } =
108
+ req.middlewareParams.rewrites;
109
+ const { defaultLocaleValue } = Settings.localization;
110
+ const url = req.nextUrl.clone();
111
+ const pathnameWithoutLocale = url.pathname.replace(
112
+ urlLocaleMatcherRegex,
113
+ ''
114
+ );
115
+
116
+ url.basePath = `/${commerceUrl}`;
117
+ url.pathname = `/${
118
+ locale.length ? `${locale}/` : ''
119
+ }${currency}${prettyUrl ?? pathnameWithoutLocale}`;
120
+
121
+ Settings.rewrites.forEach((rewrite) => {
122
+ url.pathname = url.pathname.replace(
123
+ rewrite.source,
124
+ rewrite.destination
125
+ );
126
+ });
127
+
128
+ middlewareResult = (await middleware(
129
+ req,
130
+ event
131
+ )) as NextResponse | void;
132
+
133
+ if (middlewareResult instanceof NextResponse) {
134
+ middlewareResult.headers.set(
135
+ 'x-middleware-rewrite',
136
+ url.href
137
+ );
138
+ } else {
139
+ middlewareResult = NextResponse.rewrite(url);
140
+ }
141
+
142
+ if (!url.pathname.startsWith(`/${currency}/orders`)) {
143
+ middlewareResult.cookies.set(
144
+ 'pz-locale',
145
+ locale?.length > 0 ? locale : defaultLocaleValue,
146
+ {
147
+ sameSite: 'none',
148
+ secure: true
149
+ }
150
+ );
151
+ }
152
+ middlewareResult.cookies.set('pz-currency', currency, {
153
+ sameSite: 'none',
154
+ secure: true
155
+ });
156
+
157
+ if (
158
+ req.cookies.get('pz-currency') &&
159
+ req.cookies.get('pz-currency').value !== currency
160
+ ) {
161
+ logger.debug('Currency changed', {
162
+ currency,
163
+ oldCurrency: req.cookies.get('pz-currency')?.value
164
+ });
165
+
166
+ middlewareResult.cookies.set('pz-reset-basket', 'true');
167
+ }
168
+
169
+ if (
170
+ req.cookies.get('pz-locale') &&
171
+ req.cookies.get('pz-locale').value !== locale
172
+ ) {
173
+ logger.debug('Locale changed', {
174
+ locale,
175
+ oldLocale: req.cookies.get('pz-locale')?.value
176
+ });
177
+
178
+ middlewareResult.cookies.set(
179
+ 'pz-reset-client-cache',
180
+ 'true'
181
+ );
182
+ }
183
+
184
+ middlewareResult.headers.set(
185
+ 'pz-url',
186
+ req.nextUrl.toString()
187
+ );
188
+
189
+ if (process.env.ACC_APP_VERSION) {
190
+ middlewareResult.headers.set(
191
+ 'acc-app-version',
192
+ process.env.ACC_APP_VERSION
193
+ );
194
+ }
195
+
196
+ // Set CSRF token if not set
197
+ try {
198
+ const url = `${Settings.commerceUrl}${user.csrfToken}`;
199
+
200
+ if (!req.cookies.get('csrftoken')) {
201
+ const { csrf_token } = await (
202
+ await fetch(url)
203
+ ).json();
204
+ middlewareResult.cookies.set('csrftoken', csrf_token);
205
+ }
206
+ } catch (error) {
207
+ logger.error('CSRF Error', error);
208
+ }
209
+ } catch (error) {
210
+ logger.error('withPzDefault Error', error);
211
+ }
212
+
213
+ return middlewareResult;
214
+ }
215
+ )
216
+ )
217
+ )
218
+ )
219
+ )
220
+ )
221
+ )(req, event);
222
+ };
223
+
224
+ export default withPzDefault;
@@ -0,0 +1,29 @@
1
+ import withPzDefault from './default';
2
+ import withPrettyUrl from './pretty-url';
3
+ import withThreeDRedirection from './three-d-redirection';
4
+ import withRedirectionPayment from './redirection-payment';
5
+ import withLocale from './locale';
6
+ import withOauthLogin from './oauth-login';
7
+ import withUrlRedirection from './url-redirection';
8
+ import { NextRequest } from 'next/server';
9
+
10
+ export {
11
+ withPzDefault,
12
+ withPrettyUrl,
13
+ withThreeDRedirection,
14
+ withRedirectionPayment,
15
+ withLocale,
16
+ withOauthLogin,
17
+ withUrlRedirection
18
+ };
19
+
20
+ export interface PzNextRequest extends NextRequest {
21
+ middlewareParams: {
22
+ commerceUrl: string;
23
+ rewrites: {
24
+ locale?: string;
25
+ prettyUrl?: string;
26
+ currency?: string;
27
+ };
28
+ };
29
+ }
@@ -0,0 +1,61 @@
1
+ import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
2
+ import settings from 'settings';
3
+ import { PzNextRequest } from '.';
4
+ import { LocaleUrlStrategy } from '../localization';
5
+ import { urlLocaleMatcherRegex } from '../utils';
6
+ import logger from '../utils/log';
7
+
8
+ const getMatchedLocale = (pathname: string) => {
9
+ let matchedLocale = pathname.match(urlLocaleMatcherRegex)?.[0] ?? '';
10
+ matchedLocale = matchedLocale.replace('/', '');
11
+
12
+ if (!matchedLocale.length) {
13
+ if (
14
+ settings.localization.localeUrlStrategy !==
15
+ LocaleUrlStrategy.ShowAllLocales
16
+ ) {
17
+ matchedLocale = settings.localization.defaultLocaleValue;
18
+ }
19
+ }
20
+
21
+ return matchedLocale;
22
+ };
23
+
24
+ const withLocale =
25
+ (middleware: NextMiddleware) =>
26
+ async (req: PzNextRequest, event: NextFetchEvent) => {
27
+ try {
28
+ const url = req.nextUrl.clone();
29
+ const matchedLocale = getMatchedLocale(url.pathname);
30
+ let { localeUrlStrategy, defaultLocaleValue, redirectToDefaultLocale } =
31
+ settings.localization;
32
+
33
+ localeUrlStrategy =
34
+ localeUrlStrategy ?? LocaleUrlStrategy.HideDefaultLocale;
35
+
36
+ if (!defaultLocaleValue) {
37
+ logger.error('Default locale value is not defined in settings.');
38
+ throw new Error(
39
+ 'Default locale value is not defined. Use `defaultLocaleValue` property in `localization` object in `settings.js` file.'
40
+ );
41
+ }
42
+
43
+ if (
44
+ !matchedLocale?.length &&
45
+ localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales &&
46
+ redirectToDefaultLocale &&
47
+ req.method === 'GET'
48
+ ) {
49
+ url.pathname = `/${defaultLocaleValue}${url.pathname}`;
50
+ return NextResponse.redirect(url);
51
+ }
52
+
53
+ req.middlewareParams.rewrites.locale = matchedLocale;
54
+ } catch (error) {
55
+ logger.error('withLocale error', error);
56
+ }
57
+
58
+ return middleware(req, event);
59
+ };
60
+
61
+ export default withLocale;