@akinon/next 1.25.0 → 1.26.0-rc.1

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,35 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.26.0-rc.1
4
+
5
+ ### Minor Changes
6
+
7
+ - a7e432f: ZERO-2534: Fix for recapthca regex for replacing the special chars.
8
+
9
+ ### Patch Changes
10
+
11
+ - @akinon/eslint-plugin-projectzero@1.26.0-rc.1
12
+
13
+ ## 1.26.0-rc.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 6d4aadb: ZERO-2476: Auto install recommendenent extension
18
+ - 7e41bdc: BRDG-9158: Remove redirect-three-d page endpoint
19
+ - 1289982: ZERO-2521: Add x-forwarded-for header to requests
20
+ - 3690d3b: ZERO-2485: Check ESLint peerDependency version
21
+ - b4452e9: ZERO-2463: Refactor Sentry initialization and add Sentry DSN option to settings
22
+ - b2da5e4: Revert ZERO-2435
23
+ - f76f079: ZERO-2493: Add redirect util function
24
+
25
+ ### Patch Changes
26
+
27
+ - da1e501: ZERO-2296: Fix ROUTES import
28
+ - 2e44646: ZERO-2434: Fix category URL in getCategoryDataHandler function
29
+ - 183674f: BRDG-9158: Handle locale prefix
30
+ - 8c7f5bc: ZERO-2440: Pipeline test
31
+ - @akinon/eslint-plugin-projectzero@1.26.0-rc.0
32
+
3
33
  ## 1.25.0
4
34
 
5
35
  ### Minor Changes
@@ -17,7 +47,83 @@
17
47
 
18
48
  ### Patch Changes
19
49
 
50
+ - da1e501: ZERO-2296: Fix ROUTES import
51
+ - 2e44646: ZERO-2434: Fix category URL in getCategoryDataHandler function
52
+ - 183674f: BRDG-9158: Handle locale prefix
53
+ - 8c7f5bc: ZERO-2440: Pipeline test
54
+ - @akinon/eslint-plugin-projectzero@1.25.0-rc.5
55
+
56
+ ## 1.25.0-rc.4
57
+
58
+ ### Patch Changes
59
+
60
+ - 183674f: BRDG-9158: Handle locale prefix
61
+ - @akinon/eslint-plugin-projectzero@1.25.0-rc.4
62
+
63
+ ## 1.25.0-rc.3
64
+
65
+ ### Minor Changes
66
+
67
+ - 1289982: ZERO-2521: Add x-forwarded-for header to requests
68
+
69
+ ### Patch Changes
70
+
71
+ - @akinon/eslint-plugin-projectzero@1.25.0-rc.3
72
+
73
+ ## 1.25.0-rc.2
74
+
75
+ ### Minor Changes
76
+
77
+ - 7e41bdc: BRDG-9158: Remove redirect-three-d page endpoint
78
+
79
+ ### Patch Changes
80
+
81
+ - @akinon/eslint-plugin-projectzero@1.25.0-rc.2
82
+
83
+ ## 1.25.0-rc.1
84
+
85
+ ### Minor Changes
86
+
87
+ - 6d4aadb: ZERO-2476: Auto install recommendenent extension
88
+ - e20b27f: ZERO-2454:add otp login
89
+ - e0a945e: ZERO-2494:Add LiveCommerce for managing basket and product actions
90
+ - a4674c6: ZERO-2461: add optional chaining for referrer header and add locale value for redirect url
91
+ - 1ec9775: ZERO-2462:add custom span to logs
92
+ - ab5a493: ZERO-2475:add types [key: string]: any; for unknown attributes
93
+ - 3690d3b: ZERO-2485: Check ESLint peerDependency version
94
+ - 92094d4: ZERO-2477: Update Sentry version and add hideSourceMaps option
95
+ - b4452e9: ZERO-2463: Refactor Sentry initialization and add Sentry DSN option to settings
96
+ - b2da5e4: Revert ZERO-2435
97
+ - d3edd3a: ZERO-2499:add style prop in link component
98
+ - f76f079: ZERO-2493: Add redirect util function
99
+
100
+ ### Patch Changes
101
+
102
+ - da1e501: ZERO-2296: Fix ROUTES import
20
103
  - 95510c7: ZERO-2508: Enable rc branch pipeline and add check-publish-version step
