@akinon/next 1.115.0-snapshot-ZERO-3895-20251210115756 → 1.116.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.
- package/CHANGELOG.md +21 -1
- package/api/image-proxy.ts +75 -0
- package/api/product-categories.ts +53 -0
- package/api/similar-product-list.ts +63 -0
- package/api/similar-products.ts +111 -0
- package/components/plugin-module.tsx +32 -4
- package/data/urls.ts +5 -1
- package/lib/cache-handler.mjs +12 -4
- package/middlewares/complete-gpay.ts +26 -16
- package/middlewares/complete-masterpass.ts +26 -16
- package/middlewares/complete-wallet.ts +26 -16
- package/middlewares/redirection-payment.ts +26 -16
- package/middlewares/saved-card-redirection.ts +26 -16
- package/middlewares/three-d-redirection.ts +26 -16
- package/middlewares/wallet-complete-redirection.ts +26 -16
- package/package.json +2 -2
- package/plugins.d.ts +10 -0
- package/plugins.js +4 -1
- package/types/index.ts +6 -0
- package/utils/mobile-3d-iframe.ts +8 -2
- package/utils/redirection-iframe.ts +8 -2
- package/with-pz-config.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
-
## 1.
|
|
3
|
+
## 1.116.0-rc.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d2c0e759: ZERO-3684: Handle cross-origin iframe access in iframeURLChange function
|
|
8
|
+
- b55acb76: ZERO-2577: Fix pagination bug and update usePagination hook and ensure pagination controls rendering correctly
|
|
9
|
+
- 143be2b9: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
10
|
+
- 9f8cd3bc: ZERO-3449: AI Search Active Filters & Crop Style changes have been implemented
|
|
11
|
+
- d99a6a7d: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
12
|
+
- 4de5303c: ZERO-2504: add cookie filter to api client request
|
|
13
|
+
- 95b139dc: ZERO-3795: Remove duplicate entry for SavedCard in PluginComponents map
|
|
14
|
+
|
|
15
|
+
## 1.115.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- b59bed4d: ZERO-3878: Reintegrated similar products and removed localStorage checks and implemented props based showing of buttons
|
|
20
|
+
- b5f9d75c: ZERO-3873: Refactor payment redirection middlewares to properly forward all set-cookie headers from upstream responses
|
|
21
|
+
- cbcfdf4d: ZERO-3859: Haso payment gateway implmeneted
|
|
22
|
+
- 71882722: ZERO-3897: Add compress option to default Next.js configuration
|
|
23
|
+
- 7056203a: ZERO-3875: removed shared_tags through stripTags function for unused keys
|
|
4
24
|
|
|
5
25
|
## 1.114.0
|
|
6
26
|
|
|
@@ -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,53 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { getProductData } from '@akinon/next/data/server';
|
|
3
|
+
|
|
4
|
+
export async function GET(request: NextRequest) {
|
|
5
|
+
try {
|
|
6
|
+
const { searchParams } = new URL(request.url);
|
|
7
|
+
const pksParam = searchParams.get('pks');
|
|
8
|
+
|
|
9
|
+
if (!pksParam) {
|
|
10
|
+
return NextResponse.json(
|
|
11
|
+
{ error: 'pks parameter required' },
|
|
12
|
+
{ status: 400 }
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const pks = pksParam.split(',').map(Number).filter(Boolean);
|
|
17
|
+
|
|
18
|
+
if (pks.length === 0) {
|
|
19
|
+
return NextResponse.json({ error: 'Invalid pks' }, { status: 400 });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const results = await Promise.all(
|
|
23
|
+
pks.map(async (pk) => {
|
|
24
|
+
try {
|
|
25
|
+
const { breadcrumbData } = await getProductData({ pk });
|
|
26
|
+
|
|
27
|
+
const categoryIds =
|
|
28
|
+
breadcrumbData
|
|
29
|
+
?.map((item: any) => item.extra_context?.attributes?.category_id)
|
|
30
|
+
.filter(Boolean) || [];
|
|
31
|
+
|
|
32
|
+
return { pk, categoryIds };
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(`Error fetching product ${pk}:`, error);
|
|
35
|
+
return { pk, categoryIds: [] };
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const mapping: Record<string, number[]> = {};
|
|
41
|
+
results.forEach(({ pk, categoryIds }) => {
|
|
42
|
+
mapping[String(pk)] = categoryIds;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return NextResponse.json(mapping);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error('Error in product-categories API:', error);
|
|
48
|
+
return NextResponse.json(
|
|
49
|
+
{ error: 'Internal server error' },
|
|
50
|
+
{ status: 500 }
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -24,7 +24,9 @@ enum Plugin {
|
|
|
24
24
|
FlowPayment = 'pz-flow-payment',
|
|
25
25
|
VirtualTryOn = 'pz-virtual-try-on',
|
|
26
26
|
Hepsipay = 'pz-hepsipay',
|
|
27
|
-
MasterpassRest = 'pz-masterpass-rest'
|
|
27
|
+
MasterpassRest = 'pz-masterpass-rest',
|
|
28
|
+
SimilarProducts = 'pz-similar-products',
|
|
29
|
+
Haso = 'pz-haso'
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
export enum Component {
|
|
@@ -55,7 +57,15 @@ export enum Component {
|
|
|
55
57
|
IyzicoSavedCard = 'IyzicoSavedCardOption',
|
|
56
58
|
Hepsipay = 'Hepsipay',
|
|
57
59
|
FlowPayment = 'FlowPayment',
|
|
58
|
-
MasterpassRest = 'MasterpassRestOption'
|
|
60
|
+
MasterpassRest = 'MasterpassRestOption',
|
|
61
|
+
SimilarProductsModal = 'SimilarProductsModal',
|
|
62
|
+
SimilarProductsFilterSidebar = 'SimilarProductsFilterSidebar',
|
|
63
|
+
SimilarProductsResultsGrid = 'SimilarProductsResultsGrid',
|
|
64
|
+
SimilarProductsPlugin = 'SimilarProductsPlugin',
|
|
65
|
+
ProductImageSearchFeature = 'ProductImageSearchFeature',
|
|
66
|
+
ImageSearchButton = 'ImageSearchButton',
|
|
67
|
+
HeaderImageSearchFeature = 'HeaderImageSearchFeature',
|
|
68
|
+
HasoPaymentGateway = 'HasoPaymentGateway'
|
|
59
69
|
}
|
|
60
70
|
|
|
61
71
|
const PluginComponents = new Map([
|
|
@@ -88,8 +98,19 @@ const PluginComponents = new Map([
|
|
|
88
98
|
[Component.AkifastQuickLoginButton, Component.AkifastCheckoutButton]
|
|
89
99
|
],
|
|
90
100
|
[Plugin.MultiBasket, [Component.MultiBasket]],
|
|
101
|
+
[
|
|
102
|
+
Plugin.SimilarProducts,
|
|
103
|
+
[
|
|
104
|
+
Component.SimilarProductsModal,
|
|
105
|
+
Component.SimilarProductsFilterSidebar,
|
|
106
|
+
Component.SimilarProductsResultsGrid,
|
|
107
|
+
Component.SimilarProductsPlugin,
|
|
108
|
+
Component.ProductImageSearchFeature,
|
|
109
|
+
Component.ImageSearchButton,
|
|
110
|
+
Component.HeaderImageSearchFeature
|
|
111
|
+
]
|
|
112
|
+
],
|
|
91
113
|
[Plugin.SavedCard, [Component.SavedCard, Component.IyzicoSavedCard]],
|
|
92
|
-
[Plugin.SavedCard, [Component.SavedCard]],
|
|
93
114
|
[Plugin.FlowPayment, [Component.FlowPayment]],
|
|
94
115
|
[
|
|
95
116
|
Plugin.VirtualTryOn,
|
|
@@ -97,7 +118,8 @@ const PluginComponents = new Map([
|
|
|
97
118
|
],
|
|
98
119
|
[Plugin.Hepsipay, [Component.Hepsipay]],
|
|
99
120
|
[Plugin.Hepsipay, [Component.Hepsipay]],
|
|
100
|
-
[Plugin.MasterpassRest, [Component.MasterpassRest]]
|
|
121
|
+
[Plugin.MasterpassRest, [Component.MasterpassRest]],
|
|
122
|
+
[Plugin.Haso, [Component.HasoPaymentGateway]]
|
|
101
123
|
]);
|
|
102
124
|
|
|
103
125
|
const getPlugin = (component: Component) => {
|
|
@@ -162,6 +184,8 @@ export default function PluginModule({
|
|
|
162
184
|
promise = import(`${'@akinon/pz-multi-basket'}`);
|
|
163
185
|
} else if (plugin === Plugin.SavedCard) {
|
|
164
186
|
promise = import(`${'@akinon/pz-saved-card'}`);
|
|
187
|
+
} else if (plugin === Plugin.SimilarProducts) {
|
|
188
|
+
promise = import(`${'@akinon/pz-similar-products'}`);
|
|
165
189
|
} else if (plugin === Plugin.Hepsipay) {
|
|
166
190
|
promise = import(`${'@akinon/pz-hepsipay'}`);
|
|
167
191
|
} else if (plugin === Plugin.FlowPayment) {
|
|
@@ -170,6 +194,10 @@ export default function PluginModule({
|
|
|
170
194
|
promise = import(`${'@akinon/pz-virtual-try-on'}`);
|
|
171
195
|
} else if (plugin === Plugin.MasterpassRest) {
|
|
172
196
|
promise = import(`${'@akinon/pz-masterpass-rest'}`);
|
|
197
|
+
} else if (plugin === Plugin.SimilarProducts) {
|
|
198
|
+
promise = import(`${'@akinon/pz-similar-products'}`);
|
|
199
|
+
} else if (plugin === Plugin.Haso) {
|
|
200
|
+
promise = import(`${'@akinon/pz-haso'}`);
|
|
173
201
|
}
|
|
174
202
|
} catch (error) {
|
|
175
203
|
logger.error(error);
|
package/data/urls.ts
CHANGED
|
@@ -183,7 +183,11 @@ export const product = {
|
|
|
183
183
|
breadcrumbUrl: (menuitemmodel: string) =>
|
|
184
184
|
`/menus/generate_breadcrumb/?item=${menuitemmodel}&generator_name=menu_item`,
|
|
185
185
|
bundleProduct: (productPk: string, queryString: string) =>
|
|
186
|
-
`/bundle-product/${productPk}/?${queryString}
|
|
186
|
+
`/bundle-product/${productPk}/?${queryString}`,
|
|
187
|
+
similarProducts: (params?: string) =>
|
|
188
|
+
`/similar-products${params ? `?${params}` : ''}`,
|
|
189
|
+
similarProductsList: (params?: string) =>
|
|
190
|
+
`/similar-product-list${params ? `?${params}` : ''}`
|
|
187
191
|
};
|
|
188
192
|
|
|
189
193
|
export const wishlist = {
|
package/lib/cache-handler.mjs
CHANGED
|
@@ -463,6 +463,14 @@ CacheHandler.onCreation(async () => {
|
|
|
463
463
|
set: async (key, value, context) => {
|
|
464
464
|
const vKey = versionKey(key);
|
|
465
465
|
|
|
466
|
+
const stripTags = (val) => {
|
|
467
|
+
if (val && typeof val === 'object') {
|
|
468
|
+
const { tags, ...rest } = val;
|
|
469
|
+
return { ...rest, tags: [] };
|
|
470
|
+
}
|
|
471
|
+
return val;
|
|
472
|
+
};
|
|
473
|
+
|
|
466
474
|
let compressedValue;
|
|
467
475
|
let shouldUseCompressed = false;
|
|
468
476
|
|
|
@@ -482,12 +490,12 @@ CacheHandler.onCreation(async () => {
|
|
|
482
490
|
|
|
483
491
|
if (shouldUseCompressed) {
|
|
484
492
|
try {
|
|
485
|
-
await redisHandler.set(vKey, compressedValue, context);
|
|
493
|
+
await redisHandler.set(vKey, stripTags(compressedValue), context);
|
|
486
494
|
|
|
487
495
|
redisSetResult = { status: 'fulfilled' };
|
|
488
496
|
} catch (compressionError) {
|
|
489
497
|
try {
|
|
490
|
-
await redisHandler.set(vKey, value, context);
|
|
498
|
+
await redisHandler.set(vKey, stripTags(value), context);
|
|
491
499
|
|
|
492
500
|
redisSetResult = { status: 'fulfilled' };
|
|
493
501
|
} catch (fallbackError) {
|
|
@@ -496,7 +504,7 @@ CacheHandler.onCreation(async () => {
|
|
|
496
504
|
}
|
|
497
505
|
} else {
|
|
498
506
|
try {
|
|
499
|
-
await redisHandler.set(vKey, value, context);
|
|
507
|
+
await redisHandler.set(vKey, stripTags(value), context);
|
|
500
508
|
redisSetResult = { status: 'fulfilled' };
|
|
501
509
|
} catch (error) {
|
|
502
510
|
redisSetResult = { status: 'rejected', reason: error };
|
|
@@ -510,8 +518,8 @@ CacheHandler.onCreation(async () => {
|
|
|
510
518
|
localSetResult = { status: 'fulfilled' };
|
|
511
519
|
} catch (error) {
|
|
512
520
|
localSetResult = { status: 'rejected', reason: error };
|
|
513
|
-
return localSetResult;
|
|
514
521
|
}
|
|
522
|
+
return localSetResult;
|
|
515
523
|
},
|
|
516
524
|
delete: async (key, context) => {
|
|
517
525
|
const vKey = versionKey(key);
|
|
@@ -64,7 +64,7 @@ const withCompleteGpay =
|
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const
|
|
67
|
+
const fetchResponse = await fetch(requestUrl, {
|
|
68
68
|
method: 'POST',
|
|
69
69
|
headers: requestHeaders,
|
|
70
70
|
body
|
|
@@ -72,14 +72,14 @@ const withCompleteGpay =
|
|
|
72
72
|
|
|
73
73
|
logger.info('Complete GPay payment request', {
|
|
74
74
|
requestUrl,
|
|
75
|
-
status:
|
|
75
|
+
status: fetchResponse.status,
|
|
76
76
|
requestHeaders,
|
|
77
77
|
ip
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
const
|
|
80
|
+
const responseData = await fetchResponse.json();
|
|
81
81
|
|
|
82
|
-
const { context_list: contextList, errors } =
|
|
82
|
+
const { context_list: contextList, errors } = responseData;
|
|
83
83
|
const redirectionContext = contextList?.find(
|
|
84
84
|
(context) => context.page_context?.redirect_url
|
|
85
85
|
);
|
|
@@ -93,18 +93,27 @@ const withCompleteGpay =
|
|
|
93
93
|
ip
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
const errorResponse = NextResponse.redirect(
|
|
97
97
|
`${url.origin}${getUrlPathWithLocale(
|
|
98
98
|
'/orders/checkout/',
|
|
99
99
|
req.cookies.get('pz-locale')?.value
|
|
100
100
|
)}`,
|
|
101
|
-
|
|
102
|
-
status: 303,
|
|
103
|
-
headers: {
|
|
104
|
-
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
105
|
-
}
|
|
106
|
-
}
|
|
101
|
+
303
|
|
107
102
|
);
|
|
103
|
+
|
|
104
|
+
// Forward set-cookie headers from the upstream response
|
|
105
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
106
|
+
setCookies.forEach((cookie) => {
|
|
107
|
+
errorResponse.headers.append('Set-Cookie', cookie);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Add error cookie
|
|
111
|
+
errorResponse.headers.append(
|
|
112
|
+
'Set-Cookie',
|
|
113
|
+
`pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return errorResponse;
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
logger.info('Order success page context list', {
|
|
@@ -119,7 +128,7 @@ const withCompleteGpay =
|
|
|
119
128
|
{
|
|
120
129
|
middleware: 'complete-gpay',
|
|
121
130
|
requestHeaders,
|
|
122
|
-
response: JSON.stringify(
|
|
131
|
+
response: JSON.stringify(responseData),
|
|
123
132
|
ip
|
|
124
133
|
}
|
|
125
134
|
);
|
|
@@ -147,10 +156,11 @@ const withCompleteGpay =
|
|
|
147
156
|
// So we use 303 status code to change the method to GET
|
|
148
157
|
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
149
158
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
// Forward all set-cookie headers from the upstream response
|
|
160
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
161
|
+
setCookies.forEach((cookie) => {
|
|
162
|
+
nextResponse.headers.append('Set-Cookie', cookie);
|
|
163
|
+
});
|
|
154
164
|
|
|
155
165
|
return nextResponse;
|
|
156
166
|
} catch (error) {
|
|
@@ -65,7 +65,7 @@ const withCompleteMasterpass =
|
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
const
|
|
68
|
+
const fetchResponse = await fetch(requestUrl, {
|
|
69
69
|
method: 'POST',
|
|
70
70
|
headers: requestHeaders,
|
|
71
71
|
body
|
|
@@ -73,14 +73,14 @@ const withCompleteMasterpass =
|
|
|
73
73
|
|
|
74
74
|
logger.info('Complete Masterpass payment request', {
|
|
75
75
|
requestUrl,
|
|
76
|
-
status:
|
|
76
|
+
status: fetchResponse.status,
|
|
77
77
|
requestHeaders,
|
|
78
78
|
ip
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
const
|
|
81
|
+
const responseData = await fetchResponse.json();
|
|
82
82
|
|
|
83
|
-
const { context_list: contextList, errors } =
|
|
83
|
+
const { context_list: contextList, errors } = responseData;
|
|
84
84
|
const redirectionContext = contextList?.find(
|
|
85
85
|
(context) => context.page_context?.redirect_url
|
|
86
86
|
);
|
|
@@ -94,18 +94,27 @@ const withCompleteMasterpass =
|
|
|
94
94
|
ip
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const errorResponse = NextResponse.redirect(
|
|
98
98
|
`${url.origin}${getUrlPathWithLocale(
|
|
99
99
|
'/orders/checkout/',
|
|
100
100
|
req.cookies.get('pz-locale')?.value
|
|
101
101
|
)}`,
|
|
102
|
-
|
|
103
|
-
status: 303,
|
|
104
|
-
headers: {
|
|
105
|
-
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
106
|
-
}
|
|
107
|
-
}
|
|
102
|
+
303
|
|
108
103
|
);
|
|
104
|
+
|
|
105
|
+
// Forward set-cookie headers from the upstream response
|
|
106
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
107
|
+
setCookies.forEach((cookie) => {
|
|
108
|
+
errorResponse.headers.append('Set-Cookie', cookie);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Add error cookie
|
|
112
|
+
errorResponse.headers.append(
|
|
113
|
+
'Set-Cookie',
|
|
114
|
+
`pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return errorResponse;
|
|
109
118
|
}
|
|
110
119
|
|
|
111
120
|
logger.info('Order success page context list', {
|
|
@@ -120,7 +129,7 @@ const withCompleteMasterpass =
|
|
|
120
129
|
{
|
|
121
130
|
middleware: 'complete-masterpass',
|
|
122
131
|
requestHeaders,
|
|
123
|
-
response: JSON.stringify(
|
|
132
|
+
response: JSON.stringify(responseData),
|
|
124
133
|
ip
|
|
125
134
|
}
|
|
126
135
|
);
|
|
@@ -148,10 +157,11 @@ const withCompleteMasterpass =
|
|
|
148
157
|
// So we use 303 status code to change the method to GET
|
|
149
158
|
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
150
159
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
// Forward all set-cookie headers from the upstream response
|
|
161
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
162
|
+
setCookies.forEach((cookie) => {
|
|
163
|
+
nextResponse.headers.append('Set-Cookie', cookie);
|
|
164
|
+
});
|
|
155
165
|
|
|
156
166
|
return nextResponse;
|
|
157
167
|
} catch (error) {
|
|
@@ -61,7 +61,7 @@ const withCompleteWallet =
|
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const
|
|
64
|
+
const fetchResponse = await fetch(requestUrl, {
|
|
65
65
|
method: 'POST',
|
|
66
66
|
headers: requestHeaders,
|
|
67
67
|
body
|
|
@@ -69,14 +69,14 @@ const withCompleteWallet =
|
|
|
69
69
|
|
|
70
70
|
logger.info('Complete Wallet payment request', {
|
|
71
71
|
requestUrl,
|
|
72
|
-
status:
|
|
72
|
+
status: fetchResponse.status,
|
|
73
73
|
requestHeaders,
|
|
74
74
|
ip
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
const
|
|
77
|
+
const responseData = await fetchResponse.json();
|
|
78
78
|
|
|
79
|
-
const { context_list: contextList, errors } =
|
|
79
|
+
const { context_list: contextList, errors } = responseData;
|
|
80
80
|
const redirectionContext = contextList?.find(
|
|
81
81
|
(context) => context.page_context?.redirect_url
|
|
82
82
|
);
|
|
@@ -90,18 +90,27 @@ const withCompleteWallet =
|
|
|
90
90
|
ip
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
const errorResponse = NextResponse.redirect(
|
|
94
94
|
`${url.origin}${getUrlPathWithLocale(
|
|
95
95
|
'/orders/checkout/',
|
|
96
96
|
req.cookies.get('pz-locale')?.value
|
|
97
97
|
)}`,
|
|
98
|
-
|
|
99
|
-
status: 303,
|
|
100
|
-
headers: {
|
|
101
|
-
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
102
|
-
}
|
|
103
|
-
}
|
|
98
|
+
303
|
|
104
99
|
);
|
|
100
|
+
|
|
101
|
+
// Forward set-cookie headers from the upstream response
|
|
102
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
103
|
+
setCookies.forEach((cookie) => {
|
|
104
|
+
errorResponse.headers.append('Set-Cookie', cookie);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Add error cookie
|
|
108
|
+
errorResponse.headers.append(
|
|
109
|
+
'Set-Cookie',
|
|
110
|
+
`pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
return errorResponse;
|
|
105
114
|
}
|
|
106
115
|
|
|
107
116
|
logger.info('Order success page context list', {
|
|
@@ -116,7 +125,7 @@ const withCompleteWallet =
|
|
|
116
125
|
{
|
|
117
126
|
middleware: 'complete-wallet',
|
|
118
127
|
requestHeaders,
|
|
119
|
-
response: JSON.stringify(
|
|
128
|
+
response: JSON.stringify(responseData),
|
|
120
129
|
ip
|
|
121
130
|
}
|
|
122
131
|
);
|
|
@@ -144,10 +153,11 @@ const withCompleteWallet =
|
|
|
144
153
|
// So we use 303 status code to change the method to GET
|
|
145
154
|
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
146
155
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
156
|
+
// Forward all set-cookie headers from the upstream response
|
|
157
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
158
|
+
setCookies.forEach((cookie) => {
|
|
159
|
+
nextResponse.headers.append('Set-Cookie', cookie);
|
|
160
|
+
});
|
|
151
161
|
|
|
152
162
|
return nextResponse;
|
|
153
163
|
} catch (error) {
|
|
@@ -65,7 +65,7 @@ const withRedirectionPayment =
|
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
const
|
|
68
|
+
const fetchResponse = await fetch(requestUrl, {
|
|
69
69
|
method: 'POST',
|
|
70
70
|
headers: requestHeaders,
|
|
71
71
|
body
|
|
@@ -73,14 +73,14 @@ const withRedirectionPayment =
|
|
|
73
73
|
|
|
74
74
|
logger.info('Complete redirection payment request', {
|
|
75
75
|
requestUrl,
|
|
76
|
-
status:
|
|
76
|
+
status: fetchResponse.status,
|
|
77
77
|
requestHeaders,
|
|
78
78
|
ip
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
const
|
|
81
|
+
const responseData = await fetchResponse.json();
|
|
82
82
|
|
|
83
|
-
const { context_list: contextList, errors } =
|
|
83
|
+
const { context_list: contextList, errors } = responseData;
|
|
84
84
|
const redirectionContext = contextList?.find(
|
|
85
85
|
(context) => context.page_context?.redirect_url
|
|
86
86
|
);
|
|
@@ -94,18 +94,27 @@ const withRedirectionPayment =
|
|
|
94
94
|
ip
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const errorResponse = NextResponse.redirect(
|
|
98
98
|
`${url.origin}${getUrlPathWithLocale(
|
|
99
99
|
'/orders/checkout/',
|
|
100
100
|
req.cookies.get('pz-locale')?.value
|
|
101
101
|
)}`,
|
|
102
|
-
|
|
103
|
-
status: 303,
|
|
104
|
-
headers: {
|
|
105
|
-
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
106
|
-
}
|
|
107
|
-
}
|
|
102
|
+
303
|
|
108
103
|
);
|
|
104
|
+
|
|
105
|
+
// Forward set-cookie headers from the upstream response
|
|
106
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
107
|
+
setCookies.forEach((cookie) => {
|
|
108
|
+
errorResponse.headers.append('Set-Cookie', cookie);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Add error cookie
|
|
112
|
+
errorResponse.headers.append(
|
|
113
|
+
'Set-Cookie',
|
|
114
|
+
`pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return errorResponse;
|
|
109
118
|
}
|
|
110
119
|
|
|
111
120
|
logger.info('Order success page context list', {
|
|
@@ -120,7 +129,7 @@ const withRedirectionPayment =
|
|
|
120
129
|
{
|
|
121
130
|
middleware: 'redirection-payment',
|
|
122
131
|
requestHeaders,
|
|
123
|
-
response: JSON.stringify(
|
|
132
|
+
response: JSON.stringify(responseData),
|
|
124
133
|
ip
|
|
125
134
|
}
|
|
126
135
|
);
|
|
@@ -148,10 +157,11 @@ const withRedirectionPayment =
|
|
|
148
157
|
// So we use 303 status code to change the method to GET
|
|
149
158
|
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
150
159
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
// Forward all set-cookie headers from the upstream response
|
|
161
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
162
|
+
setCookies.forEach((cookie) => {
|
|
163
|
+
nextResponse.headers.append('Set-Cookie', cookie);
|
|
164
|
+
});
|
|
155
165
|
|
|
156
166
|
return nextResponse;
|
|
157
167
|
} catch (error) {
|
|
@@ -65,7 +65,7 @@ const withSavedCardRedirection =
|
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
const
|
|
68
|
+
const fetchResponse = await fetch(requestUrl, {
|
|
69
69
|
method: 'POST',
|
|
70
70
|
headers: requestHeaders,
|
|
71
71
|
body
|
|
@@ -73,14 +73,14 @@ const withSavedCardRedirection =
|
|
|
73
73
|
|
|
74
74
|
logger.info('Complete 3D payment request', {
|
|
75
75
|
requestUrl,
|
|
76
|
-
status:
|
|
76
|
+
status: fetchResponse.status,
|
|
77
77
|
requestHeaders,
|
|
78
78
|
ip
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
const
|
|
81
|
+
const responseData = await fetchResponse.json();
|
|
82
82
|
|
|
83
|
-
const { context_list: contextList, errors } =
|
|
83
|
+
const { context_list: contextList, errors } = responseData;
|
|
84
84
|
const redirectionContext = contextList?.find(
|
|
85
85
|
(context) => context.page_context?.redirect_url
|
|
86
86
|
);
|
|
@@ -94,18 +94,27 @@ const withSavedCardRedirection =
|
|
|
94
94
|
ip
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const errorResponse = NextResponse.redirect(
|
|
98
98
|
`${url.origin}${getUrlPathWithLocale(
|
|
99
99
|
'/orders/checkout/',
|
|
100
100
|
req.cookies.get('pz-locale')?.value
|
|
101
101
|
)}`,
|
|
102
|
-
|
|
103
|
-
status: 303,
|
|
104
|
-
headers: {
|
|
105
|
-
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
106
|
-
}
|
|
107
|
-
}
|
|
102
|
+
303
|
|
108
103
|
);
|
|
104
|
+
|
|
105
|
+
// Forward set-cookie headers from the upstream response
|
|
106
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
107
|
+
setCookies.forEach((cookie) => {
|
|
108
|
+
errorResponse.headers.append('Set-Cookie', cookie);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Add error cookie
|
|
112
|
+
errorResponse.headers.append(
|
|
113
|
+
'Set-Cookie',
|
|
114
|
+
`pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return errorResponse;
|
|
109
118
|
}
|
|
110
119
|
|
|
111
120
|
logger.info('Order success page context list', {
|
|
@@ -120,7 +129,7 @@ const withSavedCardRedirection =
|
|
|
120
129
|
{
|
|
121
130
|
middleware: 'saved-card-redirection',
|
|
122
131
|
requestHeaders,
|
|
123
|
-
response: JSON.stringify(
|
|
132
|
+
response: JSON.stringify(responseData),
|
|
124
133
|
ip
|
|
125
134
|
}
|
|
126
135
|
);
|
|
@@ -148,10 +157,11 @@ const withSavedCardRedirection =
|
|
|
148
157
|
// So we use 303 status code to change the method to GET
|
|
149
158
|
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
150
159
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
// Forward all set-cookie headers from the upstream response
|
|
161
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
162
|
+
setCookies.forEach((cookie) => {
|
|
163
|
+
nextResponse.headers.append('Set-Cookie', cookie);
|
|
164
|
+
});
|
|
155
165
|
|
|
156
166
|
return nextResponse;
|
|
157
167
|
} catch (error) {
|
|
@@ -64,7 +64,7 @@ const withThreeDRedirection =
|
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const
|
|
67
|
+
const fetchResponse = await fetch(requestUrl, {
|
|
68
68
|
method: 'POST',
|
|
69
69
|
headers: requestHeaders,
|
|
70
70
|
body
|
|
@@ -72,14 +72,14 @@ const withThreeDRedirection =
|
|
|
72
72
|
|
|
73
73
|
logger.info('Complete 3D payment request', {
|
|
74
74
|
requestUrl,
|
|
75
|
-
status:
|
|
75
|
+
status: fetchResponse.status,
|
|
76
76
|
requestHeaders,
|
|
77
77
|
ip
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
const
|
|
80
|
+
const responseData = await fetchResponse.json();
|
|
81
81
|
|
|
82
|
-
const { context_list: contextList, errors } =
|
|
82
|
+
const { context_list: contextList, errors } = responseData;
|
|
83
83
|
const redirectionContext = contextList?.find(
|
|
84
84
|
(context) => context.page_context?.redirect_url
|
|
85
85
|
);
|
|
@@ -93,18 +93,27 @@ const withThreeDRedirection =
|
|
|
93
93
|
ip
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
const errorResponse = NextResponse.redirect(
|
|
97
97
|
`${url.origin}${getUrlPathWithLocale(
|
|
98
98
|
'/orders/checkout/',
|
|
99
99
|
req.cookies.get('pz-locale')?.value
|
|
100
100
|
)}`,
|
|
101
|
-
|
|
102
|
-
status: 303,
|
|
103
|
-
headers: {
|
|
104
|
-
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
105
|
-
}
|
|
106
|
-
}
|
|
101
|
+
303
|
|
107
102
|
);
|
|
103
|
+
|
|
104
|
+
// Forward set-cookie headers from the upstream response
|
|
105
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
106
|
+
setCookies.forEach((cookie) => {
|
|
107
|
+
errorResponse.headers.append('Set-Cookie', cookie);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Add error cookie
|
|
111
|
+
errorResponse.headers.append(
|
|
112
|
+
'Set-Cookie',
|
|
113
|
+
`pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return errorResponse;
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
logger.info('Order success page context list', {
|
|
@@ -119,7 +128,7 @@ const withThreeDRedirection =
|
|
|
119
128
|
{
|
|
120
129
|
middleware: 'three-d-redirection',
|
|
121
130
|
requestHeaders,
|
|
122
|
-
response: JSON.stringify(
|
|
131
|
+
response: JSON.stringify(responseData),
|
|
123
132
|
ip
|
|
124
133
|
}
|
|
125
134
|
);
|
|
@@ -147,10 +156,11 @@ const withThreeDRedirection =
|
|
|
147
156
|
// So we use 303 status code to change the method to GET
|
|
148
157
|
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
149
158
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
// Forward all set-cookie headers from the upstream response
|
|
160
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
161
|
+
setCookies.forEach((cookie) => {
|
|
162
|
+
nextResponse.headers.append('Set-Cookie', cookie);
|
|
163
|
+
});
|
|
154
164
|
|
|
155
165
|
return nextResponse;
|
|
156
166
|
} catch (error) {
|
|
@@ -85,7 +85,7 @@ const withWalletCompleteRedirection =
|
|
|
85
85
|
);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const
|
|
88
|
+
const fetchResponse = await fetch(requestUrl, {
|
|
89
89
|
method: 'POST',
|
|
90
90
|
headers: requestHeaders,
|
|
91
91
|
body
|
|
@@ -93,14 +93,14 @@ const withWalletCompleteRedirection =
|
|
|
93
93
|
|
|
94
94
|
logger.info('Complete wallet payment request', {
|
|
95
95
|
requestUrl,
|
|
96
|
-
status:
|
|
96
|
+
status: fetchResponse.status,
|
|
97
97
|
requestHeaders,
|
|
98
98
|
ip
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
-
const
|
|
101
|
+
const responseData = await fetchResponse.json();
|
|
102
102
|
|
|
103
|
-
const { context_list: contextList, errors } =
|
|
103
|
+
const { context_list: contextList, errors } = responseData;
|
|
104
104
|
const redirectionContext = contextList?.find(
|
|
105
105
|
(context) => context.page_context?.redirect_url
|
|
106
106
|
);
|
|
@@ -114,18 +114,27 @@ const withWalletCompleteRedirection =
|
|
|
114
114
|
ip
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
const errorResponse = NextResponse.redirect(
|
|
118
118
|
`${url.origin}${getUrlPathWithLocale(
|
|
119
119
|
'/orders/checkout/',
|
|
120
120
|
req.cookies.get('pz-locale')?.value
|
|
121
121
|
)}`,
|
|
122
|
-
|
|
123
|
-
status: 303,
|
|
124
|
-
headers: {
|
|
125
|
-
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
126
|
-
}
|
|
127
|
-
}
|
|
122
|
+
303
|
|
128
123
|
);
|
|
124
|
+
|
|
125
|
+
// Forward set-cookie headers from the upstream response
|
|
126
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
127
|
+
setCookies.forEach((cookie) => {
|
|
128
|
+
errorResponse.headers.append('Set-Cookie', cookie);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Add error cookie
|
|
132
|
+
errorResponse.headers.append(
|
|
133
|
+
'Set-Cookie',
|
|
134
|
+
`pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
return errorResponse;
|
|
129
138
|
}
|
|
130
139
|
|
|
131
140
|
logger.info('Order success page context list', {
|
|
@@ -140,7 +149,7 @@ const withWalletCompleteRedirection =
|
|
|
140
149
|
{
|
|
141
150
|
middleware: 'wallet-complete-redirection',
|
|
142
151
|
requestHeaders,
|
|
143
|
-
response: JSON.stringify(
|
|
152
|
+
response: JSON.stringify(responseData),
|
|
144
153
|
ip
|
|
145
154
|
}
|
|
146
155
|
);
|
|
@@ -168,10 +177,11 @@ const withWalletCompleteRedirection =
|
|
|
168
177
|
// So we use 303 status code to change the method to GET
|
|
169
178
|
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
170
179
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
180
|
+
// Forward all set-cookie headers from the upstream response
|
|
181
|
+
const setCookies = fetchResponse.headers.getSetCookie?.() ?? [];
|
|
182
|
+
setCookies.forEach((cookie) => {
|
|
183
|
+
nextResponse.headers.append('Set-Cookie', cookie);
|
|
184
|
+
});
|
|
175
185
|
|
|
176
186
|
return nextResponse;
|
|
177
187
|
} catch (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.
|
|
4
|
+
"version": "1.116.0-rc.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"set-cookie-parser": "2.6.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@akinon/eslint-plugin-projectzero": "1.
|
|
38
|
+
"@akinon/eslint-plugin-projectzero": "1.116.0-rc.0",
|
|
39
39
|
"@babel/core": "7.26.10",
|
|
40
40
|
"@babel/preset-env": "7.26.9",
|
|
41
41
|
"@babel/preset-typescript": "7.27.0",
|
package/plugins.d.ts
CHANGED
|
@@ -37,6 +37,16 @@ declare module '@akinon/pz-cybersource-uc/src/redux/middleware' {
|
|
|
37
37
|
export default middleware as any;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
declare module '@akinon/pz-apple-pay' {}
|
|
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
|
+
}
|
|
49
|
+
|
|
40
50
|
declare module '@akinon/pz-cybersource-uc/src/redux/reducer' {
|
|
41
51
|
export default reducer as any;
|
|
42
52
|
}
|
package/plugins.js
CHANGED
|
@@ -16,9 +16,12 @@ module.exports = [
|
|
|
16
16
|
'pz-tabby-extension',
|
|
17
17
|
'pz-apple-pay',
|
|
18
18
|
'pz-tamara-extension',
|
|
19
|
+
'pz-similar-products',
|
|
19
20
|
'pz-cybersource-uc',
|
|
20
21
|
'pz-hepsipay',
|
|
21
22
|
'pz-flow-payment',
|
|
22
23
|
'pz-virtual-try-on',
|
|
23
|
-
'pz-masterpass-rest'
|
|
24
|
+
'pz-masterpass-rest',
|
|
25
|
+
'pz-similar-products',
|
|
26
|
+
'pz-haso'
|
|
24
27
|
];
|
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
|
};
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
const iframeURLChange = (iframe, callback) => {
|
|
2
2
|
iframe.addEventListener('load', () => {
|
|
3
3
|
setTimeout(() => {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
try {
|
|
5
|
+
if (iframe?.contentWindow?.location) {
|
|
6
|
+
const iframeLocation = iframe.contentWindow.location;
|
|
7
|
+
|
|
8
|
+
callback(iframeLocation);
|
|
9
|
+
}
|
|
10
|
+
} catch (error) {
|
|
11
|
+
// Expected: browser blocks cross-origin iframe access for security
|
|
6
12
|
}
|
|
7
13
|
}, 0);
|
|
8
14
|
});
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
const iframeURLChange = (iframe, callback) => {
|
|
2
2
|
iframe.addEventListener('load', () => {
|
|
3
3
|
setTimeout(() => {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
try {
|
|
5
|
+
if (iframe?.contentWindow?.location) {
|
|
6
|
+
const iframeLocation = iframe.contentWindow.location;
|
|
7
|
+
|
|
8
|
+
callback(iframeLocation);
|
|
9
|
+
}
|
|
10
|
+
} catch (error) {
|
|
11
|
+
// Expected: browser blocks cross-origin iframe access for security
|
|
6
12
|
}
|
|
7
13
|
}, 0);
|
|
8
14
|
});
|