@pas7/llm-seo 0.1.6

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.
@@ -0,0 +1,673 @@
1
+ import { existsSync } from 'fs';
2
+ import { readFile, readdir } from 'fs/promises';
3
+ import { join } from 'path';
4
+
5
+ // src/adapters/next/manifest.ts
6
+ function fromNextContentManifest(manifest, options = {}) {
7
+ const { slugPrefix = "", defaultLocale } = options;
8
+ return manifest.items.map((item) => {
9
+ const result = {
10
+ slug: slugPrefix + item.slug
11
+ };
12
+ if (item.locales !== void 0) {
13
+ result.locales = item.locales;
14
+ } else if (defaultLocale !== void 0) {
15
+ result.locales = [defaultLocale];
16
+ }
17
+ if (item.publishedAt !== void 0) {
18
+ result.publishedAt = item.publishedAt;
19
+ }
20
+ if (item.updatedAt !== void 0) {
21
+ result.updatedAt = item.updatedAt;
22
+ }
23
+ if (item.title !== void 0) {
24
+ result.title = item.title;
25
+ }
26
+ if (item.description !== void 0) {
27
+ result.description = item.description;
28
+ }
29
+ if (item.priority !== void 0) {
30
+ result.priority = item.priority;
31
+ }
32
+ if (item.canonicalOverride !== void 0) {
33
+ result.canonicalOverride = item.canonicalOverride;
34
+ }
35
+ return result;
36
+ });
37
+ }
38
+ function parseFrontmatter(content) {
39
+ const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
40
+ const match = content.match(frontmatterRegex);
41
+ if (!match) {
42
+ return { frontmatter: {}, body: content };
43
+ }
44
+ const frontmatterText = match[1] ?? "";
45
+ const body = match[2] ?? content;
46
+ const frontmatter = {};
47
+ const lines = frontmatterText.split("\n");
48
+ for (const line of lines) {
49
+ const colonIndex = line.indexOf(":");
50
+ if (colonIndex === -1) continue;
51
+ const key = line.slice(0, colonIndex).trim();
52
+ let value = line.slice(colonIndex + 1).trim();
53
+ if (value.startsWith("[") && value.endsWith("]")) {
54
+ value = value.slice(1, -1).split(",").map((item) => item.trim().replace(/^['"]|['"]$/g, "")).filter((item) => item.length > 0);
55
+ } else {
56
+ value = value.replace(/^['"]|['"]$/g, "");
57
+ }
58
+ if (key === "title") frontmatter.title = value;
59
+ else if (key === "description") frontmatter.description = value;
60
+ else if (key === "date" || key === "publishedAt") frontmatter.date = value;
61
+ else if (key === "updated" || key === "updatedAt") frontmatter.updated = value;
62
+ else if (key === "locale") frontmatter.locale = value;
63
+ else if (key === "locales") frontmatter.locales = value;
64
+ else if (key === "priority") frontmatter.priority = parseInt(value, 10);
65
+ else frontmatter[key] = value;
66
+ }
67
+ return { frontmatter, body };
68
+ }
69
+ function filePathToSlug(filePath, extensions) {
70
+ let slug = filePath;
71
+ for (const ext of extensions) {
72
+ if (slug.endsWith(ext)) {
73
+ slug = slug.slice(0, -ext.length);
74
+ break;
75
+ }
76
+ }
77
+ if (slug.endsWith("/index")) {
78
+ slug = slug.slice(0, -6);
79
+ }
80
+ if (slug === "index") {
81
+ slug = "";
82
+ }
83
+ if (!slug.startsWith("/")) {
84
+ slug = "/" + slug;
85
+ }
86
+ return slug || "/";
87
+ }
88
+ async function scanDirectory(dir, extensions, basePath = "") {
89
+ const files = [];
90
+ if (!existsSync(dir)) {
91
+ return files;
92
+ }
93
+ const entries = await readdir(dir, { withFileTypes: true });
94
+ for (const entry of entries) {
95
+ const fullPath = join(dir, entry.name);
96
+ const relativePath = basePath ? join(basePath, entry.name) : entry.name;
97
+ if (entry.isDirectory()) {
98
+ const subFiles = await scanDirectory(fullPath, extensions, relativePath);
99
+ files.push(...subFiles);
100
+ } else if (entry.isFile()) {
101
+ const hasValidExtension = extensions.some((ext) => entry.name.endsWith(ext));
102
+ if (hasValidExtension) {
103
+ files.push(relativePath);
104
+ }
105
+ }
106
+ }
107
+ return files;
108
+ }
109
+ async function createManifestFromPagesDir(options) {
110
+ const {
111
+ pagesDir,
112
+ routePrefix = "",
113
+ defaultLocale,
114
+ extensions = [".mdx", ".md"]
115
+ } = options;
116
+ const files = await scanDirectory(pagesDir, extensions);
117
+ const items = [];
118
+ for (const file of files) {
119
+ const fullPath = join(pagesDir, file);
120
+ const content = await readFile(fullPath, "utf-8");
121
+ const { frontmatter } = parseFrontmatter(content);
122
+ const slug = routePrefix + filePathToSlug(file, extensions);
123
+ const item = {
124
+ slug
125
+ };
126
+ if (frontmatter.locales !== void 0) {
127
+ item.locales = frontmatter.locales;
128
+ } else if (frontmatter.locale !== void 0) {
129
+ item.locales = [frontmatter.locale];
130
+ } else if (defaultLocale !== void 0) {
131
+ item.locales = [defaultLocale];
132
+ }
133
+ if (frontmatter.date !== void 0) {
134
+ item.publishedAt = frontmatter.date;
135
+ }
136
+ if (frontmatter.updated !== void 0) {
137
+ item.updatedAt = frontmatter.updated;
138
+ }
139
+ if (frontmatter.title !== void 0) {
140
+ item.title = frontmatter.title;
141
+ }
142
+ if (frontmatter.description !== void 0) {
143
+ item.description = frontmatter.description;
144
+ }
145
+ if (frontmatter.priority !== void 0) {
146
+ item.priority = frontmatter.priority;
147
+ }
148
+ items.push(item);
149
+ }
150
+ return items.sort((a, b) => a.slug.localeCompare(b.slug));
151
+ }
152
+ function createManifestFromData(items, options = {}) {
153
+ const { slugPrefix = "", defaultLocale } = options;
154
+ return items.map((item) => {
155
+ const slugPath = Array.isArray(item.params.slug) ? "/" + item.params.slug.join("/") : item.params.slug.startsWith("/") ? item.params.slug : "/" + item.params.slug;
156
+ const result = {
157
+ slug: slugPrefix + slugPath
158
+ };
159
+ if (item.locale !== void 0) {
160
+ result.locales = [item.locale];
161
+ } else if (defaultLocale !== void 0) {
162
+ result.locales = [defaultLocale];
163
+ }
164
+ if (item.publishedAt !== void 0) {
165
+ result.publishedAt = item.publishedAt;
166
+ }
167
+ if (item.updatedAt !== void 0) {
168
+ result.updatedAt = item.updatedAt;
169
+ }
170
+ if (item.title !== void 0) {
171
+ result.title = item.title;
172
+ }
173
+ if (item.description !== void 0) {
174
+ result.description = item.description;
175
+ }
176
+ if (item.priority !== void 0) {
177
+ result.priority = item.priority;
178
+ }
179
+ return result;
180
+ });
181
+ }
182
+ function extractPagePaths(buildManifest) {
183
+ const pages = [];
184
+ for (const pagePath of Object.keys(buildManifest.pages)) {
185
+ if (pagePath.startsWith("/_")) {
186
+ continue;
187
+ }
188
+ const normalizedPath = normalizeNextPath(pagePath);
189
+ pages.push(normalizedPath);
190
+ }
191
+ return pages.sort((a, b) => a.localeCompare(b));
192
+ }
193
+ function normalizeNextPath(path) {
194
+ let normalized = path.replace(/\.(html|json)$/, "");
195
+ if (normalized === "/index" || normalized === "") {
196
+ normalized = "/";
197
+ }
198
+ if (!normalized.startsWith("/")) {
199
+ normalized = `/${normalized}`;
200
+ }
201
+ return normalized;
202
+ }
203
+ function generateNextManifest(options, buildManifest) {
204
+ const pages = [];
205
+ if (buildManifest) {
206
+ const pagePaths = extractPagePaths(buildManifest);
207
+ for (const path of pagePaths) {
208
+ pages.push({
209
+ path,
210
+ title: void 0,
211
+ // Will be filled by crawler or manually
212
+ description: void 0,
213
+ optional: false
214
+ });
215
+ }
216
+ }
217
+ return {
218
+ baseUrl: options.baseUrl,
219
+ title: options.title,
220
+ description: options.description,
221
+ pages
222
+ };
223
+ }
224
+
225
+ // src/core/normalize/sort.ts
226
+ function compareStrings(a, b) {
227
+ return a.localeCompare(b, "en", { sensitivity: "case", numeric: true });
228
+ }
229
+ function sortStrings(items) {
230
+ return [...items].sort(compareStrings);
231
+ }
232
+ function sortBy(items, keyFn) {
233
+ return [...items].sort((a, b) => compareStrings(keyFn(a), keyFn(b)));
234
+ }
235
+
236
+ // src/core/normalize/text.ts
237
+ function normalizeLineEndings(text, lineEndings) {
238
+ const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
239
+ return lineEndings === "crlf" ? normalized.replace(/\n/g, "\r\n") : normalized;
240
+ }
241
+ function normalizeLineWhitespace(text) {
242
+ const lines = text.split(/\r?\n/);
243
+ return lines.map((line) => line.trimEnd().replace(/[ \t]+/g, (match) => " ".repeat(match.length === 0 ? 0 : match.length))).map((line) => line.replace(/ +/g, " ")).join("\n");
244
+ }
245
+
246
+ // src/core/generate/llms-txt.ts
247
+ function createLlmsTxt(options) {
248
+ const { config, canonicalUrls } = options;
249
+ const lineEndings = config.format?.lineEndings ?? "lf";
250
+ const lines = [];
251
+ lines.push(`# ${config.brand.name}`);
252
+ lines.push("");
253
+ if (config.brand.tagline) {
254
+ lines.push(`> ${config.brand.tagline}`);
255
+ lines.push("");
256
+ }
257
+ if (config.brand.description) {
258
+ lines.push(config.brand.description);
259
+ lines.push("");
260
+ }
261
+ const hubs = config.sections?.hubs ?? [];
262
+ if (hubs.length > 0) {
263
+ lines.push("## Sections");
264
+ lines.push("");
265
+ const sortedHubs = sortStrings(hubs);
266
+ for (const hub of sortedHubs) {
267
+ const hubLabel = getHubLabel(hub);
268
+ lines.push(`- [${hub}](${hub}) - ${hubLabel}`);
269
+ }
270
+ lines.push("");
271
+ }
272
+ if (canonicalUrls.length > 0) {
273
+ lines.push("## URLs");
274
+ lines.push("");
275
+ const sortedUrls = sortStrings(canonicalUrls);
276
+ for (const url of sortedUrls) {
277
+ lines.push(`- ${url}`);
278
+ }
279
+ lines.push("");
280
+ }
281
+ const hasPolicies = config.policy?.geoPolicy || config.policy?.citationRules || config.policy?.restrictedClaims;
282
+ if (hasPolicies) {
283
+ lines.push("## Policies");
284
+ lines.push("");
285
+ if (config.policy?.geoPolicy) {
286
+ lines.push(`- GEO: ${config.policy.geoPolicy}`);
287
+ }
288
+ if (config.policy?.citationRules) {
289
+ lines.push(`- Citations: ${config.policy.citationRules}`);
290
+ }
291
+ if (config.policy?.restrictedClaims) {
292
+ const status = config.policy.restrictedClaims.enable ? "Enabled" : "Disabled";
293
+ lines.push(`- Restricted Claims: ${status}`);
294
+ }
295
+ lines.push("");
296
+ }
297
+ const hasContact = config.contact?.email || config.contact?.social || config.contact?.phone;
298
+ const hasBooking = config.booking?.url;
299
+ if (hasContact || hasBooking) {
300
+ lines.push("## Contact");
301
+ lines.push("");
302
+ if (config.contact?.email) {
303
+ lines.push(`- Email: ${config.contact.email}`);
304
+ }
305
+ if (config.contact?.phone) {
306
+ lines.push(`- Phone: ${config.contact.phone}`);
307
+ }
308
+ if (config.contact?.social) {
309
+ if (config.contact.social.twitter) {
310
+ lines.push(`- Twitter: ${config.contact.social.twitter}`);
311
+ }
312
+ if (config.contact.social.linkedin) {
313
+ lines.push(`- LinkedIn: ${config.contact.social.linkedin}`);
314
+ }
315
+ if (config.contact.social.github) {
316
+ lines.push(`- GitHub: ${config.contact.social.github}`);
317
+ }
318
+ }
319
+ if (config.booking?.url) {
320
+ const label = config.booking.label ?? "Book consultation";
321
+ lines.push(`- Booking: ${config.booking.url} (${label})`);
322
+ }
323
+ lines.push("");
324
+ }
325
+ const hasMachineHints = config.machineHints?.robots || config.machineHints?.sitemap || config.machineHints?.llmsTxt || config.machineHints?.llmsFullTxt;
326
+ if (hasMachineHints) {
327
+ lines.push("## Machine Hints");
328
+ lines.push("");
329
+ if (config.machineHints?.robots) {
330
+ lines.push(`- robots.txt: ${config.machineHints.robots}`);
331
+ }
332
+ if (config.machineHints?.sitemap) {
333
+ lines.push(`- sitemap.xml: ${config.machineHints.sitemap}`);
334
+ }
335
+ if (config.machineHints?.llmsTxt) {
336
+ lines.push(`- llms.txt: ${config.machineHints.llmsTxt}`);
337
+ }
338
+ if (config.machineHints?.llmsFullTxt) {
339
+ lines.push(`- llms-full.txt: ${config.machineHints.llmsFullTxt}`);
340
+ }
341
+ lines.push("");
342
+ }
343
+ let content = lines.join("\n");
344
+ content = normalizeLineWhitespace(content);
345
+ content = normalizeLineEndings(content, lineEndings);
346
+ const finalLines = content.split(lineEndings === "crlf" ? "\r\n" : "\n");
347
+ return {
348
+ content,
349
+ byteSize: Buffer.byteLength(content, "utf-8"),
350
+ lineCount: finalLines.length
351
+ };
352
+ }
353
+ function getHubLabel(hub) {
354
+ const labels = {
355
+ "/services": "Services overview",
356
+ "/blog": "Blog posts",
357
+ "/projects": "Our projects",
358
+ "/cases": "Case studies",
359
+ "/contact": "Contact us",
360
+ "/about": "About us",
361
+ "/products": "Products",
362
+ "/docs": "Documentation",
363
+ "/faq": "Frequently asked questions",
364
+ "/pricing": "Pricing information",
365
+ "/team": "Our team",
366
+ "/careers": "Career opportunities",
367
+ "/news": "News and updates",
368
+ "/resources": "Resources",
369
+ "/support": "Support center"
370
+ };
371
+ return labels[hub] ?? formatHubLabel(hub);
372
+ }
373
+ function formatHubLabel(hub) {
374
+ const clean = hub.replace(/^\//, "");
375
+ return clean.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
376
+ }
377
+ function generateLlmsTxt(manifest, _options) {
378
+ const canonicalUrls = manifest.pages.map((page) => `${manifest.baseUrl}${page.path}`);
379
+ const config = {
380
+ site: { baseUrl: manifest.baseUrl },
381
+ brand: {
382
+ name: manifest.title,
383
+ locales: ["en"],
384
+ ...manifest.description && { description: manifest.description }
385
+ },
386
+ manifests: {},
387
+ output: {
388
+ paths: {
389
+ llmsTxt: "public/llms.txt",
390
+ llmsFullTxt: "public/llms-full.txt"
391
+ }
392
+ }
393
+ };
394
+ return createLlmsTxt({ config, canonicalUrls }).content;
395
+ }
396
+
397
+ // src/core/generate/llms-full-txt.ts
398
+ function createLlmsFullTxt(options) {
399
+ const { config, canonicalUrls, manifestItems } = options;
400
+ const lineEndings = config.format?.lineEndings ?? "lf";
401
+ const lines = [];
402
+ lines.push(`# ${config.brand.name} - Full LLM Context`);
403
+ lines.push("");
404
+ if (config.brand.tagline) {
405
+ lines.push(`> ${config.brand.tagline}`);
406
+ lines.push("");
407
+ }
408
+ if (config.brand.description) {
409
+ lines.push(config.brand.description);
410
+ lines.push("");
411
+ }
412
+ if (config.brand.org) {
413
+ lines.push(`Organization: ${config.brand.org}`);
414
+ }
415
+ lines.push(`Locales: ${config.brand.locales.join(", ")}`);
416
+ lines.push("");
417
+ if (canonicalUrls.length > 0) {
418
+ lines.push("## All Canonical URLs");
419
+ lines.push("");
420
+ const sortedUrls = sortStrings(canonicalUrls);
421
+ for (const url of sortedUrls) {
422
+ lines.push(`- ${url}`);
423
+ }
424
+ lines.push("");
425
+ }
426
+ const hasPolicies = config.policy?.geoPolicy || config.policy?.citationRules || config.policy?.restrictedClaims;
427
+ if (hasPolicies) {
428
+ lines.push("## Policies");
429
+ lines.push("");
430
+ if (config.policy?.geoPolicy) {
431
+ lines.push("### GEO Policy");
432
+ lines.push(config.policy.geoPolicy);
433
+ lines.push("");
434
+ }
435
+ if (config.policy?.citationRules) {
436
+ lines.push("### Citation Rules");
437
+ lines.push(config.policy.citationRules);
438
+ lines.push("");
439
+ }
440
+ if (config.policy?.restrictedClaims) {
441
+ lines.push("### Restricted Claims");
442
+ const status = config.policy.restrictedClaims.enable ? "Enabled" : "Disabled";
443
+ lines.push(`Status: ${status}`);
444
+ if (config.policy.restrictedClaims.forbidden && config.policy.restrictedClaims.forbidden.length > 0) {
445
+ lines.push(`Forbidden terms: ${config.policy.restrictedClaims.forbidden.join(", ")}`);
446
+ }
447
+ if (config.policy.restrictedClaims.whitelist && config.policy.restrictedClaims.whitelist.length > 0) {
448
+ lines.push(`Exceptions: ${config.policy.restrictedClaims.whitelist.join(", ")}`);
449
+ }
450
+ lines.push("");
451
+ }
452
+ }
453
+ const hasSocial = config.contact?.social?.twitter || config.contact?.social?.linkedin || config.contact?.social?.github;
454
+ const hasBooking = config.booking?.url;
455
+ if (hasSocial || hasBooking) {
456
+ lines.push("## Social & Booking");
457
+ lines.push("");
458
+ if (config.contact?.social?.twitter) {
459
+ lines.push(`- Twitter: ${config.contact.social.twitter}`);
460
+ }
461
+ if (config.contact?.social?.linkedin) {
462
+ lines.push(`- LinkedIn: ${config.contact.social.linkedin}`);
463
+ }
464
+ if (config.contact?.social?.github) {
465
+ lines.push(`- GitHub: ${config.contact.social.github}`);
466
+ }
467
+ if (config.booking?.url) {
468
+ const label = config.booking.label ?? "Book consultation";
469
+ lines.push(`- Booking: ${config.booking.url} (${label})`);
470
+ }
471
+ lines.push("");
472
+ }
473
+ const hasMachineHints = config.machineHints?.robots || config.machineHints?.sitemap || config.machineHints?.llmsTxt || config.machineHints?.llmsFullTxt;
474
+ if (hasMachineHints) {
475
+ lines.push("## Machine Hints");
476
+ lines.push("");
477
+ if (config.machineHints?.robots) {
478
+ lines.push(`- robots.txt: ${config.machineHints.robots}`);
479
+ }
480
+ if (config.machineHints?.sitemap) {
481
+ lines.push(`- sitemap.xml: ${config.machineHints.sitemap}`);
482
+ }
483
+ if (config.machineHints?.llmsTxt) {
484
+ lines.push(`- llms.txt: ${config.machineHints.llmsTxt}`);
485
+ }
486
+ if (config.machineHints?.llmsFullTxt) {
487
+ lines.push(`- llms-full.txt: ${config.machineHints.llmsFullTxt}`);
488
+ }
489
+ lines.push("");
490
+ }
491
+ const hubs = config.sections?.hubs ?? [];
492
+ if (hubs.length > 0 || manifestItems.length > 0) {
493
+ lines.push("## Sitemap");
494
+ lines.push("");
495
+ if (hubs.length > 0) {
496
+ const sortedHubs = sortStrings(hubs);
497
+ for (const hub of sortedHubs) {
498
+ lines.push(`- [${hub}](${hub}) - ${getHubLabel2(hub)}`);
499
+ }
500
+ }
501
+ if (manifestItems.length > 0) {
502
+ const sortedItems = sortBy(manifestItems, (item) => item.slug);
503
+ for (const item of sortedItems) {
504
+ const url = item.canonicalOverride ?? `${config.site.baseUrl}${item.slug}`;
505
+ const title = item.title ?? item.slug;
506
+ const locales = item.locales?.join(", ") ?? config.brand.locales[0] ?? "en";
507
+ lines.push(`- [${title}](${url}) (${locales})`);
508
+ }
509
+ }
510
+ lines.push("");
511
+ }
512
+ let content = lines.join("\n");
513
+ content = normalizeLineWhitespace(content);
514
+ content = normalizeLineEndings(content, lineEndings);
515
+ const finalLines = content.split(lineEndings === "crlf" ? "\r\n" : "\n");
516
+ return {
517
+ content,
518
+ byteSize: Buffer.byteLength(content, "utf-8"),
519
+ lineCount: finalLines.length
520
+ };
521
+ }
522
+ function getHubLabel2(hub) {
523
+ const labels = {
524
+ "/services": "Services overview",
525
+ "/blog": "Blog posts",
526
+ "/projects": "Our projects",
527
+ "/cases": "Case studies",
528
+ "/contact": "Contact us",
529
+ "/about": "About us",
530
+ "/products": "Products",
531
+ "/docs": "Documentation",
532
+ "/faq": "Frequently asked questions",
533
+ "/pricing": "Pricing information",
534
+ "/team": "Our team",
535
+ "/careers": "Career opportunities",
536
+ "/news": "News and updates",
537
+ "/resources": "Resources",
538
+ "/support": "Support center"
539
+ };
540
+ return labels[hub] ?? formatHubLabel2(hub);
541
+ }
542
+ function formatHubLabel2(hub) {
543
+ const clean = hub.replace(/^\//, "");
544
+ return clean.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
545
+ }
546
+ function generateLlmsFullTxt(manifest, _options) {
547
+ const canonicalUrls = manifest.pages.map((page) => `${manifest.baseUrl}${page.path}`);
548
+ const manifestItems = manifest.pages.map((page) => ({
549
+ slug: page.path,
550
+ title: page.title,
551
+ description: page.description
552
+ }));
553
+ const config = {
554
+ site: { baseUrl: manifest.baseUrl },
555
+ brand: {
556
+ name: manifest.title,
557
+ locales: ["en"],
558
+ ...manifest.description && { description: manifest.description }
559
+ },
560
+ manifests: {},
561
+ output: {
562
+ paths: {
563
+ llmsTxt: "public/llms.txt",
564
+ llmsFullTxt: "public/llms-full.txt"
565
+ }
566
+ }
567
+ };
568
+ return createLlmsFullTxt({ config, canonicalUrls, manifestItems }).content;
569
+ }
570
+
571
+ // src/adapters/next/build-hooks.ts
572
+ function generateBuildScripts(options = {}) {
573
+ const {
574
+ configPath = "llm-seo.config.ts",
575
+ emitCitations = false,
576
+ packageManager = "pnpm"
577
+ } = options;
578
+ const configFlag = `--config ${configPath}`;
579
+ const citationsFlag = emitCitations ? " --emit-citations" : "";
580
+ const runCommand = packageManager === "npm" ? "npm run" : packageManager;
581
+ return {
582
+ "build:seo": `llm-seo generate ${configFlag}${citationsFlag}`,
583
+ postbuild: `${runCommand} build:seo && llm-seo check --fail-on error`,
584
+ "check:seo": "llm-seo check --fail-on warn"
585
+ };
586
+ }
587
+ function createRobotsLlmsPolicySnippet(options) {
588
+ const {
589
+ baseUrl,
590
+ allowLlmsTxt = true,
591
+ allowLlmsFullTxt = true,
592
+ allowSitemap = true,
593
+ additionalPaths = [],
594
+ userAgent = "*"
595
+ } = options;
596
+ const lines = ["# LLM SEO"];
597
+ try {
598
+ const url = new URL(baseUrl);
599
+ lines.push(`Host: ${url.host}`);
600
+ } catch {
601
+ }
602
+ lines.push(`User-agent: ${userAgent}`);
603
+ if (allowLlmsTxt) {
604
+ lines.push("Allow: /llms.txt");
605
+ }
606
+ if (allowLlmsFullTxt) {
607
+ lines.push("Allow: /llms-full.txt");
608
+ }
609
+ if (allowSitemap) {
610
+ lines.push("Allow: /sitemap.xml");
611
+ }
612
+ for (const path of additionalPaths) {
613
+ lines.push(`Allow: ${path}`);
614
+ }
615
+ return lines.join("\n");
616
+ }
617
+ function createNextConfig(options) {
618
+ const {
619
+ locales = [],
620
+ defaultLocale = "en",
621
+ trailingSlash = false,
622
+ unoptimizedImages = true
623
+ } = options;
624
+ const config = {
625
+ output: "export",
626
+ trailingSlash,
627
+ images: {
628
+ unoptimized: unoptimizedImages
629
+ }
630
+ };
631
+ if (locales.length > 0) {
632
+ config.i18n = {
633
+ locales,
634
+ defaultLocale
635
+ };
636
+ }
637
+ return config;
638
+ }
639
+ async function postBuildHook(options) {
640
+ const { outputDir, manifest, generateFull = false } = options;
641
+ const files = [];
642
+ try {
643
+ generateLlmsTxt(manifest);
644
+ const llmsTxtPath = `${outputDir}/llms.txt`;
645
+ files.push(llmsTxtPath);
646
+ if (generateFull) {
647
+ generateLlmsFullTxt(manifest);
648
+ const llmsFullTxtPath = `${outputDir}/llms-full.txt`;
649
+ files.push(llmsFullTxtPath);
650
+ }
651
+ return {
652
+ files,
653
+ success: true
654
+ };
655
+ } catch (error) {
656
+ const message = error instanceof Error ? error.message : "Unknown error";
657
+ return {
658
+ files,
659
+ success: false,
660
+ error: message
661
+ };
662
+ }
663
+ }
664
+ function createNextPlugin() {
665
+ return {
666
+ name: "llm-seo",
667
+ postBuild: postBuildHook
668
+ };
669
+ }
670
+
671
+ export { createManifestFromData, createManifestFromPagesDir, createNextConfig, createNextPlugin, createRobotsLlmsPolicySnippet, extractPagePaths, fromNextContentManifest, generateBuildScripts, generateNextManifest, postBuildHook };
672
+ //# sourceMappingURL=index.js.map
673
+ //# sourceMappingURL=index.js.map