@akinon/next 1.92.0-rc.15 → 1.92.0-rc.17
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 +14 -0
- package/api/image-proxy.ts +75 -0
- package/api/similar-product-list.ts +63 -0
- package/api/similar-products.ts +111 -0
- package/components/plugin-module.tsx +25 -3
- package/data/urls.ts +5 -1
- package/middlewares/complete-gpay.ts +4 -1
- package/middlewares/complete-masterpass.ts +5 -1
- package/middlewares/redirection-payment.ts +4 -1
- package/middlewares/saved-card-redirection.ts +5 -1
- package/middlewares/three-d-redirection.ts +5 -1
- package/package.json +2 -2
- package/plugins.d.ts +8 -0
- package/plugins.js +2 -1
- package/types/index.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
+
## 1.92.0-rc.17
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e7cd3a5: ZERO-3435: Add Accept-Language to requestHeaders
|
|
8
|
+
|
|
9
|
+
## 1.92.0-rc.16
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- b55acb76: ZERO-2577: Fix pagination bug and update usePagination hook and ensure pagination controls rendering correctly
|
|
14
|
+
- 9f8cd3b: ZERO-3449: AI Search Active Filters & Crop Style changes have been implemented
|
|
15
|
+
- 4de5303c: ZERO-2504: add cookie filter to api client request
|
|
16
|
+
|
|
3
17
|
## 1.92.0-rc.15
|
|
4
18
|
|
|
5
19
|
## 1.92.0-rc.14
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
async function proxyImage(imageUrl: string) {
|
|
4
|
+
if (!imageUrl) {
|
|
5
|
+
return NextResponse.json(
|
|
6
|
+
{ success: false, error: 'Missing url parameter' },
|
|
7
|
+
{ status: 400 }
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const imageResponse = await fetch(imageUrl);
|
|
12
|
+
|
|
13
|
+
if (!imageResponse.ok) {
|
|
14
|
+
return NextResponse.json(
|
|
15
|
+
{ success: false, error: 'Failed to fetch image from URL' },
|
|
16
|
+
{ status: 400 }
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const imageBuffer = await imageResponse.arrayBuffer();
|
|
21
|
+
const base64Image = Buffer.from(imageBuffer).toString('base64');
|
|
22
|
+
const contentType = imageResponse.headers.get('content-type') || 'image/jpeg';
|
|
23
|
+
|
|
24
|
+
return { base64Image, contentType, imageBuffer };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function GET(request: NextRequest) {
|
|
28
|
+
try {
|
|
29
|
+
const { searchParams } = new URL(request.url);
|
|
30
|
+
const imageUrl = searchParams.get('url');
|
|
31
|
+
|
|
32
|
+
const result = await proxyImage(imageUrl!);
|
|
33
|
+
if (result instanceof NextResponse) {
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return new NextResponse(result.imageBuffer, {
|
|
38
|
+
status: 200,
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': result.contentType,
|
|
41
|
+
'Access-Control-Allow-Origin': '*',
|
|
42
|
+
'Cache-Control': 'public, max-age=3600'
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('Image proxy error:', error);
|
|
47
|
+
return NextResponse.json(
|
|
48
|
+
{ success: false, error: 'Internal server error' },
|
|
49
|
+
{ status: 500 }
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function POST(request: NextRequest) {
|
|
55
|
+
try {
|
|
56
|
+
const body = await request.json();
|
|
57
|
+
const imageUrl = body.imageUrl;
|
|
58
|
+
|
|
59
|
+
const result = await proxyImage(imageUrl);
|
|
60
|
+
if (result instanceof NextResponse) {
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return NextResponse.json({
|
|
65
|
+
success: true,
|
|
66
|
+
base64Image: `data:${result.contentType};base64,${result.base64Image}`
|
|
67
|
+
});
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Image proxy POST error:', error);
|
|
70
|
+
return NextResponse.json(
|
|
71
|
+
{ success: false, error: 'Internal server error' },
|
|
72
|
+
{ status: 500 }
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import Settings from 'settings';
|
|
3
|
+
|
|
4
|
+
export async function GET(request: NextRequest) {
|
|
5
|
+
try {
|
|
6
|
+
const { searchParams } = new URL(request.url);
|
|
7
|
+
const dynamicFilter = request.headers.get('x-search-dynamic-filter');
|
|
8
|
+
const dynamicExclude = request.headers.get('x-search-dynamic-exclude');
|
|
9
|
+
|
|
10
|
+
if (!dynamicFilter && !dynamicExclude) {
|
|
11
|
+
return NextResponse.json(
|
|
12
|
+
{
|
|
13
|
+
error:
|
|
14
|
+
'Missing x-search-dynamic-filter or x-search-dynamic-exclude header'
|
|
15
|
+
},
|
|
16
|
+
{ status: 400 }
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (Settings.commerceUrl === 'default') {
|
|
21
|
+
return NextResponse.json(
|
|
22
|
+
{ error: 'Commerce URL is not configured' },
|
|
23
|
+
{ status: 500 }
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const queryString = searchParams.toString();
|
|
28
|
+
const apiUrl = `${Settings.commerceUrl}/list${
|
|
29
|
+
queryString ? `?${queryString}` : ''
|
|
30
|
+
}`;
|
|
31
|
+
|
|
32
|
+
const headers: Record<string, string> = {
|
|
33
|
+
Accept: 'application/json',
|
|
34
|
+
'Content-Type': 'application/json'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (dynamicFilter) {
|
|
38
|
+
headers['x-search-dynamic-filter'] = dynamicFilter;
|
|
39
|
+
} else if (dynamicExclude) {
|
|
40
|
+
headers['x-search-dynamic-exclude'] = dynamicExclude;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const response = await fetch(apiUrl, {
|
|
44
|
+
method: 'GET',
|
|
45
|
+
headers
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
return NextResponse.json(
|
|
50
|
+
{ error: `API request failed with status: ${response.status}` },
|
|
51
|
+
{ status: response.status }
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const data = await response.json();
|
|
56
|
+
return NextResponse.json(data);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return NextResponse.json(
|
|
59
|
+
{ error: (error as Error).message },
|
|
60
|
+
{ status: 500 }
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import Settings from 'settings';
|
|
3
|
+
|
|
4
|
+
const IMAGE_SEARCH_API_URL = Settings.commerceUrl + '/image-search/';
|
|
5
|
+
|
|
6
|
+
const errorResponse = (message: string, status: number) => {
|
|
7
|
+
return NextResponse.json({ error: message }, { status });
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export async function GET(request: Request) {
|
|
11
|
+
const { searchParams } = new URL(request.url);
|
|
12
|
+
const limit = searchParams.get('limit') || '20';
|
|
13
|
+
const url = searchParams.get('url');
|
|
14
|
+
const excludedProductIds = searchParams.get('excluded_product_ids');
|
|
15
|
+
|
|
16
|
+
if (!url) {
|
|
17
|
+
return errorResponse('URL parameter is required', 400);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (Settings.commerceUrl === 'default') {
|
|
21
|
+
return errorResponse('Commerce URL is not configured', 500);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const apiParams = new URLSearchParams();
|
|
25
|
+
apiParams.append('limit', limit);
|
|
26
|
+
apiParams.append('url', url);
|
|
27
|
+
|
|
28
|
+
if (excludedProductIds) {
|
|
29
|
+
apiParams.append('excluded_product_ids', excludedProductIds);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const apiUrl = `${IMAGE_SEARCH_API_URL}?${apiParams.toString()}`;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetch(apiUrl, {
|
|
36
|
+
method: 'GET',
|
|
37
|
+
headers: {
|
|
38
|
+
Accept: 'application/json'
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const errorText = await response.text();
|
|
44
|
+
return errorResponse(
|
|
45
|
+
errorText || `API request failed with status: ${response.status}`,
|
|
46
|
+
response.status
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const responseText = await response.text();
|
|
51
|
+
|
|
52
|
+
return NextResponse.json(JSON.parse(responseText));
|
|
53
|
+
} catch (error) {
|
|
54
|
+
return errorResponse((error as Error).message, 500);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function POST(request: Request) {
|
|
59
|
+
const { searchParams } = new URL(request.url);
|
|
60
|
+
const limit = searchParams.get('limit') || '20';
|
|
61
|
+
|
|
62
|
+
if (Settings.commerceUrl === 'default') {
|
|
63
|
+
return errorResponse('Commerce URL is not configured', 500);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let requestBody;
|
|
67
|
+
try {
|
|
68
|
+
requestBody = await request.json();
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return errorResponse('Invalid JSON in request body', 400);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!requestBody.image) {
|
|
74
|
+
return errorResponse('Image data is required in request body', 400);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const apiParams = new URLSearchParams();
|
|
78
|
+
apiParams.append('limit', limit);
|
|
79
|
+
|
|
80
|
+
const apiUrl = `${IMAGE_SEARCH_API_URL}?${apiParams.toString()}`;
|
|
81
|
+
|
|
82
|
+
const bodyData: any = { image: requestBody.image };
|
|
83
|
+
|
|
84
|
+
if (requestBody.excluded_product_ids) {
|
|
85
|
+
bodyData.excluded_product_ids = requestBody.excluded_product_ids;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const response = await fetch(apiUrl, {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
headers: {
|
|
92
|
+
'Content-Type': 'application/json',
|
|
93
|
+
Accept: 'application/json'
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify(bodyData)
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
const errorText = await response.text();
|
|
100
|
+
return errorResponse(
|
|
101
|
+
errorText || `API request failed with status: ${response.status}`,
|
|
102
|
+
response.status
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const responseData = await response.json();
|
|
107
|
+
return NextResponse.json(responseData);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
return errorResponse((error as Error).message, 500);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -22,7 +22,8 @@ enum Plugin {
|
|
|
22
22
|
MultiBasket = 'pz-multi-basket',
|
|
23
23
|
SavedCard = 'pz-saved-card',
|
|
24
24
|
Hepsipay = 'pz-hepsipay',
|
|
25
|
-
FlowPayment = 'pz-flow-payment'
|
|
25
|
+
FlowPayment = 'pz-flow-payment',
|
|
26
|
+
SimilarProducts = 'pz-similar-products'
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export enum Component {
|
|
@@ -49,7 +50,14 @@ export enum Component {
|
|
|
49
50
|
MultiBasket = 'MultiBasket',
|
|
50
51
|
SavedCard = 'SavedCardOption',
|
|
51
52
|
Hepsipay = 'Hepsipay',
|
|
52
|
-
FlowPayment = 'FlowPayment'
|
|
53
|
+
FlowPayment = 'FlowPayment',
|
|
54
|
+
SimilarProductsModal = 'SimilarProductsModal',
|
|
55
|
+
SimilarProductsFilterSidebar = 'SimilarProductsFilterSidebar',
|
|
56
|
+
SimilarProductsResultsGrid = 'SimilarProductsResultsGrid',
|
|
57
|
+
SimilarProductsPlugin = 'SimilarProductsPlugin',
|
|
58
|
+
ProductImageSearchFeature = 'ProductImageSearchFeature',
|
|
59
|
+
ImageSearchButton = 'ImageSearchButton',
|
|
60
|
+
HeaderImageSearchFeature = 'HeaderImageSearchFeature'
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
const PluginComponents = new Map([
|
|
@@ -84,7 +92,19 @@ const PluginComponents = new Map([
|
|
|
84
92
|
[Plugin.MultiBasket, [Component.MultiBasket]],
|
|
85
93
|
[Plugin.SavedCard, [Component.SavedCard]],
|
|
86
94
|
[Plugin.Hepsipay, [Component.Hepsipay]],
|
|
87
|
-
[Plugin.FlowPayment, [Component.FlowPayment]]
|
|
95
|
+
[Plugin.FlowPayment, [Component.FlowPayment]],
|
|
96
|
+
[
|
|
97
|
+
Plugin.SimilarProducts,
|
|
98
|
+
[
|
|
99
|
+
Component.SimilarProductsModal,
|
|
100
|
+
Component.SimilarProductsFilterSidebar,
|
|
101
|
+
Component.SimilarProductsResultsGrid,
|
|
102
|
+
Component.SimilarProductsPlugin,
|
|
103
|
+
Component.ProductImageSearchFeature,
|
|
104
|
+
Component.ImageSearchButton,
|
|
105
|
+
Component.HeaderImageSearchFeature
|
|
106
|
+
]
|
|
107
|
+
]
|
|
88
108
|
]);
|
|
89
109
|
|
|
90
110
|
const getPlugin = (component: Component) => {
|
|
@@ -153,6 +173,8 @@ export default function PluginModule({
|
|
|
153
173
|
promise = import(`${'@akinon/pz-hepsipay'}`);
|
|
154
174
|
} else if (plugin === Plugin.FlowPayment) {
|
|
155
175
|
promise = import(`${'@akinon/pz-flow-payment'}`);
|
|
176
|
+
} else if (plugin === Plugin.SimilarProducts) {
|
|
177
|
+
promise = import(`${'@akinon/pz-similar-products'}`);
|
|
156
178
|
}
|
|
157
179
|
} catch (error) {
|
|
158
180
|
logger.error(error);
|
package/data/urls.ts
CHANGED
|
@@ -182,7 +182,11 @@ export const product = {
|
|
|
182
182
|
breadcrumbUrl: (menuitemmodel: string) =>
|
|
183
183
|
`/menus/generate_breadcrumb/?item=${menuitemmodel}&generator_name=menu_item`,
|
|
184
184
|
bundleProduct: (productPk: string, queryString: string) =>
|
|
185
|
-
`/bundle-product/${productPk}/?${queryString}
|
|
185
|
+
`/bundle-product/${productPk}/?${queryString}`,
|
|
186
|
+
similarProducts: (params?: string) =>
|
|
187
|
+
`/similar-products${params ? `?${params}` : ''}`,
|
|
188
|
+
similarProductsList: (params?: string) =>
|
|
189
|
+
`/similar-product-list${params ? `?${params}` : ''}`
|
|
186
190
|
};
|
|
187
191
|
|
|
188
192
|
export const wishlist = {
|
|
@@ -34,6 +34,7 @@ const withCompleteGpay =
|
|
|
34
34
|
const url = req.nextUrl.clone();
|
|
35
35
|
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
36
36
|
const sessionId = req.cookies.get('osessionid');
|
|
37
|
+
const currentLocale = req.middlewareParams?.rewrites?.locale;
|
|
37
38
|
|
|
38
39
|
if (url.search.indexOf('GPayCompletePage') === -1) {
|
|
39
40
|
return middleware(req, event);
|
|
@@ -45,7 +46,9 @@ const withCompleteGpay =
|
|
|
45
46
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
46
47
|
Cookie: req.headers.get('cookie') ?? '',
|
|
47
48
|
'x-currency': req.cookies.get('pz-currency')?.value ?? '',
|
|
48
|
-
'x-forwarded-for': ip
|
|
49
|
+
'x-forwarded-for': ip,
|
|
50
|
+
'Accept-Language':
|
|
51
|
+
currentLocale ?? req.cookies.get('pz-locale')?.value ?? ''
|
|
49
52
|
};
|
|
50
53
|
|
|
51
54
|
try {
|
|
@@ -4,6 +4,7 @@ import { Buffer } from 'buffer';
|
|
|
4
4
|
import logger from '../utils/log';
|
|
5
5
|
import { getUrlPathWithLocale } from '../utils/localization';
|
|
6
6
|
import { PzNextRequest } from '.';
|
|
7
|
+
import { ServerVariables } from '../utils/server-variables';
|
|
7
8
|
|
|
8
9
|
const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
|
|
9
10
|
if (stream) {
|
|
@@ -34,6 +35,7 @@ const withCompleteMasterpass =
|
|
|
34
35
|
const url = req.nextUrl.clone();
|
|
35
36
|
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
36
37
|
const sessionId = req.cookies.get('osessionid');
|
|
38
|
+
const currentLocale = req.middlewareParams?.rewrites?.locale;
|
|
37
39
|
|
|
38
40
|
if (url.search.indexOf('MasterpassCompletePage') === -1) {
|
|
39
41
|
return middleware(req, event);
|
|
@@ -45,7 +47,9 @@ const withCompleteMasterpass =
|
|
|
45
47
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
46
48
|
Cookie: req.headers.get('cookie') ?? '',
|
|
47
49
|
'x-currency': req.cookies.get('pz-currency')?.value ?? '',
|
|
48
|
-
'x-forwarded-for': ip
|
|
50
|
+
'x-forwarded-for': ip,
|
|
51
|
+
'Accept-Language':
|
|
52
|
+
currentLocale ?? req.cookies.get('pz-locale')?.value ?? ''
|
|
49
53
|
};
|
|
50
54
|
|
|
51
55
|
try {
|
|
@@ -35,6 +35,7 @@ const withRedirectionPayment =
|
|
|
35
35
|
const searchParams = new URLSearchParams(url.search);
|
|
36
36
|
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
37
37
|
const sessionId = req.cookies.get('osessionid');
|
|
38
|
+
const currentLocale = req.middlewareParams?.rewrites?.locale;
|
|
38
39
|
|
|
39
40
|
if (searchParams.get('page') !== 'RedirectionPageCompletePage') {
|
|
40
41
|
return middleware(req, event);
|
|
@@ -46,7 +47,9 @@ const withRedirectionPayment =
|
|
|
46
47
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
47
48
|
Cookie: req.headers.get('cookie') ?? '',
|
|
48
49
|
'x-currency': req.cookies.get('pz-currency')?.value ?? '',
|
|
49
|
-
'x-forwarded-for': ip
|
|
50
|
+
'x-forwarded-for': ip,
|
|
51
|
+
'Accept-Language':
|
|
52
|
+
currentLocale ?? req.cookies.get('pz-locale')?.value ?? ''
|
|
50
53
|
};
|
|
51
54
|
|
|
52
55
|
try {
|
|
@@ -4,6 +4,7 @@ import { Buffer } from 'buffer';
|
|
|
4
4
|
import logger from '../utils/log';
|
|
5
5
|
import { getUrlPathWithLocale } from '../utils/localization';
|
|
6
6
|
import { PzNextRequest } from '.';
|
|
7
|
+
import { ServerVariables } from '../utils/server-variables';
|
|
7
8
|
|
|
8
9
|
const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
|
|
9
10
|
if (stream) {
|
|
@@ -34,6 +35,7 @@ const withSavedCardRedirection =
|
|
|
34
35
|
const url = req.nextUrl.clone();
|
|
35
36
|
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
36
37
|
const sessionId = req.cookies.get('osessionid');
|
|
38
|
+
const currentLocale = req.middlewareParams?.rewrites?.locale;
|
|
37
39
|
|
|
38
40
|
if (url.search.indexOf('SavedCardThreeDSecurePage') === -1) {
|
|
39
41
|
return middleware(req, event);
|
|
@@ -45,7 +47,9 @@ const withSavedCardRedirection =
|
|
|
45
47
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
46
48
|
Cookie: req.headers.get('cookie') ?? '',
|
|
47
49
|
'x-currency': req.cookies.get('pz-currency')?.value ?? '',
|
|
48
|
-
'x-forwarded-for': ip
|
|
50
|
+
'x-forwarded-for': ip,
|
|
51
|
+
'Accept-Language':
|
|
52
|
+
currentLocale ?? req.cookies.get('pz-locale')?.value ?? ''
|
|
49
53
|
};
|
|
50
54
|
|
|
51
55
|
try {
|
|
@@ -4,6 +4,7 @@ import { Buffer } from 'buffer';
|
|
|
4
4
|
import logger from '../utils/log';
|
|
5
5
|
import { getUrlPathWithLocale } from '../utils/localization';
|
|
6
6
|
import { PzNextRequest } from '.';
|
|
7
|
+
import { ServerVariables } from '../utils/server-variables';
|
|
7
8
|
|
|
8
9
|
const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
|
|
9
10
|
if (stream) {
|
|
@@ -34,6 +35,7 @@ const withThreeDRedirection =
|
|
|
34
35
|
const url = req.nextUrl.clone();
|
|
35
36
|
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
36
37
|
const sessionId = req.cookies.get('osessionid');
|
|
38
|
+
const currentLocale = req.middlewareParams?.rewrites?.locale;
|
|
37
39
|
|
|
38
40
|
if (url.search.indexOf('CreditCardThreeDSecurePage') === -1) {
|
|
39
41
|
return middleware(req, event);
|
|
@@ -45,7 +47,9 @@ const withThreeDRedirection =
|
|
|
45
47
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
46
48
|
Cookie: req.headers.get('cookie') ?? '',
|
|
47
49
|
'x-currency': req.cookies.get('pz-currency')?.value ?? '',
|
|
48
|
-
'x-forwarded-for': ip
|
|
50
|
+
'x-forwarded-for': ip,
|
|
51
|
+
'Accept-Language':
|
|
52
|
+
currentLocale ?? req.cookies.get('pz-locale')?.value ?? ''
|
|
49
53
|
};
|
|
50
54
|
|
|
51
55
|
try {
|
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.92.0-rc.
|
|
4
|
+
"version": "1.92.0-rc.17",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"set-cookie-parser": "2.6.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@akinon/eslint-plugin-projectzero": "1.92.0-rc.
|
|
37
|
+
"@akinon/eslint-plugin-projectzero": "1.92.0-rc.17",
|
|
38
38
|
"@babel/core": "7.26.10",
|
|
39
39
|
"@babel/preset-env": "7.26.9",
|
|
40
40
|
"@babel/preset-typescript": "7.27.0",
|
package/plugins.d.ts
CHANGED
|
@@ -38,3 +38,11 @@ declare module '@akinon/pz-iyzico-saved-card' {
|
|
|
38
38
|
declare module '@akinon/pz-apple-pay' {}
|
|
39
39
|
|
|
40
40
|
declare module '@akinon/pz-flow-payment' {}
|
|
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
|
+
}
|
package/plugins.js
CHANGED
package/types/index.ts
CHANGED
|
@@ -83,6 +83,12 @@ export interface Settings {
|
|
|
83
83
|
};
|
|
84
84
|
usePrettyUrlRoute?: boolean;
|
|
85
85
|
commerceUrl: string;
|
|
86
|
+
/**
|
|
87
|
+
* This option allows you to track Sentry events on the client side, in addition to server and edge environments.
|
|
88
|
+
*
|
|
89
|
+
* It overrides process.env.NEXT_PUBLIC_SENTRY_DSN and process.env.SENTRY_DSN.
|
|
90
|
+
*/
|
|
91
|
+
sentryDsn?: string;
|
|
86
92
|
redis: {
|
|
87
93
|
defaultExpirationTime: number;
|
|
88
94
|
};
|