fix(deps): update dependency sitemap to v10 #82

Merged
martin merged 1 commit from renovate/sitemap-10.x into master 2026-10-20 17:52:08 +00:00
Member

This PR contains the following updates:

Package Change Age Confidence
sitemap ^9.0.0 → ^10.0.0 age confidence

Release Notes

ekalinin/sitemap.js (sitemap)

v10.0.0

Compare Source

[BREAKING CHANGES]
Dropped CommonJS build — the package is now ESM-only
  • require('sitemap') is no longer supported on Node versions without
    built-in require(esm). The dist/cjs build, the require export condition,
    and tsconfig.cjs.json are all gone; exports now resolves to dist/index.js
    for every consumer. Migrate to import { SitemapStream } from 'sitemap'.
  • Node.js >=22.22.1 now required (previously >=20.19.5). CommonJS
    consumers can still load this package through require(esm), which landed
    unflagged in 22.12; the floor is 22.22.1 to match the development toolchain.
  • Build output flattened from dist/esm/* and dist/cjs/* to dist/*. The
    bin entry is now dist/cli.js.
simpleSitemapAndIndex defaults to 45,000 URLs per sitemap
  • The default limit drops from 50,000 to 45,000, the same default
    SitemapAndIndexStream and the CLI already use (DEFAULT_SITEMAP_ITEM_LIMIT).
    The headroom keeps rich entries (images, video, news) under the 50MB
    uncompressed file-size limit. A 50,000-URL input now produces two sitemap
    files instead of one; pass limit: 50000 to keep the old output.
SitemapStream writes an empty sitemap instead of erroring
  • Ending a SitemapStream without writing any items now produces a
    well-formed empty <urlset> instead of failing with EmptySitemap
    (#​394, #​421). This matches SitemapIndexStream, which already wrote an empty
    <sitemapindex>. EmptySitemap is still exported but deprecated and no
    longer thrown. An empty <urlset> does not pass strict sitemap.xsd
    validation, which requires at least one <url>; search engines accept it.
One logger option across the library; xmlNS renamed to xmlns
  • SitemapStream, SitemapIndexStream, SitemapAndIndexStream and
    simpleSitemapAndIndex accept the same logger option the parsers already
    had (#​348). Validation warnings that went straight to console.warn now go
    through it. Pass false to silence. The Logger type is now exported.
  • Invalid news and video attribute values now go through errorHandler (and
    so the logger) like every other validation error, instead of a hardcoded
    console.warn. The warning text is now the error's name and message, which starts with
    the item's URL. Under ErrorLevel.THROW a custom errorHandler receives
    these errors too, like every other validation error; the default handler
    still throws.
  • The SitemapStream property xmlNS is now xmlns, matching the option
    name (#​300). xmlNS still works as a deprecated alias. SitemapStream.errorHandler is always set now; it defaults to
    a handler that warns through logger.
Both XML parsers share one error store and entry cap

XMLToSitemapItemStream and XMLToSitemapIndexStream now extend one internal
base class, so they report errors and cap entries the same way.

  • XMLToSitemapIndexStream.error is a read-only getter for the first error
    (errors[0], or null). Assigning to it now throws a TypeError in strict
    mode. The index parser also gains the errors array (capped at
    LIMITS.MAX_PARSER_ERRORS) and errorCount, where it previously kept only
    the first error.
  • XMLToSitemapItemStream reports a sitemap with more than 50,000 <url>
    entries once, instead of logging and recording an error for every dropped
    entry, so errorCount and the log no longer grow with the overflow. It
    gains the index parser's maxEntries option, entryCount property and
    'maxEntriesExceeded' event, and an error getter. urlCount still works
    as a deprecated alias for entryCount. parseSitemap still resolves with
    the first 50,000 items, but it now stops reading once the cap is crossed
    and destroys the source stream, as parseSitemapIndex already did.
  • Both parsers now fail on a truncated document (an element left unclosed
    when the input ends), like any other malformed XML. Before, the
    unfinished entry was dropped silently. parseSitemap and
    parseSitemapIndex reject in that case, and parseSitemap now also
    rejects when the source stream fails instead of never settling.
  • The index parser's warnings for an invalid <loc> or <lastmod> are now
    logged as one message, the same text recorded in errors. The recorded
    lastmod error now reads Invalid lastmod date format in sitemap index: ….
SitemapAndIndexStream destroys itself on error
  • When a sitemap stream errors, or getSitemapStream throws or returns an
    invalid tuple, SitemapAndIndexStream now destroys itself and emits the
    error once. It used to emit the error without stopping, so the same failure
    could be emitted twice, and a getSitemapStream failure was followed by a
    generic No sitemap stream available error. Code that listened for error
    and kept writing now gets write-after-destroy errors instead.
sitemap --index --gzip names sitemaps sitemap-N.xml.gz
  • With --gzip, sitemap --index now writes each sitemap to sitemap-N.xml.gz
    and lists that URL in the index, as simpleSitemapAndIndex already did. It
    used to write gzipped data to sitemap-N.xml and index it under that name,
    so crawlers fetched gzip bytes from a .xml URL. Update scripts that upload
    or serve sitemap-*.xml after a gzipped run.
SitemapStream reports item errors as stream errors
  • SitemapStream and SitemapItemStream now report a failure on an item
    through the stream: write() no longer throws, and the stream emits
    error and is destroyed. This covers an invalid item at
    ErrorLevel.THROW, an item normalizeURL rejects (such as an invalid
    lastmod), and an item that can't be serialized (such as a non-string
    video attribute at ErrorLevel.SILENT). Before, the error was thrown out
    of write(), so a piped source crashed the process with an uncaught
    exception. Code that wrapped write() in try/catch must listen for
    error instead, or use pipeline().
  • SitemapStream checks xmlns.custom in its constructor, so an invalid
    custom namespace now throws from new SitemapStream() instead of from the
    first write().
  • SitemapStream serializes each item itself instead of piping it through an
    internal SitemapItemStream, so it now outputs one chunk per item. The XML
    is unchanged.
  • A priority of NaN is now reported as a PriorityInvalidError: it
    throws at ErrorLevel.THROW and warns at WARN. It used to skip
    validation and write <priority>NaN</priority> at every level.
  • An alternate link with no lang or hreflang is now reported as the new
    InvalidLinkHreflang error at WARN and THROW, and dropped from the
    output at WARN and SILENT. SitemapItemStream, which doesn't
    validate, drops it too, with no warning. Every level used to fail with a
    TypeError from the XML writer. Writing the link without hreflang would
    produce the androidLink markup, which parses back as androidLink.
Error classes are exported by name; UndefinedTargetFolder removed
  • index.ts lists the error classes explicitly instead of
    export * from './lib/errors.js', like the public types, so a new error
    class is public only once it is added there.
  • UndefinedTargetFolder is removed. Nothing has thrown it since 7.0.0,
    which removed createSitemapsAndIndex, its only user.
Changed
  • The CLI parses arguments with Node's built-in util.parseArgs instead of
    the arg package, which is no longer a dependency (#​471). Unknown options
    and a non-integer --limit now print a message and exit with code 2 instead
    of throwing an uncaught error.
  • Test suite migrated from Jest to the built-in Node.js test runner. Coverage
    thresholds moved from jest.config.cjs into the test:coverage script and are
    enforced in CI by a dedicated job.
  • CI now runs on Linux, Windows and macOS across Node 22/24/26. Lint, formatting
    and typechecking run once rather than on every matrix leg.
  • Stricter <loc> validation in the sitemap parser: XMLToSitemapItemStream
    now validates <loc> values with the same validateURL used by the sitemap
    index parser, adding a URL-parseability check on top of the existing length
    and protocol checks. A malformed URL that passed the old checks but fails
    new URL() is now dropped with a warning (or throws under
    ErrorLevel.THROW). Warn/error messages for invalid <loc> values changed to
    the Invalid URL in sitemap: … form.
  • validateURL throws InvalidURLError, a new subclass of
    InvalidHostnameError (so instanceof InvalidHostnameError still matches).
    Its message reads Invalid URL "…": … instead of Invalid hostname "…": …,
    and it shows at most the first 100 characters of the offending value.
  • Stricter video validation in validateSMIOptions: a video duration,
    rating or view_count that is NaN, Infinity or otherwise non-numeric
    is now reported as invalid (and throws under ErrorLevel.THROW). Previously
    only out-of-range finite numbers were caught, so NaN slipped through.
  • XMLToSitemapItemStream now buffers each element's character data and
    handles it once at the next tag boundary: text and CDATA chunks within one
    element are joined, surrounding whitespace is trimmed for CDATA as it already
    was for text, whitespace between chunks is kept (Episode <![CDATA[One]]>
    now parses as Episode One, not EpisodeOne), and stray character data
    between elements is reported against
    the enclosing element instead of overwriting the previous one. Character data
    longer than LIMITS.MAX_PARSER_CHAR_DATA_LENGTH (64 KiB) for one element is
    dropped with a warning.
  • Internal: the parser's duplicated text/cdata SAX handlers were collapsed
    into one, and its inline bounds checks (priority, video duration/rating/view
    count, ISO dates) now delegate to shared guards in lib/validation.ts, with
    the bounds defined once in LIMITS.
  • XMLToSitemapIndexStream now handles character data the same way: text and
    CDATA within one <loc> or <lastmod> are joined and trimmed, stray
    character data is reported against the enclosing element, and values longer
    than LIMITS.MAX_PARSER_CHAR_DATA_LENGTH are dropped with a warning.
    Unhandled CDATA is now logged as unhandled text for tag: instead of
    unhandled cdata for tag:. Both parsers share one buffer,
    createCharDataBuffer in lib/utils.ts.
  • XMLToSitemapIndexStream enforces the 50,000-entry spec limit itself.
    Entries past LIMITS.MAX_SITEMAP_ITEM_LIMIT are dropped with a single error
    (which throws under ErrorLevel.THROW), and a new entryCount property counts
    every <sitemap> seen. Previously only the parseSitemapIndex wrapper capped
    entries, so piping the stream directly had no limit. parseSitemapIndex still
    rejects an over-limit index and stops reading as soon as the limit is crossed,
    but a maxEntries above 50,000 no longer raises the limit. A new
    maxEntries stream option lowers the cap, or raises it (Infinity turns it
    off) for callers that knowingly parse oversized indexes. When the cap is
    crossed the stream emits 'maxEntriesExceeded', and logs the overflow only
    if nothing listens for that event, so parseSitemapIndex rejects without
    also logging. maxEntries: 0 is allowed (nothing is emitted, and
    parseSitemapIndex rejects on the first entry); a negative, fractional or
    NaN value is rejected, and parseSitemapIndex destroys the source stream
    before rejecting.
  • Errors that simpleSitemapAndIndex and SitemapAndIndexStream wrap, such
    as Failed to write sitemap files: … or a getSitemapStream failure, now
    carry the original error as cause.
  • SaxParserStreamOptions, the shared base of XMLToSitemapItemStreamOptions
    and XMLToSitemapIndexItemStreamOptions, is exported.
  • LIMITS gains the bounds the validators use: MIN_PRIORITY,
    MAX_PRIORITY, PRIORITY_STRING_REGEX, MIN_VIDEO_DURATION,
    MAX_VIDEO_DURATION, MIN_VIDEO_RATING, MAX_VIDEO_RATING and
    MIN_VIDEO_VIEW_COUNT.
  • LIMITS.MAX_URL_ENTRIES is deprecated. Nothing reads it; the parsers cap
    entries at LIMITS.MAX_SITEMAP_ITEM_LIMIT (the same value), which their
    maxEntries option overrides.
Fixed
  • A string priority no longer crashes SitemapStream with
    item.priority.toFixed is not a function (#​393). A plain decimal string
    such as '0.5' or '.5' is converted to a number (hex, binary and
    exponent forms such as '0x1' or '1e-1' are not), and
    SitemapItemLoose.priority now accepts number | string. Any other value,
    including an empty string, is reported as a PriorityInvalidError at
    WARN and THROW, and written as given at WARN and SILENT, like other
    invalid values. isValidPriority rejects non-numbers instead of coercing
    them.
  • isValidYesNo accepts only a whole yes, Yes, YES, no, No or NO.
    Its unanchored alternation used to accept any value that started with YES,
    contained NO or yes, or ended in no, such as NOPE or maybe-yes, so
    the parsers and validateSMIOptions let those values through.
  • XMLToSitemapItemStream reports an invalid video:requires_subscription,
    video:family_friendly, video:live or player_loc allow_embed value as a
    warning and a parse error. It used to drop the value without a word. It also
    trims whitespace around allow_embed, as it already does for element text.
  • validateSMIOptions checks requires_subscription, live and
    player_loc:allow_embed as well as family_friendly, and reports an invalid
    value with the new InvalidVideoYesNo error.
  • SitemapAndIndexStream errors with ERR_STREAM_PREMATURE_CLOSE instead of
    hanging when a sitemap's write stream is destroyed before it finishes, at any
    point in the sitemap. A SitemapAndIndexStream destroyed during rotation no
    longer opens another sitemap file once the current one has finished.
  • SitemapAndIndexStream destroys itself with the error when a sitemap's write
    stream fails while the sitemap is still open, such as EACCES or EISDIR
    when opening the file. It used to crash the process with an unhandled
    error event. simpleSitemapAndIndex now rejects in that case.
  • Destroying a SitemapAndIndexStream also destroys the open sitemap and its
    write stream, so the file descriptor is released.
  • SitemapAndIndexStream destroys the streams getSitemapStream returned when
    it rejects the tuple, instead of leaving their file open.
  • At ErrorLevel.THROW, SitemapAndIndexStream fails when the index rejects a
    sitemap's index item, such as a non-http(s) URL. It used to drop the error,
    writing the sitemap file without listing it in the index.
  • simpleSitemapAndIndex and the CLI connect each sitemap to its gzip and file
    streams with pipeline(), so a gzip failure fails the sitemap instead of
    leaving the write stream open.
  • SitemapAndIndexStream fails with the error, instead of leaving an unhandled
    promise rejection, when writing the first item of a sitemap after rotation
    throws.
  • At ErrorLevel.THROW, SitemapIndexStream no longer outputs a partial
    <sitemap><loc> element before it fails on an invalid lastmod.
  • simpleSitemapAndIndex and the CLI validate each sitemap URL before they
    create its file, so a URL the index rejects no longer leaves an empty
    sitemap file behind. They now fail on such a URL at every error level.
  • sitemap --index prints a stream error and exits with code 1 instead of
    crashing with an unhandled error event.
  • sitemap --validate exits with code 1 when the sitemap is invalid and 2 when
    validation cannot run (xmllint missing or not executable, or schema not
    found). It used to exit 0 in every case, so scripts and CI could not detect a
    failed validation. An xmllint that fails to start for a reason other than
    ENOENT, such as EACCES, now rejects xmlLint() with [error] alone
    instead of [error, ''], so it is no longer reported as an invalid sitemap.
  • sitemap --prepend writes every entry of the prepended sitemap, then the new
    URLs. Both sources were piped into one stream, so whichever ended first
    ended the sitemap: a large prepended file was cut off after its first entries
    and failed with a write-after-end error.
    A prepended file with more than 50,000 URLs, the most a sitemap may hold,
    now fails with exit code 1 instead of being silently truncated.
  • sitemap --parse, --prepend and the default mode print a stream error,
    such as a parse error or a missing input file, and exit with code 1 instead
    of crashing with an unhandled error event. In those modes a reader that
    closes stdout early, such as | head, is not treated as an error. In
    --index mode it still is (exit code 1), because the sitemap files written
    so far are left incomplete.
  • xmlLint() and sitemap --validate find the bundled schema/ directory
    when the package is installed as a dependency. The lookup searched relative
    to process.cwd(), so outside this repository it threw a synchronous
    "Schema directory not found" error that crashed the CLI. It now walks up from
    the module's own directory, and a missing schema rejects the promise instead
    of throwing.
  • xmlLint() destroys a Readable input if xmllint exits or fails to start
    before reading all of it, so the source no longer stays paused with its file
    descriptor open.
  • SitemapStream and SitemapIndexStream check their public level field
    when they warn, so changing level after construction takes effect again,
    as it did in 9.0.1.
  • @types/node is a runtime dependency again, as it was in 9.0.1, because the
    published type definitions import Node's stream types. The range now covers
    every supported Node major (^22 || ^24 || ^26), so npm can share a
    consumer's own copy.
  • XMLToSitemapItemStream now treats CDATA sections as ordinary character data
    in every tag. Previously only the 8 tags from issue #​445 (loc, image:loc,
    video:title, video:description, news:name, news:title,
    image:caption, image:title) accepted CDATA; content in any other tag was
    logged as unhandled. See docs/adr/0001-cdata-is-character-data.md.
  • xmlLint() no longer probes for the binary with which, which is not a
    command on Windows and made validation report XMLLintUnavailable there even
    when xmllint was installed. A missing binary is now detected via ENOENT from
    the spawn itself, which is correct on every platform.
  • The published tarball now contains only dist/ and schema/ (via a files
    allowlist), so maintainer files such as CLAUDE.md no longer ship to
    consumers (#​480).
  • The CLI locates package.json by walking up from its own directory instead of
    a hardcoded relative depth, so --version no longer breaks when the build
    output layout changes.
  • sitemap --index reports an invalid --limit with the same message as
    simpleSitemapAndIndex's InvalidLimitError, prefixed with --limit:, and
    accepts only decimal digits: forms such as 1e3, 0x10 or 250 are
    rejected rather than converted.
  • InvalidLimitError says the limit must be an integer between 1 and 50000,
    rather than a number, since fractional limits are rejected too.
  • XMLToSitemapItemStream no longer adds an empty { url: '', lang: '' }
    entry to links for an xhtml:link that lacks rel or href or has an
    unsupported rel. It still warns and records a parse error.
  • XMLToSitemapItemStream and XMLToSitemapIndexStream copy their options
    instead of setting objectMode on the object the caller passed in.
Documentation
  • api.md now documents XMLToSitemapIndexStream and parseSitemapIndex, and
    the 50,000-entry and error-array caps the parsers enforce.
  • api.md no longer claims simpleSitemapAndIndex accepts an absolute
    destinationDir; absolute paths have been rejected since 9.0.1 (#​478).
  • JSDoc examples for parseSitemap and parseSitemapIndex use import and
    current APIs instead of require() and the removed createSitemap.

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [sitemap](https://github.com/ekalinin/sitemap.js) | [`^9.0.0` → `^10.0.0`](https://renovatebot.com/diffs/npm/sitemap/9.0.1/10.0.0) | ![age](https://developer.mend.io/api/mc/badges/age/npm/sitemap/10.0.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/sitemap/9.0.1/10.0.0?slim=true) | --- ### Release Notes <details> <summary>ekalinin/sitemap.js (sitemap)</summary> ### [`v10.0.0`](https://github.com/ekalinin/sitemap.js/blob/HEAD/CHANGELOG.md#1000---2026-10-19) [Compare Source](https://github.com/ekalinin/sitemap.js/compare/9.0.1...10.0.0) ##### \[BREAKING CHANGES] ##### Dropped CommonJS build — the package is now ESM-only - **`require('sitemap')` is no longer supported** on Node versions without built-in `require(esm)`. The `dist/cjs` build, the `require` export condition, and `tsconfig.cjs.json` are all gone; `exports` now resolves to `dist/index.js` for every consumer. Migrate to `import { SitemapStream } from 'sitemap'`. - **Node.js >=22.22.1 now required** (previously >=20.19.5). CommonJS consumers can still load this package through `require(esm)`, which landed unflagged in 22.12; the floor is 22.22.1 to match the development toolchain. - Build output flattened from `dist/esm/*` and `dist/cjs/*` to `dist/*`. The `bin` entry is now `dist/cli.js`. ##### `simpleSitemapAndIndex` defaults to 45,000 URLs per sitemap - The default `limit` drops from 50,000 to 45,000, the same default `SitemapAndIndexStream` and the CLI already use (`DEFAULT_SITEMAP_ITEM_LIMIT`). The headroom keeps rich entries (images, video, news) under the 50MB uncompressed file-size limit. A 50,000-URL input now produces two sitemap files instead of one; pass `limit: 50000` to keep the old output. ##### `SitemapStream` writes an empty sitemap instead of erroring - Ending a `SitemapStream` without writing any items now produces a well-formed empty `<urlset>` instead of failing with `EmptySitemap` ([#&#8203;394](https://github.com/ekalinin/sitemap.js/issues/394), [#&#8203;421](https://github.com/ekalinin/sitemap.js/issues/421)). This matches `SitemapIndexStream`, which already wrote an empty `<sitemapindex>`. `EmptySitemap` is still exported but deprecated and no longer thrown. An empty `<urlset>` does not pass strict `sitemap.xsd` validation, which requires at least one `<url>`; search engines accept it. ##### One `logger` option across the library; `xmlNS` renamed to `xmlns` - `SitemapStream`, `SitemapIndexStream`, `SitemapAndIndexStream` and `simpleSitemapAndIndex` accept the same `logger` option the parsers already had ([#&#8203;348](https://github.com/ekalinin/sitemap.js/issues/348)). Validation warnings that went straight to `console.warn` now go through it. Pass `false` to silence. The `Logger` type is now exported. - Invalid news and video attribute values now go through `errorHandler` (and so the logger) like every other validation error, instead of a hardcoded `console.warn`. The warning text is now the error's name and message, which starts with the item's URL. Under `ErrorLevel.THROW` a custom `errorHandler` receives these errors too, like every other validation error; the default handler still throws. - The `SitemapStream` property `xmlNS` is now `xmlns`, matching the option name ([#&#8203;300](https://github.com/ekalinin/sitemap.js/issues/300)). `xmlNS` still works as a deprecated alias. `SitemapStream.errorHandler` is always set now; it defaults to a handler that warns through `logger`. ##### Both XML parsers share one error store and entry cap `XMLToSitemapItemStream` and `XMLToSitemapIndexStream` now extend one internal base class, so they report errors and cap entries the same way. - `XMLToSitemapIndexStream.error` is a read-only getter for the first error (`errors[0]`, or `null`). Assigning to it now throws a `TypeError` in strict mode. The index parser also gains the `errors` array (capped at `LIMITS.MAX_PARSER_ERRORS`) and `errorCount`, where it previously kept only the first error. - `XMLToSitemapItemStream` reports a sitemap with more than 50,000 `<url>` entries once, instead of logging and recording an error for every dropped entry, so `errorCount` and the log no longer grow with the overflow. It gains the index parser's `maxEntries` option, `entryCount` property and `'maxEntriesExceeded'` event, and an `error` getter. `urlCount` still works as a deprecated alias for `entryCount`. `parseSitemap` still resolves with the first 50,000 items, but it now stops reading once the cap is crossed and destroys the source stream, as `parseSitemapIndex` already did. - Both parsers now fail on a truncated document (an element left unclosed when the input ends), like any other malformed XML. Before, the unfinished entry was dropped silently. `parseSitemap` and `parseSitemapIndex` reject in that case, and `parseSitemap` now also rejects when the source stream fails instead of never settling. - The index parser's warnings for an invalid `<loc>` or `<lastmod>` are now logged as one message, the same text recorded in `errors`. The recorded lastmod error now reads `Invalid lastmod date format in sitemap index: …`. ##### `SitemapAndIndexStream` destroys itself on error - When a sitemap stream errors, or `getSitemapStream` throws or returns an invalid tuple, `SitemapAndIndexStream` now destroys itself and emits the error once. It used to emit the error without stopping, so the same failure could be emitted twice, and a `getSitemapStream` failure was followed by a generic `No sitemap stream available` error. Code that listened for `error` and kept writing now gets write-after-destroy errors instead. ##### `sitemap --index --gzip` names sitemaps `sitemap-N.xml.gz` - With `--gzip`, `sitemap --index` now writes each sitemap to `sitemap-N.xml.gz` and lists that URL in the index, as `simpleSitemapAndIndex` already did. It used to write gzipped data to `sitemap-N.xml` and index it under that name, so crawlers fetched gzip bytes from a `.xml` URL. Update scripts that upload or serve `sitemap-*.xml` after a gzipped run. ##### `SitemapStream` reports item errors as stream errors - `SitemapStream` and `SitemapItemStream` now report a failure on an item through the stream: `write()` no longer throws, and the stream emits `error` and is destroyed. This covers an invalid item at `ErrorLevel.THROW`, an item `normalizeURL` rejects (such as an invalid `lastmod`), and an item that can't be serialized (such as a non-string video attribute at `ErrorLevel.SILENT`). Before, the error was thrown out of `write()`, so a piped source crashed the process with an uncaught exception. Code that wrapped `write()` in `try`/`catch` must listen for `error` instead, or use `pipeline()`. - `SitemapStream` checks `xmlns.custom` in its constructor, so an invalid custom namespace now throws from `new SitemapStream()` instead of from the first `write()`. - `SitemapStream` serializes each item itself instead of piping it through an internal `SitemapItemStream`, so it now outputs one chunk per item. The XML is unchanged. ##### Stricter `priority` and alternate-link validation - A `priority` of `NaN` is now reported as a `PriorityInvalidError`: it throws at `ErrorLevel.THROW` and warns at `WARN`. It used to skip validation and write `<priority>NaN</priority>` at every level. - An alternate link with no `lang` or `hreflang` is now reported as the new `InvalidLinkHreflang` error at `WARN` and `THROW`, and dropped from the output at `WARN` and `SILENT`. `SitemapItemStream`, which doesn't validate, drops it too, with no warning. Every level used to fail with a `TypeError` from the XML writer. Writing the link without `hreflang` would produce the `androidLink` markup, which parses back as `androidLink`. ##### Error classes are exported by name; `UndefinedTargetFolder` removed - `index.ts` lists the error classes explicitly instead of `export * from './lib/errors.js'`, like the public types, so a new error class is public only once it is added there. - `UndefinedTargetFolder` is removed. Nothing has thrown it since 7.0.0, which removed `createSitemapsAndIndex`, its only user. ##### Changed - The CLI parses arguments with Node's built-in `util.parseArgs` instead of the `arg` package, which is no longer a dependency ([#&#8203;471](https://github.com/ekalinin/sitemap.js/issues/471)). Unknown options and a non-integer `--limit` now print a message and exit with code 2 instead of throwing an uncaught error. - Test suite migrated from Jest to the built-in Node.js test runner. Coverage thresholds moved from `jest.config.cjs` into the `test:coverage` script and are enforced in CI by a dedicated job. - CI now runs on Linux, Windows and macOS across Node 22/24/26. Lint, formatting and typechecking run once rather than on every matrix leg. - **Stricter `<loc>` validation in the sitemap parser**: `XMLToSitemapItemStream` now validates `<loc>` values with the same `validateURL` used by the sitemap index parser, adding a URL-parseability check on top of the existing length and protocol checks. A malformed URL that passed the old checks but fails `new URL()` is now dropped with a warning (or throws under `ErrorLevel.THROW`). Warn/error messages for invalid `<loc>` values changed to the `Invalid URL in sitemap: …` form. - **`validateURL` throws `InvalidURLError`**, a new subclass of `InvalidHostnameError` (so `instanceof InvalidHostnameError` still matches). Its message reads `Invalid URL "…": …` instead of `Invalid hostname "…": …`, and it shows at most the first 100 characters of the offending value. - **Stricter video validation in `validateSMIOptions`**: a video `duration`, `rating` or `view_count` that is `NaN`, `Infinity` or otherwise non-numeric is now reported as invalid (and throws under `ErrorLevel.THROW`). Previously only out-of-range finite numbers were caught, so `NaN` slipped through. - `XMLToSitemapItemStream` now buffers each element's character data and handles it once at the next tag boundary: text and CDATA chunks within one element are joined, surrounding whitespace is trimmed for CDATA as it already was for text, whitespace between chunks is kept (`Episode <![CDATA[One]]>` now parses as `Episode One`, not `EpisodeOne`), and stray character data between elements is reported against the enclosing element instead of overwriting the previous one. Character data longer than `LIMITS.MAX_PARSER_CHAR_DATA_LENGTH` (64 KiB) for one element is dropped with a warning. - Internal: the parser's duplicated `text`/`cdata` SAX handlers were collapsed into one, and its inline bounds checks (priority, video duration/rating/view count, ISO dates) now delegate to shared guards in `lib/validation.ts`, with the bounds defined once in `LIMITS`. - `XMLToSitemapIndexStream` now handles character data the same way: text and CDATA within one `<loc>` or `<lastmod>` are joined and trimmed, stray character data is reported against the enclosing element, and values longer than `LIMITS.MAX_PARSER_CHAR_DATA_LENGTH` are dropped with a warning. Unhandled CDATA is now logged as `unhandled text for tag:` instead of `unhandled cdata for tag:`. Both parsers share one buffer, `createCharDataBuffer` in `lib/utils.ts`. - **`XMLToSitemapIndexStream` enforces the 50,000-entry spec limit itself.** Entries past `LIMITS.MAX_SITEMAP_ITEM_LIMIT` are dropped with a single error (which throws under `ErrorLevel.THROW`), and a new `entryCount` property counts every `<sitemap>` seen. Previously only the `parseSitemapIndex` wrapper capped entries, so piping the stream directly had no limit. `parseSitemapIndex` still rejects an over-limit index and stops reading as soon as the limit is crossed, but a `maxEntries` above 50,000 no longer raises the limit. A new `maxEntries` stream option lowers the cap, or raises it (`Infinity` turns it off) for callers that knowingly parse oversized indexes. When the cap is crossed the stream emits `'maxEntriesExceeded'`, and logs the overflow only if nothing listens for that event, so `parseSitemapIndex` rejects without also logging. `maxEntries: 0` is allowed (nothing is emitted, and `parseSitemapIndex` rejects on the first entry); a negative, fractional or `NaN` value is rejected, and `parseSitemapIndex` destroys the source stream before rejecting. - Errors that `simpleSitemapAndIndex` and `SitemapAndIndexStream` wrap, such as `Failed to write sitemap files: …` or a `getSitemapStream` failure, now carry the original error as `cause`. - `SaxParserStreamOptions`, the shared base of `XMLToSitemapItemStreamOptions` and `XMLToSitemapIndexItemStreamOptions`, is exported. - `LIMITS` gains the bounds the validators use: `MIN_PRIORITY`, `MAX_PRIORITY`, `PRIORITY_STRING_REGEX`, `MIN_VIDEO_DURATION`, `MAX_VIDEO_DURATION`, `MIN_VIDEO_RATING`, `MAX_VIDEO_RATING` and `MIN_VIDEO_VIEW_COUNT`. - `LIMITS.MAX_URL_ENTRIES` is deprecated. Nothing reads it; the parsers cap entries at `LIMITS.MAX_SITEMAP_ITEM_LIMIT` (the same value), which their `maxEntries` option overrides. ##### Fixed - A string `priority` no longer crashes `SitemapStream` with `item.priority.toFixed is not a function` ([#&#8203;393](https://github.com/ekalinin/sitemap.js/issues/393)). A plain decimal string such as `'0.5'` or `'.5'` is converted to a number (hex, binary and exponent forms such as `'0x1'` or `'1e-1'` are not), and `SitemapItemLoose.priority` now accepts `number | string`. Any other value, including an empty string, is reported as a `PriorityInvalidError` at `WARN` and `THROW`, and written as given at `WARN` and `SILENT`, like other invalid values. `isValidPriority` rejects non-numbers instead of coercing them. - `isValidYesNo` accepts only a whole `yes`, `Yes`, `YES`, `no`, `No` or `NO`. Its unanchored alternation used to accept any value that started with `YES`, contained `NO` or `yes`, or ended in `no`, such as `NOPE` or `maybe-yes`, so the parsers and `validateSMIOptions` let those values through. - `XMLToSitemapItemStream` reports an invalid `video:requires_subscription`, `video:family_friendly`, `video:live` or `player_loc` `allow_embed` value as a warning and a parse error. It used to drop the value without a word. It also trims whitespace around `allow_embed`, as it already does for element text. - `validateSMIOptions` checks `requires_subscription`, `live` and `player_loc:allow_embed` as well as `family_friendly`, and reports an invalid value with the new `InvalidVideoYesNo` error. - `SitemapAndIndexStream` errors with `ERR_STREAM_PREMATURE_CLOSE` instead of hanging when a sitemap's write stream is destroyed before it finishes, at any point in the sitemap. A `SitemapAndIndexStream` destroyed during rotation no longer opens another sitemap file once the current one has finished. - `SitemapAndIndexStream` destroys itself with the error when a sitemap's write stream fails while the sitemap is still open, such as `EACCES` or `EISDIR` when opening the file. It used to crash the process with an unhandled `error` event. `simpleSitemapAndIndex` now rejects in that case. - Destroying a `SitemapAndIndexStream` also destroys the open sitemap and its write stream, so the file descriptor is released. - `SitemapAndIndexStream` destroys the streams `getSitemapStream` returned when it rejects the tuple, instead of leaving their file open. - At `ErrorLevel.THROW`, `SitemapAndIndexStream` fails when the index rejects a sitemap's index item, such as a non-http(s) URL. It used to drop the error, writing the sitemap file without listing it in the index. - `simpleSitemapAndIndex` and the CLI connect each sitemap to its gzip and file streams with `pipeline()`, so a gzip failure fails the sitemap instead of leaving the write stream open. - `SitemapAndIndexStream` fails with the error, instead of leaving an unhandled promise rejection, when writing the first item of a sitemap after rotation throws. - At `ErrorLevel.THROW`, `SitemapIndexStream` no longer outputs a partial `<sitemap><loc>` element before it fails on an invalid `lastmod`. - `simpleSitemapAndIndex` and the CLI validate each sitemap URL before they create its file, so a URL the index rejects no longer leaves an empty sitemap file behind. They now fail on such a URL at every error level. - `sitemap --index` prints a stream error and exits with code 1 instead of crashing with an unhandled `error` event. - `sitemap --validate` exits with code 1 when the sitemap is invalid and 2 when validation cannot run (xmllint missing or not executable, or schema not found). It used to exit 0 in every case, so scripts and CI could not detect a failed validation. An xmllint that fails to start for a reason other than `ENOENT`, such as `EACCES`, now rejects `xmlLint()` with `[error]` alone instead of `[error, '']`, so it is no longer reported as an invalid sitemap. - `sitemap --prepend` writes every entry of the prepended sitemap, then the new URLs. Both sources were piped into one stream, so whichever ended first ended the sitemap: a large prepended file was cut off after its first entries and failed with a write-after-end error. A prepended file with more than 50,000 URLs, the most a sitemap may hold, now fails with exit code 1 instead of being silently truncated. - `sitemap --parse`, `--prepend` and the default mode print a stream error, such as a parse error or a missing input file, and exit with code 1 instead of crashing with an unhandled `error` event. In those modes a reader that closes stdout early, such as `| head`, is not treated as an error. In `--index` mode it still is (exit code 1), because the sitemap files written so far are left incomplete. - `xmlLint()` and `sitemap --validate` find the bundled `schema/` directory when the package is installed as a dependency. The lookup searched relative to `process.cwd()`, so outside this repository it threw a synchronous "Schema directory not found" error that crashed the CLI. It now walks up from the module's own directory, and a missing schema rejects the promise instead of throwing. - `xmlLint()` destroys a `Readable` input if xmllint exits or fails to start before reading all of it, so the source no longer stays paused with its file descriptor open. - `SitemapStream` and `SitemapIndexStream` check their public `level` field when they warn, so changing `level` after construction takes effect again, as it did in 9.0.1. - `@types/node` is a runtime dependency again, as it was in 9.0.1, because the published type definitions import Node's stream types. The range now covers every supported Node major (`^22 || ^24 || ^26`), so npm can share a consumer's own copy. - `XMLToSitemapItemStream` now treats CDATA sections as ordinary character data in every tag. Previously only the 8 tags from issue [#&#8203;445](https://github.com/ekalinin/sitemap.js/issues/445) (`loc`, `image:loc`, `video:title`, `video:description`, `news:name`, `news:title`, `image:caption`, `image:title`) accepted CDATA; content in any other tag was logged as unhandled. See `docs/adr/0001-cdata-is-character-data.md`. - `xmlLint()` no longer probes for the binary with `which`, which is not a command on Windows and made validation report `XMLLintUnavailable` there even when xmllint was installed. A missing binary is now detected via `ENOENT` from the spawn itself, which is correct on every platform. - The published tarball now contains only `dist/` and `schema/` (via a `files` allowlist), so maintainer files such as `CLAUDE.md` no longer ship to consumers ([#&#8203;480](https://github.com/ekalinin/sitemap.js/issues/480)). - The CLI locates `package.json` by walking up from its own directory instead of a hardcoded relative depth, so `--version` no longer breaks when the build output layout changes. - `sitemap --index` reports an invalid `--limit` with the same message as `simpleSitemapAndIndex`'s `InvalidLimitError`, prefixed with `--limit:`, and accepts only decimal digits: forms such as `1e3`, `0x10` or `250` are rejected rather than converted. - `InvalidLimitError` says the limit must be an integer between 1 and 50000, rather than a number, since fractional limits are rejected too. - `XMLToSitemapItemStream` no longer adds an empty `{ url: '', lang: '' }` entry to `links` for an `xhtml:link` that lacks `rel` or `href` or has an unsupported `rel`. It still warns and records a parse error. - `XMLToSitemapItemStream` and `XMLToSitemapIndexStream` copy their options instead of setting `objectMode` on the object the caller passed in. ##### Documentation - `api.md` now documents `XMLToSitemapIndexStream` and `parseSitemapIndex`, and the 50,000-entry and error-array caps the parsers enforce. - `api.md` no longer claims `simpleSitemapAndIndex` accepts an absolute `destinationDir`; absolute paths have been rejected since 9.0.1 ([#&#8203;478](https://github.com/ekalinin/sitemap.js/issues/478)). - JSDoc examples for `parseSitemap` and `parseSitemapIndex` use `import` and current APIs instead of `require()` and the removed `createSitemap`. </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4yIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMiIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119-->
fix(deps): update dependency sitemap to v10
All checks were successful
ci/woodpecker/push/bun-verify Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
ci/woodpecker/pr/verify Pipeline was successful
680f6a5205
martin merged commit 8479cd24ac into master 2026-10-20 17:52:08 +00:00
martin deleted branch renovate/sitemap-10.x 2026-10-20 17:52:08 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
Personal/martials.no!82
No description provided.