@nuxtjs/sitemap 8.2.3 → 8.3.1

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.
Files changed (46) hide show
  1. package/dist/content.mjs +11 -8
  2. package/dist/devtools/lib/sitemap/state.ts +4 -1
  3. package/dist/devtools/pages/sitemap/index.vue +2 -2
  4. package/dist/module.json +2 -2
  5. package/dist/module.mjs +29 -45
  6. package/dist/runtime/server/plugins/compression.js +57 -13
  7. package/dist/runtime/server/plugins/stream-transport.d.ts +2 -0
  8. package/dist/runtime/server/plugins/stream-transport.js +16 -0
  9. package/dist/runtime/server/routes/__sitemap__/debug-production.d.ts +3 -3
  10. package/dist/runtime/server/routes/__sitemap__/debug-production.js +43 -27
  11. package/dist/runtime/server/routes/__sitemap__/debug.d.ts +1 -0
  12. package/dist/runtime/server/routes/__zero-runtime/sitemap/[sitemap].xml.d.ts +1 -1
  13. package/dist/runtime/server/routes/__zero-runtime/sitemap.xml.d.ts +1 -1
  14. package/dist/runtime/server/routes/__zero-runtime/sitemap_index.xml.d.ts +1 -1
  15. package/dist/runtime/server/routes/sitemap/[sitemap].xml.d.ts +1 -1
  16. package/dist/runtime/server/routes/sitemap.xml.d.ts +1 -1
  17. package/dist/runtime/server/routes/sitemap_index.xml.d.ts +1 -1
  18. package/dist/runtime/server/sitemap/builder/index-xml.d.ts +13 -0
  19. package/dist/runtime/server/sitemap/builder/index-xml.js +67 -0
  20. package/dist/runtime/server/sitemap/builder/sitemap-index.d.ts +1 -4
  21. package/dist/runtime/server/sitemap/builder/sitemap-index.js +15 -60
  22. package/dist/runtime/server/sitemap/builder/sitemap.d.ts +1 -1
  23. package/dist/runtime/server/sitemap/builder/sitemap.js +36 -25
  24. package/dist/runtime/server/sitemap/builder/xml.d.ts +9 -1
  25. package/dist/runtime/server/sitemap/builder/xml.js +37 -11
  26. package/dist/runtime/server/sitemap/event-handlers.d.ts +3 -3
  27. package/dist/runtime/server/sitemap/event-handlers.js +18 -23
  28. package/dist/runtime/server/sitemap/nitro.d.ts +4 -1
  29. package/dist/runtime/server/sitemap/nitro.js +116 -26
  30. package/dist/runtime/server/sitemap/stream.d.ts +30 -0
  31. package/dist/runtime/server/sitemap/stream.js +144 -0
  32. package/dist/runtime/server/sitemap/urlset/normalise.d.ts +6 -1
  33. package/dist/runtime/server/sitemap/urlset/normalise.js +26 -6
  34. package/dist/runtime/server/sitemap/urlset/sort.js +12 -3
  35. package/dist/runtime/server/sitemap/urlset/sources.js +50 -9
  36. package/dist/runtime/server/utils.d.ts +0 -1
  37. package/dist/runtime/server/utils.js +12 -12
  38. package/dist/runtime/types.d.ts +14 -3
  39. package/dist/runtime/utils-pure.d.ts +5 -4
  40. package/dist/runtime/utils-pure.js +43 -26
  41. package/dist/utils.d.mts +5 -29
  42. package/dist/utils.d.ts +5 -29
  43. package/dist/utils.mjs +3 -418
  44. package/package.json +28 -30
  45. package/dist/runtime/server/kit.d.ts +0 -2
  46. package/dist/runtime/server/kit.js +0 -23
@@ -1,10 +1,9 @@
1
1
  import { getHeader } from "h3";
2
2
  import { defineCachedFunction } from "nitropack/runtime";
3
- import { joinURL, withQuery } from "ufo";
3
+ import { joinURL } from "ufo";
4
4
  import staticConfig from "#sitemap-virtual/static-config.mjs";
