@akinon/next 2.0.0-beta.9 → 2.0.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 (121) hide show
  1. package/CHANGELOG.md +434 -23
  2. package/__tests__/next-config.test.ts +83 -0
  3. package/__tests__/tsconfig.json +23 -0
  4. package/api/auth.ts +367 -63
  5. package/api/barcode-search.ts +59 -0
  6. package/api/cache.ts +41 -5
  7. package/api/client.ts +21 -4
  8. package/api/form.ts +85 -0
  9. package/api/image-proxy.ts +75 -0
  10. package/api/product-categories.ts +53 -0
  11. package/api/similar-product-list.ts +63 -0
  12. package/api/similar-products.ts +111 -0
  13. package/api/virtual-try-on.ts +382 -0
  14. package/assets/styles/index.scss +84 -0
  15. package/babel.config.js +6 -0
  16. package/bin/pz-generate-routes.js +115 -0
  17. package/bin/pz-install-plugins.js +1 -1
  18. package/bin/pz-prebuild.js +1 -0
  19. package/bin/pz-predev.js +1 -0
  20. package/bin/pz-run-tests.js +99 -0
  21. package/components/accordion.tsx +21 -6
  22. package/components/client-root.tsx +119 -3
  23. package/components/file-input.tsx +65 -3
  24. package/components/index.ts +1 -0
  25. package/components/input.tsx +2 -2
  26. package/components/link.tsx +46 -16
  27. package/components/logger-popup.tsx +213 -0
  28. package/components/modal.tsx +32 -16
  29. package/components/plugin-module.tsx +62 -3
  30. package/components/price.tsx +2 -2
  31. package/components/select.tsx +3 -3
  32. package/components/selected-payment-option-view.tsx +21 -0
  33. package/data/client/account.ts +17 -2
  34. package/data/client/basket.ts +39 -0
  35. package/data/client/checkout.ts +336 -99
  36. package/data/client/misc.ts +13 -1
  37. package/data/server/category.ts +11 -9
  38. package/data/server/flatpage.ts +4 -1
  39. package/data/server/form.ts +4 -1
  40. package/data/server/landingpage.ts +4 -1
  41. package/data/server/list.ts +5 -4
  42. package/data/server/menu.ts +4 -1
  43. package/data/server/product.ts +97 -52
  44. package/data/server/seo.ts +4 -1
  45. package/data/server/special-page.ts +5 -4
  46. package/data/server/widget.ts +71 -1
  47. package/data/urls.ts +6 -3
  48. package/hocs/client/with-segment-defaults.tsx +2 -2
  49. package/hocs/server/with-segment-defaults.tsx +81 -20
  50. package/hooks/index.ts +3 -0
  51. package/hooks/use-localization.ts +24 -10
  52. package/hooks/use-logger-context.tsx +114 -0
  53. package/hooks/use-logger.ts +92 -0
  54. package/hooks/use-loyalty-availability.ts +21 -0
  55. package/hooks/use-payment-options.ts +2 -1
  56. package/hooks/use-pz-params.ts +37 -0
  57. package/hooks/use-router.ts +53 -19
  58. package/instrumentation/index.ts +0 -1
  59. package/instrumentation/node.ts +2 -20
  60. package/jest.config.js +25 -0
  61. package/lib/cache-handler.mjs +534 -16
  62. package/lib/cache.ts +269 -34
  63. package/localization/provider.tsx +2 -5
  64. package/middlewares/bfcache-headers.ts +18 -0
  65. package/middlewares/checkout-provider.ts +1 -1
  66. package/middlewares/complete-gpay.ts +32 -26
  67. package/middlewares/complete-masterpass.ts +33 -26
  68. package/middlewares/complete-wallet.ts +182 -0
  69. package/middlewares/default.ts +357 -203
  70. package/middlewares/index.ts +10 -2
  71. package/middlewares/locale.ts +5 -3
  72. package/middlewares/masterpass-rest-callback.ts +230 -0
  73. package/middlewares/oauth-login.ts +200 -57
  74. package/middlewares/pretty-url.ts +21 -8
  75. package/middlewares/redirection-payment.ts +32 -26
  76. package/middlewares/saved-card-redirection.ts +33 -26
  77. package/middlewares/three-d-redirection.ts +32 -26
  78. package/middlewares/url-redirection.ts +9 -15
  79. package/middlewares/wallet-complete-redirection.ts +206 -0
  80. package/package.json +24 -10
  81. package/plugins.d.ts +19 -4
  82. package/plugins.js +9 -1
  83. package/redux/actions.ts +47 -0
  84. package/redux/middlewares/checkout.ts +61 -8
  85. package/redux/middlewares/index.ts +14 -10
  86. package/redux/middlewares/pre-order/address.ts +1 -1
  87. package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +1 -1
  88. package/redux/middlewares/pre-order/data-source-shipping-option.ts +1 -1
  89. package/redux/middlewares/pre-order/delivery-option.ts +1 -1
  90. package/redux/middlewares/pre-order/index.ts +3 -1
  91. package/redux/middlewares/pre-order/installment-option.ts +2 -1
  92. package/redux/middlewares/pre-order/payment-option-reset.ts +37 -0
  93. package/redux/middlewares/pre-order/payment-option.ts +1 -1
  94. package/redux/middlewares/pre-order/pre-order-validation.ts +4 -3
  95. package/redux/middlewares/pre-order/redirection.ts +2 -2
  96. package/redux/middlewares/pre-order/set-pre-order.ts +2 -2
  97. package/redux/middlewares/pre-order/shipping-option.ts +1 -1
  98. package/redux/middlewares/pre-order/shipping-step.ts +1 -1
  99. package/redux/reducers/checkout.ts +15 -1
  100. package/redux/reducers/index.ts +7 -1
  101. package/redux/reducers/widget.ts +80 -0
  102. package/sentry/index.ts +54 -17
  103. package/tailwind/content.js +16 -0
  104. package/types/commerce/checkout.ts +26 -1
  105. package/types/commerce/widget.ts +33 -0
  106. package/types/index.ts +114 -5
  107. package/types/next-auth.d.ts +2 -2
  108. package/types/widget.ts +80 -0
  109. package/utils/app-fetch.ts +7 -2
  110. package/utils/generate-commerce-search-params.ts +3 -2
  111. package/utils/get-checkout-path.ts +3 -0
  112. package/utils/get-root-hostname.ts +28 -0
  113. package/utils/index.ts +69 -18
  114. package/utils/mobile-3d-iframe.ts +8 -2
  115. package/utils/override-middleware.ts +1 -0
  116. package/utils/pz-segments.ts +92 -0
  117. package/utils/redirect-ignore.ts +35 -0
  118. package/utils/redirect.ts +9 -3
  119. package/utils/redirection-iframe.ts +8 -2
  120. package/utils/widget-styles.ts +107 -0
  121. package/with-pz-config.js +20 -7
