2026-03-20 14:03:33 +00:00
|
|
|
|
// ============================================================
|
|
|
|
|
|
// CORE TYPES
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Change frequency values per the sitemap protocol specification.
|
|
|
|
|
|
* Note: Google ignores changefreq, but other search engines may use it.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export type TChangeFreq =
|
|
|
|
|
|
| 'always'
|
|
|
|
|
|
| 'hourly'
|
|
|
|
|
|
| 'daily'
|
|
|
|
|
|
| 'weekly'
|
|
|
|
|
|
| 'monthly'
|
|
|
|
|
|
| 'yearly'
|
|
|
|
|
|
| 'never';
|
|
|
|
|
|
|
|
|
|
|
|
/** Supported output formats */
|
|
|
|
|
|
export type TOutputFormat = 'xml' | 'txt' | 'json';
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// URL ENTRY — the core unit of a sitemap
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* A single URL entry in a sitemap, supporting all standard extensions.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface ISitemapUrl {
|
|
|
|
|
|
/** Absolute URL of the page (required, max 2048 chars) */
|
|
|
|
|
|
loc: string;
|
|
|
|
|
|
/** Last modification date — accepts Date, ISO string, or Unix timestamp (ms) */
|
|
|
|
|
|
lastmod?: Date | string | number;
|
|
|
|
|
|
/** How frequently the page changes */
|
|
|
|
|
|
changefreq?: TChangeFreq;
|
|
|
|
|
|
/** Priority relative to other URLs on your site, 0.0 to 1.0 */
|
|
|
|
|
|
priority?: number;
|
|
|
|
|
|
/** Image sitemap extension entries */
|
|
|
|
|
|
images?: ISitemapImage[];
|
|
|
|
|
|
/** Video sitemap extension entries */
|
|
|
|
|
|
videos?: ISitemapVideo[];
|
|
|
|
|
|
/** News sitemap extension */
|
|
|
|
|
|
news?: ISitemapNews;
|
|
|
|
|
|
/** Alternate language versions (hreflang) */
|
|
|
|
|
|
alternates?: ISitemapAlternate[];
|
2020-10-28 17:43:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-20 14:03:33 +00:00
|
|
|
|
// ============================================================
|
|
|
|
|
|
// SITEMAP EXTENSIONS
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
export interface ISitemapImage {
|
|
|
|
|
|
/** URL of the image (required) */
|
|
|
|
|
|
loc: string;
|
|
|
|
|
|
/** Caption for the image */
|
|
|
|
|
|
caption?: string;
|
|
|
|
|
|
/** Title of the image */
|
2020-10-28 17:43:58 +00:00
|
|
|
|
title?: string;
|
2026-03-20 14:03:33 +00:00
|
|
|
|
/** Geographic location (e.g. "New York, USA") */
|
|
|
|
|
|
geoLocation?: string;
|
|
|
|
|
|
/** URL to the image license */
|
|
|
|
|
|
licenseUrl?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ISitemapVideo {
|
|
|
|
|
|
/** URL to the video thumbnail (required) */
|
|
|
|
|
|
thumbnailLoc: string;
|
|
|
|
|
|
/** Title of the video (required) */
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
/** Description of the video, max 2048 chars (required) */
|
|
|
|
|
|
description: string;
|
|
|
|
|
|
/** URL of the actual video media file */
|
|
|
|
|
|
contentLoc?: string;
|
|
|
|
|
|
/** URL of the embeddable player — at least one of contentLoc or playerLoc required */
|
|
|
|
|
|
playerLoc?: string;
|
|
|
|
|
|
/** Duration in seconds (1–28800) */
|
|
|
|
|
|
duration?: number;
|
|
|
|
|
|
/** Rating 0.0 to 5.0 */
|
|
|
|
|
|
rating?: number;
|
|
|
|
|
|
/** Number of views */
|
|
|
|
|
|
viewCount?: number;
|
|
|
|
|
|
/** Publication date */
|
|
|
|
|
|
publicationDate?: Date | string;
|
|
|
|
|
|
/** Whether the video is family friendly (default true) */
|
|
|
|
|
|
familyFriendly?: boolean;
|
|
|
|
|
|
/** Tags for the video (max 32) */
|
|
|
|
|
|
tags?: string[];
|
|
|
|
|
|
/** Whether this is a live stream */
|
|
|
|
|
|
live?: boolean;
|
|
|
|
|
|
/** Whether a subscription is required to view */
|
|
|
|
|
|
requiresSubscription?: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ISitemapNews {
|
|
|
|
|
|
/** Publication information */
|
|
|
|
|
|
publication: {
|
|
|
|
|
|
/** Publication name (e.g. "The New York Times") */
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
/** Language code (ISO 639, e.g. "en", "de", "zh-cn") */
|
|
|
|
|
|
language: string;
|
|
|
|
|
|
};
|
|
|
|
|
|
/** Publication date of the article */
|
|
|
|
|
|
publicationDate: Date | string | number;
|
|
|
|
|
|
/** Article title */
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
/** Keywords (array or comma-separated string) */
|
|
|
|
|
|
keywords?: string[] | string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ISitemapAlternate {
|
|
|
|
|
|
/** Language code (ISO 639) or 'x-default' for the default version */
|
|
|
|
|
|
hreflang: string;
|
|
|
|
|
|
/** URL for this language version */
|
|
|
|
|
|
href: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// SITEMAP INDEX
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
export interface ISitemapIndexEntry {
|
|
|
|
|
|
/** URL to the sitemap file */
|
|
|
|
|
|
loc: string;
|
|
|
|
|
|
/** Last modification date of the referenced sitemap */
|
|
|
|
|
|
lastmod?: Date | string | number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// CONFIGURATION
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
export interface ISitemapOptions {
|
|
|
|
|
|
/** Base URL for the website (used to resolve relative URLs and for auto-split filenames) */
|
|
|
|
|
|
baseUrl?: string;
|
|
|
|
|
|
/** XSL stylesheet URL for browser-viewable sitemaps */
|
|
|
|
|
|
xslUrl?: string;
|
|
|
|
|
|
/** Default changefreq for URLs that don't specify one */
|
|
|
|
|
|
defaultChangeFreq?: TChangeFreq;
|
|
|
|
|
|
/** Default priority for URLs that don't specify one (0.0–1.0) */
|
|
|
|
|
|
defaultPriority?: number;
|
|
|
|
|
|
/** Whether to pretty-print XML output (default: true) */
|
|
|
|
|
|
prettyPrint?: boolean;
|
|
|
|
|
|
/** Maximum URLs per sitemap file before auto-splitting (default: 50000, max: 50000) */
|
|
|
|
|
|
maxUrlsPerSitemap?: number;
|
|
|
|
|
|
/** Enable gzip compression for toGzipBuffer() */
|
|
|
|
|
|
gzip?: boolean;
|
|
|
|
|
|
/** Whether to validate URLs and fields (default: true) */
|
|
|
|
|
|
validate?: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface INewsSitemapOptions extends ISitemapOptions {
|
|
|
|
|
|
/** Publication name — required for news sitemaps */
|
|
|
|
|
|
publicationName: string;
|
|
|
|
|
|
/** Publication language (default: 'en') */
|
|
|
|
|
|
publicationLanguage?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface IFeedImportOptions {
|
|
|
|
|
|
/** Publication name for news sitemap mapping */
|
|
|
|
|
|
publicationName?: string;
|
|
|
|
|
|
/** Publication language for news sitemap mapping */
|
|
|
|
|
|
publicationLanguage?: string;
|
|
|
|
|
|
/** Only include items newer than this date */
|
|
|
|
|
|
newerThan?: Date | number;
|
|
|
|
|
|
/** Maximum number of items to import */
|
|
|
|
|
|
limit?: number;
|
|
|
|
|
|
/** Custom mapping function from feed item to sitemap URL (return null to skip) */
|
|
|
|
|
|
mapItem?: (item: IFeedItem) => ISitemapUrl | null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Shape of a parsed RSS/Atom feed item */
|
|
|
|
|
|
export interface IFeedItem {
|
|
|
|
|
|
title?: string;
|
|
|
|
|
|
link?: string;
|
2020-10-28 17:43:58 +00:00
|
|
|
|
pubDate?: string;
|
2026-03-20 14:03:33 +00:00
|
|
|
|
author?: string;
|
2020-10-28 17:43:58 +00:00
|
|
|
|
content?: string;
|
2026-03-20 14:03:33 +00:00
|
|
|
|
contentSnippet?: string;
|
2020-10-28 17:43:58 +00:00
|
|
|
|
isoDate?: string;
|
2026-03-20 14:03:33 +00:00
|
|
|
|
id?: string;
|
2020-10-28 17:43:58 +00:00
|
|
|
|
categories?: string[];
|
2026-03-20 14:03:33 +00:00
|
|
|
|
enclosure?: {
|
|
|
|
|
|
url?: string;
|
|
|
|
|
|
type?: string;
|
|
|
|
|
|
length?: string;
|
2021-01-03 02:48:45 +00:00
|
|
|
|
};
|
2026-03-20 14:03:33 +00:00
|
|
|
|
[key: string]: any;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// YAML CONFIG
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Enhanced YAML configuration format for defining sitemaps declaratively.
|
|
|
|
|
|
* Supports per-frequency URL groups, default settings, and feed imports.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface ISitemapYamlConfig {
|
|
|
|
|
|
/** Base URL to prepend to relative paths */
|
|
|
|
|
|
baseUrl?: string;
|
|
|
|
|
|
/** Default values for all URLs */
|
|
|
|
|
|
defaults?: {
|
|
|
|
|
|
changefreq?: TChangeFreq;
|
|
|
|
|
|
priority?: number;
|
|
|
|
|
|
};
|
|
|
|
|
|
/** URL groups organized by change frequency */
|
|
|
|
|
|
urls?: { [K in TChangeFreq]?: string[] };
|
|
|
|
|
|
/** RSS/Atom feeds to import */
|
|
|
|
|
|
feeds?: Array<{
|
|
|
|
|
|
url: string;
|
|
|
|
|
|
type: 'news' | 'standard';
|
|
|
|
|
|
publicationName?: string;
|
|
|
|
|
|
publicationLanguage?: string;
|
|
|
|
|
|
}>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// PARSED SITEMAP (bidirectional)
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
export interface IParsedSitemap {
|
|
|
|
|
|
/** Whether this is a urlset or a sitemap index */
|
|
|
|
|
|
type: 'urlset' | 'sitemapindex';
|
|
|
|
|
|
/** Parsed URL entries (populated when type is 'urlset') */
|
|
|
|
|
|
urls: ISitemapUrl[];
|
|
|
|
|
|
/** Parsed index entries (populated when type is 'sitemapindex') */
|
|
|
|
|
|
sitemaps: ISitemapIndexEntry[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// VALIDATION
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
export interface IValidationError {
|
|
|
|
|
|
field: string;
|
|
|
|
|
|
message: string;
|
|
|
|
|
|
url?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface IValidationWarning {
|
|
|
|
|
|
field: string;
|
|
|
|
|
|
message: string;
|
|
|
|
|
|
url?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface IValidationResult {
|
|
|
|
|
|
valid: boolean;
|
|
|
|
|
|
errors: IValidationError[];
|
|
|
|
|
|
warnings: IValidationWarning[];
|
|
|
|
|
|
stats: ISitemapStats;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// STATISTICS
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
export interface ISitemapStats {
|
|
|
|
|
|
urlCount: number;
|
|
|
|
|
|
imageCount: number;
|
|
|
|
|
|
videoCount: number;
|
|
|
|
|
|
newsCount: number;
|
|
|
|
|
|
alternateCount: number;
|
|
|
|
|
|
estimatedSizeBytes: number;
|
|
|
|
|
|
needsIndex: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// AUTO-SPLIT OUTPUT
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
export interface ISitemapSet {
|
|
|
|
|
|
/** Whether the URL count exceeded maxUrlsPerSitemap */
|
|
|
|
|
|
needsIndex: boolean;
|
|
|
|
|
|
/** The sitemap index XML (null if all URLs fit in one sitemap) */
|
|
|
|
|
|
indexXml: string | null;
|
|
|
|
|
|
/** Individual sitemap chunks */
|
|
|
|
|
|
sitemaps: Array<{ filename: string; xml: string }>;
|
2021-01-03 02:48:45 +00:00
|
|
|
|
}
|