@@ -7,10 +7,72 @@ import { getChannelIdFromLocale } from '~/channels.config';
77import { client } from '~/client' ;
88import { defaultLocale } from '~/i18n/locales' ;
99
10- export const GET = async ( ) => {
10+ export const GET = async ( request : Request ) => {
11+ const url = new URL ( request . url ) ;
12+ const incomingHost = request . headers . get ( 'host' ) ?? url . host ;
13+ const incomingProto = request . headers . get ( 'x-forwarded-proto' ) ?? url . protocol . replace ( ':' , '' ) ;
14+
15+ const type = url . searchParams . get ( 'type' ) ;
16+ const page = url . searchParams . get ( 'page' ) ;
17+
18+ // If a specific sitemap within the index is requested, require both params
19+ if ( type !== null || page !== null ) {
20+ if ( ! type || ! page ) {
21+ return new Response ( 'Both "type" and "page" query params are required' , {
22+ status : 400 ,
23+ headers : { 'Content-Type' : 'text/plain; charset=utf-8' } ,
24+ } ) ;
25+ }
26+
27+ const upstream = await client . fetchSitemapResponse (
28+ { type, page } ,
29+ getChannelIdFromLocale ( defaultLocale ) ,
30+ ) ;
31+
32+ // Pass-through upstream status/body but enforce XML content-type
33+ const body = await upstream . text ( ) ;
34+ return new Response ( body , {
35+ status : upstream . status ,
36+ statusText : upstream . statusText ,
37+ headers : { 'Content-Type' : 'application/xml' } ,
38+ } ) ;
39+ }
40+
41+ // Otherwise, return the sitemap index with normalized internal links
1142 const sitemapIndex = await client . fetchSitemapIndex ( getChannelIdFromLocale ( defaultLocale ) ) ;
1243
13- return new Response ( sitemapIndex , {
44+ const rewritten = sitemapIndex . replace ( / < l o c > ( [ ^ < ] + ) < \/ l o c > / g, ( match , locUrlStr ) => {
45+ try {
46+ // Decode XML entities for '&' so URL parsing works
47+ const decoded = locUrlStr . replace ( / & a m p ; / g, '&' ) ;
48+ const original = new URL ( decoded ) ;
49+
50+ if ( ! original . pathname . endsWith ( '/xmlsitemap.php' ) ) {
51+ return match ;
52+ }
53+
54+ const normalized = new URL ( `${ incomingProto } ://${ incomingHost } /sitemap.xml` ) ;
55+
56+ const t = original . searchParams . get ( 'type' ) ;
57+ const p = original . searchParams . get ( 'page' ) ;
58+
59+ // Only rewrite entries that include both type and page; otherwise leave untouched
60+ if ( ! t || ! p ) {
61+ return match ;
62+ }
63+
64+ normalized . searchParams . set ( 'type' , t ) ;
65+ normalized . searchParams . set ( 'page' , p ) ;
66+
67+ // Re-encode '&' for XML output
68+ const normalizedXml = normalized . toString ( ) . replace ( / & / g, '&' ) ;
69+ return `<loc>${ normalizedXml } </loc>` ;
70+ } catch {
71+ return match ;
72+ }
73+ } ) ;
74+
75+ return new Response ( rewritten , {
1476 headers : {
1577 'Content-Type' : 'application/xml' ,
1678 } ,
0 commit comments