Remove legacy [slug] pages that clashed with [id]/[slug] and handle old URLs via middleware redirects instead. Co-authored-by: Cursor <cursoragent@cursor.com>
70 lines
2.4 KiB
TypeScript
70 lines
2.4 KiB
TypeScript
import { NextResponse, type NextRequest } from "next/server";
|
|
import { slugifyFa } from "@/lib/slugify";
|
|
import { TENANT_DOMAIN } from "@/lib/meshkee";
|
|
|
|
const API_BASE = "https://api.meshkee.com/api/v1";
|
|
|
|
function canonicalProductPath(product: { id: string; nameFa: string }) {
|
|
return `/products/${product.id}/${encodeURIComponent(slugifyFa(product.nameFa))}`;
|
|
}
|
|
|
|
function canonicalBlogPath(post: { id: string; nameFa?: string; titleFa?: string; title?: string }) {
|
|
const title = post.nameFa || post.titleFa || post.title || "post";
|
|
return `/blog/${post.id}/${encodeURIComponent(slugifyFa(title))}`;
|
|
}
|
|
|
|
async function redirectLegacyProduct(slug: string, request: NextRequest) {
|
|
const res = await fetch(
|
|
`${API_BASE}/tenants/${TENANT_DOMAIN}/products/${encodeURIComponent(slug)}`,
|
|
{ next: { revalidate: 300 } },
|
|
);
|
|
if (!res.ok) return null;
|
|
const data = (await res.json()) as { product?: { id: string; nameFa: string } };
|
|
const product = data.product;
|
|
if (!product) return null;
|
|
return NextResponse.redirect(new URL(canonicalProductPath(product), request.url), 308);
|
|
}
|
|
|
|
async function redirectLegacyBlog(slug: string, request: NextRequest) {
|
|
const res = await fetch(
|
|
`${API_BASE}/tenants/${TENANT_DOMAIN}/blogs/${encodeURIComponent(slug)}`,
|
|
{ next: { revalidate: 300 } },
|
|
);
|
|
if (!res.ok) return null;
|
|
const data = (await res.json()) as {
|
|
blog?: { id: string; nameFa?: string; titleFa?: string; title?: string };
|
|
post?: { id: string; nameFa?: string; titleFa?: string; title?: string };
|
|
};
|
|
const post = data.blog ?? data.post;
|
|
if (!post) return null;
|
|
return NextResponse.redirect(new URL(canonicalBlogPath(post), request.url), 308);
|
|
}
|
|
|
|
export async function middleware(request: NextRequest) {
|
|
const { pathname } = request.nextUrl;
|
|
|
|
const productMatch = pathname.match(/^\/products\/([^/]+)$/);
|
|
if (productMatch) {
|
|
const segment = decodeURIComponent(productMatch[1]);
|
|
if (segment !== "category" && !/^\d+$/.test(segment)) {
|
|
const redirect = await redirectLegacyProduct(segment, request);
|
|
if (redirect) return redirect;
|
|
}
|
|
}
|
|
|
|
const blogMatch = pathname.match(/^\/blog\/([^/]+)$/);
|
|
if (blogMatch) {
|
|
const segment = decodeURIComponent(blogMatch[1]);
|
|
if (!/^\d+$/.test(segment)) {
|
|
const redirect = await redirectLegacyBlog(segment, request);
|
|
if (redirect) return redirect;
|
|
}
|
|
}
|
|
|
|
return NextResponse.next();
|
|
}
|
|
|
|
export const config = {
|
|
matcher: ["/products/:path*", "/blog/:path*"],
|
|
};
|