package/utils/index.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  import settings from 'settings';
2
2
  import { LocaleUrlStrategy } from '../localization';
3
- import { CDNOptions, ClientRequestOptions, Locale } from '../types';
3
+ import { CDNOptions, ClientRequestOptions, SetCookieOptions } from '../types';
4
+ import getRootHostname from './get-root-hostname';
4
5
 
5
6
  export * from './get-currency';
6
7
  export * from './menu-generator';
7
8
  export * from './generate-commerce-search-params';
8
9
  export * from './get-currency-label';
10
+ export * from './pz-segments';
11
+ export * from './get-checkout-path';
9
12
 
10
13
  export function getCookie(name: string) {
11
14
  if (typeof document === 'undefined') {
@@ -20,14 +23,40 @@ export function getCookie(name: string) {
20
23
  }
21
24
  }
22
25
 
23
- export function setCookie(name: string, val: string) {
24
- const date = new Date();
25
- const value = val;
26
+ export function setCookie(
27
+ name: string,
28
+ value: string,
29
+ options: SetCookieOptions = {}
30
+ ) {
31
+ const cookieParts = [`${name}=${value}`];
32
+
33
+ if (options.expires) {
34
+ const date = new Date();
35
+ date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1000);
36
+ cookieParts.push(`expires=${date.toUTCString()}`);
37
+ }
26
38
 
27
- date.setTime(date.getTime() + 7 * 24 * 60 * 60 * 1000);
39
+ cookieParts.push(`path=${options.path ?? '/'}`);
40
+
41
+ if (options.secure) {
42
+ cookieParts.push('secure');
43
+ }
28
44
 
29
- document.cookie =
30
- name + '=' + value + '; expires=' + date.toUTCString() + '; path=/';
45
+ if (options.sameSite) {
46
+ cookieParts.push(`sameSite=${options.sameSite}`);
47
+ }
48
+
49
+ const domain =
50
+ options.domain ??
51
+ (settings.localization.localeUrlStrategy === LocaleUrlStrategy.Subdomain
52
+ ? getRootHostname(document.location.href)
53
+ : null);
54
+
55
+ if (domain) {
56
+ cookieParts.push(`domain=${domain}`);
57
+ }
58
+
59
+ document.cookie = cookieParts.join('; ');
31
60
  }
32
61
 
33
62
  export function removeCookie(name: string) {
@@ -152,23 +181,28 @@ export function buildCDNUrl(url: string, config?: CDNOptions) {
152
181
  return `${rootWithoutOptions}${options}${fileExtension}`;
153
182
  }
154
183
 
155
- const { locales, localeUrlStrategy, defaultLocaleValue } =
156
- settings.localization;
157
-
158
- const isLocaleExcluded = (locale: Locale) =>
159
- ![LocaleUrlStrategy.ShowAllLocales, LocaleUrlStrategy.Subdomain].includes(
160
- localeUrlStrategy
161
- ) && locale.value !== defaultLocaleValue;
162
-
163
184
  export const urlLocaleMatcherRegex = new RegExp(
164
- `^/(${locales
165
- .filter((l) => !isLocaleExcluded(l))
185
+ `^/(${settings.localization.locales
186
+ .filter((l) =>
187
+ ![LocaleUrlStrategy.ShowAllLocales, LocaleUrlStrategy.Subdomain].includes(
188
+ settings.localization.localeUrlStrategy
189
+ )
190
+ ? l.value !== settings.localization.defaultLocaleValue
191
+ : l
192
+ )
166
193
  .map((l) => l.value)
167
194
  .join('|')})(?=/|$)`
168
195
  );
169
196
 
170
197
  export const getPosError = () => {
171
- const error = JSON.parse(getCookie('pz-pos-error') ?? '{}');
198
+ const cookieValue = getCookie('pz-pos-error');
199
+ let decoded: string;
200
+ try {
201
+ decoded = cookieValue ? decodeURIComponent(cookieValue) : '{}';
202
+ } catch {
203
+ decoded = cookieValue ?? '{}';
204
+ }
205
+ const error = JSON.parse(decoded);
172
206
 
173
207
  // delete 'pz-pos-error' cookie when refreshing or closing page
174
208
  window.addEventListener('beforeunload', () => {
@@ -178,6 +212,23 @@ export const getPosError = () => {
178
212
  return error;
179
213
  };
180
214
 
215
+ export const checkPaymentWillRedirect = (response: {
216
+ context_list?: Array<{
217
+ page_name: string;
218
+ page_context?: { context_data?: { redirect_url?: string } };
219
+ }>;
220
+ redirect_url?: string;
221
+ errors?: unknown;
222
+ }): boolean => {
223
+ if (!response) return false;
224
+
225
+ const hasThankYouPage = response.context_list?.some(
226
+ (c) => c.page_name === 'ThankYouPage'
227
+ );
228
+
229
+ return Boolean(hasThankYouPage || response.redirect_url);
230
+ };
231
+
181
232
  export const urlSchemes = [
182
233
  'http',
183
234
  'tel:',
@@ -1,8 +1,14 @@
1
1
  const iframeURLChange = (iframe, callback) => {
2
2
  iframe.addEventListener('load', () => {
3
3
  setTimeout(() => {
4
- if (iframe?.contentWindow?.location) {
5
- callback(iframe.contentWindow.location);
4
+ try {
5
+ if (iframe?.contentWindow?.location) {
6
+ const iframeLocation = iframe.contentWindow.location;
7
+
8
+ callback(iframeLocation);
9
+ }
10
+ } catch (error) {
11
+ // Expected: browser blocks cross-origin iframe access for security
6
12
  }
7
13
  }, 0);
8
14
  });
@@ -10,6 +10,7 @@ export enum MiddlewareNames {
10
10
  DataSourceShippingOptionMiddleware = 'dataSourceShippingOptionMiddleware',
11
11
  AttributeBasedShippingOptionMiddleware = 'attributeBasedShippingOptionMiddleware',
12
12
  PaymentOptionMiddleware = 'paymentOptionMiddleware',
13
+ PaymentOptionResetMiddleware = 'paymentOptionResetMiddleware',
13
14
  InstallmentOptionMiddleware = 'installmentOptionMiddleware',
14
15
  ShippingStepMiddleware = 'shippingStepMiddleware'
15
16
  }
@@ -0,0 +1,92 @@
1
+ import type { PzSegmentDefinition, PzSegmentsConfig } from '../types';
2
+
3
+ export function isLegacyMode(settings: any): boolean {
4
+ return !settings.usePzSegment;
5
+ }
6
+
7
+ const DEFAULT_SEPARATOR = '--';
8
+
9
+ const DEFAULT_SEGMENTS: PzSegmentDefinition[] = [
10
+ { name: 'locale' },
11
+ { name: 'currency' },
12
+ { name: 'url' }
13
+ ];
14
+
15
+ export function getPzSegmentsConfig(settings: any): PzSegmentsConfig {
16
+ if (settings.pzSegments) {
17
+ const customSegments = (settings.pzSegments.segments ?? []).filter(
18
+ (seg: PzSegmentDefinition) =>
19
+ !DEFAULT_SEGMENTS.some((d) => d.name === seg.name)
20
+ );
21
+
22
+ return {
23
+ separator: settings.pzSegments.separator ?? DEFAULT_SEPARATOR,
24
+ segments: [...DEFAULT_SEGMENTS, ...customSegments]
25
+ };
26
+ }
27
+
28
+ return {
29
+ separator: DEFAULT_SEPARATOR,
30
+ segments: DEFAULT_SEGMENTS
31
+ };
32
+ }
33
+
34
+ export function encodePzValue(
35
+ values: Record<string, string>,
36
+ config: PzSegmentsConfig
37
+ ): string {
38
+ return config.segments
39
+ .map((seg) => values[seg.name] ?? '')
40
+ .join(config.separator);
41
+ }
42
+
43
+ export function decodePzValue(
44
+ pzValue: string,
45
+ config: PzSegmentsConfig
46
+ ): Record<string, string> {
47
+ const parts = pzValue.split(config.separator);
48
+ const result: Record<string, string> = {};
49
+
50
+ config.segments.forEach((seg, index) => {
51
+ result[seg.name] = parts[index] ?? '';
52
+ });
53
+
54
+ return result;
55
+ }
56
+
57
+ export function getBuiltInSegments(
58
+ parsed: Record<string, string>,
59
+ settings: any
60
+ ): { locale: string; currency: string; url: string } {
61
+ const { defaultLocaleValue, defaultCurrencyCode } = settings.localization;
62
+
63
+ return {
64
+ locale: parsed.locale || defaultLocaleValue,
65
+ currency: parsed.currency || defaultCurrencyCode,
66
+ url: parsed.url ? decodeURIComponent(parsed.url) : ''
67
+ };
68
+ }
69
+
70
+ export function parsePzParams(
71
+ params: { pz?: string; locale?: string; currency?: string; url?: string },
72
+ settings: any
73
+ ): { locale: string; currency: string; url: string; [key: string]: string } {
74
+ if (isLegacyMode(settings)) {
75
+ return {
76
+ locale:
77
+ params.locale ?? settings.localization.defaultLocaleValue,
78
+ currency:
79
+ params.currency ?? settings.localization.defaultCurrencyCode,
80
+ url: params.url ? decodeURIComponent(params.url) : ''
81
+ };
82
+ }
83
+
84
+ const config = getPzSegmentsConfig(settings);
85
+ const parsed = decodePzValue(params.pz ?? '', config);
86
+ const builtIn = getBuiltInSegments(parsed, settings);
87
+
88
+ return {
89
+ ...parsed,
90
+ ...builtIn
91
+ };
92
+ }
@@ -0,0 +1,35 @@
1
+ import settings from 'settings';
2
+ import { getUrlPathWithLocale } from './localization';
3
+
4
+ type IgnorePath = string | RegExp;
5
+
6
+ const defaultIgnoreList: string[] = [];
7
+
8
+ const extraIgnores: IgnorePath[] = Array.isArray(
9
+ settings.commerceRedirectionIgnoreList
10
+ )
11
+ ? settings.commerceRedirectionIgnoreList.map((path) => {
12
+ if (path === '/users/reset') {
13
+ return /^\/users\/reset\/[^/]+\/[^/]+\/$/;
14
+ }
15
+ return path;
16
+ })
17
+ : [];
18
+
19
+ export function shouldIgnoreRedirect(
20
+ pathname: string,
21
+ locale: string
22
+ ): boolean {
23
+ if (!pathname) return false;
24
+
25
+ const rawIgnoreList: IgnorePath[] = [...defaultIgnoreList, ...extraIgnores];
26
+
27
+ return rawIgnoreList.some((ignorePath) => {
28
+ if (ignorePath instanceof RegExp) {
29
+ return ignorePath.test(pathname);
30
+ }
31
+
32
+ const localized = getUrlPathWithLocale(ignorePath, locale);
33
+ return localized === pathname;
34
+ });
35
+ }
package/utils/redirect.ts CHANGED
@@ -3,21 +3,27 @@ import Settings from 'settings';
3
3
  import { headers } from 'next/headers';
4
4
  import { ServerVariables } from '@akinon/next/utils/server-variables';
5
5
  import { getUrlPathWithLocale } from '@akinon/next/utils/localization';
6
+ import { urlLocaleMatcherRegex } from '@akinon/next/utils';
6
7
 
7
8
  export const redirect = async (path: string, type?: RedirectType) => {
8
9
  const nextHeaders = await headers();
9
10
  const pageUrl = new URL(
10
- nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL
11
+ nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL ?? ''
11
12
  );
12
13
 
13
14
  const currentLocale = Settings.localization.locales.find(
14
15
  (locale) => locale.value === ServerVariables.locale
15
16
  );
16
17
 
17
- const callbackUrl = pageUrl.pathname;
18
+ const searchParams = new URLSearchParams(pageUrl.search);
19
+
20
+ const callbackUrl =
21
+ pageUrl.pathname.replace(urlLocaleMatcherRegex, '') +
22
+ (searchParams.toString() ? `?${searchParams.toString()}` : '');
23
+
18
24
  const redirectUrlWithLocale = getUrlPathWithLocale(
19
25
  path,
20
- currentLocale.localePath ?? currentLocale.value
26
+ currentLocale?.value
21
27
  );
22
28
 
23
29
  const redirectUrl = `${redirectUrlWithLocale}?callbackUrl=${callbackUrl}`;
@@ -1,8 +1,14 @@
1
1
  const iframeURLChange = (iframe, callback) => {
2
2
  iframe.addEventListener('load', () => {
3
3
  setTimeout(() => {
4
- if (iframe?.contentWindow?.location) {
5
- callback(iframe.contentWindow.location);
4
+ try {
5
+ if (iframe?.contentWindow?.location) {
6
+ const iframeLocation = iframe.contentWindow.location;
7
+
8
+ callback(iframeLocation);
9
+ }
10
+ } catch (error) {
11
+ // Expected: browser blocks cross-origin iframe access for security
6
12
  }
7
13
  }, 0);
8
14
  });
@@ -0,0 +1,107 @@
1
+ const kebabize = (str: string) => {
2
+ return str.replace(
3
+ /[A-Z]+(?![a-z])|[A-Z]/g,
4
+ ($, ofs) => (ofs ? '-' : '') + $.toLowerCase()
5
+ );
6
+ };
7
+
8
+ const formatCssValue = (value: string | number) => {
9
+ return /^\d+$/.test(value.toString()) ? `${value}px` : value;
10
+ };
11
+
12
+ interface NodeProperties {
13
+ style?: Record<string, any>;
14
+ parent_id?: string;
15
+ type?: string;
16
+ tag?: string;
17
+ breakpoints?: any[];
18
+ dataSources?: any[];
19
+ is_slider?: boolean;
20
+ iteratingNode?: string;
21
+ iteratorValue?: string;
22
+ selectedDataSourceId?: string;
23
+ order?: number;
24
+ }
25
+
26
+ interface Node {
27
+ key: string;
28
+ properties: NodeProperties;
29
+ label?: string;
30
+ data_type?: string;
31
+ }
32
+
33
+ const processNode = (node: Node, selector = '', styles: string[] = []) => {
34
+ const { key, properties } = node;
35
+ const { style } = properties;
36
+
37
+ if (key && style) {
38
+ const baseStyles: Record<string, any> = {};
39
+ const breakpointStyles: Record<string, Record<string, any>> = {};
40
+
41
+ Object.entries(style).forEach(([prop, val]) => {
42
+ if (typeof val === 'object') {
43
+ breakpointStyles[prop] = val;
44
+ } else {
45
+ baseStyles[prop] = val;
46
+ }
47
+ });
48
+
49
+ const baseCssRules = Object.entries(baseStyles)
50
+ .map(([prop, val]) => `${kebabize(prop)}: ${formatCssValue(val)};`)
51
+ .join(' ');
52
+
53
+ if (baseCssRules) {
54
+ styles.push(`${selector} { ${baseCssRules} }`);
55
+ }
56
+
57
+ Object.keys(breakpointStyles)
58
+ .map((bp) => parseInt(bp, 10))
59
+ .sort((a, b) => a - b)
60
+ .forEach((bp) => {
61
+ const bpCssRules = Object.entries(breakpointStyles[bp])
62
+ .map(([prop, val]) => `${kebabize(prop)}: ${formatCssValue(val)};`)
63
+ .join(' ');
64
+
65
+ if (bpCssRules) {
66
+ styles.push(
67
+ `@media only screen and (min-width: ${bp}px) { ${selector} { ${bpCssRules} } }`
68
+ );
69
+ }
70
+ });
71
+ }
72
+
73
+ return styles;
74
+ };
75
+
76
+ const componentToCss = (components: Record<string, Node>) => {
77
+ const styles: string[] = [];
78
+ const componentsById: Record<string, Node> = {};
79
+
80
+ Object.values(components).forEach((component) => {
81
+ componentsById[component.key] = component;
82
+ });
83
+
84
+ const addStylesForComponent = (component: Node) => {
85
+ const selector = `[data-id="${component.key}"]`;
86
+ processNode(component, selector, styles);
87
+
88
+ Object.values(componentsById)
89
+ .filter((child) => child.properties.parent_id === component.key)
90
+ .forEach(addStylesForComponent);
91
+ };
92
+
93
+ Object.values(componentsById)
94
+ .filter((component) => !component.properties?.parent_id)
95
+ .forEach(addStylesForComponent);
96
+
97
+ return styles.join(' ');
98
+ };
99
+
100
+ export const generateWidgetStyles = (widgetSchemas: Record<string, Node>[]) => {
101
+ return widgetSchemas
102
+ .filter((schema) => Object.keys(schema).length > 0)
103
+ .map((data) => componentToCss(data))
104
+ .join('\n');
105
+ };
106
+
107
+ export type { Node, NodeProperties };
package/with-pz-config.js CHANGED
@@ -1,19 +1,22 @@
1
+ const path = require('path');
1
2
  const pzPlugins = require('./plugins');
2
3
  const deepMerge = require('./utils/deep-merge');
3
4
 
4
5
  /** @type {import('next').NextConfig} */
5
6
  const defaultConfig = {
6
- experimental: { instrumentationHook: true },
7
7
  reactStrictMode: true,
8
- transpilePackages: ['@akinon/next', ...pzPlugins.map((p) => `@akinon/${p}`)],
8
+ transpilePackages: ['@akinon/next', '@akinon/pz-theme', ...pzPlugins.map((p) => `@akinon/${p}`)],
9
9
  skipTrailingSlashRedirect: true,
10
10
  poweredByHeader: false,
11
11
  cacheMaxMemorySize: 0,
12
+ output: 'standalone',
13
+ compress: false,
12
14
  env: {
13
15
  NEXT_PUBLIC_SENTRY_DSN: process.env.SENTRY_DSN
14
16
  },
15
17
  images: {
16
18
  remotePatterns: [
19
+ //It has to be like this for security reasons
17
20
  {
18
21
  protocol: 'https',
19
22
  hostname: '**.akinoncloud.com'
@@ -46,13 +49,19 @@ const defaultConfig = {
46
49
  {
47
50
  key: 'Content-Security-Policy',
48
51
  value:
49
- "frame-ancestors 'self' https://*.akifast.com akifast.com https://*.akinoncloud.com akinoncloud.com"
52
+ "frame-ancestors 'self' https://*.akifast.com akifast.com https://*.akinoncloud.com akinoncloud.com http://localhost:5174 localhost:5174"
50
53
  }
51
54
  ]
52
55
  }
53
56
  ];
54
57
  },
55
58
  webpack: (config, options) => {
59
+ // Alias 'redux/store' to the app's local redux/store module to prevent
60
+ // collision with the npm 'redux' package's exports field
61
+ config.resolve.alias = {
62
+ ...config.resolve.alias,
63
+ 'redux/store': path.resolve(process.cwd(), 'src/redux/store')
64
+ };
56
65
  config.resolve.fallback = {
57
66
  ...config.resolve.fallback,
58
67
  ...pzPlugins.reduce((acc, plugin) => {
@@ -61,11 +70,15 @@ const defaultConfig = {
61
70
  }, {}),
62
71
  translations: false
63
72
  };
73
+ // Ensure webpack can resolve deps from the app's node_modules when
74
+ // compiling transpiled packages (e.g. @akinon/next) whose imports
75
+ // may not be hoisted to the monorepo root.
76
+ const appNodeModules = path.resolve(process.cwd(), 'node_modules');
77
+ if (!config.resolve.modules.includes(appNodeModules)) {
78
+ config.resolve.modules.push(appNodeModules);
79
+ }
64
80
  return config;
65
- },
66
- sentry: {
67
- hideSourceMaps: true
68
- } // TODO: This section will be reviewed again in the Sentry 8 update.
81
+ }
69
82
  };
70
83
 
71
84
  const withPzConfig = (