5
5
  import { normaliseDate } from "../urlset/normalise.js";
6
6
  import { getResolvedSitemapUrls } from "./sitemap.js";
7
- import { escapeValueForXml } from "./xml.js";
8
7
  const SERVER_CACHE_MAX_AGE = staticConfig.cacheMaxAgeSeconds || 60 * 10;
9
8
  const buildSitemapIndexCached = defineCachedFunction(
10
9
  async (event, resolvers, runtimeConfig, nitro) => {
@@ -49,22 +48,7 @@ async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
49
48
  }
50
49
  const indexLastmod = autoLastmod ? normaliseDate(/* @__PURE__ */ new Date()) : void 0;
51
50
  const entries = [];
52
- if (typeof sitemaps.chunks !== "undefined") {
53
- const sitemap = sitemaps.chunks;
54
- const resolved = await getResolvedSitemapUrls(sitemap, "sitemap", true, resolvers, runtimeConfig, nitro);
55
- allFailedSources.push(...resolved.failedSources);
56
- const chunkCount = Math.ceil(resolved.urls.length / defaultSitemapsChunkSize);
57
- for (let i = 0; i < chunkCount; i++) {
58
- const entry = {
59
- _sitemapName: String(i),
60
- sitemap: resolvers.canonicalUrlResolver(joinURL(sitemapsPathPrefix || "", `/${i}.xml`))
61
- };
62
- if (indexLastmod)
63
- entry.lastmod = indexLastmod;
64
- entries.push(entry);
65
- }
66
- }
67
- for (const name of nonChunkedNames) {
51
+ const pushEntry = (name) => {
68
52
  const entry = {
69
53
  _sitemapName: name,
70
54
  sitemap: resolvers.canonicalUrlResolver(joinURL(sitemapsPathPrefix || "", `/${name}.xml`))
@@ -72,7 +56,17 @@ async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
72
56
  if (indexLastmod)
73
57
  entry.lastmod = indexLastmod;
74
58
  entries.push(entry);
59
+ };
60
+ if (typeof sitemaps.chunks !== "undefined") {
61
+ const sitemap = sitemaps.chunks;
62
+ const resolved = await getResolvedSitemapUrls(sitemap, "sitemap", true, resolvers, runtimeConfig, nitro);
63
+ allFailedSources.push(...resolved.failedSources);
64
+ const chunkCount = Math.ceil(resolved.urls.length / defaultSitemapsChunkSize);
65
+ for (let i = 0; i < chunkCount; i++)
66
+ pushEntry(String(i));
75
67
  }
68
+ for (const name of nonChunkedNames)
69
+ pushEntry(name);
76
70
  for (const sitemapName in sitemaps) {
77
71
  const sitemapConfig = sitemaps[sitemapName];
78
72
  if (sitemapName !== "index" && sitemapConfig._isChunking) {
@@ -86,16 +80,8 @@ async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
86
80
  chunkCount = Math.ceil(resolved.urls.length / chunkSize);
87
81
  }
88
82
  sitemapConfig._chunkCount = chunkCount;
89
- for (let i = 0; i < chunkCount; i++) {
90
- const chunkName = `${sitemapName}-${i}`;
91
- const entry = {
92
- _sitemapName: chunkName,
93
- sitemap: resolvers.canonicalUrlResolver(joinURL(sitemapsPathPrefix || "", `/${chunkName}.xml`))
94
- };
95
- if (indexLastmod)
96
- entry.lastmod = indexLastmod;
97
- entries.push(entry);
98
- }
83
+ for (let i = 0; i < chunkCount; i++)
84
+ pushEntry(`${sitemapName}-${i}`);
99
85
  }
100
86
  }
101
87
  if (sitemaps.index) {
@@ -105,41 +91,10 @@ async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
105
91
  }
106
92
  return { entries, failedSources: allFailedSources };
107
93
  }
108
- export function urlsToIndexXml(sitemaps, resolvers, { version, xsl, credits, minify }, errorInfo) {
109
- const sitemapXml = sitemaps.map((e) => [
110
- " <sitemap>",
111
- ` <loc>${escapeValueForXml(e.sitemap)}</loc>`,
112
- // lastmod is optional
113
- e.lastmod ? ` <lastmod>${escapeValueForXml(e.lastmod)}</lastmod>` : false,
114
- " </sitemap>"
115
- ].filter(Boolean).join("\n")).join("\n");
116
- const xmlParts = [
117
- '<?xml version="1.0" encoding="UTF-8"?>'
118
- ];
119
- if (xsl) {
120
- let relativeBaseUrl = resolvers.relativeBaseUrlResolver?.(xsl) ?? xsl;
121
- if (errorInfo && errorInfo.messages.length > 0) {
122
- relativeBaseUrl = withQuery(relativeBaseUrl, {
123
- errors: "true",
124
- error_messages: errorInfo.messages,
125
- error_urls: errorInfo.urls
126
- });
127
- }
128
- xmlParts.push(`<?xml-stylesheet type="text/xsl" href="${escapeValueForXml(relativeBaseUrl)}"?>`);
129
- }
130
- xmlParts.push(
131
- '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
132
- sitemapXml,
133
- "</sitemapindex>"
134
- );
135
- if (credits) {
136
- xmlParts.push(`<!-- XML Sitemap Index generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`);
137
- }
138
- return minify ? xmlParts.join("").replace(/(?<!<[^>]*)\s(?![^<]*>)/g, "") : xmlParts.join("\n");
139
- }
140
94
  export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
141
95
  if (!import.meta.dev && !import.meta.prerender && typeof runtimeConfig.cacheMaxAgeSeconds === "number" && runtimeConfig.cacheMaxAgeSeconds > 0 && resolvers.event) {
142
96
  return buildSitemapIndexCached(resolvers.event, resolvers, runtimeConfig, nitro);
143
97
  }
144
98
  return buildSitemapIndexInternal(resolvers, runtimeConfig, nitro);
145
99
  }
