@akinon/next 1.92.0-rc.33 → 1.92.0-rc.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/data/server/category.ts +44 -24
- package/data/server/flatpage.ts +16 -12
- package/data/server/landingpage.ts +16 -12
- package/data/server/list.ts +23 -13
- package/data/server/product.ts +66 -39
- package/data/server/special-page.ts +16 -12
- package/middlewares/default.ts +18 -13
- package/package.json +2 -2
- package/utils/app-fetch.ts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
+
## 1.92.0-rc.35
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 89ce46fc: ZERO-3493: return 404 status code for pz-not-found pages
|
|
8
|
+
|
|
9
|
+
## 1.92.0-rc.34
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 0ad91bbd: ZERO-3489: Improve error handling in data fetching across multiple pages and server functions
|
|
14
|
+
|
|
3
15
|
## 1.92.0-rc.33
|
|
4
16
|
|
|
5
17
|
## 1.92.0-rc.32
|
package/data/server/category.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { category, product } from '../urls';
|
|
|
5
5
|
import { Cache, CacheKey } from '../../lib/cache';
|
|
6
6
|
import { parse } from 'lossless-json';
|
|
7
7
|
import logger from '../../utils/log';
|
|
8
|
-
import { headers as nHeaders } from 'next/headers';
|
|
9
8
|
import { ServerVariables } from '../../utils/server-variables';
|
|
10
9
|
|
|
11
10
|
function getCategoryDataHandler(
|
|
@@ -18,19 +17,30 @@ function getCategoryDataHandler(
|
|
|
18
17
|
return async function () {
|
|
19
18
|
const params = generateCommerceSearchParams(searchParams);
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
20
|
+
let rawData: string;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
rawData = await appFetch<string>({
|
|
24
|
+
url: `${category.getCategoryByPk(pk)}${params ? params : ''}`,
|
|
25
|
+
locale,
|
|
26
|
+
currency,
|
|
27
|
+
init: {
|
|
28
|
+
headers: {
|
|
29
|
+
Accept: 'application/json',
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
...(headers ?? {})
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
responseType: FetchResponseType.TEXT
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
logger.error('Failed to fetch category data', {
|
|
38
|
+
handler: 'getCategoryDataHandler',
|
|
39
|
+
pk,
|
|
40
|
+
error: error.message
|
|
41
|
+
});
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
34
44
|
|
|
35
45
|
let data: GetCategoryResponse;
|
|
36
46
|
|
|
@@ -64,17 +74,27 @@ function getCategoryDataHandler(
|
|
|
64
74
|
return { data, breadcrumbData: undefined };
|
|
65
75
|
}
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
let breadcrumbData: { menu?: unknown } = {};
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
breadcrumbData = await appFetch<{ menu?: unknown }>({
|
|
81
|
+
url: product.breadcrumbUrl(menuItemModel),
|
|
82
|
+
locale,
|
|
83
|
+
currency,
|
|
84
|
+
init: {
|
|
85
|
+
headers: {
|
|
86
|
+
Accept: 'application/json',
|
|
87
|
+
'Content-Type': 'application/json'
|
|
88
|
+
}
|
|
75
89
|
}
|
|
76
|
-
}
|
|
77
|
-
})
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
logger.warn('Failed to fetch breadcrumb data', {
|
|
93
|
+
handler: 'getCategoryDataHandler',
|
|
94
|
+
pk,
|
|
95
|
+
error: error.message
|
|
96
|
+
});
|
|
97
|
+
}
|
|
78
98
|
|
|
79
99
|
return { data, breadcrumbData: breadcrumbData?.menu };
|
|
80
100
|
};
|
package/data/server/flatpage.ts
CHANGED
|
@@ -11,20 +11,24 @@ const getFlatPageDataHandler = (
|
|
|
11
11
|
headers?: Record<string, string>
|
|
12
12
|
) => {
|
|
13
13
|
return async function () {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
try {
|
|
15
|
+
const data = await appFetch<FlatPage>({
|
|
16
|
+
url: flatpage.getFlatPageByPk(pk),
|
|
17
|
+
locale,
|
|
18
|
+
currency,
|
|
19
|
+
init: {
|
|
20
|
+
headers: {
|
|
21
|
+
Accept: 'application/json',
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
...(headers ?? {})
|
|
24
|
+
}
|
|
23
25
|
}
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
+
});
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
return data;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
28
32
|
};
|
|
29
33
|
};
|
|
30
34
|
|
|
@@ -11,20 +11,24 @@ const getLandingPageHandler = (
|
|
|
11
11
|
headers?: Record<string, string>
|
|
12
12
|
) => {
|
|
13
13
|
return async function () {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
try {
|
|
15
|
+
const data = await appFetch<LandingPage>({
|
|
16
|
+
url: landingpage.getLandingPageByPk(pk),
|
|
17
|
+
locale,
|
|
18
|
+
currency,
|
|
19
|
+
init: {
|
|
20
|
+
headers: {
|
|
21
|
+
Accept: 'application/json',
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
...(headers ?? {})
|
|
24
|
+
}
|
|
23
25
|
}
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
+
});
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
return data;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
28
32
|
};
|
|
29
33
|
};
|
|
30
34
|
|
package/data/server/list.ts
CHANGED
|
@@ -16,19 +16,29 @@ const getListDataHandler = (
|
|
|
16
16
|
return async function () {
|
|
17
17
|
const params = generateCommerceSearchParams(searchParams);
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
let rawData: string;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
rawData = await appFetch<string>({
|
|
23
|
+
url: `${category.list}${params}`,
|
|
24
|
+
locale,
|
|
25
|
+
currency,
|
|
26
|
+
init: {
|
|
27
|
+
headers: {
|
|
28
|
+
Accept: 'application/json',
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
...(headers ?? {})
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
responseType: FetchResponseType.TEXT
|
|
34
|
+
});
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger.error('Failed to fetch list data', {
|
|
37
|
+
handler: 'getListDataHandler',
|
|
38
|
+
error: error.message
|
|
39
|
+
});
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
32
42
|
|
|
33
43
|
let data: GetCategoryResponse;
|
|
34
44
|
|
package/data/server/product.ts
CHANGED
|
@@ -35,57 +35,84 @@ const getProductDataHandler = ({
|
|
|
35
35
|
.join('&');
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
let data: ProductResult;
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
data = await appFetch<ProductResult>({
|
|
42
|
+
url,
|
|
43
|
+
locale,
|
|
44
|
+
currency,
|
|
45
|
+
init: {
|
|
46
|
+
headers: {
|
|
47
|
+
Accept: 'application/json',
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
...(headers ?? {})
|
|
50
|
+
}
|
|
47
51
|
}
|
|
48
|
-
}
|
|
49
|
-
})
|
|
52
|
+
});
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logger.error('Failed to fetch product data', {
|
|
55
|
+
handler: 'getProductDataHandler',
|
|
56
|
+
pk,
|
|
57
|
+
error: error.message,
|
|
58
|
+
url
|
|
59
|
+
});
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
50
62
|
|
|
51
63
|
const categoryUrl = product.categoryUrl(data.product.pk);
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
let productCategoryData: ProductCategoryResult;
|
|
66
|
+
let breadcrumbData: { menu?: unknown } = {};
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
productCategoryData = await appFetch<ProductCategoryResult>({
|
|
70
|
+
url: categoryUrl,
|
|
71
|
+
locale,
|
|
72
|
+
currency,
|
|
73
|
+
init: {
|
|
74
|
+
headers: {
|
|
75
|
+
Accept: 'application/json',
|
|
76
|
+
'Content-Type': 'application/json'
|
|
77
|
+
}
|
|
61
78
|
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const menuItemModel = productCategoryData?.results[0]?.menuitemmodel;
|
|
82
|
+
|
|
83
|
+
if (!menuItemModel) {
|
|
84
|
+
logger.warn(
|
|
85
|
+
'menuItemModel is undefined, skipping breadcrumbData fetch',
|
|
86
|
+
{
|
|
87
|
+
handler: 'getProductDataHandler',
|
|
88
|
+
pk
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
return { data, breadcrumbData: undefined };
|
|
62
92
|
}
|
|
63
|
-
});
|
|
64
93
|
|
|
65
|
-
|
|
94
|
+
const breadcrumbUrl = product.breadcrumbUrl(menuItemModel);
|
|
66
95
|
|
|
67
|
-
|
|
68
|
-
|
|
96
|
+
breadcrumbData = await appFetch<{ menu?: unknown }>({
|
|
97
|
+
url: breadcrumbUrl,
|
|
98
|
+
locale,
|
|
99
|
+
currency,
|
|
100
|
+
init: {
|
|
101
|
+
headers: {
|
|
102
|
+
Accept: 'application/json',
|
|
103
|
+
'Content-Type': 'application/json'
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
} catch (error) {
|
|
108
|
+
logger.warn('Failed to fetch breadcrumb data', {
|
|
69
109
|
handler: 'getProductDataHandler',
|
|
70
|
-
pk
|
|
110
|
+
pk,
|
|
111
|
+
error: error.message
|
|
71
112
|
});
|
|
72
|
-
|
|
113
|
+
// Continue without breadcrumb data
|
|
73
114
|
}
|
|
74
115
|
|
|
75
|
-
const breadcrumbUrl = product.breadcrumbUrl(menuItemModel);
|
|
76
|
-
|
|
77
|
-
const breadcrumbData = await appFetch<any>({
|
|
78
|
-
url: breadcrumbUrl,
|
|
79
|
-
locale,
|
|
80
|
-
currency,
|
|
81
|
-
init: {
|
|
82
|
-
headers: {
|
|
83
|
-
Accept: 'application/json',
|
|
84
|
-
'Content-Type': 'application/json'
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
116
|
return {
|
|
90
117
|
data,
|
|
91
118
|
breadcrumbData: breadcrumbData?.menu
|
|
@@ -15,20 +15,24 @@ const getSpecialPageDataHandler = (
|
|
|
15
15
|
return async function () {
|
|
16
16
|
const params = generateCommerceSearchParams(searchParams);
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
try {
|
|
19
|
+
const data: GetCategoryResponse = await appFetch({
|
|
20
|
+
url: `${category.getSpecialPageByPk(pk)}${params}`,
|
|
21
|
+
locale,
|
|
22
|
+
currency,
|
|
23
|
+
init: {
|
|
24
|
+
headers: {
|
|
25
|
+
Accept: 'application/json',
|
|
26
|
+
'Content-Type': 'application/json',
|
|
27
|
+
...(headers ?? {})
|
|
28
|
+
}
|
|
27
29
|
}
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
+
});
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
return data;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
32
36
|
};
|
|
33
37
|
};
|
|
34
38
|
|
package/middlewares/default.ts
CHANGED
|
@@ -302,19 +302,6 @@ const withPzDefault =
|
|
|
302
302
|
)}`;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
if (
|
|
306
|
-
!req.middlewareParams.found &&
|
|
307
|
-
Settings.customNotFoundEnabled
|
|
308
|
-
) {
|
|
309
|
-
const pathname = url.pathname
|
|
310
|
-
.replace(/\/+$/, '')
|
|
311
|
-
.split('/');
|
|
312
|
-
url.pathname = url.pathname.replace(
|
|
313
|
-
pathname.pop(),
|
|
314
|
-
'pz-not-found'
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
305
|
Settings.rewrites.forEach((rewrite) => {
|
|
319
306
|
url.pathname = url.pathname.replace(
|
|
320
307
|
rewrite.source,
|
|
@@ -352,6 +339,24 @@ const withPzDefault =
|
|
|
352
339
|
middlewareResult = NextResponse.rewrite(url);
|
|
353
340
|
}
|
|
354
341
|
|
|
342
|
+
if (
|
|
343
|
+
!req.middlewareParams.found &&
|
|
344
|
+
Settings.customNotFoundEnabled
|
|
345
|
+
) {
|
|
346
|
+
const pathSegments = url.pathname
|
|
347
|
+
.replace(/\/+$/, '')
|
|
348
|
+
.split('/');
|
|
349
|
+
if (pathSegments.length >= 3) {
|
|
350
|
+
url.pathname = `/${pathSegments[1]}/${pathSegments[2]}/pz-not-found`;
|
|
351
|
+
} else {
|
|
352
|
+
url.pathname = '/pz-not-found';
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
middlewareResult = NextResponse.rewrite(url, {
|
|
356
|
+
status: 404
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
355
360
|
const { localeUrlStrategy } =
|
|
356
361
|
Settings.localization;
|
|
357
362
|
|
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.92.0-rc.
|
|
4
|
+
"version": "1.92.0-rc.35",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"set-cookie-parser": "2.6.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@akinon/eslint-plugin-projectzero": "1.92.0-rc.
|
|
37
|
+
"@akinon/eslint-plugin-projectzero": "1.92.0-rc.35",
|
|
38
38
|
"@babel/core": "7.26.10",
|
|
39
39
|
"@babel/preset-env": "7.26.9",
|
|
40
40
|
"@babel/preset-typescript": "7.27.0",
|
package/utils/app-fetch.ts
CHANGED
|
@@ -60,6 +60,11 @@ 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
|
+
|
|
63
68
|
if (responseType === FetchResponseType.JSON) {
|
|
64
69
|
response = (await req.json()) as T;
|
|
65
70
|
} else {
|