parent
cf2ea84bc9
commit
b1c8d4f910
@ -7,6 +7,7 @@ const nextConfig: NextConfig = {
|
||||
NEXT_PUBLIC_API_URL: "https://api.app.witlab.us",
|
||||
// NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
|
||||
NEXT_PUBLIC_APP_URL: "https://app.witlab.us",
|
||||
NEXT_PUBLIC_AUTH_REDIRECT_URL: "https://witlab.us",
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
|
||||
@ -1,8 +1,50 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import createMiddleware from "next-intl/middleware";
|
||||
|
||||
import { routing } from "./i18n/routing";
|
||||
import { ROUTES } from "./shared/constants/client-routes";
|
||||
|
||||
export default createMiddleware(routing);
|
||||
const publicRoutes = [
|
||||
ROUTES.authCallback(),
|
||||
ROUTES.paymentSuccess(),
|
||||
ROUTES.paymentFailed(),
|
||||
];
|
||||
|
||||
function isPublicRoute(pathname: string): boolean {
|
||||
const pathWithoutLocale = pathname.replace(/^\/[a-z]{2}\//, "/");
|
||||
return publicRoutes.some(route => pathWithoutLocale.startsWith(route));
|
||||
}
|
||||
|
||||
function createAuthMiddleware() {
|
||||
return async function authMiddleware(request: NextRequest) {
|
||||
const pathname = request.nextUrl.pathname;
|
||||
|
||||
if (isPublicRoute(pathname)) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
const token = request.cookies.get("accessToken")?.value;
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.redirect(
|
||||
process.env.NEXT_PUBLIC_AUTH_REDIRECT_URL || ""
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.next();
|
||||
};
|
||||
}
|
||||
|
||||
const intlMiddleware = createMiddleware(routing);
|
||||
|
||||
export default async function middleware(request: NextRequest) {
|
||||
const authResponse = await createAuthMiddleware()(request);
|
||||
if (authResponse.status !== 200) {
|
||||
return authResponse;
|
||||
}
|
||||
|
||||
return intlMiddleware(request);
|
||||
}
|
||||
|
||||
export const config = {
|
||||
// Match all pathnames except for
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getServerAccessToken } from "../auth/token";
|
||||
@ -18,6 +19,7 @@ type RequestOpts = Omit<RequestInit, "method" | "body"> & {
|
||||
query?: Record<string, unknown>; // query-string
|
||||
schema?: z.ZodTypeAny; // runtime validation
|
||||
revalidate?: number;
|
||||
skipAuthRedirect?: boolean;
|
||||
};
|
||||
|
||||
class HttpClient {
|
||||
@ -44,7 +46,14 @@ class HttpClient {
|
||||
body?: unknown,
|
||||
errorMessage?: string
|
||||
): Promise<T> {
|
||||
const { tags = [], schema, query, revalidate = 300, ...rest } = opts;
|
||||
const {
|
||||
tags = [],
|
||||
schema,
|
||||
query,
|
||||
revalidate = 300,
|
||||
skipAuthRedirect = false,
|
||||
...rest
|
||||
} = opts;
|
||||
|
||||
const headers = new Headers();
|
||||
const accessToken = await getServerAccessToken();
|
||||
@ -61,7 +70,12 @@ class HttpClient {
|
||||
|
||||
const payload = await res.json().catch(() => null);
|
||||
|
||||
if (!res.ok) throw new ApiError(res.status, payload, errorMessage);
|
||||
if (!res.ok) {
|
||||
if (res.status === 401 && !skipAuthRedirect) {
|
||||
redirect(process.env.NEXT_PUBLIC_AUTH_REDIRECT_URL || "");
|
||||
}
|
||||
throw new ApiError(res.status, payload, errorMessage);
|
||||
}
|
||||
|
||||
const data = payload as T;
|
||||
return schema ? schema.parse(data) : data;
|
||||
|
||||
@ -10,6 +10,9 @@ const createRoute = (segments: string[]): string => {
|
||||
export const ROUTES = {
|
||||
home: () => createRoute([]),
|
||||
|
||||
// Auth
|
||||
authCallback: () => createRoute(["auth", "callback"]),
|
||||
|
||||
// Breath
|
||||
breath: (id: string) => createRoute(["breath", id]),
|
||||
breathResult: (id: string, resultId: string) =>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user