next-advanced-sitemap 1.0.4 → 1.0.6
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 +25 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -5
- package/dist/index.d.ts +15 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@ 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
|
+
- **Native Date Polymorphism (v1.0.6)**: Full support for native JavaScript `Date` objects inside Google News and Video extensions—no manual conversion required.
|
|
16
|
+
- **Strict SEO Enum Typing (v1.0.5)**: Compile-time validation and IDE autocompletion for `changefreq` and `priority` values to prevent typos.
|
|
15
17
|
- **Strict Structural Validation (v1.0.4)**: Advanced URL parsing using the platform-native engine to intercept syntax errors and unencoded whitespaces before deployment.
|
|
16
18
|
- **Auto-lastmod (v1.0.3)**: Optional automatic injection of the current system date for entries missing a `lastmod` value.
|
|
17
19
|
- **Advanced XML Escaping (v1.0.2)**: Enhanced processor to handle complex special characters (`&`, `"`, `'`, `<`, `>`) in SEO metadata, ensuring XML integrity.
|
|
@@ -35,8 +37,8 @@ export async function GET() {
|
|
|
35
37
|
{
|
|
36
38
|
url: 'https://fomadev.com',
|
|
37
39
|
lastmod: new Date(),
|
|
38
|
-
changefreq: 'daily',
|
|
39
|
-
priority: 1.0,
|
|
40
|
+
changefreq: 'daily', // Strictly typed
|
|
41
|
+
priority: 1.0, // Auto-completed and strictly typed
|
|
40
42
|
alternates: [
|
|
41
43
|
{ hreflang: 'fr', href: 'https://fomadev.com/fr' },
|
|
42
44
|
{ hreflang: 'en', href: 'https://fomadev.com/en' }
|
|
@@ -59,7 +61,7 @@ export async function GET() {
|
|
|
59
61
|
thumbnail_loc: 'https://fomadev.com/thumbs/tutorial.jpg',
|
|
60
62
|
title: 'Next.js Advanced SEO Tutorial',
|
|
61
63
|
description: 'Learn how to implement advanced sitemaps in Next.js & React.',
|
|
62
|
-
publication_date: new Date('2026-04-22')
|
|
64
|
+
publication_date: new Date('2026-04-22') // Accepts raw Date objects smoothly
|
|
63
65
|
}
|
|
64
66
|
]
|
|
65
67
|
}
|
|
@@ -103,13 +105,13 @@ Generates a standard Next.js `Response` object with the correct `application/xml
|
|
|
103
105
|
</tr>
|
|
104
106
|
<tr>
|
|
105
107
|
<td><code>changefreq</code></td>
|
|
106
|
-
<td class="type-label">
|
|
107
|
-
<td>(Optional)
|
|
108
|
+
<td class="type-label">SitemapChangeFreq</td>
|
|
109
|
+
<td>(Optional) Bounded search engine hint ('always', 'daily', etc.).</td>
|
|
108
110
|
</tr>
|
|
109
111
|
<tr>
|
|
110
112
|
<td><code>priority</code></td>
|
|
111
|
-
<td class="type-label">
|
|
112
|
-
<td>(Optional)
|
|
113
|
+
<td class="type-label">SitemapPriority</td>
|
|
114
|
+
<td>(Optional) Bounded priority float value (0.0 to 1.0).</td>
|
|
113
115
|
</tr>
|
|
114
116
|
<tr>
|
|
115
117
|
<td><code>images</code></td>
|
|
@@ -136,17 +138,28 @@ Generates a standard Next.js `Response` object with the correct `application/xml
|
|
|
136
138
|
|
|
137
139
|
## Technical Implementation
|
|
138
140
|
|
|
139
|
-
###
|
|
141
|
+
### Native Date Polymorphism (v1.0.6 Update)
|
|
142
|
+
|
|
143
|
+
To simplify integrations with database mappers and modern ORMs (like Prisma, Supabase, or Mongoose) that output raw timestamps, the compiler implements native date polymorphism. Media structures (`SitemapNews` and `SitemapVideo`) accept both standard string layouts and full JavaScript `Date` instances. The internal pipeline evaluates instances using the `instanceof Date` boundary condition and automatically fires the `.toISOString()` handler when a native object is discovered, removing boilerplate conversion overhead.
|
|
144
|
+
|
|
145
|
+
### Compile-Time Parameter Guarding
|
|
146
|
+
|
|
147
|
+
To avoid syntax typos breaking standard crawler schemas (e.g. accidentally writing `"dayly"` instead of `"daily"`), the library replaces generic primitive types with rigid evaluation layers:
|
|
148
|
+
|
|
149
|
+
* **SitemapChangeFreq**: A literal string union restricting data ingestion exclusively to authorized keywords (`'always'` | `'hourly'` | `'daily'` | `'weekly'` | `'monthly'` | `'yearly'` | `'never'`).
|
|
150
|
+
|
|
151
|
+
* **SitemapPriority**: A custom intersection schema offering direct autocomplete properties across decimal steps from `0.0` to `1.0` within modern code editors while retaining flexibility for precise custom float variables.
|
|
152
|
+
|
|
153
|
+
### Validation & Safety
|
|
140
154
|
|
|
141
|
-
The library executes
|
|
155
|
+
The library executes deterministic validation layers on all URL inputs:
|
|
142
156
|
|
|
143
157
|
1. **Protocol Match**: Enforces that all strings begin strictly with an absolute `http://` or `https://` prefix.
|
|
144
158
|
|
|
145
|
-
2. **Whitespace Interception**: Instantly isolates and rejects strings containing unencoded internal spaces
|
|
159
|
+
2. **Whitespace Interception**: Instantly isolates and rejects strings containing unencoded internal spaces.
|
|
146
160
|
|
|
147
|
-
3. **Structural Compliance**: Leverages the native `URL.canParse`() API (with a clean fallback mechanism to the `new URL()` constructor
|
|
161
|
+
3. **Structural Compliance**: Leverages the native `URL.canParse`() API (with a clean fallback mechanism to the `new URL()` constructor) to validate layout health.
|
|
148
162
|
|
|
149
|
-
If any path breaks standard RFC specifications, the generator throws an explicit runtime exception to prevent the application from deploying a malformed payload.
|
|
150
163
|
|
|
151
164
|
### Advanced XML Security
|
|
152
165
|
|
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 * Valide de manière stricte le format et la structure d'une URL.\r\n */\r\nfunction validateUrl(url: string, context: string): void {\r\n // 1. 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 // 2. Sécurité v1.0.4 : Interdire strictement les espaces blancs 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 // 3. Validation fine de la structure globale via le moteur natif\r\n let isValid = false;\r\n \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\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 URL principale\r\n validateUrl(entry.url, 'main entry');\r\n\r\n xml += ` <url>\\n`;\r\n xml += ` <loc>${escapeXml(entry.url)}</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 validateUrl(alt.href, 'alternate link');\r\n xml += ` <xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(alt.href)}\" />\\n`;\r\n }\r\n }\r\n\r\n // --- LOGIQUE AUTO-LASTMOD ---\r\n let lastmodValue = entry.lastmod;\r\n \r\n // Si l'option est activée et que lastmod est absent, on injecte la date système actuelle\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 // Autres métadonnées standard\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 validateUrl(img.loc, 'image location');\r\n xml += ` <image:image>\\n`;\r\n xml += ` <image:loc>${escapeXml(img.loc)}</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 validateUrl(vid.thumbnail_loc, 'video thumbnail');\r\n if (vid.content_loc) validateUrl(vid.content_loc, 'video content location');\r\n if (vid.player_loc) validateUrl(vid.player_loc, 'video player location');\r\n\r\n xml += ` <video:video>\\n`;\r\n xml += ` <video:thumbnail_loc>${escapeXml(vid.thumbnail_loc)}</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 (vid.content_loc) xml += ` <video:content_loc>${escapeXml(vid.content_loc)}</video:content_loc>\\n`;\r\n if (vid.player_loc) xml += ` <video:player_loc>${escapeXml(vid.player_loc)}</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 * Valide de manière stricte le format et la structure d'une URL.\r\n */\r\nfunction validateUrl(url: string, context: string): void {\r\n // 1. 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 // 2. Sécurité v1.0.4 : Interdire strictement les espaces blancs 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 // 3. Validation fine de la structure globale via le moteur natif\r\n let isValid = false;\r\n \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\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 URL principale\r\n validateUrl(entry.url, 'main entry');\r\n\r\n xml += ` <url>\\n`;\r\n xml += ` <loc>${escapeXml(entry.url)}</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 validateUrl(alt.href, 'alternate link');\r\n xml += ` <xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(alt.href)}\" />\\n`;\r\n }\r\n }\r\n\r\n // --- LOGIQUE AUTO-LASTMOD ---\r\n let lastmodValue = entry.lastmod;\r\n \r\n // Si l'option est activée et que lastmod est absent, on injecte la date système actuelle\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 // Autres métadonnées standard\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 validateUrl(img.loc, 'image location');\r\n xml += ` <image:image>\\n`;\r\n xml += ` <image:loc>${escapeXml(img.loc)}</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 validateUrl(vid.thumbnail_loc, 'video thumbnail');\r\n if (vid.content_loc) validateUrl(vid.content_loc, 'video content location');\r\n if (vid.player_loc) validateUrl(vid.player_loc, 'video player location');\r\n\r\n xml += ` <video:video>\\n`;\r\n xml += ` <video:thumbnail_loc>${escapeXml(vid.thumbnail_loc)}</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 (vid.content_loc) xml += ` <video:content_loc>${escapeXml(vid.content_loc)}</video:content_loc>\\n`;\r\n if (vid.player_loc) xml += ` <video:player_loc>${escapeXml(vid.player_loc)}</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 (v1.0.6 : Support polymorphe Date | string)\r\n if (entry.news) {\r\n const nDate = entry.news.publication_date instanceof Date \r\n ? entry.news.publication_date.toISOString() \r\n : entry.news.publication_date;\r\n\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
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fréquences de changement autorisées dans la spécification des sitemaps
|
|
3
|
+
*/
|
|
4
|
+
type SitemapChangeFreq = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
5
|
+
/**
|
|
6
|
+
* Priorités recommandées (de 0.0 à 1.0)
|
|
7
|
+
* L'intersection (number & {}) permet de conserver l'autocomplétion des paliers
|
|
8
|
+
* tout en acceptant n'importe quel autre nombre flottant.
|
|
9
|
+
*/
|
|
10
|
+
type SitemapPriority = 0.0 | 0.1 | 0.2 | 0.3 | 0.4 | 0.5 | 0.6 | 0.7 | 0.8 | 0.9 | 1.0 | (number & {});
|
|
1
11
|
/**
|
|
2
12
|
* Interface pour les liens alternatifs (Hreflang / Multilingue)
|
|
3
13
|
* @see https://developers.google.com/search/docs/specialty/international/localized-versions#sitemap
|
|
@@ -29,7 +39,7 @@ interface SitemapVideo {
|
|
|
29
39
|
player_loc?: string;
|
|
30
40
|
duration?: number;
|
|
31
41
|
view_count?: number;
|
|
32
|
-
publication_date?:
|
|
42
|
+
publication_date?: Date | string;
|
|
33
43
|
family_friendly?: 'yes' | 'no';
|
|
34
44
|
}
|
|
35
45
|
/**
|
|
@@ -39,7 +49,7 @@ interface SitemapVideo {
|
|
|
39
49
|
interface SitemapNews {
|
|
40
50
|
name: string;
|
|
41
51
|
language: string;
|
|
42
|
-
publication_date:
|
|
52
|
+
publication_date: Date | string;
|
|
43
53
|
title: string;
|
|
44
54
|
}
|
|
45
55
|
/**
|
|
@@ -48,8 +58,8 @@ interface SitemapNews {
|
|
|
48
58
|
interface SitemapEntry {
|
|
49
59
|
url: string;
|
|
50
60
|
lastmod?: string | Date;
|
|
51
|
-
changefreq?:
|
|
52
|
-
priority?:
|
|
61
|
+
changefreq?: SitemapChangeFreq;
|
|
62
|
+
priority?: SitemapPriority;
|
|
53
63
|
images?: SitemapImage[];
|
|
54
64
|
videos?: SitemapVideo[];
|
|
55
65
|
news?: SitemapNews;
|
|
@@ -74,4 +84,4 @@ interface SitemapOptions {
|
|
|
74
84
|
*/
|
|
75
85
|
declare function getServerSitemapResponse(entries: SitemapEntry[], options?: SitemapOptions): Response;
|
|
76
86
|
|
|
77
|
-
export { type SitemapAlternate, type SitemapEntry, type SitemapImage, type SitemapNews, type SitemapOptions, type SitemapVideo, getServerSitemapResponse };
|
|
87
|
+
export { type SitemapAlternate, type SitemapChangeFreq, type SitemapEntry, type SitemapImage, type SitemapNews, type SitemapOptions, type SitemapPriority, type SitemapVideo, getServerSitemapResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fréquences de changement autorisées dans la spécification des sitemaps
|
|
3
|
+
*/
|
|
4
|
+
type SitemapChangeFreq = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
5
|
+
/**
|
|
6
|
+
* Priorités recommandées (de 0.0 à 1.0)
|
|
7
|
+
* L'intersection (number & {}) permet de conserver l'autocomplétion des paliers
|
|
8
|
+
* tout en acceptant n'importe quel autre nombre flottant.
|
|
9
|
+
*/
|
|
10
|
+
type SitemapPriority = 0.0 | 0.1 | 0.2 | 0.3 | 0.4 | 0.5 | 0.6 | 0.7 | 0.8 | 0.9 | 1.0 | (number & {});
|
|
1
11
|
/**
|
|
2
12
|
* Interface pour les liens alternatifs (Hreflang / Multilingue)
|
|
3
13
|
* @see https://developers.google.com/search/docs/specialty/international/localized-versions#sitemap
|
|
@@ -29,7 +39,7 @@ interface SitemapVideo {
|
|
|
29
39
|
player_loc?: string;
|
|
30
40
|
duration?: number;
|
|
31
41
|
view_count?: number;
|
|
32
|
-
publication_date?:
|
|
42
|
+
publication_date?: Date | string;
|
|
33
43
|
family_friendly?: 'yes' | 'no';
|
|
34
44
|
}
|
|
35
45
|
/**
|
|
@@ -39,7 +49,7 @@ interface SitemapVideo {
|
|
|
39
49
|
interface SitemapNews {
|
|
40
50
|
name: string;
|
|
41
51
|
language: string;
|
|
42
|
-
publication_date:
|
|
52
|
+
publication_date: Date | string;
|
|
43
53
|
title: string;
|
|
44
54
|
}
|
|
45
55
|
/**
|
|
@@ -48,8 +58,8 @@ interface SitemapNews {
|
|
|
48
58
|
interface SitemapEntry {
|
|
49
59
|
url: string;
|
|
50
60
|
lastmod?: string | Date;
|
|
51
|
-
changefreq?:
|
|
52
|
-
priority?:
|
|
61
|
+
changefreq?: SitemapChangeFreq;
|
|
62
|
+
priority?: SitemapPriority;
|
|
53
63
|
images?: SitemapImage[];
|
|
54
64
|
videos?: SitemapVideo[];
|
|
55
65
|
news?: SitemapNews;
|
|
@@ -74,4 +84,4 @@ interface SitemapOptions {
|
|
|
74
84
|
*/
|
|
75
85
|
declare function getServerSitemapResponse(entries: SitemapEntry[], options?: SitemapOptions): Response;
|
|
76
86
|
|
|
77
|
-
export { type SitemapAlternate, type SitemapEntry, type SitemapImage, type SitemapNews, type SitemapOptions, type SitemapVideo, getServerSitemapResponse };
|
|
87
|
+
export { type SitemapAlternate, type SitemapChangeFreq, type SitemapEntry, type SitemapImage, type SitemapNews, type SitemapOptions, type SitemapPriority, type SitemapVideo, getServerSitemapResponse };
|
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 * Valide de manière stricte le format et la structure d'une URL.\r\n */\r\nfunction validateUrl(url: string, context: string): void {\r\n // 1. 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 // 2. Sécurité v1.0.4 : Interdire strictement les espaces blancs 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 // 3. Validation fine de la structure globale via le moteur natif\r\n let isValid = false;\r\n \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\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 URL principale\r\n validateUrl(entry.url, 'main entry');\r\n\r\n xml += ` <url>\\n`;\r\n xml += ` <loc>${escapeXml(entry.url)}</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 validateUrl(alt.href, 'alternate link');\r\n xml += ` <xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(alt.href)}\" />\\n`;\r\n }\r\n }\r\n\r\n // --- LOGIQUE AUTO-LASTMOD ---\r\n let lastmodValue = entry.lastmod;\r\n \r\n // Si l'option est activée et que lastmod est absent, on injecte la date système actuelle\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 // Autres métadonnées standard\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 validateUrl(img.loc, 'image location');\r\n xml += ` <image:image>\\n`;\r\n xml += ` <image:loc>${escapeXml(img.loc)}</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 validateUrl(vid.thumbnail_loc, 'video thumbnail');\r\n if (vid.content_loc) validateUrl(vid.content_loc, 'video content location');\r\n if (vid.player_loc) validateUrl(vid.player_loc, 'video player location');\r\n\r\n xml += ` <video:video>\\n`;\r\n xml += ` <video:thumbnail_loc>${escapeXml(vid.thumbnail_loc)}</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 (vid.content_loc) xml += ` <video:content_loc>${escapeXml(vid.content_loc)}</video:content_loc>\\n`;\r\n if (vid.player_loc) xml += ` <video:player_loc>${escapeXml(vid.player_loc)}</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":";AASO,SAAS,UAAU,QAA2C;AACnE,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO,OAAO,QAAQ,YAAY,CAAC,MAAM;AACvC,YAAQ,GAAG;AAAA,MACT,KAAK;AAAK,eAAO;AAAA,MACjB,KAAK;AAAK,eAAO;AAAA,MACjB,KAAK;AAAK,eAAO;AAAA,MACjB,KAAK;AAAK,eAAO;AAAA,MACjB,KAAK;AAAK,eAAO;AAAA,MACjB;AAAS,eAAO;AAAA,IAClB;AAAA,EACF,CAAC;AACH;;;ACXA,SAAS,YAAY,KAAa,SAAuB;AAEvD,MAAI,CAAC,IAAI,WAAW,SAAS,KAAK,CAAC,IAAI,WAAW,UAAU,GAAG;AAC7D,UAAM,IAAI;AAAA,MACR,0CAA0C,OAAO,MAAM,GAAG;AAAA,IAC5D;AAAA,EACF;AAGA,MAAI,IAAI,SAAS,GAAG,GAAG;AACrB,UAAM,IAAI;AAAA,MACR,+DAA+D,OAAO,MAAM,GAAG;AAAA,IACjF;AAAA,EACF;AAGA,MAAI,UAAU;AAEd,MAAI,OAAO,IAAI,aAAa,YAAY;AACtC,cAAU,IAAI,SAAS,GAAG;AAAA,EAC5B,OAAO;AACL,QAAI;AACF,UAAI,IAAI,GAAG;AACX,gBAAU;AAAA,IACZ,QAAQ;AACN,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,+DAA+D,OAAO,MAAM,GAAG;AAAA,IACjF;AAAA,EACF;AACF;AAKO,SAAS,YAAY,SAAyB,UAA0B,CAAC,GAAW;AACzF,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,MAAI,MAAM;AAAA;AACV,SAAO;AAAA;AACP,SAAO;AAAA;AACP,SAAO;AAAA;AACP,SAAO;AAAA;AACP,SAAO;AAAA;AAEP,aAAW,SAAS,SAAS;AAE3B,gBAAY,MAAM,KAAK,YAAY;AAEnC,WAAO;AAAA;AACP,WAAO,YAAY,UAAU,MAAM,GAAG,CAAC;AAAA;AAGvC,QAAI,MAAM,YAAY,QAAQ;AAC5B,iBAAW,OAAO,MAAM,YAAY;AAClC,oBAAY,IAAI,MAAM,gBAAgB;AACtC,eAAO,6CAA6C,UAAU,IAAI,QAAQ,CAAC,WAAW,UAAU,IAAI,IAAI,CAAC;AAAA;AAAA,MAC3G;AAAA,IACF;AAGA,QAAI,eAAe,MAAM;AAGzB,QAAI,QAAQ,eAAe,CAAC,cAAc;AACxC,qBAAe;AAAA,IACjB;AAEA,QAAI,cAAc;AAChB,YAAM,OAAO,wBAAwB,OAAO,aAAa,YAAY,IAAI;AACzE,aAAO,gBAAgB,IAAI;AAAA;AAAA,IAC7B;AAGA,QAAI,MAAM,YAAY;AACpB,aAAO,mBAAmB,MAAM,UAAU;AAAA;AAAA,IAC5C;AAEA,QAAI,MAAM,aAAa,QAAW;AAChC,aAAO,iBAAiB,MAAM,SAAS,QAAQ,CAAC,CAAC;AAAA;AAAA,IACnD;AAGA,QAAI,MAAM,QAAQ,QAAQ;AACxB,iBAAW,OAAO,MAAM,QAAQ;AAC9B,oBAAY,IAAI,KAAK,gBAAgB;AACrC,eAAO;AAAA;AACP,eAAO,oBAAoB,UAAU,IAAI,GAAG,CAAC;AAAA;AAC7C,YAAI,IAAI,MAAO,QAAO,sBAAsB,UAAU,IAAI,KAAK,CAAC;AAAA;AAChE,YAAI,IAAI,QAAS,QAAO,wBAAwB,UAAU,IAAI,OAAO,CAAC;AAAA;AACtE,eAAO;AAAA;AAAA,MACT;AAAA,IACF;AAGA,QAAI,MAAM,QAAQ,QAAQ;AACxB,iBAAW,OAAO,MAAM,QAAQ;AAC9B,oBAAY,IAAI,eAAe,iBAAiB;AAChD,YAAI,IAAI,YAAa,aAAY,IAAI,aAAa,wBAAwB;AAC1E,YAAI,IAAI,WAAY,aAAY,IAAI,YAAY,uBAAuB;AAEvE,eAAO;AAAA;AACP,eAAO,8BAA8B,UAAU,IAAI,aAAa,CAAC;AAAA;AACjE,eAAO,sBAAsB,UAAU,IAAI,KAAK,CAAC;AAAA;AACjD,eAAO,4BAA4B,UAAU,IAAI,WAAW,CAAC;AAAA;AAE7D,YAAI,IAAI,YAAa,QAAO,4BAA4B,UAAU,IAAI,WAAW,CAAC;AAAA;AAClF,YAAI,IAAI,WAAY,QAAO,2BAA2B,UAAU,IAAI,UAAU,CAAC;AAAA;AAE/E,YAAI,IAAI,kBAAkB;AACxB,gBAAM,QAAQ,IAAI,4BAA4B,OAAO,IAAI,iBAAiB,YAAY,IAAI,IAAI;AAC9F,iBAAO,iCAAiC,KAAK;AAAA;AAAA,QAC/C;AACA,eAAO;AAAA;AAAA,MACT;AAAA,IACF;AAGA,QAAI,MAAM,MAAM;AACd,YAAM,QAAQ,MAAM,KAAK,4BAA4B,OAAO,MAAM,KAAK,iBAAiB,YAAY,IAAI,MAAM,KAAK;AACnH,aAAO;AAAA;AACP,aAAO;AAAA;AACP,aAAO,sBAAsB,UAAU,MAAM,KAAK,IAAI,CAAC;AAAA;AACvD,aAAO,0BAA0B,UAAU,MAAM,KAAK,QAAQ,CAAC;AAAA;AAC/D,aAAO;AAAA;AACP,aAAO,gCAAgC,KAAK;AAAA;AAC5C,aAAO,qBAAqB,UAAU,MAAM,KAAK,KAAK,CAAC;AAAA;AACvD,aAAO;AAAA;AAAA,IACT;AAEA,WAAO;AAAA;AAAA,EACT;AAEA,SAAO;AACP,SAAO;AACT;;;ACtIO,SAAS,yBACd,SACA,UAA0B,CAAC,GACjB;AACV,QAAM,MAAM,YAAY,SAAS,OAAO;AAExC,SAAO,IAAI,SAAS,KAAK;AAAA,IACvB,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,IACnB;AAAA,EACF,CAAC;AACH;","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 * Valide de manière stricte le format et la structure d'une URL.\r\n */\r\nfunction validateUrl(url: string, context: string): void {\r\n // 1. 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 // 2. Sécurité v1.0.4 : Interdire strictement les espaces blancs 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 // 3. Validation fine de la structure globale via le moteur natif\r\n let isValid = false;\r\n \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\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 URL principale\r\n validateUrl(entry.url, 'main entry');\r\n\r\n xml += ` <url>\\n`;\r\n xml += ` <loc>${escapeXml(entry.url)}</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 validateUrl(alt.href, 'alternate link');\r\n xml += ` <xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(alt.href)}\" />\\n`;\r\n }\r\n }\r\n\r\n // --- LOGIQUE AUTO-LASTMOD ---\r\n let lastmodValue = entry.lastmod;\r\n \r\n // Si l'option est activée et que lastmod est absent, on injecte la date système actuelle\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 // Autres métadonnées standard\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 validateUrl(img.loc, 'image location');\r\n xml += ` <image:image>\\n`;\r\n xml += ` <image:loc>${escapeXml(img.loc)}</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 validateUrl(vid.thumbnail_loc, 'video thumbnail');\r\n if (vid.content_loc) validateUrl(vid.content_loc, 'video content location');\r\n if (vid.player_loc) validateUrl(vid.player_loc, 'video player location');\r\n\r\n xml += ` <video:video>\\n`;\r\n xml += ` <video:thumbnail_loc>${escapeXml(vid.thumbnail_loc)}</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 (vid.content_loc) xml += ` <video:content_loc>${escapeXml(vid.content_loc)}</video:content_loc>\\n`;\r\n if (vid.player_loc) xml += ` <video:player_loc>${escapeXml(vid.player_loc)}</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 (v1.0.6 : Support polymorphe Date | string)\r\n if (entry.news) {\r\n const nDate = entry.news.publication_date instanceof Date \r\n ? entry.news.publication_date.toISOString() \r\n : entry.news.publication_date;\r\n\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.6",
|
|
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",
|