@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.
- package/.prettierrc +13 -0
- package/api/auth.ts +217 -0
- package/api/cache.ts +44 -0
- package/api/client.ts +157 -0
- package/api/logout.ts +42 -0
- package/assets/styles/index.scss +24 -0
- package/bin/pz-install-plugins.js +33 -0
- package/components/client-root.tsx +69 -0
- package/components/image.tsx +133 -0
- package/components/mobile-app-toggler.tsx +15 -0
- package/components/oauth-login.tsx +24 -0
- package/components/plugin-module.tsx +78 -0
- package/components/pz-providers.tsx +24 -0
- package/components/pz-root.tsx +21 -0
- package/components/redirect-three-d/content/index.tsx +64 -0
- package/components/redirect-three-d/index.tsx +17 -0
- package/components/selected-payment-option-view.tsx +66 -0
- package/components/trans.tsx +39 -0
- package/data/client/account.ts +188 -0
- package/data/client/address.ts +107 -0
- package/data/client/api.ts +42 -0
- package/data/client/basket.ts +85 -0
- package/data/client/checkout.ts +477 -0
- package/data/client/misc.ts +101 -0
- package/data/client/product.ts +90 -0
- package/data/client/user.ts +83 -0
- package/data/client/wishlist.ts +79 -0
- package/data/server/category.ts +121 -0
- package/data/server/flatpage.ts +21 -0
- package/data/server/index.ts +8 -0
- package/data/server/list.ts +56 -0
- package/data/server/menu.ts +35 -0
- package/data/server/product.ts +86 -0
- package/data/server/seo.ts +48 -0
- package/data/server/special-page.ts +42 -0
- package/data/server/widget.ts +27 -0
- package/data/urls.ts +184 -0
- package/hocs/client/index.ts +1 -0
- package/hocs/client/with-segment-defaults.tsx +26 -0
- package/hocs/server/index.ts +1 -0
- package/hocs/server/with-segment-defaults.tsx +83 -0
- package/hooks/index.ts +8 -0
- package/hooks/use-captcha.tsx +76 -0
- package/hooks/use-common-product-attributes.ts +36 -0
- package/hooks/use-debounce.ts +20 -0
- package/hooks/use-localization.ts +63 -0
- package/hooks/use-media-query.ts +36 -0
- package/hooks/use-on-click-outside.tsx +28 -0
- package/hooks/use-router.ts +45 -0
- package/hooks/use-translation.ts +14 -0
- package/lib/cache.ts +185 -0
- package/localization/index.ts +5 -0
- package/localization/provider.tsx +58 -0
- package/middlewares/currency.ts +55 -0
- package/middlewares/default.ts +224 -0
- package/middlewares/index.ts +29 -0
- package/middlewares/locale.ts +61 -0
- package/middlewares/oauth-login.ts +78 -0
- package/middlewares/pretty-url.ts +94 -0
- package/middlewares/redirection-payment.ts +117 -0
- package/middlewares/three-d-redirection.ts +122 -0
- package/middlewares/url-redirection.ts +61 -0
- package/package.json +20 -0
- package/plugins.js +7 -0
- package/redux/hooks.ts +7 -0
- package/redux/middlewares/checkout.ts +231 -0
- package/redux/middlewares/index.ts +50 -0
- package/redux/reducers/checkout.ts +164 -0
- package/redux/reducers/config.ts +28 -0
- package/redux/reducers/header.ts +59 -0
- package/redux/reducers/index.ts +15 -0
- package/redux/reducers/root.ts +61 -0
- package/tailwind/rtl.js +137 -0
- package/types/commerce/account.ts +68 -0
- package/types/commerce/address.ts +94 -0
- package/types/commerce/basket.ts +43 -0
- package/types/commerce/category.ts +114 -0
- package/types/commerce/checkout.ts +132 -0
- package/types/commerce/flatpage.ts +7 -0
- package/types/commerce/index.ts +10 -0
- package/types/commerce/misc.ts +127 -0
- package/types/commerce/order.ts +108 -0
- package/types/commerce/product.ts +110 -0
- package/types/commerce/widget.ts +28 -0
- package/types/gtm.ts +16 -0
- package/types/index.ts +207 -0
- package/types/next-auth.d.ts +24 -0
- package/utils/app-fetch.ts +62 -0
- package/utils/generate-commerce-search-params.ts +22 -0
- package/utils/get-currency.ts +29 -0
- package/utils/image-loader.ts +31 -0
- package/utils/index.ts +132 -0
- package/utils/localization.ts +29 -0
- package/utils/log.ts +138 -0
- package/utils/menu-generator.ts +27 -0
- package/utils/mobile-3d-iframe.ts +58 -0
- package/utils/server-translation.ts +57 -0
- 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,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;
|