/opt/canhelp/apps/web/src/app
NameSizeModeActions
(auth)/-0755rm
admin/-0755rm
become-specialist/-0755rm
chat/-0755rm
dashboard/-0755rm
delete-account/-0755rm
favorites/-0755rm
maintenance/-0755rm
notifications/-0755rm
payment/-0755rm
pricing/-0755rm
privacy/-0755rm
profile/-0755rm
schedule/-0755rm
site/-0755rm
specialist-setup/-0755rm
specialist-tasks/-0755rm
specialists/-0755rm
support/-0755rm
tasks/-0755rm
users/-0755rm
apple-icon.png626050644editdlrm
globals.css95430644editdlrm
icon.png626050644editdlrm
icon.svg48820644editdlrm
layout.tsx43450644editdlrm
not-found.tsx5500644editdlrm
page.tsx243370644editdlrm
robots.ts7890644editdlrm
sitemap.ts36640644editdlrm
Edit: /opt/canhelp/apps/web/src/app/sitemap.ts (3664B)
import type { MetadataRoute } from 'next' function normalizeAppUrl(raw?: string): string { const fallback = 'http://localhost:3000' const base = (raw && raw.trim()) || fallback try { const url = new URL(base) if (url.hostname !== 'localhost' && url.protocol !== 'https:') { url.protocol = 'https:' } return url.toString().replace(/\/$/, '') } catch { return fallback } } const APP_URL = normalizeAppUrl(process.env.NEXT_PUBLIC_APP_URL) const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' const STATIC_ROUTES: MetadataRoute.Sitemap = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0, }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9, }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9, }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6, }, { url: `${APP_URL}/support`, changeFrequency: 'monthly', priority: 0.4, }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7, }, ] async function fetchAllTasks(): Promise { const entries: MetadataRoute.Sitemap = [] let page = 1 const limit = 100 try { while (true) { const res = await fetch( `${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }, ) if (!res.ok) break const json = await res.json() const tasks: { task: { id: string; updatedAt: string } }[] = json.data ?? [] for (const { task } of tasks) { entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8, }) } if (entries.length >= json.total || tasks.length < limit) break page++ } } catch { // silently skip if API is unavailable during build } return entries } async function fetchAllSpecialists(): Promise { const entries: MetadataRoute.Sitemap = [] let page = 1 const limit = 100 try { while (true) { const res = await fetch( `${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }, ) if (!res.ok) break const json = await res.json() const specialists: { id: string updatedAt?: string personalSiteSlug?: string | null }[] = json.data ?? [] for (const specialist of specialists) { entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75, }) if (specialist.personalSiteSlug) { entries.push({ url: `${APP_URL}/site/${specialist.personalSiteSlug}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.85, }) } } if (entries.length >= json.total || specialists.length < limit) break page++ } } catch { // silently skip if API is unavailable during build } return entries } export default async function sitemap(): Promise { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists(), ]) return [...STATIC_ROUTES, ...tasks, ...specialists] }