@akinon/next 1.93.0-rc.49 → 1.93.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +36 -1260
  2. package/__tests__/next-config.test.ts +10 -1
  3. package/bin/pz-prebuild.js +1 -0
  4. package/components/accordion.tsx +5 -20
  5. package/components/file-input.tsx +3 -65
  6. package/components/input.tsx +0 -2
  7. package/components/link.tsx +12 -16
  8. package/components/modal.tsx +16 -32
  9. package/components/plugin-module.tsx +3 -35
  10. package/components/selected-payment-option-view.tsx +0 -11
  11. package/data/client/checkout.ts +4 -25
  12. package/data/server/category.ts +28 -48
  13. package/data/server/flatpage.ts +12 -16
  14. package/data/server/landingpage.ts +12 -16
  15. package/data/server/list.ts +13 -23
  16. package/data/server/product.ts +39 -66
  17. package/data/server/special-page.ts +12 -16
  18. package/data/urls.ts +2 -7
  19. package/hocs/server/with-segment-defaults.tsx +2 -5
  20. package/hooks/use-localization.ts +3 -2
  21. package/instrumentation/node.ts +13 -15
  22. package/jest.config.js +1 -7
  23. package/lib/cache.ts +0 -2
  24. package/middlewares/checkout-provider.ts +1 -1
  25. package/middlewares/complete-gpay.ts +2 -6
  26. package/middlewares/complete-masterpass.ts +2 -7
  27. package/middlewares/default.ts +183 -232
  28. package/middlewares/index.ts +1 -3
  29. package/middlewares/locale.ts +1 -9
  30. package/middlewares/redirection-payment.ts +2 -6
  31. package/middlewares/saved-card-redirection.ts +2 -7
  32. package/middlewares/three-d-redirection.ts +2 -7
  33. package/middlewares/url-redirection.ts +15 -9
  34. package/package.json +3 -3
  35. package/plugins.d.ts +0 -10
  36. package/plugins.js +1 -4
  37. package/redux/middlewares/checkout.ts +2 -15
  38. package/redux/reducers/checkout.ts +1 -9
  39. package/sentry/index.ts +17 -54
  40. package/types/commerce/order.ts +0 -1
  41. package/types/index.ts +1 -42
  42. package/utils/app-fetch.ts +2 -7
  43. package/utils/index.ts +10 -34
  44. package/utils/redirect.ts +6 -31
  45. package/with-pz-config.js +5 -1
  46. package/__tests__/redirect.test.ts +0 -758
  47. package/api/image-proxy.ts +0 -75
  48. package/api/similar-product-list.ts +0 -84
  49. package/api/similar-products.ts +0 -120
  50. package/data/server/basket.ts +0 -72
  51. package/hooks/use-loyalty-availability.ts +0 -21
  52. package/middlewares/wallet-complete-redirection.ts +0 -203
  53. package/utils/redirect-ignore.ts +0 -35
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.93.0-rc.49",
4
+ "version": "1.93.0",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -17,13 +17,13 @@
17
17
  "test": "jest"
18
18
  },
