Files
2026-07-13 13:34:31 +08:00

98 lines
3.2 KiB
Diff

--- template/app/scripts/generate-llms-txt.mjs
+++ opensaas-sh/app/scripts/generate-llms-txt.mjs
@@ -0,0 +1,94 @@
+import { readdir, readFile, writeFile } from "node:fs/promises";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const APP_ROOT = path.resolve(__dirname, "..");
+const BLOG_POSTS_DIR = path.resolve(
+ APP_ROOT,
+ "../blog/src/content/docs/blog",
+);
+const OUTPUT_FILE = path.join(APP_ROOT, "public/llms.txt");
+
+const DOCS_SITE = "https://docs.opensaas.sh";
+
+function parseFrontmatter(source) {
+ const match = source.match(/^---\r?\n([\s\S]*?)\r?\n---/);
+ if (!match) return {};
+ const out = {};
+ for (const line of match[1].split(/\r?\n/)) {
+ const m = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
+ if (!m) continue;
+ const [, key, rawValue] = m;
+ let value = rawValue.trim();
+ if (
+ (value.startsWith('"') && value.endsWith('"')) ||
+ (value.startsWith("'") && value.endsWith("'"))
+ ) {
+ value = value.slice(1, -1);
+ }
+ out[key] = value;
+ }
+ return out;
+}
+
+async function collectBlogPosts() {
+ const entries = await readdir(BLOG_POSTS_DIR);
+ const posts = [];
+ for (const file of entries) {
+ if (!file.endsWith(".mdx") && !file.endsWith(".md")) continue;
+ const slug = file.replace(/\.(mdx|md)$/, "");
+ const source = await readFile(path.join(BLOG_POSTS_DIR, file), "utf8");
+ const fm = parseFrontmatter(source);
+ if (!fm.title) {
+ console.warn(`Skipping ${file}: no title in frontmatter`);
+ continue;
+ }
+ posts.push({
+ title: fm.title,
+ date: fm.date ?? "",
+ url: `${DOCS_SITE}/blog/${slug}/`,
+ });
+ }
+ posts.sort((a, b) => b.date.localeCompare(a.date));
+ return posts;
+}
+
+function renderLlmsTxt(posts) {
+ const lines = [
+ "# Open SaaS",
+ "",
+ "> Open SaaS is a free, open-source, full-stack SaaS boilerplate starter kit built on the Wasp framework (React, Node.js, Prisma). It ships with auth, Stripe/Lemon Squeezy/Polar payments, an OpenAI demo app, AWS S3 file uploads, an admin dashboard, email sending, and AI agent rules and skills.",
+ "",
+ "## Site",
+ "- [Homepage](https://opensaas.sh): product overview, features, demo, FAQ, etc.",
+ "- [GitHub repository](https://github.com/wasp-lang/open-saas): source code, issues, and releases",
+ "",
+ "## Documentation",
+ `- [Documentation site](${DOCS_SITE}/)`,
+ `- [LLM-formatted docs index](${DOCS_SITE}/llms.txt): per-guide links to raw markdown sources`,
+ `- [Full LLM-formatted docs](${DOCS_SITE}/llms-full.txt): every guide concatenated into one file`,
+ "",
+ "## Blog",
+ ];
+ for (const post of posts) {
+ const datePart = post.date ? ` — ${post.date}` : "";
+ lines.push(`- [${post.title}](${post.url})${datePart}`);
+ }
+ lines.push("");
+ return lines.join("\n");
+}
+
+async function main() {
+ const posts = await collectBlogPosts();
+ const content = renderLlmsTxt(posts);
+ await writeFile(OUTPUT_FILE, content, "utf8");
+ console.log(
+ `Wrote ${OUTPUT_FILE} with ${posts.length} blog post${posts.length === 1 ? "" : "s"}.`,
+ );
+}
+
+main().catch((err) => {
+ console.error(err);
+ process.exit(1);
+});