@akinon/next 1.14.1 → 1.16.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.
@@ -1,8 +1,8 @@
1
- import { Cache, CacheKey } from '../../lib/cache';
2
- import { FormType } from '../../types/commerce/form';
1
+ import { Cache, CacheKey } from "../../lib/cache";
2
+ import { FormType } from "../../types/commerce/form";
3
3
 
4
- import appFetch from '../../utils/app-fetch';
5
- import { form } from '../urls';
4
+ import appFetch from "../../utils/app-fetch";
5
+ import { form } from "../urls";
6
6
 
7
7
  const getFormDataHandler = (pk: number) => {
8
8
  return async function () {
@@ -17,7 +17,7 @@ export const usePaymentOptions = () => {
17
17
  const paymentTypeToPluginMap = {
18
18
  pay_on_delivery: 'pz-pay-on-delivery',
19
19
  bkm_express: 'pz-bkm',
20
- masterpass: 'pz-masterpass'
20
+ credit_payment: 'pz-credit-payment',
21
21
  };
22
22
 
23
23
  const isInitialTypeIncluded = (type: string) => initialTypes.has(type);
@@ -0,0 +1,5 @@
1
+ export async function register() {
2
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
3
+ await import('./node');
4
+ }
5
+ }
@@ -0,0 +1,20 @@
1
+ import { NodeSDK } from '@opentelemetry/sdk-node';
2
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
3
+ import { Resource } from '@opentelemetry/resources';
4
+ import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
5
+ import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node';
6
+
7
+ const sdk = new NodeSDK({
8
+ resource: new Resource({
9
+ [SemanticResourceAttributes.SERVICE_NAME]: 'pz-next-app'
10
+ }),
11
+ spanProcessor: new SimpleSpanProcessor(
12
+ new OTLPTraceExporter({
13
+ url: `${
14
+ process.env.PZ_DASHBOARD_URL ?? 'http://localhost:3005'
15
+ }/api/traces`
16
+ })
17
+ )
18
+ });
19
+
20
+ sdk.start();
@@ -0,0 +1,159 @@
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-gpay',
22
+ error
23
+ });
24
+ }
25
+
26
+ return result;
27
+ }
28
+ return null;
29
+ };
30
+
31
+ const withCompleteGpay =
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
+
37
+ if (url.search.indexOf('GPayCompletePage') === -1) {
38
+ return middleware(req, event);
39
+ }
40
+
41
+ const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
42
+ const requestHeaders = {
43
+ 'X-Requested-With': 'XMLHttpRequest',
44
+ 'Content-Type': 'application/x-www-form-urlencoded',
45
+ Cookie: `osessionid=${req.cookies.get('osessionid')?.value ?? ''}`,
46
+ 'x-currency': req.cookies.get('pz-currency')?.value ?? ''
47
+ };
48
+
49
+ try {
50
+ const body = await streamToString(req.body);
51
+
52
+ const request = await fetch(requestUrl, {
53
+ method: 'POST',
54
+ headers: requestHeaders,
55
+ body
56
+ });
57
+
58
+ logger.info('Complete GPay payment request', {
59
+ requestUrl,
60
+ status: request.status,
61
+ requestHeaders,
62
+ ip
63
+ });
64
+
65
+ const response = await request.json();
66
+
67
+ const { context_list: contextList, errors } = response;
68
+ const redirectionContext = contextList?.find(
69
+ (context) => context.page_context?.redirect_url
70
+ );
71
+ const redirectUrl = redirectionContext?.page_context?.redirect_url;
72
+
73
+ if (errors && Object.keys(errors).length) {
74
+ logger.error('Error while completing GPay payment', {
75
+ middleware: 'complete-gpay',
76
+ errors,
77
+ requestHeaders,
78
+ ip
79
+ });
80
+
81
+ return NextResponse.redirect(
82
+ `${url.origin}${getUrlPathWithLocale(
83
+ '/orders/checkout/',
84
+ req.cookies.get('pz-locale')?.value
85
+ )}`,
86
+ {
87
+ status: 303,
88
+ headers: {
89
+ 'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
90
+ }
91
+ }
92
+ );
93
+ }
94
+
95
+ logger.info('Order success page context list', {
96
+ middleware: 'complete-gpay',
97
+ contextList,
98
+ ip
99
+ });
100
+
101
+ if (!redirectUrl) {
102
+ logger.warn(
103
+ 'No redirection url for order success page found in page_context. Redirecting to checkout page.',
104
+ {
105
+ middleware: 'complete-gpay',
106
+ requestHeaders,
107
+ response: JSON.stringify(response),
108
+ ip
109
+ }
110
+ );
111
+
112
+ const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
113
+ '/orders/checkout/',
114
+ req.cookies.get('pz-locale')?.value
115
+ )}`;
116
+
117
+ return NextResponse.redirect(redirectUrlWithLocale, 303);
118
+ }
119
+
120
+ const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
121
+ redirectUrl,
122
+ req.cookies.get('pz-locale')?.value
123
+ )}`;
124
+
125
+ logger.info('Redirecting to order success page', {
126
+ middleware: 'complete-gpay',
127
+ redirectUrlWithLocale,
128
+ ip
129
+ });
130
+
131
+ // Using POST method while redirecting causes an error,
132
+ // So we use 303 status code to change the method to GET
133
+ const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
134
+
135
+ nextResponse.headers.set(
136
+ 'Set-Cookie',
137
+ request.headers.get('set-cookie') ?? ''
138
+ );
139
+
140
+ return nextResponse;
141
+ } catch (error) {
142
+ logger.error('Error while completing GPay payment', {
143
+ middleware: 'complete-gpay',
144
+ error,
145
+ requestHeaders,
146
+ ip
147
+ });
148
+
149
+ return NextResponse.redirect(
150
+ `${url.origin}${getUrlPathWithLocale(
151
+ '/orders/checkout/',
152
+ req.cookies.get('pz-locale')?.value
153
+ )}`,
154
+ 303
155
+ );
156
+ }
157
+ };
158
+
159
+ export default withCompleteGpay;
@@ -2,6 +2,7 @@ import { NextFetchEvent, NextMiddleware, NextResponse } from 'next/server';
2
2
  import Settings from 'settings';
