diff --git a/src/app/site/[site]/sitemap.xml/route.ts b/src/app/site/[site]/sitemap.xml/route.ts
new file mode 100644
index 00000000..cd116447
--- /dev/null
+++ b/src/app/site/[site]/sitemap.xml/route.ts
@@ -0,0 +1,60 @@
+import dayjs from "dayjs"
+import { NextRequest } from "next/server"
+
+import { QueryClient } from "@tanstack/react-query"
+
+import { getSiteLink } from "~/lib/helpers"
+import { NextServerResponse } from "~/lib/server-helper"
+import { PageVisibilityEnum } from "~/lib/types"
+import { fetchGetPagesBySite } from "~/queries/page.server"
+import { fetchGetSite } from "~/queries/site.server"
+
+export const GET = async (req: NextRequest) => {
+ const response = new NextServerResponse()
+
+ const queryClient = new QueryClient()
+ // http://localhost:2222/site/innei-4525/sitemap.xml
+ // http://innei-4525.localhost:2222/sitemap.xml
+ // find innei-5425 site handle by regexp
+ const domainOrSubdomain =
+ req.nextUrl.pathname.match(/\/site\/(.*)\/sitemap.xml/)?.[1] ||
+ req.headers.get("x-handle") ||
+ // http://innei-4525.localhost:2222/sitemap.xml
+ req.headers.get("host")?.split(".")[0] ||
+ ""
+
+ if (!domainOrSubdomain) {
+ return response.status(400).json({
+ message: "domainOrSubdomain is not validate",
+ })
+ }
+
+ const site = await fetchGetSite(domainOrSubdomain, queryClient)
+
+ const pages = await fetchGetPagesBySite(
+ {
+ characterId: site?.characterId,
+ type: "post",
+ visibility: PageVisibilityEnum.Published,
+ },
+ queryClient,
+ )
+
+ const link = getSiteLink({
+ subdomain: site?.handle || "",
+ })
+ return response.headers({
+ "Content-Type": "text/xml",
+ "Access-Control-Allow-Methods": "GET",
+ "Access-Control-Allow-Origin": "*",
+ }).text(`
+
+ ${pages.list?.map((page) => {
+ return `
+ ${link}/${page.metadata.content.slug}
+ ${dayjs(page.updatedAt).format("YYYY-MM-DD")}
+ `
+ }).join(`
+ `)}
+ `)
+}
diff --git a/src/lib/server-helper.ts b/src/lib/server-helper.ts
index 8dc094bf..839a2366 100644
--- a/src/lib/server-helper.ts
+++ b/src/lib/server-helper.ts
@@ -15,6 +15,7 @@ export const getQuery = (req: Request) => {
export class NextServerResponse {
#status: number = 200
+ #headers = new Headers()
constructor() {}
status(status: number) {
@@ -25,12 +26,9 @@ export class NextServerResponse {
json(data: any) {
const nextData = JSON.stringify(data)
- return new Response(nextData, {
- status: this.#status,
- headers: {
- "Content-Type": "application/json",
- },
- })
+ this.#headers.set("Content-Type", "application/json")
+
+ return new Response(nextData, this.makeResponseOptions())
}
send(data: any) {
@@ -42,11 +40,23 @@ export class NextServerResponse {
return this.json(data)
}
- return new Response(data, { status: this.#status })
+ return new Response(data, this.makeResponseOptions())
+ }
+
+ text(text: string) {
+ return new Response(text, this.makeResponseOptions())
}
end() {
- return new Response("", { status: this.#status })
+ return new Response("", this.makeResponseOptions())
+ }
+
+ headers(headers: Record) {
+ for (const [key, value] of Object.entries(headers)) {
+ this.#headers.set(key, value)
+ }
+
+ return this
}
rss(data: any, format = "json") {
@@ -72,4 +82,11 @@ export class NextServerResponse {
})
}
}
+
+ private makeResponseOptions() {
+ return {
+ status: this.#status,
+ headers: this.#headers,
+ }
+ }
}
diff --git a/src/middleware.ts b/src/middleware.ts
index 4a0f2b2d..ea0f8f2a 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -56,8 +56,7 @@ export default async function middleware(req: NextRequest) {
pathname.match(/^\/(workbox|worker|fallback)-\w+\.js(\.map)?$/) ||
pathname === "/sw.js" ||
pathname === "/sw.js.map" ||
- pathname === "/robots.txt" ||
- pathname === "/sitemap.xml"
+ pathname === "/robots.txt"
) {
return NextResponse.next()
}
@@ -84,6 +83,7 @@ export default async function middleware(req: NextRequest) {
const requestHeaders = new Headers(req.headers)
requestHeaders.set("x-pathname", req.nextUrl.pathname)
requestHeaders.set("x-search", req.nextUrl.search)
+ requestHeaders.set("x-handle", tenant.subdomain || "")
if (tenant?.subdomain) {
const url = req.nextUrl.clone()