rari 0.5.9 → 0.5.11

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/dist/client.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { C as fetchWithTimeout, S as createNavigationError, _ as LayoutErrorBoundary, a as LoadingSpinner, b as NavigationErrorOverlay, c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, l as createLoadingBoundary, m as extractServerPropsWithCache, n as DefaultLoading, o as NotFound, p as extractServerProps, r as ErrorBoundary, s as createErrorBoundary, t as DefaultError, u as clearPropsCache, v as ClientRouter, w as LayoutManager, x as NavigationErrorHandler, y as StatePreserver } from "./runtime-client-CGCu6fmO.mjs";
1
+ import { C as fetchWithTimeout, S as createNavigationError, _ as LayoutErrorBoundary, a as LoadingSpinner, b as NavigationErrorOverlay, c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, l as createLoadingBoundary, m as extractServerPropsWithCache, n as DefaultLoading, o as NotFound, p as extractServerProps, r as ErrorBoundary, s as createErrorBoundary, t as DefaultError, u as clearPropsCache, v as ClientRouter, w as LayoutManager, x as NavigationErrorHandler, y as StatePreserver } from "./runtime-client-CeW5R9VK.mjs";
2
2
 
3
3
  export { ClientRouter, DefaultError, DefaultLoading, ErrorBoundary, HttpRuntimeClient, LayoutErrorBoundary, LayoutManager, LoadingSpinner, NavigationErrorHandler, NavigationErrorOverlay, NotFound, StatePreserver, clearPropsCache, clearPropsCacheForComponent, createErrorBoundary, createHttpRuntimeClient, createLoadingBoundary, createNavigationError, extractMetadata, extractServerProps, extractServerPropsWithCache, extractStaticParams, fetchWithTimeout, hasServerSideDataFetching };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { a as headers, i as rariRouter, n as defineRariOptions, o as RariResponse, r as rari, t as defineRariConfig } from "./vite-CT18_z0c.mjs";
1
+ import { a as headers, i as rariRouter, n as defineRariOptions, o as RariResponse, r as rari, t as defineRariConfig } from "./vite-S1XOJqX6.mjs";
2
2
  import { i as writeManifest, n as generateAppRouteManifest, r as loadManifest, t as AppRouteGenerator } from "./app-routes-BjA_L5R4.mjs";
3
- import { c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, m as extractServerPropsWithCache, p as extractServerProps, u as clearPropsCache } from "./runtime-client-CGCu6fmO.mjs";
4
- import "./loading-component-map-UZ-MQYv0.mjs";
3
+ import { c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, m as extractServerPropsWithCache, p as extractServerProps, u as clearPropsCache } from "./runtime-client-CeW5R9VK.mjs";
4
+ import "./loading-component-map-SF6GiuGb.mjs";
5
5
  import "./server-build-Cvj5EwXx.mjs";
6
6
 
7
7
  export { AppRouteGenerator, HttpRuntimeClient, RariResponse, clearPropsCache, clearPropsCacheForComponent, createHttpRuntimeClient, defineRariConfig, defineRariOptions, extractMetadata, extractServerProps, extractServerPropsWithCache, extractStaticParams, generateAppRouteManifest, hasServerSideDataFetching, headers, loadManifest, rari, rariRouter, writeManifest };
@@ -1,3 +1,3 @@
1
- import { n as getLoadingComponentMapPath, t as generateLoadingComponentMap } from "./loading-component-map-UZ-MQYv0.mjs";
1
+ import { n as getLoadingComponentMapPath, t as generateLoadingComponentMap } from "./loading-component-map-SF6GiuGb.mjs";
2
2
 
3
3
  export { generateLoadingComponentMap, getLoadingComponentMapPath };
@@ -19,7 +19,7 @@ ${moduleEntries.join(",\n")}
19
19
  }
20
20
 
21
21
  if (typeof globalThis !== 'undefined') {
22
- globalThis.__rari_loading_components = loadingComponentModules
22
+ globalThis.__rari_loading_components = new Map(Object.entries(loadingComponentModules))
23
23
  }