3
3
  import {
4
4
  PzNextRequest,
5
+ withCompleteGpay,
5
6
  withOauthLogin,
6
7
  withPrettyUrl,
7
8
  withRedirectionPayment,
@@ -122,128 +123,130 @@ const withPzDefault =
122
123
  withRedirectionPayment(
123
124
  withThreeDRedirection(
124
125
  withUrlRedirection(
125
- async (req: PzNextRequest, event: NextFetchEvent) => {
126
- let middlewareResult: NextResponse | void =
127
- NextResponse.next();
126
+ withCompleteGpay(
127
+ async (req: PzNextRequest, event: NextFetchEvent) => {
128
+ let middlewareResult: NextResponse | void =
129
+ NextResponse.next();
128
130
 
129
- try {
130
- const { locale, prettyUrl, currency } =
131
- req.middlewareParams.rewrites;
132
- const { defaultLocaleValue } = Settings.localization;
133
- const url = req.nextUrl.clone();
134
- const pathnameWithoutLocale = url.pathname.replace(
135
- urlLocaleMatcherRegex,
136
- ''
137
- );
138
-
139
- url.basePath = `/${commerceUrl}`;
140
- url.pathname = `/${
141
- locale.length ? `${locale}/` : ''
142
- }${currency}${prettyUrl ?? pathnameWithoutLocale}`;
143
-
144
- Settings.rewrites.forEach((rewrite) => {
145
- url.pathname = url.pathname.replace(
146
- rewrite.source,
147
- rewrite.destination
131
+ try {
132
+ const { locale, prettyUrl, currency } =
133
+ req.middlewareParams.rewrites;
134
+ const { defaultLocaleValue } = Settings.localization;
135
+ const url = req.nextUrl.clone();
136
+ const pathnameWithoutLocale = url.pathname.replace(
137
+ urlLocaleMatcherRegex,
138
+ ''
148
139
  );
149
- });
150
140
 
151
- middlewareResult = (await middleware(
152
- req,
153
- event
154
- )) as NextResponse | void;
141
+ url.basePath = `/${commerceUrl}`;
142
+ url.pathname = `/${
143
+ locale.length ? `${locale}/` : ''
144
+ }${currency}${prettyUrl ?? pathnameWithoutLocale}`;
155
145
 
156
- // if middleware.ts has a return value for current url
157
- if (middlewareResult instanceof NextResponse) {
158
- // pz-override-response header is used to prevent 404 page for custom responses.
159
- if (
160
- middlewareResult.headers.get(
161
- 'pz-override-response'
162
- ) !== 'true'
163
- ) {
164
- middlewareResult.headers.set(
165
- 'x-middleware-rewrite',
166
- url.href
146
+ Settings.rewrites.forEach((rewrite) => {
147
+ url.pathname = url.pathname.replace(
148
+ rewrite.source,
149
+ rewrite.destination
167
150
  );
168
- }
169
- } else {
170
- // if middleware.ts doesn't have a return value.
171
- // e.g. NextResponse.next() doesn't exist in middleware.ts
151
+ });
172
152
 
173
- middlewareResult = NextResponse.rewrite(url);
174
- }
153
+ middlewareResult = (await middleware(
154
+ req,
155
+ event
156
+ )) as NextResponse | void;
175
157
 
176
- if (!url.pathname.startsWith(`/${currency}/orders`)) {
177
- middlewareResult.cookies.set(
178
- 'pz-locale',
179
- locale?.length > 0 ? locale : defaultLocaleValue,
180
- {
181
- sameSite: 'none',
182
- secure: true,
183
- expires: new Date(
184
- Date.now() + 1000 * 60 * 60 * 24 * 7
185
- ) // 7 days
158
+ // if middleware.ts has a return value for current url
159
+ if (middlewareResult instanceof NextResponse) {
160
+ // pz-override-response header is used to prevent 404 page for custom responses.
161
+ if (
162
+ middlewareResult.headers.get(
163
+ 'pz-override-response'
164
+ ) !== 'true'
165
+ ) {
166
+ middlewareResult.headers.set(
167
+ 'x-middleware-rewrite',
168
+ url.href
169
+ );
186
170
  }
187
- );
188
- }
189
- middlewareResult.cookies.set('pz-currency', currency, {
190
- sameSite: 'none',
191
- secure: true,
192
- expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7) // 7 days
193
- });
171
+ } else {
172
+ // if middleware.ts doesn't have a return value.
173
+ // e.g. NextResponse.next() doesn't exist in middleware.ts
194
174
 
195
- if (
196
- req.cookies.get('pz-locale') &&
197
- req.cookies.get('pz-locale').value !== locale
198
- ) {
199
- logger.debug('Locale changed', {
200
- locale,
201
- oldLocale: req.cookies.get('pz-locale')?.value,
202
- ip
203
- });
204
- }
175
+ middlewareResult = NextResponse.rewrite(url);
176
+ }
205
177
 
206
- middlewareResult.headers.set(
207
- 'pz-url',
208
- req.nextUrl.toString()
209
- );
178
+ if (!url.pathname.startsWith(`/${currency}/orders`)) {
179
+ middlewareResult.cookies.set(
180
+ 'pz-locale',
181
+ locale?.length > 0 ? locale : defaultLocaleValue,
182
+ {
183
+ sameSite: 'none',
184
+ secure: true,
185
+ expires: new Date(
186
+ Date.now() + 1000 * 60 * 60 * 24 * 7
187
+ ) // 7 days
188
+ }
189
+ );
190
+ }
191
+ middlewareResult.cookies.set('pz-currency', currency, {
192
+ sameSite: 'none',
193
+ secure: true,
194
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7) // 7 days
195
+ });
210
196
 
211
- if (req.cookies.get('pz-set-currency')) {
212
- middlewareResult.cookies.delete('pz-set-currency');
213
- }
197
+ if (
198
+ req.cookies.get('pz-locale') &&
199
+ req.cookies.get('pz-locale').value !== locale
200
+ ) {
201
+ logger.debug('Locale changed', {
202
+ locale,
203
+ oldLocale: req.cookies.get('pz-locale')?.value,
204
+ ip
205
+ });
206
+ }
214
207
 
215
- if (process.env.ACC_APP_VERSION) {
216
208
  middlewareResult.headers.set(
217
- 'acc-app-version',
218
- process.env.ACC_APP_VERSION
209
+ 'pz-url',
210
+ req.nextUrl.toString()
219
211
  );
220
- }
221
212
 
222
- // Set CSRF token if not set
223
- try {
224
- const url = `${Settings.commerceUrl}${user.csrfToken}`;
213
+ if (req.cookies.get('pz-set-currency')) {
214
+ middlewareResult.cookies.delete('pz-set-currency');
215
+ }
225
216
 
226
- if (!req.cookies.get('csrftoken')) {
227
- const { csrf_token } = await (
228
- await fetch(url)
229
- ).json();
230
- middlewareResult.cookies.set('csrftoken', csrf_token);
217
+ if (process.env.ACC_APP_VERSION) {
218
+ middlewareResult.headers.set(
219
+ 'acc-app-version',
220
+ process.env.ACC_APP_VERSION
221
+ );
222
+ }
223
+
224
+ // Set CSRF token if not set
225
+ try {
226
+ const url = `${Settings.commerceUrl}${user.csrfToken}`;
227
+
228
+ if (!req.cookies.get('csrftoken')) {
229
+ const { csrf_token } = await (
230
+ await fetch(url)
231
+ ).json();
232
+ middlewareResult.cookies.set('csrftoken', csrf_token);
233
+ }
234
+ } catch (error) {
235
+ logger.error('CSRF Error', {
236
+ error,
237
+ ip
238
+ });
231
239
  }
232
240
  } catch (error) {
233
- logger.error('CSRF Error', {
241
+ logger.error('withPzDefault Error', {
234
242
  error,
235
243
  ip
236
244
  });
237
245
  }
238
- } catch (error) {
239
- logger.error('withPzDefault Error', {
240
- error,
241
- ip
242
- });
243
- }
244
246
 
245
- return middlewareResult;
246
- }
247
+ return middlewareResult;
248
+ }
249
+ )
247
250
  )
248
251
  )
249
252
  )
@@ -5,6 +5,7 @@ import withRedirectionPayment from './redirection-payment';
5
5
  import withLocale from './locale';
6
6
  import withOauthLogin from './oauth-login';
7
7
  import withUrlRedirection from './url-redirection';
8
+ import withCompleteGpay from './complete-gpay';
8
9
  import { NextRequest } from 'next/server';
9
10
 
10
11
  export {
@@ -14,7 +15,8 @@ export {
14
15
  withRedirectionPayment,
15
16
  withLocale,
16
17
  withOauthLogin,
17
- withUrlRedirection
18
+ withUrlRedirection,
19
+ withCompleteGpay
18
20
  };
19
21
 
20
22
  export interface PzNextRequest extends NextRequest {
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.14.1",
4
+ "version": "1.16.0",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -14,6 +14,11 @@
14
14
  "pz-postdev": "bin/pz-postdev.js"
15
15
  },
16
16
  "dependencies": {
17
+ "@opentelemetry/sdk-node": "0.46.0",
18
+ "@opentelemetry/exporter-trace-otlp-http": "0.46.0",
19
+ "@opentelemetry/resources": "1.19.0",
20
+ "@opentelemetry/semantic-conventions": "1.19.0",
21
+ "@opentelemetry/sdk-trace-node": "1.19.0",
17
22
  "@reduxjs/toolkit": "1.9.7",
18
23
  "cross-spawn": "7.0.3",
19
24
  "react-redux": "8.1.3",
@@ -26,7 +31,7 @@
26
31
  "@typescript-eslint/eslint-plugin": "6.7.4",
27
32
  "@typescript-eslint/parser": "6.7.4",
28
33
  "eslint": "^8.14.0",
29
- "@akinon/eslint-plugin-projectzero": "1.14.1",
34
+ "@akinon/eslint-plugin-projectzero": "1.16.0",
30
35
  "eslint-config-prettier": "8.5.0"
31
36
  }
32
37
  }
package/plugins.js CHANGED
@@ -7,5 +7,5 @@ module.exports = [
7
7
  'pz-gpay',
8
8
  'pz-otp',
9
9
  'pz-bkm',
10
- 'pz-masterpass'
10
+ 'pz-credit-payment',
11
11
  ];