@akinon/next 1.96.0-rc.56 → 1.96.0-snapshot-ZERO-35861-20250908151109

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 (49) hide show
  1. package/CHANGELOG.md +41 -1244
  2. package/__tests__/next-config.test.ts +10 -1
  3. package/api/cache.ts +39 -5
  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 -30
  10. package/data/client/checkout.ts +4 -5
  11. package/data/server/category.ts +32 -50
  12. package/data/server/flatpage.ts +16 -17
  13. package/data/server/form.ts +4 -1
  14. package/data/server/landingpage.ts +12 -16
  15. package/data/server/list.ts +15 -24
  16. package/data/server/menu.ts +5 -2
  17. package/data/server/product.ts +41 -67
  18. package/data/server/special-page.ts +12 -16
  19. package/data/server/widget.ts +4 -1
  20. package/data/urls.ts +1 -5
  21. package/hocs/server/with-segment-defaults.tsx +2 -5
  22. package/hooks/use-localization.ts +3 -2
  23. package/jest.config.js +1 -7
  24. package/lib/cache-handler.mjs +365 -87
  25. package/lib/cache.ts +252 -25
  26. package/middlewares/complete-gpay.ts +1 -2
  27. package/middlewares/complete-masterpass.ts +1 -2
  28. package/middlewares/default.ts +13 -50
  29. package/middlewares/locale.ts +1 -9
  30. package/middlewares/pretty-url.ts +2 -1
  31. package/middlewares/redirection-payment.ts +1 -2
  32. package/middlewares/saved-card-redirection.ts +1 -2
  33. package/middlewares/three-d-redirection.ts +1 -2
  34. package/middlewares/url-redirection.ts +14 -8
  35. package/package.json +4 -3
  36. package/plugins.d.ts +0 -8
  37. package/plugins.js +1 -3
  38. package/redux/middlewares/checkout.ts +1 -5
  39. package/types/commerce/order.ts +0 -1
  40. package/types/index.ts +2 -34
  41. package/utils/app-fetch.ts +2 -7
  42. package/utils/redirect.ts +6 -31
  43. package/with-pz-config.js +5 -1
  44. package/__tests__/redirect.test.ts +0 -319
  45. package/api/image-proxy.ts +0 -75
  46. package/api/similar-product-list.ts +0 -84
  47. package/api/similar-products.ts +0 -120
  48. package/data/server/basket.ts +0 -72
  49. package/utils/redirect-ignore.ts +0 -35
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
  };
@@ -222,6 +216,7 @@ export interface CacheOptions {
222
216
  cache?: boolean;
223
217
  expire?: number;
224
218
  useProxy?: boolean;
219
+ compressed?: boolean;
225
220
  }
226
221
 
227
222
  export interface SetCookieOptions {
@@ -297,13 +292,7 @@ export interface ButtonProps
297
292
  target?: '_blank' | '_self' | '_parent' | '_top';
298
293
  }
299
294
 
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
- }
295
+ export type FileInputProps = React.HTMLProps<HTMLInputElement>;
307
296
 