24
24
  `;
25
25
  }
@@ -1,3 +1,71 @@
1
+ //#region src/runtime/csrf.ts
2
+ function getCsrfToken() {
3
+ if (typeof window === "undefined") return null;
4
+ const meta = document.querySelector("meta[name=\"csrf-token\"]");
5
+ return meta ? meta.getAttribute("content") : null;
6
+ }
7
+ async function refreshCsrfToken() {
8
+ if (typeof window === "undefined") return false;
9
+ try {
10
+ const response = await fetch("/api/rsc/csrf-token");
11
+ if (!response.ok) {
12
+ console.warn("Failed to refresh CSRF token:", response.status);
13
+ return false;
14
+ }
15
+ const data = await response.json();
16
+ if (data.token) {
17
+ let meta = document.querySelector("meta[name=\"csrf-token\"]");
18
+ if (!meta) {
19
+ meta = document.createElement("meta");
20
+ meta.setAttribute("name", "csrf-token");
21
+ document.head.appendChild(meta);
22
+ }
23
+ meta.setAttribute("content", data.token);
24
+ return true;
25
+ }
26
+ return false;
27
+ } catch (error) {
28
+ console.error("Error refreshing CSRF token:", error);
29
+ return false;
30
+ }
31
+ }
32
+ async function fetchWithCsrf(url, options = {}) {
33
+ let token = getCsrfToken();
34
+ if (!token) {
35
+ await refreshCsrfToken();
36
+ token = getCsrfToken();
37
+ }
38
+ const headers = new Headers(options.headers);
39
+ if (token) headers.set("X-CSRF-Token", token);
40
+ const response = await fetch(url, {
41
+ ...options,
42
+ headers
43
+ });
44
+ if (response.status === 403 && url.includes("/api/rsc/")) {
45
+ if (await refreshCsrfToken()) {
46
+ const retryToken = getCsrfToken();
47
+ if (retryToken) {
48
+ headers.set("X-CSRF-Token", retryToken);
49
+ return fetch(url, {
50
+ ...options,
51
+ headers
52
+ });
53
+ }
54
+ }
55
+ }
56
+ return response;
57
+ }
58
+ if (typeof window !== "undefined") {
59
+ window.getCsrfToken = getCsrfToken;
60
+ window.fetchWithCsrf = fetchWithCsrf;
61
+ window.refreshCsrfToken = refreshCsrfToken;
62
+ if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", () => {
63
+ refreshCsrfToken();
64
+ });
65
+ else refreshCsrfToken();
66
+ }
67
+
68
+ //#endregion
1
69
  //#region src/runtime/actions.ts
2
70
  function createServerReference(functionName, moduleId, exportName) {
3
71
  return async (...args) => {
@@ -12,7 +80,7 @@ function createServerReference(functionName, moduleId, exportName) {
12
80
  }
13
81
  return arg;
14
82
  });
15
- const response = await fetch("/api/rsc/action", {
83
+ const response = await (typeof window !== "undefined" && window.fetchWithCsrf ? window.fetchWithCsrf : fetch)("/api/rsc/action", {
16
84
  method: "POST",
17
85
  headers: { "Content-Type": "application/json" },
18
86
  body: JSON.stringify({
@@ -86,6 +154,19 @@ function createFormAction(moduleId, exportName, action) {
86
154
  exportNameInput.name = "__export_name";
87
155
  exportNameInput.value = exportName;
88
156
  form.appendChild(exportNameInput);
157
+ if (typeof window !== "undefined" && window.getCsrfToken) {
158
+ const csrfToken = window.getCsrfToken();
159
+ if (csrfToken) {
160
+ let csrfInput = form.querySelector("input[name=\"__csrf_token\"]");
161
+ if (!csrfInput) {
162
+ csrfInput = document.createElement("input");
163
+ csrfInput.type = "hidden";
164
+ csrfInput.name = "__csrf_token";
165
+ form.appendChild(csrfInput);
166
+ }
167
+ csrfInput.value = csrfToken;
168
+ }
169
+ }
89
170
  form.action = "/api/rsc/form-action";
90
171
  form.method = "POST";
91
172
  return enhanceFormWithAction(form, action, options);
@@ -1073,7 +1073,7 @@ function ClientRouter({ children, manifest, initialRoute }) {
1073
1073
  };
1074
1074
  if (options.replace) window.history.replaceState(historyState, "", targetPath);
1075
1075
  else window.history.pushState(historyState, "", targetPath);
1076
- const fetchUrl = window.location.origin + targetPath;
1076
+ const fetchUrl = (window.location.origin.includes(":5173") ? "http://localhost:3000" : window.location.origin) + targetPath;
1077
1077
  const response = await fetch(fetchUrl, {
1078
1078
  headers: { Accept: "text/x-component" },
1079
1079
  signal: abortController.signal
@@ -1751,7 +1751,7 @@ function rariRouter(options = {}) {
1751
1751
  const outDir = path.resolve(root, opts.outDir);
1752
1752
  await promises.mkdir(outDir, { recursive: true });
1753
1753
  await promises.writeFile(path.join(outDir, "app-routes.json"), manifestContent, "utf-8");
1754
- const { generateLoadingComponentMap, getLoadingComponentMapPath } = await import("./loading-component-map-Db2B5rLX.mjs");
1754
+ const { generateLoadingComponentMap, getLoadingComponentMapPath } = await import("./loading-component-map-DP2Hh1ka.mjs");
1755
1755
  const loadingMapCode = generateLoadingComponentMap({
1756
1756
  appDir: opts.appDir,
1757
1757
  loadingComponents: manifest.loading
@@ -1882,7 +1882,7 @@ function rariRouter(options = {}) {
1882
1882
  });
1883
1883
  try {
1884
1884
  const manifest = JSON.parse(cachedManifestContent);
1885
- const { generateLoadingComponentMap } = await import("./loading-component-map-Db2B5rLX.mjs");
1885
+ const { generateLoadingComponentMap } = await import("./loading-component-map-DP2Hh1ka.mjs");
1886
1886
  const loadingMapCode = generateLoadingComponentMap({
1887
1887
  appDir: opts.appDir,
1888
1888
  loadingComponents: manifest.loading
@@ -2890,6 +2890,24 @@ const ${componentName$1} = registerClientReference(
2890
2890
  await handleServerComponentHMR(filePath);
2891
2891
  } else setTimeout(discoverAndRegisterComponents, 1e3);
2892
2892
  });
2893
+ server.middlewares.use("/app-routes.json", async (req, res) => {
2894
+ try {
2895
+ const manifestPath = path.join(server.config.root, "dist", "app-routes.json");
2896
+ if (fs.existsSync(manifestPath)) {
2897
+ const manifestContent = await fs.promises.readFile(manifestPath, "utf-8");
2898
+ res.statusCode = 200;
2899
+ res.setHeader("Content-Type", "application/json");
2900
+ res.setHeader("Cache-Control", "no-cache");
2901
+ res.end(manifestContent);
2902
+ } else {
2903
+ res.statusCode = 404;
2904
+ res.end("Manifest not found");
2905
+ }
2906
+ } catch (error) {
2907
+ res.statusCode = 500;
2908
+ res.end(`Error reading manifest: ${error instanceof Error ? error.message : String(error)}`);
2909
+ }
2910
+ });
2893
2911
  server.middlewares.use("/api/vite/hmr-transform", async (req, res) => {
2894
2912
  if (req.method !== "POST") {
2895
2913
  res.statusCode = 405;
package/dist/vite.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { a as headers, i as rariRouter, n as defineRariOptions, o as RariResponse, r as rari, t as defineRariConfig } from "./vite-CT18_z0c.mjs";
1
+ import { a as headers, i as rariRouter, n as defineRariOptions, o as RariResponse, r as rari, t as defineRariConfig } from "./vite-S1XOJqX6.mjs";
2
2
  import { i as writeManifest, n as generateAppRouteManifest, r as loadManifest, t as AppRouteGenerator } from "./app-routes-BjA_L5R4.mjs";
3
- import { c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, m as extractServerPropsWithCache, p as extractServerProps, u as clearPropsCache } from "./runtime-client-CGCu6fmO.mjs";
4
- import "./loading-component-map-UZ-MQYv0.mjs";
3
+ import { c as createHttpRuntimeClient, d as clearPropsCacheForComponent, f as extractMetadata, g as hasServerSideDataFetching, h as extractStaticParams, i as HttpRuntimeClient, m as extractServerPropsWithCache, p as extractServerProps, u as clearPropsCache } from "./runtime-client-CeW5R9VK.mjs";
4
+ import "./loading-component-map-SF6GiuGb.mjs";
5
5
  import "./server-build-Cvj5EwXx.mjs";
6
6
 
7
7
  export { AppRouteGenerator, HttpRuntimeClient, RariResponse, clearPropsCache, clearPropsCacheForComponent, createHttpRuntimeClient, defineRariConfig, defineRariOptions, extractMetadata, extractServerProps, extractServerPropsWithCache, extractStaticParams, generateAppRouteManifest, hasServerSideDataFetching, headers, loadManifest, rari, rariRouter, writeManifest };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rari",
3
3
  "type": "module",
4
- "version": "0.5.9",
4
+ "version": "0.5.11",
5
5
  "description": "Runtime Accelerated Rendering Infrastructure (Rari)",
6
6
  "author": "Ryan Skinner",
7
7
  "license": "MIT",
@@ -89,19 +89,19 @@
89
89
  "picocolors": "^1.1.1"
90
90
  },
91
91
  "optionalDependencies": {
92
- "rari-darwin-arm64": "0.5.5",
93
- "rari-darwin-x64": "0.5.5",
94
- "rari-linux-arm64": "0.5.5",
95
- "rari-linux-x64": "0.5.5",
96
- "rari-win32-x64": "0.5.5"
92
+ "rari-darwin-arm64": "0.5.6",
93
+ "rari-darwin-x64": "0.5.6",
94
+ "rari-linux-arm64": "0.5.6",
95
+ "rari-linux-x64": "0.5.6",
96
+ "rari-win32-x64": "0.5.6"
97
97
  },
98
98
  "devDependencies": {
99
- "@types/node": "^24.10.1",
99
+ "@types/node": "^24.10.2",
100
100
  "@types/react": "^19.2.7",
101
101
  "@typescript/native-preview": "7.0.0-dev.20251203.1",
102
102
  "chokidar": "^4.0.3",
103
103
  "eslint": "^9.39.1",
104
- "oxlint": "^1.31.0",
104
+ "oxlint": "^1.32.0",
105
105
  "rolldown-vite": "^7.2.10",
106
106
  "tsdown": "^0.15.12"
107
107
  }
@@ -286,7 +286,10 @@ export function ClientRouter({ children, manifest, initialRoute }: ClientRouterP
286
286
  )
287
287
  }
288
288
 
289
- const fetchUrl = window.location.origin + targetPath
289
+ const rariServerUrl = window.location.origin.includes(':5173')
290
+ ? 'http://localhost:3000'
291
+ : window.location.origin
292
+ const fetchUrl = rariServerUrl + targetPath
290
293
 
291
294
  const response = await fetch(fetchUrl, {
292
295
  headers: { Accept: 'text/x-component' },
@@ -32,7 +32,7 @@ ${moduleEntries.join(',\n')}
32
32
  }
33
33
 
34
34
  if (typeof globalThis !== 'undefined') {
35
- globalThis.__rari_loading_components = loadingComponentModules
35
+ globalThis.__rari_loading_components = new Map(Object.entries(loadingComponentModules))
36
36
  }
37
37
  `
