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 +1 -1
- package/dist/index.mjs +3 -3
- package/dist/{loading-component-map-Db2B5rLX.mjs → loading-component-map-DP2Hh1ka.mjs} +1 -1
- package/dist/{loading-component-map-UZ-MQYv0.mjs → loading-component-map-SF6GiuGb.mjs} +1 -1
- package/dist/runtime/actions.mjs +82 -1
- package/dist/{runtime-client-CGCu6fmO.mjs → runtime-client-CeW5R9VK.mjs} +1 -1
- package/dist/{vite-CT18_z0c.mjs → vite-S1XOJqX6.mjs} +20 -2
- package/dist/vite.mjs +3 -3
- package/package.json +8 -8
- package/src/router/ClientRouter.tsx +4 -1
- package/src/router/loading-component-map.ts +1 -1
- package/src/runtime/AppRouterProvider.tsx +24 -5
- package/src/runtime/actions.ts +21 -1
- package/src/runtime/csrf.ts +88 -0
- package/src/runtime/entry-client.js +1 -1
- package/src/runtime/rsc-client-runtime.js +1 -1
- package/src/vite/index.ts +21 -0
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-
|
|
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-
|
|
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-
|
|
4
|
-
import "./loading-component-map-
|
|
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-
|
|
1
|
+
import { n as getLoadingComponentMapPath, t as generateLoadingComponentMap } from "./loading-component-map-SF6GiuGb.mjs";
|
|
2
2
|
|
|
3
3
|
export { generateLoadingComponentMap, getLoadingComponentMapPath };
|
package/dist/runtime/actions.mjs
CHANGED
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
4
|
-
import "./loading-component-map-
|
|
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.
|
|
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.
|
|
93
|
-
"rari-darwin-x64": "0.5.
|
|
94
|
-
"rari-linux-arm64": "0.5.
|
|
95
|
-
"rari-linux-x64": "0.5.
|
|
96
|
-
"rari-win32-x64": "0.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.
|
|
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.
|
|
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
|
|
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' },
|
|
@@ -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(
|
|
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) =>
|
|
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
|
-
|
|
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
|
}
|
package/src/runtime/actions.ts
CHANGED
|
@@ -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
|
|
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
|
-
? '
|
|
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
|
|
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
|