@power-seo/sitemap 1.0.2 → 1.0.5

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/dist/index.cjs CHANGED
@@ -1,8 +1,38 @@
1
- 'use strict';
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
2
19
 
3
- var core = require('@power-seo/core');
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ MAX_SITEMAP_SIZE_BYTES: () => MAX_SITEMAP_SIZE_BYTES,
24
+ MAX_URLS_PER_SITEMAP: () => MAX_URLS_PER_SITEMAP,
25
+ generateSitemap: () => generateSitemap,
26
+ generateSitemapIndex: () => generateSitemapIndex,
27
+ splitSitemap: () => splitSitemap,
28
+ streamSitemap: () => streamSitemap,
29
+ toNextSitemap: () => toNextSitemap,
30
+ validateSitemapUrl: () => validateSitemapUrl
31
+ });
32
+ module.exports = __toCommonJS(index_exports);
4
33
 
5
34
  // src/generator.ts
35
+ var import_core = require("@power-seo/core");
6
36
  function escapeXml(str) {
7
37
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
8
38
  }
@@ -91,7 +121,7 @@ function buildNewsXml(news) {
91
121
  return xml;
92
122
  }
93
123
  function buildUrlXml(url, hostname) {
94
- const loc = url.loc.startsWith("http") ? url.loc : core.normalizeUrl(`${hostname}${url.loc.startsWith("/") ? "" : "/"}${url.loc}`);
124
+ const loc = url.loc.startsWith("http") ? url.loc : (0, import_core.normalizeUrl)(`${hostname}${url.loc.startsWith("/") ? "" : "/"}${url.loc}`);
95
125
  let xml = " <url>\n";
96
126
  xml += ` <loc>${escapeXml(loc)}</loc>
97
127
  `;
@@ -125,7 +155,7 @@ function generateSitemap(config) {
125
155
 
126
156
  // src/types.ts
127
157
  var MAX_URLS_PER_SITEMAP = 5e4;
128
- var MAX_SITEMAP_SIZE_BYTES = 50 * 1024 * 1024;
158
+ var MAX_SITEMAP_SIZE_BYTES = 52428800;
129
159
 
130
160
  // src/sitemap-index.ts
131
161
  function escapeXml2(str) {
@@ -174,6 +204,9 @@ function splitSitemap(config, sitemapUrlPattern = "/sitemap-{index}.xml") {
174
204
  sitemaps
175
205
  };
176
206
  }
207
+
208
+ // src/stream.ts
209
+ var import_core2 = require("@power-seo/core");
177
210
  function escapeXml3(str) {
178
211
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
179
212
  }
@@ -184,7 +217,7 @@ function* streamSitemap(hostname, urls) {
184
217
  yield ' xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"\n';
185
218
  yield ' xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">\n';
186
219
  for (const url of urls) {
187
- const loc = url.loc.startsWith("http") ? url.loc : core.normalizeUrl(`${hostname}${url.loc.startsWith("/") ? "" : "/"}${url.loc}`);
220
+ const loc = url.loc.startsWith("http") ? url.loc : (0, import_core2.normalizeUrl)(`${hostname}${url.loc.startsWith("/") ? "" : "/"}${url.loc}`);
188
221
  yield " <url>\n";
189
222
  yield ` <loc>${escapeXml3(loc)}</loc>
190
223
  `;
@@ -242,6 +275,9 @@ function* streamSitemap(hostname, urls) {
242
275
  }
243
276
  yield "</urlset>\n";
244
277
  }
278
+
279
+ // src/validate.ts
280
+ var import_core3 = require("@power-seo/core");
245
281
  var VALID_CHANGEFREQ = ["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"];
246
282
  function validateSitemapUrl(url) {
247
283
  const errors = [];
@@ -249,15 +285,15 @@ function validateSitemapUrl(url) {
249
285
  if (!url.loc || url.loc.trim().length === 0) {
250
286
  errors.push('URL "loc" is required and cannot be empty.');
251
287
  } else {
252
- if (!core.isAbsoluteUrl(url.loc)) {
288
+ if (!(0, import_core3.isAbsoluteUrl)(url.loc)) {
253
289
  errors.push(`URL "${url.loc}" must be an absolute URL (starting with http:// or https://).`);
254
290
  }
255
291
  if (url.loc.length > 2048) {
256
292
  errors.push(`URL "${url.loc}" exceeds the maximum length of 2048 characters.`);
257
293
  }
258
- if (url.loc.length > core.MAX_URL_LENGTH) {
294
+ if (url.loc.length > import_core3.MAX_URL_LENGTH) {
259
295
  warnings.push(
260
- `URL "${url.loc}" is ${url.loc.length} characters. URLs under ${core.MAX_URL_LENGTH} characters are recommended for SEO.`
296
+ `URL "${url.loc}" is ${url.loc.length} characters. URLs under ${import_core3.MAX_URL_LENGTH} characters are recommended for SEO.`
261
297
  );
262
298
  }
263
299
  }
@@ -284,7 +320,7 @@ function validateSitemapUrl(url) {
284
320
  const img = url.images[i];
285
321
  if (!img.loc || img.loc.trim().length === 0) {
286
322
  errors.push(`Image ${i + 1}: "loc" is required.`);
287
- } else if (!core.isAbsoluteUrl(img.loc)) {
323
+ } else if (!(0, import_core3.isAbsoluteUrl)(img.loc)) {
288
324
  errors.push(`Image ${i + 1}: "${img.loc}" must be an absolute URL.`);
289
325
  }
290
326
  }
@@ -321,12 +357,35 @@ function validateSitemapUrl(url) {
321
357
  };
322
358
  }
323
359
 
324
- exports.MAX_SITEMAP_SIZE_BYTES = MAX_SITEMAP_SIZE_BYTES;
325
- exports.MAX_URLS_PER_SITEMAP = MAX_URLS_PER_SITEMAP;
326
- exports.generateSitemap = generateSitemap;
327
- exports.generateSitemapIndex = generateSitemapIndex;
328
- exports.splitSitemap = splitSitemap;
329
- exports.streamSitemap = streamSitemap;
330
- exports.validateSitemapUrl = validateSitemapUrl;
331
- //# sourceMappingURL=index.cjs.map
360
+ // src/next-adapter.ts
361
+ function toNextSitemap(urls) {
362
+ const entries = [];
363
+ for (const url of urls) {
364
+ const { valid } = validateSitemapUrl(url);
365
+ if (!valid) continue;
366
+ const entry = { url: url.loc };
367
+ if (url.lastmod) {
368
+ entry.lastModified = url.lastmod;
369
+ }
370
+ if (url.changefreq) {
371
+ entry.changeFrequency = url.changefreq;
372
+ }
373
+ if (url.priority !== void 0) {
374
+ entry.priority = url.priority;
375
+ }
376
+ entries.push(entry);
377
+ }
378
+ return entries;
379
+ }
380
+ // Annotate the CommonJS export names for ESM import in node:
381
+ 0 && (module.exports = {
382
+ MAX_SITEMAP_SIZE_BYTES,
383
+ MAX_URLS_PER_SITEMAP,
384
+ generateSitemap,
385
+ generateSitemapIndex,
386
+ splitSitemap,
387
+ streamSitemap,
388
+ toNextSitemap,
389
+ validateSitemapUrl
390
+ });
332
391
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/generator.ts","../src/types.ts","../src/sitemap-index.ts","../src/stream.ts","../src/validate.ts"],"names":["normalizeUrl","escapeXml","indexEntries","isAbsoluteUrl","MAX_URL_LENGTH"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\n// @power-seo/sitemap — XML Sitemap Generator\n// ============================================================================\n\nimport type {\n SitemapConfig,\n SitemapURL,\n SitemapImage,\n SitemapVideo,\n SitemapNews,\n} from '@power-seo/core';\nimport { normalizeUrl } from '@power-seo/core';\n\n/** Escape special XML characters. */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/** Determine which namespace extensions are needed. */\nfunction detectNamespaces(urls: SitemapURL[]): { image: boolean; video: boolean; news: boolean } {\n let image = false;\n let video = false;\n let news = false;\n for (const url of urls) {\n if (url.images && url.images.length > 0) image = true;\n if (url.videos && url.videos.length > 0) video = true;\n if (url.news) news = true;\n if (image && video && news) break;\n }\n return { image, video, news };\n}\n\nfunction buildImageXml(images: SitemapImage[]): string {\n return images\n .map((img) => {\n let xml = ' <image:image>\\n';\n xml += ` <image:loc>${escapeXml(img.loc)}</image:loc>\\n`;\n if (img.caption) xml += ` <image:caption>${escapeXml(img.caption)}</image:caption>\\n`;\n if (img.geoLocation)\n xml += ` <image:geo_location>${escapeXml(img.geoLocation)}</image:geo_location>\\n`;\n if (img.title) xml += ` <image:title>${escapeXml(img.title)}</image:title>\\n`;\n if (img.license) xml += ` <image:license>${escapeXml(img.license)}</image:license>\\n`;\n xml += ' </image:image>\\n';\n return xml;\n })\n .join('');\n}\n\nfunction buildVideoXml(videos: SitemapVideo[]): string {\n return videos\n .map((vid) => {\n let xml = ' <video:video>\\n';\n xml += ` <video:thumbnail_loc>${escapeXml(vid.thumbnailLoc)}</video:thumbnail_loc>\\n`;\n xml += ` <video:title>${escapeXml(vid.title)}</video:title>\\n`;\n xml += ` <video:description>${escapeXml(vid.description)}</video:description>\\n`;\n if (vid.contentLoc)\n xml += ` <video:content_loc>${escapeXml(vid.contentLoc)}</video:content_loc>\\n`;\n if (vid.playerLoc)\n xml += ` <video:player_loc>${escapeXml(vid.playerLoc)}</video:player_loc>\\n`;\n if (vid.duration !== undefined)\n xml += ` <video:duration>${vid.duration}</video:duration>\\n`;\n if (vid.expirationDate)\n xml += ` <video:expiration_date>${escapeXml(vid.expirationDate)}</video:expiration_date>\\n`;\n if (vid.rating !== undefined) xml += ` <video:rating>${vid.rating}</video:rating>\\n`;\n if (vid.viewCount !== undefined)\n xml += ` <video:view_count>${vid.viewCount}</video:view_count>\\n`;\n if (vid.publicationDate)\n xml += ` <video:publication_date>${escapeXml(vid.publicationDate)}</video:publication_date>\\n`;\n if (vid.familyFriendly !== undefined)\n xml += ` <video:family_friendly>${vid.familyFriendly ? 'yes' : 'no'}</video:family_friendly>\\n`;\n if (vid.live !== undefined)\n xml += ` <video:live>${vid.live ? 'yes' : 'no'}</video:live>\\n`;\n xml += ' </video:video>\\n';\n return xml;\n })\n .join('');\n}\n\nfunction buildNewsXml(news: SitemapNews): string {\n let xml = ' <news:news>\\n';\n xml += ' <news:publication>\\n';\n xml += ` <news:name>${escapeXml(news.publication.name)}</news:name>\\n`;\n xml += ` <news:language>${escapeXml(news.publication.language)}</news:language>\\n`;\n xml += ' </news:publication>\\n';\n xml += ` <news:publication_date>${escapeXml(news.publicationDate)}</news:publication_date>\\n`;\n xml += ` <news:title>${escapeXml(news.title)}</news:title>\\n`;\n xml += ' </news:news>\\n';\n return xml;\n}\n\nfunction buildUrlXml(url: SitemapURL, hostname: string): string {\n const loc = url.loc.startsWith('http')\n ? url.loc\n : normalizeUrl(`${hostname}${url.loc.startsWith('/') ? '' : '/'}${url.loc}`);\n\n let xml = ' <url>\\n';\n xml += ` <loc>${escapeXml(loc)}</loc>\\n`;\n if (url.lastmod) xml += ` <lastmod>${escapeXml(url.lastmod)}</lastmod>\\n`;\n if (url.changefreq) xml += ` <changefreq>${url.changefreq}</changefreq>\\n`;\n if (url.priority !== undefined) xml += ` <priority>${url.priority.toFixed(1)}</priority>\\n`;\n if (url.images && url.images.length > 0) xml += buildImageXml(url.images);\n if (url.videos && url.videos.length > 0) xml += buildVideoXml(url.videos);\n if (url.news) xml += buildNewsXml(url.news);\n xml += ' </url>\\n';\n return xml;\n}\n\n/**\n * Generate an XML sitemap string from a sitemap configuration.\n *\n * @example\n * ```ts\n * const xml = generateSitemap({\n * hostname: 'https://example.com',\n * urls: [\n * { loc: '/', changefreq: 'daily', priority: 1.0 },\n * { loc: '/about', changefreq: 'monthly', priority: 0.8 },\n * ],\n * });\n * ```\n */\nexport function generateSitemap(config: SitemapConfig): string {\n const { hostname, urls } = config;\n const ns = detectNamespaces(urls);\n\n let xml = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n xml += '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"';\n if (ns.image) xml += '\\n xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"';\n if (ns.video) xml += '\\n xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"';\n if (ns.news) xml += '\\n xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\"';\n xml += '>\\n';\n\n for (const url of urls) {\n xml += buildUrlXml(url, hostname);\n }\n\n xml += '</urlset>\\n';\n return xml;\n}\n","// ============================================================================\n// @power-seo/sitemap — Types\n// ============================================================================\n\nexport type {\n SitemapURL,\n SitemapImage,\n SitemapVideo,\n SitemapNews,\n SitemapConfig,\n} from '@power-seo/core';\n\n/** A sitemap entry in a sitemap index. */\nexport interface SitemapIndexEntry {\n loc: string;\n lastmod?: string;\n}\n\n/** Configuration for the sitemap index generator. */\nexport interface SitemapIndexConfig {\n sitemaps: SitemapIndexEntry[];\n}\n\n/** Result of URL validation. */\nexport interface SitemapValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\n/** Maximum URLs allowed per sitemap file. */\nexport const MAX_URLS_PER_SITEMAP = 50_000;\n\n/** Maximum sitemap file size in bytes (50MB). */\nexport const MAX_SITEMAP_SIZE_BYTES = 50 * 1024 * 1024;\n","// ============================================================================\n// @power-seo/sitemap — Sitemap Index Generator\n// ============================================================================\n\nimport type { SitemapConfig } from '@power-seo/core';\nimport type { SitemapIndexConfig, SitemapIndexEntry } from './types.js';\nimport { MAX_URLS_PER_SITEMAP } from './types.js';\nimport { generateSitemap } from './generator.js';\n\n/** Escape special XML characters. */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * Generate a sitemap index XML string.\n *\n * @example\n * ```ts\n * const indexXml = generateSitemapIndex({\n * sitemaps: [\n * { loc: 'https://example.com/sitemap-0.xml', lastmod: '2024-01-01' },\n * { loc: 'https://example.com/sitemap-1.xml', lastmod: '2024-01-01' },\n * ],\n * });\n * ```\n */\nexport function generateSitemapIndex(config: SitemapIndexConfig): string {\n let xml = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n xml += '<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n';\n\n for (const sitemap of config.sitemaps) {\n xml += ' <sitemap>\\n';\n xml += ` <loc>${escapeXml(sitemap.loc)}</loc>\\n`;\n if (sitemap.lastmod) {\n xml += ` <lastmod>${escapeXml(sitemap.lastmod)}</lastmod>\\n`;\n }\n xml += ' </sitemap>\\n';\n }\n\n xml += '</sitemapindex>\\n';\n return xml;\n}\n\n/**\n * Split a large sitemap config into multiple sitemaps + an index.\n *\n * When a site has more than 50,000 URLs, this function splits them into\n * multiple sitemap files and returns both the individual sitemaps and\n * the index that references them.\n *\n * @example\n * ```ts\n * const { index, sitemaps } = splitSitemap({\n * hostname: 'https://example.com',\n * urls: largeUrlArray,\n * });\n * // sitemaps[0].xml, sitemaps[1].xml, etc.\n * // index = sitemap index XML\n * ```\n */\nexport function splitSitemap(\n config: SitemapConfig,\n sitemapUrlPattern = '/sitemap-{index}.xml',\n): { index: string; sitemaps: Array<{ filename: string; xml: string }> } {\n const maxPerSitemap = config.maxUrlsPerSitemap ?? MAX_URLS_PER_SITEMAP;\n const { hostname, urls } = config;\n\n if (urls.length <= maxPerSitemap) {\n const xml = generateSitemap(config);\n const filename = sitemapUrlPattern.replace('{index}', '0');\n const indexEntries: SitemapIndexEntry[] = [{ loc: `${hostname}${filename}` }];\n return {\n index: generateSitemapIndex({ sitemaps: indexEntries }),\n sitemaps: [{ filename, xml }],\n };\n }\n\n const sitemaps: Array<{ filename: string; xml: string }> = [];\n const indexEntries: SitemapIndexEntry[] = [];\n\n for (let i = 0; i < urls.length; i += maxPerSitemap) {\n const chunk = urls.slice(i, i + maxPerSitemap);\n const chunkIndex = Math.floor(i / maxPerSitemap);\n const filename = sitemapUrlPattern.replace('{index}', String(chunkIndex));\n const xml = generateSitemap({ hostname, urls: chunk });\n\n sitemaps.push({ filename, xml });\n indexEntries.push({ loc: `${hostname}${filename}` });\n }\n\n return {\n index: generateSitemapIndex({ sitemaps: indexEntries }),\n sitemaps,\n };\n}\n","// ============================================================================\n// @power-seo/sitemap — Streaming Sitemap Generator\n// ============================================================================\n\nimport type { SitemapURL } from '@power-seo/core';\nimport { normalizeUrl } from '@power-seo/core';\n\n/** Escape special XML characters. */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * A streaming sitemap generator that yields XML chunks.\n *\n * Useful for server responses where you want to stream the sitemap\n * instead of building the entire XML string in memory.\n *\n * @example\n * ```ts\n * const stream = streamSitemap('https://example.com', urls);\n * for (const chunk of stream) {\n * response.write(chunk);\n * }\n * ```\n */\nexport function* streamSitemap(\n hostname: string,\n urls: Iterable<SitemapURL>,\n): Generator<string, void, undefined> {\n yield '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n yield '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\\n';\n yield ' xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"\\n';\n yield ' xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"\\n';\n yield ' xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\">\\n';\n\n for (const url of urls) {\n const loc = url.loc.startsWith('http')\n ? url.loc\n : normalizeUrl(`${hostname}${url.loc.startsWith('/') ? '' : '/'}${url.loc}`);\n\n yield ' <url>\\n';\n yield ` <loc>${escapeXml(loc)}</loc>\\n`;\n\n if (url.lastmod) yield ` <lastmod>${escapeXml(url.lastmod)}</lastmod>\\n`;\n if (url.changefreq) yield ` <changefreq>${url.changefreq}</changefreq>\\n`;\n if (url.priority !== undefined) yield ` <priority>${url.priority.toFixed(1)}</priority>\\n`;\n\n // Images\n if (url.images) {\n for (const img of url.images) {\n yield ' <image:image>\\n';\n yield ` <image:loc>${escapeXml(img.loc)}</image:loc>\\n`;\n if (img.caption) yield ` <image:caption>${escapeXml(img.caption)}</image:caption>\\n`;\n if (img.title) yield ` <image:title>${escapeXml(img.title)}</image:title>\\n`;\n yield ' </image:image>\\n';\n }\n }\n\n // Videos\n if (url.videos) {\n for (const vid of url.videos) {\n yield ' <video:video>\\n';\n yield ` <video:thumbnail_loc>${escapeXml(vid.thumbnailLoc)}</video:thumbnail_loc>\\n`;\n yield ` <video:title>${escapeXml(vid.title)}</video:title>\\n`;\n yield ` <video:description>${escapeXml(vid.description)}</video:description>\\n`;\n if (vid.contentLoc)\n yield ` <video:content_loc>${escapeXml(vid.contentLoc)}</video:content_loc>\\n`;\n if (vid.playerLoc)\n yield ` <video:player_loc>${escapeXml(vid.playerLoc)}</video:player_loc>\\n`;\n yield ' </video:video>\\n';\n }\n }\n\n // News\n if (url.news) {\n yield ' <news:news>\\n';\n yield ' <news:publication>\\n';\n yield ` <news:name>${escapeXml(url.news.publication.name)}</news:name>\\n`;\n yield ` <news:language>${escapeXml(url.news.publication.language)}</news:language>\\n`;\n yield ' </news:publication>\\n';\n yield ` <news:publication_date>${escapeXml(url.news.publicationDate)}</news:publication_date>\\n`;\n yield ` <news:title>${escapeXml(url.news.title)}</news:title>\\n`;\n yield ' </news:news>\\n';\n }\n\n yield ' </url>\\n';\n }\n\n yield '</urlset>\\n';\n}\n","// ============================================================================\n// @power-seo/sitemap — URL Validation\n// ============================================================================\n\nimport type { SitemapURL } from '@power-seo/core';\nimport { isAbsoluteUrl, MAX_URL_LENGTH } from '@power-seo/core';\nimport type { SitemapValidationResult } from './types.js';\n\nconst VALID_CHANGEFREQ = ['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'];\n\n/**\n * Validate a sitemap URL entry against the sitemap protocol spec.\n */\nexport function validateSitemapUrl(url: SitemapURL): SitemapValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // loc is required\n if (!url.loc || url.loc.trim().length === 0) {\n errors.push('URL \"loc\" is required and cannot be empty.');\n } else {\n if (!isAbsoluteUrl(url.loc)) {\n errors.push(`URL \"${url.loc}\" must be an absolute URL (starting with http:// or https://).`);\n }\n\n if (url.loc.length > 2048) {\n errors.push(`URL \"${url.loc}\" exceeds the maximum length of 2048 characters.`);\n }\n\n if (url.loc.length > MAX_URL_LENGTH) {\n warnings.push(\n `URL \"${url.loc}\" is ${url.loc.length} characters. URLs under ${MAX_URL_LENGTH} characters are recommended for SEO.`,\n );\n }\n }\n\n // lastmod validation\n if (url.lastmod) {\n const dateRegex = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2})?([+-]\\d{2}:\\d{2}|Z)?)?$/;\n if (!dateRegex.test(url.lastmod)) {\n errors.push(\n `\"lastmod\" value \"${url.lastmod}\" is not a valid W3C datetime format (YYYY-MM-DD or ISO 8601).`,\n );\n }\n }\n\n // changefreq validation\n if (url.changefreq && !VALID_CHANGEFREQ.includes(url.changefreq)) {\n errors.push(\n `\"changefreq\" value \"${url.changefreq}\" is invalid. Must be one of: ${VALID_CHANGEFREQ.join(', ')}.`,\n );\n }\n\n // priority validation\n if (url.priority !== undefined) {\n if (url.priority < 0 || url.priority > 1) {\n errors.push(`\"priority\" value ${url.priority} is out of range. Must be between 0.0 and 1.0.`);\n }\n }\n\n // Image validation\n if (url.images) {\n for (let i = 0; i < url.images.length; i++) {\n const img = url.images[i]!;\n if (!img.loc || img.loc.trim().length === 0) {\n errors.push(`Image ${i + 1}: \"loc\" is required.`);\n } else if (!isAbsoluteUrl(img.loc)) {\n errors.push(`Image ${i + 1}: \"${img.loc}\" must be an absolute URL.`);\n }\n }\n if (url.images.length > 1000) {\n warnings.push(\n `URL has ${url.images.length} images. Google supports up to 1,000 images per page.`,\n );\n }\n }\n\n // Video validation\n if (url.videos) {\n for (let i = 0; i < url.videos.length; i++) {\n const vid = url.videos[i]!;\n if (!vid.title) errors.push(`Video ${i + 1}: \"title\" is required.`);\n if (!vid.description) errors.push(`Video ${i + 1}: \"description\" is required.`);\n if (!vid.thumbnailLoc) errors.push(`Video ${i + 1}: \"thumbnailLoc\" is required.`);\n if (!vid.contentLoc && !vid.playerLoc) {\n errors.push(`Video ${i + 1}: either \"contentLoc\" or \"playerLoc\" must be provided.`);\n }\n if (vid.rating !== undefined && (vid.rating < 0 || vid.rating > 5)) {\n errors.push(`Video ${i + 1}: \"rating\" must be between 0.0 and 5.0.`);\n }\n }\n }\n\n // News validation\n if (url.news) {\n if (!url.news.publication?.name) errors.push('News: \"publication.name\" is required.');\n if (!url.news.publication?.language) errors.push('News: \"publication.language\" is required.');\n if (!url.news.publicationDate) errors.push('News: \"publicationDate\" is required.');\n if (!url.news.title) errors.push('News: \"title\" is required.');\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/generator.ts","../src/types.ts","../src/sitemap-index.ts","../src/stream.ts","../src/validate.ts","../src/next-adapter.ts"],"sourcesContent":["// ============================================================================\n// @power-seo/sitemap — Public API\n// ============================================================================\n\nexport { generateSitemap } from './generator.js';\nexport { generateSitemapIndex, splitSitemap } from './sitemap-index.js';\nexport { streamSitemap } from './stream.js';\nexport { validateSitemapUrl } from './validate.js';\nexport { toNextSitemap } from './next-adapter.js';\nexport type { NextSitemapEntry } from './next-adapter.js';\n\nexport type {\n SitemapURL,\n SitemapImage,\n SitemapVideo,\n SitemapNews,\n SitemapConfig,\n SitemapIndexEntry,\n SitemapIndexConfig,\n SitemapValidationResult,\n} from './types.js';\n\nexport { MAX_URLS_PER_SITEMAP, MAX_SITEMAP_SIZE_BYTES } from './types.js';\n","// ============================================================================\n// @power-seo/sitemap — XML Sitemap Generator\n// ============================================================================\n\nimport type {\n SitemapConfig,\n SitemapURL,\n SitemapImage,\n SitemapVideo,\n SitemapNews,\n} from '@power-seo/core';\nimport { normalizeUrl } from '@power-seo/core';\n\n/** Escape special XML characters. */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/** Determine which namespace extensions are needed. */\nfunction detectNamespaces(urls: SitemapURL[]): { image: boolean; video: boolean; news: boolean } {\n let image = false;\n let video = false;\n let news = false;\n for (const url of urls) {\n if (url.images && url.images.length > 0) image = true;\n if (url.videos && url.videos.length > 0) video = true;\n if (url.news) news = true;\n if (image && video && news) break;\n }\n return { image, video, news };\n}\n\nfunction buildImageXml(images: SitemapImage[]): string {\n return images\n .map((img) => {\n let xml = ' <image:image>\\n';\n xml += ` <image:loc>${escapeXml(img.loc)}</image:loc>\\n`;\n if (img.caption) xml += ` <image:caption>${escapeXml(img.caption)}</image:caption>\\n`;\n if (img.geoLocation)\n xml += ` <image:geo_location>${escapeXml(img.geoLocation)}</image:geo_location>\\n`;\n if (img.title) xml += ` <image:title>${escapeXml(img.title)}</image:title>\\n`;\n if (img.license) xml += ` <image:license>${escapeXml(img.license)}</image:license>\\n`;\n xml += ' </image:image>\\n';\n return xml;\n })\n .join('');\n}\n\nfunction buildVideoXml(videos: SitemapVideo[]): string {\n return videos\n .map((vid) => {\n let xml = ' <video:video>\\n';\n xml += ` <video:thumbnail_loc>${escapeXml(vid.thumbnailLoc)}</video:thumbnail_loc>\\n`;\n xml += ` <video:title>${escapeXml(vid.title)}</video:title>\\n`;\n xml += ` <video:description>${escapeXml(vid.description)}</video:description>\\n`;\n if (vid.contentLoc)\n xml += ` <video:content_loc>${escapeXml(vid.contentLoc)}</video:content_loc>\\n`;\n if (vid.playerLoc)\n xml += ` <video:player_loc>${escapeXml(vid.playerLoc)}</video:player_loc>\\n`;\n if (vid.duration !== undefined)\n xml += ` <video:duration>${vid.duration}</video:duration>\\n`;\n if (vid.expirationDate)\n xml += ` <video:expiration_date>${escapeXml(vid.expirationDate)}</video:expiration_date>\\n`;\n if (vid.rating !== undefined) xml += ` <video:rating>${vid.rating}</video:rating>\\n`;\n if (vid.viewCount !== undefined)\n xml += ` <video:view_count>${vid.viewCount}</video:view_count>\\n`;\n if (vid.publicationDate)\n xml += ` <video:publication_date>${escapeXml(vid.publicationDate)}</video:publication_date>\\n`;\n if (vid.familyFriendly !== undefined)\n xml += ` <video:family_friendly>${vid.familyFriendly ? 'yes' : 'no'}</video:family_friendly>\\n`;\n if (vid.live !== undefined)\n xml += ` <video:live>${vid.live ? 'yes' : 'no'}</video:live>\\n`;\n xml += ' </video:video>\\n';\n return xml;\n })\n .join('');\n}\n\nfunction buildNewsXml(news: SitemapNews): string {\n let xml = ' <news:news>\\n';\n xml += ' <news:publication>\\n';\n xml += ` <news:name>${escapeXml(news.publication.name)}</news:name>\\n`;\n xml += ` <news:language>${escapeXml(news.publication.language)}</news:language>\\n`;\n xml += ' </news:publication>\\n';\n xml += ` <news:publication_date>${escapeXml(news.publicationDate)}</news:publication_date>\\n`;\n xml += ` <news:title>${escapeXml(news.title)}</news:title>\\n`;\n xml += ' </news:news>\\n';\n return xml;\n}\n\nfunction buildUrlXml(url: SitemapURL, hostname: string): string {\n const loc = url.loc.startsWith('http')\n ? url.loc\n : normalizeUrl(`${hostname}${url.loc.startsWith('/') ? '' : '/'}${url.loc}`);\n\n let xml = ' <url>\\n';\n xml += ` <loc>${escapeXml(loc)}</loc>\\n`;\n if (url.lastmod) xml += ` <lastmod>${escapeXml(url.lastmod)}</lastmod>\\n`;\n if (url.changefreq) xml += ` <changefreq>${url.changefreq}</changefreq>\\n`;\n if (url.priority !== undefined) xml += ` <priority>${url.priority.toFixed(1)}</priority>\\n`;\n if (url.images && url.images.length > 0) xml += buildImageXml(url.images);\n if (url.videos && url.videos.length > 0) xml += buildVideoXml(url.videos);\n if (url.news) xml += buildNewsXml(url.news);\n xml += ' </url>\\n';\n return xml;\n}\n\n/**\n * Generate an XML sitemap string from a sitemap configuration.\n *\n * @example\n * ```ts\n * const xml = generateSitemap({\n * hostname: 'https://example.com',\n * urls: [\n * { loc: '/', changefreq: 'daily', priority: 1.0 },\n * { loc: '/about', changefreq: 'monthly', priority: 0.8 },\n * ],\n * });\n * ```\n */\nexport function generateSitemap(config: SitemapConfig): string {\n const { hostname, urls } = config;\n const ns = detectNamespaces(urls);\n\n let xml = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n xml += '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"';\n if (ns.image) xml += '\\n xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"';\n if (ns.video) xml += '\\n xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"';\n if (ns.news) xml += '\\n xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\"';\n xml += '>\\n';\n\n for (const url of urls) {\n xml += buildUrlXml(url, hostname);\n }\n\n xml += '</urlset>\\n';\n return xml;\n}\n","// ============================================================================\n// @power-seo/sitemap — Types\n// ============================================================================\n\nexport type {\n SitemapURL,\n SitemapImage,\n SitemapVideo,\n SitemapNews,\n SitemapConfig,\n} from '@power-seo/core';\n\n/** A sitemap entry in a sitemap index. */\nexport interface SitemapIndexEntry {\n loc: string;\n lastmod?: string;\n}\n\n/** Configuration for the sitemap index generator. */\nexport interface SitemapIndexConfig {\n sitemaps: SitemapIndexEntry[];\n}\n\n/** Result of URL validation. */\nexport interface SitemapValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\n/** Maximum URLs allowed per sitemap file. */\nexport const MAX_URLS_PER_SITEMAP = 50_000 as const;\n\n/** Maximum sitemap file size in bytes (50MB). */\nexport const MAX_SITEMAP_SIZE_BYTES = 52_428_800 as const;\n","// ============================================================================\n// @power-seo/sitemap — Sitemap Index Generator\n// ============================================================================\n\nimport type { SitemapConfig } from '@power-seo/core';\nimport type { SitemapIndexConfig, SitemapIndexEntry } from './types.js';\nimport { MAX_URLS_PER_SITEMAP } from './types.js';\nimport { generateSitemap } from './generator.js';\n\n/** Escape special XML characters. */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * Generate a sitemap index XML string.\n *\n * @example\n * ```ts\n * const indexXml = generateSitemapIndex({\n * sitemaps: [\n * { loc: 'https://example.com/sitemap-0.xml', lastmod: '2024-01-01' },\n * { loc: 'https://example.com/sitemap-1.xml', lastmod: '2024-01-01' },\n * ],\n * });\n * ```\n */\nexport function generateSitemapIndex(config: SitemapIndexConfig): string {\n let xml = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n xml += '<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n';\n\n for (const sitemap of config.sitemaps) {\n xml += ' <sitemap>\\n';\n xml += ` <loc>${escapeXml(sitemap.loc)}</loc>\\n`;\n if (sitemap.lastmod) {\n xml += ` <lastmod>${escapeXml(sitemap.lastmod)}</lastmod>\\n`;\n }\n xml += ' </sitemap>\\n';\n }\n\n xml += '</sitemapindex>\\n';\n return xml;\n}\n\n/**\n * Split a large sitemap config into multiple sitemaps + an index.\n *\n * When a site has more than 50,000 URLs, this function splits them into\n * multiple sitemap files and returns both the individual sitemaps and\n * the index that references them.\n *\n * @example\n * ```ts\n * const { index, sitemaps } = splitSitemap({\n * hostname: 'https://example.com',\n * urls: largeUrlArray,\n * });\n * // sitemaps[0].xml, sitemaps[1].xml, etc.\n * // index = sitemap index XML\n * ```\n */\nexport function splitSitemap(\n config: SitemapConfig,\n sitemapUrlPattern = '/sitemap-{index}.xml',\n): { index: string; sitemaps: Array<{ filename: string; xml: string }> } {\n const maxPerSitemap = config.maxUrlsPerSitemap ?? MAX_URLS_PER_SITEMAP;\n const { hostname, urls } = config;\n\n if (urls.length <= maxPerSitemap) {\n const xml = generateSitemap(config);\n const filename = sitemapUrlPattern.replace('{index}', '0');\n const indexEntries: SitemapIndexEntry[] = [{ loc: `${hostname}${filename}` }];\n return {\n index: generateSitemapIndex({ sitemaps: indexEntries }),\n sitemaps: [{ filename, xml }],\n };\n }\n\n const sitemaps: Array<{ filename: string; xml: string }> = [];\n const indexEntries: SitemapIndexEntry[] = [];\n\n for (let i = 0; i < urls.length; i += maxPerSitemap) {\n const chunk = urls.slice(i, i + maxPerSitemap);\n const chunkIndex = Math.floor(i / maxPerSitemap);\n const filename = sitemapUrlPattern.replace('{index}', String(chunkIndex));\n const xml = generateSitemap({ hostname, urls: chunk });\n\n sitemaps.push({ filename, xml });\n indexEntries.push({ loc: `${hostname}${filename}` });\n }\n\n return {\n index: generateSitemapIndex({ sitemaps: indexEntries }),\n sitemaps,\n };\n}\n","// ============================================================================\n// @power-seo/sitemap — Streaming Sitemap Generator\n// ============================================================================\n\nimport type { SitemapURL } from '@power-seo/core';\nimport { normalizeUrl } from '@power-seo/core';\n\n/** Escape special XML characters. */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * A streaming sitemap generator that yields XML chunks.\n *\n * Useful for server responses where you want to stream the sitemap\n * instead of building the entire XML string in memory.\n *\n * @example\n * ```ts\n * const stream = streamSitemap('https://example.com', urls);\n * for (const chunk of stream) {\n * response.write(chunk);\n * }\n * ```\n */\nexport function* streamSitemap(\n hostname: string,\n urls: Iterable<SitemapURL>,\n): Generator<string, void, undefined> {\n yield '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n yield '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\\n';\n yield ' xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"\\n';\n yield ' xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"\\n';\n yield ' xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\">\\n';\n\n for (const url of urls) {\n const loc = url.loc.startsWith('http')\n ? url.loc\n : normalizeUrl(`${hostname}${url.loc.startsWith('/') ? '' : '/'}${url.loc}`);\n\n yield ' <url>\\n';\n yield ` <loc>${escapeXml(loc)}</loc>\\n`;\n\n if (url.lastmod) yield ` <lastmod>${escapeXml(url.lastmod)}</lastmod>\\n`;\n if (url.changefreq) yield ` <changefreq>${url.changefreq}</changefreq>\\n`;\n if (url.priority !== undefined) yield ` <priority>${url.priority.toFixed(1)}</priority>\\n`;\n\n // Images\n if (url.images) {\n for (const img of url.images) {\n yield ' <image:image>\\n';\n yield ` <image:loc>${escapeXml(img.loc)}</image:loc>\\n`;\n if (img.caption) yield ` <image:caption>${escapeXml(img.caption)}</image:caption>\\n`;\n if (img.title) yield ` <image:title>${escapeXml(img.title)}</image:title>\\n`;\n yield ' </image:image>\\n';\n }\n }\n\n // Videos\n if (url.videos) {\n for (const vid of url.videos) {\n yield ' <video:video>\\n';\n yield ` <video:thumbnail_loc>${escapeXml(vid.thumbnailLoc)}</video:thumbnail_loc>\\n`;\n yield ` <video:title>${escapeXml(vid.title)}</video:title>\\n`;\n yield ` <video:description>${escapeXml(vid.description)}</video:description>\\n`;\n if (vid.contentLoc)\n yield ` <video:content_loc>${escapeXml(vid.contentLoc)}</video:content_loc>\\n`;\n if (vid.playerLoc)\n yield ` <video:player_loc>${escapeXml(vid.playerLoc)}</video:player_loc>\\n`;\n yield ' </video:video>\\n';\n }\n }\n\n // News\n if (url.news) {\n yield ' <news:news>\\n';\n yield ' <news:publication>\\n';\n yield ` <news:name>${escapeXml(url.news.publication.name)}</news:name>\\n`;\n yield ` <news:language>${escapeXml(url.news.publication.language)}</news:language>\\n`;\n yield ' </news:publication>\\n';\n yield ` <news:publication_date>${escapeXml(url.news.publicationDate)}</news:publication_date>\\n`;\n yield ` <news:title>${escapeXml(url.news.title)}</news:title>\\n`;\n yield ' </news:news>\\n';\n }\n\n yield ' </url>\\n';\n }\n\n yield '</urlset>\\n';\n}\n","// ============================================================================\n// @power-seo/sitemap — URL Validation\n// ============================================================================\n\nimport type { SitemapURL } from '@power-seo/core';\nimport { isAbsoluteUrl, MAX_URL_LENGTH } from '@power-seo/core';\nimport type { SitemapValidationResult } from './types.js';\n\nconst VALID_CHANGEFREQ = ['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'];\n\n/**\n * Validate a sitemap URL entry against the sitemap protocol spec.\n */\nexport function validateSitemapUrl(url: SitemapURL): SitemapValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // loc is required\n if (!url.loc || url.loc.trim().length === 0) {\n errors.push('URL \"loc\" is required and cannot be empty.');\n } else {\n if (!isAbsoluteUrl(url.loc)) {\n errors.push(`URL \"${url.loc}\" must be an absolute URL (starting with http:// or https://).`);\n }\n\n if (url.loc.length > 2048) {\n errors.push(`URL \"${url.loc}\" exceeds the maximum length of 2048 characters.`);\n }\n\n if (url.loc.length > MAX_URL_LENGTH) {\n warnings.push(\n `URL \"${url.loc}\" is ${url.loc.length} characters. URLs under ${MAX_URL_LENGTH} characters are recommended for SEO.`,\n );\n }\n }\n\n // lastmod validation\n if (url.lastmod) {\n const dateRegex = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2})?([+-]\\d{2}:\\d{2}|Z)?)?$/;\n if (!dateRegex.test(url.lastmod)) {\n errors.push(\n `\"lastmod\" value \"${url.lastmod}\" is not a valid W3C datetime format (YYYY-MM-DD or ISO 8601).`,\n );\n }\n }\n\n // changefreq validation\n if (url.changefreq && !VALID_CHANGEFREQ.includes(url.changefreq)) {\n errors.push(\n `\"changefreq\" value \"${url.changefreq}\" is invalid. Must be one of: ${VALID_CHANGEFREQ.join(', ')}.`,\n );\n }\n\n // priority validation\n if (url.priority !== undefined) {\n if (url.priority < 0 || url.priority > 1) {\n errors.push(`\"priority\" value ${url.priority} is out of range. Must be between 0.0 and 1.0.`);\n }\n }\n\n // Image validation\n if (url.images) {\n for (let i = 0; i < url.images.length; i++) {\n const img = url.images[i]!;\n if (!img.loc || img.loc.trim().length === 0) {\n errors.push(`Image ${i + 1}: \"loc\" is required.`);\n } else if (!isAbsoluteUrl(img.loc)) {\n errors.push(`Image ${i + 1}: \"${img.loc}\" must be an absolute URL.`);\n }\n }\n if (url.images.length > 1000) {\n warnings.push(\n `URL has ${url.images.length} images. Google supports up to 1,000 images per page.`,\n );\n }\n }\n\n // Video validation\n if (url.videos) {\n for (let i = 0; i < url.videos.length; i++) {\n const vid = url.videos[i]!;\n if (!vid.title) errors.push(`Video ${i + 1}: \"title\" is required.`);\n if (!vid.description) errors.push(`Video ${i + 1}: \"description\" is required.`);\n if (!vid.thumbnailLoc) errors.push(`Video ${i + 1}: \"thumbnailLoc\" is required.`);\n if (!vid.contentLoc && !vid.playerLoc) {\n errors.push(`Video ${i + 1}: either \"contentLoc\" or \"playerLoc\" must be provided.`);\n }\n if (vid.rating !== undefined && (vid.rating < 0 || vid.rating > 5)) {\n errors.push(`Video ${i + 1}: \"rating\" must be between 0.0 and 5.0.`);\n }\n }\n }\n\n // News validation\n if (url.news) {\n if (!url.news.publication?.name) errors.push('News: \"publication.name\" is required.');\n if (!url.news.publication?.language) errors.push('News: \"publication.language\" is required.');\n if (!url.news.publicationDate) errors.push('News: \"publicationDate\" is required.');\n if (!url.news.title) errors.push('News: \"title\" is required.');\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n","// ============================================================================\n// @power-seo/sitemap — Next.js App Router Adapter\n// ============================================================================\n\nimport type { SitemapURL } from '@power-seo/core';\nimport { validateSitemapUrl } from './validate.js';\n\n/**\n * A plain object that matches the shape of Next.js `MetadataRoute.Sitemap[number]`.\n * Typed locally so `@power-seo/sitemap` has no dependency on `next`.\n */\nexport interface NextSitemapEntry {\n url: string;\n lastModified?: string | Date;\n changeFrequency?:\n | 'always'\n | 'hourly'\n | 'daily'\n | 'weekly'\n | 'monthly'\n | 'yearly'\n | 'never';\n priority?: number;\n alternates?: {\n languages?: Record<string, string>;\n };\n}\n\n/**\n * Convert an array of `SitemapURL` objects to a Next.js-compatible sitemap array.\n *\n * Use this in `app/sitemap.ts` to bridge `@power-seo/sitemap` with Next.js's\n * built-in `MetadataRoute.Sitemap` convention.\n *\n * @example\n * ```ts\n * // app/sitemap.ts\n * import type { MetadataRoute } from 'next';\n * import { toNextSitemap } from '@power-seo/sitemap';\n *\n * export default async function sitemap(): Promise<MetadataRoute.Sitemap> {\n * const urls = [\n * { loc: 'https://example.com', changefreq: 'daily', priority: 1.0 },\n * { loc: 'https://example.com/about', changefreq: 'monthly', priority: 0.8 },\n * ];\n * return toNextSitemap(urls) as MetadataRoute.Sitemap;\n * }\n * ```\n */\nexport function toNextSitemap(urls: SitemapURL[]): NextSitemapEntry[] {\n const entries: NextSitemapEntry[] = [];\n\n for (const url of urls) {\n const { valid } = validateSitemapUrl(url);\n if (!valid) continue;\n\n const entry: NextSitemapEntry = { url: url.loc };\n\n if (url.lastmod) {\n entry.lastModified = url.lastmod;\n }\n\n if (url.changefreq) {\n entry.changeFrequency = url.changefreq as NextSitemapEntry['changeFrequency'];\n }\n\n if (url.priority !== undefined) {\n entry.priority = url.priority;\n }\n\n entries.push(entry);\n }\n\n return entries;\n}\n"],"mappings":"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","names":["escapeXml","indexEntries","import_core","escapeXml","import_core"]}
package/dist/index.d.cts CHANGED
@@ -33,9 +33,9 @@ interface SitemapValidationResult {
33
33
  warnings: string[];
34
34
  }
35
35
  /** Maximum URLs allowed per sitemap file. */
36
- declare const MAX_URLS_PER_SITEMAP = 50000;
36
+ declare const MAX_URLS_PER_SITEMAP: 50000;
37
37
  /** Maximum sitemap file size in bytes (50MB). */
38
- declare const MAX_SITEMAP_SIZE_BYTES: number;
38
+ declare const MAX_SITEMAP_SIZE_BYTES: 52428800;
39
39
 
40
40
  /**
41
41
  * Generate a sitemap index XML string.
@@ -97,4 +97,40 @@ declare function streamSitemap(hostname: string, urls: Iterable<SitemapURL>): Ge
97
97
  */
98
98
  declare function validateSitemapUrl(url: SitemapURL): SitemapValidationResult;
99
99
 
100
- export { MAX_SITEMAP_SIZE_BYTES, MAX_URLS_PER_SITEMAP, type SitemapIndexConfig, type SitemapIndexEntry, type SitemapValidationResult, generateSitemap, generateSitemapIndex, splitSitemap, streamSitemap, validateSitemapUrl };
100
+ /**
101
+ * A plain object that matches the shape of Next.js `MetadataRoute.Sitemap[number]`.
102
+ * Typed locally so `@power-seo/sitemap` has no dependency on `next`.
103
+ */
104
+ interface NextSitemapEntry {
105
+ url: string;
106
+ lastModified?: string | Date;
107
+ changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
108
+ priority?: number;
109
+ alternates?: {
110
+ languages?: Record<string, string>;
111
+ };
112
+ }
113
+ /**
114
+ * Convert an array of `SitemapURL` objects to a Next.js-compatible sitemap array.
115
+ *
116
+ * Use this in `app/sitemap.ts` to bridge `@power-seo/sitemap` with Next.js's
117
+ * built-in `MetadataRoute.Sitemap` convention.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * // app/sitemap.ts
122
+ * import type { MetadataRoute } from 'next';
123
+ * import { toNextSitemap } from '@power-seo/sitemap';
124
+ *
125
+ * export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
126
+ * const urls = [
127
+ * { loc: 'https://example.com', changefreq: 'daily', priority: 1.0 },
128
+ * { loc: 'https://example.com/about', changefreq: 'monthly', priority: 0.8 },
129
+ * ];
130
+ * return toNextSitemap(urls) as MetadataRoute.Sitemap;
131
+ * }
132
+ * ```
133
+ */
134
+ declare function toNextSitemap(urls: SitemapURL[]): NextSitemapEntry[];
135
+
136
+ export { MAX_SITEMAP_SIZE_BYTES, MAX_URLS_PER_SITEMAP, type NextSitemapEntry, type SitemapIndexConfig, type SitemapIndexEntry, type SitemapValidationResult, generateSitemap, generateSitemapIndex, splitSitemap, streamSitemap, toNextSitemap, validateSitemapUrl };
package/dist/index.d.ts CHANGED
@@ -33,9 +33,9 @@ interface SitemapValidationResult {
33
33
  warnings: string[];
34
34
  }
35
35
  /** Maximum URLs allowed per sitemap file. */
36
- declare const MAX_URLS_PER_SITEMAP = 50000;
36
+ declare const MAX_URLS_PER_SITEMAP: 50000;
37
37
  /** Maximum sitemap file size in bytes (50MB). */
38
- declare const MAX_SITEMAP_SIZE_BYTES: number;
38
+ declare const MAX_SITEMAP_SIZE_BYTES: 52428800;
39
39
 
40
40
  /**
41
41
  * Generate a sitemap index XML string.
@@ -97,4 +97,40 @@ declare function streamSitemap(hostname: string, urls: Iterable<SitemapURL>): Ge
97
97
  */
98
98
  declare function validateSitemapUrl(url: SitemapURL): SitemapValidationResult;
99
99
 
100
- export { MAX_SITEMAP_SIZE_BYTES, MAX_URLS_PER_SITEMAP, type SitemapIndexConfig, type SitemapIndexEntry, type SitemapValidationResult, generateSitemap, generateSitemapIndex, splitSitemap, streamSitemap, validateSitemapUrl };
100
+ /**
101
+ * A plain object that matches the shape of Next.js `MetadataRoute.Sitemap[number]`.
102
+ * Typed locally so `@power-seo/sitemap` has no dependency on `next`.
103
+ */
104
+ interface NextSitemapEntry {
105
+ url: string;
106
+ lastModified?: string | Date;
107
+ changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
108
+ priority?: number;
109
+ alternates?: {
110
+ languages?: Record<string, string>;
111
+ };
112
+ }
113
+ /**
114
+ * Convert an array of `SitemapURL` objects to a Next.js-compatible sitemap array.
115
+ *
116
+ * Use this in `app/sitemap.ts` to bridge `@power-seo/sitemap` with Next.js's
117
+ * built-in `MetadataRoute.Sitemap` convention.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * // app/sitemap.ts
122
+ * import type { MetadataRoute } from 'next';
123
+ * import { toNextSitemap } from '@power-seo/sitemap';
124
+ *
125
+ * export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
126
+ * const urls = [
127
+ * { loc: 'https://example.com', changefreq: 'daily', priority: 1.0 },
128
+ * { loc: 'https://example.com/about', changefreq: 'monthly', priority: 0.8 },
129
+ * ];
130
+ * return toNextSitemap(urls) as MetadataRoute.Sitemap;
131
+ * }
132
+ * ```
133
+ */
134
+ declare function toNextSitemap(urls: SitemapURL[]): NextSitemapEntry[];
135
+
136
+ export { MAX_SITEMAP_SIZE_BYTES, MAX_URLS_PER_SITEMAP, type NextSitemapEntry, type SitemapIndexConfig, type SitemapIndexEntry, type SitemapValidationResult, generateSitemap, generateSitemapIndex, splitSitemap, streamSitemap, toNextSitemap, validateSitemapUrl };
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
- import { normalizeUrl, isAbsoluteUrl, MAX_URL_LENGTH } from '@power-seo/core';
2
-
3
1
  // src/generator.ts
2
+ import { normalizeUrl } from "@power-seo/core";
4
3
  function escapeXml(str) {
5
4
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
6
5
  }
@@ -123,7 +122,7 @@ function generateSitemap(config) {
123
122
 
124
123
  // src/types.ts
125
124
  var MAX_URLS_PER_SITEMAP = 5e4;
126
- var MAX_SITEMAP_SIZE_BYTES = 50 * 1024 * 1024;
125
+ var MAX_SITEMAP_SIZE_BYTES = 52428800;
127
126
 
128
127
  // src/sitemap-index.ts
129
128
  function escapeXml2(str) {
@@ -172,6 +171,9 @@ function splitSitemap(config, sitemapUrlPattern = "/sitemap-{index}.xml") {
172
171
  sitemaps
173
172
  };
174
173
  }
174
+
175
+ // src/stream.ts
176
+ import { normalizeUrl as normalizeUrl2 } from "@power-seo/core";
175
177
  function escapeXml3(str) {
176
178
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
177
179
  }
@@ -182,7 +184,7 @@ function* streamSitemap(hostname, urls) {
182
184
  yield ' xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"\n';
183
185
  yield ' xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">\n';
184
186
  for (const url of urls) {
185
- const loc = url.loc.startsWith("http") ? url.loc : normalizeUrl(`${hostname}${url.loc.startsWith("/") ? "" : "/"}${url.loc}`);
187
+ const loc = url.loc.startsWith("http") ? url.loc : normalizeUrl2(`${hostname}${url.loc.startsWith("/") ? "" : "/"}${url.loc}`);
186
188
  yield " <url>\n";
187
189
  yield ` <loc>${escapeXml3(loc)}</loc>
188
190
  `;
@@ -240,6 +242,9 @@ function* streamSitemap(hostname, urls) {
240
242
  }
241
243
  yield "</urlset>\n";
242
244
  }
245
+
246
+ // src/validate.ts
247
+ import { isAbsoluteUrl, MAX_URL_LENGTH } from "@power-seo/core";
243
248
  var VALID_CHANGEFREQ = ["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"];
244
249
  function validateSitemapUrl(url) {
245
250
  const errors = [];
@@ -319,6 +324,34 @@ function validateSitemapUrl(url) {
319
324
  };
320
325
  }
321
326
 
322
- export { MAX_SITEMAP_SIZE_BYTES, MAX_URLS_PER_SITEMAP, generateSitemap, generateSitemapIndex, splitSitemap, streamSitemap, validateSitemapUrl };
323
- //# sourceMappingURL=index.js.map
327
+ // src/next-adapter.ts
328
+ function toNextSitemap(urls) {
329
+ const entries = [];
330
+ for (const url of urls) {
331
+ const { valid } = validateSitemapUrl(url);
332
+ if (!valid) continue;
333
+ const entry = { url: url.loc };
334
+ if (url.lastmod) {
335
+ entry.lastModified = url.lastmod;
336
+ }
337
+ if (url.changefreq) {
338
+ entry.changeFrequency = url.changefreq;
339
+ }
340
+ if (url.priority !== void 0) {
341
+ entry.priority = url.priority;
342
+ }
343
+ entries.push(entry);
344
+ }
345
+ return entries;
346
+ }
347
+ export {
348
+ MAX_SITEMAP_SIZE_BYTES,
349
+ MAX_URLS_PER_SITEMAP,
350
+ generateSitemap,
351
+ generateSitemapIndex,
352
+ splitSitemap,
353
+ streamSitemap,
354
+ toNextSitemap,
355
+ validateSitemapUrl
356
+ };
324
357
  //# sourceMappingURL=index.js.map