38
38
 
@@ -214,7 +214,14 @@ export function AppRouterProvider({ children, initialPayload, onNavigate }: AppR
214
214
  const processedProps = processProps(props, modules, layoutPath)
215
215
  return React.createElement(type, serverKey ? { ...processedProps, key: serverKey } : processedProps)
216
216
  }
217
- return rsc.map(child => rscToReact(child, modules, layoutPath))
217
+ return rsc.map((child, index) => {
218
+ const element = rscToReact(child, modules, layoutPath)
219
+ if (element && typeof element === 'object' && !element.key) {
220
+ // eslint-disable-next-line react/no-clone-element
221
+ return React.cloneElement(element, { key: index })
222
+ }
223
+ return element
224
+ })
218
225
  }
219
226
 
220
227
  return rsc
@@ -696,12 +703,24 @@ export function AppRouterProvider({ children, initialPayload, onNavigate }: AppR
696
703
  )
697
704
 
698
705
  if (hasMain) {
699
- newChildren = children.map((child: any) => cloneWithLoadingInjected(child))
706
+ newChildren = children.map((child: any, index: number) => {
707
+ const cloned = cloneWithLoadingInjected(child)
708
+
709
+ return cloned && typeof cloned === 'object' && !cloned.key
710
+ // eslint-disable-next-line react/no-clone-element
711
+ ? React.cloneElement(cloned, { key: child?.key || index })
712
+ : cloned
713
+ })
700
714
  }
