import fs from "node:fs"; import path from "node:path"; import { NextResponse } from "next/server"; import { WEBSITE_DOMAIN } from "@/lib/meshkee"; // Published for the Meshkee business dashboard's "Refresh" sitemap button — // see AI_PROMPT.md ("What the website must publish"). Meshkee's own nginx // proxy serves the actual /sitemap.xml (and the CMS-driven child sitemaps // like /sitemap-blogs.xml) from the API; this route only lists this app's // *static* public pages so the dashboard can fold them into the sitemap // index. Do not add app/sitemap.ts / app/robots.ts — those paths are owned // by the Meshkee proxy once this site is live on a Meshkee-managed domain. export const dynamic = "force-static"; // Route segments that never map to a crawlable public page: dynamic detail // pages (CMS-managed — Meshkee generates their own sitemap entries), and // this "meshkee/*" integration namespace itself. const EXCLUDE_SEGMENT = (segment) => segment.startsWith("[") || segment === "meshkee" || segment.startsWith("_"); // Per-path SEO weight. Anything not listed falls back to a sane default. const PAGE_META = { "/": { changefreq: "daily", priority: 1.0 }, "/services": { changefreq: "weekly", priority: 0.8 }, "/about-us": { changefreq: "monthly", priority: 0.6 }, "/blog": { changefreq: "daily", priority: 0.7 }, "/contact-us": { changefreq: "monthly", priority: 0.5 }, "/virtual-tour": { changefreq: "yearly", priority: 0.4 }, }; /** Scan app/ for `page.js` files and turn each into a public URL path. */ function scanStaticPages(dir, baseSegments = []) { const pages = []; let entries; try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return pages; } const hasPage = entries.some( (e) => e.isFile() && /^page\.(js|jsx|ts|tsx)$/.test(e.name) ); if (hasPage && !baseSegments.some(EXCLUDE_SEGMENT)) { const urlPath = "/" + baseSegments.join("/"); pages.push(urlPath === "/" ? "/" : urlPath.replace(/\/$/, "")); } for (const entry of entries) { if (!entry.isDirectory()) continue; // route groups "(name)" don't appear in the URL const isGroup = entry.name.startsWith("(") && entry.name.endsWith(")"); const nextSegments = isGroup ? baseSegments : [...baseSegments, entry.name]; if (EXCLUDE_SEGMENT(entry.name)) continue; pages.push(...scanStaticPages(path.join(dir, entry.name), nextSegments)); } return pages; } export async function GET() { const appDir = path.join(process.cwd(), "app"); const paths = scanStaticPages(appDir).sort( (a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b) ); const staticPages = paths.map((p) => ({ path: p, ...(PAGE_META[p] || { changefreq: "monthly", priority: 0.5 }), })); return NextResponse.json({ baseUrl: `https://${WEBSITE_DOMAIN}`, staticPages, }); }