+
Redirect Kind
+
Test different redirect kinds via server actions:
+
+
+ );
+}
diff --git a/examples/file-router/redirect-actions.ts b/examples/file-router/redirect-actions.ts
new file mode 100644
index 00000000..42e57a8e
--- /dev/null
+++ b/examples/file-router/redirect-actions.ts
@@ -0,0 +1,23 @@
+"use server";
+
+import { redirect } from "@lazarv/react-server";
+
+export async function redirectNavigate() {
+ redirect("/about", 302, "navigate");
+}
+
+export async function redirectPush() {
+ redirect("/about", 302, "push");
+}
+
+export async function redirectLocation() {
+ redirect("/about", 302, "location");
+}
+
+export async function redirectLocationExternal() {
+ redirect("https://react-server.dev", 302, "location");
+}
+
+export async function redirectError() {
+ redirect("/about", 302, "error");
+}
diff --git a/examples/file-router/tsconfig.json b/examples/file-router/tsconfig.json
new file mode 100644
index 00000000..c9052503
--- /dev/null
+++ b/examples/file-router/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "strict": true,
+ "target": "ESNext",
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler"
+ },
+ "include": ["**/*.ts", "**/*.tsx"],
+ "exclude": ["**/*.js", "**/*.mjs", "node_modules"]
+}
diff --git a/packages/react-server/client/ClientProvider.jsx b/packages/react-server/client/ClientProvider.jsx
index a0f65dfa..e0464b27 100644
--- a/packages/react-server/client/ClientProvider.jsx
+++ b/packages/react-server/client/ClientProvider.jsx
@@ -525,19 +525,40 @@ export const streamOptions = ({
resolve(typeof value === "undefined" ? args[0] : value);
} catch (e) {
- const location = e?.digest?.startsWith("Location=")
- ? e.digest.slice(9)
- : res.headers.get("Location");
- if (location) {
+ let redirectLocation = null;
+ let redirectKind = "navigate";
+ if (e?.digest?.startsWith("Location=")) {
+ const digestValue = e.digest.slice(9);
+ const semicolonIndex = digestValue.indexOf(";");
+ if (semicolonIndex !== -1) {
+ redirectLocation = digestValue.slice(0, semicolonIndex);
+ const kindMatch = digestValue
+ .slice(semicolonIndex)
+ .match(/kind=([^;]+)/);
+ redirectKind = kindMatch?.[1] || "navigate";
+ } else {
+ redirectLocation = digestValue;
+ }
+ } else {
+ redirectLocation = res.headers.get("Location");
+ }
+ if (redirectLocation) {
+ if (redirectKind === "error") {
+ return reject(e);
+ }
+ if (redirectKind === "location") {
+ location.href = redirectLocation;
+ return resolve(args[0]);
+ }
const value = rsc.slice(0, -1);
- flightCache.set(`${outlet}:${location}`, value);
+ flightCache.set(`${outlet}:${redirectLocation}`, value);
flightCache.set(
- `${outlet}:${location}:timestamp`,
+ `${outlet}:${redirectLocation}:timestamp`,
Date.now()
);
- navigate(location, {
+ navigate(redirectLocation, {
outlet,
- replace: true,
+ push: redirectKind === "push",
fromCache: true,
});
return resolve(args[0]);
@@ -727,6 +748,7 @@ function getFlightResponse(url, options = {}) {
let chunks = 0;
let redirectTo = null;
+ let redirectKind = "navigate";
const reader = body.getReader();
abortController?.signal?.addEventListener(
@@ -743,9 +765,13 @@ function getFlightResponse(url, options = {}) {
if (value) {
if (!redirectTo) {
const decodedValue = decoder.decode(value);
- redirectTo = decodedValue.match(
- /1:E\{"digest":"Location=(?