11import { MetadataRoute } from 'next'
22import path from 'path'
3- import { XMLParser } from 'fast-xml-parser'
43import { getPageForSitemap } from '@/utils/sitemap'
5- import {
6- landingPageHostname ,
7- landingPageFramerHostname ,
8- blogFramerHostname ,
9- changelogFramerHostname ,
10- } from '@/app/hostnames'
11- import { replaceUrls } from '@/utils/replaceUrls'
124
135export const dynamic = 'force-static'
146
15- type ChangeFrequency =
16- | 'always'
17- | 'hourly'
18- | 'daily'
19- | 'weekly'
20- | 'monthly'
21- | 'yearly'
22- | 'never'
23-
24- type Site = {
25- sitemapUrl : string
26- lastModified ?: string | Date
27- changeFrequency ?: ChangeFrequency
28- priority ?: number
29- }
30-
31- const sites : Site [ ] = [
32- {
33- sitemapUrl : `https://${ landingPageHostname } /sitemap.xml` ,
34- priority : 1.0 ,
35- changeFrequency : 'daily' ,
36- } ,
37- {
38- sitemapUrl : `https://${ blogFramerHostname } /sitemap.xml` ,
39- priority : 0.9 ,
40- changeFrequency : 'daily' ,
41- } ,
42- {
43- sitemapUrl : `https://${ changelogFramerHostname } /sitemap.xml` ,
44- priority : 0.2 ,
45- changeFrequency : 'weekly' ,
46- } ,
47- ]
48-
49- type SitemapData = {
50- loc : string
51- lastmod ?: string | Date
52- changefreq ?: ChangeFrequency
53- priority ?: number
54- }
55-
56- type Sitemap = {
57- urlset : {
58- url : SitemapData | SitemapData [ ]
59- }
60- }
61-
62- async function getXmlData ( url : string ) : Promise < Sitemap > {
63- const parser = new XMLParser ( )
64-
65- const response = await fetch ( url )
66-
67- if ( ! response . ok ) {
68- return { urlset : { url : [ ] } }
69- }
70-
71- const text = await response . text ( )
72-
73- return parser . parse ( text ) as Sitemap
74- }
75- async function getSitemap ( site : Site ) : Promise < MetadataRoute . Sitemap > {
76- const data = await getXmlData ( site . sitemapUrl )
77-
78- if ( ! data ) {
79- return [ ]
80- }
81-
82- const normalizeUrl = ( inputUrl : string , pathname : string ) => {
83- // First normalize the URL format
84- let normalizedUrl = inputUrl
85- . replace ( / ^ w w w \. / , '' ) // Remove www. prefix
86- . replace ( / h t t p s : \/ \/ h t t p s : \/ \/ / , 'https://' ) // Fix double https://
87- . replace ( / ^ h t t p s : \/ \/ w w w \. / , 'https://' ) // Remove www. after https://
88-
89- // Parse the URL to work with its components
90- const urlObj = new URL ( normalizedUrl )
91-
92- // Normalize category URLs to include /blog prefix
93- if ( pathname . startsWith ( '/category/' ) ) {
94- urlObj . pathname = `/blog${ pathname } `
95- }
96-
97- // Convert back to string for further processing
98- normalizedUrl = urlObj . toString ( )
99-
100- // Apply replaceUrls after initial normalization
101- normalizedUrl = replaceUrls ( normalizedUrl , urlObj . pathname )
102-
103- // Ensure all URLs use e2b.dev domain
104- // Handle both www. and non-www variants
105- const hostnames = [
106- landingPageFramerHostname ,
107- landingPageHostname ,
108- changelogFramerHostname ,
109- blogFramerHostname ,
110- ]
111-
112- for ( const hostname of hostnames ) {
113- normalizedUrl = normalizedUrl
114- . replace ( `www.${ hostname } ` , 'e2b.dev' )
115- . replace ( hostname , 'e2b.dev' )
116- }
117-
118- // Final cleanup for any remaining double https:// or www.
119- return normalizedUrl
120- . replace ( / h t t p s : \/ \/ h t t p s : \/ \/ / , 'https://' )
121- . replace ( / ^ h t t p s : \/ \/ w w w \. / , 'https://' )
122- }
123-
124- if ( Array . isArray ( data . urlset . url ) ) {
125- return data . urlset . url . map ( ( line ) => {
126- const url = new URL ( line . loc )
127- const pathname = url . pathname
128-
129- return {
130- url : normalizeUrl ( line . loc , pathname ) ,
131- priority : line ?. priority || site . priority ,
132- changeFrequency : line ?. changefreq || site . changeFrequency ,
133- }
134- } )
135- } else {
136- const url = new URL ( data . urlset . url . loc )
137- const pathname = url . pathname
138-
139- return [
140- {
141- url : normalizeUrl ( data . urlset . url . loc , pathname ) ,
142- priority : data . urlset . url ?. priority || site . priority ,
143- changeFrequency : data . urlset . url ?. changefreq || site . changeFrequency ,
144- } ,
145- ]
146- }
147- }
148-
1497export default async function sitemap ( ) : Promise < MetadataRoute . Sitemap > {
150- let mergedSitemap : MetadataRoute . Sitemap = [ ]
151-
1528 const docsDirectory = path . join (
1539 process . env . NODE_ENV === 'production'
15410 ? path . join ( '.' , 'src' , 'app' , '(docs)' , 'docs' )
@@ -161,16 +17,9 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
16117 0.8
16218 )
16319
164- mergedSitemap = mergedSitemap . concat ( docsPages )
165-
166- for ( const site of sites ) {
167- const urls = await getSitemap ( site )
168- mergedSitemap = mergedSitemap . concat ( ...urls )
169- }
170-
17120 // Deduplicate URLs, keeping the entry with highest priority
17221 const urlMap = new Map < string , MetadataRoute . Sitemap [ 0 ] > ( )
173- for ( const entry of mergedSitemap ) {
22+ for ( const entry of docsPages ) {
17423 const existing = urlMap . get ( entry . url )
17524 if ( ! existing || ( existing . priority || 0 ) < ( entry . priority || 0 ) ) {
17625 urlMap . set ( entry . url , entry )
0 commit comments