@akinon/next 1.106.0 → 1.107.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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.107.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4ca44c78: ZERO-3634: add register_consumer_card
8
+ - 28c7ea79: ZERO-3427: Refactor redirect utility to handle undefined URL and improve locale handling
9
+ - b6e5b624: ZERO-3257: Enhance locale middleware to redirect using existing or default locale and support 303 status for POST requests
10
+ - 5b500797: ZERO-3634: iyzico saved card
11
+
3
12
  ## 1.106.0
4
13
 
5
14
  ### Minor Changes
@@ -48,6 +48,7 @@ export enum Component {
48
48
  AkifastCheckoutButton = 'CheckoutButton',
49
49
  MultiBasket = 'MultiBasket',
50
50
  SavedCard = 'SavedCardOption',
51
+ IyzicoSavedCard = 'IyzicoSavedCardOption',
51
52
  Hepsipay = 'Hepsipay',
52
53
  FlowPayment = 'FlowPayment'
53
54
  }
@@ -82,6 +83,7 @@ const PluginComponents = new Map([
82
83
  [Component.AkifastQuickLoginButton, Component.AkifastCheckoutButton]
83
84
  ],
84
85
  [Plugin.MultiBasket, [Component.MultiBasket]],
86
+ [Plugin.SavedCard, [Component.SavedCard, Component.IyzicoSavedCard]],
85
87
  [Plugin.SavedCard, [Component.SavedCard]],
86
88
  [Plugin.Hepsipay, [Component.Hepsipay]],
87
89
  [Plugin.FlowPayment, [Component.FlowPayment]]
@@ -60,6 +60,15 @@ export default function SelectedPaymentOptionView({
60
60
  return typeof mod?.default === 'function'
61
61
  ? mod.default
62
62
  : fallbackView;
63
+ } else if (
64
+ payment_option?.payment_type === 'wallet' &&
65
+ wallet_method === 'cybersource_uc'
66
+ ) {
67
+ const mod = await import('@akinon/pz-cybersource-uc');
68
+
69
+ return typeof mod?.CyberSourceUcPaymentOption === 'function'
70
+ ? mod.CyberSourceUcPaymentOption
71
+ : fallbackView;
63
72
  }
64
73
 
65
74
  if (
@@ -0,0 +1,179 @@
1
+ import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
2
+ import Settings from 'settings';
3
+ import { Buffer } from 'buffer';
4
+ import logger from '../utils/log';
5
+ import { getUrlPathWithLocale } from '../utils/localization';
6
+ import { PzNextRequest } from '.';
7
+
8
+ const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
9
+ if (stream) {
10
+ const chunks = [];
11
+ let result = '';
12
+
13
+ try {
14
+ for await (const chunk of stream as any) {
15
+ chunks.push(Buffer.from(chunk));
16
+ }
17
+
18
+ result = Buffer.concat(chunks).toString('utf-8');
19
+ } catch (error) {
20
+ logger.error('Error while reading body stream', {
21
+ middleware: 'complete-wallet',
22
+ error
23
+ });
24
+ }
25
+
26
+ return result;
27
+ }
28
+ return null;
29
+ };
30
+
31
+ const withCompleteWallet =
32
+ (middleware: NextMiddleware) =>
33
+ async (req: PzNextRequest, event: NextFetchEvent) => {
34
+ const url = req.nextUrl.clone();
35
+ const ip = req.headers.get('x-forwarded-for') ?? '';
36
+ const sessionId = req.cookies.get('osessionid');
37
+
38
+ if (url.search.indexOf('WalletRedirectCompletePage') === -1) {
39
+ return middleware(req, event);
40
+ }
41
+
42
+ const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
43
+ const requestHeaders = {
44
+ 'X-Requested-With': 'XMLHttpRequest',
45
+ 'Content-Type': 'application/x-www-form-urlencoded',
46
+ Cookie: req.headers.get('cookie') ?? '',
47
+ 'x-currency': req.cookies.get('pz-currency')?.value ?? '',
48
+ 'x-forwarded-for': ip
49
+ };
50
+
51
+ try {
52
+ const body = await streamToString(req.body);
53
+
54
+ if (!sessionId) {
55
+ logger.warn(
56
+ 'Make sure that the SESSION_COOKIE_SAMESITE environment variable is set to None in Commerce.',
57
+ {
58
+ middleware: 'complete-wallet',
59
+ ip
60
+ }
61
+ );
62
+
63
+ return NextResponse.redirect(
64
+ `${url.origin}${getUrlPathWithLocale(
65
+ '/orders/checkout/',
66
+ req.cookies.get('pz-locale')?.value
67
+ )}`,
68
+ 303
69
+ );
70
+ }
71
+
72
+ const request = await fetch(requestUrl, {
73
+ method: 'POST',
74
+ headers: requestHeaders,
75
+ body
76
+ });
77
+
78
+ logger.info('Complete Wallet payment request', {
79
+ requestUrl,
80
+ status: request.status,
81
+ requestHeaders,
82
+ ip
83
+ });
84
+
85
+ const response = await request.json();
86
+
87
+ const { context_list: contextList, errors } = response;
88
+ const redirectionContext = contextList?.find(
89
+ (context) => context.page_context?.redirect_url
90
+ );
91
+ const redirectUrl = redirectionContext?.page_context?.redirect_url;
92
+
93
+ if (errors && Object.keys(errors).length) {
94
+ logger.error('Error while completing Wallet payment', {
95
+ middleware: 'complete-wallet',
96
+ errors,
97
+ requestHeaders,
98
+ ip
99
+ });
100
+
101
+ return NextResponse.redirect(
102
+ `${url.origin}${getUrlPathWithLocale(
103
+ '/orders/checkout/',
104
+ req.cookies.get('pz-locale')?.value
105
+ )}`,
106
+ {
107
+ status: 303,
108
+ headers: {
109
+ 'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
110
+ }
111
+ }
112
+ );
113
+ }
114
+
115
+ logger.info('Order success page context list', {
116
+ middleware: 'complete-wallet',
117
+ contextList,
118
+ ip
119
+ });
120
+
121
+ if (!redirectUrl) {
122
+ logger.warn(
123
+ 'No redirection url for order success page found in page_context. Redirecting to checkout page.',
124
+ {
125
+ middleware: 'complete-wallet',
126
+ requestHeaders,
127
+ response: JSON.stringify(response),
128
+ ip
129
+ }
130
+ );
131
+
132
+ const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
133
+ '/orders/checkout/',
134
+ req.cookies.get('pz-locale')?.value
135
+ )}`;
136
+
137
+ return NextResponse.redirect(redirectUrlWithLocale, 303);
138
+ }
139
+
140
+ const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
141
+ redirectUrl,
142
+ req.cookies.get('pz-locale')?.value
143
+ )}`;
144
+
145
+ logger.info('Redirecting to order success page', {
146
+ middleware: 'complete-wallet',
147
+ redirectUrlWithLocale,
148
+ ip
149
+ });
150
+
151
+ // Using POST method while redirecting causes an error,
152
+ // So we use 303 status code to change the method to GET
153
+ const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
154
+
155
+ nextResponse.headers.set(
156
+ 'Set-Cookie',
157
+ request.headers.get('set-cookie') ?? ''
158
+ );
159
+
160
+ return nextResponse;
161
+ } catch (error) {
162
+ logger.error('Error while completing Wallet payment', {
163
+ middleware: 'complete-wallet',
164
+ error,
165
+ requestHeaders,
166
+ ip
167
+ });
168
+
169
+ return NextResponse.redirect(
170
+ `${url.origin}${getUrlPathWithLocale(
171
+ '/orders/checkout/',
172
+ req.cookies.get('pz-locale')?.value
173
+ )}`,
174
+ 303
175
+ );
176
+ }
177
+ };
178
+
179
+ export default withCompleteWallet;
@@ -12,6 +12,7 @@ import {
12
12
  withSavedCardRedirection,
13
13
  withThreeDRedirection,
14
14
  withUrlRedirection,
15
+ withCompleteWallet,
15
16
  withWalletCompleteRedirection
16
17
  } from '.';
17
18
  import { urlLocaleMatcherRegex } from '../utils';
@@ -228,6 +229,7 @@ const withPzDefault =
228
229
  withCompleteGpay(
229
230
  withCompleteMasterpass(
230
231
  withSavedCardRedirection(
232
+ withCompleteWallet(
231
233
  withWalletCompleteRedirection(
232
234
  async (
233
235
  req: PzNextRequest,
@@ -459,6 +461,7 @@ const withPzDefault =
459
461
  )
460
462
  )
461
463
  )
464
+ )
462
465
  )(req, event);
463
466
  };
464
467
 
@@ -9,6 +9,7 @@ import withCompleteGpay from './complete-gpay';
9
9
  import withCompleteMasterpass from './complete-masterpass';
10
10
  import withCheckoutProvider from './checkout-provider';
11
11
  import withSavedCardRedirection from './saved-card-redirection';
12
+ import withCompleteWallet from './complete-wallet';
12
13
  import withWalletCompleteRedirection from './wallet-complete-redirection';
13
14
  import { NextRequest } from 'next/server';
14
15
 
@@ -24,6 +25,7 @@ export {
24
25
  withCompleteMasterpass,
25
26
  withCheckoutProvider,
26
27
  withSavedCardRedirection,
28
+ withCompleteWallet,
27
29
  withWalletCompleteRedirection
28
30
  };
29
31
 
@@ -69,7 +69,6 @@ const withLocale =
69
69
  req.method === 'GET'
70
70
  ) {
71
71
  // Redirect to existing or default locale
72
-
73
72
  url.pathname = getUrlPathWithLocale(
74
73
  url.pathname,
75
74
  req.cookies.get('pz-locale')?.value
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.106.0",
4
+ "version": "1.107.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.106.0",
38
+ "@akinon/eslint-plugin-projectzero": "1.107.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
@@ -31,11 +31,18 @@ declare module '@akinon/pz-saved-card' {
31
31
  export const SavedCardOption: any;
32
32
  }
33
33
 
34
- declare module '@akinon/pz-iyzico-saved-card' {
35
- export const iyzicoSavedCardReducer: any;
36
- export const iyzicoSavedCardMiddleware: any;
34
+ declare module '@akinon/pz-apple-pay' {}
35
+
36
+ declare module '@akinon/pz-cybersource-uc/src/redux/middleware' {
37
+ export default middleware as any;
37
38
  }
38
39
 
39
- declare module '@akinon/pz-apple-pay' {}
40
+ declare module '@akinon/pz-cybersource-uc/src/redux/reducer' {
41
+ export default reducer as any;
42
+ }
43
+
44
+ declare module '@akinon/pz-cybersource-uc' {
45
+ export const CyberSourceUcPaymentOption: any;
46
+ }
40
47
 
41
48
  declare module '@akinon/pz-flow-payment' {}
package/plugins.js CHANGED
@@ -16,6 +16,7 @@ module.exports = [
16
16
  'pz-tabby-extension',
17
17
  'pz-apple-pay',
18
18
  'pz-tamara-extension',
19
+ 'pz-cybersource-uc',
19
20
  'pz-hepsipay',
20
21
  'pz-flow-payment'
21
22
  ];
@@ -18,13 +18,11 @@ import logger from '@akinon/next/utils/log';
18
18
 
19
19
  // Plugin middlewares
20
20
  import { savedCardMiddleware } from '@akinon/pz-saved-card';
21
+ import cyberSourceUcMiddleware from '@akinon/pz-cybersource-uc/src/redux/middleware';
21
22
 
22
- export const rtkQueryResponseHandler: Middleware =
23
- ({ dispatch }) =>
24
- (next) =>
25
- (action) => {
26
- return next(action);
27
- };
23
+ export const rtkQueryResponseHandler: Middleware = () => (next) => (action) => {
24
+ return next(action);
25
+ };
28
26
 
29
27
  export const rtkQueryErrorHandler: Middleware =
30
28
  () => (next) => async (action) => {
@@ -56,7 +54,8 @@ const middlewares = [
56
54
  contextListMiddleware,
57
55
  hepsiPayMiddleware,
58
56
  walletPaymentMiddleware,
59
- savedCardMiddleware
57
+ savedCardMiddleware,
58
+ cyberSourceUcMiddleware
60
59
  ];
61
60
 
62
61
  // Filter out any non-function middleware to ensure all middlewares are valid and executable
@@ -8,6 +8,7 @@ import { api } from '../../data/client/api';
8
8
  import { masterpassReducer } from '@akinon/pz-masterpass';
9
9
  import { otpReducer } from '@akinon/pz-otp';
10
10
  import { savedCardReducer } from '@akinon/pz-saved-card';
11
+ import cyberSourceUcReducer from '@akinon/pz-cybersource-uc/src/redux/reducer';
11
12
 
12
13
  const fallbackReducer = (state = {}) => state;
13
14
 
@@ -19,7 +20,8 @@ const reducers = {
19
20
  header: headerReducer,
20
21
  masterpass: masterpassReducer || fallbackReducer,
21
22
  otp: otpReducer || fallbackReducer,
22
- savedCard: savedCardReducer || fallbackReducer
23
+ savedCard: savedCardReducer || fallbackReducer,
24
+ cybersource_uc: cyberSourceUcReducer || fallbackReducer
23
25
  };
24
26
 
25
27
  export default reducers;