@@ -3,236 +3,148 @@ import { SITE_URL } from '@/app/util/constants';
33import { getPosts } from '@/lib/blog-query' ;
44import { source } from '@/lib/source' ;
55
6- // Regex pattern for matching integration pages
7- const integrationPattern = / \/ d o c s \/ i n t e g r a t i o n s \/ ( .+ ) / ;
8-
9- // Priority mapping for different page types
10- const priorityMap : Record < string , number > = {
11- '/docs' : 1.0 ,
12- '/docs/getting-started' : 0.9 ,
13- '/docs/sdk' : 0.9 ,
14- '/docs/comparisons/databuddy-vs-google-analytics' : 0.95 ,
15- '/docs/compliance/gdpr-compliance-guide' : 0.9 ,
16- '/docs/performance/core-web-vitals-guide' : 0.85 ,
17- '/docs/dashboard' : 0.8 ,
18- '/docs/security' : 0.8 ,
19- '/docs/integrations' : 0.8 ,
20- '/docs/api' : 0.7 ,
21- '/blog' : 0.8 ,
22- '/api' : 0.7 ,
23- '/contributors' : 0.8 ,
24- '/privacy' : 0.5 ,
25- '/llms.txt' : 0.4 ,
26- } ;
27-
28- // Change frequency mapping
29- const changeFrequencyMap : Record < string , 'weekly' | 'monthly' | 'yearly' > = {
30- '/docs' : 'weekly' ,
31- '/docs/getting-started' : 'weekly' ,
32- '/docs/sdk' : 'weekly' ,
33- '/docs/comparisons/databuddy-vs-google-analytics' : 'monthly' ,
34- '/docs/compliance/gdpr-compliance-guide' : 'monthly' ,
35- '/docs/performance/core-web-vitals-guide' : 'monthly' ,
36- '/docs/dashboard' : 'weekly' ,
37- '/docs/security' : 'monthly' ,
38- '/docs/integrations' : 'weekly' ,
39- '/docs/api' : 'monthly' ,
40- '/blog' : 'monthly' ,
41- '/api' : 'monthly' ,
42- '/contributors' : 'monthly' ,
43- '/privacy' : 'yearly' ,
44- '/llms.txt' : 'weekly' ,
45- } ;
6+ const priorityRules = [
7+ { pattern : '/docs' , priority : 1.0 } ,
8+ { pattern : '/comparisons/databuddy-vs-google-analytics' , priority : 0.95 } ,
9+ { pattern : '/getting-started' , priority : 0.9 } ,
10+ { pattern : '/sdk' , priority : 0.9 } ,
11+ { pattern : '/compliance/gdpr' , priority : 0.85 } ,
12+ { pattern : '/performance/core-web-vitals' , priority : 0.85 } ,
13+ { pattern : '/integrations/react' , priority : 0.8 } ,
14+ { pattern : '/integrations/nextjs' , priority : 0.8 } ,
15+ { pattern : '/dashboard' , priority : 0.8 } ,
16+ { pattern : '/security' , priority : 0.8 } ,
17+ { pattern : '/contributors' , priority : 0.8 } ,
18+ { pattern : '/pricing' , priority : 0.8 } ,
19+ { pattern : '/integrations/' , priority : 0.7 } ,
20+ { pattern : '/blog' , priority : 0.7 } ,
21+ { pattern : '/api' , priority : 0.7 } ,
22+ { pattern : '/roadmap' , priority : 0.6 } ,
23+ { pattern : '/sponsors' , priority : 0.6 } ,
24+ { pattern : '/ambassadors' , priority : 0.6 } ,
25+ { pattern : '/privacy' , priority : 0.5 } ,
26+ { pattern : '/terms' , priority : 0.5 } ,
27+ { pattern : '/llms.txt' , priority : 0.4 } ,
28+ ] ;
4629
4730function getPriority ( url : string ) : number {
48- return priorityMap [ url ] || ( url . includes ( '/integrations/' ) ? 0.7 : 0.6 ) ;
49- }
50-
51- function getChangeFrequency ( url : string ) : 'weekly' | 'monthly' | 'yearly' {
52- return changeFrequencyMap [ url ] || 'weekly' ;
53- }
54-
55- function createSitemapEntry (
56- url : string ,
57- baseUrl : string ,
58- lastModified : Date ,
59- priority ?: number ,
60- changeFrequency ?: 'weekly' | 'monthly' | 'yearly'
61- ) : MetadataRoute . Sitemap [ 0 ] {
62- return {
63- url : `${ baseUrl } ${ url } ` ,
64- lastModified,
65- changeFrequency : changeFrequency || getChangeFrequency ( url ) ,
66- priority : priority || getPriority ( url ) ,
67- } ;
68- }
69-
70- function processIntegrationPages ( entries : MetadataRoute . Sitemap ) : void {
71- for ( const entry of entries ) {
72- const match = entry . url . match ( integrationPattern ) ;
73- if ( match ) {
74- const integrationName = match [ 1 ] ;
75- if ( integrationName === 'react' || integrationName === 'nextjs' ) {
76- entry . priority = 0.8 ;
77- }
31+ for ( const rule of priorityRules ) {
32+ if (
33+ url === rule . pattern ||
34+ ( rule . pattern !== url && url . includes ( rule . pattern ) )
35+ ) {
36+ return rule . priority ;
7837 }
7938 }
39+ return 0.6 ;
8040}
8141
82- function processSourcePages (
83- pages : Array < { url : string } > ,
84- baseUrl : string ,
85- lastModified : Date
86- ) : MetadataRoute . Sitemap {
87- return pages . map ( ( page ) =>
88- createSitemapEntry ( page . url , baseUrl , lastModified )
89- ) ;
90- }
91-
92- function processNonDocPages (
93- pages : string [ ] ,
94- baseUrl : string ,
95- lastModified : Date
96- ) : MetadataRoute . Sitemap {
97- return pages . map ( ( page ) =>
98- createSitemapEntry ( page , baseUrl , lastModified , 0.5 , 'yearly' )
99- ) ;
100- }
101-
102- function processBlogPages ( baseUrl : string ) : Promise < MetadataRoute . Sitemap > {
103- return getPosts ( )
104- . then ( ( data ) => {
105- if ( 'error' in data || ! data ?. posts ) {
106- return [ ] ;
107- }
108-
109- return data . posts . map ( ( post ) => ( {
110- url : `${ baseUrl } /blog/${ post . slug } ` ,
111- lastModified : new Date ( post . publishedAt ) ,
112- changeFrequency : 'monthly' as const ,
113- priority : 0.8 ,
114- } ) ) ;
115- } )
116- . catch ( ( error ) => {
117- console . warn ( 'Failed to fetch blog posts for sitemap:' , error ) ;
118- return [ ] ;
119- } ) ;
120- }
121-
122- function getFallbackEntries ( ) : Array < {
123- url : string ;
124- priority : number ;
125- changeFrequency : 'weekly' | 'monthly' | 'yearly' ;
126- } > {
127- return [
128- { url : '/docs' , priority : 1.0 , changeFrequency : 'weekly' } ,
129- { url : '/docs/getting-started' , priority : 0.9 , changeFrequency : 'weekly' } ,
130- { url : '/docs/sdk' , priority : 0.9 , changeFrequency : 'weekly' } ,
131- { url : '/docs/dashboard' , priority : 0.8 , changeFrequency : 'weekly' } ,
132- { url : '/docs/security' , priority : 0.8 , changeFrequency : 'monthly' } ,
133- { url : '/docs/api' , priority : 0.7 , changeFrequency : 'monthly' } ,
134- { url : '/docs/integrations' , priority : 0.8 , changeFrequency : 'weekly' } ,
135- {
136- url : '/docs/integrations/react' ,
137- priority : 0.8 ,
138- changeFrequency : 'weekly' ,
139- } ,
140- {
141- url : '/docs/integrations/nextjs' ,
142- priority : 0.8 ,
143- changeFrequency : 'weekly' ,
144- } ,
145- {
146- url : '/docs/integrations/wordpress' ,
147- priority : 0.8 ,
148- changeFrequency : 'weekly' ,
149- } ,
150- {
151- url : '/docs/integrations/shopify' ,
152- priority : 0.8 ,
153- changeFrequency : 'weekly' ,
154- } ,
155- {
156- url : '/docs/integrations/stripe' ,
157- priority : 0.8 ,
158- changeFrequency : 'weekly' ,
159- } ,
160- {
161- url : '/docs/integrations/framer' ,
162- priority : 0.7 ,
163- changeFrequency : 'weekly' ,
164- } ,
165- { url : '/docs/integrations/gtm' , priority : 0.7 , changeFrequency : 'weekly' } ,
166- { url : '/privacy' , priority : 0.5 , changeFrequency : 'yearly' } ,
167- { url : '/llms.txt' , priority : 0.4 , changeFrequency : 'weekly' } ,
168- ] ;
169- }
170-
171- function processFallbackEntries (
172- baseUrl : string ,
173- lastModified : Date
174- ) : MetadataRoute . Sitemap {
175- const fallbackEntries = getFallbackEntries ( ) ;
176- return fallbackEntries . map ( ( entry ) =>
177- createSitemapEntry (
178- entry . url ,
179- baseUrl ,
180- lastModified ,
181- entry . priority ,
182- entry . changeFrequency
183- )
184- ) ;
42+ // Simple change frequency rules
43+ function getChangeFrequency ( url : string ) : 'weekly' | 'monthly' | 'yearly' {
44+ if ( url . includes ( '/privacy' ) || url . includes ( '/terms' ) ) {
45+ return 'yearly' ;
46+ }
47+ if (
48+ url . includes ( '/compliance/' ) ||
49+ url . includes ( '/performance/' ) ||
50+ url . includes ( '/security' )
51+ ) {
52+ return 'monthly' ;
53+ }
54+ if ( url . includes ( '/api' ) && ! url . includes ( '/api-keys' ) ) {
55+ return 'monthly' ;
56+ }
57+ if ( url . includes ( '/blog' ) && url !== '/blog' ) {
58+ return 'monthly' ;
59+ }
60+ if ( url . includes ( '/pricing' ) || url . includes ( '/roadmap' ) ) {
61+ return 'monthly' ;
62+ }
63+ if (
64+ url . includes ( '/contributors' ) ||
65+ url . includes ( '/sponsors' ) ||
66+ url . includes ( '/ambassadors' )
67+ ) {
68+ return 'monthly' ;
69+ }
70+ return 'weekly' ;
18571}
18672
18773export async function generateSitemapEntries ( ) : Promise < MetadataRoute . Sitemap > {
18874 const lastModified = new Date ( ) ;
18975 const entries : MetadataRoute . Sitemap = [ ] ;
19076
19177 try {
78+ // Get all documentation pages from source
19279 const pages = source . getPages ( ) ;
193- const nonDocPages = [ '/privacy' , '/llms.txt' , '/contributors' , '/api' ] ;
194-
195- entries . push ( ...processSourcePages ( pages , SITE_URL , lastModified ) ) ;
196- entries . push ( ...processNonDocPages ( nonDocPages , SITE_URL , lastModified ) ) ;
197-
198- const blogEntries = await processBlogPages ( SITE_URL ) ;
199- entries . push ( ...blogEntries ) ;
80+ entries . push (
81+ ...pages . map ( ( page ) => ( {
82+ url : `${ SITE_URL } ${ page . url } ` ,
83+ lastModified,
84+ changeFrequency : getChangeFrequency ( page . url ) ,
85+ priority : getPriority ( page . url ) ,
86+ } ) )
87+ ) ;
20088
201- // Add the blog index page with lastModified set to latest blog post
202- const latestBlogModified = blogEntries . length
203- ? new Date (
204- Math . max (
205- ... blogEntries
206- . map ( ( e ) =>
207- e . lastModified ? new Date ( e . lastModified ) . getTime ( ) : 0
208- )
209- . filter ( ( t ) => Number . isFinite ( t ) && t > 0 )
210- )
211- )
212- : lastModified ;
89+ // Add static pages that actually exist
90+ const staticPages = [
91+ '/privacy' ,
92+ '/llms.txt' ,
93+ '/api' ,
94+ '/contributors' ,
95+ '/pricing' ,
96+ '/roadmap' ,
97+ '/sponsors' ,
98+ '/terms' ,
99+ '/ambassadors' ,
100+ ] ;
213101 entries . push (
214- createSitemapEntry (
215- '/blog' ,
216- SITE_URL ,
217- latestBlogModified ,
218- priorityMap [ '/blog' ] ,
219- changeFrequencyMap [ '/blog' ]
220- )
102+ ...staticPages . map ( ( page ) => ( {
103+ url : `${ SITE_URL } ${ page } ` ,
104+ lastModified,
105+ changeFrequency : getChangeFrequency ( page ) ,
106+ priority : getPriority ( page ) ,
107+ } ) )
221108 ) ;
222109
223- processIntegrationPages ( entries ) ;
110+ // Add blog posts and blog index
111+ const blogData = await getPosts ( ) ;
112+ if ( ! ( 'error' in blogData ) && blogData ?. posts ) {
113+ const blogEntries = blogData . posts . map ( ( post ) => ( {
114+ url : `${ SITE_URL } /blog/${ post . slug } ` ,
115+ lastModified : new Date ( post . publishedAt ) ,
116+ changeFrequency : 'monthly' as const ,
117+ priority : 0.7 ,
118+ } ) ) ;
119+ entries . push ( ...blogEntries ) ;
120+
121+ // Add blog index with latest post date
122+ const latestPostDate =
123+ blogEntries . length > 0
124+ ? blogEntries . reduce (
125+ ( latest , entry ) =>
126+ entry . lastModified > latest ? entry . lastModified : latest ,
127+ blogEntries [ 0 ] . lastModified
128+ )
129+ : lastModified ;
130+
131+ entries . push ( {
132+ url : `${ SITE_URL } /blog` ,
133+ lastModified : latestPostDate ,
134+ changeFrequency : 'monthly' ,
135+ priority : 0.8 ,
136+ } ) ;
137+ }
224138 } catch ( error ) {
225- console . warn ( 'Failed to generate dynamic sitemap, using fallback:' , error ) ;
226- entries . push ( ...processFallbackEntries ( SITE_URL , lastModified ) ) ;
139+ console . warn ( 'Sitemap generation failed, using minimal fallback:' , error ) ;
140+ // Minimal fallback - just the main docs page
141+ entries . push ( {
142+ url : `${ SITE_URL } /docs` ,
143+ lastModified,
144+ changeFrequency : 'weekly' ,
145+ priority : 1.0 ,
146+ } ) ;
227147 }
228148
229149 return entries ;
230150}
231-
232- export function getSitemapMetadata ( ) {
233- return {
234- title : 'Databuddy Documentation Sitemap' ,
235- description :
236- 'Dynamically generated sitemap of Databuddy documentation including all guides, integrations, and API references.' ,
237- } ;
238- }
0 commit comments