104
+ - 2e44646: ZERO-2434: Fix category URL in getCategoryDataHandler function
105
+ - 8c7f5bc: ZERO-2440: Pipeline test
106
+ - Updated dependencies [95510c7]
107
+ - @akinon/eslint-plugin-projectzero@1.25.0-rc.1
108
+
109
+ ## 1.25.0-rc.0
110
+
111
+ ### Minor Changes
112
+
113
+ - 6d4aadb: ZERO-2476: Auto install recommendenent extension
114
+ - e20b27f: ZERO-2454:add otp login
115
+ - a4674c6: ZERO-2461: add optional chaining for referrer header and add locale value for redirect url
116
+ - 1ec9775: ZERO-2462:add custom span to logs
117
+ - 3690d3b: ZERO-2485: Check ESLint peerDependency version
118
+ - b4452e9: ZERO-2463: Refactor Sentry initialization and add Sentry DSN option to settings
119
+ - b2da5e4: Revert ZERO-2435
120
+
121
+ ### Patch Changes
122
+
123
+ - da1e501: ZERO-2296: Fix ROUTES import
124
+ - 2e44646: ZERO-2434: Fix category URL in getCategoryDataHandler function
125
+ - 8c7f5bc: ZERO-2440: Pipeline test
126
+ - @akinon/eslint-plugin-projectzero@1.25.0-rc.0
21
127
 
22
128
  ## 1.24.0
23
129
 
package/api/auth.ts CHANGED
@@ -80,14 +80,21 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
80
80
  const language = Settings.localization.locales.find(
81
81
  (item) => item.value === credentials.locale
82
82
  ).apiValue;
83
+ const userIp = req.headers['x-forwarded-for']?.toString() ?? '';
83
84
 
84
85
  headers.set('Content-Type', 'application/json');
85
86
  headers.set('cookie', `${req.headers.cookie}`);
86
87
  headers.set('Accept-Language', `${language}`);
87
88
  headers.set('x-currency', req.cookies['pz-currency'] ?? '');
89
+ headers.set('x-forwarded-for', userIp);
90
+ headers.set(
91
+ 'x-app-device',
92
+ req.headers['x-app-device']?.toString() ?? ''
93
+ );
88
94
 
89
95
  logger.debug('Trying to login/register', {
90
- formType: credentials.formType
96
+ formType: credentials.formType,
97
+ userIp
91
98
  });
92
99
 
93
100
  const apiRequest = await fetch(
@@ -99,7 +106,9 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
99
106
  }
100
107
  );
101
108
 
102
- logger.info(`Login/Register request result: ${apiRequest.status}`);
109
+ logger.info(`Login/Register request result: ${apiRequest.status}`, {
110
+ userIp
111
+ });
103
112
 
104
113
  const response = (await apiRequest.json()) as {
105
114
  key: string;
@@ -220,6 +229,17 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
220
229
  pages: {
221
230
  signIn: ROUTES.AUTH,
222
231
  error: ROUTES.AUTH
232
+ },
233
+ cookies: {
234
+ sessionToken: {
235
+ name: `__Secure-next-auth.session-token`,
236
+ options: {
237
+ httpOnly: true,
238
+ sameSite: 'none',
239
+ path: '/',
240
+ secure: true
241
+ }
242
+ }
223
243
  }
224
244
  };
225
245
  };
