@lacspace/llms-txt 1.0.2 → 1.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/README.md +26 -0
- package/dist/index.cjs +43 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +41 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,6 +94,32 @@ const doc = parseLlmsTxt(existing); // { title, summary, details, sections: [{ t
|
|
|
94
94
|
| [`@lacspace/rss`](https://www.npmjs.com/package/@lacspace/rss) | RSS / Atom / JSON feeds |
|
|
95
95
|
| [`@lacspace/slugify`](https://www.npmjs.com/package/@lacspace/slugify) | SEO URL slugs |
|
|
96
96
|
|
|
97
|
+
## New in 1.2 — build from your sitemap
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { llmsTxtFromSitemap } from "@lacspace/llms-txt";
|
|
101
|
+
|
|
102
|
+
// Feed the same URL list your sitemap uses; sections + titles are derived
|
|
103
|
+
const txt = llmsTxtFromSitemap(
|
|
104
|
+
[
|
|
105
|
+
{ url: "https://x.com/", section: "Main" },
|
|
106
|
+
{ url: "https://x.com/docs/sdk", section: "Docs", title: "SDK" },
|
|
107
|
+
],
|
|
108
|
+
{ title: "Lacspace", summary: "Open-source packages & products." },
|
|
109
|
+
);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## New in 1.1 — Response helpers
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { llmsTxtResponse, llmsFullTxtResponse } from "@lacspace/llms-txt";
|
|
116
|
+
|
|
117
|
+
// app/llms.txt/route.ts — served as text/plain
|
|
118
|
+
export function GET() {
|
|
119
|
+
return llmsTxtResponse({ title: "Lacspace", summary: "…", sections });
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
97
123
|
## Licensing
|
|
98
124
|
|
|
99
125
|
This package is **free** under the **[Lacspace Free Licence](https://lacspace.com/licenses/lacspace-free-1.0)** — MIT-equivalent freedoms. Use it in personal and commercial projects at no cost; just keep the notice.
|
package/dist/index.cjs
CHANGED
|
@@ -49,9 +49,52 @@ function parseLlmsTxt(txt) {
|
|
|
49
49
|
if (details) doc.details = details;
|
|
50
50
|
return doc;
|
|
51
51
|
}
|
|
52
|
+
function titleFromUrl(url) {
|
|
53
|
+
let path;
|
|
54
|
+
try {
|
|
55
|
+
path = new URL(url).pathname;
|
|
56
|
+
} catch {
|
|
57
|
+
path = url;
|
|
58
|
+
}
|
|
59
|
+
const seg = path.split("/").filter(Boolean).pop();
|
|
60
|
+
if (!seg) return "Home";
|
|
61
|
+
return decodeURIComponent(seg).replace(/\.[a-z]+$/i, "").replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
62
|
+
}
|
|
63
|
+
function llmsTxtFromSitemap(entries, meta) {
|
|
64
|
+
const bySection = /* @__PURE__ */ new Map();
|
|
65
|
+
for (const e of entries) {
|
|
66
|
+
const url = e.url ?? e.loc;
|
|
67
|
+
if (!url) continue;
|
|
68
|
+
const section = e.section ?? meta.defaultSection ?? "Pages";
|
|
69
|
+
if (!bySection.has(section)) bySection.set(section, []);
|
|
70
|
+
bySection.get(section).push({ title: e.title ?? titleFromUrl(url), url });
|
|
71
|
+
}
|
|
72
|
+
const doc = {
|
|
73
|
+
title: meta.title,
|
|
74
|
+
summary: meta.summary,
|
|
75
|
+
details: meta.details,
|
|
76
|
+
sections: [...bySection].map(([title, links]) => ({ title, links }))
|
|
77
|
+
};
|
|
78
|
+
return llmsTxt(doc);
|
|
79
|
+
}
|
|
80
|
+
function llmsTxtResponse(doc, init = {}) {
|
|
81
|
+
return new Response(llmsTxt(doc), {
|
|
82
|
+
...init,
|
|
83
|
+
headers: { "content-type": "text/plain; charset=utf-8", ...init.headers ?? {} }
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function llmsFullTxtResponse(doc, init = {}) {
|
|
87
|
+
return new Response(llmsFullTxt(doc), {
|
|
88
|
+
...init,
|
|
89
|
+
headers: { "content-type": "text/plain; charset=utf-8", ...init.headers ?? {} }
|
|
90
|
+
});
|
|
91
|
+
}
|
|
52
92
|
|
|
53
93
|
exports.llmsFullTxt = llmsFullTxt;
|
|
94
|
+
exports.llmsFullTxtResponse = llmsFullTxtResponse;
|
|
54
95
|
exports.llmsTxt = llmsTxt;
|
|
96
|
+
exports.llmsTxtFromSitemap = llmsTxtFromSitemap;
|
|
97
|
+
exports.llmsTxtResponse = llmsTxtResponse;
|
|
55
98
|
exports.parseLlmsTxt = parseLlmsTxt;
|
|
56
99
|
//# sourceMappingURL=index.cjs.map
|
|
57
100
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lacspace/llms-txt\n * Generate and parse llms.txt and llms-full.txt (the llmstxt.org standard).\n *\n * llms.txt is a Markdown file at your site root that gives LLMs a curated map of\n * your most useful content; llms-full.txt inlines the full text so a model can\n * read everything in one request.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\nexport interface LlmsLink {\n title: string;\n url: string;\n /** Short note shown after the link. */\n notes?: string;\n}\n\nexport interface LlmsSection {\n title: string;\n links: LlmsLink[];\n}\n\nexport interface LlmsDoc {\n /** The site / project name (rendered as the H1). */\n title: string;\n /** One-line summary (rendered as a blockquote). */\n summary?: string;\n /** Free-form Markdown shown before the sections. */\n details?: string;\n sections: LlmsSection[];\n}\n\n/**\n * Render an `llms.txt` document.\n * @example\n * llmsTxt({\n * title: \"Lacspace\",\n * summary: \"Open-source TypeScript packages and products.\",\n * sections: [{ title: \"Docs\", links: [{ title: \"Packages\", url: \"https://lacspace.com/packages\" }] }],\n * });\n */\nexport function llmsTxt(doc: LlmsDoc): string {\n const out: string[] = [`# ${doc.title}`];\n if (doc.summary) out.push(\"\", `> ${doc.summary}`);\n if (doc.details) out.push(\"\", doc.details.trim());\n for (const section of doc.sections) {\n out.push(\"\", `## ${section.title}`, \"\");\n for (const l of section.links) {\n out.push(`- [${l.title}](${l.url})${l.notes ? `: ${l.notes}` : \"\"}`);\n }\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n\nexport interface LlmsFullSection {\n title: string;\n /** Full Markdown content for this section. */\n content: string;\n /** Optional source URL, added as a heading link. */\n url?: string;\n}\n\nexport interface LlmsFullDoc {\n title: string;\n summary?: string;\n sections: LlmsFullSection[];\n}\n\n/** Render an `llms-full.txt` document with the full content inlined. */\nexport function llmsFullTxt(doc: LlmsFullDoc): string {\n const out: string[] = [`# ${doc.title}`];\n if (doc.summary) out.push(\"\", `> ${doc.summary}`);\n for (const section of doc.sections) {\n out.push(\"\", \"---\", \"\", `## ${section.title}`);\n if (section.url) out.push(\"\", `Source: ${section.url}`);\n out.push(\"\", section.content.trim());\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n\n/** Parse an `llms.txt` string back into a structured document. */\nexport function parseLlmsTxt(txt: string): LlmsDoc {\n const lines = txt.split(/\\r?\\n/);\n const doc: LlmsDoc = { title: \"\", sections: [] };\n let current: LlmsSection | null = null;\n const detailBuf: string[] = [];\n const linkRe = /^-\\s*\\[([^\\]]+)\\]\\(([^)]+)\\)\\s*(?::\\s*(.*))?$/;\n\n for (const raw of lines) {\n const line = raw.trimEnd();\n if (line.startsWith(\"# \")) {\n doc.title = line.slice(2).trim();\n } else if (line.startsWith(\"> \")) {\n doc.summary = (doc.summary ? doc.summary + \" \" : \"\") + line.slice(2).trim();\n } else if (line.startsWith(\"## \")) {\n current = { title: line.slice(3).trim(), links: [] };\n doc.sections.push(current);\n } else if (current && linkRe.test(line)) {\n const m = line.match(linkRe)!;\n current.links.push({ title: m[1]!, url: m[2]!, notes: m[3]?.trim() || undefined });\n } else if (!current && line && !line.startsWith(\"#\")) {\n detailBuf.push(line);\n }\n }\n const details = detailBuf.join(\"\\n\").trim();\n if (details) doc.details = details;\n return doc;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lacspace/llms-txt\n * Generate and parse llms.txt and llms-full.txt (the llmstxt.org standard).\n *\n * llms.txt is a Markdown file at your site root that gives LLMs a curated map of\n * your most useful content; llms-full.txt inlines the full text so a model can\n * read everything in one request.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\nexport interface LlmsLink {\n title: string;\n url: string;\n /** Short note shown after the link. */\n notes?: string;\n}\n\nexport interface LlmsSection {\n title: string;\n links: LlmsLink[];\n}\n\nexport interface LlmsDoc {\n /** The site / project name (rendered as the H1). */\n title: string;\n /** One-line summary (rendered as a blockquote). */\n summary?: string;\n /** Free-form Markdown shown before the sections. */\n details?: string;\n sections: LlmsSection[];\n}\n\n/**\n * Render an `llms.txt` document.\n * @example\n * llmsTxt({\n * title: \"Lacspace\",\n * summary: \"Open-source TypeScript packages and products.\",\n * sections: [{ title: \"Docs\", links: [{ title: \"Packages\", url: \"https://lacspace.com/packages\" }] }],\n * });\n */\nexport function llmsTxt(doc: LlmsDoc): string {\n const out: string[] = [`# ${doc.title}`];\n if (doc.summary) out.push(\"\", `> ${doc.summary}`);\n if (doc.details) out.push(\"\", doc.details.trim());\n for (const section of doc.sections) {\n out.push(\"\", `## ${section.title}`, \"\");\n for (const l of section.links) {\n out.push(`- [${l.title}](${l.url})${l.notes ? `: ${l.notes}` : \"\"}`);\n }\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n\nexport interface LlmsFullSection {\n title: string;\n /** Full Markdown content for this section. */\n content: string;\n /** Optional source URL, added as a heading link. */\n url?: string;\n}\n\nexport interface LlmsFullDoc {\n title: string;\n summary?: string;\n sections: LlmsFullSection[];\n}\n\n/** Render an `llms-full.txt` document with the full content inlined. */\nexport function llmsFullTxt(doc: LlmsFullDoc): string {\n const out: string[] = [`# ${doc.title}`];\n if (doc.summary) out.push(\"\", `> ${doc.summary}`);\n for (const section of doc.sections) {\n out.push(\"\", \"---\", \"\", `## ${section.title}`);\n if (section.url) out.push(\"\", `Source: ${section.url}`);\n out.push(\"\", section.content.trim());\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n\n/** Parse an `llms.txt` string back into a structured document. */\nexport function parseLlmsTxt(txt: string): LlmsDoc {\n const lines = txt.split(/\\r?\\n/);\n const doc: LlmsDoc = { title: \"\", sections: [] };\n let current: LlmsSection | null = null;\n const detailBuf: string[] = [];\n const linkRe = /^-\\s*\\[([^\\]]+)\\]\\(([^)]+)\\)\\s*(?::\\s*(.*))?$/;\n\n for (const raw of lines) {\n const line = raw.trimEnd();\n if (line.startsWith(\"# \")) {\n doc.title = line.slice(2).trim();\n } else if (line.startsWith(\"> \")) {\n doc.summary = (doc.summary ? doc.summary + \" \" : \"\") + line.slice(2).trim();\n } else if (line.startsWith(\"## \")) {\n current = { title: line.slice(3).trim(), links: [] };\n doc.sections.push(current);\n } else if (current && linkRe.test(line)) {\n const m = line.match(linkRe)!;\n current.links.push({ title: m[1]!, url: m[2]!, notes: m[3]?.trim() || undefined });\n } else if (!current && line && !line.startsWith(\"#\")) {\n detailBuf.push(line);\n }\n }\n const details = detailBuf.join(\"\\n\").trim();\n if (details) doc.details = details;\n return doc;\n}\n\n/* ------------------------------ from sitemap ------------------------------ */\n\n/** A sitemap-ish entry — accepts `url` or `loc`, plus optional title/section. */\nexport interface SitemapEntryLike {\n url?: string;\n loc?: string;\n title?: string;\n section?: string;\n}\n\nfunction titleFromUrl(url: string): string {\n let path: string;\n try {\n path = new URL(url).pathname;\n } catch {\n path = url;\n }\n const seg = path.split(\"/\").filter(Boolean).pop();\n if (!seg) return \"Home\";\n return decodeURIComponent(seg).replace(/\\.[a-z]+$/i, \"\").replace(/[-_]+/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\n/**\n * Build an `llms.txt` from a list of sitemap entries — group by `section`,\n * derive titles from the URL when not given. Pairs with `@lacspace/sitemap`.\n */\nexport function llmsTxtFromSitemap(\n entries: SitemapEntryLike[],\n meta: { title: string; summary?: string; details?: string; defaultSection?: string },\n): string {\n const bySection = new Map<string, LlmsLink[]>();\n for (const e of entries) {\n const url = e.url ?? e.loc;\n if (!url) continue;\n const section = e.section ?? meta.defaultSection ?? \"Pages\";\n if (!bySection.has(section)) bySection.set(section, []);\n bySection.get(section)!.push({ title: e.title ?? titleFromUrl(url), url });\n }\n const doc: LlmsDoc = {\n title: meta.title,\n summary: meta.summary,\n details: meta.details,\n sections: [...bySection].map(([title, links]) => ({ title, links })),\n };\n return llmsTxt(doc);\n}\n\n/* ------------------------------ adapters ------------------------------ */\n\n/** `llms.txt` as a Fetch/edge `Response` (text/plain) for app/llms.txt/route.ts. */\nexport function llmsTxtResponse(doc: LlmsDoc, init: ResponseInit = {}): Response {\n return new Response(llmsTxt(doc), {\n ...init,\n headers: { \"content-type\": \"text/plain; charset=utf-8\", ...(init.headers ?? {}) },\n });\n}\n\n/** `llms-full.txt` as a Fetch/edge `Response` (text/plain). */\nexport function llmsFullTxtResponse(doc: LlmsFullDoc, init: ResponseInit = {}): Response {\n return new Response(llmsFullTxt(doc), {\n ...init,\n headers: { \"content-type\": \"text/plain; charset=utf-8\", ...(init.headers ?? {}) },\n });\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -53,5 +53,26 @@ interface LlmsFullDoc {
|
|
|
53
53
|
declare function llmsFullTxt(doc: LlmsFullDoc): string;
|
|
54
54
|
/** Parse an `llms.txt` string back into a structured document. */
|
|
55
55
|
declare function parseLlmsTxt(txt: string): LlmsDoc;
|
|
56
|
+
/** A sitemap-ish entry — accepts `url` or `loc`, plus optional title/section. */
|
|
57
|
+
interface SitemapEntryLike {
|
|
58
|
+
url?: string;
|
|
59
|
+
loc?: string;
|
|
60
|
+
title?: string;
|
|
61
|
+
section?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Build an `llms.txt` from a list of sitemap entries — group by `section`,
|
|
65
|
+
* derive titles from the URL when not given. Pairs with `@lacspace/sitemap`.
|
|
66
|
+
*/
|
|
67
|
+
declare function llmsTxtFromSitemap(entries: SitemapEntryLike[], meta: {
|
|
68
|
+
title: string;
|
|
69
|
+
summary?: string;
|
|
70
|
+
details?: string;
|
|
71
|
+
defaultSection?: string;
|
|
72
|
+
}): string;
|
|
73
|
+
/** `llms.txt` as a Fetch/edge `Response` (text/plain) for app/llms.txt/route.ts. */
|
|
74
|
+
declare function llmsTxtResponse(doc: LlmsDoc, init?: ResponseInit): Response;
|
|
75
|
+
/** `llms-full.txt` as a Fetch/edge `Response` (text/plain). */
|
|
76
|
+
declare function llmsFullTxtResponse(doc: LlmsFullDoc, init?: ResponseInit): Response;
|
|
56
77
|
|
|
57
|
-
export { type LlmsDoc, type LlmsFullDoc, type LlmsFullSection, type LlmsLink, type LlmsSection, llmsFullTxt, llmsTxt, parseLlmsTxt };
|
|
78
|
+
export { type LlmsDoc, type LlmsFullDoc, type LlmsFullSection, type LlmsLink, type LlmsSection, type SitemapEntryLike, llmsFullTxt, llmsFullTxtResponse, llmsTxt, llmsTxtFromSitemap, llmsTxtResponse, parseLlmsTxt };
|
package/dist/index.d.ts
CHANGED
|
@@ -53,5 +53,26 @@ interface LlmsFullDoc {
|
|
|
53
53
|
declare function llmsFullTxt(doc: LlmsFullDoc): string;
|
|
54
54
|
/** Parse an `llms.txt` string back into a structured document. */
|
|
55
55
|
declare function parseLlmsTxt(txt: string): LlmsDoc;
|
|
56
|
+
/** A sitemap-ish entry — accepts `url` or `loc`, plus optional title/section. */
|
|
57
|
+
interface SitemapEntryLike {
|
|
58
|
+
url?: string;
|
|
59
|
+
loc?: string;
|
|
60
|
+
title?: string;
|
|
61
|
+
section?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Build an `llms.txt` from a list of sitemap entries — group by `section`,
|
|
65
|
+
* derive titles from the URL when not given. Pairs with `@lacspace/sitemap`.
|
|
66
|
+
*/
|
|
67
|
+
declare function llmsTxtFromSitemap(entries: SitemapEntryLike[], meta: {
|
|
68
|
+
title: string;
|
|
69
|
+
summary?: string;
|
|
70
|
+
details?: string;
|
|
71
|
+
defaultSection?: string;
|
|
72
|
+
}): string;
|
|
73
|
+
/** `llms.txt` as a Fetch/edge `Response` (text/plain) for app/llms.txt/route.ts. */
|
|
74
|
+
declare function llmsTxtResponse(doc: LlmsDoc, init?: ResponseInit): Response;
|
|
75
|
+
/** `llms-full.txt` as a Fetch/edge `Response` (text/plain). */
|
|
76
|
+
declare function llmsFullTxtResponse(doc: LlmsFullDoc, init?: ResponseInit): Response;
|
|
56
77
|
|
|
57
|
-
export { type LlmsDoc, type LlmsFullDoc, type LlmsFullSection, type LlmsLink, type LlmsSection, llmsFullTxt, llmsTxt, parseLlmsTxt };
|
|
78
|
+
export { type LlmsDoc, type LlmsFullDoc, type LlmsFullSection, type LlmsLink, type LlmsSection, type SitemapEntryLike, llmsFullTxt, llmsFullTxtResponse, llmsTxt, llmsTxtFromSitemap, llmsTxtResponse, parseLlmsTxt };
|
package/dist/index.js
CHANGED
|
@@ -47,7 +47,47 @@ function parseLlmsTxt(txt) {
|
|
|
47
47
|
if (details) doc.details = details;
|
|
48
48
|
return doc;
|
|
49
49
|
}
|
|
50
|
+
function titleFromUrl(url) {
|
|
51
|
+
let path;
|
|
52
|
+
try {
|
|
53
|
+
path = new URL(url).pathname;
|
|
54
|
+
} catch {
|
|
55
|
+
path = url;
|
|
56
|
+
}
|
|
57
|
+
const seg = path.split("/").filter(Boolean).pop();
|
|
58
|
+
if (!seg) return "Home";
|
|
59
|
+
return decodeURIComponent(seg).replace(/\.[a-z]+$/i, "").replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
60
|
+
}
|
|
61
|
+
function llmsTxtFromSitemap(entries, meta) {
|
|
62
|
+
const bySection = /* @__PURE__ */ new Map();
|
|
63
|
+
for (const e of entries) {
|
|
64
|
+
const url = e.url ?? e.loc;
|
|
65
|
+
if (!url) continue;
|
|
66
|
+
const section = e.section ?? meta.defaultSection ?? "Pages";
|
|
67
|
+
if (!bySection.has(section)) bySection.set(section, []);
|
|
68
|
+
bySection.get(section).push({ title: e.title ?? titleFromUrl(url), url });
|
|
69
|
+
}
|
|
70
|
+
const doc = {
|
|
71
|
+
title: meta.title,
|
|
72
|
+
summary: meta.summary,
|
|
73
|
+
details: meta.details,
|
|
74
|
+
sections: [...bySection].map(([title, links]) => ({ title, links }))
|
|
75
|
+
};
|
|
76
|
+
return llmsTxt(doc);
|
|
77
|
+
}
|
|
78
|
+
function llmsTxtResponse(doc, init = {}) {
|
|
79
|
+
return new Response(llmsTxt(doc), {
|
|
80
|
+
...init,
|
|
81
|
+
headers: { "content-type": "text/plain; charset=utf-8", ...init.headers ?? {} }
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function llmsFullTxtResponse(doc, init = {}) {
|
|
85
|
+
return new Response(llmsFullTxt(doc), {
|
|
86
|
+
...init,
|
|
87
|
+
headers: { "content-type": "text/plain; charset=utf-8", ...init.headers ?? {} }
|
|
88
|
+
});
|
|
89
|
+
}
|
|
50
90
|
|
|
51
|
-
export { llmsFullTxt, llmsTxt, parseLlmsTxt };
|
|
91
|
+
export { llmsFullTxt, llmsFullTxtResponse, llmsTxt, llmsTxtFromSitemap, llmsTxtResponse, parseLlmsTxt };
|
|
52
92
|
//# sourceMappingURL=index.js.map
|
|
53
93
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @lacspace/llms-txt\n * Generate and parse llms.txt and llms-full.txt (the llmstxt.org standard).\n *\n * llms.txt is a Markdown file at your site root that gives LLMs a curated map of\n * your most useful content; llms-full.txt inlines the full text so a model can\n * read everything in one request.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\nexport interface LlmsLink {\n title: string;\n url: string;\n /** Short note shown after the link. */\n notes?: string;\n}\n\nexport interface LlmsSection {\n title: string;\n links: LlmsLink[];\n}\n\nexport interface LlmsDoc {\n /** The site / project name (rendered as the H1). */\n title: string;\n /** One-line summary (rendered as a blockquote). */\n summary?: string;\n /** Free-form Markdown shown before the sections. */\n details?: string;\n sections: LlmsSection[];\n}\n\n/**\n * Render an `llms.txt` document.\n * @example\n * llmsTxt({\n * title: \"Lacspace\",\n * summary: \"Open-source TypeScript packages and products.\",\n * sections: [{ title: \"Docs\", links: [{ title: \"Packages\", url: \"https://lacspace.com/packages\" }] }],\n * });\n */\nexport function llmsTxt(doc: LlmsDoc): string {\n const out: string[] = [`# ${doc.title}`];\n if (doc.summary) out.push(\"\", `> ${doc.summary}`);\n if (doc.details) out.push(\"\", doc.details.trim());\n for (const section of doc.sections) {\n out.push(\"\", `## ${section.title}`, \"\");\n for (const l of section.links) {\n out.push(`- [${l.title}](${l.url})${l.notes ? `: ${l.notes}` : \"\"}`);\n }\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n\nexport interface LlmsFullSection {\n title: string;\n /** Full Markdown content for this section. */\n content: string;\n /** Optional source URL, added as a heading link. */\n url?: string;\n}\n\nexport interface LlmsFullDoc {\n title: string;\n summary?: string;\n sections: LlmsFullSection[];\n}\n\n/** Render an `llms-full.txt` document with the full content inlined. */\nexport function llmsFullTxt(doc: LlmsFullDoc): string {\n const out: string[] = [`# ${doc.title}`];\n if (doc.summary) out.push(\"\", `> ${doc.summary}`);\n for (const section of doc.sections) {\n out.push(\"\", \"---\", \"\", `## ${section.title}`);\n if (section.url) out.push(\"\", `Source: ${section.url}`);\n out.push(\"\", section.content.trim());\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n\n/** Parse an `llms.txt` string back into a structured document. */\nexport function parseLlmsTxt(txt: string): LlmsDoc {\n const lines = txt.split(/\\r?\\n/);\n const doc: LlmsDoc = { title: \"\", sections: [] };\n let current: LlmsSection | null = null;\n const detailBuf: string[] = [];\n const linkRe = /^-\\s*\\[([^\\]]+)\\]\\(([^)]+)\\)\\s*(?::\\s*(.*))?$/;\n\n for (const raw of lines) {\n const line = raw.trimEnd();\n if (line.startsWith(\"# \")) {\n doc.title = line.slice(2).trim();\n } else if (line.startsWith(\"> \")) {\n doc.summary = (doc.summary ? doc.summary + \" \" : \"\") + line.slice(2).trim();\n } else if (line.startsWith(\"## \")) {\n current = { title: line.slice(3).trim(), links: [] };\n doc.sections.push(current);\n } else if (current && linkRe.test(line)) {\n const m = line.match(linkRe)!;\n current.links.push({ title: m[1]!, url: m[2]!, notes: m[3]?.trim() || undefined });\n } else if (!current && line && !line.startsWith(\"#\")) {\n detailBuf.push(line);\n }\n }\n const details = detailBuf.join(\"\\n\").trim();\n if (details) doc.details = details;\n return doc;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @lacspace/llms-txt\n * Generate and parse llms.txt and llms-full.txt (the llmstxt.org standard).\n *\n * llms.txt is a Markdown file at your site root that gives LLMs a curated map of\n * your most useful content; llms-full.txt inlines the full text so a model can\n * read everything in one request.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\nexport interface LlmsLink {\n title: string;\n url: string;\n /** Short note shown after the link. */\n notes?: string;\n}\n\nexport interface LlmsSection {\n title: string;\n links: LlmsLink[];\n}\n\nexport interface LlmsDoc {\n /** The site / project name (rendered as the H1). */\n title: string;\n /** One-line summary (rendered as a blockquote). */\n summary?: string;\n /** Free-form Markdown shown before the sections. */\n details?: string;\n sections: LlmsSection[];\n}\n\n/**\n * Render an `llms.txt` document.\n * @example\n * llmsTxt({\n * title: \"Lacspace\",\n * summary: \"Open-source TypeScript packages and products.\",\n * sections: [{ title: \"Docs\", links: [{ title: \"Packages\", url: \"https://lacspace.com/packages\" }] }],\n * });\n */\nexport function llmsTxt(doc: LlmsDoc): string {\n const out: string[] = [`# ${doc.title}`];\n if (doc.summary) out.push(\"\", `> ${doc.summary}`);\n if (doc.details) out.push(\"\", doc.details.trim());\n for (const section of doc.sections) {\n out.push(\"\", `## ${section.title}`, \"\");\n for (const l of section.links) {\n out.push(`- [${l.title}](${l.url})${l.notes ? `: ${l.notes}` : \"\"}`);\n }\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n\nexport interface LlmsFullSection {\n title: string;\n /** Full Markdown content for this section. */\n content: string;\n /** Optional source URL, added as a heading link. */\n url?: string;\n}\n\nexport interface LlmsFullDoc {\n title: string;\n summary?: string;\n sections: LlmsFullSection[];\n}\n\n/** Render an `llms-full.txt` document with the full content inlined. */\nexport function llmsFullTxt(doc: LlmsFullDoc): string {\n const out: string[] = [`# ${doc.title}`];\n if (doc.summary) out.push(\"\", `> ${doc.summary}`);\n for (const section of doc.sections) {\n out.push(\"\", \"---\", \"\", `## ${section.title}`);\n if (section.url) out.push(\"\", `Source: ${section.url}`);\n out.push(\"\", section.content.trim());\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n\n/** Parse an `llms.txt` string back into a structured document. */\nexport function parseLlmsTxt(txt: string): LlmsDoc {\n const lines = txt.split(/\\r?\\n/);\n const doc: LlmsDoc = { title: \"\", sections: [] };\n let current: LlmsSection | null = null;\n const detailBuf: string[] = [];\n const linkRe = /^-\\s*\\[([^\\]]+)\\]\\(([^)]+)\\)\\s*(?::\\s*(.*))?$/;\n\n for (const raw of lines) {\n const line = raw.trimEnd();\n if (line.startsWith(\"# \")) {\n doc.title = line.slice(2).trim();\n } else if (line.startsWith(\"> \")) {\n doc.summary = (doc.summary ? doc.summary + \" \" : \"\") + line.slice(2).trim();\n } else if (line.startsWith(\"## \")) {\n current = { title: line.slice(3).trim(), links: [] };\n doc.sections.push(current);\n } else if (current && linkRe.test(line)) {\n const m = line.match(linkRe)!;\n current.links.push({ title: m[1]!, url: m[2]!, notes: m[3]?.trim() || undefined });\n } else if (!current && line && !line.startsWith(\"#\")) {\n detailBuf.push(line);\n }\n }\n const details = detailBuf.join(\"\\n\").trim();\n if (details) doc.details = details;\n return doc;\n}\n\n/* ------------------------------ from sitemap ------------------------------ */\n\n/** A sitemap-ish entry — accepts `url` or `loc`, plus optional title/section. */\nexport interface SitemapEntryLike {\n url?: string;\n loc?: string;\n title?: string;\n section?: string;\n}\n\nfunction titleFromUrl(url: string): string {\n let path: string;\n try {\n path = new URL(url).pathname;\n } catch {\n path = url;\n }\n const seg = path.split(\"/\").filter(Boolean).pop();\n if (!seg) return \"Home\";\n return decodeURIComponent(seg).replace(/\\.[a-z]+$/i, \"\").replace(/[-_]+/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\n/**\n * Build an `llms.txt` from a list of sitemap entries — group by `section`,\n * derive titles from the URL when not given. Pairs with `@lacspace/sitemap`.\n */\nexport function llmsTxtFromSitemap(\n entries: SitemapEntryLike[],\n meta: { title: string; summary?: string; details?: string; defaultSection?: string },\n): string {\n const bySection = new Map<string, LlmsLink[]>();\n for (const e of entries) {\n const url = e.url ?? e.loc;\n if (!url) continue;\n const section = e.section ?? meta.defaultSection ?? \"Pages\";\n if (!bySection.has(section)) bySection.set(section, []);\n bySection.get(section)!.push({ title: e.title ?? titleFromUrl(url), url });\n }\n const doc: LlmsDoc = {\n title: meta.title,\n summary: meta.summary,\n details: meta.details,\n sections: [...bySection].map(([title, links]) => ({ title, links })),\n };\n return llmsTxt(doc);\n}\n\n/* ------------------------------ adapters ------------------------------ */\n\n/** `llms.txt` as a Fetch/edge `Response` (text/plain) for app/llms.txt/route.ts. */\nexport function llmsTxtResponse(doc: LlmsDoc, init: ResponseInit = {}): Response {\n return new Response(llmsTxt(doc), {\n ...init,\n headers: { \"content-type\": \"text/plain; charset=utf-8\", ...(init.headers ?? {}) },\n });\n}\n\n/** `llms-full.txt` as a Fetch/edge `Response` (text/plain). */\nexport function llmsFullTxtResponse(doc: LlmsFullDoc, init: ResponseInit = {}): Response {\n return new Response(llmsFullTxt(doc), {\n ...init,\n headers: { \"content-type\": \"text/plain; charset=utf-8\", ...(init.headers ?? {}) },\n });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lacspace/llms-txt",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Generate and parse llms.txt and llms-full.txt (the llmstxt.org standard) — a Markdown map of your site for LLMs. Zero-dependency, isomorphic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|