next-advanced-sitemap 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -6
- package/dist/index.cjs +9 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ While Next.js provides a built-in `MetadataRoute.Sitemap` utility, it currently
|
|
|
12
12
|
- **Google Video Support**: Improve search visibility for video content with thumbnail and description metadata.
|
|
13
13
|
- **Google News Support**: Comply with Google News requirements including publication names and dates.
|
|
14
14
|
- **Internationalization**: Seamless integration of `xhtml:link` tags for Hreflang and multi-regional SEO.
|
|
15
|
+
- **Priority Auto-Sorting (v1.0.8)**: Optional deterministic descending sort (`1.0` to `0.0`) based on entry weights to present your most strategic pages to crawlers first.
|
|
15
16
|
- **Auto-Trimming Sanitization (v1.0.7)**: Automatic `.trim()` execution on all URL fields to silently correct leading/trailing whitespace errors from CMS or databases.
|
|
16
17
|
- **Native Date Polymorphism (v1.0.6)**: Full support for native JavaScript `Date` objects inside Google News and Video extensions—no manual conversion required.
|
|
17
18
|
- **Strict SEO Enum Typing (v1.0.5)**: Compile-time validation and IDE autocompletion for `changefreq` and `priority` values to prevent typos.
|
|
@@ -36,10 +37,10 @@ import { getServerSitemapResponse, SitemapEntry } from 'next-advanced-sitemap';
|
|
|
36
37
|
export async function GET() {
|
|
37
38
|
const entries: SitemapEntry[] = [
|
|
38
39
|
{
|
|
39
|
-
url: 'https://fomadev.com',
|
|
40
|
+
url: ' https://fomadev.com ', // Auto-trimmed seamlessly in v1.0.7
|
|
40
41
|
lastmod: new Date(),
|
|
41
42
|
changefreq: 'daily', // Strictly typed
|
|
42
|
-
priority: 1.0,
|
|
43
|
+
priority: 1.0, // Auto-completed and strictly typed
|
|
43
44
|
alternates: [
|
|
44
45
|
{ hreflang: 'fr', href: 'https://fomadev.com/fr' },
|
|
45
46
|
{ hreflang: 'en', href: 'https://fomadev.com/en' }
|
|
@@ -47,6 +48,7 @@ export async function GET() {
|
|
|
47
48
|
},
|
|
48
49
|
{
|
|
49
50
|
url: 'https://fomadev.com/dashboard',
|
|
51
|
+
priority: 0.8,
|
|
50
52
|
images: [
|
|
51
53
|
{
|
|
52
54
|
loc: 'https://fomadev.com/charts/analytics.png',
|
|
@@ -57,19 +59,23 @@ export async function GET() {
|
|
|
57
59
|
},
|
|
58
60
|
{
|
|
59
61
|
url: 'https://fomadev.com/video-tutorial',
|
|
62
|
+
priority: 0.6,
|
|
60
63
|
videos: [
|
|
61
64
|
{
|
|
62
65
|
thumbnail_loc: 'https://fomadev.com/thumbs/tutorial.jpg',
|
|
63
66
|
title: 'Next.js Advanced SEO Tutorial',
|
|
64
67
|
description: 'Learn how to implement advanced sitemaps in Next.js & React.',
|
|
65
|
-
publication_date: new Date('2026-
|
|
68
|
+
publication_date: new Date('2026-05-25') // Accepts raw Date objects smoothly
|
|
66
69
|
}
|
|
67
70
|
]
|
|
68
71
|
}
|
|
69
72
|
];
|
|
70
73
|
|
|
71
|
-
// (
|
|
72
|
-
return getServerSitemapResponse(entries, {
|
|
74
|
+
// Enable autoLastmod and sortByPriority (v1.0.8) to optimize crawl efficiency
|
|
75
|
+
return getServerSitemapResponse(entries, {
|
|
76
|
+
autoLastmod: true,
|
|
77
|
+
sortByPriority: true
|
|
78
|
+
});
|
|
73
79
|
}
|
|
74
80
|
```
|
|
75
81
|
|
|
@@ -83,6 +89,8 @@ Generates a standard Next.js `Response` object with the correct `application/xml
|
|
|
83
89
|
|
|
84
90
|
* `autoLastmod` (boolean): If `true`, injects the current ISO date for any entry missing the `lastmod` property.
|
|
85
91
|
|
|
92
|
+
* `sortByPriority` (boolean): If `true`, sorts the sitemap records in a descending sequence based on their priority level (`1.0` down to `0.0`) before writing the XML stream. Items without an explicit priority fall back safely to `0.5`.
|
|
93
|
+
|
|
86
94
|
### SitemapEntry Object
|
|
87
95
|
|
|
88
96
|
<table>
|
|
@@ -139,7 +147,10 @@ Generates a standard Next.js `Response` object with the correct `application/xml
|
|
|
139
147
|
|
|
140
148
|
## Technical Implementation
|
|
141
149
|
|
|
142
|
-
### Auto-
|
|
150
|
+
### Priority Auto-Sorting (v1.0.8 Update)
|
|
151
|
+
Search engine crawlers allocate a finite scanning resource quota (crawl budget) when inspecting domain properties. By default, raw database queries or collection iterations generate un-ordered XML lists, causing indexers to process trivial nodes ahead of strategic content. When `sortByPriority` is enabled, the generation engine executes an immutable descending sorting operation. Unlabeled entries smoothly receive an RFC-compliant fallback baseline score of `0.5`, allowing top-tier entries to line up at the absolute top of the index file.
|
|
152
|
+
|
|
153
|
+
### Auto-Trimming & Ingestion Sanitization
|
|
143
154
|
|
|
144
155
|
Distributed content pipelines frequently face issues with accidental leading spaces, trailing newlines, or indentation remnants introduced via headless CMS panels or Markdown document updates. To protect against application deployment errors caused by these invisible characters, the pipeline incorporates an automatic `.trim()` sanitization step. This layer cleans all input strings—including primary entries, alternative nodes, image endpoints, and video references—and passes the cleaned string directly down to the structural validation layer and the output XML stream.
|
|
145
156
|
|
package/dist/index.cjs
CHANGED
|
@@ -78,6 +78,14 @@ function sanitizeAndValidateUrl(rawUrl, context) {
|
|
|
78
78
|
}
|
|
79
79
|
function generateXml(entries, options = {}) {
|
|
80
80
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
81
|
+
let finalEntries = [...entries];
|
|
82
|
+
if (options.sortByPriority) {
|
|
83
|
+
finalEntries.sort((a, b) => {
|
|
84
|
+
const priorityA = a.priority !== void 0 ? a.priority : 0.5;
|
|
85
|
+
const priorityB = b.priority !== void 0 ? b.priority : 0.5;
|
|
86
|
+
return priorityB - priorityA;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
81
89
|
let xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
82
90
|
`;
|
|
83
91
|
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
@@ -90,7 +98,7 @@ function generateXml(entries, options = {}) {
|
|
|
90
98
|
`;
|
|
91
99
|
xml += ` xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
92
100
|
`;
|
|
93
|
-
for (const entry of
|
|
101
|
+
for (const entry of finalEntries) {
|
|
94
102
|
const cleanMainUrl = sanitizeAndValidateUrl(entry.url, "main entry");
|
|
95
103
|
xml += ` <url>
|
|
96
104
|
`;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils/xml-escape.ts","../src/core/generator.ts"],"sourcesContent":["/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\nimport { SitemapEntry, SitemapOptions } from './types/sitemap.js';\r\nimport { generateXml } from './core/generator.js';\r\n\r\nexport * from './types/sitemap.js';\r\n\r\n/**\r\n * Génère une réponse HTTP compatible Next.js (App Router) avec options de configuration.\r\n * * @param entries - Liste des entrées du sitemap\r\n * @param options - Options de génération facultatives (ex: autoLastmod)\r\n * @returns Une instance de Response contenant le flux XML configuré\r\n */\r\nexport function getServerSitemapResponse(\r\n entries: SitemapEntry[], \r\n options: SitemapOptions = {}\r\n): Response {\r\n const xml = generateXml(entries, options);\r\n\r\n return new Response(xml, {\r\n headers: {\r\n 'Content-Type': 'application/xml',\r\n 'Cache-Control': 'public, s-maxage=86400, stale-while-revalidate',\r\n },\r\n });\r\n}","/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\n/**\r\n * Convertit les caractères spéciaux en entités XML pour éviter la corruption du fichier.\r\n * Gère : <, >, &, \", '\r\n */\r\nexport function escapeXml(unsafe: string | undefined | null): string {\r\n if (!unsafe) return '';\r\n \r\n return unsafe.replace(/[<>&\"']/g, (c) => {\r\n switch (c) {\r\n case '<': return '<';\r\n case '>': return '>';\r\n case '&': return '&';\r\n case '\"': return '"';\r\n case \"'\": return ''';\r\n default: return c;\r\n }\r\n });\r\n}","/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\nimport { SitemapEntry, SitemapOptions } from '../types/sitemap.js';\r\nimport { escapeXml } from '../utils/xml-escape.js';\r\n\r\n/**\r\n * Nettoie et valide de manière stricte le format et la structure d'une URL.\r\n * v1.0.7 : Intégration de l'Auto-Trimming (nettoyage des espaces de début et de fin)\r\n */\r\nfunction sanitizeAndValidateUrl(rawUrl: string, context: string): string {\r\n // 1. Auto-Trimming (v1.0.7)\r\n const url = rawUrl ? rawUrl.trim() : '';\r\n\r\n // 2. Vérification rapide du protocole\r\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Invalid URL in ${context}: \"${url}\". URLs must start with http:// or https://`\r\n );\r\n }\r\n\r\n // 3. Sécurité v1.0.4 : Interdire strictement les espaces blancs internes non encodés\r\n if (url.includes(' ')) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Malformed URL structure detected in ${context}: \"${url}\". Please verify spaces or special characters.`\r\n );\r\n }\r\n\r\n // 4. Validation fine de la structure globale via le moteur natif\r\n let isValid = false;\r\n if (typeof URL.canParse === 'function') {\r\n isValid = URL.canParse(url);\r\n } else {\r\n try {\r\n new URL(url);\r\n isValid = true;\r\n } catch {\r\n isValid = false;\r\n }\r\n }\r\n\r\n if (!isValid) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Malformed URL structure detected in ${context}: \"${url}\". Please verify spaces or special characters.`\r\n );\r\n }\r\n\r\n return url; // Retourne l'URL nettoyée\r\n}\r\n\r\n/**\r\n * Génère le flux XML complet du sitemap incluant les extensions Images, Vidéos, News et Hreflang.\r\n */\r\nexport function generateXml(entries: SitemapEntry[], options: SitemapOptions = {}): string {\r\n const now = new Date().toISOString();\r\n \r\n let xml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n`;\r\n xml += `<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\\n`;\r\n xml += ` xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"\\n`;\r\n xml += ` xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"\\n`;\r\n xml += ` xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\"\\n`;\r\n xml += ` xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\\n`;\r\n\r\n for (const entry of entries) {\r\n // Validation et nettoyage URL principale\r\n const cleanMainUrl = sanitizeAndValidateUrl(entry.url, 'main entry');\r\n\r\n xml += ` <url>\\n`;\r\n xml += ` <loc>${escapeXml(cleanMainUrl)}</loc>\\n`;\r\n\r\n // Support Hreflang (Internationalisation)\r\n if (entry.alternates?.length) {\r\n for (const alt of entry.alternates) {\r\n const cleanAltUrl = sanitizeAndValidateUrl(alt.href, 'alternate link');\r\n xml += ` <xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(cleanAltUrl)}\" />\\n`;\r\n }\r\n }\r\n\r\n // --- LOGIQUE AUTO-LASTMOD ---\r\n let lastmodValue = entry.lastmod;\r\n if (options.autoLastmod && !lastmodValue) {\r\n lastmodValue = now;\r\n }\r\n\r\n if (lastmodValue) {\r\n const date = lastmodValue instanceof Date ? lastmodValue.toISOString() : lastmodValue;\r\n xml += ` <lastmod>${date}</lastmod>\\n`;\r\n }\r\n\r\n if (entry.changefreq) {\r\n xml += ` <changefreq>${entry.changefreq}</changefreq>\\n`;\r\n }\r\n\r\n if (entry.priority !== undefined) {\r\n xml += ` <priority>${entry.priority.toFixed(1)}</priority>\\n`;\r\n }\r\n\r\n // Extension Images\r\n if (entry.images?.length) {\r\n for (const img of entry.images) {\r\n const cleanImgUrl = sanitizeAndValidateUrl(img.loc, 'image location');\r\n xml += ` <image:image>\\n`;\r\n xml += ` <image:loc>${escapeXml(cleanImgUrl)}</image:loc>\\n`;\r\n if (img.title) xml += ` <image:title>${escapeXml(img.title)}</image:title>\\n`;\r\n if (img.caption) xml += ` <image:caption>${escapeXml(img.caption)}</image:caption>\\n`;\r\n xml += ` </image:image>\\n`;\r\n }\r\n }\r\n\r\n // Extension Vidéos\r\n if (entry.videos?.length) {\r\n for (const vid of entry.videos) {\r\n const cleanThumbLoc = sanitizeAndValidateUrl(vid.thumbnail_loc, 'video thumbnail');\r\n const cleanContentLoc = vid.content_loc ? sanitizeAndValidateUrl(vid.content_loc, 'video content location') : undefined;\r\n const cleanPlayerLoc = vid.player_loc ? sanitizeAndValidateUrl(vid.player_loc, 'video player location') : undefined;\r\n\r\n xml += ` <video:video>\\n`;\r\n xml += ` <video:thumbnail_loc>${escapeXml(cleanThumbLoc)}</video:thumbnail_loc>\\n`;\r\n xml += ` <video:title>${escapeXml(vid.title)}</video:title>\\n`;\r\n xml += ` <video:description>${escapeXml(vid.description)}</video:description>\\n`;\r\n \r\n if (cleanContentLoc) xml += ` <video:content_loc>${escapeXml(cleanContentLoc)}</video:content_loc>\\n`;\r\n if (cleanPlayerLoc) xml += ` <video:player_loc>${escapeXml(cleanPlayerLoc)}</video:player_loc>\\n`;\r\n \r\n if (vid.publication_date) {\r\n const vDate = vid.publication_date instanceof Date ? vid.publication_date.toISOString() : vid.publication_date;\r\n xml += ` <video:publication_date>${vDate}</video:publication_date>\\n`;\r\n }\r\n xml += ` </video:video>\\n`;\r\n }\r\n }\r\n\r\n // Extension News\r\n if (entry.news) {\r\n const nDate = entry.news.publication_date instanceof Date ? entry.news.publication_date.toISOString() : entry.news.publication_date;\r\n xml += ` <news:news>\\n`;\r\n xml += ` <news:publication>\\n`;\r\n xml += ` <news:name>${escapeXml(entry.news.name)}</news:name>\\n`;\r\n xml += ` <news:language>${escapeXml(entry.news.language)}</news:language>\\n`;\r\n xml += ` </news:publication>\\n`;\r\n xml += ` <news:publication_date>${nDate}</news:publication_date>\\n`;\r\n xml += ` <news:title>${escapeXml(entry.news.title)}</news:title>\\n`;\r\n xml += ` </news:news>\\n`;\r\n }\r\n\r\n xml += ` </url>\\n`;\r\n }\r\n\r\n xml += `</urlset>`;\r\n return xml;\r\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/xml-escape.ts","../src/core/generator.ts"],"sourcesContent":["/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\nimport { SitemapEntry, SitemapOptions } from './types/sitemap.js';\r\nimport { generateXml } from './core/generator.js';\r\n\r\nexport * from './types/sitemap.js';\r\n\r\n/**\r\n * Génère une réponse HTTP compatible Next.js (App Router) avec options de configuration.\r\n * * @param entries - Liste des entrées du sitemap\r\n * @param options - Options de génération facultatives (ex: autoLastmod)\r\n * @returns Une instance de Response contenant le flux XML configuré\r\n */\r\nexport function getServerSitemapResponse(\r\n entries: SitemapEntry[], \r\n options: SitemapOptions = {}\r\n): Response {\r\n const xml = generateXml(entries, options);\r\n\r\n return new Response(xml, {\r\n headers: {\r\n 'Content-Type': 'application/xml',\r\n 'Cache-Control': 'public, s-maxage=86400, stale-while-revalidate',\r\n },\r\n });\r\n}","/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\n/**\r\n * Convertit les caractères spéciaux en entités XML pour éviter la corruption du fichier.\r\n * Gère : <, >, &, \", '\r\n */\r\nexport function escapeXml(unsafe: string | undefined | null): string {\r\n if (!unsafe) return '';\r\n \r\n return unsafe.replace(/[<>&\"']/g, (c) => {\r\n switch (c) {\r\n case '<': return '<';\r\n case '>': return '>';\r\n case '&': return '&';\r\n case '\"': return '"';\r\n case \"'\": return ''';\r\n default: return c;\r\n }\r\n });\r\n}","/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\nimport { SitemapEntry, SitemapOptions } from '../types/sitemap.js';\r\nimport { escapeXml } from '../utils/xml-escape.js';\r\n\r\n/**\r\n * Nettoie et valide de manière stricte le format et la structure d'une URL.\r\n * v1.0.7 : Intégration de l'Auto-Trimming (nettoyage des espaces de début et de fin)\r\n */\r\nfunction sanitizeAndValidateUrl(rawUrl: string, context: string): string {\r\n // 1. Auto-Trimming (v1.0.7)\r\n const url = rawUrl ? rawUrl.trim() : '';\r\n\r\n // 2. Vérification rapide du protocole\r\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Invalid URL in ${context}: \"${url}\". URLs must start with http:// or https://`\r\n );\r\n }\r\n\r\n // 3. Sécurité v1.0.4 : Interdire strictement les espaces blancs internes non encodés\r\n if (url.includes(' ')) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Malformed URL structure detected in ${context}: \"${url}\". Please verify spaces or special characters.`\r\n );\r\n }\r\n\r\n // 4. Validation fine de la structure globale via le moteur natif\r\n let isValid = false;\r\n if (typeof URL.canParse === 'function') {\r\n isValid = URL.canParse(url);\r\n } else {\r\n try {\r\n new URL(url);\r\n isValid = true;\r\n } catch {\r\n isValid = false;\r\n }\r\n }\r\n\r\n if (!isValid) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Malformed URL structure detected in ${context}: \"${url}\". Please verify spaces or special characters.`\r\n );\r\n }\r\n\r\n return url; // Retourne l'URL nettoyée\r\n}\r\n\r\n/**\r\n * Génère le flux XML complet du sitemap incluant les extensions Images, Vidéos, News et Hreflang.\r\n * v1.0.8 : Intégration du tri automatique optionnel par priorité (Auto-Sorting)\r\n */\r\nexport function generateXml(entries: SitemapEntry[], options: SitemapOptions = {}): string {\r\n const now = new Date().toISOString();\r\n \r\n // Cloner le tableau d'entrées pour éviter de modifier la structure d'origine par effet de bord\r\n let finalEntries = [...entries];\r\n\r\n // Exécuter l'Auto-Sorting si l'option sortByPriority est activée\r\n if (options.sortByPriority) {\r\n finalEntries.sort((a, b) => {\r\n const priorityA = a.priority !== undefined ? (a.priority as number) : 0.5;\r\n const priorityB = b.priority !== undefined ? (b.priority as number) : 0.5;\r\n return priorityB - priorityA; // Ordre décroissant : de 1.0 à 0.0\r\n });\r\n }\r\n \r\n let xml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n`;\r\n xml += `<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\\n`;\r\n xml += ` xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"\\n`;\r\n xml += ` xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"\\n`;\r\n xml += ` xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\"\\n`;\r\n xml += ` xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\\n`;\r\n\r\n for (const entry of finalEntries) {\r\n // Validation et nettoyage URL principale\r\n const cleanMainUrl = sanitizeAndValidateUrl(entry.url, 'main entry');\r\n\r\n xml += ` <url>\\n`;\r\n xml += ` <loc>${escapeXml(cleanMainUrl)}</loc>\\n`;\r\n\r\n // Support Hreflang (Internationalisation)\r\n if (entry.alternates?.length) {\r\n for (const alt of entry.alternates) {\r\n const cleanAltUrl = sanitizeAndValidateUrl(alt.href, 'alternate link');\r\n xml += ` <xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(cleanAltUrl)}\" />\\n`;\r\n }\r\n }\r\n\r\n // --- LOGIQUE AUTO-LASTMOD ---\r\n let lastmodValue = entry.lastmod;\r\n if (options.autoLastmod && !lastmodValue) {\r\n lastmodValue = now;\r\n }\r\n\r\n if (lastmodValue) {\r\n const date = lastmodValue instanceof Date ? lastmodValue.toISOString() : lastmodValue;\r\n xml += ` <lastmod>${date}</lastmod>\\n`;\r\n }\r\n\r\n if (entry.changefreq) {\r\n xml += ` <changefreq>${entry.changefreq}</changefreq>\\n`;\r\n }\r\n\r\n if (entry.priority !== undefined) {\r\n xml += ` <priority>${(entry.priority as number).toFixed(1)}</priority>\\n`;\r\n }\r\n\r\n // Extension Images\r\n if (entry.images?.length) {\r\n for (const img of entry.images) {\r\n const cleanImgUrl = sanitizeAndValidateUrl(img.loc, 'image location');\r\n xml += ` <image:image>\\n`;\r\n xml += ` <image:loc>${escapeXml(cleanImgUrl)}</image:loc>\\n`;\r\n if (img.title) xml += ` <image:title>${escapeXml(img.title)}</image:title>\\n`;\r\n if (img.caption) xml += ` <image:caption>${escapeXml(img.caption)}</image:caption>\\n`;\r\n xml += ` </image:image>\\n`;\r\n }\r\n }\r\n\r\n // Extension Vidéos\r\n if (entry.videos?.length) {\r\n for (const vid of entry.videos) {\r\n const cleanThumbLoc = sanitizeAndValidateUrl(vid.thumbnail_loc, 'video thumbnail');\r\n const cleanContentLoc = vid.content_loc ? sanitizeAndValidateUrl(vid.content_loc, 'video content location') : undefined;\r\n const cleanPlayerLoc = vid.player_loc ? sanitizeAndValidateUrl(vid.player_loc, 'video player location') : undefined;\r\n\r\n xml += ` <video:video>\\n`;\r\n xml += ` <video:thumbnail_loc>${escapeXml(cleanThumbLoc)}</video:thumbnail_loc>\\n`;\r\n xml += ` <video:title>${escapeXml(vid.title)}</video:title>\\n`;\r\n xml += ` <video:description>${escapeXml(vid.description)}</video:description>\\n`;\r\n \r\n if (cleanContentLoc) xml += ` <video:content_loc>${escapeXml(cleanContentLoc)}</video:content_loc>\\n`;\r\n if (cleanPlayerLoc) xml += ` <video:player_loc>${escapeXml(cleanPlayerLoc)}</video:player_loc>\\n`;\r\n \r\n if (vid.publication_date) {\r\n const vDate = vid.publication_date instanceof Date ? vid.publication_date.toISOString() : vid.publication_date;\r\n xml += ` <video:publication_date>${vDate}</video:publication_date>\\n`;\r\n }\r\n xml += ` </video:video>\\n`;\r\n }\r\n }\r\n\r\n // Extension News\r\n if (entry.news) {\r\n const nDate = entry.news.publication_date instanceof Date ? entry.news.publication_date.toISOString() : entry.news.publication_date;\r\n xml += ` <news:news>\\n`;\r\n xml += ` <news:publication>\\n`;\r\n xml += ` <news:name>${escapeXml(entry.news.name)}</news:name>\\n`;\r\n xml += ` <news:language>${escapeXml(entry.news.language)}</news:language>\\n`;\r\n xml += ` </news:publication>\\n`;\r\n xml += ` <news:publication_date>${nDate}</news:publication_date>\\n`;\r\n xml += ` <news:title>${escapeXml(entry.news.title)}</news:title>\\n`;\r\n xml += ` </news:news>\\n`;\r\n }\r\n\r\n xml += ` </url>\\n`;\r\n }\r\n\r\n xml += `</urlset>`;\r\n return xml;\r\n}"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -74,6 +74,12 @@ interface SitemapOptions {
|
|
|
74
74
|
* qui n'ont pas de champ 'lastmod' défini.
|
|
75
75
|
*/
|
|
76
76
|
autoLastmod?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Si true, trie le tableau des URLs de la priorité la plus haute (1.0)
|
|
79
|
+
* à la plus basse (0.0) avant de lancer la génération du flux XML.
|
|
80
|
+
* Les entrées sans priorité héritent d'une valeur par défaut de 0.5.
|
|
81
|
+
*/
|
|
82
|
+
sortByPriority?: boolean;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -74,6 +74,12 @@ interface SitemapOptions {
|
|
|
74
74
|
* qui n'ont pas de champ 'lastmod' défini.
|
|
75
75
|
*/
|
|
76
76
|
autoLastmod?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Si true, trie le tableau des URLs de la priorité la plus haute (1.0)
|
|
79
|
+
* à la plus basse (0.0) avant de lancer la génération du flux XML.
|
|
80
|
+
* Les entrées sans priorité héritent d'une valeur par défaut de 0.5.
|
|
81
|
+
*/
|
|
82
|
+
sortByPriority?: boolean;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
/**
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,14 @@ function sanitizeAndValidateUrl(rawUrl, context) {
|
|
|
52
52
|
}
|
|
53
53
|
function generateXml(entries, options = {}) {
|
|
54
54
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
55
|
+
let finalEntries = [...entries];
|
|
56
|
+
if (options.sortByPriority) {
|
|
57
|
+
finalEntries.sort((a, b) => {
|
|
58
|
+
const priorityA = a.priority !== void 0 ? a.priority : 0.5;
|
|
59
|
+
const priorityB = b.priority !== void 0 ? b.priority : 0.5;
|
|
60
|
+
return priorityB - priorityA;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
55
63
|
let xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
56
64
|
`;
|
|
57
65
|
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
@@ -64,7 +72,7 @@ function generateXml(entries, options = {}) {
|
|
|
64
72
|
`;
|
|
65
73
|
xml += ` xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
66
74
|
`;
|
|
67
|
-
for (const entry of
|
|
75
|
+
for (const entry of finalEntries) {
|
|
68
76
|
const cleanMainUrl = sanitizeAndValidateUrl(entry.url, "main entry");
|
|
69
77
|
xml += ` <url>
|
|
70
78
|
`;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/xml-escape.ts","../src/core/generator.ts","../src/index.ts"],"sourcesContent":["/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\n/**\r\n * Convertit les caractères spéciaux en entités XML pour éviter la corruption du fichier.\r\n * Gère : <, >, &, \", '\r\n */\r\nexport function escapeXml(unsafe: string | undefined | null): string {\r\n if (!unsafe) return '';\r\n \r\n return unsafe.replace(/[<>&\"']/g, (c) => {\r\n switch (c) {\r\n case '<': return '<';\r\n case '>': return '>';\r\n case '&': return '&';\r\n case '\"': return '"';\r\n case \"'\": return ''';\r\n default: return c;\r\n }\r\n });\r\n}","/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\nimport { SitemapEntry, SitemapOptions } from '../types/sitemap.js';\r\nimport { escapeXml } from '../utils/xml-escape.js';\r\n\r\n/**\r\n * Nettoie et valide de manière stricte le format et la structure d'une URL.\r\n * v1.0.7 : Intégration de l'Auto-Trimming (nettoyage des espaces de début et de fin)\r\n */\r\nfunction sanitizeAndValidateUrl(rawUrl: string, context: string): string {\r\n // 1. Auto-Trimming (v1.0.7)\r\n const url = rawUrl ? rawUrl.trim() : '';\r\n\r\n // 2. Vérification rapide du protocole\r\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Invalid URL in ${context}: \"${url}\". URLs must start with http:// or https://`\r\n );\r\n }\r\n\r\n // 3. Sécurité v1.0.4 : Interdire strictement les espaces blancs internes non encodés\r\n if (url.includes(' ')) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Malformed URL structure detected in ${context}: \"${url}\". Please verify spaces or special characters.`\r\n );\r\n }\r\n\r\n // 4. Validation fine de la structure globale via le moteur natif\r\n let isValid = false;\r\n if (typeof URL.canParse === 'function') {\r\n isValid = URL.canParse(url);\r\n } else {\r\n try {\r\n new URL(url);\r\n isValid = true;\r\n } catch {\r\n isValid = false;\r\n }\r\n }\r\n\r\n if (!isValid) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Malformed URL structure detected in ${context}: \"${url}\". Please verify spaces or special characters.`\r\n );\r\n }\r\n\r\n return url; // Retourne l'URL nettoyée\r\n}\r\n\r\n/**\r\n * Génère le flux XML complet du sitemap incluant les extensions Images, Vidéos, News et Hreflang.\r\n */\r\nexport function generateXml(entries: SitemapEntry[], options: SitemapOptions = {}): string {\r\n const now = new Date().toISOString();\r\n \r\n let xml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n`;\r\n xml += `<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\\n`;\r\n xml += ` xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"\\n`;\r\n xml += ` xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"\\n`;\r\n xml += ` xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\"\\n`;\r\n xml += ` xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\\n`;\r\n\r\n for (const entry of entries) {\r\n // Validation et nettoyage URL principale\r\n const cleanMainUrl = sanitizeAndValidateUrl(entry.url, 'main entry');\r\n\r\n xml += ` <url>\\n`;\r\n xml += ` <loc>${escapeXml(cleanMainUrl)}</loc>\\n`;\r\n\r\n // Support Hreflang (Internationalisation)\r\n if (entry.alternates?.length) {\r\n for (const alt of entry.alternates) {\r\n const cleanAltUrl = sanitizeAndValidateUrl(alt.href, 'alternate link');\r\n xml += ` <xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(cleanAltUrl)}\" />\\n`;\r\n }\r\n }\r\n\r\n // --- LOGIQUE AUTO-LASTMOD ---\r\n let lastmodValue = entry.lastmod;\r\n if (options.autoLastmod && !lastmodValue) {\r\n lastmodValue = now;\r\n }\r\n\r\n if (lastmodValue) {\r\n const date = lastmodValue instanceof Date ? lastmodValue.toISOString() : lastmodValue;\r\n xml += ` <lastmod>${date}</lastmod>\\n`;\r\n }\r\n\r\n if (entry.changefreq) {\r\n xml += ` <changefreq>${entry.changefreq}</changefreq>\\n`;\r\n }\r\n\r\n if (entry.priority !== undefined) {\r\n xml += ` <priority>${entry.priority.toFixed(1)}</priority>\\n`;\r\n }\r\n\r\n // Extension Images\r\n if (entry.images?.length) {\r\n for (const img of entry.images) {\r\n const cleanImgUrl = sanitizeAndValidateUrl(img.loc, 'image location');\r\n xml += ` <image:image>\\n`;\r\n xml += ` <image:loc>${escapeXml(cleanImgUrl)}</image:loc>\\n`;\r\n if (img.title) xml += ` <image:title>${escapeXml(img.title)}</image:title>\\n`;\r\n if (img.caption) xml += ` <image:caption>${escapeXml(img.caption)}</image:caption>\\n`;\r\n xml += ` </image:image>\\n`;\r\n }\r\n }\r\n\r\n // Extension Vidéos\r\n if (entry.videos?.length) {\r\n for (const vid of entry.videos) {\r\n const cleanThumbLoc = sanitizeAndValidateUrl(vid.thumbnail_loc, 'video thumbnail');\r\n const cleanContentLoc = vid.content_loc ? sanitizeAndValidateUrl(vid.content_loc, 'video content location') : undefined;\r\n const cleanPlayerLoc = vid.player_loc ? sanitizeAndValidateUrl(vid.player_loc, 'video player location') : undefined;\r\n\r\n xml += ` <video:video>\\n`;\r\n xml += ` <video:thumbnail_loc>${escapeXml(cleanThumbLoc)}</video:thumbnail_loc>\\n`;\r\n xml += ` <video:title>${escapeXml(vid.title)}</video:title>\\n`;\r\n xml += ` <video:description>${escapeXml(vid.description)}</video:description>\\n`;\r\n \r\n if (cleanContentLoc) xml += ` <video:content_loc>${escapeXml(cleanContentLoc)}</video:content_loc>\\n`;\r\n if (cleanPlayerLoc) xml += ` <video:player_loc>${escapeXml(cleanPlayerLoc)}</video:player_loc>\\n`;\r\n \r\n if (vid.publication_date) {\r\n const vDate = vid.publication_date instanceof Date ? vid.publication_date.toISOString() : vid.publication_date;\r\n xml += ` <video:publication_date>${vDate}</video:publication_date>\\n`;\r\n }\r\n xml += ` </video:video>\\n`;\r\n }\r\n }\r\n\r\n // Extension News\r\n if (entry.news) {\r\n const nDate = entry.news.publication_date instanceof Date ? entry.news.publication_date.toISOString() : entry.news.publication_date;\r\n xml += ` <news:news>\\n`;\r\n xml += ` <news:publication>\\n`;\r\n xml += ` <news:name>${escapeXml(entry.news.name)}</news:name>\\n`;\r\n xml += ` <news:language>${escapeXml(entry.news.language)}</news:language>\\n`;\r\n xml += ` </news:publication>\\n`;\r\n xml += ` <news:publication_date>${nDate}</news:publication_date>\\n`;\r\n xml += ` <news:title>${escapeXml(entry.news.title)}</news:title>\\n`;\r\n xml += ` </news:news>\\n`;\r\n }\r\n\r\n xml += ` </url>\\n`;\r\n }\r\n\r\n xml += `</urlset>`;\r\n return xml;\r\n}","/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\nimport { SitemapEntry, SitemapOptions } from './types/sitemap.js';\r\nimport { generateXml } from './core/generator.js';\r\n\r\nexport * from './types/sitemap.js';\r\n\r\n/**\r\n * Génère une réponse HTTP compatible Next.js (App Router) avec options de configuration.\r\n * * @param entries - Liste des entrées du sitemap\r\n * @param options - Options de génération facultatives (ex: autoLastmod)\r\n * @returns Une instance de Response contenant le flux XML configuré\r\n */\r\nexport function getServerSitemapResponse(\r\n entries: SitemapEntry[], \r\n options: SitemapOptions = {}\r\n): Response {\r\n const xml = generateXml(entries, options);\r\n\r\n return new Response(xml, {\r\n headers: {\r\n 'Content-Type': 'application/xml',\r\n 'Cache-Control': 'public, s-maxage=86400, stale-while-revalidate',\r\n },\r\n });\r\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/xml-escape.ts","../src/core/generator.ts","../src/index.ts"],"sourcesContent":["/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\n/**\r\n * Convertit les caractères spéciaux en entités XML pour éviter la corruption du fichier.\r\n * Gère : <, >, &, \", '\r\n */\r\nexport function escapeXml(unsafe: string | undefined | null): string {\r\n if (!unsafe) return '';\r\n \r\n return unsafe.replace(/[<>&\"']/g, (c) => {\r\n switch (c) {\r\n case '<': return '<';\r\n case '>': return '>';\r\n case '&': return '&';\r\n case '\"': return '"';\r\n case \"'\": return ''';\r\n default: return c;\r\n }\r\n });\r\n}","/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\nimport { SitemapEntry, SitemapOptions } from '../types/sitemap.js';\r\nimport { escapeXml } from '../utils/xml-escape.js';\r\n\r\n/**\r\n * Nettoie et valide de manière stricte le format et la structure d'une URL.\r\n * v1.0.7 : Intégration de l'Auto-Trimming (nettoyage des espaces de début et de fin)\r\n */\r\nfunction sanitizeAndValidateUrl(rawUrl: string, context: string): string {\r\n // 1. Auto-Trimming (v1.0.7)\r\n const url = rawUrl ? rawUrl.trim() : '';\r\n\r\n // 2. Vérification rapide du protocole\r\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Invalid URL in ${context}: \"${url}\". URLs must start with http:// or https://`\r\n );\r\n }\r\n\r\n // 3. Sécurité v1.0.4 : Interdire strictement les espaces blancs internes non encodés\r\n if (url.includes(' ')) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Malformed URL structure detected in ${context}: \"${url}\". Please verify spaces or special characters.`\r\n );\r\n }\r\n\r\n // 4. Validation fine de la structure globale via le moteur natif\r\n let isValid = false;\r\n if (typeof URL.canParse === 'function') {\r\n isValid = URL.canParse(url);\r\n } else {\r\n try {\r\n new URL(url);\r\n isValid = true;\r\n } catch {\r\n isValid = false;\r\n }\r\n }\r\n\r\n if (!isValid) {\r\n throw new Error(\r\n `[next-advanced-sitemap] Malformed URL structure detected in ${context}: \"${url}\". Please verify spaces or special characters.`\r\n );\r\n }\r\n\r\n return url; // Retourne l'URL nettoyée\r\n}\r\n\r\n/**\r\n * Génère le flux XML complet du sitemap incluant les extensions Images, Vidéos, News et Hreflang.\r\n * v1.0.8 : Intégration du tri automatique optionnel par priorité (Auto-Sorting)\r\n */\r\nexport function generateXml(entries: SitemapEntry[], options: SitemapOptions = {}): string {\r\n const now = new Date().toISOString();\r\n \r\n // Cloner le tableau d'entrées pour éviter de modifier la structure d'origine par effet de bord\r\n let finalEntries = [...entries];\r\n\r\n // Exécuter l'Auto-Sorting si l'option sortByPriority est activée\r\n if (options.sortByPriority) {\r\n finalEntries.sort((a, b) => {\r\n const priorityA = a.priority !== undefined ? (a.priority as number) : 0.5;\r\n const priorityB = b.priority !== undefined ? (b.priority as number) : 0.5;\r\n return priorityB - priorityA; // Ordre décroissant : de 1.0 à 0.0\r\n });\r\n }\r\n \r\n let xml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n`;\r\n xml += `<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\\n`;\r\n xml += ` xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"\\n`;\r\n xml += ` xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"\\n`;\r\n xml += ` xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\"\\n`;\r\n xml += ` xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\\n`;\r\n\r\n for (const entry of finalEntries) {\r\n // Validation et nettoyage URL principale\r\n const cleanMainUrl = sanitizeAndValidateUrl(entry.url, 'main entry');\r\n\r\n xml += ` <url>\\n`;\r\n xml += ` <loc>${escapeXml(cleanMainUrl)}</loc>\\n`;\r\n\r\n // Support Hreflang (Internationalisation)\r\n if (entry.alternates?.length) {\r\n for (const alt of entry.alternates) {\r\n const cleanAltUrl = sanitizeAndValidateUrl(alt.href, 'alternate link');\r\n xml += ` <xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(cleanAltUrl)}\" />\\n`;\r\n }\r\n }\r\n\r\n // --- LOGIQUE AUTO-LASTMOD ---\r\n let lastmodValue = entry.lastmod;\r\n if (options.autoLastmod && !lastmodValue) {\r\n lastmodValue = now;\r\n }\r\n\r\n if (lastmodValue) {\r\n const date = lastmodValue instanceof Date ? lastmodValue.toISOString() : lastmodValue;\r\n xml += ` <lastmod>${date}</lastmod>\\n`;\r\n }\r\n\r\n if (entry.changefreq) {\r\n xml += ` <changefreq>${entry.changefreq}</changefreq>\\n`;\r\n }\r\n\r\n if (entry.priority !== undefined) {\r\n xml += ` <priority>${(entry.priority as number).toFixed(1)}</priority>\\n`;\r\n }\r\n\r\n // Extension Images\r\n if (entry.images?.length) {\r\n for (const img of entry.images) {\r\n const cleanImgUrl = sanitizeAndValidateUrl(img.loc, 'image location');\r\n xml += ` <image:image>\\n`;\r\n xml += ` <image:loc>${escapeXml(cleanImgUrl)}</image:loc>\\n`;\r\n if (img.title) xml += ` <image:title>${escapeXml(img.title)}</image:title>\\n`;\r\n if (img.caption) xml += ` <image:caption>${escapeXml(img.caption)}</image:caption>\\n`;\r\n xml += ` </image:image>\\n`;\r\n }\r\n }\r\n\r\n // Extension Vidéos\r\n if (entry.videos?.length) {\r\n for (const vid of entry.videos) {\r\n const cleanThumbLoc = sanitizeAndValidateUrl(vid.thumbnail_loc, 'video thumbnail');\r\n const cleanContentLoc = vid.content_loc ? sanitizeAndValidateUrl(vid.content_loc, 'video content location') : undefined;\r\n const cleanPlayerLoc = vid.player_loc ? sanitizeAndValidateUrl(vid.player_loc, 'video player location') : undefined;\r\n\r\n xml += ` <video:video>\\n`;\r\n xml += ` <video:thumbnail_loc>${escapeXml(cleanThumbLoc)}</video:thumbnail_loc>\\n`;\r\n xml += ` <video:title>${escapeXml(vid.title)}</video:title>\\n`;\r\n xml += ` <video:description>${escapeXml(vid.description)}</video:description>\\n`;\r\n \r\n if (cleanContentLoc) xml += ` <video:content_loc>${escapeXml(cleanContentLoc)}</video:content_loc>\\n`;\r\n if (cleanPlayerLoc) xml += ` <video:player_loc>${escapeXml(cleanPlayerLoc)}</video:player_loc>\\n`;\r\n \r\n if (vid.publication_date) {\r\n const vDate = vid.publication_date instanceof Date ? vid.publication_date.toISOString() : vid.publication_date;\r\n xml += ` <video:publication_date>${vDate}</video:publication_date>\\n`;\r\n }\r\n xml += ` </video:video>\\n`;\r\n }\r\n }\r\n\r\n // Extension News\r\n if (entry.news) {\r\n const nDate = entry.news.publication_date instanceof Date ? entry.news.publication_date.toISOString() : entry.news.publication_date;\r\n xml += ` <news:news>\\n`;\r\n xml += ` <news:publication>\\n`;\r\n xml += ` <news:name>${escapeXml(entry.news.name)}</news:name>\\n`;\r\n xml += ` <news:language>${escapeXml(entry.news.language)}</news:language>\\n`;\r\n xml += ` </news:publication>\\n`;\r\n xml += ` <news:publication_date>${nDate}</news:publication_date>\\n`;\r\n xml += ` <news:title>${escapeXml(entry.news.title)}</news:title>\\n`;\r\n xml += ` </news:news>\\n`;\r\n }\r\n\r\n xml += ` </url>\\n`;\r\n }\r\n\r\n xml += `</urlset>`;\r\n return xml;\r\n}","/* * Copyright (c) 2026 Fordi / FomaDev. \r\n * Licensed under FomaDev Public License.\r\n * See LICENSE file in the project root for full license information.\r\n */\r\n\r\nimport { SitemapEntry, SitemapOptions } from './types/sitemap.js';\r\nimport { generateXml } from './core/generator.js';\r\n\r\nexport * from './types/sitemap.js';\r\n\r\n/**\r\n * Génère une réponse HTTP compatible Next.js (App Router) avec options de configuration.\r\n * * @param entries - Liste des entrées du sitemap\r\n * @param options - Options de génération facultatives (ex: autoLastmod)\r\n * @returns Une instance de Response contenant le flux XML configuré\r\n */\r\nexport function getServerSitemapResponse(\r\n entries: SitemapEntry[], \r\n options: SitemapOptions = {}\r\n): Response {\r\n const xml = generateXml(entries, options);\r\n\r\n return new Response(xml, {\r\n headers: {\r\n 'Content-Type': 'application/xml',\r\n 'Cache-Control': 'public, s-maxage=86400, stale-while-revalidate',\r\n },\r\n });\r\n}"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-advanced-sitemap",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Advanced sitemap generator for Next.js. Powerful support for Google Images, Video, News, and Hreflang (multilingual). Type-safe, zero-dependency, and built for App Router.",
|
|
6
6
|
"main": "./dist/index.cjs",
|