701
715
  else {
702
- newChildren = children.map((child: any) => {
716
+ newChildren = children.map((child: any, index: number) => {
703
717
  if (child && typeof child === 'object') {
704
- return cloneWithLoadingInjected(child)
718
+ const cloned = cloneWithLoadingInjected(child)
719
+
720
+ return cloned && !cloned.key
721
+ // eslint-disable-next-line react/no-clone-element
722
+ ? React.cloneElement(cloned, { key: child.key || index })
723
+ : cloned
705
724
  }
706
725
  return child
707
726
  })
@@ -739,7 +758,7 @@ export function AppRouterProvider({ children, initialPayload, onNavigate }: AppR
739
758
  if (rscPayload?.element) {
740
759
  contentToRender = injectLoadingIntoLayout(rscPayload.element, loadingComponentElement)
741
760
  }
742
- else {
761
+ else if (loadingComponentElement) {
743
762
  contentToRender = loadingComponentElement
744
763
  }
745
764
  }
@@ -1,3 +1,5 @@
1
+ import './csrf'
2
+
1
3
  export interface ServerActionResponse {
2
4
  success: boolean
3
5
  result?: any
@@ -29,7 +31,11 @@ export function createServerReference(
29
31
  return arg
30
32
  })
31
33
 
32
- const response = await fetch('/api/rsc/action', {
34
+ const fetchFn = typeof window !== 'undefined' && (window as any).fetchWithCsrf
35
+ ? (window as any).fetchWithCsrf
36
+ : fetch
37
+
38
+ const response = await fetchFn('/api/rsc/action', {
33
39
  method: 'POST',
34
40
  headers: {
35
41
  'Content-Type': 'application/json',
@@ -150,6 +156,20 @@ export function createFormAction(
150
156
  exportNameInput.value = exportName
151
157
  form.appendChild(exportNameInput)
152
158
 
159
+ if (typeof window !== 'undefined' && (window as any).getCsrfToken) {
160
+ const csrfToken = (window as any).getCsrfToken()
161
+ if (csrfToken) {
162
+ let csrfInput = form.querySelector('input[name="__csrf_token"]') as HTMLInputElement
163
+ if (!csrfInput) {
164
+ csrfInput = document.createElement('input')
165
+ csrfInput.type = 'hidden'
166
+ csrfInput.name = '__csrf_token'
167
+ form.appendChild(csrfInput)
168
+ }
169
+ csrfInput.value = csrfToken
170
+ }
171
+ }
172
+
153
173
  form.action = '/api/rsc/form-action'
154
174
  form.method = 'POST'
155
175
 
@@ -0,0 +1,88 @@
1
+ export function getCsrfToken(): string | null {
2
+ if (typeof window === 'undefined')
3
+ return null
4
+ const meta = document.querySelector('meta[name="csrf-token"]')
5
+ return meta ? meta.getAttribute('content') : null
6
+ }
7
+
8
+ export async function refreshCsrfToken(): Promise<boolean> {
9
+ if (typeof window === 'undefined')
10
+ return false
11
+
12
+ try {
13
+ const response = await fetch('/api/rsc/csrf-token')
14
+ if (!response.ok) {
15
+ console.warn('Failed to refresh CSRF token:', response.status)
16
+ return false
17
+ }
18
+ const data = await response.json()
19
+ if (data.token) {
20
+ let meta = document.querySelector('meta[name="csrf-token"]')
21
+ if (!meta) {
22
+ meta = document.createElement('meta')
23
+ meta.setAttribute('name', 'csrf-token')
24
+ document.head.appendChild(meta)
25
+ }
26
+ meta.setAttribute('content', data.token)
27
+ return true
28
+ }
29
+ return false
30
+ }
31
+ catch (error) {
32
+ console.error('Error refreshing CSRF token:', error)
33
+ return false
34
+ }
35
+ }
36
+
37
+ export async function fetchWithCsrf(
38
+ url: string,
39
+ options: RequestInit = {},
40
+ ): Promise<Response> {
41
+ let token = getCsrfToken()
42
+
43
+ if (!token) {
44
+ await refreshCsrfToken()
45
+ token = getCsrfToken()
46
+ }
47
+
48
+ const headers = new Headers(options.headers)
49
+ if (token) {
50
+ headers.set('X-CSRF-Token', token)
51
+ }
52
+
53
+ const response = await fetch(url, {
54
+ ...options,
55
+ headers,
56
+ })
57
+
58
+ if (response.status === 403 && url.includes('/api/rsc/')) {
59
+ const refreshed = await refreshCsrfToken()
60
+ if (refreshed) {
61
+ const retryToken = getCsrfToken()
62
+ if (retryToken) {
63
+ headers.set('X-CSRF-Token', retryToken)
64
+ return fetch(url, {
65
+ ...options,
66
+ headers,
67
+ })
68
+ }
69
+ }
70
+ }
71
+
72
+ return response
73
+ }
74
+
75
+ if (typeof window !== 'undefined') {
76
+ ;(window as any).getCsrfToken = getCsrfToken
77
+ ;(window as any).fetchWithCsrf = fetchWithCsrf
78
+ ;(window as any).refreshCsrfToken = refreshCsrfToken
79
+
80
+ if (document.readyState === 'loading') {
81
+ document.addEventListener('DOMContentLoaded', () => {
82
+ refreshCsrfToken()
83
+ })
84
+ }
85
+ else {
86
+ refreshCsrfToken()
87
+ }
88
+ }
@@ -62,7 +62,7 @@ export async function renderApp() {
62
62
  if (!manifest) {
63
63
  try {
64
64
  const manifestUrl = window.location.origin.includes(':5173')
65
- ? 'http://localhost:3000/app-routes.json'
65
+ ? '/app-routes.json'
66
66
  : '/app-routes.json'
67
67
 
68
68
  const manifestResponse = await fetch(manifestUrl, {
@@ -885,7 +885,7 @@ function ServerComponentWrapper({
885
885
  let mounted = true
886
886
 
887
887
  if (prevPropsKeyRef.current !== propsKey) {
888
- // eslint-disable-next-line react-hooks/set-state-in-effect, react-hooks-extra/no-direct-set-state-in-use-effect
888
+ // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect
889
889
  setState({ data: null, loading: true, error: null })
890
890
  prevPropsKeyRef.current = propsKey
891
891
  }
package/src/vite/index.ts CHANGED
@@ -1162,6 +1162,27 @@ const ${componentName} = registerClientReference(
1162
1162
  }
1163
1163
  })
1164
1164
 
1165
+ server.middlewares.use('/app-routes.json', async (req, res) => {
1166
+ try {
1167
+ const manifestPath = path.join(server.config.root, 'dist', 'app-routes.json')
1168
+ if (fs.existsSync(manifestPath)) {
1169
+ const manifestContent = await fs.promises.readFile(manifestPath, 'utf-8')
1170
+ res.statusCode = 200
1171
+ res.setHeader('Content-Type', 'application/json')
1172
+ res.setHeader('Cache-Control', 'no-cache')
1173
+ res.end(manifestContent)
1174
+ }
1175
+ else {
1176
+ res.statusCode = 404
1177
+ res.end('Manifest not found')
1178
+ }
1179
+ }
1180
+ catch (error) {
1181
+ res.statusCode = 500
1182
+ res.end(`Error reading manifest: ${error instanceof Error ? error.message : String(error)}`)
1183
+ }
1184
+ })
1185
+
1165
1186
  server.middlewares.use('/api/vite/hmr-transform', async (req, res) => {
1166
1187
  if (req.method !== 'POST') {
1167
1188
  res.statusCode = 405