@fecommunity/reactpress 4.0.0-beta.14 → 4.0.0-beta.15
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.
|
@@ -4,55 +4,100 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const PATCH_MARKER = '.reactpress-api-proxy-patched';
|
|
7
|
+
const ENCODING_PATCH_MARKER = 'reactpress-api-proxy-encoding';
|
|
7
8
|
const ROUTE_REL = path.join('app', 'api', '[[...path]]', 'route.ts');
|
|
9
|
+
const PROXY_REL = path.join('lib', 'mock-api', 'proxy.ts');
|
|
8
10
|
/** Buggy pattern: body read before mock/proxy branch (breaks upstream proxy). */
|
|
9
|
-
const
|
|
11
|
+
const BUGGY_ROUTE_BLOCK = ` const keyword = new URL(request.url).searchParams.get('keyword')?.trim() ?? ''
|
|
10
12
|
const body = await readJsonBody(request)
|
|
11
13
|
|
|
12
14
|
let response: Response
|
|
13
15
|
if (isMockApiEnabled()) {
|
|
14
16
|
const mockResponse = matchMockRoute(request.method, path, { keyword, body })`;
|
|
15
|
-
const
|
|
17
|
+
const FIXED_ROUTE_BLOCK = ` const keyword = new URL(request.url).searchParams.get('keyword')?.trim() ?? ''
|
|
16
18
|
|
|
17
19
|
let response: Response
|
|
18
20
|
if (isMockApiEnabled()) {
|
|
19
21
|
const body = await readJsonBody(request)
|
|
20
22
|
const mockResponse = matchMockRoute(request.method, path, { keyword, body })`;
|
|
23
|
+
const BUGGY_PROXY_BLOCK = ` return new Response(upstream.body, {
|
|
24
|
+
status: upstream.status,
|
|
25
|
+
headers: upstream.headers,
|
|
26
|
+
})`;
|
|
27
|
+
const FIXED_PROXY_BLOCK = ` const responseHeaders = new Headers(upstream.headers)
|
|
28
|
+
// ${ENCODING_PATCH_MARKER}: Node fetch decompresses bodies; strip stale encoding headers.
|
|
29
|
+
responseHeaders.delete('content-encoding')
|
|
30
|
+
responseHeaders.delete('content-length')
|
|
31
|
+
responseHeaders.delete('transfer-encoding')
|
|
32
|
+
|
|
33
|
+
return new Response(upstream.body, {
|
|
34
|
+
status: upstream.status,
|
|
35
|
+
headers: responseHeaders,
|
|
36
|
+
})`;
|
|
21
37
|
function resolveApiRoutePath(themeDir) {
|
|
22
38
|
if (!themeDir)
|
|
23
39
|
return null;
|
|
24
40
|
const routePath = path.join(themeDir, ROUTE_REL);
|
|
25
41
|
return fs.existsSync(routePath) ? routePath : null;
|
|
26
42
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
43
|
+
function resolveApiProxyPath(themeDir) {
|
|
44
|
+
if (!themeDir)
|
|
45
|
+
return null;
|
|
46
|
+
const proxyPath = path.join(themeDir, PROXY_REL);
|
|
47
|
+
return fs.existsSync(proxyPath) ? proxyPath : null;
|
|
48
|
+
}
|
|
49
|
+
function touchPatchMarker(themeDir) {
|
|
50
|
+
fs.writeFileSync(path.join(themeDir, PATCH_MARKER), `${new Date().toISOString()}\n`, 'utf8');
|
|
51
|
+
}
|
|
52
|
+
function patchThemeApiRouteBodyRead(themeDir) {
|
|
33
53
|
const routePath = resolveApiRoutePath(themeDir);
|
|
34
54
|
if (!routePath)
|
|
35
55
|
return false;
|
|
36
|
-
const markerPath = path.join(themeDir, PATCH_MARKER);
|
|
37
56
|
let src = fs.readFileSync(routePath, 'utf8');
|
|
38
|
-
if (src.includes(
|
|
39
|
-
if (!fs.existsSync(markerPath)) {
|
|
40
|
-
fs.writeFileSync(markerPath, `${new Date().toISOString()}\n`, 'utf8');
|
|
41
|
-
}
|
|
57
|
+
if (src.includes(FIXED_ROUTE_BLOCK) || !src.includes(BUGGY_ROUTE_BLOCK)) {
|
|
42
58
|
return false;
|
|
43
59
|
}
|
|
44
|
-
|
|
60
|
+
src = src.replace(BUGGY_ROUTE_BLOCK, FIXED_ROUTE_BLOCK);
|
|
61
|
+
fs.writeFileSync(routePath, src, 'utf8');
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Node fetch() auto-decompresses upstream bodies but leaves Content-Encoding on the Response.
|
|
66
|
+
* Browsers then fail with ERR_CONTENT_DECODING_FAILED (HTTP 200).
|
|
67
|
+
*/
|
|
68
|
+
function patchThemeApiProxyEncodingHeaders(themeDir) {
|
|
69
|
+
const proxyPath = resolveApiProxyPath(themeDir);
|
|
70
|
+
if (!proxyPath)
|
|
71
|
+
return false;
|
|
72
|
+
let src = fs.readFileSync(proxyPath, 'utf8');
|
|
73
|
+
if (src.includes(ENCODING_PATCH_MARKER) || !src.includes(BUGGY_PROXY_BLOCK)) {
|
|
45
74
|
return false;
|
|
46
75
|
}
|
|
47
|
-
src = src.replace(
|
|
48
|
-
fs.writeFileSync(
|
|
49
|
-
fs.writeFileSync(markerPath, `${new Date().toISOString()}\n`, 'utf8');
|
|
76
|
+
src = src.replace(BUGGY_PROXY_BLOCK, FIXED_PROXY_BLOCK);
|
|
77
|
+
fs.writeFileSync(proxyPath, src, 'utf8');
|
|
50
78
|
return true;
|
|
51
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* App Router themes proxy /api via app/api/[[...path]]/route.ts.
|
|
82
|
+
* Patches known theme-starter issues before production build.
|
|
83
|
+
*/
|
|
84
|
+
function patchThemeApiProxyRoute(themeDir) {
|
|
85
|
+
const routePatched = patchThemeApiRouteBodyRead(themeDir);
|
|
86
|
+
const proxyPatched = patchThemeApiProxyEncodingHeaders(themeDir);
|
|
87
|
+
if (routePatched || proxyPatched) {
|
|
88
|
+
touchPatchMarker(themeDir);
|
|
89
|
+
}
|
|
90
|
+
return routePatched || proxyPatched;
|
|
91
|
+
}
|
|
52
92
|
module.exports = {
|
|
53
93
|
PATCH_MARKER,
|
|
94
|
+
ENCODING_PATCH_MARKER,
|
|
54
95
|
ROUTE_REL,
|
|
96
|
+
PROXY_REL,
|
|
55
97
|
patchThemeApiProxyRoute,
|
|
98
|
+
patchThemeApiRouteBodyRead,
|
|
99
|
+
patchThemeApiProxyEncodingHeaders,
|
|
56
100
|
resolveApiRoutePath,
|
|
101
|
+
resolveApiProxyPath,
|
|
57
102
|
};
|
|
58
103
|
//# sourceMappingURL=theme-api-proxy-patch.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fecommunity/reactpress",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.15",
|
|
4
4
|
"description": "ReactPress CLI — publishing platform for modern developers. CMS, Admin, API, and Next.js themes in one command. Self-hosted, MIT. `npx @fecommunity/reactpress init`",
|
|
5
5
|
"author": "fecommunity",
|
|
6
6
|
"license": "MIT",
|
package/server/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fecommunity/reactpress-server",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.15",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@fecommunity/reactpress-server",
|
|
9
|
-
"version": "4.0.0-beta.
|
|
9
|
+
"version": "4.0.0-beta.15",
|
|
10
10
|
"deprecated": "Bundled in @fecommunity/reactpress CLI from v3.1. Run `npx @fecommunity/reactpress init` for new projects.",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
},
|
|
92
92
|
"../toolkit": {
|
|
93
93
|
"name": "@fecommunity/reactpress-toolkit",
|
|
94
|
-
"version": "4.0.0-beta.
|
|
94
|
+
"version": "4.0.0-beta.15",
|
|
95
95
|
"dependencies": {
|
|
96
96
|
"ajv": "^8.17.1",
|
|
97
97
|
"axios": "^1.12.2",
|
package/server/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fecommunity/reactpress-server",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.15",
|
|
4
4
|
"deprecated": "Bundled in @fecommunity/reactpress CLI from v3.1. Run `npx @fecommunity/reactpress init` for new projects.",
|
|
5
5
|
"description": "ReactPress NestJS REST API (deprecated). Bundled in @fecommunity/reactpress CLI from v3.1. Headless CMS for articles, media, plugins, and themes",
|
|
6
6
|
"author": "fecommunity",
|
|
@@ -41,9 +41,12 @@ function applyThemeWebpackResolve(config, appDir) {
|
|
|
41
41
|
* Pass overrides to extend (your `webpack` runs after the supports-color alias).
|
|
42
42
|
*/
|
|
43
43
|
function createReactPressNextConfig(overrides = {}) {
|
|
44
|
-
const { webpack: userWebpack, eslint, transpilePackages, ...rest } = overrides;
|
|
44
|
+
const { webpack: userWebpack, eslint, transpilePackages, compress, ...rest } = overrides;
|
|
45
45
|
return {
|
|
46
46
|
reactStrictMode: true,
|
|
47
|
+
// Themes rewrite `/api` to Nest. Next's compress middleware decompresses upstream
|
|
48
|
+
// bodies but can still emit `Content-Encoding: br`, breaking admin fetch (ERR_CONTENT_DECODING_FAILED).
|
|
49
|
+
compress: compress ?? false,
|
|
47
50
|
transpilePackages: ['@fecommunity/reactpress-toolkit', ...(transpilePackages ?? [])],
|
|
48
51
|
eslint: {
|
|
49
52
|
ignoreDuringBuilds: true,
|