@flightdev/seo 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +403 -0
- package/dist/index.d.ts +282 -0
- package/dist/index.js +1239 -0
- package/dist/index.js.map +1 -0
- package/dist/json-ld/index.d.ts +341 -0
- package/dist/json-ld/index.js +82 -0
- package/dist/json-ld/index.js.map +1 -0
- package/dist/react/index.d.ts +161 -0
- package/dist/react/index.js +1300 -0
- package/dist/react/index.js.map +1 -0
- package/dist/robots/index.d.ts +105 -0
- package/dist/robots/index.js +186 -0
- package/dist/robots/index.js.map +1 -0
- package/dist/sitemap/index.d.ts +224 -0
- package/dist/sitemap/index.js +242 -0
- package/dist/sitemap/index.js.map +1 -0
- package/dist/solid/index.d.ts +50 -0
- package/dist/solid/index.js +1217 -0
- package/dist/solid/index.js.map +1 -0
- package/dist/svelte/index.d.ts +131 -0
- package/dist/svelte/index.js +1253 -0
- package/dist/svelte/index.js.map +1 -0
- package/dist/types-BBIMJIqz.d.ts +433 -0
- package/dist/vue/index.d.ts +130 -0
- package/dist/vue/index.js +1293 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +129 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/robots/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @flightdev/seo - robots.txt Generator\r\n *\r\n * Generate robots.txt files for search engine crawlers.\r\n * Supports multiple user-agents, allow/disallow rules, crawl-delay, and sitemaps.\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * robots.txt rule\r\n */\r\nexport interface RobotsRule {\r\n /** User-agent this rule applies to */\r\n userAgent: string;\r\n /** Allowed paths */\r\n allow?: string[];\r\n /** Disallowed paths */\r\n disallow?: string[];\r\n /** Crawl delay in seconds */\r\n crawlDelay?: number;\r\n}\r\n\r\n/**\r\n * robots.txt configuration\r\n */\r\nexport interface RobotsConfig {\r\n /** Sitemap URLs */\r\n sitemapUrls?: string[];\r\n /** Host directive (for Yandex) */\r\n host?: string;\r\n /** Initial rules */\r\n rules?: RobotsRule[];\r\n}\r\n\r\n// ============================================================================\r\n// Robots Class\r\n// ============================================================================\r\n\r\n/**\r\n * robots.txt generator\r\n */\r\nexport class Robots {\r\n private rules: Map<string, RobotsRule> = new Map();\r\n private sitemaps: string[] = [];\r\n private host: string | undefined;\r\n\r\n constructor(config?: RobotsConfig) {\r\n if (config?.sitemapUrls) {\r\n this.sitemaps = [...config.sitemapUrls];\r\n }\r\n if (config?.host) {\r\n this.host = config.host;\r\n }\r\n if (config?.rules) {\r\n for (const rule of config.rules) {\r\n this.rules.set(rule.userAgent, rule);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Add an allow rule\r\n */\r\n allow(userAgent: string, path: string): this {\r\n const rule = this.getOrCreateRule(userAgent);\r\n if (!rule.allow) {\r\n rule.allow = [];\r\n }\r\n if (!rule.allow.includes(path)) {\r\n rule.allow.push(path);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a disallow rule\r\n */\r\n disallow(userAgent: string, path: string): this {\r\n const rule = this.getOrCreateRule(userAgent);\r\n if (!rule.disallow) {\r\n rule.disallow = [];\r\n }\r\n if (!rule.disallow.includes(path)) {\r\n rule.disallow.push(path);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Set crawl delay for a user-agent\r\n */\r\n setCrawlDelay(userAgent: string, seconds: number): this {\r\n const rule = this.getOrCreateRule(userAgent);\r\n rule.crawlDelay = seconds;\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a sitemap URL\r\n */\r\n addSitemap(url: string): this {\r\n if (!this.sitemaps.includes(url)) {\r\n this.sitemaps.push(url);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Set host directive\r\n */\r\n setHost(host: string): this {\r\n this.host = host;\r\n return this;\r\n }\r\n\r\n /**\r\n * Block all crawlers from all paths\r\n */\r\n blockAll(): this {\r\n return this.disallow('*', '/');\r\n }\r\n\r\n /**\r\n * Allow all crawlers to access all paths\r\n */\r\n allowAll(): this {\r\n return this.allow('*', '/');\r\n }\r\n\r\n /**\r\n * Block specific paths for all crawlers\r\n */\r\n blockPaths(...paths: string[]): this {\r\n for (const path of paths) {\r\n this.disallow('*', path);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Block specific bots entirely\r\n */\r\n blockBots(...bots: string[]): this {\r\n for (const bot of bots) {\r\n this.disallow(bot, '/');\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Get or create a rule for a user-agent\r\n */\r\n private getOrCreateRule(userAgent: string): RobotsRule {\r\n let rule = this.rules.get(userAgent);\r\n if (!rule) {\r\n rule = { userAgent };\r\n this.rules.set(userAgent, rule);\r\n }\r\n return rule;\r\n }\r\n\r\n /**\r\n * Generate robots.txt content\r\n */\r\n generate(): string {\r\n const lines: string[] = [];\r\n\r\n // Sort rules: specific bots first, then * last\r\n const sortedRules = Array.from(this.rules.values()).sort((a, b) => {\r\n if (a.userAgent === '*') return 1;\r\n if (b.userAgent === '*') return -1;\r\n return a.userAgent.localeCompare(b.userAgent);\r\n });\r\n\r\n for (const rule of sortedRules) {\r\n lines.push(`User-agent: ${rule.userAgent}`);\r\n\r\n if (rule.allow) {\r\n for (const path of rule.allow) {\r\n lines.push(`Allow: ${path}`);\r\n }\r\n }\r\n\r\n if (rule.disallow) {\r\n for (const path of rule.disallow) {\r\n lines.push(`Disallow: ${path}`);\r\n }\r\n }\r\n\r\n if (rule.crawlDelay !== undefined) {\r\n lines.push(`Crawl-delay: ${rule.crawlDelay}`);\r\n }\r\n\r\n lines.push('');\r\n }\r\n\r\n // Host directive\r\n if (this.host) {\r\n lines.push(`Host: ${this.host}`);\r\n lines.push('');\r\n }\r\n\r\n // Sitemaps\r\n for (const sitemap of this.sitemaps) {\r\n lines.push(`Sitemap: ${sitemap}`);\r\n }\r\n\r\n return lines.join('\\n').trim();\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Factory Function\r\n// ============================================================================\r\n\r\n/**\r\n * Create a new robots.txt generator\r\n */\r\nexport function createRobots(config?: RobotsConfig): Robots {\r\n return new Robots(config);\r\n}\r\n\r\n// ============================================================================\r\n// Presets\r\n// ============================================================================\r\n\r\n/**\r\n * Create a robots.txt that allows all crawlers\r\n */\r\nexport function allowAllRobots(sitemapUrl?: string): Robots {\r\n const robots = new Robots();\r\n robots.allowAll();\r\n if (sitemapUrl) {\r\n robots.addSitemap(sitemapUrl);\r\n }\r\n return robots;\r\n}\r\n\r\n/**\r\n * Create a robots.txt that blocks all crawlers\r\n */\r\nexport function blockAllRobots(): Robots {\r\n const robots = new Robots();\r\n robots.blockAll();\r\n return robots;\r\n}\r\n\r\n/**\r\n * Create a standard robots.txt for a typical web app\r\n */\r\nexport function standardRobots(options: {\r\n sitemapUrl?: string;\r\n blockPaths?: string[];\r\n host?: string;\r\n}): Robots {\r\n const robots = new Robots();\r\n\r\n // Allow all by default\r\n robots.allow('*', '/');\r\n\r\n // Block common paths that should not be indexed\r\n const defaultBlockPaths = [\r\n '/api/',\r\n '/admin/',\r\n '/_next/',\r\n '/private/',\r\n ];\r\n\r\n for (const path of [...defaultBlockPaths, ...(options.blockPaths || [])]) {\r\n robots.disallow('*', path);\r\n }\r\n\r\n if (options.sitemapUrl) {\r\n robots.addSitemap(options.sitemapUrl);\r\n }\r\n\r\n if (options.host) {\r\n robots.setHost(options.host);\r\n }\r\n\r\n return robots;\r\n}\r\n"]}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/seo - Sitemap Generator
|
|
3
|
+
*
|
|
4
|
+
* Generate XML sitemaps for search engine indexing.
|
|
5
|
+
* Supports standard sitemaps and sitemap indexes for large sites.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Streaming output for memory efficiency
|
|
9
|
+
* - Automatic sitemap splitting (50,000 URLs per file)
|
|
10
|
+
* - Image and video sitemaps
|
|
11
|
+
* - News sitemaps
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Change frequency for URLs
|
|
15
|
+
*/
|
|
16
|
+
type ChangeFrequency = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
17
|
+
/**
|
|
18
|
+
* Sitemap URL entry
|
|
19
|
+
*/
|
|
20
|
+
interface SitemapUrl {
|
|
21
|
+
/** URL location (required) */
|
|
22
|
+
loc: string;
|
|
23
|
+
/** Last modification date (ISO 8601) */
|
|
24
|
+
lastmod?: string | Date;
|
|
25
|
+
/** Change frequency hint */
|
|
26
|
+
changefreq?: ChangeFrequency;
|
|
27
|
+
/** Priority (0.0 to 1.0, default 0.5) */
|
|
28
|
+
priority?: number;
|
|
29
|
+
/** Images for this URL */
|
|
30
|
+
images?: SitemapImage[];
|
|
31
|
+
/** Videos for this URL */
|
|
32
|
+
videos?: SitemapVideo[];
|
|
33
|
+
/** News article info */
|
|
34
|
+
news?: SitemapNews;
|
|
35
|
+
/** Alternate language versions */
|
|
36
|
+
alternates?: SitemapAlternate[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Sitemap image
|
|
40
|
+
*/
|
|
41
|
+
interface SitemapImage {
|
|
42
|
+
/** Image URL */
|
|
43
|
+
loc: string;
|
|
44
|
+
/** Image caption */
|
|
45
|
+
caption?: string;
|
|
46
|
+
/** Image title */
|
|
47
|
+
title?: string;
|
|
48
|
+
/** Geographic location */
|
|
49
|
+
geoLocation?: string;
|
|
50
|
+
/** License URL */
|
|
51
|
+
license?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sitemap video
|
|
55
|
+
*/
|
|
56
|
+
interface SitemapVideo {
|
|
57
|
+
/** Thumbnail URL */
|
|
58
|
+
thumbnailLoc: string;
|
|
59
|
+
/** Video title */
|
|
60
|
+
title: string;
|
|
61
|
+
/** Video description */
|
|
62
|
+
description: string;
|
|
63
|
+
/** Content location (URL) */
|
|
64
|
+
contentLoc?: string;
|
|
65
|
+
/** Player location (embed URL) */
|
|
66
|
+
playerLoc?: string;
|
|
67
|
+
/** Duration in seconds */
|
|
68
|
+
duration?: number;
|
|
69
|
+
/** Expiration date */
|
|
70
|
+
expirationDate?: string;
|
|
71
|
+
/** Rating (0.0 to 5.0) */
|
|
72
|
+
rating?: number;
|
|
73
|
+
/** View count */
|
|
74
|
+
viewCount?: number;
|
|
75
|
+
/** Publication date */
|
|
76
|
+
publicationDate?: string;
|
|
77
|
+
/** Family friendly */
|
|
78
|
+
familyFriendly?: boolean;
|
|
79
|
+
/** Restriction (allow/deny countries) */
|
|
80
|
+
restriction?: {
|
|
81
|
+
relationship: 'allow' | 'deny';
|
|
82
|
+
countries: string[];
|
|
83
|
+
};
|
|
84
|
+
/** Platform restrictions */
|
|
85
|
+
platform?: {
|
|
86
|
+
relationship: 'allow' | 'deny';
|
|
87
|
+
platforms: ('web' | 'mobile' | 'tv')[];
|
|
88
|
+
};
|
|
89
|
+
/** Requires subscription */
|
|
90
|
+
requiresSubscription?: boolean;
|
|
91
|
+
/** Uploader name */
|
|
92
|
+
uploader?: string;
|
|
93
|
+
/** Live stream */
|
|
94
|
+
live?: boolean;
|
|
95
|
+
/** Tags */
|
|
96
|
+
tags?: string[];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Sitemap news
|
|
100
|
+
*/
|
|
101
|
+
interface SitemapNews {
|
|
102
|
+
/** Publication name */
|
|
103
|
+
publicationName: string;
|
|
104
|
+
/** Publication language */
|
|
105
|
+
publicationLanguage: string;
|
|
106
|
+
/** Publication date */
|
|
107
|
+
publicationDate: string;
|
|
108
|
+
/** Article title */
|
|
109
|
+
title: string;
|
|
110
|
+
/** Keywords */
|
|
111
|
+
keywords?: string[];
|
|
112
|
+
/** Stock tickers */
|
|
113
|
+
stockTickers?: string[];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Sitemap alternate (hreflang)
|
|
117
|
+
*/
|
|
118
|
+
interface SitemapAlternate {
|
|
119
|
+
/** Language/region code */
|
|
120
|
+
hreflang: string;
|
|
121
|
+
/** URL for this language */
|
|
122
|
+
href: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Sitemap configuration
|
|
126
|
+
*/
|
|
127
|
+
interface SitemapConfig {
|
|
128
|
+
/** Base URL for all entries */
|
|
129
|
+
baseUrl: string;
|
|
130
|
+
/** Pretty print XML */
|
|
131
|
+
pretty?: boolean;
|
|
132
|
+
/** Maximum URLs per sitemap (default 50000) */
|
|
133
|
+
maxUrls?: number;
|
|
134
|
+
/** Default change frequency */
|
|
135
|
+
defaultChangefreq?: ChangeFrequency;
|
|
136
|
+
/** Default priority */
|
|
137
|
+
defaultPriority?: number;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Sitemap index entry
|
|
141
|
+
*/
|
|
142
|
+
interface SitemapIndexEntry {
|
|
143
|
+
/** Sitemap URL */
|
|
144
|
+
loc: string;
|
|
145
|
+
/** Last modification */
|
|
146
|
+
lastmod?: string | Date;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Sitemap generator
|
|
150
|
+
*/
|
|
151
|
+
declare class Sitemap {
|
|
152
|
+
private urls;
|
|
153
|
+
private config;
|
|
154
|
+
constructor(config: SitemapConfig);
|
|
155
|
+
/**
|
|
156
|
+
* Add a URL to the sitemap
|
|
157
|
+
*/
|
|
158
|
+
add(url: string | SitemapUrl): this;
|
|
159
|
+
/**
|
|
160
|
+
* Add multiple URLs
|
|
161
|
+
*/
|
|
162
|
+
addAll(urls: (string | SitemapUrl)[]): this;
|
|
163
|
+
/**
|
|
164
|
+
* Get all URLs
|
|
165
|
+
*/
|
|
166
|
+
getUrls(): SitemapUrl[];
|
|
167
|
+
/**
|
|
168
|
+
* Get URL count
|
|
169
|
+
*/
|
|
170
|
+
get count(): number;
|
|
171
|
+
/**
|
|
172
|
+
* Check if sitemap needs to be split
|
|
173
|
+
*/
|
|
174
|
+
needsSplit(): boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Generate sitemap XML
|
|
177
|
+
*/
|
|
178
|
+
generate(): string;
|
|
179
|
+
/**
|
|
180
|
+
* Render a single URL entry
|
|
181
|
+
*/
|
|
182
|
+
private renderUrl;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Sitemap index generator for large sites
|
|
186
|
+
*/
|
|
187
|
+
declare class SitemapIndex {
|
|
188
|
+
private sitemaps;
|
|
189
|
+
private pretty;
|
|
190
|
+
constructor(options?: {
|
|
191
|
+
pretty?: boolean;
|
|
192
|
+
});
|
|
193
|
+
/**
|
|
194
|
+
* Add a sitemap to the index
|
|
195
|
+
*/
|
|
196
|
+
add(sitemap: string | SitemapIndexEntry): this;
|
|
197
|
+
/**
|
|
198
|
+
* Add multiple sitemaps
|
|
199
|
+
*/
|
|
200
|
+
addAll(sitemaps: (string | SitemapIndexEntry)[]): this;
|
|
201
|
+
/**
|
|
202
|
+
* Generate sitemap index XML
|
|
203
|
+
*/
|
|
204
|
+
generate(): string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Create a new sitemap
|
|
208
|
+
*/
|
|
209
|
+
declare function createSitemap(config: SitemapConfig): Sitemap;
|
|
210
|
+
/**
|
|
211
|
+
* Create a new sitemap index
|
|
212
|
+
*/
|
|
213
|
+
declare function createSitemapIndex(options?: {
|
|
214
|
+
pretty?: boolean;
|
|
215
|
+
}): SitemapIndex;
|
|
216
|
+
/**
|
|
217
|
+
* Split URLs into multiple sitemaps
|
|
218
|
+
*/
|
|
219
|
+
declare function splitSitemap(config: SitemapConfig, urls: (string | SitemapUrl)[]): {
|
|
220
|
+
sitemaps: Sitemap[];
|
|
221
|
+
index: SitemapIndex;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export { type ChangeFrequency, Sitemap, type SitemapAlternate, type SitemapConfig, type SitemapImage, SitemapIndex, type SitemapIndexEntry, type SitemapNews, type SitemapUrl, type SitemapVideo, createSitemap, createSitemapIndex, splitSitemap };
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// src/sitemap/index.ts
|
|
2
|
+
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>';
|
|
3
|
+
var SITEMAP_NS = "http://www.sitemaps.org/schemas/sitemap/0.9";
|
|
4
|
+
var IMAGE_NS = "http://www.google.com/schemas/sitemap-image/1.1";
|
|
5
|
+
var VIDEO_NS = "http://www.google.com/schemas/sitemap-video/1.1";
|
|
6
|
+
var NEWS_NS = "http://www.google.com/schemas/sitemap-news/0.9";
|
|
7
|
+
var XHTML_NS = "http://www.w3.org/1999/xhtml";
|
|
8
|
+
var MAX_URLS_DEFAULT = 5e4;
|
|
9
|
+
function escapeXml(str) {
|
|
10
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
11
|
+
}
|
|
12
|
+
function formatDate(date) {
|
|
13
|
+
if (typeof date === "string") {
|
|
14
|
+
return date;
|
|
15
|
+
}
|
|
16
|
+
return date.toISOString();
|
|
17
|
+
}
|
|
18
|
+
function normalizeUrl(url, baseUrl) {
|
|
19
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
20
|
+
return url;
|
|
21
|
+
}
|
|
22
|
+
const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
23
|
+
const path = url.startsWith("/") ? url : "/" + url;
|
|
24
|
+
return base + path;
|
|
25
|
+
}
|
|
26
|
+
var Sitemap = class {
|
|
27
|
+
urls = [];
|
|
28
|
+
config;
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this.config = {
|
|
31
|
+
baseUrl: config.baseUrl,
|
|
32
|
+
pretty: config.pretty ?? false,
|
|
33
|
+
maxUrls: config.maxUrls ?? MAX_URLS_DEFAULT,
|
|
34
|
+
defaultChangefreq: config.defaultChangefreq ?? "weekly",
|
|
35
|
+
defaultPriority: config.defaultPriority ?? 0.5
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Add a URL to the sitemap
|
|
40
|
+
*/
|
|
41
|
+
add(url) {
|
|
42
|
+
if (typeof url === "string") {
|
|
43
|
+
this.urls.push({
|
|
44
|
+
loc: normalizeUrl(url, this.config.baseUrl),
|
|
45
|
+
changefreq: this.config.defaultChangefreq,
|
|
46
|
+
priority: this.config.defaultPriority
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
this.urls.push({
|
|
50
|
+
...url,
|
|
51
|
+
loc: normalizeUrl(url.loc, this.config.baseUrl),
|
|
52
|
+
changefreq: url.changefreq ?? this.config.defaultChangefreq,
|
|
53
|
+
priority: url.priority ?? this.config.defaultPriority
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Add multiple URLs
|
|
60
|
+
*/
|
|
61
|
+
addAll(urls) {
|
|
62
|
+
for (const url of urls) {
|
|
63
|
+
this.add(url);
|
|
64
|
+
}
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get all URLs
|
|
69
|
+
*/
|
|
70
|
+
getUrls() {
|
|
71
|
+
return [...this.urls];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get URL count
|
|
75
|
+
*/
|
|
76
|
+
get count() {
|
|
77
|
+
return this.urls.length;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if sitemap needs to be split
|
|
81
|
+
*/
|
|
82
|
+
needsSplit() {
|
|
83
|
+
return this.urls.length > this.config.maxUrls;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generate sitemap XML
|
|
87
|
+
*/
|
|
88
|
+
generate() {
|
|
89
|
+
const newline = this.config.pretty ? "\n" : "";
|
|
90
|
+
const indent = this.config.pretty ? " " : "";
|
|
91
|
+
const hasImages = this.urls.some((u) => u.images && u.images.length > 0);
|
|
92
|
+
const hasVideos = this.urls.some((u) => u.videos && u.videos.length > 0);
|
|
93
|
+
const hasNews = this.urls.some((u) => u.news);
|
|
94
|
+
const hasAlternates = this.urls.some((u) => u.alternates && u.alternates.length > 0);
|
|
95
|
+
const namespaces = [`xmlns="${SITEMAP_NS}"`];
|
|
96
|
+
if (hasImages) namespaces.push(`xmlns:image="${IMAGE_NS}"`);
|
|
97
|
+
if (hasVideos) namespaces.push(`xmlns:video="${VIDEO_NS}"`);
|
|
98
|
+
if (hasNews) namespaces.push(`xmlns:news="${NEWS_NS}"`);
|
|
99
|
+
if (hasAlternates) namespaces.push(`xmlns:xhtml="${XHTML_NS}"`);
|
|
100
|
+
const lines = [
|
|
101
|
+
XML_HEADER,
|
|
102
|
+
`<urlset ${namespaces.join(" ")}>`
|
|
103
|
+
];
|
|
104
|
+
for (const url of this.urls) {
|
|
105
|
+
lines.push(this.renderUrl(url, indent, newline));
|
|
106
|
+
}
|
|
107
|
+
lines.push("</urlset>");
|
|
108
|
+
return lines.join(newline);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Render a single URL entry
|
|
112
|
+
*/
|
|
113
|
+
renderUrl(url, indent, newline) {
|
|
114
|
+
const lines = [`${indent}<url>`];
|
|
115
|
+
lines.push(`${indent}${indent}<loc>${escapeXml(url.loc)}</loc>`);
|
|
116
|
+
if (url.lastmod) {
|
|
117
|
+
lines.push(`${indent}${indent}<lastmod>${formatDate(url.lastmod)}</lastmod>`);
|
|
118
|
+
}
|
|
119
|
+
if (url.changefreq) {
|
|
120
|
+
lines.push(`${indent}${indent}<changefreq>${url.changefreq}</changefreq>`);
|
|
121
|
+
}
|
|
122
|
+
if (url.priority !== void 0) {
|
|
123
|
+
lines.push(`${indent}${indent}<priority>${url.priority.toFixed(1)}</priority>`);
|
|
124
|
+
}
|
|
125
|
+
if (url.alternates) {
|
|
126
|
+
for (const alt of url.alternates) {
|
|
127
|
+
lines.push(
|
|
128
|
+
`${indent}${indent}<xhtml:link rel="alternate" hreflang="${escapeXml(alt.hreflang)}" href="${escapeXml(alt.href)}" />`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (url.images) {
|
|
133
|
+
for (const image of url.images) {
|
|
134
|
+
lines.push(`${indent}${indent}<image:image>`);
|
|
135
|
+
lines.push(`${indent}${indent}${indent}<image:loc>${escapeXml(image.loc)}</image:loc>`);
|
|
136
|
+
if (image.caption) {
|
|
137
|
+
lines.push(`${indent}${indent}${indent}<image:caption>${escapeXml(image.caption)}</image:caption>`);
|
|
138
|
+
}
|
|
139
|
+
if (image.title) {
|
|
140
|
+
lines.push(`${indent}${indent}${indent}<image:title>${escapeXml(image.title)}</image:title>`);
|
|
141
|
+
}
|
|
142
|
+
if (image.geoLocation) {
|
|
143
|
+
lines.push(`${indent}${indent}${indent}<image:geo_location>${escapeXml(image.geoLocation)}</image:geo_location>`);
|
|
144
|
+
}
|
|
145
|
+
if (image.license) {
|
|
146
|
+
lines.push(`${indent}${indent}${indent}<image:license>${escapeXml(image.license)}</image:license>`);
|
|
147
|
+
}
|
|
148
|
+
lines.push(`${indent}${indent}</image:image>`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (url.news) {
|
|
152
|
+
lines.push(`${indent}${indent}<news:news>`);
|
|
153
|
+
lines.push(`${indent}${indent}${indent}<news:publication>`);
|
|
154
|
+
lines.push(`${indent}${indent}${indent}${indent}<news:name>${escapeXml(url.news.publicationName)}</news:name>`);
|
|
155
|
+
lines.push(`${indent}${indent}${indent}${indent}<news:language>${url.news.publicationLanguage}</news:language>`);
|
|
156
|
+
lines.push(`${indent}${indent}${indent}</news:publication>`);
|
|
157
|
+
lines.push(`${indent}${indent}${indent}<news:publication_date>${url.news.publicationDate}</news:publication_date>`);
|
|
158
|
+
lines.push(`${indent}${indent}${indent}<news:title>${escapeXml(url.news.title)}</news:title>`);
|
|
159
|
+
if (url.news.keywords) {
|
|
160
|
+
lines.push(`${indent}${indent}${indent}<news:keywords>${escapeXml(url.news.keywords.join(", "))}</news:keywords>`);
|
|
161
|
+
}
|
|
162
|
+
lines.push(`${indent}${indent}</news:news>`);
|
|
163
|
+
}
|
|
164
|
+
lines.push(`${indent}</url>`);
|
|
165
|
+
return lines.join(newline);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
var SitemapIndex = class {
|
|
169
|
+
sitemaps = [];
|
|
170
|
+
pretty;
|
|
171
|
+
constructor(options) {
|
|
172
|
+
this.pretty = options?.pretty ?? false;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Add a sitemap to the index
|
|
176
|
+
*/
|
|
177
|
+
add(sitemap) {
|
|
178
|
+
if (typeof sitemap === "string") {
|
|
179
|
+
this.sitemaps.push({ loc: sitemap });
|
|
180
|
+
} else {
|
|
181
|
+
this.sitemaps.push(sitemap);
|
|
182
|
+
}
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Add multiple sitemaps
|
|
187
|
+
*/
|
|
188
|
+
addAll(sitemaps) {
|
|
189
|
+
for (const sitemap of sitemaps) {
|
|
190
|
+
this.add(sitemap);
|
|
191
|
+
}
|
|
192
|
+
return this;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Generate sitemap index XML
|
|
196
|
+
*/
|
|
197
|
+
generate() {
|
|
198
|
+
const newline = this.pretty ? "\n" : "";
|
|
199
|
+
const indent = this.pretty ? " " : "";
|
|
200
|
+
const lines = [
|
|
201
|
+
XML_HEADER,
|
|
202
|
+
`<sitemapindex xmlns="${SITEMAP_NS}">`
|
|
203
|
+
];
|
|
204
|
+
for (const sitemap of this.sitemaps) {
|
|
205
|
+
lines.push(`${indent}<sitemap>`);
|
|
206
|
+
lines.push(`${indent}${indent}<loc>${escapeXml(sitemap.loc)}</loc>`);
|
|
207
|
+
if (sitemap.lastmod) {
|
|
208
|
+
lines.push(`${indent}${indent}<lastmod>${formatDate(sitemap.lastmod)}</lastmod>`);
|
|
209
|
+
}
|
|
210
|
+
lines.push(`${indent}</sitemap>`);
|
|
211
|
+
}
|
|
212
|
+
lines.push("</sitemapindex>");
|
|
213
|
+
return lines.join(newline);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
function createSitemap(config) {
|
|
217
|
+
return new Sitemap(config);
|
|
218
|
+
}
|
|
219
|
+
function createSitemapIndex(options) {
|
|
220
|
+
return new SitemapIndex(options);
|
|
221
|
+
}
|
|
222
|
+
function splitSitemap(config, urls) {
|
|
223
|
+
const maxUrls = config.maxUrls ?? MAX_URLS_DEFAULT;
|
|
224
|
+
const sitemaps = [];
|
|
225
|
+
const index = new SitemapIndex({ pretty: config.pretty });
|
|
226
|
+
for (let i = 0; i < urls.length; i += maxUrls) {
|
|
227
|
+
const chunk = urls.slice(i, i + maxUrls);
|
|
228
|
+
const sitemap = new Sitemap(config);
|
|
229
|
+
sitemap.addAll(chunk);
|
|
230
|
+
sitemaps.push(sitemap);
|
|
231
|
+
const sitemapIndex = Math.floor(i / maxUrls) + 1;
|
|
232
|
+
index.add({
|
|
233
|
+
loc: `${config.baseUrl}/sitemap-${sitemapIndex}.xml`,
|
|
234
|
+
lastmod: /* @__PURE__ */ new Date()
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
return { sitemaps, index };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export { Sitemap, SitemapIndex, createSitemap, createSitemapIndex, splitSitemap };
|
|
241
|
+
//# sourceMappingURL=index.js.map
|
|
242
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/sitemap/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @flightdev/seo - Sitemap Generator\r\n *\r\n * Generate XML sitemaps for search engine indexing.\r\n * Supports standard sitemaps and sitemap indexes for large sites.\r\n *\r\n * Features:\r\n * - Streaming output for memory efficiency\r\n * - Automatic sitemap splitting (50,000 URLs per file)\r\n * - Image and video sitemaps\r\n * - News sitemaps\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Change frequency for URLs\r\n */\r\nexport type ChangeFrequency = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';\r\n\r\n/**\r\n * Sitemap URL entry\r\n */\r\nexport interface SitemapUrl {\r\n /** URL location (required) */\r\n loc: string;\r\n /** Last modification date (ISO 8601) */\r\n lastmod?: string | Date;\r\n /** Change frequency hint */\r\n changefreq?: ChangeFrequency;\r\n /** Priority (0.0 to 1.0, default 0.5) */\r\n priority?: number;\r\n /** Images for this URL */\r\n images?: SitemapImage[];\r\n /** Videos for this URL */\r\n videos?: SitemapVideo[];\r\n /** News article info */\r\n news?: SitemapNews;\r\n /** Alternate language versions */\r\n alternates?: SitemapAlternate[];\r\n}\r\n\r\n/**\r\n * Sitemap image\r\n */\r\nexport interface SitemapImage {\r\n /** Image URL */\r\n loc: string;\r\n /** Image caption */\r\n caption?: string;\r\n /** Image title */\r\n title?: string;\r\n /** Geographic location */\r\n geoLocation?: string;\r\n /** License URL */\r\n license?: string;\r\n}\r\n\r\n/**\r\n * Sitemap video\r\n */\r\nexport interface SitemapVideo {\r\n /** Thumbnail URL */\r\n thumbnailLoc: string;\r\n /** Video title */\r\n title: string;\r\n /** Video description */\r\n description: string;\r\n /** Content location (URL) */\r\n contentLoc?: string;\r\n /** Player location (embed URL) */\r\n playerLoc?: string;\r\n /** Duration in seconds */\r\n duration?: number;\r\n /** Expiration date */\r\n expirationDate?: string;\r\n /** Rating (0.0 to 5.0) */\r\n rating?: number;\r\n /** View count */\r\n viewCount?: number;\r\n /** Publication date */\r\n publicationDate?: string;\r\n /** Family friendly */\r\n familyFriendly?: boolean;\r\n /** Restriction (allow/deny countries) */\r\n restriction?: { relationship: 'allow' | 'deny'; countries: string[] };\r\n /** Platform restrictions */\r\n platform?: { relationship: 'allow' | 'deny'; platforms: ('web' | 'mobile' | 'tv')[] };\r\n /** Requires subscription */\r\n requiresSubscription?: boolean;\r\n /** Uploader name */\r\n uploader?: string;\r\n /** Live stream */\r\n live?: boolean;\r\n /** Tags */\r\n tags?: string[];\r\n}\r\n\r\n/**\r\n * Sitemap news\r\n */\r\nexport interface SitemapNews {\r\n /** Publication name */\r\n publicationName: string;\r\n /** Publication language */\r\n publicationLanguage: string;\r\n /** Publication date */\r\n publicationDate: string;\r\n /** Article title */\r\n title: string;\r\n /** Keywords */\r\n keywords?: string[];\r\n /** Stock tickers */\r\n stockTickers?: string[];\r\n}\r\n\r\n/**\r\n * Sitemap alternate (hreflang)\r\n */\r\nexport interface SitemapAlternate {\r\n /** Language/region code */\r\n hreflang: string;\r\n /** URL for this language */\r\n href: string;\r\n}\r\n\r\n/**\r\n * Sitemap configuration\r\n */\r\nexport interface SitemapConfig {\r\n /** Base URL for all entries */\r\n baseUrl: string;\r\n /** Pretty print XML */\r\n pretty?: boolean;\r\n /** Maximum URLs per sitemap (default 50000) */\r\n maxUrls?: number;\r\n /** Default change frequency */\r\n defaultChangefreq?: ChangeFrequency;\r\n /** Default priority */\r\n defaultPriority?: number;\r\n}\r\n\r\n/**\r\n * Sitemap index entry\r\n */\r\nexport interface SitemapIndexEntry {\r\n /** Sitemap URL */\r\n loc: string;\r\n /** Last modification */\r\n lastmod?: string | Date;\r\n}\r\n\r\n// ============================================================================\r\n// Constants\r\n// ============================================================================\r\n\r\nconst XML_HEADER = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>';\r\nconst SITEMAP_NS = 'http://www.sitemaps.org/schemas/sitemap/0.9';\r\nconst IMAGE_NS = 'http://www.google.com/schemas/sitemap-image/1.1';\r\nconst VIDEO_NS = 'http://www.google.com/schemas/sitemap-video/1.1';\r\nconst NEWS_NS = 'http://www.google.com/schemas/sitemap-news/0.9';\r\nconst XHTML_NS = 'http://www.w3.org/1999/xhtml';\r\n\r\nconst MAX_URLS_DEFAULT = 50000;\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Escape XML special characters\r\n */\r\nfunction escapeXml(str: string): string {\r\n return str\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\n/**\r\n * Format date to ISO 8601 (W3C format)\r\n */\r\nfunction formatDate(date: string | Date): string {\r\n if (typeof date === 'string') {\r\n return date;\r\n }\r\n return date.toISOString();\r\n}\r\n\r\n/**\r\n * Normalize URL with base\r\n */\r\nfunction normalizeUrl(url: string, baseUrl: string): string {\r\n if (url.startsWith('http://') || url.startsWith('https://')) {\r\n return url;\r\n }\r\n const base = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\r\n const path = url.startsWith('/') ? url : '/' + url;\r\n return base + path;\r\n}\r\n\r\n// ============================================================================\r\n// Sitemap Class\r\n// ============================================================================\r\n\r\n/**\r\n * Sitemap generator\r\n */\r\nexport class Sitemap {\r\n private urls: SitemapUrl[] = [];\r\n private config: Required<SitemapConfig>;\r\n\r\n constructor(config: SitemapConfig) {\r\n this.config = {\r\n baseUrl: config.baseUrl,\r\n pretty: config.pretty ?? false,\r\n maxUrls: config.maxUrls ?? MAX_URLS_DEFAULT,\r\n defaultChangefreq: config.defaultChangefreq ?? 'weekly',\r\n defaultPriority: config.defaultPriority ?? 0.5,\r\n };\r\n }\r\n\r\n /**\r\n * Add a URL to the sitemap\r\n */\r\n add(url: string | SitemapUrl): this {\r\n if (typeof url === 'string') {\r\n this.urls.push({\r\n loc: normalizeUrl(url, this.config.baseUrl),\r\n changefreq: this.config.defaultChangefreq,\r\n priority: this.config.defaultPriority,\r\n });\r\n } else {\r\n this.urls.push({\r\n ...url,\r\n loc: normalizeUrl(url.loc, this.config.baseUrl),\r\n changefreq: url.changefreq ?? this.config.defaultChangefreq,\r\n priority: url.priority ?? this.config.defaultPriority,\r\n });\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Add multiple URLs\r\n */\r\n addAll(urls: (string | SitemapUrl)[]): this {\r\n for (const url of urls) {\r\n this.add(url);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Get all URLs\r\n */\r\n getUrls(): SitemapUrl[] {\r\n return [...this.urls];\r\n }\r\n\r\n /**\r\n * Get URL count\r\n */\r\n get count(): number {\r\n return this.urls.length;\r\n }\r\n\r\n /**\r\n * Check if sitemap needs to be split\r\n */\r\n needsSplit(): boolean {\r\n return this.urls.length > this.config.maxUrls;\r\n }\r\n\r\n /**\r\n * Generate sitemap XML\r\n */\r\n generate(): string {\r\n const newline = this.config.pretty ? '\\n' : '';\r\n const indent = this.config.pretty ? ' ' : '';\r\n\r\n const hasImages = this.urls.some(u => u.images && u.images.length > 0);\r\n const hasVideos = this.urls.some(u => u.videos && u.videos.length > 0);\r\n const hasNews = this.urls.some(u => u.news);\r\n const hasAlternates = this.urls.some(u => u.alternates && u.alternates.length > 0);\r\n\r\n const namespaces = [`xmlns=\"${SITEMAP_NS}\"`];\r\n if (hasImages) namespaces.push(`xmlns:image=\"${IMAGE_NS}\"`);\r\n if (hasVideos) namespaces.push(`xmlns:video=\"${VIDEO_NS}\"`);\r\n if (hasNews) namespaces.push(`xmlns:news=\"${NEWS_NS}\"`);\r\n if (hasAlternates) namespaces.push(`xmlns:xhtml=\"${XHTML_NS}\"`);\r\n\r\n const lines: string[] = [\r\n XML_HEADER,\r\n `<urlset ${namespaces.join(' ')}>`,\r\n ];\r\n\r\n for (const url of this.urls) {\r\n lines.push(this.renderUrl(url, indent, newline));\r\n }\r\n\r\n lines.push('</urlset>');\r\n\r\n return lines.join(newline);\r\n }\r\n\r\n /**\r\n * Render a single URL entry\r\n */\r\n private renderUrl(url: SitemapUrl, indent: string, newline: string): string {\r\n const lines: string[] = [`${indent}<url>`];\r\n\r\n lines.push(`${indent}${indent}<loc>${escapeXml(url.loc)}</loc>`);\r\n\r\n if (url.lastmod) {\r\n lines.push(`${indent}${indent}<lastmod>${formatDate(url.lastmod)}</lastmod>`);\r\n }\r\n\r\n if (url.changefreq) {\r\n lines.push(`${indent}${indent}<changefreq>${url.changefreq}</changefreq>`);\r\n }\r\n\r\n if (url.priority !== undefined) {\r\n lines.push(`${indent}${indent}<priority>${url.priority.toFixed(1)}</priority>`);\r\n }\r\n\r\n // Alternates (hreflang)\r\n if (url.alternates) {\r\n for (const alt of url.alternates) {\r\n lines.push(\r\n `${indent}${indent}<xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(alt.hreflang)}\" href=\"${escapeXml(alt.href)}\" />`\r\n );\r\n }\r\n }\r\n\r\n // Images\r\n if (url.images) {\r\n for (const image of url.images) {\r\n lines.push(`${indent}${indent}<image:image>`);\r\n lines.push(`${indent}${indent}${indent}<image:loc>${escapeXml(image.loc)}</image:loc>`);\r\n if (image.caption) {\r\n lines.push(`${indent}${indent}${indent}<image:caption>${escapeXml(image.caption)}</image:caption>`);\r\n }\r\n if (image.title) {\r\n lines.push(`${indent}${indent}${indent}<image:title>${escapeXml(image.title)}</image:title>`);\r\n }\r\n if (image.geoLocation) {\r\n lines.push(`${indent}${indent}${indent}<image:geo_location>${escapeXml(image.geoLocation)}</image:geo_location>`);\r\n }\r\n if (image.license) {\r\n lines.push(`${indent}${indent}${indent}<image:license>${escapeXml(image.license)}</image:license>`);\r\n }\r\n lines.push(`${indent}${indent}</image:image>`);\r\n }\r\n }\r\n\r\n // News\r\n if (url.news) {\r\n lines.push(`${indent}${indent}<news:news>`);\r\n lines.push(`${indent}${indent}${indent}<news:publication>`);\r\n lines.push(`${indent}${indent}${indent}${indent}<news:name>${escapeXml(url.news.publicationName)}</news:name>`);\r\n lines.push(`${indent}${indent}${indent}${indent}<news:language>${url.news.publicationLanguage}</news:language>`);\r\n lines.push(`${indent}${indent}${indent}</news:publication>`);\r\n lines.push(`${indent}${indent}${indent}<news:publication_date>${url.news.publicationDate}</news:publication_date>`);\r\n lines.push(`${indent}${indent}${indent}<news:title>${escapeXml(url.news.title)}</news:title>`);\r\n if (url.news.keywords) {\r\n lines.push(`${indent}${indent}${indent}<news:keywords>${escapeXml(url.news.keywords.join(', '))}</news:keywords>`);\r\n }\r\n lines.push(`${indent}${indent}</news:news>`);\r\n }\r\n\r\n lines.push(`${indent}</url>`);\r\n\r\n return lines.join(newline);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Sitemap Index\r\n// ============================================================================\r\n\r\n/**\r\n * Sitemap index generator for large sites\r\n */\r\nexport class SitemapIndex {\r\n private sitemaps: SitemapIndexEntry[] = [];\r\n private pretty: boolean;\r\n\r\n constructor(options?: { pretty?: boolean }) {\r\n this.pretty = options?.pretty ?? false;\r\n }\r\n\r\n /**\r\n * Add a sitemap to the index\r\n */\r\n add(sitemap: string | SitemapIndexEntry): this {\r\n if (typeof sitemap === 'string') {\r\n this.sitemaps.push({ loc: sitemap });\r\n } else {\r\n this.sitemaps.push(sitemap);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Add multiple sitemaps\r\n */\r\n addAll(sitemaps: (string | SitemapIndexEntry)[]): this {\r\n for (const sitemap of sitemaps) {\r\n this.add(sitemap);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Generate sitemap index XML\r\n */\r\n generate(): string {\r\n const newline = this.pretty ? '\\n' : '';\r\n const indent = this.pretty ? ' ' : '';\r\n\r\n const lines: string[] = [\r\n XML_HEADER,\r\n `<sitemapindex xmlns=\"${SITEMAP_NS}\">`,\r\n ];\r\n\r\n for (const sitemap of this.sitemaps) {\r\n lines.push(`${indent}<sitemap>`);\r\n lines.push(`${indent}${indent}<loc>${escapeXml(sitemap.loc)}</loc>`);\r\n if (sitemap.lastmod) {\r\n lines.push(`${indent}${indent}<lastmod>${formatDate(sitemap.lastmod)}</lastmod>`);\r\n }\r\n lines.push(`${indent}</sitemap>`);\r\n }\r\n\r\n lines.push('</sitemapindex>');\r\n\r\n return lines.join(newline);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Factory Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Create a new sitemap\r\n */\r\nexport function createSitemap(config: SitemapConfig): Sitemap {\r\n return new Sitemap(config);\r\n}\r\n\r\n/**\r\n * Create a new sitemap index\r\n */\r\nexport function createSitemapIndex(options?: { pretty?: boolean }): SitemapIndex {\r\n return new SitemapIndex(options);\r\n}\r\n\r\n/**\r\n * Split URLs into multiple sitemaps\r\n */\r\nexport function splitSitemap(\r\n config: SitemapConfig,\r\n urls: (string | SitemapUrl)[]\r\n): { sitemaps: Sitemap[]; index: SitemapIndex } {\r\n const maxUrls = config.maxUrls ?? MAX_URLS_DEFAULT;\r\n const sitemaps: Sitemap[] = [];\r\n const index = new SitemapIndex({ pretty: config.pretty });\r\n\r\n for (let i = 0; i < urls.length; i += maxUrls) {\r\n const chunk = urls.slice(i, i + maxUrls);\r\n const sitemap = new Sitemap(config);\r\n sitemap.addAll(chunk);\r\n sitemaps.push(sitemap);\r\n\r\n const sitemapIndex = Math.floor(i / maxUrls) + 1;\r\n index.add({\r\n loc: `${config.baseUrl}/sitemap-${sitemapIndex}.xml`,\r\n lastmod: new Date(),\r\n });\r\n }\r\n\r\n return { sitemaps, index };\r\n}\r\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { M as Metadata } from '../types-BBIMJIqz.js';
|
|
2
|
+
export { O as OpenGraphMeta, T as TwitterCardMeta } from '../types-BBIMJIqz.js';
|
|
3
|
+
import { JsonLdSchema } from '../json-ld/index.js';
|
|
4
|
+
export { createJsonLd, createJsonLdGraph } from '../json-ld/index.js';
|
|
5
|
+
export { createSEO, defineMeta, mergeMetadata } from '../index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @flightdev/seo/solid
|
|
9
|
+
*
|
|
10
|
+
* Solid primitives for SEO management.
|
|
11
|
+
* SSR-first with fine-grained reactivity.
|
|
12
|
+
*
|
|
13
|
+
* Note: This module exports primitive functions.
|
|
14
|
+
* JSX components should be created in userland using these primitives.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* import { createSEOSignal, updateDocumentHead } from '@flightdev/seo/solid';
|
|
19
|
+
* import { createEffect } from 'solid-js';
|
|
20
|
+
*
|
|
21
|
+
* function useSEO(metadata) {
|
|
22
|
+
* createEffect(() => {
|
|
23
|
+
* updateDocumentHead(metadata);
|
|
24
|
+
* });
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Render metadata to HTML string for SSR
|
|
31
|
+
*/
|
|
32
|
+
declare function renderMetadataToString(metadata: Metadata): string;
|
|
33
|
+
/**
|
|
34
|
+
* Create JSON-LD script HTML string
|
|
35
|
+
*/
|
|
36
|
+
declare function renderJsonLdToString<T extends JsonLdSchema>(schema: T, id?: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Update document head with metadata (client-side)
|
|
39
|
+
*/
|
|
40
|
+
declare function updateDocumentHead(metadata: Metadata): void;
|
|
41
|
+
/**
|
|
42
|
+
* Update JSON-LD script element (client-side)
|
|
43
|
+
*/
|
|
44
|
+
declare function updateJsonLd<T extends JsonLdSchema>(schema: T, id?: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Remove JSON-LD script element (client-side cleanup)
|
|
47
|
+
*/
|
|
48
|
+
declare function removeJsonLd(id?: string): void;
|
|
49
|
+
|
|
50
|
+
export { JsonLdSchema, Metadata, removeJsonLd, renderJsonLdToString, renderMetadataToString, updateDocumentHead, updateJsonLd };
|