308
297
  export interface PriceProps {
309
298
  currencyCode?: string;
@@ -324,19 +313,15 @@ export interface InputProps extends React.HTMLProps<HTMLInputElement> {
324
313
 
325
314
  export interface AccordionProps {
326
315
  isCollapse?: boolean;
327
- collapseClassName?: string;
328
316
  title?: string;
329
317
  subTitle?: string;
330
318
  icons?: string[];
331
319
  iconSize?: number;
332
320
  iconColor?: string;
333
321
  children?: ReactNode;
334
- headerClassName?: string;
335
322
  className?: string;
336
323
  titleClassName?: string;
337
- subTitleClassName?: string;
338
324
  dataTestId?: string;
339
- contentClassName?: string;
340
325
  }
341
326
 
342
327
  export interface PluginModuleComponentProps {
@@ -361,20 +346,3 @@ export interface PaginationProps {
361
346
  direction?: 'next' | 'prev';
362
347
  isLoading?: boolean;
363
348
  }
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/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: {
@@ -1,319 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
-
4
- jest.mock(
5
- 'countries',
6
- () => ({
7
- countries: [
8
- { value: 'ae', localizable: true },
9
- { value: 'qa', localizable: true },
10
- { value: 'sa', localizable: true }
11
- ],
12
- countryCurrencyMap: { ae: 'aed', qa: 'qar', sa: 'sar' },
13
- countryShortCodeMap: { ae: 'uae', qa: 'qtr', sa: 'ksa' }
14
- }),
15
- { virtual: true }
16
- );
17
-
18
- jest.mock(
19
- '@theme/routes',
20
- () => ({
21
- ROUTES: {
22
- AUTH: '/auth',
23
- BASKET: '/basket',
24
- ACCOUNT_ORDERS: '/account/orders'
25
- }
26
- }),
27
- { virtual: true }
28
- );
29
-
30
- type Locale = {
31
- value: string;
32
- label?: string;
33
- localePath?: string;
34
- apiValue?: string;
35
- rtl?: boolean;
36
- };
37
-
38
- type Settings = {
39
- localization: {
40
- defaultLocaleValue: string;
41
- localeUrlStrategy: string;
42
- locales: Locale[];
43
- };
44
- };
45
-
46
- function resolveSettingsPath(): string | null {
47
- const insideNodeModules = __dirname.includes('node_modules');
48
-
49
- const candidates: string[] = [];
50
-
51
- if (insideNodeModules) {
52
- const projectRoot = path.resolve(__dirname, '../../../../');
53
- candidates.push(path.join(projectRoot, 'src/settings.js'));
54
- candidates.push(
55
- path.join(projectRoot, 'apps', 'projectzeronext', 'src', 'settings.js')
56
- );
57
- } else {
58
- const repoRoot = path.resolve(__dirname, '../../..');
59
- candidates.push(
60
- path.join(repoRoot, 'apps', 'projectzeronext', 'src', 'settings.js')
61
- );
62
- candidates.push(path.join(repoRoot, 'src', 'settings.js'));
63
- }
64
-
65
- for (const p of candidates) {
66
- if (fs.existsSync(p)) return p;
67
- }
68
-
69
- return null;
70
- }
71
-
72
- function loadProjectSettings(): Settings {
73
- const settingsPath = resolveSettingsPath();
74
- if (settingsPath) {
75
- const settings: any = require(settingsPath);
76
- return settings as Settings;
77
- }
78
-
79
- return {
80
- localization: {
81
- defaultLocaleValue: 'en',
82
- localeUrlStrategy: 'hide-default-locale',
83
- locales: [
84
- { value: 'en', label: 'EN' },
85
- { value: 'tr', label: 'TR' }
86
- ]
87
- }
88
- };
89
- }
90
-
91
- function getUrlPathWithLocaleLocal(
92
- pathname: string,
93
- currentLocale: string | undefined,
94
- settings: Settings
95
- ): string {
96
- const { defaultLocaleValue, localeUrlStrategy } = settings.localization;
97
- const effectiveLocale = currentLocale ?? defaultLocaleValue;
98
-
99
- if (
100
- localeUrlStrategy === 'subdomain' ||
101
- localeUrlStrategy === 'hide-all-locales'
102
- ) {
103
- return pathname;
104
- }
105
-
106
- if (localeUrlStrategy === 'hide-default-locale') {
107
- if (effectiveLocale === defaultLocaleValue) {
108
- return pathname;
109
- }
110
- return `/${effectiveLocale}${pathname}`;
111
- }
112
-
113
- return `/${effectiveLocale}${pathname}`;
114
- }
115
-
116
- function computeUrlLocaleMatcherRegex(settings: Settings): RegExp {
117
- const { locales, localeUrlStrategy, defaultLocaleValue } =
118
- settings.localization;
119
-
120
- const filtered =
121
- localeUrlStrategy === 'show-all-locales' ||
122
- localeUrlStrategy === 'subdomain'
123
- ? locales
124
- : locales.filter((l: any) => l.value !== defaultLocaleValue);
125
-
126
- return new RegExp(
127
- `^/(${filtered.map((l: any) => l.value).join('|')})(?=/|$)`
128
- );
129
- }
130
-
131
- function redirectMinimal(
132
- destPath: string,
133
- pageUrlInput: string,
134
- settings: Settings
135
- ): string {
136
- const regex = computeUrlLocaleMatcherRegex(settings);
137
- const pageUrl = new URL(pageUrlInput);
138
- let currentLocaleValue = settings.localization.defaultLocaleValue;
139
-
140
- const match = pageUrl.pathname.match(regex);
141
- if (match && match[0]) {
142
- currentLocaleValue = match[0].replace('/', '');
143
- }
144
-
145
- const redirectUrlWithLocale = getUrlPathWithLocaleLocal(
146
- destPath,
147
- currentLocaleValue,
148
- settings
149
- );
150
-
151
- const callbackPath = pageUrl.pathname.replace(regex, '');
152
-
153
- return `${redirectUrlWithLocale}?callbackUrl=${callbackPath}`;
154
- }
155
-
156
- describe('Redirect utility functional tests', () => {
157
- const settings = loadProjectSettings();
158
-
159
- function buildPageUrl(pathAfter: string, locale: string): string {
160
- const { defaultLocaleValue, localeUrlStrategy } = settings.localization;
161
- const isDefault = locale === defaultLocaleValue;
162
- let prefix = '';
163
- if (isDefault) {
164
- prefix = localeUrlStrategy === 'show-all-locales' ? `/${locale}` : '';
165
- } else {
166
- prefix = `/${locale}`;
167
- }
168
- return `https://example.com${prefix}${pathAfter}`;
169
- }
170
-
171
- describe('getUrlPathWithLocale functional tests', () => {
172
- it('should respect project localeUrlStrategy dynamically', () => {
173
- const { defaultLocaleValue, locales, localeUrlStrategy } =
174
- settings.localization;
175
-
176
- const nonDefault = locales.find((l) => l.value !== defaultLocaleValue);
177
-
178
- const resultDefault = getUrlPathWithLocaleLocal(
179
- '/login',
180
- defaultLocaleValue,
181
- settings
182
- );
183
- const resultNonDefault = nonDefault
184
- ? getUrlPathWithLocaleLocal('/login', nonDefault.value, settings)
185
- : null;
186
- const resultUndefined = getUrlPathWithLocaleLocal(
187
- '/login',
188
- undefined,
189
- settings
190
- );
191
-
192
- if (localeUrlStrategy === 'hide-default-locale') {
193
- expect(resultDefault).toBe('/login');
194
- if (resultNonDefault && nonDefault) {
195
- expect(resultNonDefault).toBe(`/${nonDefault.value}/login`);
196
- }
197
- expect(resultUndefined).toBe('/login');
198
- } else if (localeUrlStrategy === 'show-all-locales') {
199
- expect(resultDefault).toBe(`/${defaultLocaleValue}/login`);
200
- if (resultNonDefault && nonDefault) {
201
- expect(resultNonDefault).toBe(`/${nonDefault.value}/login`);
202
- }
203
- expect(resultUndefined).toBe(`/${defaultLocaleValue}/login`);
204
- } else if (localeUrlStrategy === 'hide-all-locales') {
205
- expect(resultDefault).toBe('/login');
206
- if (resultNonDefault) {
207
- expect(resultNonDefault).toBe('/login');
208
- }
209
- expect(resultUndefined).toBe('/login');
210
- } else if (localeUrlStrategy === 'subdomain') {
211
- expect(resultDefault).toBe('/login');
212
- if (resultNonDefault) {
213
- expect(resultNonDefault).toBe('/login');
214
- }
215
- expect(resultUndefined).toBe('/login');
216
- }
217
- });
218
- });
219
-
220
- describe('redirect function behavior (simulated)', () => {
221
- it('should redirect with correct URL for default locale (no query preserved)', () => {
222
- const { defaultLocaleValue } = settings.localization;
223
- const regex = computeUrlLocaleMatcherRegex(settings);
224
- const url = buildPageUrl(
225
- '/profile?tab=settings&view=list#frag',
226
- defaultLocaleValue
227
- );
228
- const matched = new URL(url).pathname.match(regex)?.[0]?.replace('/', '');
229
- const expectedPath = getUrlPathWithLocaleLocal(
230
- '/login',
231
- matched,
232
- settings
233
- );
234
- const out = redirectMinimal('/login', url, settings);
235
- expect(out).toBe(`${expectedPath}?callbackUrl=/profile`);
236
- });
237
-
238
- it('should handle non-default locale from path', () => {
239
- const nonDefault = settings.localization.locales.find(
240
- (l) => l.value !== settings.localization.defaultLocaleValue
241
- );
242
- if (!nonDefault) return;
243
- const url = buildPageUrl('/products/123', nonDefault.value);
244
- const regex = computeUrlLocaleMatcherRegex(settings);
245
- const matched = new URL(url).pathname.match(regex)?.[0]?.replace('/', '');
246
- const expectedPath = getUrlPathWithLocaleLocal(
247
- '/auth',
248
- matched,
249
- settings
250
- );
251
- const out = redirectMinimal('/auth', url, settings);
252
- expect(out).toBe(`${expectedPath}?callbackUrl=/products/123`);
253
- });
254
-
255
- it('should use env fallback when header missing (no query preserved)', () => {
256
- const { defaultLocaleValue } = settings.localization;
257
- const url = buildPageUrl('/some/path?x=1#y', defaultLocaleValue).replace(
258
- 'https://example.com',
259
- 'https://fallback.com'
260
- );
261
- const regex = computeUrlLocaleMatcherRegex(settings);
262
- const matched = new URL(url).pathname.match(regex)?.[0]?.replace('/', '');
263
- const expectedPath = getUrlPathWithLocaleLocal(
264
- '/login',
265
- matched,
266
- settings
267
- );
268
- const out = redirectMinimal('/login', url, settings);
269
- expect(out).toBe(`${expectedPath}?callbackUrl=/some/path`);
270
- });
271
-
272
- it('should throw with invalid URL', () => {
273
- expect(() => new URL('')).toThrow();
274
- });
275
-
276
- it('should mention RedirectType usage in implementation', () => {
277
- const redirectFilePath = path.resolve(__dirname, '../utils/redirect.ts');
278
- const content = fs.readFileSync(redirectFilePath, 'utf8');
279
- expect(content.includes('RedirectType')).toBe(true);
280
- expect(content.includes('nextRedirect(redirectUrl, type)')).toBe(true);
281
- expect(content.includes('nextRedirect(redirectUrl)')).toBe(true);
282
- });
283
- });
284
-
285
- describe('URL locale matcher regex behavior (simulated)', () => {
286
- it('should match prefixes based on project strategy', () => {
287
- const { defaultLocaleValue, locales, localeUrlStrategy } =
288
- settings.localization;
289
- const urlLocaleMatcherRegex = computeUrlLocaleMatcherRegex(settings);
290
-
291
- const nonDefault = locales.find((l) => l.value !== defaultLocaleValue);
292
-
293
- if (localeUrlStrategy === 'show-all-locales') {
294
- expect(
295
- urlLocaleMatcherRegex.test(`/${defaultLocaleValue}/profile`)
296
- ).toBe(true);
297
- } else {
298
- expect(
299
- urlLocaleMatcherRegex.test(`/${defaultLocaleValue}/profile`)
300
- ).toBe(false);
301
- }
302
-
303
- if (nonDefault) {
304
- expect(urlLocaleMatcherRegex.test(`/${nonDefault.value}/profile`)).toBe(
305
- true
306
- );
307
- }
308
- expect(urlLocaleMatcherRegex.test('/profile')).toBe(false);
309
- });
310
- });
311
-
312
- it('should verify redirect utility file exists and has expected structure', () => {
313
- const redirectFilePath = path.resolve(__dirname, '../utils/redirect.ts');
314
- const redirectFileContent = fs.readFileSync(redirectFilePath, 'utf8');
315
- expect(redirectFileContent.includes('export const redirect')).toBe(true);
316
- expect(redirectFileContent.includes('getUrlPathWithLocale')).toBe(true);
317
- expect(redirectFileContent.includes('callbackUrl')).toBe(true);
318
- });
319
- });
@@ -1,75 +0,0 @@
1
- import { NextRequest, NextResponse } from 'next/server';
2
-
3
- async function proxyImage(imageUrl: string) {
4
- if (!imageUrl) {
5
- return NextResponse.json(
6
- { success: false, error: 'Missing url parameter' },
7
- { status: 400 }
8
- );
9
- }
10
-
11
- const imageResponse = await fetch(imageUrl);
12
-
13
- if (!imageResponse.ok) {
14
- return NextResponse.json(
15
- { success: false, error: 'Failed to fetch image from URL' },
16
- { status: 400 }
17
- );
18
- }
19
-
20
- const imageBuffer = await imageResponse.arrayBuffer();
21
- const base64Image = Buffer.from(imageBuffer).toString('base64');
22
- const contentType = imageResponse.headers.get('content-type') || 'image/jpeg';
23
-
24
- return { base64Image, contentType, imageBuffer };
25
- }
26
-
27
- export async function GET(request: NextRequest) {
28
- try {
29
- const { searchParams } = new URL(request.url);
30
- const imageUrl = searchParams.get('url');
31
-
32
- const result = await proxyImage(imageUrl!);
33
- if (result instanceof NextResponse) {
34
- return result;
35
- }
36
-
37
- return new NextResponse(result.imageBuffer, {
38
- status: 200,
39
- headers: {
40
- 'Content-Type': result.contentType,
41
- 'Access-Control-Allow-Origin': '*',
42
- 'Cache-Control': 'public, max-age=3600'
43
- }
44
- });
45
- } catch (error) {
46
- console.error('Image proxy error:', error);
47
- return NextResponse.json(
48
- { success: false, error: 'Internal server error' },
49
- { status: 500 }
50
- );
51
- }
52
- }
53
-
54
- export async function POST(request: NextRequest) {
55
- try {
56
- const body = await request.json();
57
- const imageUrl = body.imageUrl;
58
-
59
- const result = await proxyImage(imageUrl);
60
- if (result instanceof NextResponse) {
61
- return result;
62
- }
63
-
64
- return NextResponse.json({
65
- success: true,
66
- base64Image: `data:${result.contentType};base64,${result.base64Image}`
67
- });
68
- } catch (error) {
69
- console.error('Image proxy POST error:', error);
70
- return NextResponse.json(
71
- { success: false, error: 'Internal server error' },
72
- { status: 500 }
73
- );
74
- }
75
- }
@@ -1,84 +0,0 @@
1
- import { NextRequest, NextResponse } from 'next/server';
2
- import { cookies } from 'next/headers';
3
- import Settings from 'settings';
4
- import { ServerVariables } from '../utils/server-variables';
5
-
6
- export async function GET(request: NextRequest) {
7
- try {
8
- const { searchParams } = new URL(request.url);
9
- const dynamicFilter = request.headers.get('x-search-dynamic-filter');
10
- const dynamicExclude = request.headers.get('x-search-dynamic-exclude');
11
-
12
- const nextCookies = cookies();
13
- const currency =
14
- nextCookies.get('pz-currency')?.value || ServerVariables.currency;
15
- const locale =
16
- nextCookies.get('pz-locale')?.value || ServerVariables.locale;
17
-
18
- if (!dynamicFilter && !dynamicExclude) {
19
- return NextResponse.json(
20
- {
21
- error:
22
- 'Missing x-search-dynamic-filter or x-search-dynamic-exclude header'
23
- },
24
- { status: 400 }
25
- );
26
- }
27
-
28
- if (Settings.commerceUrl === 'default') {
29
- return NextResponse.json(
30
- { error: 'Commerce URL is not configured' },
31
- { status: 500 }
32
- );
33
- }
34
-
35
- const queryString = searchParams.toString();
36
- const apiUrl = `${Settings.commerceUrl}/list${
37
- queryString ? `?${queryString}` : ''
38
- }`;
39
-
40
- const headers: Record<string, string> = {
41
- Accept: 'application/json',
42
- 'Content-Type': 'application/json'
43
- };
44
-
45
- if (dynamicFilter) {
46
- headers['x-search-dynamic-filter'] = dynamicFilter;
47
- } else if (dynamicExclude) {
48
- headers['x-search-dynamic-exclude'] = dynamicExclude;
49
- }
50
-
51
- if (currency) {
52
- headers['x-currency'] = currency;
53
- }
54
-
55
- if (locale) {
56
- const currentLocale = Settings.localization.locales.find(
57
- (l) => l.value === locale
58
- );
59
- if (currentLocale) {
60
- headers['Accept-Language'] = currentLocale.apiValue;
61
- }
62
- }
63
-
64
- const response = await fetch(apiUrl, {
65
- method: 'GET',
66
- headers
67
- });
68
-
69
- if (!response.ok) {
70
- return NextResponse.json(
71
- { error: `API request failed with status: ${response.status}` },
72
- { status: response.status }
73
- );
74
- }
75
-
76
- const data = await response.json();
77
- return NextResponse.json(data);
78
- } catch (error) {
79
- return NextResponse.json(
80
- { error: (error as Error).message },
81
- { status: 500 }
82
- );
83
- }
84
- }