@nuxtjs/sitemap 8.3.0 → 8.3.2

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.
@@ -144,13 +144,22 @@ export function normaliseEntry(_e, defaults, resolvers, cache) {
144
144
  return e;
145
145
  }
146
146
  const IS_VALID_W3C_DATE = [
147
- /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/,
147
+ /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)$/,
148
+ /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)$/,
149
+ /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)$/,
148
150
  /^\d{4}-[01]\d-[0-3]\d$/,
149
151
  /^\d{4}-[01]\d$/,
150
152
  /^\d{4}$/
151
153
  ];
152
154
  export function isValidW3CDate(d) {
153
- return IS_VALID_W3C_DATE.some((r) => r.test(d));
155
+ if (!IS_VALID_W3C_DATE.some((r) => r.test(d)))
156
+ return false;
157
+ const [year, month, day] = d.slice(0, 10).split("-").map(Number);
158
+ if (month !== void 0 && (month < 1 || month > 12))
159
+ return false;
160
+ if (day !== void 0 && (day < 1 || day > new Date(year, month, 0).getDate()))
161
+ return false;
162
+ return true;
154
163
  }
155
164
  export function normaliseDate(d) {
156
165
  if (typeof d === "string") {
@@ -1,8 +1,39 @@
1
- import { parseSitemapXml } from "@nuxtjs/sitemap/utils";
2
1
  import { defu } from "defu";
3
2
  import { getRequestHost } from "h3";
3
+ import { collectSitemap } from "sitemapd/parse";
4
4
  import { parseURL } from "ufo";
5
5
  import { logger } from "../../../utils-pure.js";
6
+ const changeFrequencies = /* @__PURE__ */ new Set([
7
+ "always",
8
+ "hourly",
9
+ "daily",
10
+ "weekly",
11
+ "monthly",
12
+ "yearly",
13
+ "never"
14
+ ]);
15
+ function readerEntryToSitemapInput(entry) {
16
+ const priority = entry.priority === void 0 ? void 0 : Number.parseFloat(entry.priority);
17
+ const changefreq = entry.changefreq && changeFrequencies.has(entry.changefreq) ? entry.changefreq : void 0;
18
+ return {
19
+ loc: entry.loc,
20
+ ...entry.lastmod ? { lastmod: entry.lastmod } : {},
21
+ ...changefreq ? { changefreq } : {},
22
+ ...priority !== void 0 && Number.isFinite(priority) ? { priority } : {},
23
+ ...entry.extensions?.alternatives ? { alternatives: entry.extensions.alternatives.map(({ hreflang, href }) => ({ hreflang, href })) } : {},
24
+ ...entry.extensions?.images ? {
25
+ images: entry.extensions.images.map((image) => ({
26
+ loc: image.loc,
27
+ ...image.caption ? { caption: image.caption } : {},
28
+ ...image.geoLocation ? { geo_location: image.geoLocation } : {},
29
+ ...image.title ? { title: image.title } : {},
30
+ ...image.license ? { license: image.license } : {}
31
+ }))
32
+ } : {},
33
+ ...entry.extensions?.videos ? { videos: entry.extensions.videos } : {},
34
+ ...entry.extensions?.news ? { news: entry.extensions.news } : {}
35
+ };
36
+ }
6
37
  export function normalizeSourceInput(source) {
7
38
  if (typeof source === "string") {
8
39
  return { context: { name: "hook" }, fetch: source };
@@ -48,7 +79,9 @@ export async function fetchDataSource(input, event) {
48
79
  const abortRequestTimeout = setTimeout(() => timeoutController.abort(), timeout);
49
80
  try {
50
81
  let isMaybeErrorResponse = false;
51
- const isXmlRequest = parseURL(url).pathname.endsWith(".xml");
82
+ const pathname = parseURL(url).pathname.toLowerCase();
83
+ const isGzUrl = pathname.endsWith(".gz");
84
+ const isXmlRequest = pathname.endsWith(".xml") || isGzUrl;
52
85
  const mergedHeaders = defu(
53
86
  options?.headers,
54
87
  {
@@ -58,7 +91,10 @@ export async function fetchDataSource(input, event) {
58
91
  );
59
92
  const fetchOptions = {
60
93
  ...options,
61
- responseType: isXmlRequest ? "text" : "json",
94
+ // Fetch XML sources as raw bytes so we can detect and decompress a gzip body
95
+ // (either a `.gz` URL, or a server that serves gzip without Content-Encoding)
96
+ // before it's mangled by a UTF-8 text decode.
97
+ responseType: isXmlRequest ? "arrayBuffer" : "json",
62
98
  signal: timeoutController.signal,
63
99
  headers: mergedHeaders,
64
100
  // Use ofetch's built-in retry for external sources
@@ -84,11 +120,16 @@ export async function fetchDataSource(input, event) {
84
120
  };
85
121
  }
86
122
  let urls = [];
87
- if (typeof res === "object") {
123
+ if (isXmlRequest) {
124
+ const bytes = res instanceof Uint8Array ? res : new Uint8Array(res);
125
+ const result = await collectSitemap(bytes);
126
+ if (result._tag !== "document")
127
+ throw new Error(result.issues.map((issue) => issue.message).join("; ") || "Invalid sitemap document");
128
+ if (result.document._tag !== "urlset")
129
+ throw new Error("Sitemap URL source must be a URL set, not a sitemap index");
130
+ urls = result.document.entries.map(readerEntryToSitemapInput);
131
+ } else if (typeof res === "object") {
88
132
  urls = res.urls || res;
89
- } else if (typeof res === "string" && isXmlRequest) {
90
- const result = await parseSitemapXml(res);
91
- urls = result.urls;
92
133
  }
93
134
  return {
94
135
  ...input,
@@ -1,13 +1,8 @@
1
- import { createConsola } from "consola";
2
1
  import { createDefu } from "defu";
3
- import { createFilter } from "nuxtseo-shared/utils";
2
+ import { createFilter, createModuleLogger } from "nuxtseo-shared/utils";
4
3
  import { parseURL, withoutBase } from "ufo";
5
4
  export { createFilter } from "nuxtseo-shared/utils";
6
- export const logger = createConsola({
7
- defaults: {
8
- tag: "@nuxt/sitemap"
9
- }
10
- });
5
+ export const logger = createModuleLogger("@nuxt/sitemap");
11
6
  const XML_ENTITIES = {
12
7
  "&": "&amp;",
13
8
  "<": "&lt;",
package/dist/utils.d.mts CHANGED
@@ -1,14 +1,11 @@
1
- import { SitemapUrl, SitemapUrlInput } from '../dist/runtime/types.js';
1
+ import { SitemapUrlInput, SitemapUrl } from '../dist/runtime/types.js';
2
2
  export * from '../dist/runtime/types.js';
3
+ import { SitemapInput } from 'sitemapd/parse';
4
+ export { CollectSitemapResult, ParseSitemapOptions, SitemapCompleteness, SitemapDocument, SitemapDocumentKind, SitemapExtensions, SitemapFormat, SitemapInput, SitemapIssue, SitemapIssueCode, SitemapParseEvent, SitemapReference, SitemapUrlRecord, collectSitemap, parseSitemap } from 'sitemapd/parse';
5
+ export { SitemapDocumentLoadResult, SitemapDocumentLoader, SitemapLoadFailureCode, SitemapLoadRequest, SitemapLoadSource, SitemapReadOptions, SitemapReadResult, SitemapReader, SitemapReaderOptions, SitemapTargetAuthorization, SitemapTargetAuthorizer, SitemapWalkDocument, SitemapWalkDocumentVisitor, SitemapWalkFailure, SitemapWalkNonRetainedResult, SitemapWalkOptions, SitemapWalkPartialReason, SitemapWalkResult, SitemapWalkRetainedResult, createSitemapReader } from 'sitemapd';
6
+ export { FetchDocumentLoaderOptions, SitemapFetch, createFetchDocumentLoader } from 'sitemapd/fetch';
3
7
 
4
- declare function parseHtmlExtractSitemapMeta(html: string, options?: {
5
- images?: boolean;
6
- videos?: boolean;
7
- lastmod?: boolean;
8
- alternatives?: boolean;
9
- resolveUrl?: (s: string) => string;
10
- }): Partial<SitemapUrl> | null;
11
-
8
+ /** @deprecated Use `SitemapIssue` with `parseSitemap` or `collectSitemap`. */
12
9
  interface SitemapWarning {
13
10
  type: 'validation';
14
11
  message: string;
@@ -18,16 +15,31 @@ interface SitemapWarning {
18
15
  value?: unknown;
19
16
  };
20
17
  }
18
+ /** @deprecated Use the tagged `CollectSitemapResult` returned by `collectSitemap`. */
21
19
  interface SitemapParseResult {
22
20
  urls: SitemapUrlInput[];
23
21
  warnings: SitemapWarning[];
24
22
  }
23
+ /** @deprecated Use `SitemapReference`. */
24
+ interface SitemapIndexEntry {
25
+ loc: string;
26
+ lastmod?: string;
27
+ }
28
+ /** @deprecated Use the tagged `CollectSitemapResult` returned by `collectSitemap`. */
29
+ interface SitemapIndexParseResult {
30
+ entries: SitemapIndexEntry[];
31
+ warnings: SitemapWarning[];
32
+ }
33
+ /** @deprecated Use `SitemapInput`. */
25
34
  type SitemapXmlChunk = string | Uint8Array;
26
- type SitemapXmlInput = SitemapXmlChunk | Iterable<SitemapXmlChunk> | AsyncIterable<SitemapXmlChunk> | ReadableStream<SitemapXmlChunk>;
35
+ /** @deprecated Use `SitemapInput`. */
36
+ type SitemapXmlInput = SitemapInput;
37
+ /** @deprecated Use `ParseSitemapOptions`. */
27
38
  interface SitemapStreamOptions {
28
39
  maxEntryBytes?: number;
29
40
  maxBufferBytes?: number;
30
41
  }
42
+ /** @deprecated Use `SitemapParseEvent`. */
31
43
  type SitemapXmlStreamEvent = {
32
44
  _tag: 'url';
33
45
  url: SitemapUrlInput;
@@ -35,6 +47,7 @@ type SitemapXmlStreamEvent = {
35
47
  _tag: 'warning';
36
48
  warning: SitemapWarning;
37
49
  };
50
+ /** @deprecated Use `SitemapParseEvent`. */
38
51
  type SitemapIndexStreamEvent = {
39
52
  _tag: 'sitemap';
40
53
  sitemap: SitemapIndexEntry;
@@ -42,26 +55,52 @@ type SitemapIndexStreamEvent = {
42
55
  _tag: 'warning';
43
56
  warning: SitemapWarning;
44
57
  };
58
+ /** @deprecated Use `SitemapDocumentKind`. */
45
59
  type SitemapKind = 'urlset' | 'index';
60
+ /** @deprecated Use `SitemapParseEvent`. */
46
61
  type SitemapStreamEvent = {
47
62
  _tag: 'kind';
48
63
  kind: SitemapKind;
49
64
  } | SitemapXmlStreamEvent | SitemapIndexStreamEvent;
65
+ /**
66
+ * @deprecated Use `parseSitemap` from `@nuxtjs/sitemap/utils`. Canonical
67
+ * streams emit `document`, `url`, `sitemap`, `issue`, and terminal `end`
68
+ * events. URL and sitemap payloads use `entry`.
69
+ */
50
70
  declare function parseSitemapStream(input: SitemapXmlInput, options?: SitemapStreamOptions): AsyncGenerator<SitemapStreamEvent>;
71
+ /**
72
+ * @deprecated Use `parseSitemap` from `@nuxtjs/sitemap/utils` and handle
73
+ * events whose document kind is `urlset`.
74
+ */
51
75
  declare function parseSitemapXmlStream(input: SitemapXmlInput, options?: SitemapStreamOptions): AsyncGenerator<SitemapXmlStreamEvent>;
76
+ /**
77
+ * @deprecated Use `parseSitemap` from `@nuxtjs/sitemap/utils` and handle
78
+ * events whose document kind is `index`.
79
+ */
52
80
  declare function parseSitemapIndexStream(input: SitemapXmlInput, options?: SitemapStreamOptions): AsyncGenerator<SitemapIndexStreamEvent>;
81
+ /**
82
+ * @deprecated Use `collectSitemap` from `@nuxtjs/sitemap/utils` and handle
83
+ * its tagged result.
84
+ */
53
85
  declare function parseSitemapXml(xml: string): Promise<SitemapParseResult>;
54
-
55
- interface SitemapIndexEntry {
56
- loc: string;
57
- lastmod?: string;
58
- }
59
- interface SitemapIndexParseResult {
60
- entries: SitemapIndexEntry[];
61
- warnings: SitemapWarning[];
62
- }
86
+ /**
87
+ * @deprecated Use `collectSitemap` from `@nuxtjs/sitemap/utils` and handle
88
+ * an `index` document result.
89
+ */
63
90
  declare function parseSitemapIndex(xml: string): Promise<SitemapIndexParseResult>;
91
+ /**
92
+ * @deprecated Use `collectSitemap` from `@nuxtjs/sitemap/utils` and inspect
93
+ * the tagged document result.
94
+ */
64
95
  declare function isSitemapIndex(xml: string): boolean;
65
96
 
97
+ declare function parseHtmlExtractSitemapMeta(html: string, options?: {
98
+ images?: boolean;
99
+ videos?: boolean;
100
+ lastmod?: boolean;
101
+ alternatives?: boolean;
102
+ resolveUrl?: (s: string) => string;
103
+ }): Partial<SitemapUrl> | null;
104
+
66
105
  export { isSitemapIndex, parseHtmlExtractSitemapMeta, parseSitemapIndex, parseSitemapIndexStream, parseSitemapStream, parseSitemapXml, parseSitemapXmlStream };
67
106
  export type { SitemapIndexEntry, SitemapIndexParseResult, SitemapIndexStreamEvent, SitemapKind, SitemapParseResult, SitemapStreamEvent, SitemapStreamOptions, SitemapWarning, SitemapXmlChunk, SitemapXmlInput, SitemapXmlStreamEvent };
package/dist/utils.d.ts CHANGED
@@ -1,14 +1,11 @@
1
- import { SitemapUrl, SitemapUrlInput } from '../dist/runtime/types.js';
1
+ import { SitemapUrlInput, SitemapUrl } from '../dist/runtime/types.js';
2
2
  export * from '../dist/runtime/types.js';
3
+ import { SitemapInput } from 'sitemapd/parse';
4
+ export { CollectSitemapResult, ParseSitemapOptions, SitemapCompleteness, SitemapDocument, SitemapDocumentKind, SitemapExtensions, SitemapFormat, SitemapInput, SitemapIssue, SitemapIssueCode, SitemapParseEvent, SitemapReference, SitemapUrlRecord, collectSitemap, parseSitemap } from 'sitemapd/parse';
5
+ export { SitemapDocumentLoadResult, SitemapDocumentLoader, SitemapLoadFailureCode, SitemapLoadRequest, SitemapLoadSource, SitemapReadOptions, SitemapReadResult, SitemapReader, SitemapReaderOptions, SitemapTargetAuthorization, SitemapTargetAuthorizer, SitemapWalkDocument, SitemapWalkDocumentVisitor, SitemapWalkFailure, SitemapWalkNonRetainedResult, SitemapWalkOptions, SitemapWalkPartialReason, SitemapWalkResult, SitemapWalkRetainedResult, createSitemapReader } from 'sitemapd';
6
+ export { FetchDocumentLoaderOptions, SitemapFetch, createFetchDocumentLoader } from 'sitemapd/fetch';
3
7
 
4
- declare function parseHtmlExtractSitemapMeta(html: string, options?: {
5
- images?: boolean;
6
- videos?: boolean;
7
- lastmod?: boolean;
8
- alternatives?: boolean;
9
- resolveUrl?: (s: string) => string;
10
- }): Partial<SitemapUrl> | null;
11
-
8
+ /** @deprecated Use `SitemapIssue` with `parseSitemap` or `collectSitemap`. */
12
9
  interface SitemapWarning {
13
10
  type: 'validation';
14
11
  message: string;
@@ -18,16 +15,31 @@ interface SitemapWarning {
18
15
  value?: unknown;
19
16
  };
20
17
  }
18
+ /** @deprecated Use the tagged `CollectSitemapResult` returned by `collectSitemap`. */
21
19
  interface SitemapParseResult {
22
20
  urls: SitemapUrlInput[];
23
21
  warnings: SitemapWarning[];
24
22
  }
23
+ /** @deprecated Use `SitemapReference`. */
24
+ interface SitemapIndexEntry {
25
+ loc: string;
26
+ lastmod?: string;
27
+ }
28
+ /** @deprecated Use the tagged `CollectSitemapResult` returned by `collectSitemap`. */
29
+ interface SitemapIndexParseResult {
30
+ entries: SitemapIndexEntry[];
31
+ warnings: SitemapWarning[];
32
+ }
33
+ /** @deprecated Use `SitemapInput`. */
25
34
  type SitemapXmlChunk = string | Uint8Array;
26
- type SitemapXmlInput = SitemapXmlChunk | Iterable<SitemapXmlChunk> | AsyncIterable<SitemapXmlChunk> | ReadableStream<SitemapXmlChunk>;
35
+ /** @deprecated Use `SitemapInput`. */
36
+ type SitemapXmlInput = SitemapInput;
37
+ /** @deprecated Use `ParseSitemapOptions`. */
27
38
  interface SitemapStreamOptions {
28
39
  maxEntryBytes?: number;
29
40
  maxBufferBytes?: number;
30
41
  }
42
+ /** @deprecated Use `SitemapParseEvent`. */
31
43
  type SitemapXmlStreamEvent = {
32
44
  _tag: 'url';
33
45
  url: SitemapUrlInput;
@@ -35,6 +47,7 @@ type SitemapXmlStreamEvent = {
35
47
  _tag: 'warning';
36
48
  warning: SitemapWarning;
37
49
  };
50
+ /** @deprecated Use `SitemapParseEvent`. */
38
51
  type SitemapIndexStreamEvent = {
39
52
  _tag: 'sitemap';
40
53
  sitemap: SitemapIndexEntry;
@@ -42,26 +55,52 @@ type SitemapIndexStreamEvent = {
42
55
  _tag: 'warning';
43
56
  warning: SitemapWarning;
44
57
  };
58
+ /** @deprecated Use `SitemapDocumentKind`. */
45
59
  type SitemapKind = 'urlset' | 'index';
60
+ /** @deprecated Use `SitemapParseEvent`. */
46
61
  type SitemapStreamEvent = {
47
62
  _tag: 'kind';
48
63
  kind: SitemapKind;
49
64
  } | SitemapXmlStreamEvent | SitemapIndexStreamEvent;
65
+ /**
66
+ * @deprecated Use `parseSitemap` from `@nuxtjs/sitemap/utils`. Canonical
67
+ * streams emit `document`, `url`, `sitemap`, `issue`, and terminal `end`
68
+ * events. URL and sitemap payloads use `entry`.
69
+ */
50
70
  declare function parseSitemapStream(input: SitemapXmlInput, options?: SitemapStreamOptions): AsyncGenerator<SitemapStreamEvent>;
71
+ /**
72
+ * @deprecated Use `parseSitemap` from `@nuxtjs/sitemap/utils` and handle
73
+ * events whose document kind is `urlset`.
74
+ */
51
75
  declare function parseSitemapXmlStream(input: SitemapXmlInput, options?: SitemapStreamOptions): AsyncGenerator<SitemapXmlStreamEvent>;
76
+ /**
77
+ * @deprecated Use `parseSitemap` from `@nuxtjs/sitemap/utils` and handle
78
+ * events whose document kind is `index`.
79
+ */
52
80
  declare function parseSitemapIndexStream(input: SitemapXmlInput, options?: SitemapStreamOptions): AsyncGenerator<SitemapIndexStreamEvent>;
81
+ /**
82
+ * @deprecated Use `collectSitemap` from `@nuxtjs/sitemap/utils` and handle
83
+ * its tagged result.
84
+ */
53
85
  declare function parseSitemapXml(xml: string): Promise<SitemapParseResult>;
54
-
55
- interface SitemapIndexEntry {
56
- loc: string;
57
- lastmod?: string;
58
- }
59
- interface SitemapIndexParseResult {
60
- entries: SitemapIndexEntry[];
61
- warnings: SitemapWarning[];
62
- }
86
+ /**
87
+ * @deprecated Use `collectSitemap` from `@nuxtjs/sitemap/utils` and handle
88
+ * an `index` document result.
89
+ */
63
90
  declare function parseSitemapIndex(xml: string): Promise<SitemapIndexParseResult>;
91
+ /**
92
+ * @deprecated Use `collectSitemap` from `@nuxtjs/sitemap/utils` and inspect
93
+ * the tagged document result.
94
+ */
64
95
  declare function isSitemapIndex(xml: string): boolean;
65
96
 
97
+ declare function parseHtmlExtractSitemapMeta(html: string, options?: {
98
+ images?: boolean;
99
+ videos?: boolean;
100
+ lastmod?: boolean;
101
+ alternatives?: boolean;
102
+ resolveUrl?: (s: string) => string;
103
+ }): Partial<SitemapUrl> | null;
104
+
66
105
  export { isSitemapIndex, parseHtmlExtractSitemapMeta, parseSitemapIndex, parseSitemapIndexStream, parseSitemapStream, parseSitemapXml, parseSitemapXmlStream };
67
106
  export type { SitemapIndexEntry, SitemapIndexParseResult, SitemapIndexStreamEvent, SitemapKind, SitemapParseResult, SitemapStreamEvent, SitemapStreamOptions, SitemapWarning, SitemapXmlChunk, SitemapXmlInput, SitemapXmlStreamEvent };