package/api/client.ts CHANGED
@@ -51,7 +51,6 @@ async function proxyRequest(...args) {
51
51
 
52
52
  [
53
53
  'x-forwarded-host',
54
- 'x-forwarded-for',
55
54
  'x-forwarded-proto',
56
55
  'x-forwarded-port',
57
56
  'x-requested-with',
@@ -23,6 +23,21 @@ function checkDir() {
23
23
 
24
24
  const BASE_DIR = checkDir();
25
25
 
26
+ function getProjectZeroNextPackagePath() {
27
+ const possiblePaths = [
28
+ path.join(BASE_DIR, 'apps/projectzeronext/package.json'),
29
+ path.join(BASE_DIR, 'package.json')
30
+ ];
31
+
32
+ for (const packagePath of possiblePaths) {
33
+ if (fs.existsSync(packagePath)) {
34
+ return packagePath;
35
+ }
36
+ }
37
+
38
+ throw new Error('Unable to find package.json in expected locations.');
39
+ }
40
+
26
41
  try {
27
42
  const akinonNextPackagePath = fs.existsSync(
28
43
  path.join(BASE_DIR, 'packages/akinon-next/package.json')
@@ -34,7 +49,7 @@ try {
34
49
  fs.readFileSync(akinonNextPackagePath, 'utf8')
35
50
  );
36
51
 
37
- const projectZeroNextPackagePath = path.join(BASE_DIR, 'package.json');
52
+ const projectZeroNextPackagePath = getProjectZeroNextPackagePath();
38
53
 
39
54
  const projectZeroNextPackage = JSON.parse(
40
55
  fs.readFileSync(projectZeroNextPackagePath, 'utf8')
@@ -0,0 +1,27 @@
1
+ const { execSync } = require('child_process');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ function findBaseDir() {
6
+ let currentDir = __dirname;
7
+ while (currentDir !== path.resolve(currentDir, '..')) {
8
+ if (fs.existsSync(path.join(currentDir, 'turbo.json'))) {
9
+ return currentDir;
10
+ }
11
+ currentDir = path.resolve(currentDir, '..');
12
+ }
13
+ return null;
14
+ }
15
+
16
+ const BASE_DIR = findBaseDir();
17
+
18
+ if (BASE_DIR) {
19
+ const extensions = ['bilal-akinon.pznext'];
20
+ extensions.forEach((extension) => {
21
+ try {
22
+ execSync(`code --install-extension ${extension}`, { stdio: 'inherit' });
23
+ } catch (error) {
24
+ console.error(`Error installing ${extension}:`);
25
+ }
26
+ });
27
+ }
package/bin/pz-predev.js CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const runScript = require('./run-script');
4
+
5
+ runScript('pz-install-extensions.js');
4
6
  runScript('pz-install-theme.js');
@@ -22,9 +22,9 @@ const userApi = api.injectEndpoints({
22
22
  getCaptcha: build.query<GetCaptchaResponse, void>({
23
23
  query: () => buildClientRequestUrl(user.captcha),
24
24
  transformResponse: (response: { html: string }) => {
25
- const siteKeyMatch = response.html.match(/sitekey=["|']\w+/gi);
25
+ const siteKeyMatch = response.html.match(/sitekey=["|'][^"']+/gi);
26
26
  const csrfTokenMatch = response.html.match(
27
- /name=['|"]csrfmiddlewaretoken['|"] value=['|"]\w+/gi
27
+ /name=['|"]csrfmiddlewaretoken['|"] value=['|"][^'"]+/gi
28
28
  );
29
29
  const siteKey = siteKeyMatch?.[0].replace(/sitekey=["|']/, '') || '';
30
30
  const csrfToken =
@@ -43,7 +43,8 @@ const withCompleteGpay =
43
43
  'X-Requested-With': 'XMLHttpRequest',
44
44
  'Content-Type': 'application/x-www-form-urlencoded',
45
45
  Cookie: `osessionid=${req.cookies.get('osessionid')?.value ?? ''}`,
46
- 'x-currency': req.cookies.get('pz-currency')?.value ?? ''
46
+ 'x-currency': req.cookies.get('pz-currency')?.value ?? '',
47
+ 'x-forwarded-for': ip
47
48
  };
48
49
 
49
50
  try {
@@ -43,7 +43,8 @@ const withCompleteMasterpass =
43
43
  'X-Requested-With': 'XMLHttpRequest',
44
44
  'Content-Type': 'application/x-www-form-urlencoded',
45
45
  Cookie: `osessionid=${req.cookies.get('osessionid')?.value ?? ''}`,
46
- 'x-currency': req.cookies.get('pz-currency')?.value ?? ''
46
+ 'x-currency': req.cookies.get('pz-currency')?.value ?? '',
47
+ 'x-forwarded-for': ip
47
48
  };
48
49
 
49
50
  try {
@@ -97,6 +97,12 @@ const withPzDefault =
97
97
  );
98
98
  }
99
99
 
100
+ if (req.nextUrl.pathname.includes('/orders/redirect-three-d')) {
101
+ return NextResponse.rewrite(
102
+ new URL(`${encodeURI(Settings.commerceUrl)}/orders/redirect-three-d/`)
103
+ );
104
+ }
105
+
100
106
  // If commerce redirects to /orders/checkout/ without locale
101
107
  if (
102
108
  req.nextUrl.pathname.match(new RegExp('^/orders/checkout/$')) &&
@@ -133,7 +139,8 @@ const withPzDefault =
133
139
  Cookie: req.headers.get('cookie') || '',
134
140
  Accept: 'application/json',
135
141
  'Content-Type': 'application/json',
136
- 'X-Requested-With': 'XMLHttpRequest'
142
+ 'X-Requested-With': 'XMLHttpRequest',
143
+ 'x-forwarded-for': ip
137
144
  }
138
145
  }
139
146
  );
@@ -15,11 +15,13 @@ const withOauthLogin =
15
15
  const loginCallbackUrlMatcherRegex = new RegExp(
16
16
  /^\/(\w+)\/login\/callback\/?$/
17
17
  );
18
+ const ip = req.headers.get('x-forwarded-for') ?? '';
18
19
 
19
20
  const headers = {
20
21
  'x-forwarded-host':
21
22
  req.headers.get('x-forwarded-host') || req.headers.get('host') || '',
22
- 'x-currency': req.cookies.get('pz-currency')?.value ?? ''
23
+ 'x-currency': req.cookies.get('pz-currency')?.value ?? '',
24
+ 'x-forwarded-for': ip
23
25
  };
24
26
 
25
27
  if (loginUrlMatcherRegex.test(url.pathname)) {
@@ -44,7 +44,9 @@ const withRedirectionPayment =
44
44
  'X-Requested-With': 'XMLHttpRequest',
45
45
  'Content-Type': 'application/x-www-form-urlencoded',
46
46
  Cookie: req.headers.get('cookie') ?? '',
47
- 'x-currency': req.cookies.get('pz-currency')?.value ?? ''
47
+ 'x-currency': req.cookies.get('pz-currency')?.value ?? '',
48
+ 'x-forwarded-for': ip
49
+
48
50
  };
49
51
 
50
52
  try {
@@ -43,7 +43,8 @@ const withThreeDRedirection =
43
43
  'X-Requested-With': 'XMLHttpRequest',
44
44
  'Content-Type': 'application/x-www-form-urlencoded',
45
45
  Cookie: `osessionid=${req.cookies.get('osessionid')?.value ?? ''}`,
46
- 'x-currency': req.cookies.get('pz-currency')?.value ?? ''
46
+ 'x-currency': req.cookies.get('pz-currency')?.value ?? '',
47
+ 'x-forwarded-for': ip
47
48
  };
48
49
 
49
50
  try {
@@ -31,6 +31,9 @@ const withUrlRedirection =
31
31
  const request = await fetch(
32
32
  `${settings.commerceUrl}${pathnameWithoutLocale}${url.search}`,
33
33
  {
34
+ headers: {
35
+ 'x-forwarded-for': ip
36
+ },
34
37
  redirect: 'manual',
35
38
  next: {
36
39
  revalidate: 0
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.25.0",
4
+ "version": "1.26.0-rc.1",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -34,5 +34,8 @@
34
34
  "eslint": "^8.14.0",
35
35
  "@akinon/eslint-plugin-projectzero": "1.24.0",
36
36
  "eslint-config-prettier": "8.5.0"
37
+ },
38
+ "peerDependencies": {
39
+ "@akinon/eslint-plugin-projectzero": "1.24.0"
37
40
  }
38
41
  }
package/sentry/index.ts CHANGED
@@ -1,27 +1,33 @@
1
1
  import * as Sentry from '@sentry/nextjs';
2
+ import settings from 'settings';
2
3
 
3
4
  const SENTRY_DSN: string =
4
- process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
5
+ settings.sentryDsn ||
6
+ process.env.SENTRY_DSN ||
7
+ process.env.NEXT_PUBLIC_SENTRY_DSN;
5
8
 
6
9
  export const initSentry = (
7
10
  type: 'Server' | 'Client' | 'Edge',
8
- options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {}
11
+ options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {
12
+ dsn: SENTRY_DSN,
13
+ integrations: [],
14
+ tracesSampleRate: 1.0
15
+ }
9
16
  ) => {
10
- // TODO: Handle options with ESLint rules
11
-
12
- // TODO: Remove Zero Project DSN
13
-
14
- Sentry.init({
15
- dsn:
16
- SENTRY_DSN ||
17
- 'https://d8558ef8997543deacf376c7d8d7cf4b@o64293.ingest.sentry.io/4504338423742464',
17
+ const initOptions = {
18
+ ...options,
18
19
  initialScope: {
19
20
  tags: {
21
+ ...((
22
+ options.initialScope as {
23
+ tags?: Record<string, string>;
24
+ }
25
+ )?.tags ?? {}),
20
26
  APP_TYPE: 'ProjectZeroNext',
21
27
  TYPE: type
22
28
  }
23
- },
24
- tracesSampleRate: 1.0,
25
- integrations: []
26
- });
29
+ }
30
+ };
31
+
32
+ Sentry.init(initOptions);
27
33
  };
package/types/index.ts CHANGED
@@ -71,6 +71,12 @@ export interface Currency {
71
71
 
72
72
  export interface Settings {
73
73
  commerceUrl: string;
74
+ /**
75
+ * This option allows you to track Sentry events on the client side, in addition to server and edge environments.
76
+ *
77
+ * It overrides process.env.NEXT_PUBLIC_SENTRY_DSN and process.env.SENTRY_DSN.
78
+ */
79
+ sentryDsn?: string;
74
80
  redis: {
75
81
  defaultExpirationTime: number;
76
82
  };
@@ -36,7 +36,8 @@ const appFetch = async <T>(
36
36
  init.headers = {
37
37
  ...(init.headers ?? {}),
38
38
  'Accept-Language': currentLocale.apiValue,
39
- 'x-currency': ServerVariables.currency
39
+ 'x-currency': ServerVariables.currency,
40
+ 'x-forwarded-for': ip
40
41
  };
41
42
 
42
43
  init.next = {
@@ -0,0 +1,30 @@
1
+ import { redirect as nextRedirect, RedirectType } from 'next/navigation';
2
+ import Settings from 'settings';
3
+ import { headers } from 'next/headers';
4
+ import { ServerVariables } from '@akinon/next/utils/server-variables';
5
+ import { getUrlPathWithLocale } from '@akinon/next/utils/localization';
6
+
7
+ export const redirect = (path: string, type?: RedirectType) => {
8
+ const nextHeaders = headers();
9
+ const pageUrl = new URL(
10
+ nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL
11
+ );
12
+
13
+ const currentLocale = Settings.localization.locales.find(
14
+ (locale) => locale.value === ServerVariables.locale
15
+ );
16
+
17
+ const callbackUrl = pageUrl.pathname;
18
+ const redirectUrlWithLocale = getUrlPathWithLocale(
19
+ path,
20
+ currentLocale.localePath ?? currentLocale.value
21
+ );
22
+
23
+ const redirectUrl = `${redirectUrlWithLocale}?callbackUrl=${callbackUrl}`;
24
+
25
+ if (type) {
26
+ return nextRedirect(redirectUrl, type);
27
+ } else {
28
+ return nextRedirect(redirectUrl);
29
+ }
30
+ };
@@ -1,74 +0,0 @@
1
- 'use client';
2
-
3
- import { useEffect, useState } from 'react';
4
- import { ROUTES } from 'routes';
5
- import { useGet3dRedirectFormQuery } from '@akinon/next/data/client/checkout';
6
- import { LoaderSpinner } from 'components';
7
- import { useLocalization } from '../../../hooks/use-localization';
8
- import { getUrlPathWithLocale } from '../../../utils/localization';
9
- import { useSearchParams } from 'next/navigation';
10
-
11
- interface RedirectThreeDContentProps {
12
- sessionId: string;
13
- }
14
-
15
- export default function RedirectThreeDContent({
16
- sessionId
17
- }: RedirectThreeDContentProps) {
18
- const searchParams = useSearchParams();
19
- const { data } = useGet3dRedirectFormQuery();
20
- const [error, setError] = useState(null);
21
- const { locale } = useLocalization();
22
-
23
- useEffect(() => {
24
- if (data) {
25
- const fragment = document.createElement('fragment');
26
- fragment.innerHTML = data.result;
27
-
28
- const form = fragment.querySelector('form');
29
-
30
- // a way to determine if response includes a redirection form or not
31
- if (fragment.querySelector('link[rel="canonical"]') || !form) {
32
- setError('Redirecting to checkout page. Please wait...');
33
-
34
- setTimeout(() => {
35
- let checkoutUrl = `${ROUTES.CHECKOUT}`;
36
-
37
- // iframe param is used to prevent header and footer rendering
38
- if (searchParams.get('iframe') === 'true') {
39
- checkoutUrl = `${checkoutUrl}?iframe=true`;
40
- }
41
-
42
- // Use `window.location.href` instead of `router.push`
43
- // to capture the url change event in iframe
44
- location.href = getUrlPathWithLocale(checkoutUrl, locale);
45
- }, 3000);
46
- return;
47
- }
48
-
49
- const pzParamsInput = document.createElement('input');
50
- pzParamsInput.setAttribute('type', 'hidden');
51
- pzParamsInput.setAttribute('name', 'pzparams');
52
- pzParamsInput.setAttribute(
53
- 'value',
54
- encodeURIComponent(
55
- JSON.stringify({
56
- session: sessionId,
57
- locale
58
- })
59
- )
60
- );
61
- form.appendChild(pzParamsInput);
62
-
63
- form.style.display = 'none';
64
- document.body.appendChild(form);
65
- form.submit();
66
- }
67
- }, [data]);
68
-
69
- return (
70
- <div className="flex items-center justify-center py-20">
71
- {error ?? <LoaderSpinner />}
72
- </div>
73
- );
74
- }
@@ -1,17 +0,0 @@
1
- import { cookies } from 'next/headers';
2
- import { redirect } from 'next/navigation';
3
- import RedirectThreeDContent from './content';
4
- import { ROUTES } from 'routes';
5
-
6
- const RedirectThreeD = async () => {
7
- const nextCookies = cookies();
8
- const sessionId = await nextCookies.get('osessionid')?.value;
9
-
10
- if (!sessionId) {
11
- return redirect(ROUTES.CHECKOUT);
12
- }
13
-
14
- return <RedirectThreeDContent sessionId={sessionId} />;
15
- };
16
-
17
- export default RedirectThreeD;