100
+ export { urlsToIndexXml, urlsToIndexXmlStream } from "./index-xml.js";
@@ -18,4 +18,4 @@ export declare function buildResolvedSitemapUrls(effectiveSitemap: SitemapDefini
18
18
  export declare const buildResolvedSitemapUrlsCached: (_event: H3Event<import("h3").EventHandlerRequest>, effectiveSitemap: SitemapDefinition, matchName: string, isChunked: boolean, resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig, nitro?: NitroApp | undefined) => Promise<ResolvedSitemapUrlsResult>;
19
19
  export declare function getResolvedSitemapUrls(effectiveSitemap: SitemapDefinition, matchName: string, isChunked: boolean, resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig, nitro?: NitroApp): Promise<ResolvedSitemapUrlsResult>;
20
20
  export declare function buildSitemapUrls(sitemap: SitemapDefinition, resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig, nitro?: NitroApp): Promise<ResolvedSitemapUrlsResult>;
21
- export { urlsToXml } from './xml.js';
21
+ export { urlsToXml, urlsToXmlStream } from './xml.js';
@@ -14,30 +14,33 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers, b
14
14
  autoI18n,
15
15
  isI18nMapped
16
16
  } = runtimeConfig;
17
- const filterPath = createPathFilter({
17
+ const hasFilters = !!sitemap.include?.length || !!sitemap.exclude?.length;
18
+ const filterPath = hasFilters ? createPathFilter({
18
19
  include: sitemap.include,
19
20
  exclude: sitemap.exclude
20
- }, baseURL || "/");
21
- const _urls = urls.map((_e) => {
21
+ }, baseURL || "/") : void 0;
22
+ const _urls = [];
23
+ for (const _e of urls) {
22
24
  const e = preNormalizeEntry(_e, resolvers);
23
- if (!e.loc || !filterPath(e.loc))
24
- return false;
25
- return e;
26
- }).filter(Boolean);
27
- let validI18nUrlsForTransform = [];
25
+ if (e.loc && (!filterPath || filterPath(e.loc, e._path?.pathname)))
26
+ _urls.push(e);
27
+ }
28
28
  const withoutPrefixPaths = {};
