@akinon/next 1.34.0-rc.9 → 1.34.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.
@@ -5,6 +5,7 @@ module.exports = {
5
5
  es2021: true
6
6
  },
7
7
  extends: [
8
+ 'eslint:recommended',
8
9
  'next/core-web-vitals',
9
10
  'eslint:recommended',
10
11
  'plugin:@typescript-eslint/recommended',
@@ -17,7 +18,7 @@ module.exports = {
17
18
  env: {
18
19
  node: true
19
20
  },
20
- files: ['eslint.config.{js,cjs}', 'middlewares/default.ts'],
21
+ files: ['.eslintrc.{js,cjs}', 'middlewares/default.ts'],
21
22
  rules: {
22
23
  '@akinon/projectzero/check-middleware-order': 'error'
23
24
  },
package/CHANGELOG.md CHANGED
@@ -1,39 +1,6 @@
1
1
  # @akinon/next
2
2
 
3
- ## 1.34.0-rc.9
4
-
5
- ### Minor Changes
6
-
7
- - beb499e: ZERO-2551: Add new tsconfig paths
8
-
9
- ## 1.34.0-rc.8
10
-
11
- ### Minor Changes
12
-
13
- - 91265bb: ZERO-2551: Improve pretty url and caching performance
14
-
15
- ## 1.34.0-rc.7
16
-
17
- ## 1.34.0-rc.6
18
-
19
- ### Minor Changes
20
-
21
- - d09b677: ZERO-2577: Fix pagination bug and update usePagination hook and ensure pagination controls rendering correctly
22
- - 6d4aadb: ZERO-2476: Auto install recommendenent extension
23
- - ebb63ce: ZERO-2525: Fix category facet removal bug and add close icon to active filters
24
- - 7cebe87: ZERO-2524: Add check monorepo utility function
25
- - f0c23bc: ZERO-2135: add custom not found page
26
- - 3420416: ZERO-2533: extend eslint config from @akinon/next
27
- - 495d155: ZERO-2505: findBaseDir function is united and move on to the utils
28
- - 40ad73e: ZERO-2504: add cookie filter to api client request
29
- - 495d155: ZERO-2524: Zero-cli dist checks for changes and renders it to the terminal.
30
- - f046f8e: ZERO-2575: update version for react-number-format
31
- - 6b2972b: ZERO-2514: Fix handling of status 204 and return Commerce status code in client proxy API.
32
- - 3e68768: ZERO-2578: Add osessionid check in middleware
33
-
34
- ### Patch Changes
35
-
36
- - 59fb7c3: ZERO-2504: get set-cookie headers from commerce request
3
+ ## 1.34.0
37
4
 
38
5
  ## 1.33.2
39
6
 
package/api/client.ts CHANGED
@@ -2,8 +2,6 @@ import { ClientRequestOptions } from '../types';
2
2
  import { NextResponse } from 'next/server';
3
3
  import settings from 'settings';
4
4
  import logger from '../utils/log';
5
- import formatCookieString from '../utils/format-cookie-string';
6
- import cookieParser from 'set-cookie-parser';
7
5
 
8
6
  interface RouteParams {
9
7
  params: {
@@ -115,14 +113,6 @@ async function proxyRequest(...args) {
115
113
 
116
114
  try {
117
115
  const request = await fetch(url, fetchOptions);
118
-
119
- // Using NextResponse.json with status 204 will cause an error
120
- if (request.status === 204) {
121
- return new Response(null, {
122
- status: 204
123
- });
124
- }
125
-
126
116
  let response = {} as any;
127
117
 
128
118
  try {
@@ -141,26 +131,20 @@ async function proxyRequest(...args) {
141
131
  );
142
132
  }
143
133
 
144
- const setCookieHeaders = request.headers.getSetCookie();
145
- const exceptCookieKeys = ['pz-locale', 'pz-currency'];
146
-
147
- const isExcludedCookie = (name: string) => exceptCookieKeys.includes(name);
148
-
149
- const filteredCookies = cookieParser
150
- .parse(setCookieHeaders)
151
- .filter((cookie) => !isExcludedCookie(cookie.name));
152
-
134
+ const setCookieHeader = request.headers.get('set-cookie');
153
135
  const responseHeaders: any = {};
154
136
 
155
- if (filteredCookies.length > 0) {
156
- responseHeaders['set-cookie'] = filteredCookies
157
- .map(formatCookieString)
158
- .join(', ');
137
+ if (setCookieHeader) {
138
+ responseHeaders['set-cookie'] = setCookieHeader;
159
139
  }
160
140
 
141
+ const statusCode = new RegExp(/^20./).test(request.status.toString())
142
+ ? 200
143
+ : request.status;
144
+
161
145
  return NextResponse.json(
162
146
  options.responseType === 'text' ? { result: response } : response,
163
- { status: request.status, headers: responseHeaders }
147
+ { status: statusCode, headers: responseHeaders }
164
148
  );
165
149
  } catch (error) {
166
150
  logger.error('Client proxy request failed', error);
@@ -1,7 +1,13 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { execSync } = require('child_process');
4
- const findBaseDir = require('../utils/find-base-dir');
4
+
5
+ function findBaseDir() {
6
+ const insideNodeModules = __dirname.includes('node_modules');
7
+ return insideNodeModules
8
+ ? process.cwd()
9
+ : path.resolve(__dirname, '../../../apps/projectzeronext');
10
+ }
5
11
 
6
12
  const BASE_DIR = findBaseDir();
7
13
  const getFullPath = (relativePath) => path.join(BASE_DIR, relativePath);
@@ -3,7 +3,16 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const spawn = require('cross-spawn');
6
- const findBaseDir = require('../utils/find-base-dir');
6
+
7
+ function findBaseDir() {
8
+ const insideNodeModules = __dirname.includes('node_modules');
9
+
10
+ if (insideNodeModules) {
11
+ return path.resolve(__dirname, '../../../../');
12
+ } else {
13
+ return path.resolve(__dirname, '../../../apps/projectzeronext');
14
+ }
15
+ }
7
16
 
8
17
  const BASE_DIR = findBaseDir();
9
18
 
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const runScript = require('./run-script');
4
-
5
4
  runScript('pz-install-theme.js');
6
- // runScript('pz-pre-check-dist.js');
package/bin/pz-predev.js CHANGED
@@ -1,7 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const runScript = require('./run-script');
4
-
5
- runScript('pz-install-extensions.js');
6
4
  runScript('pz-check-env.js');
7
5
  runScript('pz-install-theme.js');
@@ -1,28 +1,17 @@
1
1
  import clsx from 'clsx';
2
- import { forwardRef, FocusEvent, useState, Ref } from 'react';
2
+ import { forwardRef, FocusEvent, useState } from 'react';
3
3
  import { Controller } from 'react-hook-form';
4
- import { PatternFormat, PatternFormatProps } from 'react-number-format';
4
+ import NumberFormat, { NumberFormatProps } from 'react-number-format';
5
5
  import { InputProps } from '../types';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
 
8
- const PatternFormatWithRef = forwardRef(
9
- (props: PatternFormatProps, ref: Ref<HTMLInputElement>) => {
10
- return <PatternFormat {...props} getInputRef={ref} />;
11
- }
12
- );
13
- PatternFormatWithRef.displayName = 'PatternFormatWithRef';
14
-
15
8
  export const Input = forwardRef<
16
9
  HTMLInputElement,
17
10
  InputProps &
18
11
  Pick<
19
- PatternFormatProps,
20
- 'mask' | 'allowEmptyFormatting' | 'onValueChange'
21
- > & {
22
- format?: string;
23
- defaultValue?: string;
24
- type?: string;
25
- }
12
+ NumberFormatProps,
13
+ 'format' | 'mask' | 'allowEmptyFormatting' | 'onValueChange'
14
+ >
26
15
  >((props, ref) => {
27
16
  const [focused, setFocused] = useState(false);
28
17
  const [hasValue, setHasValue] = useState(false);
@@ -48,7 +37,6 @@ export const Input = forwardRef<
48
37
  ),
49
38
  props.className
50
39
  );
51
-
52
40
  const inputProps: any = {
53
41
  id,
54
42
  ref,
@@ -91,14 +79,14 @@ export const Input = forwardRef<
91
79
  <Controller
92
80
  name={props.name ?? ''}
93
81
  control={props.control}
82
+ defaultValue={false}
94
83
  render={({ field }) => (
95
- <PatternFormatWithRef
84
+ <NumberFormat
96
85
  format={format}
97
86
  mask={mask ?? ''}
98
87
  {...rest}
99
88
  {...field}
100
89
  {...inputProps}
101
- type={props.type as 'text' | 'password' | 'tel'}
102
90
  />
103
91
  )}
104
92
  />
@@ -1,11 +1,11 @@
1
1
  import { useMemo } from 'react';
2
- import { NumericFormat, NumericFormatProps } from 'react-number-format';
2
+ import NumberFormat, { NumberFormatProps } from 'react-number-format';
3
3
  import { getCurrency } from '@akinon/next/utils';
4
4
 
5
5
  import { useLocalization } from '@akinon/next/hooks';
6
6
  import { PriceProps } from '../types';
7
7
 
8
- export const Price = (props: NumericFormatProps & PriceProps) => {
8
+ export const Price = (props: NumberFormatProps & PriceProps) => {
9
9
  const {
10
10
  value,
11
11
  currencyCode,
@@ -39,7 +39,7 @@ export const Price = (props: NumericFormatProps & PriceProps) => {
39
39
  );
40
40
 
41
41
  return (
42
- <NumericFormat
42
+ <NumberFormat
43
43
  value={useNegative ? `-${useNegativeSpace}${_value}` : _value}
44
44
  {...{
45
45
  [useCurrencyAfterPrice ? 'suffix' : 'prefix']: currency
@@ -8,7 +8,7 @@ import logger from '../../utils/log';
8
8
 
9
9
  function getCategoryDataHandler(
10
10
  pk: number,
11
- searchParams?: { [key: string]: string | string[] | undefined },
11
+ searchParams?: URLSearchParams,
12
12
  headers?: Record<string, string>
13
13
  ) {
14
14
  return async function () {
@@ -78,7 +78,7 @@ export const getCategoryData = ({
78
78
  headers
79
79
  }: {
80
80
  pk: number;
81
- searchParams?: { [key: string]: string | string[] | undefined };
81
+ searchParams?: URLSearchParams;
82
82
  headers?: Record<string, string>;
83
83
  }) => {
84
84
  return Cache.wrap(
@@ -7,7 +7,7 @@ import { parse } from 'lossless-json';
7
7
  import logger from '../../utils/log';
8
8
 
9
9
  const getListDataHandler = (
10
- searchParams: { [key: string]: string | string[] | undefined },
10
+ searchParams: URLSearchParams,
11
11
  headers?: Record<string, string>
12
12
  ) => {
13
13
  return async function () {
@@ -54,7 +54,7 @@ export const getListData = async ({
54
54
  searchParams,
55
55
  headers
56
56
  }: {
57
- searchParams: { [key: string]: string | string[] | undefined };
57
+ searchParams: URLSearchParams;
58
58
  headers?: Record<string, string>;
59
59
  }) => {
60
60
  return Cache.wrap(
@@ -9,7 +9,7 @@ import appFetch from '../../utils/app-fetch';
9
9
 
10
10
  type GetProduct = {
11
11
  pk: number;
12
- searchParams?: { [key: string]: string | string[] | undefined };
12
+ searchParams?: URLSearchParams;
13
13
  groupProduct?: boolean;
14
14
  };
15
15
 
@@ -74,7 +74,10 @@ export const getProductData = async ({
74
74
  groupProduct
75
75
  }: GetProduct) => {
76
76
  return Cache.wrap(
77
- CacheKey[groupProduct ? 'GroupProduct' : 'Product'](pk, searchParams ?? {}),
77
+ CacheKey[groupProduct ? 'GroupProduct' : 'Product'](
78
+ pk,
79
+ searchParams ?? new URLSearchParams()
80
+ ),
78
81
  getProductDataHandler({ pk, searchParams, groupProduct }),
79
82
  {
80
83
  expire: 300
@@ -7,7 +7,7 @@ import header from '../../redux/reducers/header';
7
7
 
8
8
  const getSpecialPageDataHandler = (
9
9
  pk: number,
10
- searchParams: { [key: string]: string | string[] | undefined },
10
+ searchParams: URLSearchParams,
11
11
  headers?: Record<string, string>
12
12
  ) => {
13
13
  return async function () {
@@ -34,7 +34,7 @@ export const getSpecialPageData = async ({
34
34
  headers
35
35
  }: {
36
36
  pk: number;
37
- searchParams: { [key: string]: string | string[] | undefined };
37
+ searchParams: URLSearchParams;
38
38
  headers?: Record<string, string>;
39
39
  }) => {
40
40
  return Cache.wrap(
@@ -28,11 +28,7 @@ function reducer(state: InitialState, action: ACTIONTYPE) {
28
28
  case 'setPage':
29
29
  return { ...state, page: action.payload };
30
30
  case 'setLimit':
31
- return {
32
- ...state,
33
- limit: action.payload,
34
- last: Math.ceil(state.total / action.payload)
35
- };
31
+ return { ...state, limit: action.payload };
36
32
  default:
37
33
  throw new Error();
38
34
  }
@@ -50,11 +46,10 @@ export default function usePagination(
50
46
  () => new URLSearchParams(searchParams.toString()),
51
47
  [searchParams]
52
48
  );
53
-
54
49
  const { page, limit } = useMemo(
55
50
  () => ({
56
51
  page: _page || Number(searchParams.get('page')) || 1,
57
- limit: _limit || Number(searchParams.get('limit')) || 12
52
+ limit: _limit || Number(searchParams.get('limit'))
58
53
  }),
59
54
  [searchParams, _page, _limit]
60
55
  );
@@ -65,7 +60,6 @@ export default function usePagination(
65
60
  last: _last || Math.ceil(_total / limit) || 1,
66
61
  total: _total
67
62
  };
68
-
69
63
  const [state, dispatch] = useReducer(reducer, initialState);
70
64
 
71
65
  useEffect(() => {
@@ -99,24 +93,23 @@ export default function usePagination(
99
93
  [dispatch]
100
94
  );
101
95
 
102
- const pageList = useMemo(
103
- () =>
104
- Array.from({ length: state.last }, (_, i) => {
105
- urlSearchParams.set('page', (i + 1).toString());
106
- return {
107
- page: i + 1,
108
- url: `${pathname}?${urlSearchParams.toString()}`
109
- };
110
- }),
111
- [state.last, pathname, urlSearchParams]
112
- );
96
+ const pageList = useMemo(() => {
97
+ return Array.from({ length: state.last }, (_, i) => {
98
+ urlSearchParams.set('page', (i + 1).toString());
99
+
100
+ return {
101
+ page: i + 1,
102
+ url: `${pathname}?${urlSearchParams.toString()}`
103
+ };
104
+ });
105
+ }, [state.last, pathname, urlSearchParams]);
113
106
 
114
107
  const prev = useMemo(() => {
115
108
  if (state.page > 1) {
116
109
  urlSearchParams.set('page', (Number(state.page) - 1).toString());
117
110
  return `${pathname}?${urlSearchParams.toString()}`;
118
111
  }
119
- return '#';
112
+ return null;
120
113
  }, [state.page, pathname, urlSearchParams]);
121
114
 
122
115
  const next = useMemo(() => {
@@ -124,7 +117,7 @@ export default function usePagination(
124
117
  urlSearchParams.set('page', (Number(state.page) + 1).toString());
125
118
  return `${pathname}?${urlSearchParams.toString()}`;
126
119
  }
127
- return '#';
120
+ return null;
128
121
  }, [state.page, state.last, pathname, urlSearchParams]);
129
122
 
130
123
  return {
package/lib/cache.ts CHANGED
@@ -20,16 +20,13 @@ const hashCacheKey = (object?: Record<string, string>) => {
20
20
  return `_${encodeURIComponent(cacheKey)}`;
21
21
  };
22
22
  export const CacheKey = {
23
- List: (
24
- searchParams: { [key: string]: string | string[] | undefined },
25
- headers?: Record<string, string>
26
- ) =>
23
+ List: (searchParams: URLSearchParams, headers?: Record<string, string>) =>
27
24
  `list_${encodeURIComponent(JSON.stringify(searchParams))}${hashCacheKey(
28
25
  headers
29
26
  )}`,
30
27
  Category: (
31
28
  pk: number,
32
- searchParams?: { [key: string]: string | string[] | undefined },
29
+ searchParams?: URLSearchParams,
33
30
  headers?: Record<string, string>
34
31
  ) =>
35
32
  `category_${pk}_${encodeURIComponent(
@@ -38,20 +35,15 @@ export const CacheKey = {
38
35
  CategorySlug: (slug: string) => `category_${slug}`,
39
36
  SpecialPage: (
40
37
  pk: number,
41
- searchParams: { [key: string]: string | string[] | undefined },
38
+ searchParams: URLSearchParams,
42
39
  headers?: Record<string, string>
43
40
  ) =>
44
41
  `special_page_${pk}_${encodeURIComponent(
45
42
  JSON.stringify(searchParams)
46
43
  )}${hashCacheKey(headers)}`,
47
- Product: (
48
- pk: number,
49
- searchParams: { [key: string]: string | string[] | undefined }
50
- ) => `product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
51
- GroupProduct: (
52
- pk: number,
53
- searchParams: { [key: string]: string | string[] | undefined }
54
- ) =>
44
+ Product: (pk: number, searchParams: URLSearchParams) =>
45
+ `product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
46
+ GroupProduct: (pk: number, searchParams: URLSearchParams) =>
55
47
  `group_product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
56
48
  FlatPage: (pk: number) => `flat_page_${pk}`,
57
49
  LandingPage: (pk: number) => `landing_page_${pk}`,
@@ -166,10 +158,6 @@ export class Cache {
166
158
  handler: () => Promise<T>,
167
159
  options?: CacheOptions
168
160
  ): Promise<T> {
169
- if (Settings.usePrettyUrlRoute) {
170
- return await handler();
171
- }
172
-
173
161
  const requiredVariables = [
174
162
  process.env.CACHE_HOST,
175
163
  process.env.CACHE_PORT,
@@ -33,7 +33,6 @@ const withCompleteGpay =
33
33
  async (req: PzNextRequest, event: NextFetchEvent) => {
34
34
  const url = req.nextUrl.clone();
35
35
  const ip = req.headers.get('x-forwarded-for') ?? '';
36
- const sessionId = req.cookies.get('osessionid');
37
36
 
38
37
  if (url.search.indexOf('GPayCompletePage') === -1) {
39
38
  return middleware(req, event);
@@ -51,24 +50,6 @@ const withCompleteGpay =
51
50
  try {
52
51
  const body = await streamToString(req.body);
53
52
 
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-masterpass',
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
53
  const request = await fetch(requestUrl, {
73
54
  method: 'POST',
74
55
  headers: requestHeaders,
@@ -33,7 +33,6 @@ const withCompleteMasterpass =
33
33
  async (req: PzNextRequest, event: NextFetchEvent) => {
34
34
  const url = req.nextUrl.clone();
35
35
  const ip = req.headers.get('x-forwarded-for') ?? '';
36
- const sessionId = req.cookies.get('osessionid');
37
36
 
38
37
  if (url.search.indexOf('MasterpassCompletePage') === -1) {
39
38
  return middleware(req, event);
@@ -51,24 +50,6 @@ const withCompleteMasterpass =
51
50
  try {
52
51
  const body = await streamToString(req.body);
53
52
 
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-masterpass',
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
53
  const request = await fetch(requestUrl, {
73
54
  method: 'POST',
74
55
  headers: requestHeaders,
@@ -153,7 +153,6 @@ const withPzDefault =
153
153
 
154
154
  req.middlewareParams = {
155
155
  commerceUrl,
156
- found: true,
157
156
  rewrites: {}
158
157
  };
159
158
 
@@ -187,28 +186,6 @@ const withPzDefault =
187
186
  locale.length ? `${locale}/` : ''
188
187
  }${currency}${prettyUrl ?? pathnameWithoutLocale}`;
189
188
 
190
- if (
191
- !req.middlewareParams.found &&
192
- Settings.customNotFoundEnabled
193
- ) {
194
- let pathname = url.pathname
195
- .replace(/\/+$/, '')
196
- .split('/');
197
- url.pathname = url.pathname.replace(
198
- pathname.pop(),
199
- 'pz-not-found'
200
- );
201
- }
202
-
203
- if (
204
- Settings.usePrettyUrlRoute &&
205
- url.searchParams.toString().length > 0
206
- ) {
207
- url.pathname =
208
- url.pathname +
209
- `searchparams|${url.searchParams.toString()}`;
210
- }
211
-
212
189
  Settings.rewrites.forEach((rewrite) => {
213
190
  url.pathname = url.pathname.replace(
214
191
  rewrite.source,
@@ -26,7 +26,6 @@ export {
26
26
  export interface PzNextRequest extends NextRequest {
27
27
  middlewareParams: {
28
28
  commerceUrl: string;
29
- found: boolean;
30
29
  rewrites: {
31
30
  locale?: string;
32
31
  prettyUrl?: string;
@@ -56,10 +56,6 @@ const resolvePrettyUrl = async (pathname: string, ip: string | null) => {
56
56
  const withPrettyUrl =
57
57
  (middleware: NextMiddleware) =>
58
58
  async (req: PzNextRequest, event: NextFetchEvent) => {
59
- if (Settings.usePrettyUrlRoute) {
60
- return middleware(req, event);
61
- }
62
-
63
59
  const url = req.nextUrl.clone();
64
60
  const matchedLanguagePrefix = url.pathname.match(
65
61
  urlLocaleMatcherRegex
@@ -102,8 +98,6 @@ const withPrettyUrl =
102
98
  return middleware(req, event);
103
99
  }
104
100
 
105
- req.middlewareParams.found = false;
106
-
107
101
  return middleware(req, event);
108
102
  };
109
103
 
@@ -34,7 +34,6 @@ const withRedirectionPayment =
34
34
  const url = req.nextUrl.clone();
35
35
  const searchParams = new URLSearchParams(url.search);
36
36
  const ip = req.headers.get('x-forwarded-for') ?? '';
37
- const sessionId = req.cookies.get('osessionid');
38
37
 
39
38
  if (searchParams.get('page') !== 'RedirectionPageCompletePage') {
40
39
  return middleware(req, event);
@@ -47,29 +46,12 @@ const withRedirectionPayment =
47
46
  Cookie: req.headers.get('cookie') ?? '',
48
47
  'x-currency': req.cookies.get('pz-currency')?.value ?? '',
49
48
  'x-forwarded-for': ip
49
+
50
50
  };
51
51
 
52
52
  try {
53
53
  const body = await streamToString(req.body);
54
54
 
55
- if (!sessionId) {
56
- logger.warn(
57
- 'Make sure that the SESSION_COOKIE_SAMESITE environment variable is set to None in Commerce.',
58
- {
59
- middleware: 'redirection-payment',
60
- ip
61
- }
62
- );
63
-
64
- return NextResponse.redirect(
65
- `${url.origin}${getUrlPathWithLocale(
66
- '/orders/checkout/',
67
- req.cookies.get('pz-locale')?.value
68
- )}`,
69
- 303
70
- );
71
- }
72
-
73
55
  const request = await fetch(requestUrl, {
74
56
  method: 'POST',
75
57
  headers: requestHeaders,
@@ -33,7 +33,6 @@ const withThreeDRedirection =
33
33
  async (req: PzNextRequest, event: NextFetchEvent) => {
34
34
  const url = req.nextUrl.clone();
35
35
  const ip = req.headers.get('x-forwarded-for') ?? '';
36
- const sessionId = req.cookies.get('osessionid');
37
36
 
38
37
  if (url.search.indexOf('CreditCardThreeDSecurePage') === -1) {
39
38
  return middleware(req, event);
@@ -51,24 +50,6 @@ const withThreeDRedirection =
51
50
  try {
52
51
  const body = await streamToString(req.body);
53
52
 
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: 'three-d-redirection',
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
53
  const request = await fetch(requestUrl, {
73
54
  method: 'POST',
74
55
  headers: requestHeaders,
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.34.0-rc.9",
4
+ "version": "1.34.0",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -20,22 +20,19 @@
20
20
  "@opentelemetry/sdk-trace-node": "1.19.0",
21
21
  "@opentelemetry/semantic-conventions": "1.19.0",
22
22
  "@reduxjs/toolkit": "1.9.7",
23
- "@neshca/cache-handler": "1.0.7",
24
23
  "cross-spawn": "7.0.3",
25
24
  "generic-pool": "3.9.0",
26
25
  "react-redux": "8.1.3",
27
26
  "react-string-replace": "1.1.1",
28
- "redis": "4.6.13",
29
- "semver": "7.5.4",
30
- "set-cookie-parser": "2.6.0"
27
+ "redis": "4.5.1",
28
+ "semver": "7.5.4"
31
29
  },
32
30
  "devDependencies": {
33
31
  "@types/react-redux": "7.1.30",
34
- "@types/set-cookie-parser": "2.4.7",
35
32
  "@typescript-eslint/eslint-plugin": "6.7.4",
36
33
  "@typescript-eslint/parser": "6.7.4",
37
34
  "eslint": "^8.14.0",
38
- "@akinon/eslint-plugin-projectzero": "1.34.0-rc.9",
35
+ "@akinon/eslint-plugin-projectzero": "1.34.0",
39
36
  "eslint-config-prettier": "8.5.0"
40
37
  }
41
38
  }
@@ -36,7 +36,6 @@ export type FacetChoice = {
36
36
  quantity: number;
37
37
  is_selected: boolean;
38
38
  url?: string;
39
- real_depth?: string;
40
39
  [key: string]: any;
41
40
  };
42
41
 
package/types/index.ts CHANGED
@@ -70,7 +70,6 @@ export interface Currency {
70
70
  }
71
71
 
72
72
  export interface Settings {
73
- usePrettyUrlRoute?: boolean;
74
73
  commerceUrl: string;
75
74
  redis: {
76
75
  defaultExpirationTime: number;
@@ -182,7 +181,6 @@ export interface Settings {
182
181
  extraPaymentTypes?: string[];
183
182
  masterpassJsUrl?: string;
184
183
  };
185
- customNotFoundEnabled: boolean;
186
184
  }
187
185
 
188
186
  export interface CacheOptions {
@@ -215,7 +213,7 @@ export type Translations = { [key: string]: object };
215
213
 
216
214
  export interface PageProps<T = any> {
217
215
  params: T;
218
- searchParams: { [key: string]: string | string[] | undefined };
216
+ searchParams: URLSearchParams;
219
217
  }
220
218
 
221
219
  export interface LayoutProps<T = any> extends PageProps<T> {
@@ -41,7 +41,7 @@ const appFetch = async <T>(
41
41
  };
42
42
 
43
43
  init.next = {
44
- revalidate: Settings.usePrettyUrlRoute ? 0 : 60
44
+ revalidate: 60
45
45
  };
46
46
 
47
47
  logger.debug(`FETCH START ${url}`, { requestURL, init, ip });
@@ -1,15 +1,11 @@
1
1
  import logger from './log';
2
2
 
3
- export const generateCommerceSearchParams = (searchParams?: {
4
- [key: string]: string | string[] | undefined;
5
- }) => {
3
+ export const generateCommerceSearchParams = (searchParams?: URLSearchParams) => {
6
4
  if (!searchParams) {
7
5
  return null;
8
6
  }
9
7
 
10
- const urlSerchParams = new URLSearchParams(
11
- searchParams as Record<string, string>
12
- );
8
+ const urlSerchParams = new URLSearchParams(searchParams);
13
9
 
14
10
  Object.entries(searchParams).forEach(([key, value]) => {
15
11
  if (typeof value === 'object') {
package/with-pz-config.js CHANGED
@@ -8,7 +8,6 @@ const defaultConfig = {
8
8
  transpilePackages: ['@akinon/next', ...pzPlugins.map((p) => `@akinon/${p}`)],
9
9
  skipTrailingSlashRedirect: true,
10
10
  poweredByHeader: false,
11
- cacheMaxMemorySize: 0,
12
11
  env: {
13
12
  NEXT_PUBLIC_SENTRY_DSN: process.env.SENTRY_DSN
14
13
  },
@@ -66,12 +65,7 @@ const defaultConfig = {
66
65
  }
67
66
  };
68
67
 
69
- const withPzConfig = (
70
- myNextConfig = {},
71
- options = {
72
- useCacheHandler: false
73
- }
74
- ) => {
68
+ const withPzConfig = (myNextConfig = {}) => {
75
69
  let extendedConfig = deepMerge({}, defaultConfig, myNextConfig);
76
70
 
77
71
  const originalPzHeadersFunction = defaultConfig.headers;
@@ -97,10 +91,6 @@ const withPzConfig = (
97
91
  return [...pzRewrites, ...myRewrites];
98
92
  };
99
93
 
100
- if (options.useCacheHandler) {
101
- extendedConfig.cacheHandler = require.resolve('./lib/cache-handler.mjs');
102
- }
103
-
104
94
  return extendedConfig;
105
95
  };
106
96
 
@@ -1,27 +0,0 @@
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
- }
@@ -1,21 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const hashDirectory = require('../utils/hash-directory');
4
- const checkMonorepo = require('../utils/check-monorepo');
5
-
6
- const BASE_DIR = checkMonorepo();
7
-
8
- if (!BASE_DIR) {
9
- process.exit(0);
10
- }
11
-
12
- const packageDistPath = path.join(
13
- __dirname,
14
- '../../../packages/projectzero-cli/dist/commands'
15
- );
16
-
17
- const hash = hashDirectory(packageDistPath);
18
- fs.writeFileSync(
19
- path.join(__dirname, '../../../packages/projectzero-cli/dist/dist-hash.txt'),
20
- hash
21
- );
@@ -1,33 +0,0 @@
1
- import { CacheHandler } from '@neshca/cache-handler';
2
- import createLruHandler from '@neshca/cache-handler/local-lru';
3
- import createRedisHandler from '@neshca/cache-handler/redis-stack';
4
- import { createClient } from 'redis';
5
-
6
- CacheHandler.onCreation(async () => {
7
- const redisUrl = `redis://${process.env.CACHE_HOST}:${
8
- process.env.CACHE_PORT
9
- }/${process.env.CACHE_BUCKET ?? '0'}`;
10
-
11
- const client = createClient({
12
- url: redisUrl
13
- });
14
-
15
- client.on('error', (error) => {
16
- console.error('Redis client error', { redisUrl, error });
17
- });
18
-
19
- await client.connect();
20
-
21
- const redisHandler = await createRedisHandler({
22
- client,
23
- timeoutMs: 5000
24
- });
25
-
26
- const localHandler = createLruHandler();
27
-
28
- return {
29
- handlers: [redisHandler, localHandler]
30
- };
31
- });
32
-
33
- export default CacheHandler;
@@ -1,194 +0,0 @@
1
- import { URLS } from '@akinon/next/data/urls';
2
- import { Metadata, PageProps } from '@akinon/next/types';
3
- import logger from '@akinon/next/utils/log';
4
- import { notFound } from 'next/navigation';
5
-
6
- type PrettyUrlResult = {
7
- matched: boolean;
8
- path?: string;
9
- pk?: number;
10
- };
11
-
12
- const resolvePrettyUrlHandler =
13
- (pathname: string, ip: string | null) => async () => {
14
- let results = [] as { old_path: string }[];
15
- let prettyUrlResult: PrettyUrlResult = {
16
- matched: false
17
- };
18
-
19
- try {
20
- const requestUrl = URLS.misc.prettyUrls(`/${pathname}/`);
21
-
22
- logger.debug(`Resolving pretty url`, { pathname, requestUrl, ip });
23
-
24
- const start = Date.now();
25
- const apiResponse = await fetch(requestUrl, {
26
- next: {
27
- revalidate: 0
28
- }
29
- });
30
- const data = await apiResponse.json();
31
- ({ results } = data);
32
- const end = Date.now();
33
- console.warn('Pretty url response time', end - start, requestUrl);
34
-
35
- const matched = results.length > 0;
36
- const [{ old_path: path } = { old_path: '' }] = results;
37
- let pk;
38
-
39
- if (matched) {
40
- const pkRegex = /\/(\d+)\/$/;
41
- const match = path.match(pkRegex);
42
- pk = match ? parseInt(match[1]) : undefined;
43
- }
44
-
45
- prettyUrlResult = {
46
- matched,
47
- path,
48
- pk
49
- };
50
-
51
- logger.trace('Pretty url result', { prettyUrlResult, ip });
52
- } catch (error) {
53
- logger.error('Error resolving pretty url', { error, pathname, ip });
54
- }
55
-
56
- return prettyUrlResult;
57
- };
58
-
59
- export async function generateMetadata({ params }: PageProps) {
60
- let result: Metadata = {};
61
- const { prettyurl } = params;
62
- const pageSlug = prettyurl
63
- .filter((x) => !x.startsWith('searchparams'))
64
- .join('/');
65
-
66
- const searchParams = Object.fromEntries(
67
- new URLSearchParams(
68
- decodeURIComponent(
69
- prettyurl
70
- .find((x) => x.startsWith('searchparams'))
71
- ?.replace('searchparams%7C', '')
72
- ) ?? {}
73
- ).entries()
74
- );
75
-
76
- const prettyUrlResult = await resolvePrettyUrlHandler(pageSlug, null)();
77
-
78
- if (!prettyUrlResult.matched) {
79
- return notFound();
80
- }
81
-
82
- const commonProps = {
83
- params: {
84
- ...params,
85
- pk: prettyUrlResult.pk
86
- },
87
- searchParams
88
- };
89
-
90
- try {
91
- if (prettyUrlResult.path.startsWith('/product/')) {
92
- await import('@product/[pk]/page').then(async (module) => {
93
- result = await module['generateMetadata']?.(commonProps);
94
- });
95
- }
96
-
97
- if (prettyUrlResult.path.startsWith('/group-product/')) {
98
- await import('@group-product/[pk]/page').then(async (module) => {
99
- result = await module['generateMetadata']?.(commonProps);
100
- });
101
- }
102
-
103
- if (prettyUrlResult.path.startsWith('/category/')) {
104
- await import('@category/[pk]/page').then(async (module) => {
105
- result = await module['generateMetadata']?.(commonProps);
106
- });
107
- }
108
-
109
- if (prettyUrlResult.path.startsWith('/special-page/')) {
110
- await import('@special-page/[pk]/page').then(async (module) => {
111
- result = await module['generateMetadata']?.(commonProps);
112
- });
113
- }
114
-
115
- if (prettyUrlResult.path.startsWith('/flat-page/')) {
116
- await import('@flat-page/[pk]/page').then(async (module) => {
117
- result = await module['generateMetadata']?.(commonProps);
118
- });
119
- }
120
- // eslint-disable-next-line no-empty
121
- } catch (error) {}
122
-
123
- return result;
124
- }
125
-
126
- export const dynamic = 'force-static';
127
- export const revalidate = 300;
128
-
129
- export default async function Page({ params }) {
130
- const { prettyurl } = params;
131
- const pageSlug = prettyurl
132
- .filter((x) => !x.startsWith('searchparams'))
133
- .join('/');
134
-
135
- const urlSearchParams = new URLSearchParams(
136
- decodeURIComponent(
137
- prettyurl
138
- .find((x) => x.startsWith('searchparams'))
139
- ?.replace('searchparams%7C', '')
140
- ) ?? {}
141
- );
142
-
143
- const searchParams = {};
144
-
145
- for (const [key, value] of urlSearchParams.entries() as unknown as Array<
146
- [string, string]
147
- >) {
148
- if (!searchParams[key]) {
149
- searchParams[key] = [];
150
- }
151
- searchParams[key].push(value);
152
- }
153
-
154
- const result = await resolvePrettyUrlHandler(pageSlug, null)();
155
-
156
- if (!result.matched) {
157
- return notFound();
158
- }
159
-
160
- const commonProps = {
161
- params: {
162
- ...params,
163
- pk: result.pk
164
- },
165
- searchParams
166
- };
167
-
168
- if (result.path.startsWith('/category/')) {
169
- const CategoryPage = (await import('@category/[pk]/page')).default;
170
- return <CategoryPage {...commonProps} />;
171
- }
172
-
173
- if (result.path.startsWith('/product/')) {
174
- const ProductPage = (await import('@product/[pk]/page')).default;
175
- return <ProductPage {...commonProps} />;
176
- }
177
-
178
- if (result.path.startsWith('/group-product/')) {
179
- const GroupProduct = (await import('@group-product/[pk]/page')).default;
180
- return <GroupProduct {...commonProps} />;
181
- }
182
-
183
- if (result.path.startsWith('/special-page/')) {
184
- const SpecialPage = (await import('@special-page/[pk]/page')).default;
185
- return <SpecialPage {...commonProps} />;
186
- }
187
-
188
- if (result.path.startsWith('/flat-page/')) {
189
- const FlatPage = (await import('@flat-page/[pk]/page')).default;
190
- return <FlatPage {...commonProps} />;
191
- }
192
-
193
- return null;
194
- }
@@ -1,15 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- function checkMonorepo() {
5
- let currentDir = __dirname;
6
- while (currentDir !== path.resolve(currentDir, '..')) {
7
- if (fs.existsSync(path.join(currentDir, 'turbo.json'))) {
8
- return currentDir;
9
- }
10
- currentDir = path.resolve(currentDir, '..');
11
- }
12
- return null;
13
- }
14
-
15
- module.exports = checkMonorepo;
@@ -1,13 +0,0 @@
1
- const path = require('path');
2
-
3
- function findBaseDir() {
4
- const insideNodeModules = __dirname.includes('node_modules');
5
-
6
- if (insideNodeModules) {
7
- return path.resolve(__dirname, '../../../../');
8
- } else {
9
- return path.resolve(__dirname, '../../../apps/projectzeronext');
10
- }
11
- }
12
-
13
- module.exports = findBaseDir;
@@ -1,27 +0,0 @@
1
- export default function formatCookieString(cookieObj: Record<string, any>) {
2
- const cookieParts = [`${cookieObj.name}=${cookieObj.value}`];
3
-
4
- if (cookieObj.expires) {
5
- cookieParts.push(`Expires=${cookieObj.expires.toUTCString()}`);
6
- }
7
- if (cookieObj.maxAge) {
8
- cookieParts.push(`Max-Age=${cookieObj.maxAge}`);
9
- }
10
- if (cookieObj.path) {
11
- cookieParts.push(`Path=${cookieObj.path}`);
12
- }
13
- if (cookieObj.domain) {
14
- cookieParts.push(`Domain=${cookieObj.domain}`);
15
- }
16
- if (cookieObj.secure) {
17
- cookieParts.push('Secure');
18
- }
19
- if (cookieObj.httpOnly) {
20
- cookieParts.push('HttpOnly');
21
- }
22
- if (cookieObj.sameSite) {
23
- cookieParts.push(`SameSite=${cookieObj.sameSite}`);
24
- }
25
-
26
- return cookieParts.join('; ');
27
- }
@@ -1,18 +0,0 @@
1
- const { createHash } = require('crypto');
2
- const fs = require('fs');
3
- const path = require('path');
4
-
5
- function hashDirectory(directory) {
6
- const files = fs.readdirSync(directory).sort();
7
- const hash = createHash('sha256');
8
- files.forEach((file) => {
9
- const filePath = path.join(directory, file);
10
- if (fs.statSync(filePath).isFile()) {
11
- const fileBuffer = fs.readFileSync(filePath);
12
- hash.update(fileBuffer);
13
- }
14
- });
15
- return hash.digest('hex');
16
- }
17
-
18
- module.exports = hashDirectory;