1- import { statSync } from "fs" ;
2- import { join } from "path" ;
1+ import { statSync } from "node: fs" ;
2+ import { join } from "node: path" ;
33import type { MetadataRoute } from "next" ;
44
55import { getRegistryBaseUrl , source } from "@/lib/source" ;
@@ -15,88 +15,148 @@ function getFileLastModified(filePath: string): Date {
1515 }
1616}
1717
18- const sitemap = ( ) : MetadataRoute . Sitemap => {
18+ // feat: Validate URL format for sitemap
19+ function isValidUrl ( url : string ) : boolean {
20+ try {
21+ new URL ( url ) ;
22+ return true ;
23+ } catch {
24+ return false ;
25+ }
26+ }
27+
28+ // feat: Generate sitemap data for Next.js App Router with enhanced error handling
29+ function generateSitemapData ( ) : MetadataRoute . Sitemap {
1930 const baseUrl = getRegistryBaseUrl ( ) ;
2031
32+ // feat: Validate base URL
33+ if ( ! isValidUrl ( baseUrl ) ) {
34+ console . error ( "Invalid base URL for sitemap:" , baseUrl ) ;
35+ return [ ] ;
36+ }
37+
2138 const sitemap : MetadataRoute . Sitemap = [ ] ;
2239
23- sitemap . push ( {
24- url : `${ baseUrl } /` ,
25- lastModified : new Date ( ) ,
26- changeFrequency : "weekly" ,
27- priority : 1 ,
28- } ) ;
40+ // Add homepage with validation
41+ const homepageUrl = `${ baseUrl } /` ;
42+ if ( isValidUrl ( homepageUrl ) ) {
43+ sitemap . push ( {
44+ url : homepageUrl ,
45+ lastModified : new Date ( ) ,
46+ changeFrequency : "weekly" ,
47+ priority : 1 ,
48+ } ) ;
49+ }
2950
51+ // Add documentation pages with enhanced error handling
3052 try {
3153 const pages = source . getPages ( ) ;
32- pages . forEach ( ( page ) => {
33- // feat: Try to get actual file modification date
34- let lastModified = new Date ( ) ;
35- if ( page . data . lastModified ) {
36- lastModified = new Date ( page . data . lastModified ) ;
37- } else {
38- // Try to get file modification date from content directory
39- try {
40- const contentPath = join (
41- process . cwd ( ) ,
42- "content" ,
43- "docs" ,
44- `${ page . url . replace ( "/docs/" , "" ) } .mdx` ,
45- ) ;
46- lastModified = getFileLastModified ( contentPath ) ;
47- } catch {
48- // Fallback to current date
49- lastModified = new Date ( ) ;
54+ if ( Array . isArray ( pages ) ) {
55+ pages . forEach ( ( page ) => {
56+ if ( ! page ?. url ) return ;
57+
58+ // feat: Try to get actual file modification date
59+ let lastModified = new Date ( ) ;
60+ if ( page . data ?. lastModified ) {
61+ try {
62+ lastModified = new Date ( page . data . lastModified ) ;
63+ // Validate date
64+ if ( Number . isNaN ( lastModified . getTime ( ) ) ) {
65+ lastModified = new Date ( ) ;
66+ }
67+ } catch {
68+ lastModified = new Date ( ) ;
69+ }
70+ } else {
71+ // Try to get file modification date from content directory
72+ try {
73+ const contentPath = join (
74+ process . cwd ( ) ,
75+ "content" ,
76+ "docs" ,
77+ `${ page . url . replace ( "/docs/" , "" ) } .mdx` ,
78+ ) ;
79+ lastModified = getFileLastModified ( contentPath ) ;
80+ } catch {
81+ // Fallback to current date
82+ lastModified = new Date ( ) ;
83+ }
5084 }
51- }
5285
53- sitemap . push ( {
54- url : `${ baseUrl } ${ page . url } ` ,
55- lastModified,
56- changeFrequency : "monthly" ,
57- priority : 0.9 ,
86+ const pageUrl = `${ baseUrl } ${ page . url } ` ;
87+ if ( isValidUrl ( pageUrl ) ) {
88+ sitemap . push ( {
89+ url : pageUrl ,
90+ lastModified,
91+ changeFrequency : "monthly" ,
92+ priority : 0.9 ,
93+ } ) ;
94+ }
5895 } ) ;
59- } ) ;
96+ }
6097 } catch ( error ) {
61- console . warn ( "Error generating sitemap" , error ) ;
98+ console . warn ( "Error generating sitemap for pages: " , error ) ;
6299 }
63100
64- Object . keys ( Index ) . forEach ( ( componentName ) => {
65- if ( componentName . endsWith ( "-demo" ) ) return ;
101+ // Add component registry JSON files with validation
102+ try {
103+ if ( Index && typeof Index === "object" ) {
104+ Object . keys ( Index ) . forEach ( ( componentName ) => {
105+ if ( componentName . endsWith ( "-demo" ) || ! componentName ) return ;
66106
67- // feat: Component registry JSON file with proper modification date
68- const componentPath = join (
69- process . cwd ( ) ,
70- "public" ,
71- "r" ,
72- `${ componentName } .json` ,
73- ) ;
74- const lastModified = getFileLastModified ( componentPath ) ;
107+ // feat: Component registry JSON file with proper modification date
108+ const componentPath = join (
109+ process . cwd ( ) ,
110+ "public" ,
111+ "r" ,
112+ `${ componentName } .json` ,
113+ ) ;
114+ const lastModified = getFileLastModified ( componentPath ) ;
75115
76- sitemap . push ( {
77- url : `${ baseUrl } /r/${ componentName } .json` ,
78- lastModified,
79- changeFrequency : "monthly" ,
80- priority : 0.6 ,
81- } ) ;
82- } ) ;
116+ const componentUrl = `${ baseUrl } /r/${ componentName } .json` ;
117+ if ( isValidUrl ( componentUrl ) ) {
118+ sitemap . push ( {
119+ url : componentUrl ,
120+ lastModified,
121+ changeFrequency : "monthly" ,
122+ priority : 0.6 ,
123+ } ) ;
124+ }
125+ } ) ;
126+ }
127+ } catch ( error ) {
128+ console . warn ( "Error generating sitemap for components:" , error ) ;
129+ }
83130
84- sitemap . push (
131+ // Add API endpoints and other important pages with validation
132+ const additionalUrls = [
85133 {
86134 url : `${ baseUrl } /api/search` ,
87- lastModified : new Date ( ) ,
88- changeFrequency : "weekly" ,
135+ changeFrequency : "weekly" as const ,
89136 priority : 0.7 ,
90137 } ,
91138 {
92139 url : `${ baseUrl } /llms-full.txt` ,
93- lastModified : new Date ( ) ,
94- changeFrequency : "weekly" ,
140+ changeFrequency : "weekly" as const ,
95141 priority : 0.8 ,
96142 } ,
97- ) ;
143+ ] ;
144+
145+ additionalUrls . forEach ( ( { url, changeFrequency, priority } ) => {
146+ if ( isValidUrl ( url ) ) {
147+ sitemap . push ( {
148+ url,
149+ lastModified : new Date ( ) ,
150+ changeFrequency,
151+ priority,
152+ } ) ;
153+ }
154+ } ) ;
98155
99156 return sitemap ;
100- } ;
157+ }
101158
102- export default sitemap ;
159+ // feat: Export sitemap function for Next.js App Router
160+ export default function sitemap ( ) : MetadataRoute . Sitemap {
161+ return generateSitemapData ( ) ;
162+ }
0 commit comments