@akinon/next 1.111.0-snapshot-ZERO-3792-20251107072714 → 1.111.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 +3 -2
- package/api/virtual-try-on.ts +9 -83
- package/components/plugin-module.tsx +13 -12
- package/components/selected-payment-option-view.tsx +1 -0
- package/hooks/use-payment-options.ts +2 -1
- package/middlewares/default.ts +217 -208
- package/middlewares/index.ts +3 -1
- package/middlewares/masterpass-rest-callback.ts +218 -0
- package/package.json +2 -2
- package/plugins.d.ts +5 -0
- package/plugins.js +2 -1
- package/redux/middlewares/checkout.ts +4 -1
- package/redux/middlewares/pre-order/installment-option.ts +1 -0
- package/redux/reducers/index.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
-
## 1.111.0
|
|
3
|
+
## 1.111.0
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- c026300: ZERO-3833: fix masterpass rest conflicts
|
|
8
|
+
- b47b9d8: ZERO-3414: create masterpass-rest package
|
|
8
9
|
|
|
9
10
|
## 1.110.0
|
|
10
11
|
|
package/api/virtual-try-on.ts
CHANGED
|
@@ -122,55 +122,6 @@ export async function GET(request: NextRequest) {
|
|
|
122
122
|
'X-Virtual-Try-On-Cache-Status': 'MISS'
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
|
-
} else if (endpoint === 'job-status') {
|
|
126
|
-
const referenceUrl = searchParams.get('reference_url');
|
|
127
|
-
if (!referenceUrl) {
|
|
128
|
-
return NextResponse.json(
|
|
129
|
-
{ error: 'reference_url is required' },
|
|
130
|
-
{ status: 400 }
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const externalUrl = `${VIRTUAL_TRY_ON_API_URL}/api/async/v1/job-status?reference_url=${encodeURIComponent(referenceUrl)}`;
|
|
135
|
-
const clientIP = getClientIP(request);
|
|
136
|
-
const locale = getLocaleFromRequest(request);
|
|
137
|
-
|
|
138
|
-
const headersToSend = {
|
|
139
|
-
Accept: 'application/json',
|
|
140
|
-
...(locale && { 'Accept-Language': locale }),
|
|
141
|
-
...(request.headers.get('authorization') && {
|
|
142
|
-
Authorization: request.headers.get('authorization')!
|
|
143
|
-
}),
|
|
144
|
-
...(clientIP && {
|
|
145
|
-
'X-Forwarded-For': clientIP
|
|
146
|
-
})
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const response = await fetch(externalUrl, {
|
|
150
|
-
method: 'GET',
|
|
151
|
-
headers: headersToSend
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
let responseData: any;
|
|
155
|
-
const responseText = await response.text();
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
responseData = responseText ? JSON.parse(responseText) : {};
|
|
159
|
-
} catch (parseError) {
|
|
160
|
-
return NextResponse.json(
|
|
161
|
-
{ error: 'Invalid JSON response from job status API' },
|
|
162
|
-
{ status: 500 }
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return NextResponse.json(responseData, {
|
|
167
|
-
status: response.status,
|
|
168
|
-
headers: {
|
|
169
|
-
'Access-Control-Allow-Origin': '*',
|
|
170
|
-
'Access-Control-Allow-Methods': 'GET, POST, PUT, OPTIONS',
|
|
171
|
-
'Access-Control-Allow-Headers': 'Content-Type, Accept, Authorization'
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
125
|
}
|
|
175
126
|
|
|
176
127
|
return NextResponse.json(
|
|
@@ -190,32 +141,13 @@ export async function POST(request: NextRequest) {
|
|
|
190
141
|
const body = await request.json();
|
|
191
142
|
|
|
192
143
|
let externalUrl: string;
|
|
193
|
-
let httpMethod = 'POST';
|
|
194
|
-
|
|
195
144
|
if (endpoint === 'feedback') {
|
|
196
|
-
if (!body.url || typeof body.url !== 'string' || !body.url.trim()) {
|
|
197
|
-
return NextResponse.json(
|
|
198
|
-
{ status: 'error', message: 'URL is required for feedback' },
|
|
199
|
-
{ status: 400 }
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
if (typeof body.feedback !== 'boolean') {
|
|
203
|
-
return NextResponse.json(
|
|
204
|
-
{ status: 'error', message: 'Feedback must be a boolean value' },
|
|
205
|
-
{ status: 400 }
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
145
|
externalUrl = `${VIRTUAL_TRY_ON_API_URL}/api/v1/feedback`;
|
|
209
|
-
httpMethod = 'PUT';
|
|
210
|
-
} else if (endpoint === 'async-multiple-try-on') {
|
|
211
|
-
externalUrl = `${VIRTUAL_TRY_ON_API_URL}/api/async/v1/multiple-virtual-try-on`;
|
|
212
146
|
} else {
|
|
213
|
-
|
|
214
|
-
{ error: 'Invalid endpoint specified' },
|
|
215
|
-
{ status: 400 }
|
|
216
|
-
);
|
|
147
|
+
externalUrl = `${VIRTUAL_TRY_ON_API_URL}/api/v1/virtual-try-on`;
|
|
217
148
|
}
|
|
218
149
|
|
|
150
|
+
const httpMethod = endpoint === 'feedback' ? 'PUT' : 'POST';
|
|
219
151
|
const clientIP = getClientIP(request);
|
|
220
152
|
const locale = getLocaleFromRequest(request);
|
|
221
153
|
|
|
@@ -231,18 +163,13 @@ export async function POST(request: NextRequest) {
|
|
|
231
163
|
})
|
|
232
164
|
};
|
|
233
165
|
|
|
234
|
-
const
|
|
166
|
+
const response = await fetch(externalUrl, {
|
|
235
167
|
method: httpMethod,
|
|
236
|
-
headers: headersToSend
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if (httpMethod !== 'GET') {
|
|
240
|
-
fetchOptions.body = JSON.stringify(body);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const response = await fetch(externalUrl, fetchOptions);
|
|
168
|
+
headers: headersToSend,
|
|
169
|
+
body: JSON.stringify(body)
|
|
170
|
+
});
|
|
244
171
|
|
|
245
|
-
let responseData:
|
|
172
|
+
let responseData: any;
|
|
246
173
|
const responseText = await response.text();
|
|
247
174
|
|
|
248
175
|
if (endpoint === 'feedback') {
|
|
@@ -346,7 +273,7 @@ export async function PUT(request: NextRequest) {
|
|
|
346
273
|
body: JSON.stringify(body)
|
|
347
274
|
});
|
|
348
275
|
|
|
349
|
-
const responseData = response
|
|
276
|
+
const responseData = await response.json();
|
|
350
277
|
|
|
351
278
|
return NextResponse.json(responseData, {
|
|
352
279
|
status: response.status,
|
|
@@ -360,8 +287,7 @@ export async function PUT(request: NextRequest) {
|
|
|
360
287
|
return NextResponse.json(
|
|
361
288
|
{
|
|
362
289
|
status: 'error',
|
|
363
|
-
message: 'Internal server error occurred during feedback submission'
|
|
364
|
-
error: (error as Error).message
|
|
290
|
+
message: 'Internal server error occurred during feedback submission'
|
|
365
291
|
},
|
|
366
292
|
{ status: 500 }
|
|
367
293
|
);
|
|
@@ -23,7 +23,8 @@ enum Plugin {
|
|
|
23
23
|
SavedCard = 'pz-saved-card',
|
|
24
24
|
FlowPayment = 'pz-flow-payment',
|
|
25
25
|
VirtualTryOn = 'pz-virtual-try-on',
|
|
26
|
-
Hepsipay = 'pz-hepsipay'
|
|
26
|
+
Hepsipay = 'pz-hepsipay',
|
|
27
|
+
MasterpassRest = 'pz-masterpass-rest'
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export enum Component {
|
|
@@ -50,10 +51,10 @@ export enum Component {
|
|
|
50
51
|
MultiBasket = 'MultiBasket',
|
|
51
52
|
SavedCard = 'SavedCardOption',
|
|
52
53
|
VirtualTryOnPlugin = 'VirtualTryOnPlugin',
|
|
53
|
-
BasketVirtualTryOn = 'BasketVirtualTryOn',
|
|
54
54
|
IyzicoSavedCard = 'IyzicoSavedCardOption',
|
|
55
55
|
Hepsipay = 'Hepsipay',
|
|
56
|
-
FlowPayment = 'FlowPayment'
|
|
56
|
+
FlowPayment = 'FlowPayment',
|
|
57
|
+
MasterpassRest = 'MasterpassRestOption'
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
const PluginComponents = new Map([
|
|
@@ -89,11 +90,9 @@ const PluginComponents = new Map([
|
|
|
89
90
|
[Plugin.SavedCard, [Component.SavedCard, Component.IyzicoSavedCard]],
|
|
90
91
|
[Plugin.SavedCard, [Component.SavedCard]],
|
|
91
92
|
[Plugin.FlowPayment, [Component.FlowPayment]],
|
|
92
|
-
[
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
],
|
|
96
|
-
[Plugin.Hepsipay, [Component.Hepsipay]]
|
|
93
|
+
[Plugin.VirtualTryOn, [Component.VirtualTryOnPlugin]],
|
|
94
|
+
[Plugin.Hepsipay, [Component.Hepsipay]],
|
|
95
|
+
[Plugin.MasterpassRest, [Component.MasterpassRest]]
|
|
97
96
|
]);
|
|
98
97
|
|
|
99
98
|
const getPlugin = (component: Component) => {
|
|
@@ -105,10 +104,10 @@ const getPlugin = (component: Component) => {
|
|
|
105
104
|
};
|
|
106
105
|
|
|
107
106
|
export default function PluginModule({
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}: {
|
|
107
|
+
component,
|
|
108
|
+
props,
|
|
109
|
+
children
|
|
110
|
+
}: {
|
|
112
111
|
component: Component;
|
|
113
112
|
props?: any;
|
|
114
113
|
children?: React.ReactNode;
|
|
@@ -164,6 +163,8 @@ export default function PluginModule({
|
|
|
164
163
|
promise = import(`${'@akinon/pz-flow-payment'}`);
|
|
165
164
|
} else if (plugin === Plugin.VirtualTryOn) {
|
|
166
165
|
promise = import(`${'@akinon/pz-virtual-try-on'}`);
|
|
166
|
+
} else if (plugin === Plugin.MasterpassRest) {
|
|
167
|
+
promise = import(`${'@akinon/pz-masterpass-rest'}`);
|
|
167
168
|
}
|
|
168
169
|
} catch (error) {
|
|
169
170
|
logger.error(error);
|
|
@@ -21,7 +21,8 @@ export const usePaymentOptions = () => {
|
|
|
21
21
|
credit_payment: 'pz-credit-payment',
|
|
22
22
|
masterpass: 'pz-masterpass',
|
|
23
23
|
saved_card: 'pz-saved-card',
|
|
24
|
-
gpay: 'pz-gpay'
|
|
24
|
+
gpay: 'pz-gpay',
|
|
25
|
+
masterpass_rest: 'pz-masterpass-rest'
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
const isInitialTypeIncluded = (type: string) => initialTypes.has(type);
|
package/middlewares/default.ts
CHANGED
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
withThreeDRedirection,
|
|
14
14
|
withUrlRedirection,
|
|
15
15
|
withCompleteWallet,
|
|
16
|
-
withWalletCompleteRedirection
|
|
16
|
+
withWalletCompleteRedirection,
|
|
17
|
+
withMasterpassRestCallback
|
|
17
18
|
} from '.';
|
|
18
19
|
import { urlLocaleMatcherRegex } from '../utils';
|
|
19
20
|
import withCurrency from './currency';
|
|
@@ -230,226 +231,235 @@ const withPzDefault =
|
|
|
230
231
|
withCompleteMasterpass(
|
|
231
232
|
withSavedCardRedirection(
|
|
232
233
|
withCompleteWallet(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
234
|
+
withWalletCompleteRedirection(
|
|
235
|
+
withMasterpassRestCallback(
|
|
236
|
+
async (
|
|
237
|
+
req: PzNextRequest,
|
|
238
|
+
event: NextFetchEvent
|
|
239
|
+
) => {
|
|
240
|
+
let middlewareResult: NextResponse | void =
|
|
241
|
+
NextResponse.next();
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const { locale, prettyUrl, currency } =
|
|
245
|
+
req.middlewareParams.rewrites;
|
|
246
|
+
const { defaultLocaleValue } =
|
|
247
|
+
Settings.localization;
|
|
248
|
+
const url = req.nextUrl.clone();
|
|
249
|
+
const pathnameWithoutLocale =
|
|
250
|
+
url.pathname.replace(
|
|
251
|
+
urlLocaleMatcherRegex,
|
|
252
|
+
''
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
middlewareResult = (await middleware(
|
|
256
|
+
req,
|
|
257
|
+
event
|
|
258
|
+
)) as NextResponse | void;
|
|
259
|
+
|
|
260
|
+
let customRewriteUrlDiff = '';
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
middlewareResult instanceof
|
|
264
|
+
NextResponse &&
|
|
265
|
+
middlewareResult.headers.get(
|
|
266
|
+
'pz-override-response'
|
|
267
|
+
) &&
|
|
268
|
+
middlewareResult.headers.get(
|
|
269
|
+
'x-middleware-rewrite'
|
|
270
|
+
)
|
|
271
|
+
) {
|
|
272
|
+
const rewriteUrl = new URL(
|
|
273
|
+
middlewareResult.headers.get(
|
|
274
|
+
'x-middleware-rewrite'
|
|
275
|
+
)
|
|
276
|
+
);
|
|
277
|
+
const originalUrl = new URL(req.url);
|
|
278
|
+
customRewriteUrlDiff =
|
|
279
|
+
rewriteUrl.pathname.replace(
|
|
280
|
+
originalUrl.pathname,
|
|
281
|
+
''
|
|
282
|
+
);
|
|
283
|
+
}
|
|
281
284
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
285
|
+
url.basePath = `/${commerceUrl}`;
|
|
286
|
+
url.pathname = `/${
|
|
287
|
+
locale.length ? `${locale}/` : ''
|
|
288
|
+
}${currency}/${customRewriteUrlDiff}${
|
|
289
|
+
prettyUrl ?? pathnameWithoutLocale
|
|
290
|
+
}`.replace(/\/+/g, '/');
|
|
291
|
+
|
|
292
|
+
if (
|
|
293
|
+
Settings.usePrettyUrlRoute &&
|
|
294
|
+
url.searchParams.toString().length > 0 &&
|
|
295
|
+
!Object.entries(ROUTES).find(
|
|
296
|
+
([, value]) =>
|
|
297
|
+
new RegExp(`^${value}/?$`).test(
|
|
298
|
+
pathnameWithoutLocale
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
) {
|
|
302
|
+
url.pathname =
|
|
303
|
+
url.pathname +
|
|
304
|
+
(/\/$/.test(url.pathname) ? '' : '/') +
|
|
305
|
+
`searchparams|${encodeURIComponent(
|
|
306
|
+
url.searchParams.toString()
|
|
307
|
+
)}`;
|
|
308
|
+
}
|
|
305
309
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
310
|
+
Settings.rewrites.forEach((rewrite) => {
|
|
311
|
+
url.pathname = url.pathname.replace(
|
|
312
|
+
rewrite.source,
|
|
313
|
+
rewrite.destination
|
|
314
|
+
);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// if middleware.ts has a return value for current url
|
|
318
|
+
if (
|
|
319
|
+
middlewareResult instanceof NextResponse
|
|
320
|
+
) {
|
|
321
|
+
// pz-override-response header is used to prevent 404 page for custom responses.
|
|
322
|
+
if (
|
|
323
|
+
middlewareResult.headers.get(
|
|
324
|
+
'pz-override-response'
|
|
325
|
+
) !== 'true'
|
|
326
|
+
) {
|
|
327
|
+
middlewareResult.headers.set(
|
|
328
|
+
'x-middleware-rewrite',
|
|
329
|
+
url.href
|
|
330
|
+
);
|
|
331
|
+
} else if (
|
|
332
|
+
middlewareResult.headers.get(
|
|
333
|
+
'x-middleware-rewrite'
|
|
334
|
+
) &&
|
|
335
|
+
middlewareResult.headers.get(
|
|
336
|
+
'pz-override-response'
|
|
337
|
+
) === 'true'
|
|
338
|
+
) {
|
|
339
|
+
middlewareResult =
|
|
340
|
+
NextResponse.rewrite(url);
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
// if middleware.ts doesn't have a return value.
|
|
344
|
+
// e.g. NextResponse.next() doesn't exist in middleware.ts
|
|
339
345
|
|
|
340
|
-
|
|
341
|
-
|
|
346
|
+
middlewareResult =
|
|
347
|
+
NextResponse.rewrite(url);
|
|
348
|
+
}
|
|
342
349
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
350
|
+
const { localeUrlStrategy } =
|
|
351
|
+
Settings.localization;
|
|
352
|
+
|
|
353
|
+
const fallbackHost =
|
|
354
|
+
req.headers.get('x-forwarded-host') ||
|
|
355
|
+
req.headers.get('host');
|
|
356
|
+
const hostname =
|
|
357
|
+
process.env.NEXT_PUBLIC_URL ||
|
|
358
|
+
`https://${fallbackHost}`;
|
|
359
|
+
const rootHostname =
|
|
360
|
+
localeUrlStrategy ===
|
|
361
|
+
LocaleUrlStrategy.Subdomain
|
|
362
|
+
? getRootHostname(hostname)
|
|
363
|
+
: null;
|
|
364
|
+
|
|
365
|
+
if (
|
|
366
|
+
!url.pathname.startsWith(
|
|
367
|
+
`/${currency}/orders`
|
|
368
|
+
)
|
|
369
|
+
) {
|
|
370
|
+
middlewareResult.cookies.set(
|
|
371
|
+
'pz-locale',
|
|
372
|
+
locale?.length > 0
|
|
373
|
+
? locale
|
|
374
|
+
: defaultLocaleValue,
|
|
375
|
+
{
|
|
376
|
+
domain: rootHostname,
|
|
377
|
+
sameSite: 'none',
|
|
378
|
+
secure: true,
|
|
379
|
+
expires: new Date(
|
|
380
|
+
Date.now() + 1000 * 60 * 60 * 24 * 7
|
|
381
|
+
) // 7 days
|
|
382
|
+
}
|
|
383
|
+
);
|
|
375
384
|
}
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
385
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (
|
|
393
|
-
req.cookies.get('pz-locale') &&
|
|
394
|
-
req.cookies.get('pz-locale').value !== locale
|
|
395
|
-
) {
|
|
396
|
-
logger.debug('Locale changed', {
|
|
397
|
-
locale,
|
|
398
|
-
oldLocale:
|
|
399
|
-
req.cookies.get('pz-locale')?.value,
|
|
400
|
-
ip
|
|
401
|
-
});
|
|
402
|
-
}
|
|
386
|
+
middlewareResult.cookies.set(
|
|
387
|
+
'pz-currency',
|
|
388
|
+
currency,
|
|
389
|
+
{
|
|
390
|
+
domain: rootHostname,
|
|
391
|
+
sameSite: 'none',
|
|
392
|
+
secure: true,
|
|
393
|
+
expires: new Date(
|
|
394
|
+
Date.now() + 1000 * 60 * 60 * 24 * 7
|
|
395
|
+
) // 7 days
|
|
396
|
+
}
|
|
397
|
+
);
|
|
403
398
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
399
|
+
if (
|
|
400
|
+
req.cookies.get('pz-locale') &&
|
|
401
|
+
req.cookies.get('pz-locale').value !==
|
|
402
|
+
locale
|
|
403
|
+
) {
|
|
404
|
+
logger.debug('Locale changed', {
|
|
405
|
+
locale,
|
|
406
|
+
oldLocale:
|
|
407
|
+
req.cookies.get('pz-locale')?.value,
|
|
408
|
+
ip
|
|
409
|
+
});
|
|
410
|
+
}
|
|
408
411
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
412
|
+
middlewareResult.headers.set(
|
|
413
|
+
'pz-url',
|
|
414
|
+
req.nextUrl.toString()
|
|
415
|
+
);
|
|
414
416
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
417
|
+
if (req.cookies.get('pz-set-currency')) {
|
|
418
|
+
middlewareResult.cookies.delete(
|
|
419
|
+
'pz-set-currency'
|
|
420
|
+
);
|
|
421
|
+
}
|
|
421
422
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
423
|
+
if (process.env.ACC_APP_VERSION) {
|
|
424
|
+
middlewareResult.headers.set(
|
|
425
|
+
'acc-app-version',
|
|
426
|
+
process.env.ACC_APP_VERSION
|
|
427
|
+
);
|
|
428
|
+
}
|
|
425
429
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
430
|
+
// Set CSRF token if not set
|
|
431
|
+
try {
|
|
432
|
+
const url = `${Settings.commerceUrl}${user.csrfToken}`;
|
|
433
|
+
|
|
434
|
+
if (!req.cookies.get('csrftoken')) {
|
|
435
|
+
const { csrf_token } = await (
|
|
436
|
+
await fetch(url)
|
|
437
|
+
).json();
|
|
438
|
+
middlewareResult.cookies.set(
|
|
439
|
+
'csrftoken',
|
|
440
|
+
csrf_token,
|
|
441
|
+
{
|
|
442
|
+
domain: rootHostname
|
|
443
|
+
}
|
|
444
|
+
);
|
|
435
445
|
}
|
|
436
|
-
)
|
|
446
|
+
} catch (error) {
|
|
447
|
+
logger.error('CSRF Error', {
|
|
448
|
+
error,
|
|
449
|
+
ip
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
} catch (error) {
|
|
453
|
+
logger.error('withPzDefault Error', {
|
|
454
|
+
error,
|
|
455
|
+
ip
|
|
456
|
+
});
|
|
437
457
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
error,
|
|
441
|
-
ip
|
|
442
|
-
});
|
|
458
|
+
|
|
459
|
+
return middlewareResult;
|
|
443
460
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
error,
|
|
447
|
-
ip
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
return middlewareResult;
|
|
452
|
-
}
|
|
461
|
+
)
|
|
462
|
+
)
|
|
453
463
|
)
|
|
454
464
|
)
|
|
455
465
|
)
|
|
@@ -461,7 +471,6 @@ const withPzDefault =
|
|
|
461
471
|
)
|
|
462
472
|
)
|
|
463
473
|
)
|
|
464
|
-
)
|
|
465
474
|
)(req, event);
|
|
466
475
|
};
|
|
467
476
|
|
package/middlewares/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import withCheckoutProvider from './checkout-provider';
|
|
|
11
11
|
import withSavedCardRedirection from './saved-card-redirection';
|
|
12
12
|
import withCompleteWallet from './complete-wallet';
|
|
13
13
|
import withWalletCompleteRedirection from './wallet-complete-redirection';
|
|
14
|
+
import withMasterpassRestCallback from './masterpass-rest-callback';
|
|
14
15
|
import { NextRequest } from 'next/server';
|
|
15
16
|
|
|
16
17
|
export {
|
|
@@ -26,7 +27,8 @@ export {
|
|
|
26
27
|
withCheckoutProvider,
|
|
27
28
|
withSavedCardRedirection,
|
|
28
29
|
withCompleteWallet,
|
|
29
|
-
withWalletCompleteRedirection
|
|
30
|
+
withWalletCompleteRedirection,
|
|
31
|
+
withMasterpassRestCallback
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
export interface PzNextRequest extends NextRequest {
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
|
|
2
|
+
import Settings from 'settings';
|
|
3
|
+
import logger from '../utils/log';
|
|
4
|
+
import { getUrlPathWithLocale } from '../utils/localization';
|
|
5
|
+
import { PzNextRequest } from '.';
|
|
6
|
+
|
|
7
|
+
const withMasterpassRestCallback =
|
|
8
|
+
(middleware: NextMiddleware) =>
|
|
9
|
+
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
10
|
+
const url = req.nextUrl.clone();
|
|
11
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
12
|
+
const sessionId = req.cookies.get('osessionid');
|
|
13
|
+
|
|
14
|
+
if (!url.pathname.includes('/orders/masterpass-rest-callback')) {
|
|
15
|
+
return middleware(req, event);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (req.method !== 'POST') {
|
|
19
|
+
logger.warn('Invalid request method for masterpass REST callback', {
|
|
20
|
+
middleware: 'masterpass-rest-callback',
|
|
21
|
+
method: req.method,
|
|
22
|
+
ip
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return NextResponse.redirect(
|
|
26
|
+
`${url.origin}${getUrlPathWithLocale(
|
|
27
|
+
'/orders/checkout/',
|
|
28
|
+
req.cookies.get('pz-locale')?.value
|
|
29
|
+
)}`,
|
|
30
|
+
303
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const responseCode = url.searchParams.get('responseCode');
|
|
35
|
+
const token = url.searchParams.get('token');
|
|
36
|
+
|
|
37
|
+
if (!responseCode || !token) {
|
|
38
|
+
logger.warn('Missing required parameters for masterpass REST callback', {
|
|
39
|
+
middleware: 'masterpass-rest-callback',
|
|
40
|
+
responseCode,
|
|
41
|
+
token,
|
|
42
|
+
ip
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return NextResponse.redirect(
|
|
46
|
+
`${url.origin}${getUrlPathWithLocale(
|
|
47
|
+
'/orders/checkout/',
|
|
48
|
+
req.cookies.get('pz-locale')?.value
|
|
49
|
+
)}`,
|
|
50
|
+
303
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const formData = await req.formData();
|
|
56
|
+
const body: Record<string, string> = {};
|
|
57
|
+
|
|
58
|
+
Array.from(formData.entries()).forEach(([key, value]) => {
|
|
59
|
+
body[key] = value.toString();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (!sessionId) {
|
|
63
|
+
logger.warn(
|
|
64
|
+
'Make sure that the SESSION_COOKIE_SAMESITE environment variable is set to None in Commerce.',
|
|
65
|
+
{
|
|
66
|
+
middleware: 'masterpass-rest-callback',
|
|
67
|
+
ip
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return NextResponse.redirect(
|
|
72
|
+
`${url.origin}${getUrlPathWithLocale(
|
|
73
|
+
'/orders/checkout/',
|
|
74
|
+
req.cookies.get('pz-locale')?.value
|
|
75
|
+
)}`,
|
|
76
|
+
303
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const requestUrl = new URL('/orders/checkout/', Settings.commerceUrl);
|
|
81
|
+
requestUrl.searchParams.set('page', 'MasterpassRestCompletePage');
|
|
82
|
+
requestUrl.searchParams.set('responseCode', responseCode);
|
|
83
|
+
requestUrl.searchParams.set('token', token);
|
|
84
|
+
requestUrl.searchParams.set(
|
|
85
|
+
'three_d_secure',
|
|
86
|
+
body.transactionType?.includes('3D') ? 'true' : 'false'
|
|
87
|
+
);
|
|
88
|
+
requestUrl.searchParams.set(
|
|
89
|
+
'transactionType',
|
|
90
|
+
body.transactionType || ''
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const requestHeaders = {
|
|
94
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
95
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
96
|
+
Cookie: req.headers.get('cookie') ?? '',
|
|
97
|
+
'x-currency': req.cookies.get('pz-currency')?.value ?? '',
|
|
98
|
+
'x-forwarded-for': ip,
|
|
99
|
+
'User-Agent': req.headers.get('user-agent') ?? ''
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const request = await fetch(requestUrl.toString(), {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
headers: requestHeaders,
|
|
105
|
+
body: new URLSearchParams(body)
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
logger.info('Masterpass REST callback request', {
|
|
109
|
+
requestUrl: requestUrl.toString(),
|
|
110
|
+
status: request.status,
|
|
111
|
+
requestHeaders,
|
|
112
|
+
ip
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const response = await request.json();
|
|
116
|
+
|
|
117
|
+
const { context_list: contextList, errors } = response;
|
|
118
|
+
|
|
119
|
+
let redirectUrl = response.redirect_url;
|
|
120
|
+
|
|
121
|
+
if (!redirectUrl && contextList && contextList.length > 0) {
|
|
122
|
+
for (const context of contextList) {
|
|
123
|
+
if (context.page_context && context.page_context.redirect_url) {
|
|
124
|
+
redirectUrl = context.page_context.redirect_url;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (errors && Object.keys(errors).length) {
|
|
131
|
+
logger.error('Error while processing masterpass REST callback', {
|
|
132
|
+
middleware: 'masterpass-rest-callback',
|
|
133
|
+
errors,
|
|
134
|
+
requestHeaders,
|
|
135
|
+
ip
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return NextResponse.redirect(
|
|
139
|
+
`${url.origin}${getUrlPathWithLocale(
|
|
140
|
+
'/orders/checkout/',
|
|
141
|
+
req.cookies.get('pz-locale')?.value
|
|
142
|
+
)}`,
|
|
143
|
+
{
|
|
144
|
+
status: 303,
|
|
145
|
+
headers: {
|
|
146
|
+
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
logger.info('Masterpass REST callback response', {
|
|
153
|
+
middleware: 'masterpass-rest-callback',
|
|
154
|
+
contextList,
|
|
155
|
+
redirectUrl,
|
|
156
|
+
ip
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (!redirectUrl) {
|
|
160
|
+
logger.warn(
|
|
161
|
+
'No redirection url found in response. Redirecting to checkout page.',
|
|
162
|
+
{
|
|
163
|
+
middleware: 'masterpass-rest-callback',
|
|
164
|
+
requestHeaders,
|
|
165
|
+
response: JSON.stringify(response),
|
|
166
|
+
ip
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
|
|
171
|
+
'/orders/checkout/',
|
|
172
|
+
req.cookies.get('pz-locale')?.value
|
|
173
|
+
)}`;
|
|
174
|
+
|
|
175
|
+
return NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
|
|
179
|
+
redirectUrl,
|
|
180
|
+
req.cookies.get('pz-locale')?.value
|
|
181
|
+
)}`;
|
|
182
|
+
|
|
183
|
+
logger.info('Redirecting after masterpass REST callback', {
|
|
184
|
+
middleware: 'masterpass-rest-callback',
|
|
185
|
+
redirectUrlWithLocale,
|
|
186
|
+
ip
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
190
|
+
|
|
191
|
+
nextResponse.headers.set(
|
|
192
|
+
'Set-Cookie',
|
|
193
|
+
request.headers.get('set-cookie') ?? ''
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
return nextResponse;
|
|
197
|
+
} catch (error) {
|
|
198
|
+
logger.error('Error while processing masterpass REST callback', {
|
|
199
|
+
middleware: 'masterpass-rest-callback',
|
|
200
|
+
error,
|
|
201
|
+
requestHeaders: {
|
|
202
|
+
Cookie: req.headers.get('cookie') ?? '',
|
|
203
|
+
'x-currency': req.cookies.get('pz-currency')?.value ?? ''
|
|
204
|
+
},
|
|
205
|
+
ip
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return NextResponse.redirect(
|
|
209
|
+
`${url.origin}${getUrlPathWithLocale(
|
|
210
|
+
'/orders/checkout/',
|
|
211
|
+
req.cookies.get('pz-locale')?.value
|
|
212
|
+
)}`,
|
|
213
|
+
303
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export default withMasterpassRestCallback;
|
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.111.0
|
|
4
|
+
"version": "1.111.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.111.0
|
|
38
|
+
"@akinon/eslint-plugin-projectzero": "1.111.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
package/plugins.js
CHANGED
|
@@ -208,7 +208,10 @@ export const contextListMiddleware: Middleware = ({
|
|
|
208
208
|
dispatch(setCardType(context.page_context.card_type));
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
if (
|
|
211
|
+
if (
|
|
212
|
+
context.page_context.installments &&
|
|
213
|
+
preOrder?.payment_option?.payment_type !== 'masterpass_rest'
|
|
214
|
+
) {
|
|
212
215
|
dispatch(setInstallmentOptions(context.page_context.installments));
|
|
213
216
|
}
|
|
214
217
|
}
|
|
@@ -20,6 +20,7 @@ export const installmentOptionMiddleware: Middleware = ({
|
|
|
20
20
|
if (
|
|
21
21
|
!preOrder?.installment &&
|
|
22
22
|
preOrder?.payment_option?.payment_type !== 'saved_card' &&
|
|
23
|
+
preOrder?.payment_option?.payment_type !== 'masterpass_rest' &&
|
|
23
24
|
installmentOptions.length > 0
|
|
24
25
|
) {
|
|
25
26
|
const firstInstallmentOptionPk = installmentOptions[0]?.pk;
|
package/redux/reducers/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { masterpassReducer } from '@akinon/pz-masterpass';
|
|
|
9
9
|
import { otpReducer } from '@akinon/pz-otp';
|
|
10
10
|
import { savedCardReducer } from '@akinon/pz-saved-card';
|
|
11
11
|
import cyberSourceUcReducer from '@akinon/pz-cybersource-uc/src/redux/reducer';
|
|
12
|
+
import { masterpassRestReducer } from '@akinon/pz-masterpass-rest';
|
|
12
13
|
|
|
13
14
|
const fallbackReducer = (state = {}) => state;
|
|
14
15
|
|
|
@@ -21,7 +22,8 @@ const reducers = {
|
|
|
21
22
|
masterpass: masterpassReducer || fallbackReducer,
|
|
22
23
|
otp: otpReducer || fallbackReducer,
|
|
23
24
|
savedCard: savedCardReducer || fallbackReducer,
|
|
24
|
-
cybersource_uc: cyberSourceUcReducer || fallbackReducer
|
|
25
|
+
cybersource_uc: cyberSourceUcReducer || fallbackReducer,
|
|
26
|
+
masterpassRest: masterpassRestReducer || fallbackReducer
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
export default reducers;
|