19
19
  "dependencies": {
20
+ "@neshca/cache-handler": "1.5.1",
20
21
  "@opentelemetry/exporter-trace-otlp-http": "0.46.0",
21
22
  "@opentelemetry/resources": "1.19.0",
22
23
  "@opentelemetry/sdk-node": "0.46.0",
23
24
  "@opentelemetry/sdk-trace-node": "1.19.0",
24
25
  "@opentelemetry/semantic-conventions": "1.19.0",
25
26
  "@reduxjs/toolkit": "1.9.7",
26
- "@neshca/cache-handler": "1.9.0",
27
27
  "@sentry/nextjs": "9.5.0",
28
28
  "cross-spawn": "7.0.3",
29
29
  "generic-pool": "3.9.0",
@@ -34,7 +34,7 @@
34
34
  "set-cookie-parser": "2.6.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@akinon/eslint-plugin-projectzero": "1.93.0-rc.49",
37
+ "@akinon/eslint-plugin-projectzero": "1.93.0",
38
38
  "@babel/core": "7.26.10",
39
39
  "@babel/preset-env": "7.26.9",
40
40
  "@babel/preset-typescript": "7.27.0",
package/plugins.d.ts CHANGED
@@ -36,13 +36,3 @@ declare module '@akinon/pz-iyzico-saved-card' {
36
36
  }
37
37
 
38
38
  declare module '@akinon/pz-apple-pay' {}
39
-
40
- declare module '@akinon/pz-flow-payment' {}
41
-
42
- declare module '@akinon/pz-similar-products' {
43
- export const SimilarProductsModal: any;
44
- export const SimilarProductsFilterSidebar: any;
45
- export const SimilarProductsResultsGrid: any;
46
- export const SimilarProductsPlugin: any;
47
- export const SimilarProductsButtonPlugin: any;
48
- }
package/plugins.js CHANGED
@@ -15,8 +15,5 @@ module.exports = [
15
15
  'pz-saved-card',
16
16
  'pz-tabby-extension',
17
17
  'pz-apple-pay',
18
- 'pz-tamara-extension',
19
- 'pz-hepsipay',
20
- 'pz-flow-payment',
21
- 'pz-similar-products'
18
+ 'pz-tamara-extension'
22
19
  ];
@@ -20,8 +20,7 @@ import {
20
20
  setShippingOptions,
21
21
  setHepsipayAvailability,
22
22
  setWalletPaymentData,
23
- setPayOnDeliveryOtpModalActive,
24
- setUnavailablePaymentOptions
23
+ setPayOnDeliveryOtpModalActive
25
24
  } from '../../redux/reducers/checkout';
26
25
  import { RootState, TypedDispatch } from 'redux/store';
27
26
  import { checkoutApi } from '../../data/client/checkout';
@@ -51,11 +50,7 @@ export const errorMiddleware: Middleware = ({ dispatch }: MiddlewareParams) => {
51
50
  const result: CheckoutResult = next(action);
52
51
  const errors = result?.payload?.errors;
53
52
 
54
- if (
55
- !!errors &&
56
- ((typeof errors === 'object' && Object.keys(errors).length > 0) ||
57
- (Array.isArray(errors) && errors.length > 0))
58
- ) {
53
+ if (errors) {
59
54
  dispatch(setErrors(errors));
60
55
  }
61
56
 
@@ -181,14 +176,6 @@ export const contextListMiddleware: Middleware = ({
181
176
  dispatch(setPaymentOptions(context.page_context.payment_options));
182
177
  }
183
178
 
184
- if (context.page_context.unavailable_options) {
185
- dispatch(
186
- setUnavailablePaymentOptions(
187
- context.page_context.unavailable_options
188
- )
189
- );
190
- }
191
-
192
179
  if (context.page_context.credit_payment_options) {
193
180
  dispatch(
194
181
  setCreditPaymentOptions(context.page_context.credit_payment_options)
@@ -40,7 +40,6 @@ export interface CheckoutState {
40
40
  shippingOptions: ShippingOption[];
41
41
  dataSourceShippingOptions: DataSource[];
42
42
  paymentOptions: PaymentOption[];
43
- unavailablePaymentOptions: PaymentOption[];
44
43
  creditPaymentOptions: CheckoutCreditPaymentOption[];
45
44
  selectedCreditPaymentPk: number;
46
45
  paymentChoices: PaymentChoice[];
@@ -61,8 +60,6 @@ export interface CheckoutState {
61
60
  countryCode: string;
62
61
  currencyCode: string;
63
62
  version: string;
64
- public_key: string;
65
- [key: string]: any;
66
63
  };
67
64
  detail: {
68
65
  label: string;
@@ -97,7 +94,6 @@ const initialState: CheckoutState = {
97
94
  shippingOptions: [],
98
95
  dataSourceShippingOptions: [],
99
96
  paymentOptions: [],
100
- unavailablePaymentOptions: [],
101
97
  creditPaymentOptions: [],
102
98
  selectedCreditPaymentPk: null,
103
99
  paymentChoices: [],
@@ -161,9 +157,6 @@ const checkoutSlice = createSlice({
161
157
  setPaymentOptions(state, { payload }) {
162
158
  state.paymentOptions = payload;
163
159
  },
164
- setUnavailablePaymentOptions(state, { payload }) {
165
- state.unavailablePaymentOptions = payload;
166
- },
167
160
  setPaymentChoices(state, { payload }) {
168
161
  state.paymentChoices = payload;
169
162
  },
@@ -225,10 +218,9 @@ export const {
225
218
  setShippingOptions,
226
219
  setDataSourceShippingOptions,
227
220
  setPaymentOptions,
228
- setUnavailablePaymentOptions,
229
- setPaymentChoices,
230
221
  setCreditPaymentOptions,
231
222
  setSelectedCreditPaymentPk,
223
+ setPaymentChoices,
232
224
  setCardType,
233
225
  setInstallmentOptions,
234
226
  setBankAccounts,
package/sentry/index.ts CHANGED
@@ -13,73 +13,36 @@ const ALLOWED_CLIENT_LOG_TYPES: ClientLogType[] = [
13
13
  ClientLogType.CHECKOUT
14
14
  ];
15
15
 
16
- const isNetworkError = (exception: unknown): boolean => {
17
- if (!(exception instanceof Error)) return false;
18
-
19
- const networkErrorPatterns = [
20
- 'networkerror',
21
- 'failed to fetch',
22
- 'network request failed',
23
- 'network error',
24
- 'loading chunk',
25
- 'chunk load failed'
26
- ];
27
-
28
- if (exception.name === 'NetworkError') return true;
29
-
30
- if (exception.name === 'TypeError') {
31
- return networkErrorPatterns.some((pattern) =>
32
- exception.message.toLowerCase().includes(pattern)
33
- );
34
- }
35
-
36
- return networkErrorPatterns.some((pattern) =>
37
- exception.message.toLowerCase().includes(pattern)
38
- );
39
- };
40
-
41
16
  export const initSentry = (
42
17
  type: 'Server' | 'Client' | 'Edge',
43
18
  options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {}
44
19
  ) => {
45
- // TODO: Remove Zero Project DSN
20
+ // TODO: Handle options with ESLint rules
46
21
 
47
- const baseConfig = {
22
+ Sentry.init({
48
23
  dsn:
49
- SENTRY_DSN ||
50
24
  options.dsn ||
25
+ SENTRY_DSN ||
51
26
  'https://d8558ef8997543deacf376c7d8d7cf4b@o64293.ingest.sentry.io/4504338423742464',
52
27
  initialScope: {
53
28
  tags: {
54
29
  APP_TYPE: 'ProjectZeroNext',
55
- TYPE: type,
56
- ...((options.initialScope as any)?.tags || {})
30
+ TYPE: type
57
31
  }
58
32
  },
59
33
  tracesSampleRate: 0,
60
- integrations: []
61
- };
62
-
63
- if (type === 'Server' || type === 'Edge') {
64
- Sentry.init(baseConfig);
65
- } else if (type === 'Client') {
66
- Sentry.init({
67
- ...baseConfig,
68
- beforeSend: (event, hint) => {
69
- if (
70
- !ALLOWED_CLIENT_LOG_TYPES.includes(
71
- event.tags?.LOG_TYPE as ClientLogType
72
- )
73
- ) {
74
- return null;
75
- }
76
-
77
- if (isNetworkError(hint?.originalException)) {
78
- return null;
79
- }
80
-
81
- return event;
34
+ integrations: [],
35
+ beforeSend: (event, hint) => {
36
+ if (
37
+ type === 'Client' &&
38
+ !ALLOWED_CLIENT_LOG_TYPES.includes(
39
+ event.tags?.LOG_TYPE as ClientLogType
40
+ )
41
+ ) {
42
+ return null;
82
43
  }
83
- });
84
- }
44
+
45
+ return event;
46
+ }
47
+ });
85
48
  };
@@ -114,7 +114,6 @@ export interface Order {
114
114
  pk: number;
115
115
  name: string;
116
116
  slug: string;
117
- logo: string;
118
117
  [key: string]: any;
119
118
  };
120
119
  }
package/types/index.ts CHANGED
@@ -83,12 +83,6 @@ export interface Settings {
83
83
  };
84
84
  usePrettyUrlRoute?: boolean;
85
85
  commerceUrl: string;
86
- /**
87
- * This option allows you to track Sentry events on the client side, in addition to server and edge environments.
88
- *
89
- * It overrides process.env.NEXT_PUBLIC_SENTRY_DSN and process.env.SENTRY_DSN.
90
- */
91
- sentryDsn?: string;
92
86
  redis: {
93
87
  defaultExpirationTime: number;
94
88
  };
@@ -224,14 +218,6 @@ export interface CacheOptions {
224
218
  useProxy?: boolean;
225
219
  }
226
220
 
227
- export interface SetCookieOptions {
228
- expires?: number; // days
229
- path?: string;
230
- domain?: string;
231
- secure?: boolean;
232
- sameSite?: 'strict' | 'lax' | 'none';
233
- }
234
-
235
221
  export interface ClientRequestOptions {
236
222
  useTrailingSlash?: boolean;
237
223
  useFormData?: boolean;
@@ -297,13 +283,7 @@ export interface ButtonProps
297
283
  target?: '_blank' | '_self' | '_parent' | '_top';
298
284
  }
299
285
 
300
- export interface FileInputProps extends React.HTMLProps<HTMLInputElement> {
301
- fileClassName?: string;
302
- fileNameWrapperClassName?: string;
303
- fileInputClassName?: string;
304
- onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
305
- buttonClassName?: string;
306
- }
286
+ export type FileInputProps = React.HTMLProps<HTMLInputElement>;
307
287
 
308
288
  export interface PriceProps {
309
289
  currencyCode?: string;
@@ -324,19 +304,15 @@ export interface InputProps extends React.HTMLProps<HTMLInputElement> {
324
304
 
325
305
  export interface AccordionProps {
326
306
  isCollapse?: boolean;
327
- collapseClassName?: string;
328
307
  title?: string;
329
308
  subTitle?: string;
330
309
  icons?: string[];
331
310
  iconSize?: number;
332
311
  iconColor?: string;
333
312
  children?: ReactNode;
334
- headerClassName?: string;
335
313
  className?: string;
336
314
  titleClassName?: string;
337
- subTitleClassName?: string;
338
315
  dataTestId?: string;
339
- contentClassName?: string;
340
316
  }
341
317
 
342
318
  export interface PluginModuleComponentProps {
@@ -361,20 +337,3 @@ export interface PaginationProps {
361
337
  direction?: 'next' | 'prev';
362
338
  isLoading?: boolean;
363
339
  }
364
-
365
- export interface ModalProps {
366
- portalId: string;
367
- children?: React.ReactNode;
368
- open?: boolean;
369
- setOpen?: (open: boolean) => void;
370
- title?: React.ReactNode;
371
- showCloseButton?: React.ReactNode;
372
- className?: string;
373
- overlayClassName?: string;
374
- headerWrapperClassName?: string;
375
- titleClassName?: string;
376
- closeButtonClassName?: string;
377
- iconName?: string;
378
- iconSize?: number;
379
- iconClassName?: string;
380
- }
@@ -43,12 +43,12 @@ const appFetch = async <T>({
43
43
  const requestURL = `${decodeURIComponent(commerceUrl)}${url}`;
44
44
 
45
45
  init.headers = {
46
- cookie: nextCookies.toString(),
47
46
  ...(init.headers ?? {}),
48
47
  ...(ServerVariables.globalHeaders ?? {}),
49
48
  'Accept-Language': currentLocale.apiValue,
50
49
  'x-currency': currency,
51
- 'x-forwarded-for': ip
50
+ 'x-forwarded-for': ip,
51
+ cookie: nextCookies.toString()
52
52
  };
53
53
 
54
54
  init.next = {
@@ -60,11 +60,6 @@ const appFetch = async <T>({
60
60
  status = req.status;
61
61
  logger.debug(`FETCH END ${url}`, { status: req.status, ip });
62
62
 
63
- if (!req.ok) {
64
- const errorMessage = `HTTP ${req.status}: ${req.statusText}`;
65
- throw new Error(errorMessage);
66
- }
67
-
68
63
  if (responseType === FetchResponseType.JSON) {
69
64
  response = (await req.json()) as T;
70
65
  } else {
package/utils/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import settings from 'settings';
2
2
  import { LocaleUrlStrategy } from '../localization';
3
- import { CDNOptions, ClientRequestOptions, SetCookieOptions } from '../types';
4
- import getRootHostname from './get-root-hostname';
3
+ import { CDNOptions, ClientRequestOptions } from '../types';
5
4
 
6
5
  export * from './get-currency';
7
6
  export * from './menu-generator';
@@ -21,40 +20,14 @@ export function getCookie(name: string) {
21
20
  }
22
21
  }
23
22
 
24
- export function setCookie(
25
- name: string,
26
- value: string,
27
- options: SetCookieOptions = {}
28
- ) {
29
- const cookieParts = [`${name}=${value}`];
30
-
31
- if (options.expires) {
32
- const date = new Date();
33
- date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1000);
34
- cookieParts.push(`expires=${date.toUTCString()}`);
35
- }
23
+ export function setCookie(name: string, val: string) {
24
+ const date = new Date();
25
+ const value = val;
36
26
 
37
- cookieParts.push(`path=${options.path ?? '/'}`);
27
+ date.setTime(date.getTime() + 7 * 24 * 60 * 60 * 1000);
38
28
 
39
- if (options.secure) {
40
- cookieParts.push('secure');
41
- }
42
-
43
- if (options.sameSite) {
44
- cookieParts.push(`sameSite=${options.sameSite}`);
45
- }
46
-
47
- const domain =
48
- options.domain ??
49
- (settings.localization.localeUrlStrategy === LocaleUrlStrategy.Subdomain
50
- ? getRootHostname(document.location.href)
51
- : null);
52
-
53
- if (domain) {
54
- cookieParts.push(`domain=${domain}`);
55
- }
56
-
57
- document.cookie = cookieParts.join('; ');
29
+ document.cookie =
30
+ name + '=' + value + '; expires=' + date.toUTCString() + '; path=/';
58
31
  }
59
32
 
60
33
  export function removeCookie(name: string) {
@@ -179,6 +152,9 @@ export function buildCDNUrl(url: string, config?: CDNOptions) {
179
152
  return `${rootWithoutOptions}${options}${fileExtension}`;
180
153
  }
181
154
 
155
+ const { locales, localeUrlStrategy, defaultLocaleValue } =
156
+ settings.localization;
157
+
182
158
  export const urlLocaleMatcherRegex = new RegExp(
183
159
  `^/(${settings.localization.locales
184
160
  .filter((l) =>
package/utils/redirect.ts CHANGED
@@ -1,48 +1,23 @@
1
1
  import { redirect as nextRedirect, RedirectType } from 'next/navigation';
2
2
  import Settings from 'settings';
3
- import { headers, cookies } from 'next/headers';
3
+ import { headers } from 'next/headers';
4
+ import { ServerVariables } from '@akinon/next/utils/server-variables';
4
5
  import { getUrlPathWithLocale } from '@akinon/next/utils/localization';
5
- import { urlLocaleMatcherRegex } from '@akinon/next/utils';
6
6
 
7
7
  export const redirect = (path: string, type?: RedirectType) => {
8
8
  const nextHeaders = headers();
9
- const nextCookies = cookies();
10
9
  const pageUrl = new URL(
11
- nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL ?? ''
10
+ nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL
12
11
  );
13
12
 
14
- let currentLocaleValue = Settings.localization.defaultLocaleValue;
15
- const urlLocaleMatch = pageUrl.pathname.match(urlLocaleMatcherRegex);
16
-
17
- if (urlLocaleMatch && urlLocaleMatch[0]) {
18
- currentLocaleValue = urlLocaleMatch[0].replace('/', '');
19
- } else {
20
- const cookieLocale = nextCookies.get('pz-locale')?.value;
21
- if (
22
- cookieLocale &&
23
- Settings.localization.locales.find((l) => l.value === cookieLocale)
24
- ) {
25
- currentLocaleValue = cookieLocale;
26
- }
27
- }
28
-
29
13
  const currentLocale = Settings.localization.locales.find(
30
- (locale) => locale.value === currentLocaleValue
14
+ (locale) => locale.value === ServerVariables.locale
31
15
  );
32
16
 
33
- if (!currentLocale) {
34
- currentLocaleValue = Settings.localization.defaultLocaleValue;
35
- }
36
-
37
- const searchParams = new URLSearchParams(pageUrl.search);
38
-
39
- const callbackUrl =
40
- pageUrl.pathname.replace(urlLocaleMatcherRegex, '') +
41
- (searchParams.toString() ? `?${searchParams.toString()}` : '');
42
-
17
+ const callbackUrl = pageUrl.pathname;
43
18
  const redirectUrlWithLocale = getUrlPathWithLocale(
44
19
  path,
45
- currentLocale?.value
20
+ currentLocale.localePath ?? currentLocale.value
46
21
  );
47
22
 
48
23
  const redirectUrl = `${redirectUrlWithLocale}?callbackUrl=${callbackUrl}`;
package/with-pz-config.js CHANGED
@@ -16,8 +16,12 @@ const defaultConfig = {
16
16
  remotePatterns: [
17
17
  {
18
18
  protocol: 'https',
19
- hostname: '**'
19
+ hostname: '**.akinoncloud.com'
20
20
  },
21
+ {
22
+ protocol: 'https',
23
+ hostname: '**.akinoncdn.com'
24
+ }
21
25
  ]
22
26
  },
23
27
  modularizeImports: {