@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 BUGGY_BLOCK = ` const keyword = new URL(request.url).searchParams.get('keyword')?.trim() ?? ''
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 FIXED_BLOCK = ` const keyword = new URL(request.url).searchParams.get('keyword')?.trim() ?? ''
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
- * App Router themes proxy /api via app/api/[[...path]]/route.ts.
29
- * Older theme-starter builds read the request body before the mock branch,
30
- * which leaves nothing for proxyToUpstreamApi() in production.
31
- */
32
- function patchThemeApiProxyRoute(themeDir) {
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(FIXED_BLOCK)) {
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
- if (!src.includes(BUGGY_BLOCK)) {
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(BUGGY_BLOCK, FIXED_BLOCK);
48
- fs.writeFileSync(routePath, src, 'utf8');
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.14",
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",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@fecommunity/reactpress-server",
3
- "version": "4.0.0-beta.14",
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.14",
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.14",
94
+ "version": "4.0.0-beta.15",
95
95
  "dependencies": {
96
96
  "ajv": "^8.17.1",
97
97
  "axios": "^1.12.2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fecommunity/reactpress-server",
3
- "version": "4.0.0-beta.14",
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,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fecommunity/reactpress-toolkit",
3
- "version": "4.0.0-beta.14",
3
+ "version": "4.0.0-beta.15",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "exports": {