29
29
  if (autoI18n && autoI18n.strategy !== "no_prefix") {
30
- const localeCodes = autoI18n.locales.map((l) => l.code);
30
+ const localeCodes = new Set(autoI18n.locales.map((l) => l.code));
31
31
  const localeByCode = new Map(autoI18n.locales.map((l) => [l.code, l]));
32
32
  const isPrefixStrategy = autoI18n.strategy === "prefix";
33
33
  const isPrefixExceptOrAndDefault = autoI18n.strategy === "prefix_and_default" || autoI18n.strategy === "prefix_except_default";
34
34
  const xDefaultAndLocales = [{ code: "x-default", _hreflang: "x-default" }, ...autoI18n.locales];
35
35
  const defaultLocale = autoI18n.defaultLocale;
36
36
  const hasPages = !!autoI18n.pages;
37
+ const sortedPageKeys = hasPages ? Object.keys(autoI18n.pages).sort((a, b) => b.length - a.length) : void 0;
37
38
  const hasDifferentDomains = !!autoI18n.differentDomains;
38
- validI18nUrlsForTransform = _urls.map((_e, i) => {
39
+ const validI18nUrlsForTransform = [];
40
+ for (let i = 0; i < _urls.length; i++) {
41
+ const _e = _urls[i];
39
42
  if (_e._abs)
40
- return false;
43
+ continue;
41
44
  const split = splitForLocales(_e._relativeLoc, localeCodes);
42
45
  let localeCode = split[0];
43
46
  const pathWithoutPrefix = split[1];
@@ -47,31 +50,30 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers, b
47
50
  e._pathWithoutPrefix = pathWithoutPrefix;
48
51
  const locale = localeByCode.get(localeCode);
49
52
  if (!locale)
50
- return false;
53
+ continue;
51
54
  e._locale = locale;
52
55
  e._index = i;
53
56
  e._key = `${e._sitemap || ""}${e._path?.pathname || "/"}${e._path?.search || ""}`;
54
57
  withoutPrefixPaths[pathWithoutPrefix] = withoutPrefixPaths[pathWithoutPrefix] || [];
55
58
  if (!withoutPrefixPaths[pathWithoutPrefix].some((e2) => e2._locale.code === locale.code))
56
59
  withoutPrefixPaths[pathWithoutPrefix].push(e);
57
- return e;
58
- }).filter(Boolean);
60
+ validI18nUrlsForTransform.push(e);
61
+ }
59
62
  for (const e of validI18nUrlsForTransform) {
60
63
  if (!e._i18nTransform && !e.alternatives?.length) {
61
- const alternatives = (withoutPrefixPaths[e._pathWithoutPrefix] || []).map((u) => {
62
- const entries = [];
64
+ const alternatives = [];
65
+ for (const u of withoutPrefixPaths[e._pathWithoutPrefix] || []) {
63
66
  if (u._locale.code === defaultLocale) {
64
- entries.push({
67
+ alternatives.push({
65
68
  href: u.loc,
66
69
  hreflang: "x-default"
67
70
  });
68
71
  }
69
- entries.push({
72
+ alternatives.push({
70
73
  href: u.loc,
71
74
  hreflang: u._locale._hreflang || defaultLocale
72
75
  });
73
- return entries;
74
- }).flat().filter(Boolean);
76
+ }
75
77
  if (alternatives.length)
76
78
  e.alternatives = alternatives;
77
79
  } else if (e._i18nTransform) {
@@ -91,7 +93,7 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers, b
91
93
  };
92
94
  });
93
95
  } else {
94
- const pageMatch = hasPages ? findPageMapping(e._pathWithoutPrefix, autoI18n.pages) : null;
96
+ const pageMatch = hasPages ? findPageMapping(e._pathWithoutPrefix, autoI18n.pages, sortedPageKeys) : null;
95
97
  const pathSearch = e._path?.search || "";
96
98
  const pathWithoutPrefix = e._pathWithoutPrefix;
97
99
  for (const l of autoI18n.locales) {
@@ -130,7 +132,7 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers, b
130
132
  } else if (isPrefixExceptOrAndDefault && !isDefault) {
131
133
  href = joinURL("/", code, pathWithoutPrefix);
132
134
  }
133
- if (!filterPath(href))
135
+ if (filterPath && !filterPath(href))
134
136
  continue;
135
137
  alternatives.push({
136
138
  hreflang: locale._hreflang,
@@ -192,9 +194,17 @@ export async function buildResolvedSitemapUrls(effectiveSitemap, matchName, isCh
192
194
  const localeSitemapKeys = isI18nMapped && autoI18n ? autoI18n.locales.map((l) => l._sitemap) : [];
193
195
  if (isMultiSitemap) {
194
196
  const sitemapNames = Object.keys(sitemaps).filter((k) => k !== "index");
197
+ const validSitemapNames = new Set(sitemapNames);
198
+ if (isI18nMapped) {
199
+ for (const name of sitemapNames) {
200
+ const localeKey = resolveI18nSitemapLocaleKey(name, localeSitemapKeys);
201
+ if (localeKey)
202
+ validSitemapNames.add(localeKey);
203
+ }
204
+ }
195
205
  const warnedSitemaps = nitro?._sitemapWarnedSitemaps || /* @__PURE__ */ new Set();
196
206
  for (const e of enhancedUrls) {
197
- const hasMatchingSitemap = typeof e._sitemap === "string" && (sitemapNames.includes(e._sitemap) || isI18nMapped && sitemapNames.some((name) => resolveI18nSitemapLocaleKey(name, localeSitemapKeys) === e._sitemap));
207
+ const hasMatchingSitemap = typeof e._sitemap === "string" && validSitemapNames.has(e._sitemap);
198
208
  if (typeof e._sitemap === "string" && !hasMatchingSitemap) {
199
209
  if (!warnedSitemaps.has(e._sitemap)) {
200
210
  warnedSitemaps.add(e._sitemap);
@@ -206,6 +216,7 @@ export async function buildResolvedSitemapUrls(effectiveSitemap, matchName, isCh
206
216
  nitro._sitemapWarnedSitemaps = warnedSitemaps;
207
217
  }
208
218
  }
219
+ const matchedLocaleSitemap = isI18nMapped ? resolveI18nSitemapLocaleKey(matchName, localeSitemapKeys) : null;
209
220
  const filteredUrls = enhancedUrls.filter((e) => {
210
221
  if (e._sitemap === false)
211
222
  return false;
@@ -215,7 +226,7 @@ export async function buildResolvedSitemapUrls(effectiveSitemap, matchName, isCh
215
226
  if (e._sitemap === matchName)
216
227
  return true;
217
228
  if (isI18nMapped)
218
- return e._sitemap === resolveI18nSitemapLocaleKey(matchName, localeSitemapKeys);
229
+ return e._sitemap === matchedLocaleSitemap;
219
230
  return false;
220
231
  }
221
232
  return true;
@@ -273,4 +284,4 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
273
284
  const urls = sliceUrlsForChunk(resolved.urls, sitemap.sitemapName, sitemaps, chunkSize);
274
285
  return { urls, failedSources: resolved.failedSources };
275
286
  }
276
- export { urlsToXml } from "./xml.js";
287
+ export { urlsToXml, urlsToXmlStream } from "./xml.js";
@@ -1,6 +1,14 @@
1
1
  import type { ModuleRuntimeConfig, NitroUrlResolvers, ResolvedSitemapUrl } from '../../../types.js';
2
2
  export declare function escapeValueForXml(value: boolean | string | number): string;
3
- export declare function urlsToXml(urls: ResolvedSitemapUrl[], resolvers: NitroUrlResolvers, { version, xsl, credits, minify }: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>, errorInfo?: {
3
+ export declare function renderSitemapXmlChunks(urls: ResolvedSitemapUrl[], resolvers: NitroUrlResolvers, config: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>, errorInfo?: {
4
+ messages: string[];
5
+ urls: string[];
6
+ }): Generator<string>;
7
+ export declare function urlsToXml(urls: ResolvedSitemapUrl[], resolvers: NitroUrlResolvers, config: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>, errorInfo?: {
4
8
  messages: string[];
5
9
  urls: string[];
6
10
  }): string;
11
+ export declare function urlsToXmlStream(urls: ResolvedSitemapUrl[], resolvers: NitroUrlResolvers, config: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>, errorInfo?: {
12
+ messages: string[];
13
+ urls: string[];
14
+ }): ReadableStream<Uint8Array>;
@@ -1,5 +1,6 @@
1
1
  import { withQuery } from "ufo";
2
- import { xmlEscape } from "../../utils.js";
2
+ import { xmlEscape } from "../../../utils-pure.js";
3
+ import { createChunkedXmlStream } from "../stream.js";
3
4
  export function escapeValueForXml(value) {
4
5
  if (value === true || value === false)
5
6
  return value ? "yes" : "no";
@@ -24,7 +25,10 @@ function buildUrlXml(url, NL, I1, I2, I3, I4) {
24
25
  if (url.alternatives) {
25
26
  for (const alt of url.alternatives) {
26
27
  let attrs = "";
27
- for (const [k, v] of Object.entries(alt)) attrs += ` ${k}="${xmlEscape(String(v))}"`;
28
+ for (const k in alt) {
29
+ if (Object.hasOwn(alt, k))
30
+ attrs += ` ${k}="${xmlEscape(String(alt[k]))}"`;
31
+ }
28
32
  xml += `${I2}<xhtml:link rel="alternate"${attrs} />${NL}`;
29
33
  }
30
34
  }
@@ -112,7 +116,7 @@ function buildUrlXml(url, NL, I1, I2, I3, I4) {
112
116
  xml += `${I1}</url>`;
113
117
  return xml;
114
118
  }
115
- export function urlsToXml(urls, resolvers, { version, xsl, credits, minify }, errorInfo) {
119
+ function resolveXmlRenderContext(resolvers, { xsl, minify }, errorInfo) {
116
120
  let xslHref = xsl ? resolvers.relativeBaseUrlResolver(xsl) : false;
117
121
  if (xslHref && errorInfo?.messages.length) {
118
122
  xslHref = withQuery(xslHref, {
@@ -122,18 +126,40 @@ export function urlsToXml(urls, resolvers, { version, xsl, credits, minify }, er
122
126
  });
123
127
  }
124
128
  const NL = minify ? "" : "\n";
125
- const I1 = minify ? "" : " ";
126
- const I2 = minify ? "" : " ";
127
- const I3 = minify ? "" : " ";
128
- const I4 = minify ? "" : " ";
129
+ return {
130
+ xslHref,
131
+ NL,
132
+ I1: minify ? "" : " ",
133
+ I2: minify ? "" : " ",
134
+ I3: minify ? "" : " ",
135
+ I4: minify ? "" : " "
136
+ };
137
+ }
138
+ export function* renderSitemapXmlChunks(urls, resolvers, config, errorInfo) {
139
+ const { version, credits } = config;
140
+ const { xslHref, NL, I1, I2, I3, I4 } = resolveXmlRenderContext(resolvers, config, errorInfo);
141
+ yield xslHref ? `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="${escapeValueForXml(xslHref)}"?>${NL}` : `<?xml version="1.0" encoding="UTF-8"?>${NL}`;
142
+ yield URLSET_OPENING_TAG + NL;
143
+ for (const url of urls) {
144
+ yield buildUrlXml(url, NL, I1, I2, I3, I4) + NL;
145
+ }
146
+ yield "</urlset>";
147
+ if (credits) {
148
+ yield `${NL}<!-- XML Sitemap generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`;
149
+ }
150
+ }
151
+ export function urlsToXml(urls, resolvers, config, errorInfo) {
152
+ const { version, credits } = config;
153
+ const { xslHref, NL, I1, I2, I3, I4 } = resolveXmlRenderContext(resolvers, config, errorInfo);
129
154
  let xml = xslHref ? `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="${escapeValueForXml(xslHref)}"?>${NL}` : `<?xml version="1.0" encoding="UTF-8"?>${NL}`;
130
155
  xml += URLSET_OPENING_TAG + NL;
131
- for (const url of urls) {
156
+ for (const url of urls)
132
157
  xml += buildUrlXml(url, NL, I1, I2, I3, I4) + NL;
133
- }
134
158
  xml += "</urlset>";
135
- if (credits) {
159
+ if (credits)
136
160
  xml += `${NL}<!-- XML Sitemap generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`;
137
- }
138
161
  return xml;
139
162
  }
163
+ export function urlsToXmlStream(urls, resolvers, config, errorInfo) {
164
+ return createChunkedXmlStream(renderSitemapXmlChunks(urls, resolvers, config, errorInfo));
165
+ }
@@ -1,4 +1,4 @@
1
1
  import type { H3Event } from 'h3';
2
- export declare function sitemapXmlEventHandler(e: H3Event): Promise<string | void>;
3
- export declare function sitemapIndexXmlEventHandler(e: H3Event): Promise<string>;
4
- export declare function sitemapChildXmlEventHandler(e: H3Event): Promise<string | undefined>;
2
+ export declare function sitemapXmlEventHandler(e: H3Event): Promise<string | void | ReadableStream<Uint8Array<ArrayBufferLike>>>;
3
+ export declare function sitemapIndexXmlEventHandler(e: H3Event): Promise<string | ReadableStream<Uint8Array<ArrayBufferLike>>>;
4
+ export declare function sitemapChildXmlEventHandler(e: H3Event): Promise<string | ReadableStream<Uint8Array<ArrayBufferLike>> | undefined>;
@@ -1,9 +1,10 @@
1
- import { appendHeader, createError, getRouterParam, sendRedirect, setHeader } from "h3";
1
+ import { appendHeader, createError, getRequestURL, getRouterParam, sendRedirect } from "h3";
2
2
  import { useNitroApp, useRuntimeConfig } from "nitropack/runtime";
3
3
  import { joinURL, withBase, withLeadingSlash, withoutLeadingSlash, withoutTrailingSlash } from "ufo";
4
4
  import { useSitemapRuntimeConfig } from "../utils.js";
5
- import { buildSitemapIndex, urlsToIndexXml } from "./builder/sitemap-index.js";
6
- import { createSitemap, useNitroUrlResolvers } from "./nitro.js";
5
+ import { urlsToIndexXml, urlsToIndexXmlStream } from "./builder/index-xml.js";
6
+ import { buildSitemapIndex } from "./builder/sitemap-index.js";
7
+ import { createSitemap, renderSitemapOutput, setSitemapResponseHeaders, useNitroUrlResolvers } from "./nitro.js";
7
8
  import { getSitemapConfig, parseChunkInfo } from "./utils/chunk.js";
8
9
  export async function sitemapXmlEventHandler(e) {
9
10
  const runtimeConfig = useSitemapRuntimeConfig();
@@ -27,33 +28,27 @@ export async function sitemapIndexXmlEventHandler(e) {
27
28
  const indexResolvedCtx = { sitemaps, event: e };
28
29
  await nitro.hooks.callHook("sitemap:index-resolved", indexResolvedCtx);
29
30
  const errorInfo = failedSources.length > 0 ? { messages: failedSources.map((f) => f.error), urls: failedSources.map((f) => f.url) } : void 0;
30
- const output = urlsToIndexXml(indexResolvedCtx.sitemaps, resolvers, runtimeConfig, errorInfo);
31
- const ctx = { sitemap: output, sitemapName: "sitemap", event: e };
32
- await nitro.hooks.callHook("sitemap:output", ctx);
33
- setHeader(e, "Content-Type", "text/xml; charset=UTF-8");
34
- if (runtimeConfig.cacheMaxAgeSeconds) {
35
- setHeader(e, "Cache-Control", `public, max-age=${runtimeConfig.cacheMaxAgeSeconds}, s-maxage=${runtimeConfig.cacheMaxAgeSeconds}, stale-while-revalidate=3600`);
36
- const now = /* @__PURE__ */ new Date();
37
- setHeader(e, "X-Sitemap-Generated", now.toISOString());
38
- setHeader(e, "X-Sitemap-Cache-Duration", `${runtimeConfig.cacheMaxAgeSeconds}s`);
39
- const expiryTime = new Date(now.getTime() + runtimeConfig.cacheMaxAgeSeconds * 1e3);
40
- setHeader(e, "X-Sitemap-Cache-Expires", expiryTime.toISOString());
41
- const remainingSeconds = Math.floor((expiryTime.getTime() - now.getTime()) / 1e3);
42
- setHeader(e, "X-Sitemap-Cache-Remaining", `${remainingSeconds}s`);
43
- } else {
44
- setHeader(e, "Cache-Control", `no-cache, no-store`);
45
- }
46
- return ctx.sitemap;
31
+ const output = await renderSitemapOutput(
32
+ nitro,
33
+ e,
34
+ "sitemap",
35
+ () => urlsToIndexXml(indexResolvedCtx.sitemaps, resolvers, runtimeConfig, errorInfo),
36
+ () => urlsToIndexXmlStream(indexResolvedCtx.sitemaps, resolvers, runtimeConfig, errorInfo),
37
+ !!runtimeConfig.experimentalStreaming && !import.meta.prerender,
38
+ runtimeConfig.debug
39
+ );
40
+ setSitemapResponseHeaders(e, runtimeConfig);
41
+ return output;
47
42
  }
48
43
  export async function sitemapChildXmlEventHandler(e) {
49
- if (!e.path.endsWith(".xml"))
44
+ const pathname = getRequestURL(e).pathname;
45
+ if (!pathname.endsWith(".xml"))
50
46
  return;
51
47
  const runtimeConfig = useSitemapRuntimeConfig(e);
52
48
  const { sitemaps } = runtimeConfig;
53
49
  let sitemapName = getRouterParam(e, "sitemap");
54
50
  if (!sitemapName) {
55
- const path = e.path;
56
- const match = path.match(/(?:\/__sitemap__\/)?(.+)\.xml$/);
51
+ const match = pathname.match(/(?:\/__sitemap__\/)?(.+)\.xml$/);
57
52
  if (match)
58
53
  sitemapName = match[1];
59
54
  }
@@ -1,4 +1,7 @@
1
1
  import type { H3Event } from 'h3';
2
+ import type { NitroApp } from 'nitropack/types';
2
3
  import type { ModuleRuntimeConfig, NitroUrlResolvers, SitemapDefinition } from '../../types.js';
3
4
  export declare function useNitroUrlResolvers(e: H3Event): NitroUrlResolvers;
4
- export declare function createSitemap(event: H3Event, definition: SitemapDefinition, runtimeConfig: ModuleRuntimeConfig): Promise<string>;
5
+ export declare function renderSitemapOutput(nitro: NitroApp, event: H3Event, sitemapName: string, renderString: () => string, renderStream: () => ReadableStream<Uint8Array>, shouldStream: boolean, debug: boolean): Promise<string | ReadableStream<Uint8Array>>;
6
+ export declare function setSitemapResponseHeaders(event: H3Event, runtimeConfig: ModuleRuntimeConfig): void;
7
+ export declare function createSitemap(event: H3Event, definition: SitemapDefinition, runtimeConfig: ModuleRuntimeConfig): Promise<string | ReadableStream<Uint8Array<ArrayBufferLike>>>;