From 78824eff3b148dba7400664508de1d5ad0601fa6 Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 20:13:02 +0500 Subject: [PATCH 1/9] fix: npm publish auth + correct @llmstxt scope --- .gitignore | 1 + .npmrc.example | 1 + packages/core/package.json | 2 +- packages/middleware/package.json | 2 +- packages/next/README.md | 5 ++++- packages/next/package.json | 2 +- 6 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 .npmrc.example diff --git a/.gitignore b/.gitignore index d5b3be1..987f995 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ web_modules/ # dotenv environment variables file .env.test .env.local +.npmrc # parcel-bundler cache (https://parceljs.org/) .cache diff --git a/.npmrc.example b/.npmrc.example new file mode 100644 index 0000000..55343a2 --- /dev/null +++ b/.npmrc.example @@ -0,0 +1 @@ +//registry.npmjs.org/:_authToken=YOUR_NPM_AUTOMATION_TOKEN_HERE \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index f7cfd5a..86a1eb1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -44,4 +44,4 @@ "engines": { "node": ">=18.0.0" } -} \ No newline at end of file +} diff --git a/packages/middleware/package.json b/packages/middleware/package.json index 2a8d745..e128c7d 100644 --- a/packages/middleware/package.json +++ b/packages/middleware/package.json @@ -48,4 +48,4 @@ "engines": { "node": ">=18.0.0" } -} \ No newline at end of file +} diff --git a/packages/next/README.md b/packages/next/README.md index 7c4f899..1a00bbf 100644 --- a/packages/next/README.md +++ b/packages/next/README.md @@ -41,12 +41,16 @@ src/app/ route.ts ``` +For `llms.txt`: + **`src/app/llms.txt/route.ts`**: ```ts export { GET } from '@llmstxt/next' ``` +For `llms-full.txt`: + **`src/app/llms-full.txt/route.ts`**: ```ts @@ -122,4 +126,3 @@ export { middleware, config } from '@llmstxt/middleware' ``` See [`@llmstxt/middleware`](https://www.npmjs.com/package/@llmstxt/middleware) for full options. - diff --git a/packages/next/package.json b/packages/next/package.json index 52ff822..a2b84d6 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -53,4 +53,4 @@ "devDependencies": { "@types/node": "^18.19.130" } -} \ No newline at end of file +} From 1367cf3d3f1f977248117beb77a4f523d8ee59af Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 20:54:02 +0500 Subject: [PATCH 2/9] chore: rename scope to @llmtxt --- .npmrc.example | 3 +- README.md | 60 +++++++++---------- examples/README.md | 4 +- examples/nextjs-test/README.md | 10 ++-- examples/nextjs-test/app/about/page.tsx | 8 +-- .../nextjs-test/app/api-reference/page.tsx | 16 ++--- examples/nextjs-test/app/blog/page.tsx | 4 +- .../app/docs/getting-started/page.tsx | 8 +-- examples/nextjs-test/app/features/page.tsx | 2 +- .../nextjs-test/app/llms-full.txt/route.ts | 2 +- examples/nextjs-test/app/llms.txt/route.ts | 4 +- examples/nextjs-test/app/page.tsx | 4 +- examples/nextjs-test/app/pricing/page.tsx | 2 +- examples/nextjs-test/middleware.ts | 2 +- examples/nextjs-test/package-lock.json | 23 +++---- examples/nextjs-test/package.json | 8 +-- package-lock.json | 26 ++++---- package.json | 6 +- packages/core/README.md | 14 ++--- packages/core/package.json | 4 +- packages/core/src/generate.ts | 6 +- packages/core/test/scan.spec.ts | 4 +- packages/middleware/README.md | 12 ++-- packages/middleware/package.json | 4 +- packages/middleware/src/index.ts | 2 +- packages/next/README.md | 20 +++---- packages/next/package.json | 6 +- packages/next/src/llms-full-txt-route.ts | 4 +- packages/next/src/llms-txt-route.ts | 4 +- 29 files changed, 138 insertions(+), 134 deletions(-) diff --git a/.npmrc.example b/.npmrc.example index 55343a2..47f8978 100644 --- a/.npmrc.example +++ b/.npmrc.example @@ -1 +1,2 @@ -//registry.npmjs.org/:_authToken=YOUR_NPM_AUTOMATION_TOKEN_HERE \ No newline at end of file +registry=https://registry.npmjs.org/ +//registry.npmjs.org/:_authToken=${NPM_TOKEN} diff --git a/README.md b/README.md index efa1a84..5823954 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ -# @llmstxt — `llms.txt`, `llms-full.txt`, and Markdown for agents +# @llmtxt — `llms.txt`, `llms-full.txt`, and Markdown for agents Generate `llms.txt` (table of contents) and `llms-full.txt` (full content) from your app’s pages, and optionally serve **any page as Markdown** via content negotiation (`Accept: text/markdown`). - Standard: [llmstxt.org](https://llmstxt.org) -- Works with: Next.js App Router (`@llmstxt/next`), any Node.js framework (`@llmstxt/core`), and Next.js middleware (`@llmstxt/middleware`) +- Works with: Next.js App Router (`@llmtxt/next`), any Node.js framework (`@llmtxt/core`), and Next.js middleware (`@llmtxt/middleware`) ## Packages | Package | What it does | |---|---| -| [`@llmstxt/core`](./packages/core) | Scan your `app/` directory and generate `llms.txt` + `llms-full.txt` | -| [`@llmstxt/next`](./packages/next) | Next.js App Router route handlers for `/llms.txt` and `/llms-full.txt` | -| [`@llmstxt/middleware`](./packages/middleware) | Next.js middleware: any page responds as Markdown on `Accept: text/markdown` | +| [`@llmtxt/core`](./packages/core) | Scan your `app/` directory and generate `llms.txt` + `llms-full.txt` | +| [`@llmtxt/next`](./packages/next) | Next.js App Router route handlers for `/llms.txt` and `/llms-full.txt` | +| [`@llmtxt/middleware`](./packages/middleware) | Next.js middleware: any page responds as Markdown on `Accept: text/markdown` | ## Keywords (SEO) -llms.txt, llms-full.txt, llmstxt, markdown for agents, content negotiation, Next.js, middleware, App Router, AI, LLM, SEO, website indexing, documentation, crawlable content, sitemap alternative +llms.txt, llms-full.txt, llmtxt, markdown for agents, content negotiation, Next.js, middleware, App Router, AI, LLM, SEO, website indexing, documentation, crawlable content, sitemap alternative ## Table of Contents @@ -23,8 +23,8 @@ llms.txt, llms-full.txt, llmstxt, markdown for agents, content negotiation, Next - [Quick Start — Markdown for Agents (Next.js Middleware)](#quick-start--markdown-for-agents-nextjs-middleware) - [Quick Start — Other Frameworks](#quick-start--other-frameworks-express-hono-bun-etc) - [How It Works](#how-it-works) -- [API Reference (`@llmstxt/core`)](#api-reference-llmstxtcore) -- [Environment Variables (`@llmstxt/next`)](#environment-variables-llmstxtnext) +- [API Reference (`@llmtxt/core`)](#api-reference-llmtxtcore) +- [Environment Variables (`@llmtxt/next`)](#environment-variables-llmtxtnext) - [Tips for Better Descriptions](#tips-for-better-descriptions) - [Development (this repo)](#development-this-repo) - [License](#license) @@ -36,7 +36,7 @@ llms.txt, llms-full.txt, llmstxt, markdown for agents, content negotiation, Next ### Install ```bash -npm install @llmstxt/next +npm install @llmtxt/next ``` ### Add route handlers @@ -51,12 +51,12 @@ src/app/ **`src/app/llms.txt/route.ts`** (zero-config): ```ts -export { GET } from '@llmstxt/next' +export { GET } from '@llmtxt/next' ``` **`src/app/llms-full.txt/route.ts`** (zero-config): ```ts -import { createLlmsFullTxtHandler } from '@llmstxt/next' +import { createLlmsFullTxtHandler } from '@llmtxt/next' export const GET = createLlmsFullTxtHandler() ``` @@ -64,7 +64,7 @@ Set one of: - `NEXT_PUBLIC_APP_URL` (recommended) - `VERCEL_URL` (usually already set on Vercel) -> Tip: Set `NEXT_PUBLIC_APP_URL` explicitly in local development and production. `@llmstxt/next` will only fall back to `http://localhost:3000` when `NODE_ENV=development`. +> Tip: Set `NEXT_PUBLIC_APP_URL` explicitly in local development and production. `@llmtxt/next` will only fall back to `http://localhost:3000` when `NODE_ENV=development`. Visit: - `/llms.txt` @@ -74,7 +74,7 @@ Visit: ```ts // src/app/llms.txt/route.ts -import { createLlmsTxtHandler } from '@llmstxt/next' +import { createLlmsTxtHandler } from '@llmtxt/next' export const GET = createLlmsTxtHandler({ title: 'My SaaS App', @@ -85,7 +85,7 @@ export const GET = createLlmsTxtHandler({ ```ts // src/app/llms-full.txt/route.ts -import { createLlmsFullTxtHandler } from '@llmstxt/next' +import { createLlmsFullTxtHandler } from '@llmtxt/next' export const GET = createLlmsFullTxtHandler({ fetchTimeoutMs: 8000, @@ -105,14 +105,14 @@ Serve the Markdown version of **any page** when a client sends `Accept: text/mar ### Install ```bash -npm install @llmstxt/middleware +npm install @llmtxt/middleware ``` ### Add middleware ```ts // middleware.ts (project root) -export { middleware, config } from '@llmstxt/middleware' +export { middleware, config } from '@llmtxt/middleware' ``` This returns: @@ -134,11 +134,11 @@ For best Markdown quality in production, plug in `@mozilla/readability` + `turnd ## Quick Start — Other Frameworks (Express, Hono, Bun, etc.) ```bash -npm install @llmstxt/core +npm install @llmtxt/core ``` ```ts -import { generateLlmsTxt, generateLlmsFullTxt } from '@llmstxt/core' +import { generateLlmsTxt, generateLlmsFullTxt } from '@llmtxt/core' import path from 'path' app.get('/llms.txt', async (req, res) => { @@ -167,7 +167,7 @@ app.get('/llms-full.txt', async (req, res) => { ## How It Works ### `llms.txt` (Table of contents) -`@llmstxt/core` scans your `app/` directory for `page.tsx`/`page.jsx`/`page.ts`/`page.js` files and produces a structured +`@llmtxt/core` scans your `app/` directory for `page.tsx`/`page.jsx`/`page.ts`/`page.js` files and produces a structured index of links + descriptions. LLMs use this like a sitemap to understand what your site covers. Example output: @@ -183,14 +183,14 @@ Example output: - [Advanced Usage](https://example.com/blog/advanced): Deep-dives and recipes --- -*Generated by @llmstxt/core · 2025-01-01T00:00:00.000Z · 12 pages* +*Generated by @llmtxt/core · 2025-01-01T00:00:00.000Z · 12 pages* ``` ### `llms-full.txt` (Full content) Same scan, but also fetches and converts each page to Markdown (or plain text by default). This produces one big file containing your site’s content for ingestion. ### `Accept: text/markdown` (Markdown for agents) -`@llmstxt/middleware` adds content negotiation to your Next.js app: when a client requests any URL with `Accept: text/markdown`, it re-fetches that page as HTML, converts it to Markdown, and returns it with `Content-Type: text/markdown`, `Vary: Accept`, and `x-markdown-tokens`. +`@llmtxt/middleware` adds content negotiation to your Next.js app: when a client requests any URL with `Accept: text/markdown`, it re-fetches that page as HTML, converts it to Markdown, and returns it with `Content-Type: text/markdown`, `Vary: Accept`, and `x-markdown-tokens`. ## Why this helps SEO (and AI discoverability) @@ -199,7 +199,7 @@ These files are primarily for **LLM discoverability**: they provide a structured --- -## API Reference (`@llmstxt/core`) +## API Reference (`@llmtxt/core`) ### `generateLlmsTxt(options)` Generates `llms.txt` as a string. @@ -235,14 +235,14 @@ Generates `llms-full.txt` as a string (fetches pages and converts HTML→text/Ma --- -## Environment Variables (`@llmstxt/next`) +## Environment Variables (`@llmtxt/next`) | Variable | Purpose | |---|---| | `NEXT_PUBLIC_APP_URL` | Your public app root URL, e.g. `https://example.com` — recommended for production and local dev | | `VERCEL_URL` | Automatically set by Vercel; used as a fallback if `NEXT_PUBLIC_APP_URL` is missing | -> Note: When `NODE_ENV=development`, `@llmstxt/next` will default to `http://localhost:3000` if neither variable is set. For predictable results, always set `NEXT_PUBLIC_APP_URL` in `.env.local` or your deployment environment. +> Note: When `NODE_ENV=development`, `@llmtxt/next` will default to `http://localhost:3000` if neither variable is set. For predictable results, always set `NEXT_PUBLIC_APP_URL` in `.env.local` or your deployment environment. --- @@ -250,16 +250,16 @@ Generates `llms-full.txt` as a string (fetches pages and converts HTML→text/Ma This repository publishes three npm packages: -- `@llmstxt/core` — framework-agnostic generator for `llms.txt` and `llms-full.txt` -- `@llmstxt/next` — Next.js App Router route handlers for `llms.txt` and `llms-full.txt` -- `@llmstxt/middleware` — Next.js middleware that serves Markdown on `Accept: text/markdown` +- `@llmtxt/core` — framework-agnostic generator for `llms.txt` and `llms-full.txt` +- `@llmtxt/next` — Next.js App Router route handlers for `llms.txt` and `llms-full.txt` +- `@llmtxt/middleware` — Next.js middleware that serves Markdown on `Accept: text/markdown` Install only the packages you need: ```bash -npm install @llmstxt/core -npm install @llmstxt/next -npm install @llmstxt/middleware +npm install @llmtxt/core +npm install @llmtxt/next +npm install @llmtxt/middleware ``` See each package README for the full option reference. diff --git a/examples/README.md b/examples/README.md index 9902893..427dd05 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,8 +2,8 @@ This folder contains two example projects for local testing of the monorepo packages: -- `basic-test` — a simple TypeScript script that imports `@llmstxt/core` and generates `llms.txt` locally. -- `next-app-test` — a minimal Next.js App Router project that consumes `@llmstxt/next` and exposes `/llms.txt` and `/llms-full.txt`. +- `basic-test` — a simple TypeScript script that imports `@llmtxt/core` and generates `llms.txt` locally. +- `next-app-test` — a minimal Next.js App Router project that consumes `@llmtxt/next` and exposes `/llms.txt` and `/llms-full.txt`. ## Getting started diff --git a/examples/nextjs-test/README.md b/examples/nextjs-test/README.md index b0c3d73..65e9945 100644 --- a/examples/nextjs-test/README.md +++ b/examples/nextjs-test/README.md @@ -1,10 +1,10 @@ # LLMsText Next.js Example Application -This example demonstrates all features of the @llmstxt packages including: +This example demonstrates all features of the @llmtxt packages including: -- `@llmstxt/core` for scanning and generating documentation -- `@llmstxt/next` for Next.js route handlers -- `@llmstxt/middleware` for markdown content negotiation +- `@llmtxt/core` for scanning and generating documentation +- `@llmtxt/next` for Next.js route handlers +- `@llmtxt/middleware` for markdown content negotiation ## Features Demonstrated @@ -28,7 +28,7 @@ npm run build NEXT_PUBLIC_APP_URL=http://localhost:3000 ``` -> For local development, put this in `.env.local` so Next.js and `@llmstxt/next` can resolve your public site URL. +> For local development, put this in `.env.local` so Next.js and `@llmtxt/next` can resolve your public site URL. 1. Run the development server: diff --git a/examples/nextjs-test/app/about/page.tsx b/examples/nextjs-test/app/about/page.tsx index 2332e7b..2123469 100644 --- a/examples/nextjs-test/app/about/page.tsx +++ b/examples/nextjs-test/app/about/page.tsx @@ -2,7 +2,7 @@ import { Navigation, Card } from '@/components/widgets'; export const metadata = { title: 'About | LLMsText', - description: 'About the llmstxt project', + description: 'About the llmtxt project', }; export default function About() { @@ -39,15 +39,15 @@ export default function About() {

Our Packages

diff --git a/examples/nextjs-test/app/api-reference/page.tsx b/examples/nextjs-test/app/api-reference/page.tsx index 928863f..6b20105 100644 --- a/examples/nextjs-test/app/api-reference/page.tsx +++ b/examples/nextjs-test/app/api-reference/page.tsx @@ -2,7 +2,7 @@ import { Navigation, CodeBlock } from '@/components/widgets'; export const metadata = { title: 'API Reference | LLMsText', - description: 'API reference for llmstxt packages', + description: 'API reference for llmtxt packages', }; export default function APIReference() { @@ -11,11 +11,11 @@ export default function APIReference() {

API Reference

-

Complete API documentation for all llmstxt packages

+

Complete API documentation for all llmtxt packages

-

@llmstxt/core

+

@llmtxt/core

scanAppDirForPages(options)

@@ -56,7 +56,7 @@ export default function APIReference() {
-

@llmstxt/next

+

@llmtxt/next

createLlmsTxtHandler()

@@ -64,7 +64,7 @@ export default function APIReference() { Creates a Next.js route handler for the /llms.txt endpoint.

@@ -88,7 +88,7 @@ export const GET = createLlmsFullTxtHandler();`}
-

@llmstxt/middleware

+

@llmtxt/middleware

createMarkdownMiddleware(options)

@@ -96,7 +96,7 @@ export const GET = createLlmsFullTxtHandler();`} Creates Next.js middleware that serves markdown for requests with Accept: text/markdown header.

- We're excited to announce llmstxt, a framework-agnostic solution for automatically generating + We're excited to announce llmtxt, a framework-agnostic solution for automatically generating AI-friendly documentation from your Next.js applications.

diff --git a/examples/nextjs-test/app/docs/getting-started/page.tsx b/examples/nextjs-test/app/docs/getting-started/page.tsx index 32a1607..7f95084 100644 --- a/examples/nextjs-test/app/docs/getting-started/page.tsx +++ b/examples/nextjs-test/app/docs/getting-started/page.tsx @@ -2,7 +2,7 @@ import { Card, Navigation, CodeBlock } from '@/components/widgets'; export const metadata = { title: 'Getting Started | Docs', - description: 'Getting started with llmstxt documentation', + description: 'Getting started with llmtxt documentation', }; export default function GettingStarted() { @@ -32,9 +32,9 @@ export default function GettingStarted() {

Installation

- Install the @llmstxt packages using npm: + Install the @llmtxt packages using npm:

- +
@@ -44,7 +44,7 @@ export default function GettingStarted() {

diff --git a/examples/nextjs-test/app/features/page.tsx b/examples/nextjs-test/app/features/page.tsx index e985349..bb6dc77 100644 --- a/examples/nextjs-test/app/features/page.tsx +++ b/examples/nextjs-test/app/features/page.tsx @@ -2,7 +2,7 @@ import { Navigation, FeatureCard, Hero } from '@/components/widgets'; export const metadata = { title: 'Features | LLMsText', - description: 'Features of the llmstxt packages', + description: 'Features of the llmtxt packages', }; export default function Features() { diff --git a/examples/nextjs-test/app/llms-full.txt/route.ts b/examples/nextjs-test/app/llms-full.txt/route.ts index 00adebd..36ef253 100644 --- a/examples/nextjs-test/app/llms-full.txt/route.ts +++ b/examples/nextjs-test/app/llms-full.txt/route.ts @@ -1,3 +1,3 @@ -import { createLlmsFullTxtHandler } from '@llmstxt/next'; +import { createLlmsFullTxtHandler } from '@llmtxt/next'; export const GET = createLlmsFullTxtHandler(); diff --git a/examples/nextjs-test/app/llms.txt/route.ts b/examples/nextjs-test/app/llms.txt/route.ts index 70704f5..dd00145 100644 --- a/examples/nextjs-test/app/llms.txt/route.ts +++ b/examples/nextjs-test/app/llms.txt/route.ts @@ -1,8 +1,8 @@ -import { createLlmsTxtHandler } from '@llmstxt/next'; +import { createLlmsTxtHandler } from '@llmtxt/next'; // Create the handler with optional configuration export const GET = createLlmsTxtHandler({ title: 'LLMsText Example Application', summary: - 'This is a comprehensive example application demonstrating all features of the @llmstxt packages including documentation generation, middleware integration, and AI-friendly content serving.', + 'This is a comprehensive example application demonstrating all features of the @llmtxt packages including documentation generation, middleware integration, and AI-friendly content serving.', }); diff --git a/examples/nextjs-test/app/page.tsx b/examples/nextjs-test/app/page.tsx index 3996d2b..bde776a 100644 --- a/examples/nextjs-test/app/page.tsx +++ b/examples/nextjs-test/app/page.tsx @@ -2,7 +2,7 @@ import { Navigation, Hero, Card } from '@/components/widgets'; export const metadata = { title: 'Home | LLMsText Example App', - description: 'Testing all @llmstxt packages - core, next, and middleware', + description: 'Testing all @llmtxt packages - core, next, and middleware', }; export default function Home() { @@ -21,7 +21,7 @@ export default function Home() { />
diff --git a/examples/nextjs-test/app/pricing/page.tsx b/examples/nextjs-test/app/pricing/page.tsx index 628783c..734f159 100644 --- a/examples/nextjs-test/app/pricing/page.tsx +++ b/examples/nextjs-test/app/pricing/page.tsx @@ -2,7 +2,7 @@ import { Navigation, PricingPlan } from '@/components/widgets'; export const metadata = { title: 'Pricing | LLMsText', - description: 'Pricing plans for llmstxt', + description: 'Pricing plans for llmtxt', }; export default function Pricing() { diff --git a/examples/nextjs-test/middleware.ts b/examples/nextjs-test/middleware.ts index 3dfd188..aaea5bb 100644 --- a/examples/nextjs-test/middleware.ts +++ b/examples/nextjs-test/middleware.ts @@ -1,4 +1,4 @@ -import { createMarkdownMiddleware } from '@llmstxt/middleware'; +import { createMarkdownMiddleware } from '@llmtxt/middleware'; /** * Markdown middleware for serving markdown versions of pages diff --git a/examples/nextjs-test/package-lock.json b/examples/nextjs-test/package-lock.json index 21580b4..7637a83 100644 --- a/examples/nextjs-test/package-lock.json +++ b/examples/nextjs-test/package-lock.json @@ -8,9 +8,9 @@ "name": "nextjs-test", "version": "0.1.0", "dependencies": { - "@llmstxt/core": "file:../../packages/core", - "@llmstxt/middleware": "file:../../packages/middleware", - "@llmstxt/next": "file:../../packages/next", + "@llmtxt/core": "file:../../packages/core", + "@llmtxt/middleware": "file:../../packages/middleware", + "@llmtxt/next": "file:../../packages/next", "next": "16.2.6", "react": "19.2.4", "react-dom": "19.2.4" @@ -27,7 +27,7 @@ } }, "../../packages/core": { - "name": "@llmstxt/core", + "name": "@llmtxt/core", "version": "0.1.0", "license": "MIT", "engines": { @@ -35,7 +35,7 @@ } }, "../../packages/middleware": { - "name": "@llmstxt/middleware", + "name": "@llmtxt/middleware", "version": "0.1.0", "license": "MIT", "engines": { @@ -46,11 +46,14 @@ } }, "../../packages/next": { - "name": "@llmstxt/next", + "name": "@llmtxt/next", "version": "0.1.0", "license": "MIT", "dependencies": { - "@llmstxt/core": "^0.1.0" + "@llmtxt/core": "^0.1.0" + }, + "devDependencies": { + "@types/node": "^18.19.130" }, "engines": { "node": ">=18.0.0" @@ -1007,15 +1010,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@llmstxt/core": { + "node_modules/@llmtxt/core": { "resolved": "../../packages/core", "link": true }, - "node_modules/@llmstxt/middleware": { + "node_modules/@llmtxt/middleware": { "resolved": "../../packages/middleware", "link": true }, - "node_modules/@llmstxt/next": { + "node_modules/@llmtxt/next": { "resolved": "../../packages/next", "link": true }, diff --git a/examples/nextjs-test/package.json b/examples/nextjs-test/package.json index 54182b5..f6fcf30 100644 --- a/examples/nextjs-test/package.json +++ b/examples/nextjs-test/package.json @@ -9,9 +9,9 @@ "lint": "eslint" }, "dependencies": { - "@llmstxt/core": "file:../../packages/core", - "@llmstxt/next": "file:../../packages/next", - "@llmstxt/middleware": "file:../../packages/middleware", + "@llmtxt/core": "file:../../packages/core", + "@llmtxt/next": "file:../../packages/next", + "@llmtxt/middleware": "file:../../packages/middleware", "next": "16.2.6", "react": "19.2.4", "react-dom": "19.2.4" @@ -26,4 +26,4 @@ "tailwindcss": "^4", "typescript": "^5" } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index ecdc08a..ee83b0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "@llmstxt/monorepo", + "name": "@llmtxt/monorepo", "version": "0.0.0-development", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "@llmstxt/monorepo", + "name": "@llmtxt/monorepo", "license": "MIT", "workspaces": [ "packages/*" @@ -1853,15 +1853,15 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@llmstxt/core": { + "node_modules/@llmtxt/core": { "resolved": "packages/core", "link": true }, - "node_modules/@llmstxt/middleware": { + "node_modules/@llmtxt/middleware": { "resolved": "packages/middleware", "link": true }, - "node_modules/@llmstxt/next": { + "node_modules/@llmtxt/next": { "resolved": "packages/next", "link": true }, @@ -14453,7 +14453,7 @@ } }, "packages/core": { - "name": "@llmstxt/core", + "name": "@llmtxt/core", "version": "0.1.0", "license": "MIT", "engines": { @@ -14461,7 +14461,7 @@ } }, "packages/middleware": { - "name": "@llmstxt/middleware", + "name": "@llmtxt/middleware", "version": "0.1.0", "license": "MIT", "engines": { @@ -14472,11 +14472,11 @@ } }, "packages/next": { - "name": "@llmstxt/next", + "name": "@llmtxt/next", "version": "0.1.0", "license": "MIT", "dependencies": { - "@llmstxt/core": "^0.1.0" + "@llmtxt/core": "^0.1.0" }, "devDependencies": { "@types/node": "^18.19.130" @@ -15772,17 +15772,17 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "@llmstxt/core": { + "@llmtxt/core": { "version": "file:packages/core" }, - "@llmstxt/middleware": { + "@llmtxt/middleware": { "version": "file:packages/middleware", "requires": {} }, - "@llmstxt/next": { + "@llmtxt/next": { "version": "file:packages/next", "requires": { - "@llmstxt/core": "^0.1.0", + "@llmtxt/core": "^0.1.0", "@types/node": "^18.19.130" } }, diff --git a/package.json b/package.json index f92f1e5..e9986c6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "@llmstxt/monorepo", + "name": "@llmtxt/monorepo", "private": true, - "description": "Monorepo for @llmstxt (llms.txt, llms-full.txt, and Markdown for agents).", + "description": "Monorepo for @llmtxt (llms.txt, llms-full.txt, and Markdown for agents).", "license": "MIT", "workspaces": [ "packages/*" @@ -45,6 +45,6 @@ } }, "lint-staged": { - "*.ts": "eslint --cache --cache-location .eslintcache --fix" + "packages/**/*.ts": "eslint --cache --cache-location .eslintcache --fix" } } diff --git a/packages/core/README.md b/packages/core/README.md index 61ec7e7..77604cf 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -1,13 +1,13 @@ -# `@llmstxt/core` +# `@llmtxt/core` Framework-agnostic scanner & generator for `llms.txt` and `llms-full.txt` (see [llmstxt.org](https://llmstxt.org)). -Pairs with [`@llmstxt/next`](https://www.npmjs.com/package/@llmstxt/next) for Next.js route handlers and [`@llmstxt/middleware`](https://www.npmjs.com/package/@llmstxt/middleware) for Markdown content negotiation. +Pairs with [`@llmtxt/next`](https://www.npmjs.com/package/@llmtxt/next) for Next.js route handlers and [`@llmtxt/middleware`](https://www.npmjs.com/package/@llmtxt/middleware) for Markdown content negotiation. ## Install ```bash -npm install @llmstxt/core +npm install @llmtxt/core ``` > Requires Node.js 18+ (uses native `fetch()`). Provide a polyfill for older runtimes. @@ -15,7 +15,7 @@ npm install @llmstxt/core ## Quick start ```ts -import { generateLlmsTxt, generateLlmsFullTxt } from '@llmstxt/core' +import { generateLlmsTxt, generateLlmsFullTxt } from '@llmtxt/core' import path from 'path' const appDir = path.join(process.cwd(), 'src/app') @@ -40,7 +40,7 @@ const llmsFullTxt = await generateLlmsFullTxt({ ```ts import express from 'express' -import { generateLlmsTxt, generateLlmsFullTxt } from '@llmstxt/core' +import { generateLlmsTxt, generateLlmsFullTxt } from '@llmtxt/core' import path from 'path' const app = express() @@ -145,7 +145,7 @@ Inherits all shared options, plus: - [Advanced Usage](https://example.com/blog/advanced): Deep dives and recipes --- -*Generated by @llmstxt/core · 2026-01-01T00:00:00.000Z · 12 pages* +*Generated by @llmtxt/core · 2026-01-01T00:00:00.000Z · 12 pages* ``` ## Example output — `llms-full.txt` @@ -174,7 +174,7 @@ npm install turndown @mozilla/readability jsdom ``` ```ts -import { generateLlmsFullTxt } from '@llmstxt/core' +import { generateLlmsFullTxt } from '@llmtxt/core' import TurndownService from 'turndown' import { Readability } from '@mozilla/readability' import { JSDOM } from 'jsdom' diff --git a/packages/core/package.json b/packages/core/package.json index 86a1eb1..dc189e8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,5 +1,5 @@ { - "name": "@llmstxt/core", + "name": "@llmtxt/core", "version": "0.1.0", "description": "Framework-agnostic scanner & generator for llms.txt and llms-full.txt.", "license": "MIT", @@ -14,7 +14,7 @@ "llms", "llms.txt", "llms-full.txt", - "llmstxt", + "llmtxt", "ai", "llm", "seo", diff --git a/packages/core/src/generate.ts b/packages/core/src/generate.ts index 590413a..7a65159 100644 --- a/packages/core/src/generate.ts +++ b/packages/core/src/generate.ts @@ -57,7 +57,7 @@ async function fetchWithTimeout( try { const res = await fetch(url, { signal: controller.signal, - headers: { 'User-Agent': '@llmstxt/core' }, + headers: { 'User-Agent': '@llmtxt/core' }, }); if (!res.ok) throw new Error( @@ -103,7 +103,7 @@ export async function generateLlmsTxt( lines.push('---'); lines.push( - `*Generated by @llmstxt/core · ${isoNow()} · ${pages.length} pages*` + `*Generated by @llmtxt/core · ${isoNow()} · ${pages.length} pages*` ); lines.push(''); return lines.join('\n'); @@ -119,7 +119,7 @@ export async function generateLlmsFullTxt( lines.push('# llms-full.txt'); lines.push(''); lines.push( - `*Generated by @llmstxt/core · ${isoNow()} · ${pages.length} pages*` + `*Generated by @llmtxt/core · ${isoNow()} · ${pages.length} pages*` ); lines.push(''); lines.push('---'); diff --git a/packages/core/test/scan.spec.ts b/packages/core/test/scan.spec.ts index 0f8d395..006de69 100644 --- a/packages/core/test/scan.spec.ts +++ b/packages/core/test/scan.spec.ts @@ -4,7 +4,7 @@ import path from 'path'; import { scanAppDirForPages } from '../src'; async function mkTmpDir(): Promise { - return await fs.mkdtemp(path.join(os.tmpdir(), 'llmstxt-core-')); + return await fs.mkdtemp(path.join(os.tmpdir(), 'llmtxt-core-')); } async function writeFile(filePath: string, contents: string): Promise { @@ -12,7 +12,7 @@ async function writeFile(filePath: string, contents: string): Promise { await fs.writeFile(filePath, contents, 'utf8'); } -describe('@llmstxt/core scanAppDirForPages', () => { +describe('@llmtxt/core scanAppDirForPages', () => { it('scans Next.js app pages and extracts descriptions', async () => { const dir = await mkTmpDir(); const appDir = path.join(dir, 'src', 'app'); diff --git a/packages/middleware/README.md b/packages/middleware/README.md index 233af4a..31ca817 100644 --- a/packages/middleware/README.md +++ b/packages/middleware/README.md @@ -1,15 +1,15 @@ -# `@llmstxt/middleware` +# `@llmtxt/middleware` Next.js middleware that serves **any page as Markdown** when the request includes `Accept: text/markdown`. This implements the "Markdown for Agents" content-negotiation pattern: AI agents and LLMs can request a clean Markdown version of any page by sending `Accept: text/markdown`, while browsers continue to receive HTML normally. -Also see [`@llmstxt/next`](https://www.npmjs.com/package/@llmstxt/next) for `llms.txt` and `llms-full.txt` route handlers. +Also see [`@llmtxt/next`](https://www.npmjs.com/package/@llmtxt/next) for `llms.txt` and `llms-full.txt` route handlers. ## Install ```bash -npm install @llmstxt/middleware +npm install @llmtxt/middleware ``` **Peer dependency**: `next >= 13.0.0` @@ -18,7 +18,7 @@ npm install @llmstxt/middleware ```ts // middleware.ts (project root) -export { middleware, config } from '@llmstxt/middleware' +export { middleware, config } from '@llmtxt/middleware' ``` Test it: @@ -52,7 +52,7 @@ generated: "2026-01-01T00:00:00.000Z" ```ts // middleware.ts (project root) -import { createMarkdownMiddleware } from '@llmstxt/middleware' +import { createMarkdownMiddleware } from '@llmtxt/middleware' export const middleware = createMarkdownMiddleware({ contentSignal: 'ai-train=no, search=yes, ai-input=yes', @@ -95,7 +95,7 @@ npm install turndown @mozilla/readability jsdom ``` ```ts -import { createMarkdownMiddleware } from '@llmstxt/middleware' +import { createMarkdownMiddleware } from '@llmtxt/middleware' import TurndownService from 'turndown' import { Readability } from '@mozilla/readability' import { JSDOM } from 'jsdom' diff --git a/packages/middleware/package.json b/packages/middleware/package.json index e128c7d..46e052d 100644 --- a/packages/middleware/package.json +++ b/packages/middleware/package.json @@ -1,5 +1,5 @@ { - "name": "@llmstxt/middleware", + "name": "@llmtxt/middleware", "version": "0.1.0", "description": "Next.js middleware that serves Markdown when requests send Accept: text/markdown.", "license": "MIT", @@ -11,7 +11,7 @@ }, "homepage": "https://github.com/Muhammad-Hashim/llmstxt#readme", "keywords": [ - "llmstxt", + "llmtxt", "markdown", "markdown for agents", "content negotiation", diff --git a/packages/middleware/src/index.ts b/packages/middleware/src/index.ts index b0e9f69..b866725 100644 --- a/packages/middleware/src/index.ts +++ b/packages/middleware/src/index.ts @@ -301,7 +301,7 @@ export function createMarkdownMiddleware( Cookie: request.headers.get('cookie') ?? '', Authorization: request.headers.get('authorization') ?? '', 'Accept-Language': request.headers.get('accept-language') ?? '', - 'User-Agent': 'llmstxt-middleware/0.1.0', + 'User-Agent': 'llmtxt-middleware/0.1.0', }, redirect: 'manual', }); diff --git a/packages/next/README.md b/packages/next/README.md index 1a00bbf..65c14e7 100644 --- a/packages/next/README.md +++ b/packages/next/README.md @@ -1,13 +1,13 @@ -# `@llmstxt/next` +# `@llmtxt/next` Next.js App Router route handlers for `llms.txt` and `llms-full.txt` (see [llmstxt.org](https://llmstxt.org)). -Also see [`@llmstxt/core`](https://www.npmjs.com/package/@llmstxt/core) (framework-agnostic generator) and [`@llmstxt/middleware`](https://www.npmjs.com/package/@llmstxt/middleware) (Markdown content negotiation). +Also see [`@llmtxt/core`](https://www.npmjs.com/package/@llmtxt/core) (framework-agnostic generator) and [`@llmtxt/middleware`](https://www.npmjs.com/package/@llmtxt/middleware) (Markdown content negotiation). ## Install ```bash -npm install @llmstxt/next +npm install @llmtxt/next ``` **Peer dependency**: `next >= 13.0.0` @@ -46,7 +46,7 @@ For `llms.txt`: **`src/app/llms.txt/route.ts`**: ```ts -export { GET } from '@llmstxt/next' +export { GET } from '@llmtxt/next' ``` For `llms-full.txt`: @@ -54,7 +54,7 @@ For `llms-full.txt`: **`src/app/llms-full.txt/route.ts`**: ```ts -import { createLlmsFullTxtHandler } from '@llmstxt/next' +import { createLlmsFullTxtHandler } from '@llmtxt/next' export const GET = createLlmsFullTxtHandler() ``` @@ -65,7 +65,7 @@ Then visit `/llms.txt` and `/llms-full.txt`. **`src/app/llms.txt/route.ts`**: ```ts -import { createLlmsTxtHandler } from '@llmstxt/next' +import { createLlmsTxtHandler } from '@llmtxt/next' export const GET = createLlmsTxtHandler({ title: 'My App', @@ -78,7 +78,7 @@ export const GET = createLlmsTxtHandler({ **`src/app/llms-full.txt/route.ts`**: ```ts -import { createLlmsFullTxtHandler } from '@llmstxt/next' +import { createLlmsFullTxtHandler } from '@llmtxt/next' export const GET = createLlmsFullTxtHandler({ fetchTimeoutMs: 8000, @@ -116,13 +116,13 @@ All options are optional. `appDir` and `baseUrl` are resolved automatically from Both handlers set `Cache-Control: public, max-age=0, s-maxage=3600, stale-while-revalidate=86400` by default, giving you CDN-level caching with fast revalidation. -## With `@llmstxt/middleware` (optional) +## With `@llmtxt/middleware` (optional) To serve any page as Markdown on `Accept: text/markdown`, add a middleware file: ```ts // middleware.ts (project root) -export { middleware, config } from '@llmstxt/middleware' +export { middleware, config } from '@llmtxt/middleware' ``` -See [`@llmstxt/middleware`](https://www.npmjs.com/package/@llmstxt/middleware) for full options. +See [`@llmtxt/middleware`](https://www.npmjs.com/package/@llmtxt/middleware) for full options. diff --git a/packages/next/package.json b/packages/next/package.json index a2b84d6..920e112 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,5 +1,5 @@ { - "name": "@llmstxt/next", + "name": "@llmtxt/next", "version": "0.1.0", "description": "Next.js App Router route handlers for llms.txt and llms-full.txt.", "license": "MIT", @@ -14,7 +14,7 @@ "llms", "llms.txt", "llms-full.txt", - "llmstxt", + "llmtxt", "ai", "llm", "seo", @@ -40,7 +40,7 @@ "next": ">=13.0.0" }, "dependencies": { - "@llmstxt/core": "^0.1.0" + "@llmtxt/core": "^0.1.0" }, "scripts": { "build": "tsc -p tsconfig.build.json", diff --git a/packages/next/src/llms-full-txt-route.ts b/packages/next/src/llms-full-txt-route.ts index 319a441..9a5e839 100644 --- a/packages/next/src/llms-full-txt-route.ts +++ b/packages/next/src/llms-full-txt-route.ts @@ -1,6 +1,6 @@ import path from 'path'; -import { generateLlmsFullTxt } from '@llmstxt/core'; -import type { GenerateLlmsFullTxtOptions } from '@llmstxt/core'; +import { generateLlmsFullTxt } from '@llmtxt/core'; +import type { GenerateLlmsFullTxtOptions } from '@llmtxt/core'; import { resolveBaseUrlFromEnv, resolveNextAppDir } from './shared'; export function createLlmsFullTxtHandler( diff --git a/packages/next/src/llms-txt-route.ts b/packages/next/src/llms-txt-route.ts index fa2f75f..982cbaa 100644 --- a/packages/next/src/llms-txt-route.ts +++ b/packages/next/src/llms-txt-route.ts @@ -1,6 +1,6 @@ import path from 'path'; -import { generateLlmsTxt } from '@llmstxt/core'; -import type { GenerateLlmsTxtOptions } from '@llmstxt/core'; +import { generateLlmsTxt } from '@llmtxt/core'; +import type { GenerateLlmsTxtOptions } from '@llmtxt/core'; import { resolveBaseUrlFromEnv, resolveNextAppDir } from './shared'; export function createLlmsTxtHandler( From 098adb61c636402b9ec244439a9e8077645e0ca5 Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 20:56:13 +0500 Subject: [PATCH 3/9] chore: bump @llmtxt/next to 0.1.1 --- package-lock.json | 2 +- packages/next/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ee83b0e..5494d52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14473,7 +14473,7 @@ }, "packages/next": { "name": "@llmtxt/next", - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "dependencies": { "@llmtxt/core": "^0.1.0" diff --git a/packages/next/package.json b/packages/next/package.json index 920e112..213cafb 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@llmtxt/next", - "version": "0.1.0", + "version": "0.1.1", "description": "Next.js App Router route handlers for llms.txt and llms-full.txt.", "license": "MIT", "author": "Recordly", From 3738954142a071aa1988d4f7dac163070dc7e8a9 Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 20:58:06 +0500 Subject: [PATCH 4/9] chore: bump core and middleware to 0.1.1 --- package-lock.json | 4 ++-- packages/core/package.json | 2 +- packages/middleware/package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5494d52..921d8bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14454,7 +14454,7 @@ }, "packages/core": { "name": "@llmtxt/core", - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -14462,7 +14462,7 @@ }, "packages/middleware": { "name": "@llmtxt/middleware", - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "engines": { "node": ">=18.0.0" diff --git a/packages/core/package.json b/packages/core/package.json index dc189e8..c1764b4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@llmtxt/core", - "version": "0.1.0", + "version": "0.1.1", "description": "Framework-agnostic scanner & generator for llms.txt and llms-full.txt.", "license": "MIT", "author": "Recordly", diff --git a/packages/middleware/package.json b/packages/middleware/package.json index 46e052d..43f5dad 100644 --- a/packages/middleware/package.json +++ b/packages/middleware/package.json @@ -1,6 +1,6 @@ { "name": "@llmtxt/middleware", - "version": "0.1.0", + "version": "0.1.1", "description": "Next.js middleware that serves Markdown when requests send Accept: text/markdown.", "license": "MIT", "author": "Recordly", From 66307e278a44028142040a61b14606f3c8c8bb93 Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 21:05:50 +0500 Subject: [PATCH 5/9] chore: bump @llmtxt/next to 0.1.2 --- package-lock.json | 2 +- packages/next/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 921d8bf..4317d23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14473,7 +14473,7 @@ }, "packages/next": { "name": "@llmtxt/next", - "version": "0.1.1", + "version": "0.1.2", "license": "MIT", "dependencies": { "@llmtxt/core": "^0.1.0" diff --git a/packages/next/package.json b/packages/next/package.json index 213cafb..7c404f3 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@llmtxt/next", - "version": "0.1.1", + "version": "0.1.2", "description": "Next.js App Router route handlers for llms.txt and llms-full.txt.", "license": "MIT", "author": "Recordly", From 9860f0787a7ec7d652bcc24b5570abc0a3524bd9 Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 21:09:16 +0500 Subject: [PATCH 6/9] feat: add @llmtxt/react --- README.md | 45 ++++++++ packages/react/README.md | 81 ++++++++++++++ packages/react/package.json | 47 +++++++++ packages/react/src/index.ts | 164 +++++++++++++++++++++++++++++ packages/react/tsconfig.build.json | 13 +++ packages/react/tsconfig.json | 9 ++ 6 files changed, 359 insertions(+) create mode 100644 packages/react/README.md create mode 100644 packages/react/package.json create mode 100644 packages/react/src/index.ts create mode 100644 packages/react/tsconfig.build.json create mode 100644 packages/react/tsconfig.json diff --git a/README.md b/README.md index 5823954..3640485 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Generate `llms.txt` (table of contents) and `llms-full.txt` (full content) from | [`@llmtxt/core`](./packages/core) | Scan your `app/` directory and generate `llms.txt` + `llms-full.txt` | | [`@llmtxt/next`](./packages/next) | Next.js App Router route handlers for `/llms.txt` and `/llms-full.txt` | | [`@llmtxt/middleware`](./packages/middleware) | Next.js middleware: any page responds as Markdown on `Accept: text/markdown` | +| [`@llmtxt/react`](./packages/react) | Build-time helpers for React SPAs: generate `llms.txt` + `llms-full.txt` from a route list | ## Keywords (SEO) @@ -21,6 +22,7 @@ llms.txt, llms-full.txt, llmtxt, markdown for agents, content negotiation, Next. - [Quick Start — Next.js (App Router)](#quick-start--nextjs-app-router) - [Quick Start — Markdown for Agents (Next.js Middleware)](#quick-start--markdown-for-agents-nextjs-middleware) +- [Quick Start — React (Build-time, no backend)](#quick-start--react-build-time-no-backend) - [Quick Start — Other Frameworks](#quick-start--other-frameworks-express-hono-bun-etc) - [How It Works](#how-it-works) - [API Reference (`@llmtxt/core`)](#api-reference-llmtxtcore) @@ -131,6 +133,49 @@ For best Markdown quality in production, plug in `@mozilla/readability` + `turnd --- +## Quick Start — React (Build-time, no backend) + +For React SPAs (Vite/CRA/React Router), generate the files at build time and ship them from `public/`. + +```bash +npm install -D @llmtxt/react +``` + +Create a route list: + +```ts +// llmtxt.routes.ts +import type { LlmtxtRoute } from '@llmtxt/react' + +export const routes: LlmtxtRoute[] = [ + { path: '/', title: 'Home', description: 'What this site is about.' }, + { path: '/docs', title: 'Docs' }, +] +``` + +Generate: + +```ts +// scripts/generate-llms.ts +import path from 'path' +import { writeLlmsFiles } from '@llmtxt/react' +import { routes } from '../llmtxt.routes' + +await writeLlmsFiles({ + routes, + baseUrl: process.env.PUBLIC_SITE_URL!, // e.g. https://example.com + outDir: path.join(process.cwd(), 'public'), +}) +``` + +Run it after deploy (recommended) or against a preview server: + +```bash +PUBLIC_SITE_URL=https://example.com node scripts/generate-llms.ts +``` + +--- + ## Quick Start — Other Frameworks (Express, Hono, Bun, etc.) ```bash diff --git a/packages/react/README.md b/packages/react/README.md new file mode 100644 index 0000000..914cfc0 --- /dev/null +++ b/packages/react/README.md @@ -0,0 +1,81 @@ +# `@llmtxt/react` + +Build-time helpers for React SPAs to generate `llms.txt` and `llms-full.txt` **without a backend**. + +React apps (Vite/CRA/React Router) don’t have a universal “pages directory” like Next.js App Router, so this package works by taking an **explicit route list** and generating files into your `public/` (or `dist/`) folder during CI/build. + +--- + +## Install + +```bash +npm install -D @llmtxt/react +``` + +--- + +## 1) Create a route list + +Create `llmtxt.routes.ts`: + +```ts +import type { LlmtxtRoute } from '@llmtxt/react' + +export const routes: LlmtxtRoute[] = [ + { path: '/', title: 'Home', description: 'What this site is about.' }, + { path: '/docs', title: 'Docs', description: 'Documentation index.' }, + { path: '/pricing', title: 'Pricing' }, +] +``` + +--- + +## 2) Generate `public/llms.txt` and `public/llms-full.txt` + +Create `scripts/generate-llms.ts`: + +```ts +import path from 'path' +import { writeLlmsFiles } from '@llmtxt/react' +import { routes } from '../llmtxt.routes' + +await writeLlmsFiles({ + routes, + baseUrl: process.env.PUBLIC_SITE_URL!, // e.g. https://example.com + outDir: path.join(process.cwd(), 'public'), +}) +``` + +Run it in CI after deploy (recommended) or against a preview server: + +```bash +PUBLIC_SITE_URL=https://example.com node scripts/generate-llms.ts +``` + +--- + +## How it works + +- `llms.txt` is generated purely from your route list (titles + descriptions). +- `llms-full.txt` fetches each route from `baseUrl` and converts the returned HTML into Markdown using a built-in dependency-free converter (you can override it). + +--- + +## API + +### `writeLlmsFiles(options)` + +Writes: +- `llms.txt` +- `llms-full.txt` + +### Options + +| Option | Type | Required | Description | +|---|---|---:|---| +| `routes` | `LlmtxtRoute[]` | yes | Routes to include | +| `baseUrl` | `string` | yes | Public base URL (no trailing slash) | +| `outDir` | `string` | yes | Folder to write files (e.g. `public`) | +| `fetchTimeoutMs` | `number` | no | Per-page fetch timeout | +| `htmlToMarkdown` | `(html, url) => string \| Promise` | no | Custom converter | + diff --git a/packages/react/package.json b/packages/react/package.json new file mode 100644 index 0000000..a7471c4 --- /dev/null +++ b/packages/react/package.json @@ -0,0 +1,47 @@ +{ + "name": "@llmtxt/react", + "version": "0.1.0", + "description": "Build-time helpers for React SPAs to generate llms.txt and llms-full.txt from an explicit route list.", + "license": "MIT", + "author": "Recordly", + "repository": { + "type": "git", + "url": "https://github.com/Muhammad-Hashim/llmstxt.git", + "directory": "packages/react" + }, + "homepage": "https://github.com/Muhammad-Hashim/llmstxt#readme", + "keywords": [ + "llmtxt", + "llms", + "llms.txt", + "llms-full.txt", + "react", + "spa", + "seo", + "ai", + "llm" + ], + "type": "commonjs", + "main": "./lib/index.js", + "types": "./lib/index.d.ts", + "readme": "README.md", + "files": [ + "lib/**/*" + ], + "exports": { + ".": { + "types": "./lib/index.d.ts", + "default": "./lib/index.js" + } + }, + "dependencies": {}, + "scripts": { + "build": "tsc -p tsconfig.build.json", + "prepare": "npm run build", + "clean": "node ../../scripts/rmrf.js lib" + }, + "engines": { + "node": ">=18.0.0" + } +} + diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts new file mode 100644 index 0000000..8252d2f --- /dev/null +++ b/packages/react/src/index.ts @@ -0,0 +1,164 @@ +import fs from 'fs/promises'; +import path from 'path'; + +export type LlmtxtRoute = { + path: string; + title: string; + description?: string; +}; + +export type WriteLlmsFilesOptions = { + routes: LlmtxtRoute[]; + baseUrl: string; + outDir: string; + fetchTimeoutMs?: number; + htmlToMarkdown?: (html: string, url: string) => Promise | string; +}; + +function normalizeBaseUrl(baseUrl: string): string { + return baseUrl.replace(/\/+$/, ''); +} + +function isoNow(): string { + return new Date().toISOString(); +} + +function stripHtmlToText(html: string): string { + return html + .replace(//gi, '') + .replace(//gi, '') + .replace(/<\/(p|div|section|article|h\d|li|ul|ol|br)\s*>/gi, '\n') + .replace(/<[^>]+>/g, '') + .replace(/ /g, ' ') + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/'/g, "'") + .replace(/"/g, '"') + .replace(/[ \t]+\n/g, '\n') + .replace(/\n{3,}/g, '\n\n') + .trim(); +} + +async function fetchWithTimeout(url: string, timeoutMs: number): Promise { + if (typeof fetch !== 'function') { + throw new Error( + 'Global fetch() is not available. Use Node.js >= 18 or provide a fetch polyfill.' + ); + } + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), timeoutMs); + try { + const res = await fetch(url, { + signal: controller.signal, + headers: { 'User-Agent': '@llmtxt/react' }, + }); + if (!res.ok) { + throw new Error(`Fetch failed for ${url}: ${res.status} ${res.statusText}`); + } + return await res.text(); + } finally { + clearTimeout(timeout); + } +} + +export async function generateLlmsTxtFromRoutes(options: { + routes: LlmtxtRoute[]; + baseUrl: string; + title?: string; + summary?: string; +}): Promise { + const title = options.title ?? 'Documentation'; + const baseUrl = normalizeBaseUrl(options.baseUrl); + const routes = [...options.routes].sort((a, b) => a.path.localeCompare(b.path)); + + const lines: string[] = []; + lines.push(`# ${title}`); + if (options.summary) { + lines.push(''); + lines.push(`> ${options.summary}`); + } + lines.push(''); + + for (const route of routes) { + const url = `${baseUrl}${route.path === '/' ? '' : route.path}`; + const suffix = route.description ? `: ${route.description}` : ''; + lines.push(`- [${route.title}](${url})${suffix}`); + } + + lines.push(''); + lines.push('---'); + lines.push(`*Generated by @llmtxt/react · ${isoNow()} · ${routes.length} pages*`); + lines.push(''); + return lines.join('\n'); +} + +export async function generateLlmsFullTxtFromRoutes(options: { + routes: LlmtxtRoute[]; + baseUrl: string; + fetchTimeoutMs?: number; + htmlToMarkdown?: (html: string, url: string) => Promise | string; +}): Promise { + const baseUrl = normalizeBaseUrl(options.baseUrl); + const routes = [...options.routes].sort((a, b) => a.path.localeCompare(b.path)); + const fetchTimeoutMs = options.fetchTimeoutMs ?? 8000; + + const lines: string[] = []; + lines.push('# llms-full.txt'); + lines.push(''); + lines.push(`*Generated by @llmtxt/react · ${isoNow()} · ${routes.length} pages*`); + lines.push(''); + lines.push('---'); + lines.push(''); + + for (const route of routes) { + const url = `${baseUrl}${route.path === '/' ? '' : route.path}`; + lines.push(`## ${route.title}`); + lines.push(''); + lines.push(url); + lines.push(''); + try { + const html = await fetchWithTimeout(url, fetchTimeoutMs); + const markdown = + typeof options.htmlToMarkdown === 'function' + ? await options.htmlToMarkdown(html, url) + : stripHtmlToText(html); + lines.push(markdown.trim()); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + lines.push(`(Failed to fetch or convert content: ${msg})`); + } + lines.push(''); + lines.push('---'); + lines.push(''); + } + + return lines.join('\n'); +} + +export async function writeLlmsFiles(options: WriteLlmsFilesOptions): Promise<{ + llmsTxtPath: string; + llmsFullTxtPath: string; +}> { + const outDir = path.resolve(options.outDir); + await fs.mkdir(outDir, { recursive: true }); + + const llmsTxt = await generateLlmsTxtFromRoutes({ + routes: options.routes, + baseUrl: options.baseUrl, + }); + const llmsFullTxt = await generateLlmsFullTxtFromRoutes({ + routes: options.routes, + baseUrl: options.baseUrl, + fetchTimeoutMs: options.fetchTimeoutMs, + htmlToMarkdown: options.htmlToMarkdown, + }); + + const llmsTxtPath = path.join(outDir, 'llms.txt'); + const llmsFullTxtPath = path.join(outDir, 'llms-full.txt'); + await fs.writeFile(llmsTxtPath, llmsTxt, 'utf8'); + await fs.writeFile(llmsFullTxtPath, llmsFullTxt, 'utf8'); + + return { llmsTxtPath, llmsFullTxtPath }; +} + diff --git a/packages/react/tsconfig.build.json b/packages/react/tsconfig.build.json new file mode 100644 index 0000000..6feccc5 --- /dev/null +++ b/packages/react/tsconfig.build.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "noEmit": false + }, + "include": ["src/**/*.ts"] +} + diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json new file mode 100644 index 0000000..f7a8479 --- /dev/null +++ b/packages/react/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "./lib" + }, + "include": ["src/**/*.ts"] +} + From 0e81778c9e73fb5b20489641a2b8dedc8649d57d Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 21:49:34 +0500 Subject: [PATCH 7/9] feat: improve @llmtxt/react for SPA and dynamic routes --- examples/my-react-app/.gitignore | 24 + examples/my-react-app/README.md | 145 + examples/my-react-app/eslint.config.js | 21 + examples/my-react-app/index.html | 13 + examples/my-react-app/llmtxt.routes.js | 14 + examples/my-react-app/package-lock.json | 2322 +++++++++++++++++ examples/my-react-app/package.json | 30 + examples/my-react-app/public/favicon.svg | 1 + examples/my-react-app/public/icons.svg | 24 + examples/my-react-app/public/llms-full.txt | 101 + examples/my-react-app/public/llms.txt | 17 + .../my-react-app/scripts/generate-llms.js | 43 + examples/my-react-app/src/App.css | 850 ++++++ examples/my-react-app/src/App.jsx | 63 + examples/my-react-app/src/assets/hero.png | Bin 0 -> 13057 bytes examples/my-react-app/src/assets/react.svg | 1 + examples/my-react-app/src/assets/vite.svg | 1 + examples/my-react-app/src/index.css | 111 + examples/my-react-app/src/main.jsx | 10 + examples/my-react-app/src/pages/About.jsx | 53 + examples/my-react-app/src/pages/Blog.jsx | 52 + examples/my-react-app/src/pages/BlogPost.jsx | 146 ++ examples/my-react-app/src/pages/Contact.jsx | 53 + examples/my-react-app/src/pages/Docs.jsx | 49 + examples/my-react-app/src/pages/DocsAPI.jsx | 89 + .../src/pages/DocsGettingStarted.jsx | 53 + examples/my-react-app/src/pages/FAQ.jsx | 65 + examples/my-react-app/src/pages/Features.jsx | 72 + examples/my-react-app/src/pages/Home.jsx | 44 + examples/my-react-app/src/pages/Pricing.jsx | 58 + examples/my-react-app/vite.config.js | 7 + package-lock.json | 15 + packages/react/README.md | 73 +- packages/react/package.json | 3 +- packages/react/src/index.ts | 52 +- 35 files changed, 4632 insertions(+), 43 deletions(-) create mode 100644 examples/my-react-app/.gitignore create mode 100644 examples/my-react-app/README.md create mode 100644 examples/my-react-app/eslint.config.js create mode 100644 examples/my-react-app/index.html create mode 100644 examples/my-react-app/llmtxt.routes.js create mode 100644 examples/my-react-app/package-lock.json create mode 100644 examples/my-react-app/package.json create mode 100644 examples/my-react-app/public/favicon.svg create mode 100644 examples/my-react-app/public/icons.svg create mode 100644 examples/my-react-app/public/llms-full.txt create mode 100644 examples/my-react-app/public/llms.txt create mode 100644 examples/my-react-app/scripts/generate-llms.js create mode 100644 examples/my-react-app/src/App.css create mode 100644 examples/my-react-app/src/App.jsx create mode 100644 examples/my-react-app/src/assets/hero.png create mode 100644 examples/my-react-app/src/assets/react.svg create mode 100644 examples/my-react-app/src/assets/vite.svg create mode 100644 examples/my-react-app/src/index.css create mode 100644 examples/my-react-app/src/main.jsx create mode 100644 examples/my-react-app/src/pages/About.jsx create mode 100644 examples/my-react-app/src/pages/Blog.jsx create mode 100644 examples/my-react-app/src/pages/BlogPost.jsx create mode 100644 examples/my-react-app/src/pages/Contact.jsx create mode 100644 examples/my-react-app/src/pages/Docs.jsx create mode 100644 examples/my-react-app/src/pages/DocsAPI.jsx create mode 100644 examples/my-react-app/src/pages/DocsGettingStarted.jsx create mode 100644 examples/my-react-app/src/pages/FAQ.jsx create mode 100644 examples/my-react-app/src/pages/Features.jsx create mode 100644 examples/my-react-app/src/pages/Home.jsx create mode 100644 examples/my-react-app/src/pages/Pricing.jsx create mode 100644 examples/my-react-app/vite.config.js diff --git a/examples/my-react-app/.gitignore b/examples/my-react-app/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/examples/my-react-app/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/my-react-app/README.md b/examples/my-react-app/README.md new file mode 100644 index 0000000..6cd1a78 --- /dev/null +++ b/examples/my-react-app/README.md @@ -0,0 +1,145 @@ +# React Demo App with @llmtxt/react + +A comprehensive example React application demonstrating how to use `@llmtxt/react` to generate AI-friendly documentation from your Vite + React SPA. + +## Features + +- **11+ Demo Pages** including Home, Docs, Pricing, Blog, and more +- **React Router** for full SPA navigation +- **Responsive Design** with modern CSS styling +- **@llmtxt/react Integration** for automatic documentation generation + +## Pages Included + +### Core Pages + +- **Home** (`/`) - Welcome and feature overview +- **Documentation** (`/docs`) - Documentation index + - Getting Started (`/docs/getting-started`) + - API Reference (`/docs/api`) +- **Features** (`/features`) - Feature showcase +- **Pricing** (`/pricing`) - Pricing plans +- **Blog** (`/blog`) - Blog post listing + - Individual Posts (`/blog/:slug`) +- **About** (`/about`) - About page +- **Contact** (`/contact`) - Contact form +- **FAQ** (`/faq`) - Frequently asked questions + +## Setup + +### 1. Install Dependencies + +```bash +npm install +``` + +### 2. Development Server + +```bash +npm run dev +``` + +Then visit `http://localhost:5173` + +### 3. Generate Documentation + +After deploying your app, generate the documentation: + +```bash +PUBLIC_SITE_URL=http://localhost:5173 npm run generate:llms +``` + +> Note: Because this is a client-rendered SPA, plain fetch() returns `index.html` for every route. +> For “real” `llms-full.txt` content, use prerender/SSR HTML, provide `route.markdown`, or render with Playwright: +> +> ```bash +> npm i -D playwright +> LLMTXT_RENDER=playwright PUBLIC_SITE_URL=http://localhost:5173 npm run generate:llms +> ``` + +This creates: + +- `public/llms.txt` - Lightweight documentation index +- `public/llms-full.txt` - Full documentation with page content + +## How It Works + +1. **Route List** (`llmtxt.routes.js`): + - Defines all routes to document + - Each route has path, title, and optional description + +2. **Generation Script** (`scripts/generate-llms.js`): + - Fetches each route from your running app + - Converts HTML to Markdown + - Writes documentation files to `public/` + +3. **Build Process**: + - `npm run build` runs Vite build + generation script + - Files are included in your deployment + +## File Structure + +``` +my-react-app/ +├── src/ +│ ├── pages/ # Individual page components +│ ├── App.jsx # Main app with routing +│ ├── App.css # Styling +│ └── main.jsx # Entry point +├── scripts/ +│ └── generate-llms.js # Documentation generator +├── llmtxt.routes.js # Route configuration +└── package.json # Dependencies +``` + +## Customization + +### Add a New Page + +1. Create a component in `src/pages/MyPage.jsx` +2. Add route to `App.jsx` +3. Add entry to `llmtxt.routes.js` + +### Customize Documentation Generation + +Edit `scripts/generate-llms.js`: + +```js +await writeLlmsFiles({ + routes, + baseUrl: process.env.PUBLIC_SITE_URL || 'http://localhost:5173', + outDir: path.join(process.cwd(), 'public'), + fetchTimeoutMs: 5000, // Per-page timeout + // htmlToMarkdown: customConverter // Optional custom converter +}) +``` + +## Viewing Generated Documentation + +After running `npm run generate:llms`: + +```bash +cat public/llms.txt # Lightweight index +cat public/llms-full.txt # Full documentation +``` + +## Environment Variables + +- `PUBLIC_SITE_URL` - Your app's public URL (used for documentation generation) + +For local development: + +```bash +PUBLIC_SITE_URL=http://localhost:5173 +``` + +For production: + +```bash +PUBLIC_SITE_URL=https://your-app.com +``` + +## Learn More + +- [@llmtxt/react](../../packages/react/) - Package documentation +- [llmstxt.org](https://llmstxt.org) - Format specification diff --git a/examples/my-react-app/eslint.config.js b/examples/my-react-app/eslint.config.js new file mode 100644 index 0000000..ea36dd3 --- /dev/null +++ b/examples/my-react-app/eslint.config.js @@ -0,0 +1,21 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + globals: globals.browser, + parserOptions: { ecmaFeatures: { jsx: true } }, + }, + }, +]) diff --git a/examples/my-react-app/index.html b/examples/my-react-app/index.html new file mode 100644 index 0000000..7b228d7 --- /dev/null +++ b/examples/my-react-app/index.html @@ -0,0 +1,13 @@ + + + + + + + my-react-app + + +
+ + + diff --git a/examples/my-react-app/llmtxt.routes.js b/examples/my-react-app/llmtxt.routes.js new file mode 100644 index 0000000..24964b9 --- /dev/null +++ b/examples/my-react-app/llmtxt.routes.js @@ -0,0 +1,14 @@ +export const routes = [ + { path: '/', title: 'Home', description: 'Welcome to our demo React application' }, + { path: '/docs', title: 'Documentation', description: 'Complete documentation and guides' }, + { path: '/docs/getting-started', title: 'Getting Started', description: 'Quick start guide' }, + { path: '/docs/api', title: 'API Reference', description: 'Full API documentation' }, + { path: '/features', title: 'Features', description: 'Core features and capabilities' }, + { path: '/pricing', title: 'Pricing', description: 'Pricing plans and billing' }, + { path: '/blog', title: 'Blog', description: 'Latest blog posts and articles' }, + { path: '/blog/introducing-v2', title: 'Introducing v2', description: 'Major release announcement' }, + { path: '/blog/best-practices', title: 'Best Practices', description: 'Development best practices' }, + { path: '/about', title: 'About', description: 'About our company and mission' }, + { path: '/contact', title: 'Contact', description: 'Get in touch with us' }, + { path: '/faq', title: 'FAQ', description: 'Frequently asked questions' }, +] diff --git a/examples/my-react-app/package-lock.json b/examples/my-react-app/package-lock.json new file mode 100644 index 0000000..219fec9 --- /dev/null +++ b/examples/my-react-app/package-lock.json @@ -0,0 +1,2322 @@ +{ + "name": "my-react-app", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "my-react-app", + "version": "0.0.0", + "dependencies": { + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-router-dom": "^7.15.0" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@llmtxt/react": "file:../../packages/react", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.6.0", + "vite": "^8.0.12" + } + }, + "../../packages/react": { + "name": "@llmtxt/react", + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", + "dev": true, + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", + "dev": true, + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@llmtxt/react": { + "resolved": "../../packages/react", + "link": true + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.129.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.129.0.tgz", + "integrity": "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz", + "integrity": "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz", + "integrity": "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz", + "integrity": "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0.tgz", + "integrity": "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0.tgz", + "integrity": "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz", + "integrity": "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz", + "integrity": "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0.tgz", + "integrity": "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0.tgz", + "integrity": "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz", + "integrity": "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz", + "integrity": "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0.tgz", + "integrity": "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0.tgz", + "integrity": "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz", + "integrity": "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz", + "integrity": "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.29", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz", + "integrity": "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.353", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.353.tgz", + "integrity": "sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.3.0.tgz", + "integrity": "sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", + "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", + "dev": true, + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.44", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz", + "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", + "dev": true + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.6" + } + }, + "node_modules/react-router": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.15.0.tgz", + "integrity": "sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.15.0.tgz", + "integrity": "sha512-VcrVg64Fo8nwBvDscajG8gRTLIuTC6N50nb22l2HOOV4PTOHgoGp8mUjy9wLiHYoYTSYI36tUnXZgasSRFZorQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.15.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/rolldown": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz", + "integrity": "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==", + "dev": true, + "dependencies": { + "@oxc-project/types": "=0.129.0", + "@rolldown/pluginutils": "1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0", + "@rolldown/binding-darwin-arm64": "1.0.0", + "@rolldown/binding-darwin-x64": "1.0.0", + "@rolldown/binding-freebsd-x64": "1.0.0", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0", + "@rolldown/binding-linux-arm64-gnu": "1.0.0", + "@rolldown/binding-linux-arm64-musl": "1.0.0", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0", + "@rolldown/binding-linux-s390x-gnu": "1.0.0", + "@rolldown/binding-linux-x64-gnu": "1.0.0", + "@rolldown/binding-linux-x64-musl": "1.0.0", + "@rolldown/binding-openharmony-arm64": "1.0.0", + "@rolldown/binding-wasm32-wasi": "1.0.0", + "@rolldown/binding-win32-arm64-msvc": "1.0.0", + "@rolldown/binding-win32-x64-msvc": "1.0.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0.tgz", + "integrity": "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "8.0.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.12.tgz", + "integrity": "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==", + "dev": true, + "peer": true, + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.14", + "rolldown": "1.0.0", + "tinyglobby": "^0.2.16" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/examples/my-react-app/package.json b/examples/my-react-app/package.json new file mode 100644 index 0000000..492b204 --- /dev/null +++ b/examples/my-react-app/package.json @@ -0,0 +1,30 @@ +{ + "name": "my-react-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build && npm run generate:llms", + "generate:llms": "node scripts/generate-llms.js", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-router-dom": "^7.15.0" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@llmtxt/react": "file:../../packages/react", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.6.0", + "vite": "^8.0.12" + } +} \ No newline at end of file diff --git a/examples/my-react-app/public/favicon.svg b/examples/my-react-app/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/examples/my-react-app/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/my-react-app/public/icons.svg b/examples/my-react-app/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/examples/my-react-app/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/my-react-app/public/llms-full.txt b/examples/my-react-app/public/llms-full.txt new file mode 100644 index 0000000..dca08f9 --- /dev/null +++ b/examples/my-react-app/public/llms-full.txt @@ -0,0 +1,101 @@ +# llms-full.txt + +*Generated by @llmtxt/react · 2026-05-12T16:29:03.935Z · 12 pages* + +--- + +## Home + +http://localhost:5173 + +my-react-app + +--- + +## About + +http://localhost:5173/about + +my-react-app + +--- + +## Blog + +http://localhost:5173/blog + +my-react-app + +--- + +## Best Practices + +http://localhost:5173/blog/best-practices + +my-react-app + +--- + +## Introducing v2 + +http://localhost:5173/blog/introducing-v2 + +my-react-app + +--- + +## Contact + +http://localhost:5173/contact + +my-react-app + +--- + +## Documentation + +http://localhost:5173/docs + +my-react-app + +--- + +## API Reference + +http://localhost:5173/docs/api + +my-react-app + +--- + +## Getting Started + +http://localhost:5173/docs/getting-started + +my-react-app + +--- + +## FAQ + +http://localhost:5173/faq + +my-react-app + +--- + +## Features + +http://localhost:5173/features + +my-react-app + +--- + +## Pricing + +http://localhost:5173/pricing + +my-react-app + +--- diff --git a/examples/my-react-app/public/llms.txt b/examples/my-react-app/public/llms.txt new file mode 100644 index 0000000..e52208b --- /dev/null +++ b/examples/my-react-app/public/llms.txt @@ -0,0 +1,17 @@ +# Documentation + +- [Home](http://localhost:5173): Welcome to our demo React application +- [About](http://localhost:5173/about): About our company and mission +- [Blog](http://localhost:5173/blog): Latest blog posts and articles +- [Best Practices](http://localhost:5173/blog/best-practices): Development best practices +- [Introducing v2](http://localhost:5173/blog/introducing-v2): Major release announcement +- [Contact](http://localhost:5173/contact): Get in touch with us +- [Documentation](http://localhost:5173/docs): Complete documentation and guides +- [API Reference](http://localhost:5173/docs/api): Full API documentation +- [Getting Started](http://localhost:5173/docs/getting-started): Quick start guide +- [FAQ](http://localhost:5173/faq): Frequently asked questions +- [Features](http://localhost:5173/features): Core features and capabilities +- [Pricing](http://localhost:5173/pricing): Pricing plans and billing + +--- +*Generated by @llmtxt/react · 2026-05-12T16:29:03.933Z · 12 pages* diff --git a/examples/my-react-app/scripts/generate-llms.js b/examples/my-react-app/scripts/generate-llms.js new file mode 100644 index 0000000..f249f47 --- /dev/null +++ b/examples/my-react-app/scripts/generate-llms.js @@ -0,0 +1,43 @@ +import path from 'path' +import { writeLlmsFiles } from '@llmtxt/react' +import { routes } from '../llmtxt.routes.js' + +const baseUrl = process.env.PUBLIC_SITE_URL || 'http://localhost:5173' +const outDir = path.join(process.cwd(), 'public') +const renderMode = (process.env.LLMTXT_RENDER || '').toLowerCase() + +console.log('Generating llms.txt files...') +console.log(` Base URL: ${baseUrl}`) +console.log(` Output: ${outDir}`) +console.log(` Routes: ${routes.length}`) + +async function fetchHtmlWithPlaywright(url, timeoutMs) { + const { chromium } = await import('playwright') + const browser = await chromium.launch() + try { + const page = await browser.newPage() + page.setDefaultNavigationTimeout(timeoutMs) + await page.goto(url, { waitUntil: 'networkidle' }) + return await page.content() + } finally { + await browser.close() + } +} + +await writeLlmsFiles({ + routes, + baseUrl, + outDir, + title: 'React Demo App', + summary: 'Comprehensive demo React application showcasing @llmtxt/react integration', + + // React SPAs are client-rendered. Plain fetch() returns index.html for every route. + // To capture real rendered HTML, set: LLMTXT_RENDER=playwright and install playwright. + fetchHtml: + renderMode === 'playwright' + ? (url, timeoutMs) => fetchHtmlWithPlaywright(url, timeoutMs) + : undefined, +}) + +console.log('✓ Generated llms.txt and llms-full.txt') + diff --git a/examples/my-react-app/src/App.css b/examples/my-react-app/src/App.css new file mode 100644 index 0000000..d288421 --- /dev/null +++ b/examples/my-react-app/src/App.css @@ -0,0 +1,850 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --primary: #0066cc; + --primary-dark: #004499; + --secondary: #666; + --light: #f5f5f5; + --border: #ddd; + --text: #333; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif; + line-height: 1.6; + color: var(--text); + background: #fff; +} + +.app { + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* Header & Navigation */ +.header { + background: var(--text); + color: white; + padding: 1rem 0; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.nav { + max-width: 1200px; + margin: 0 auto; + padding: 0 2rem; + display: flex; + align-items: center; + justify-content: space-between; +} + +.logo { + font-size: 1.5rem; + font-weight: bold; + color: white; + text-decoration: none; + margin-right: 3rem; +} + +.nav-links { + display: flex; + list-style: none; + gap: 2rem; + flex: 1; +} + +.nav-links a { + color: white; + text-decoration: none; + font-size: 0.95rem; + transition: opacity 0.2s; +} + +.nav-links a:hover { + opacity: 0.7; +} + +/* Main Content */ +.main-content { + flex: 1; + max-width: 1200px; + width: 100%; + margin: 0 auto; + padding: 2rem; +} + +.page { + animation: fadeIn 0.3s ease-in; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +.page h1 { + font-size: 2.5rem; + margin-bottom: 1rem; + color: var(--text); +} + +.page h2 { + font-size: 1.8rem; + margin-top: 2rem; + margin-bottom: 1rem; + color: var(--text); +} + +.page h3 { + font-size: 1.3rem; + margin-top: 1.5rem; + margin-bottom: 0.8rem; + color: var(--text); +} + +.subtitle { + font-size: 1.1rem; + color: var(--secondary); + margin-bottom: 2rem; +} + +.page p { + margin-bottom: 1rem; + line-height: 1.8; +} + +.page section { + margin-bottom: 3rem; +} + +/* Hero Section */ +.hero { + text-align: center; + padding: 3rem 0; +} + +.hero h1 { + font-size: 3rem; + margin-bottom: 1rem; +} + +.hero p { + font-size: 1.2rem; + color: var(--secondary); + margin-bottom: 2rem; +} + +.cta-buttons { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; +} + +/* Buttons */ +.btn { + padding: 0.8rem 1.5rem; + border: none; + border-radius: 4px; + font-size: 1rem; + cursor: pointer; + text-decoration: none; + display: inline-block; + transition: all 0.2s; + font-weight: 500; +} + +.btn-primary { + background: var(--primary); + color: white; +} + +.btn-primary:hover { + background: var(--primary-dark); +} + +.btn-secondary { + background: var(--light); + color: var(--text); + border: 1px solid var(--border); +} + +.btn-secondary:hover { + background: #e0e0e0; +} + +/* Grid Layouts */ +.grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 2rem; + margin: 2rem 0; +} + +.card { + padding: 1.5rem; + border: 1px solid var(--border); + border-radius: 8px; + background: var(--light); + transition: transform 0.2s, box-shadow 0.2s; +} + +.card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} + +.card h3 { + margin-top: 0; + font-size: 1.2rem; +} + +/* Features Preview */ +.features-preview { + margin: 3rem 0; +} + +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; + margin: 2rem 0; +} + +.feature-card { + padding: 2rem; + border: 1px solid var(--border); + border-radius: 8px; + text-align: center; + transition: all 0.3s; +} + +.feature-card:hover { + border-color: var(--primary); + box-shadow: 0 4px 12px rgba(0, 102, 204, 0.1); +} + +.feature-icon { + font-size: 2.5rem; + margin-bottom: 1rem; +} + +.feature-card h3 { + margin-top: 0; +} + +/* CTA Section */ +.cta-section { + background: var(--light); + padding: 3rem; + border-radius: 8px; + text-align: center; + margin: 3rem 0; +} + +.cta-section h2 { + margin-top: 0; +} + +/* Docs Grid */ +.docs-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 2rem; + margin: 2rem 0; +} + +.doc-card { + padding: 1.5rem; + border: 1px solid var(--border); + border-radius: 8px; + transition: all 0.2s; +} + +.doc-card:hover { + border-color: var(--primary); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +.doc-card a { + text-decoration: none; + color: inherit; +} + +.doc-card h2 { + margin-top: 0; + color: var(--primary); + font-size: 1.3rem; +} + +.doc-section { + background: var(--light); + padding: 2rem; + border-radius: 8px; +} + +/* Code Blocks */ +pre { + background: #2d2d2d; + color: #f8f8f2; + padding: 1rem; + border-radius: 4px; + overflow-x: auto; + margin: 1rem 0; + font-family: 'Courier New', monospace; + font-size: 0.9rem; +} + +code { + font-family: 'Courier New', monospace; + background: rgba(0, 0, 0, 0.05); + padding: 0.2rem 0.5rem; + border-radius: 3px; + font-size: 0.9em; +} + +pre code { + background: none; + padding: 0; +} + +/* Pricing */ +.pricing-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; + margin: 2rem 0; +} + +.pricing-card { + padding: 2rem; + border: 1px solid var(--border); + border-radius: 8px; + text-align: center; + transition: all 0.3s; +} + +.pricing-card.highlighted { + border: 2px solid var(--primary); + box-shadow: 0 4px 12px rgba(0, 102, 204, 0.2); +} + +.pricing-card h2 { + margin-top: 0; + font-size: 1.5rem; +} + +.price { + font-size: 2.5rem; + font-weight: bold; + color: var(--primary); + margin: 1rem 0; +} + +.features-list { + list-style: none; + text-align: left; + margin: 2rem 0; +} + +.features-list li { + padding: 0.5rem 0; +} + +.faq-pricing { + background: var(--light); + padding: 2rem; + border-radius: 8px; + margin-top: 3rem; +} + +.faq-item { + margin-bottom: 1.5rem; +} + +.faq-item h3 { + margin-top: 0; +} + +/* Blog */ +.blog-list { + display: grid; + gap: 2rem; +} + +.blog-item { + padding: 1.5rem; + border: 1px solid var(--border); + border-radius: 8px; + transition: all 0.2s; +} + +.blog-item:hover { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +.blog-item h2 { + margin-top: 0; + margin-bottom: 0.5rem; +} + +.blog-item a { + text-decoration: none; + color: inherit; +} + +.blog-meta { + display: flex; + gap: 1rem; + color: var(--secondary); + font-size: 0.9rem; + margin-bottom: 1rem; +} + +.date { + font-weight: 500; +} + +.excerpt { + color: var(--secondary); + margin-bottom: 1rem; +} + +.read-more { + color: var(--primary); + text-decoration: none; + font-weight: 500; +} + +.read-more:hover { + text-decoration: underline; +} + +/* Blog Post */ +.blog-post { + max-width: 800px; + margin: 0 auto; +} + +.post-meta { + display: flex; + gap: 2rem; + color: var(--secondary); + margin-bottom: 2rem; + font-size: 0.95rem; +} + +.post-content { + line-height: 1.8; +} + +.post-content h3 { + margin-top: 2rem; +} + +.post-content ul { + margin-left: 1.5rem; + margin-bottom: 1rem; +} + +.post-content li { + margin-bottom: 0.5rem; +} + +/* Contact */ +.contact-container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 3rem; + margin: 2rem 0; +} + +.contact-info { + display: flex; + flex-direction: column; + gap: 2rem; +} + +.info-item h3 { + margin-top: 0; +} + +.contact-form { + background: var(--light); + padding: 2rem; + border-radius: 8px; +} + +.form-group { + margin-bottom: 1.5rem; +} + +.form-group label { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; +} + +.form-group input, +.form-group textarea { + width: 100%; + padding: 0.8rem; + border: 1px solid var(--border); + border-radius: 4px; + font-family: inherit; + font-size: 1rem; +} + +.form-group input:focus, +.form-group textarea:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.1); +} + +/* FAQ */ +.faq-container { + display: grid; + gap: 1rem; + margin: 2rem 0; +} + +details { + padding: 1rem; + border: 1px solid var(--border); + border-radius: 4px; + cursor: pointer; +} + +details[open] { + background: var(--light); +} + +summary { + font-weight: 500; + user-select: none; +} + +summary:hover { + color: var(--primary); +} + +.faq-answer { + margin-top: 1rem; + color: var(--secondary); + padding-top: 1rem; + border-top: 1px solid var(--border); +} + +.faq-cta { + background: var(--light); + padding: 2rem; + border-radius: 8px; + text-align: center; + margin-top: 3rem; +} + +/* Tables */ +table { + width: 100%; + border-collapse: collapse; + margin: 1.5rem 0; +} + +th, +td { + padding: 0.8rem; + text-align: left; + border-bottom: 1px solid var(--border); +} + +th { + background: var(--light); + font-weight: 600; +} + +tr:hover { + background: rgba(0, 0, 0, 0.02); +} + +/* Lists */ +ul, +ol { + margin-left: 1.5rem; + margin-bottom: 1rem; +} + +li { + margin-bottom: 0.5rem; +} + +a { + color: var(--primary); +} + +a:hover { + text-decoration: underline; +} + +/* Footer */ +.footer { + background: var(--text); + color: white; + padding: 2rem; + text-align: center; + margin-top: auto; +} + +.footer p { + margin-bottom: 1rem; +} + +.footer-links { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; +} + +.footer-links a { + color: white; + text-decoration: none; +} + +.footer-links a:hover { + text-decoration: underline; +} + +/* Responsive */ +@media (max-width: 768px) { + .nav-links { + gap: 1rem; + font-size: 0.9rem; + } + + .logo { + margin-right: 1rem; + } + + .page h1 { + font-size: 1.8rem; + } + + .hero h1 { + font-size: 2rem; + } + + .cta-buttons { + flex-direction: column; + } + + .btn { + width: 100%; + text-align: center; + } + + .contact-container { + grid-template-columns: 1fr; + } + + .main-content { + padding: 1rem; + } + + .grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 480px) { + .nav { + padding: 0 1rem; + } + + .nav-links { + gap: 0.5rem; + font-size: 0.8rem; + } + + .page h1 { + font-size: 1.5rem; + } +} + +.hero { + position: relative; + + .base, + .framework, + .vite { + inset-inline: 0; + margin: 0 auto; + } + + .base { + width: 170px; + position: relative; + z-index: 0; + } + + .framework, + .vite { + position: absolute; + } + + .framework { + z-index: 1; + top: 34px; + height: 28px; + transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) scale(1.4); + } + + .vite { + z-index: 0; + top: 107px; + height: 26px; + width: auto; + transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) scale(0.8); + } +} + +#center { + display: flex; + flex-direction: column; + gap: 25px; + place-content: center; + place-items: center; + flex-grow: 1; + + @media (max-width: 1024px) { + padding: 32px 20px 24px; + gap: 18px; + } +} + +#next-steps { + display: flex; + border-top: 1px solid var(--border); + text-align: left; + + &>div { + flex: 1 1 0; + padding: 32px; + + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + + &::after { + right: 0; + border-right-color: var(--border); + } +} \ No newline at end of file diff --git a/examples/my-react-app/src/App.jsx b/examples/my-react-app/src/App.jsx new file mode 100644 index 0000000..fe5b4c6 --- /dev/null +++ b/examples/my-react-app/src/App.jsx @@ -0,0 +1,63 @@ +import { BrowserRouter, Routes, Route, Link } from 'react-router-dom' +import './App.css' +import Home from './pages/Home' +import Docs from './pages/Docs' +import DocsGettingStarted from './pages/DocsGettingStarted' +import DocsAPI from './pages/DocsAPI' +import Features from './pages/Features' +import Pricing from './pages/Pricing' +import Blog from './pages/Blog' +import BlogPost from './pages/BlogPost' +import About from './pages/About' +import Contact from './pages/Contact' +import FAQ from './pages/FAQ' + +function App() { + return ( + +
+
+ +
+ +
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+ +
+

© 2026 React Demo App · Built with @llmtxt/react

+
+ About + FAQ + Contact +
+
+
+
+ ) +} + +export default App diff --git a/examples/my-react-app/src/assets/hero.png b/examples/my-react-app/src/assets/hero.png new file mode 100644 index 0000000000000000000000000000000000000000..02251f4b956c55af2d76fd0788124d7eee2b45eb GIT binary patch literal 13057 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 P00000NkvXXu0mjft=yBf literal 0 HcmV?d00001 diff --git a/examples/my-react-app/src/assets/react.svg b/examples/my-react-app/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/examples/my-react-app/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/my-react-app/src/assets/vite.svg b/examples/my-react-app/src/assets/vite.svg new file mode 100644 index 0000000..5101b67 --- /dev/null +++ b/examples/my-react-app/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/examples/my-react-app/src/index.css b/examples/my-react-app/src/index.css new file mode 100644 index 0000000..2c84af0 --- /dev/null +++ b/examples/my-react-app/src/index.css @@ -0,0 +1,111 @@ +:root { + --text: #6b6375; + --text-h: #08060d; + --bg: #fff; + --border: #e5e4e7; + --code-bg: #f4f3ec; + --accent: #aa3bff; + --accent-bg: rgba(170, 59, 255, 0.1); + --accent-border: rgba(170, 59, 255, 0.5); + --social-bg: rgba(244, 243, 236, 0.5); + --shadow: + rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px; + + --sans: system-ui, 'Segoe UI', Roboto, sans-serif; + --heading: system-ui, 'Segoe UI', Roboto, sans-serif; + --mono: ui-monospace, Consolas, monospace; + + font: 18px/145% var(--sans); + letter-spacing: 0.18px; + color-scheme: light dark; + color: var(--text); + background: var(--bg); + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + @media (max-width: 1024px) { + font-size: 16px; + } +} + +@media (prefers-color-scheme: dark) { + :root { + --text: #9ca3af; + --text-h: #f3f4f6; + --bg: #16171d; + --border: #2e303a; + --code-bg: #1f2028; + --accent: #c084fc; + --accent-bg: rgba(192, 132, 252, 0.15); + --accent-border: rgba(192, 132, 252, 0.5); + --social-bg: rgba(47, 48, 58, 0.5); + --shadow: + rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; + } + + #social .button-icon { + filter: invert(1) brightness(2); + } +} + +body { + margin: 0; +} + +#root { + width: 1126px; + max-width: 100%; + margin: 0 auto; + text-align: center; + border-inline: 1px solid var(--border); + min-height: 100svh; + display: flex; + flex-direction: column; + box-sizing: border-box; +} + +h1, +h2 { + font-family: var(--heading); + font-weight: 500; + color: var(--text-h); +} + +h1 { + font-size: 56px; + letter-spacing: -1.68px; + margin: 32px 0; + @media (max-width: 1024px) { + font-size: 36px; + margin: 20px 0; + } +} +h2 { + font-size: 24px; + line-height: 118%; + letter-spacing: -0.24px; + margin: 0 0 8px; + @media (max-width: 1024px) { + font-size: 20px; + } +} +p { + margin: 0; +} + +code, +.counter { + font-family: var(--mono); + display: inline-flex; + border-radius: 4px; + color: var(--text-h); +} + +code { + font-size: 15px; + line-height: 135%; + padding: 4px 8px; + background: var(--code-bg); +} diff --git a/examples/my-react-app/src/main.jsx b/examples/my-react-app/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/examples/my-react-app/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/examples/my-react-app/src/pages/About.jsx b/examples/my-react-app/src/pages/About.jsx new file mode 100644 index 0000000..70f0ef2 --- /dev/null +++ b/examples/my-react-app/src/pages/About.jsx @@ -0,0 +1,53 @@ +export default function About() { + return ( +
+

About Us

+ +
+

Our Mission

+

+ We believe that great documentation is essential for successful software projects. + Our mission is to make it easy for developers to create and maintain documentation + that works well for both humans and AI. +

+
+ +
+

Who We Are

+

+ The @llmtxt/react team is a group of passionate developers who believe in the power + of open-source software and community-driven development. We're committed to building + tools that make developers' lives easier. +

+
+ +
+

Our Story

+

+ Started in 2024, @llmtxt/react emerged from the need for a simple way to generate + AI-friendly documentation from React applications. We wanted a tool that was easy to + use, required no server-side setup, and worked with any React framework. +

+
+ +
+

Our Values

+
    +
  • Simplicity - Tools should be easy to understand and use
  • +
  • Quality - We prioritize code quality and user experience
  • +
  • Community - We believe in collaborative development
  • +
  • Transparency - We're open about our roadmap and decisions
  • +
  • Innovation - We're always looking for better ways to solve problems
  • +
+
+ +
+

Get In Touch

+

+ Have questions or feedback? We'd love to hear from you. + You can reach us at hello@example.com +

+
+
+ ) +} diff --git a/examples/my-react-app/src/pages/Blog.jsx b/examples/my-react-app/src/pages/Blog.jsx new file mode 100644 index 0000000..b9a7e4b --- /dev/null +++ b/examples/my-react-app/src/pages/Blog.jsx @@ -0,0 +1,52 @@ +import { Link } from 'react-router-dom' + +export default function Blog() { + const posts = [ + { + slug: 'introducing-v2', + title: 'Introducing v2', + date: 'May 12, 2026', + excerpt: 'Major release with new features and improvements for better documentation generation' + }, + { + slug: 'best-practices', + title: 'Best Practices for Documentation', + date: 'May 5, 2026', + excerpt: 'Tips and tricks for writing great documentation that works well with LLMs' + }, + { + slug: 'performance-tips', + title: 'Performance Tips for Large Sites', + date: 'April 28, 2026', + excerpt: 'Optimize your documentation generation for large React applications' + }, + { + slug: 'integrations', + title: 'New Integrations Available', + date: 'April 20, 2026', + excerpt: 'Connect with Stripe, Slack, GitHub, and more from your documentation' + } + ] + + return ( +
+

Blog

+

Latest news, tips, and updates

+ +
+ {posts.map((post) => ( +
+ +

{post.title}

+ +
+ {post.date} +
+

{post.excerpt}

+ Read More → +
+ ))} +
+
+ ) +} diff --git a/examples/my-react-app/src/pages/BlogPost.jsx b/examples/my-react-app/src/pages/BlogPost.jsx new file mode 100644 index 0000000..30bffca --- /dev/null +++ b/examples/my-react-app/src/pages/BlogPost.jsx @@ -0,0 +1,146 @@ +import { useParams } from 'react-router-dom' + +export default function BlogPost() { + const { slug } = useParams() + + const posts = { + 'introducing-v2': { + title: 'Introducing v2', + date: 'May 12, 2026', + author: 'John Doe', + content: `We're excited to announce the release of @llmtxt/react v2! This major update brings significant improvements and new features. + +## What's New + +### Better Performance +We've optimized the HTML to Markdown conversion process, making it 50% faster on average. Large documentation sites now generate in seconds instead of minutes. + +### Enhanced Configuration +New options allow you to customize how your documentation is generated. Set per-route timeouts, provide custom converters, and more. + +### Improved Error Handling +Better error messages and fallback strategies ensure your build process is reliable and maintainable. + +## Migration Guide + +Upgrading from v1 is easy. In most cases, your existing configuration will work without any changes. See our migration guide for details. + +## Thank You + +Special thanks to our community for feedback and contributions that made this release possible!` + }, + 'best-practices': { + title: 'Best Practices for Documentation', + date: 'May 5, 2026', + author: 'Jane Smith', + content: `Writing good documentation is an art and a science. Here are our best practices for creating documentation that works well with AI language models. + +## Clear, Concise Content + +Write in short paragraphs with clear headings. AI models perform better when content is well-structured and easy to parse. + +## Use Descriptive Titles + +Page titles should clearly describe what the page is about. This helps both humans and AI understand your content at a glance. + +## Include Code Examples + +Provide real, working code examples. Documentation without examples is harder for AI to understand and learn from. + +## Maintain Consistency + +Use consistent terminology and formatting throughout your documentation. This improves comprehension for both humans and AI. + +## Regular Updates + +Keep your documentation up-to-date with your latest features. Outdated documentation can mislead AI models.` + }, + 'performance-tips': { + title: 'Performance Tips for Large Sites', + date: 'April 28, 2026', + author: 'Mike Johnson', + content: `If you have a large site with hundreds or thousands of pages, here are some tips to optimize your documentation generation. + +## Use Selective Routes + +You don't need to document every route. Focus on user-facing pages and skip admin pages, API routes, and internal tools. + +## Set Appropriate Timeouts + +Large pages or slow servers may need higher timeouts. Set \`fetchTimeoutMs\` based on your page load times. + +## Parallel Generation + +Generate documentation in parallel across multiple processes or machines for faster builds. + +## Caching Strategy + +Cache frequently accessed resources to avoid redundant fetches during development.` + }, + 'integrations': { + title: 'New Integrations Available', + date: 'April 20, 2026', + author: 'Sarah Williams', + content: `We're thrilled to announce new integrations that extend the capabilities of @llmtxt/react. + +## Available Integrations + +### Stripe +Connect your Stripe account to document your payment integrations and pricing pages automatically. + +### Slack +Send documentation updates to your team's Slack channel whenever your docs are regenerated. + +### GitHub +Automatically commit generated documentation files to your GitHub repository. + +### SendGrid +Generate and email updated documentation to stakeholders. + +### Datadog +Monitor the performance of your documentation generation process. + +### Sentry +Track errors that occur during documentation generation and deployment. + +More integrations are coming soon. Let us know what you'd like to see next!` + } + } + + const post = posts[slug] + + if (!post) { + return

Post not found

+ } + + return ( +
+
+

{post.title}

+
+ {post.date} + By {post.author} +
+
+ {post.content.split('\n\n').map((paragraph, idx) => { + if (paragraph.startsWith('#')) { + const level = paragraph.match(/^#+/)[0].length + const text = paragraph.replace(/^#+\s/, '') + const HeadingTag = `h${level + 1}` + return {text} + } + if (paragraph.startsWith('-')) { + const items = paragraph.split('\n').map(line => line.replace(/^-\s/, '')) + return ( +
    + {items.map((item, i) =>
  • {item}
  • )} +
+ ) + } + return

{paragraph}

+ })} +
+
+
+ ) +} diff --git a/examples/my-react-app/src/pages/Contact.jsx b/examples/my-react-app/src/pages/Contact.jsx new file mode 100644 index 0000000..72c06a9 --- /dev/null +++ b/examples/my-react-app/src/pages/Contact.jsx @@ -0,0 +1,53 @@ +export default function Contact() { + return ( +
+

Contact Us

+

We'd love to hear from you

+ +
+
+

Get In Touch

+
+

Email

+

hello@example.com

+
+
+

Social Media

+

+ Twitter · + GitHub · + LinkedIn +

+
+
+

Office

+

123 Developer Lane
San Francisco, CA 94105

+
+
+ +
+

Send Us a Message

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+ ) +} diff --git a/examples/my-react-app/src/pages/Docs.jsx b/examples/my-react-app/src/pages/Docs.jsx new file mode 100644 index 0000000..827ee25 --- /dev/null +++ b/examples/my-react-app/src/pages/Docs.jsx @@ -0,0 +1,49 @@ +import { Link } from 'react-router-dom' + +export default function Docs() { + return ( +
+

Documentation

+

Complete documentation and resources for using @llmtxt/react

+ +
+
+ +

Getting Started

+

Quick start guide to set up @llmtxt/react in your project

+ +
+ +
+ +

API Reference

+

Complete API documentation with examples and use cases

+ +
+ +
+

Configuration

+

Learn how to configure routes and generation options

+
+ +
+

Examples

+

Real-world examples and code snippets

+
+
+ +
+

Overview

+

+ @llmtxt/react is a build-time helper for React SPAs to generate llms.txt and llms-full.txt + documentation files automatically. It works by taking an explicit route list and generating + files into your public folder during the build process. +

+

+ Since React apps don't have a universal "pages directory" like Next.js, this package + requires you to explicitly define your routes in a configuration file. +

+
+
+ ) +} diff --git a/examples/my-react-app/src/pages/DocsAPI.jsx b/examples/my-react-app/src/pages/DocsAPI.jsx new file mode 100644 index 0000000..21efdfe --- /dev/null +++ b/examples/my-react-app/src/pages/DocsAPI.jsx @@ -0,0 +1,89 @@ +export default function DocsAPI() { + return ( +
+

API Reference

+ +
+

writeLlmsFiles(options)

+

The main function to generate llms.txt and llms-full.txt files.

+ +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionTypeRequiredDescription
routesLlmtxtRoute[]YesArray of routes to include in documentation
baseUrlstringYesPublic base URL (no trailing slash)
outDirstringYesOutput directory path (e.g., 'public')
fetchTimeoutMsnumberNoPer-page fetch timeout in milliseconds
htmlToMarkdownfunctionNoCustom HTML to Markdown converter
+
+ +
+

LlmtxtRoute Type

+
{`type LlmtxtRoute = {
+  path: string          // Route path (e.g., '/docs')
+  title: string         // Page title
+  description?: string  // Optional description
+}`}
+
+ +
+

Example Usage

+
{`import { writeLlmsFiles } from '@llmtxt/react'
+
+await writeLlmsFiles({
+  routes: [
+    { path: '/', title: 'Home' },
+    { path: '/about', title: 'About', description: 'Learn about us' },
+  ],
+  baseUrl: 'https://example.com',
+  outDir: './public',
+  fetchTimeoutMs: 5000,
+})`}
+
+ +
+

Output Files

+

The function generates two files:

+
    +
  • llms.txt: Lightweight documentation with titles and links
  • +
  • llms-full.txt: Full documentation with page content
  • +
+
+
+ ) +} diff --git a/examples/my-react-app/src/pages/DocsGettingStarted.jsx b/examples/my-react-app/src/pages/DocsGettingStarted.jsx new file mode 100644 index 0000000..143449c --- /dev/null +++ b/examples/my-react-app/src/pages/DocsGettingStarted.jsx @@ -0,0 +1,53 @@ +export default function DocsGettingStarted() { + return ( +
+

Getting Started with @llmtxt/react

+ +
+

Installation

+

Install the package as a dev dependency:

+
npm install -D @llmtxt/react
+
+ +
+

Step 1: Create a Route List

+

Create a file named llmtxt.routes.ts or .js:

+
{`export const routes = [
+  { path: '/', title: 'Home', description: 'Homepage' },
+  { path: '/docs', title: 'Docs', description: 'Documentation' },
+  { path: '/pricing', title: 'Pricing', description: 'Pricing plans' },
+]`}
+
+ +
+

Step 2: Create Generation Script

+

Create scripts/generate-llms.js:

+
{`import path from 'path'
+import { writeLlmsFiles } from '@llmtxt/react'
+import { routes } from '../llmtxt.routes.js'
+
+await writeLlmsFiles({
+  routes,
+  baseUrl: process.env.PUBLIC_SITE_URL || 'http://localhost:5173',
+  outDir: path.join(process.cwd(), 'public'),
+})`}
+
+ +
+

Step 3: Update Build Script

+

Update your package.json to run the generator after build:

+
{`"scripts": {
+  "build": "vite build && npm run generate:llms",
+  "generate:llms": "node scripts/generate-llms.js"
+}`}
+
+ +
+

Step 4: Deploy and Generate

+

After deploying your app, run:

+
PUBLIC_SITE_URL=https://example.com npm run generate:llms
+

This will fetch your pages and generate llms.txt and llms-full.txt files.

+
+
+ ) +} diff --git a/examples/my-react-app/src/pages/FAQ.jsx b/examples/my-react-app/src/pages/FAQ.jsx new file mode 100644 index 0000000..f1be697 --- /dev/null +++ b/examples/my-react-app/src/pages/FAQ.jsx @@ -0,0 +1,65 @@ +export default function FAQ() { + const faqs = [ + { + question: 'What is @llmtxt/react?', + answer: 'A build-time helper for React SPAs to generate llms.txt and llms-full.txt documentation files automatically from your route list.' + }, + { + question: 'How does it work?', + answer: 'You provide a list of routes, and the package fetches each route from your running app and converts the HTML to Markdown for documentation.' + }, + { + question: 'Do I need a backend?', + answer: 'No, it works entirely with your frontend. You can generate the documentation after deploying your SPA to any static hosting.' + }, + { + question: 'What formats are generated?', + answer: 'Two files: llms.txt (lightweight index) and llms-full.txt (full documentation with page content).' + }, + { + question: 'Can I customize the output?', + answer: 'Yes, you can provide custom HTML to Markdown converters and configure various generation options.' + }, + { + question: 'Is it compatible with React Router?', + answer: 'Yes, it works with any React routing solution. Just provide the list of routes to document.' + }, + { + question: 'What about performance?', + answer: 'Very fast. Generation typically takes seconds even for large sites. You can configure timeouts and parallel generation.' + }, + { + question: 'How do I update my documentation?', + answer: 'Run the generation script anytime after deployment. We recommend including it in your CI/CD pipeline.' + }, + { + question: 'Is there a free version?', + answer: 'Yes! The Starter plan is completely free. Upgrade when you need advanced features.' + }, + { + question: 'Can I use it with Create React App?', + answer: 'Yes, it works with any React framework including Create React App, Vite, Next.js, Remix, and more.' + } + ] + + return ( +
+

Frequently Asked Questions

+

Find answers to common questions about @llmtxt/react

+ +
+ {faqs.map((faq, idx) => ( +
+ {faq.question} +
{faq.answer}
+
+ ))} +
+ +
+

Still have questions?

+

Check out our documentation or contact us directly for more help.

+
+
+ ) +} diff --git a/examples/my-react-app/src/pages/Features.jsx b/examples/my-react-app/src/pages/Features.jsx new file mode 100644 index 0000000..8fe3f1f --- /dev/null +++ b/examples/my-react-app/src/pages/Features.jsx @@ -0,0 +1,72 @@ +export default function Features() { + const features = [ + { + title: 'Build-Time Generation', + description: 'Generate documentation files during your build process, no runtime overhead', + icon: '⚡' + }, + { + title: 'Zero Runtime Dependencies', + description: 'No additional packages needed in your production bundle', + icon: '📦' + }, + { + title: 'HTML to Markdown', + description: 'Automatically convert your page HTML to clean Markdown', + icon: '🔄' + }, + { + title: 'Route-Based', + description: 'Simple configuration with just a route list', + icon: '🗺️' + }, + { + title: 'AI-Friendly', + description: 'Generate documentation optimized for AI language models', + icon: '🤖' + }, + { + title: 'Flexible Timeouts', + description: 'Configure per-page fetch timeouts for slow or heavy pages', + icon: '⏱️' + }, + { + title: 'Custom Converters', + description: 'Provide your own HTML to Markdown converter if needed', + icon: '🛠️' + }, + { + title: 'Environment Aware', + description: 'Works with different base URLs for preview and production', + icon: '🌍' + }, + ] + + return ( +
+

Features

+

Powerful capabilities for documentation generation

+ +
+ {features.map((feature, idx) => ( +
+
{feature.icon}
+

{feature.title}

+

{feature.description}

+
+ ))} +
+ +
+

Why Use @llmtxt/react?

+
    +
  • Automatically keep your AI documentation in sync with your app
  • +
  • No server-side rendering or API needed
  • +
  • Works with any React framework (Vite, Create React App, etc.)
  • +
  • Perfect for SPA applications and static sites
  • +
  • Lightweight and fast build process
  • +
+
+
+ ) +} diff --git a/examples/my-react-app/src/pages/Home.jsx b/examples/my-react-app/src/pages/Home.jsx new file mode 100644 index 0000000..04d6f62 --- /dev/null +++ b/examples/my-react-app/src/pages/Home.jsx @@ -0,0 +1,44 @@ +import { Link } from 'react-router-dom' + +export default function Home() { + return ( +
+
+

Welcome to React Demo App

+

A comprehensive example showcasing @llmtxt/react integration

+
+ Get Started + Learn More +
+
+ +
+

What We Offer

+
+
+

📚 Documentation

+

Complete guides and API reference to get you started quickly

+
+
+

⚡ High Performance

+

Optimized for speed with minimal bundle size

+
+
+

🔧 Easy Integration

+

Simple setup process that works with your existing React app

+
+
+

📱 Responsive

+

Works perfectly on desktop, tablet, and mobile devices

+
+
+
+ +
+

Ready to Get Started?

+

Check out our documentation to learn more about @llmtxt/react

+ Read Documentation +
+
+ ) +} diff --git a/examples/my-react-app/src/pages/Pricing.jsx b/examples/my-react-app/src/pages/Pricing.jsx new file mode 100644 index 0000000..ab7272f --- /dev/null +++ b/examples/my-react-app/src/pages/Pricing.jsx @@ -0,0 +1,58 @@ +export default function Pricing() { + const plans = [ + { + name: 'Starter', + price: 'Free', + features: ['Up to 10 routes', 'Basic HTML to Markdown', 'Community support'] + }, + { + name: 'Professional', + price: '$49/mo', + features: ['Unlimited routes', 'Custom converters', 'Priority support', 'Advanced caching'], + highlighted: true + }, + { + name: 'Enterprise', + price: 'Custom', + features: ['Everything in Pro', 'Custom SLAs', 'Dedicated support', 'White-label options'] + } + ] + + return ( +
+

Pricing

+

Simple, transparent pricing for everyone

+ +
+ {plans.map((plan, idx) => ( +
+

{plan.name}

+
{plan.price}
+
    + {plan.features.map((feature, i) => ( +
  • ✓ {feature}
  • + ))} +
+ +
+ ))} +
+ +
+

Frequently Asked Questions

+
+

Can I upgrade or downgrade anytime?

+

Yes, you can change your plan at any time. Changes take effect immediately.

+
+
+

Is there a free trial?

+

Our Starter plan is completely free forever. Upgrade whenever you need more features.

+
+
+

Do you offer discounts for annual billing?

+

Yes! Pay annually and get 2 months free. Contact our sales team for details.

+
+
+
+ ) +} diff --git a/examples/my-react-app/vite.config.js b/examples/my-react-app/vite.config.js new file mode 100644 index 0000000..8b0f57b --- /dev/null +++ b/examples/my-react-app/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/package-lock.json b/package-lock.json index 4317d23..caab703 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1865,6 +1865,10 @@ "resolved": "packages/next", "link": true }, + "node_modules/@llmtxt/react": { + "resolved": "packages/react", + "link": true + }, "node_modules/@next/env": { "version": "16.2.6", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz", @@ -14487,6 +14491,14 @@ "peerDependencies": { "next": ">=13.0.0" } + }, + "packages/react": { + "name": "@llmtxt/react", + "version": "0.1.0", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } } }, "dependencies": { @@ -15786,6 +15798,9 @@ "@types/node": "^18.19.130" } }, + "@llmtxt/react": { + "version": "file:packages/react" + }, "@next/env": { "version": "16.2.6", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz", diff --git a/packages/react/README.md b/packages/react/README.md index 914cfc0..f24d436 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -1,10 +1,8 @@ # `@llmtxt/react` -Build-time helpers for React SPAs to generate `llms.txt` and `llms-full.txt` **without a backend**. +Generate `llms.txt` and `llms-full.txt` for React SPAs **without a backend** by writing the files into your `public/` folder at build time. -React apps (Vite/CRA/React Router) don’t have a universal “pages directory” like Next.js App Router, so this package works by taking an **explicit route list** and generating files into your `public/` (or `dist/`) folder during CI/build. - ---- +React Router/Vite/CRA apps don’t have a universal “pages directory”, so this package uses an **explicit route list**. ## Install @@ -12,29 +10,27 @@ React apps (Vite/CRA/React Router) don’t have a universal “pages directory npm install -D @llmtxt/react ``` ---- - -## 1) Create a route list +## Usage -Create `llmtxt.routes.ts`: +Create a route list: ```ts +// llmtxt.routes.ts import type { LlmtxtRoute } from '@llmtxt/react' export const routes: LlmtxtRoute[] = [ { path: '/', title: 'Home', description: 'What this site is about.' }, - { path: '/docs', title: 'Docs', description: 'Documentation index.' }, - { path: '/pricing', title: 'Pricing' }, + { path: '/docs', title: 'Docs' }, + + // Dynamic routes must be expanded into concrete paths: + // { path: '/blog/hello-world', title: 'Hello World' }, ] ``` ---- - -## 2) Generate `public/llms.txt` and `public/llms-full.txt` - -Create `scripts/generate-llms.ts`: +Generate files: ```ts +// scripts/generate-llms.ts import path from 'path' import { writeLlmsFiles } from '@llmtxt/react' import { routes } from '../llmtxt.routes' @@ -43,23 +39,20 @@ await writeLlmsFiles({ routes, baseUrl: process.env.PUBLIC_SITE_URL!, // e.g. https://example.com outDir: path.join(process.cwd(), 'public'), + title: 'My App', + summary: 'My app documentation for AI models.', }) ``` -Run it in CI after deploy (recommended) or against a preview server: +## Why `llms-full.txt` may look empty in SPAs -```bash -PUBLIC_SITE_URL=https://example.com node scripts/generate-llms.ts -``` - ---- - -## How it works +If your app is a **client-rendered SPA**, fetching `https://yoursite.com/pricing` usually returns the same `index.html` for every route (no page content). In that case, `llms-full.txt` can end up containing only the shell. -- `llms.txt` is generated purely from your route list (titles + descriptions). -- `llms-full.txt` fetches each route from `baseUrl` and converts the returned HTML into Markdown using a built-in dependency-free converter (you can override it). +To generate real content you need one of: ---- +1) **SSR / Prerendered HTML** for each route (best), or +2) Provide `route.markdown` per route (recommended for CMS-driven/dynamic pages), or +3) Provide `fetchHtml` to render routes with a headless browser (Playwright/Puppeteer). ## API @@ -69,13 +62,25 @@ Writes: - `llms.txt` - `llms-full.txt` -### Options +### Types -| Option | Type | Required | Description | -|---|---|---:|---| -| `routes` | `LlmtxtRoute[]` | yes | Routes to include | -| `baseUrl` | `string` | yes | Public base URL (no trailing slash) | -| `outDir` | `string` | yes | Folder to write files (e.g. `public`) | -| `fetchTimeoutMs` | `number` | no | Per-page fetch timeout | -| `htmlToMarkdown` | `(html, url) => string \| Promise` | no | Custom converter | +```ts +export type LlmtxtRoute = { + path: string + title: string + description?: string + markdown?: string +} + +export type WriteLlmsFilesOptions = { + routes: LlmtxtRoute[] + baseUrl: string + outDir: string + title?: string + summary?: string + fetchTimeoutMs?: number + htmlToMarkdown?: (html: string, url: string) => Promise | string + fetchHtml?: (url: string, timeoutMs: number) => Promise +} +``` diff --git a/packages/react/package.json b/packages/react/package.json index a7471c4..5603ae9 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@llmtxt/react", - "version": "0.1.0", + "version": "0.1.1", "description": "Build-time helpers for React SPAs to generate llms.txt and llms-full.txt from an explicit route list.", "license": "MIT", "author": "Recordly", @@ -44,4 +44,3 @@ "node": ">=18.0.0" } } - diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 8252d2f..b935e73 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -5,6 +5,11 @@ export type LlmtxtRoute = { path: string; title: string; description?: string; + /** + * Optional precomputed Markdown for this route. + * If provided, `llms-full.txt` uses this instead of fetching HTML. + */ + markdown?: string; }; export type WriteLlmsFilesOptions = { @@ -13,6 +18,13 @@ export type WriteLlmsFilesOptions = { outDir: string; fetchTimeoutMs?: number; htmlToMarkdown?: (html: string, url: string) => Promise | string; + /** + * Optional fetcher for HTML. Use this to support SPAs/dynamic pages by + * rendering with a headless browser (Playwright/Puppeteer) instead of plain fetch. + */ + fetchHtml?: (url: string, timeoutMs: number) => Promise; + title?: string; + summary?: string; }; function normalizeBaseUrl(baseUrl: string): string { @@ -40,6 +52,15 @@ function stripHtmlToText(html: string): string { .trim(); } +function looksLikeClientRenderedSpa(html: string, markdown: string): boolean { + const hasLikelyMount = + /]+id=["']root["'][^>]*><\/div>/i.test(html) || + /]+id=["']app["'][^>]*><\/div>/i.test(html); + const hasScripts = / { if (typeof fetch !== 'function') { throw new Error( @@ -98,6 +119,7 @@ export async function generateLlmsFullTxtFromRoutes(options: { baseUrl: string; fetchTimeoutMs?: number; htmlToMarkdown?: (html: string, url: string) => Promise | string; + fetchHtml?: (url: string, timeoutMs: number) => Promise; }): Promise { const baseUrl = normalizeBaseUrl(options.baseUrl); const routes = [...options.routes].sort((a, b) => a.path.localeCompare(b.path)); @@ -118,12 +140,26 @@ export async function generateLlmsFullTxtFromRoutes(options: { lines.push(url); lines.push(''); try { - const html = await fetchWithTimeout(url, fetchTimeoutMs); - const markdown = - typeof options.htmlToMarkdown === 'function' - ? await options.htmlToMarkdown(html, url) - : stripHtmlToText(html); - lines.push(markdown.trim()); + if (route.markdown) { + lines.push(route.markdown.trim()); + } else { + const html = + typeof options.fetchHtml === 'function' + ? await options.fetchHtml(url, fetchTimeoutMs) + : await fetchWithTimeout(url, fetchTimeoutMs); + const markdown = + typeof options.htmlToMarkdown === 'function' + ? await options.htmlToMarkdown(html, url) + : stripHtmlToText(html); + const trimmed = markdown.trim(); + lines.push(trimmed); + if (looksLikeClientRenderedSpa(html, trimmed)) { + lines.push(''); + lines.push( + '(Note: This route looks like a client-rendered SPA shell. For full content, provide `route.markdown`, prerender/SSR HTML, or pass `fetchHtml` to render with a headless browser.)' + ); + } + } } catch (err) { const msg = err instanceof Error ? err.message : String(err); lines.push(`(Failed to fetch or convert content: ${msg})`); @@ -146,12 +182,15 @@ export async function writeLlmsFiles(options: WriteLlmsFilesOptions): Promise<{ const llmsTxt = await generateLlmsTxtFromRoutes({ routes: options.routes, baseUrl: options.baseUrl, + title: options.title, + summary: options.summary, }); const llmsFullTxt = await generateLlmsFullTxtFromRoutes({ routes: options.routes, baseUrl: options.baseUrl, fetchTimeoutMs: options.fetchTimeoutMs, htmlToMarkdown: options.htmlToMarkdown, + fetchHtml: options.fetchHtml, }); const llmsTxtPath = path.join(outDir, 'llms.txt'); @@ -161,4 +200,3 @@ export async function writeLlmsFiles(options: WriteLlmsFilesOptions): Promise<{ return { llmsTxtPath, llmsFullTxtPath }; } - From 2e2a4120e514cb535f91289e8c61512e89baf991 Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 21:57:48 +0500 Subject: [PATCH 8/9] feat(react): add pages-dir route scanner --- package-lock.json | 2 +- packages/react/README.md | 28 +++++++- packages/react/package.json | 2 +- packages/react/src/index.ts | 2 + packages/react/src/scan.ts | 139 ++++++++++++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 packages/react/src/scan.ts diff --git a/package-lock.json b/package-lock.json index caab703..9e13d44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14494,7 +14494,7 @@ }, "packages/react": { "name": "@llmtxt/react", - "version": "0.1.0", + "version": "0.1.2", "license": "MIT", "engines": { "node": ">=18.0.0" diff --git a/packages/react/README.md b/packages/react/README.md index f24d436..aa34e50 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -44,6 +44,33 @@ await writeLlmsFiles({ }) ``` +## Optional: auto-scan `src/pages` (convention-based) + +If your React app follows a simple `src/pages/**` convention, you can generate the route list automatically: + +```ts +import path from 'path' +import { scanPagesDirForRoutes, writeLlmsFiles } from '@llmtxt/react' + +const routes = await scanPagesDirForRoutes({ + pagesDir: path.join(process.cwd(), 'src/pages'), + skipDynamic: true, +}) + +await writeLlmsFiles({ + routes, + baseUrl: process.env.PUBLIC_SITE_URL!, + outDir: path.join(process.cwd(), 'public'), +}) +``` + +Mapping rules: +- `src/pages/index.tsx` → `/` +- `src/pages/About.tsx` → `/about` +- `src/pages/docs/GettingStarted.tsx` → `/docs/getting-started` + +Dynamic files like `src/pages/blog/[slug].tsx` are skipped by default. + ## Why `llms-full.txt` may look empty in SPAs If your app is a **client-rendered SPA**, fetching `https://yoursite.com/pricing` usually returns the same `index.html` for every route (no page content). In that case, `llms-full.txt` can end up containing only the shell. @@ -83,4 +110,3 @@ export type WriteLlmsFilesOptions = { fetchHtml?: (url: string, timeoutMs: number) => Promise } ``` - diff --git a/packages/react/package.json b/packages/react/package.json index 5603ae9..6212e26 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@llmtxt/react", - "version": "0.1.1", + "version": "0.1.2", "description": "Build-time helpers for React SPAs to generate llms.txt and llms-full.txt from an explicit route list.", "license": "MIT", "author": "Recordly", diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index b935e73..5d5595a 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -1,5 +1,7 @@ import fs from 'fs/promises'; import path from 'path'; +export { scanPagesDirForRoutes } from './scan'; +export type { ScanPagesDirOptions } from './scan'; export type LlmtxtRoute = { path: string; diff --git a/packages/react/src/scan.ts b/packages/react/src/scan.ts new file mode 100644 index 0000000..7e2d455 --- /dev/null +++ b/packages/react/src/scan.ts @@ -0,0 +1,139 @@ +import fs from 'fs/promises'; +import path from 'path'; +import type { LlmtxtRoute } from './index'; + +export type ScanPagesDirOptions = { + /** + * Directory that contains page components, e.g. `src/pages`. + */ + pagesDir: string; + + /** + * Route prefixes to drop from the path computation, e.g. `['(components)']`. + */ + ignoreSegments?: string[]; + + /** + * Skip dynamic routes by default (files like `[slug].tsx` or `$slug.tsx`). + * @default true + */ + skipDynamic?: boolean; +}; + +const DEFAULT_IGNORE = ['components', '__tests__', '__mocks__']; + +function splitSegments(p: string): string[] { + return p.split(/[\\/]/g).filter(Boolean); +} + +function isDynamicSegment(seg: string): boolean { + return ( + /^\[.+\]$/.test(seg) || // [slug] + /^\[\.\.\..+\]$/.test(seg) || // [...slug] + /^\$.+/.test(seg) // $slug + ); +} + +function kebabCase(input: string): string { + return input + .replace(/([a-z0-9])([A-Z])/g, '$1-$2') + .replace(/[_\s]+/g, '-') + .replace(/-+/g, '-') + .toLowerCase(); +} + +function titleFromSegments(segments: string[]): string { + const last = segments[segments.length - 1] ?? 'Home'; + const cleaned = last + .replace(/^\[(\.\.\.)?/, '') + .replace(/\]$/, '') + .replace(/^\$/, '') + .replace(/[-_]+/g, ' ') + .trim(); + const base = cleaned || 'Home'; + return base.replace(/\b\w/g, c => c.toUpperCase()); +} + +function descriptionFromFileContents(fileContents: string): string | undefined { + const lines = fileContents.split(/\r?\n/); + for (const line of lines.slice(0, 40)) { + const m = /^\s*\/\/\s*(.+?)\s*$/.exec(line); + if (m?.[1]) return m[1]; + if ( + line.trim() && + !line.trim().startsWith('import') && + !line.trim().startsWith('export') + ) { + break; + } + } + return undefined; +} + +function shouldIgnoreSegment(seg: string, ignoreSegments: string[]): boolean { + const s = seg.toLowerCase(); + if (ignoreSegments.some(x => x.toLowerCase() === s)) return true; + if (s.startsWith('_')) return true; + if (s.startsWith('.')) return true; + return false; +} + +function routePathFromFile(relFileNoExt: string): string | null { + const segs = splitSegments(relFileNoExt); + const normalized = segs.map(s => (s === 'Home' ? 'index' : s)); + const last = normalized[normalized.length - 1]; + const withoutIndex = + last?.toLowerCase() === 'index' ? normalized.slice(0, -1) : normalized; + const parts = withoutIndex.map(kebabCase).filter(Boolean); + return parts.length ? `/${parts.join('/')}` : '/'; +} + +export async function scanPagesDirForRoutes( + options: ScanPagesDirOptions +): Promise { + const pagesDir = path.resolve(options.pagesDir); + const ignoreSegments = [ + ...(options.ignoreSegments ?? []), + ...DEFAULT_IGNORE, + ]; + const skipDynamic = options.skipDynamic ?? true; + + const results: LlmtxtRoute[] = []; + + async function walk(dir: string): Promise { + const entries = await fs.readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + if (shouldIgnoreSegment(entry.name, ignoreSegments)) continue; + await walk(full); + continue; + } + if (!entry.isFile()) continue; + if (!/\.(t|j)sx?$/.test(entry.name)) continue; + + const rel = path.relative(pagesDir, full); + const relNoExt = rel.replace(/\.(t|j)sx?$/, ''); + const relSegs = splitSegments(relNoExt); + if (relSegs.some(s => shouldIgnoreSegment(s, ignoreSegments))) continue; + if (skipDynamic && relSegs.some(isDynamicSegment)) continue; + + const routePath = routePathFromFile(relNoExt); + if (!routePath) continue; + + const fileContents = await fs.readFile(full, 'utf8'); + const description = descriptionFromFileContents(fileContents); + + results.push({ + path: routePath, + title: titleFromSegments(relSegs), + description, + }); + } + } + + await walk(pagesDir); + results.sort((a, b) => a.path.localeCompare(b.path)); + return results; +} + From 62e2026c0239708a5bb055e8ba9dd652aee36cb8 Mon Sep 17 00:00:00 2001 From: Muhammad Hashim Date: Tue, 12 May 2026 22:16:51 +0500 Subject: [PATCH 9/9] chore(examples): use @llmtxt/react pages scan --- examples/my-react-app/.gitignore | 4 + examples/my-react-app/README.md | 10 +- examples/my-react-app/llmtxt.routes.js | 14 -- examples/my-react-app/public/llms-full.txt | 101 ------------ examples/my-react-app/public/llms.txt | 17 -- .../my-react-app/scripts/generate-llms.js | 19 ++- examples/my-react-app/src/App.jsx | 24 +-- examples/my-react-app/src/pages/About.jsx | 53 ------ examples/my-react-app/src/pages/Blog.jsx | 52 ------ examples/my-react-app/src/pages/BlogPost.jsx | 146 ----------------- examples/my-react-app/src/pages/Contact.jsx | 53 ------ examples/my-react-app/src/pages/Docs.jsx | 49 ------ examples/my-react-app/src/pages/DocsAPI.jsx | 89 ---------- .../src/pages/DocsGettingStarted.jsx | 53 ------ examples/my-react-app/src/pages/FAQ.jsx | 65 -------- examples/my-react-app/src/pages/Features.jsx | 72 --------- examples/my-react-app/src/pages/Home.jsx | 44 ----- examples/my-react-app/src/pages/Pricing.jsx | 58 ------- examples/my-react-app/src/pages/about.jsx | 12 ++ .../my-react-app/src/pages/blog/[slug].jsx | 153 ++++++++++++++++++ .../my-react-app/src/pages/blog/index.jsx | 55 +++++++ examples/my-react-app/src/pages/contact.jsx | 9 ++ examples/my-react-app/src/pages/docs/api.jsx | 43 +++++ .../src/pages/docs/getting-started.jsx | 63 ++++++++ .../my-react-app/src/pages/docs/index.jsx | 37 +++++ examples/my-react-app/src/pages/faq.jsx | 18 +++ examples/my-react-app/src/pages/features.jsx | 42 +++++ examples/my-react-app/src/pages/index.jsx | 51 ++++++ examples/my-react-app/src/pages/pricing.jsx | 37 +++++ package-lock.json | 2 +- packages/react/package.json | 2 +- packages/react/src/index.ts | 8 +- packages/react/src/scan.ts | 17 +- 33 files changed, 575 insertions(+), 897 deletions(-) delete mode 100644 examples/my-react-app/llmtxt.routes.js delete mode 100644 examples/my-react-app/public/llms-full.txt delete mode 100644 examples/my-react-app/public/llms.txt delete mode 100644 examples/my-react-app/src/pages/About.jsx delete mode 100644 examples/my-react-app/src/pages/Blog.jsx delete mode 100644 examples/my-react-app/src/pages/BlogPost.jsx delete mode 100644 examples/my-react-app/src/pages/Contact.jsx delete mode 100644 examples/my-react-app/src/pages/Docs.jsx delete mode 100644 examples/my-react-app/src/pages/DocsAPI.jsx delete mode 100644 examples/my-react-app/src/pages/DocsGettingStarted.jsx delete mode 100644 examples/my-react-app/src/pages/FAQ.jsx delete mode 100644 examples/my-react-app/src/pages/Features.jsx delete mode 100644 examples/my-react-app/src/pages/Home.jsx delete mode 100644 examples/my-react-app/src/pages/Pricing.jsx create mode 100644 examples/my-react-app/src/pages/about.jsx create mode 100644 examples/my-react-app/src/pages/blog/[slug].jsx create mode 100644 examples/my-react-app/src/pages/blog/index.jsx create mode 100644 examples/my-react-app/src/pages/contact.jsx create mode 100644 examples/my-react-app/src/pages/docs/api.jsx create mode 100644 examples/my-react-app/src/pages/docs/getting-started.jsx create mode 100644 examples/my-react-app/src/pages/docs/index.jsx create mode 100644 examples/my-react-app/src/pages/faq.jsx create mode 100644 examples/my-react-app/src/pages/features.jsx create mode 100644 examples/my-react-app/src/pages/index.jsx create mode 100644 examples/my-react-app/src/pages/pricing.jsx diff --git a/examples/my-react-app/.gitignore b/examples/my-react-app/.gitignore index a547bf3..703f5d2 100644 --- a/examples/my-react-app/.gitignore +++ b/examples/my-react-app/.gitignore @@ -12,6 +12,10 @@ dist dist-ssr *.local +# Generated llms files (generated by scripts/generate-llms.js) +public/llms.txt +public/llms-full.txt + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/examples/my-react-app/README.md b/examples/my-react-app/README.md index 6cd1a78..48de779 100644 --- a/examples/my-react-app/README.md +++ b/examples/my-react-app/README.md @@ -64,9 +64,9 @@ This creates: ## How It Works -1. **Route List** (`llmtxt.routes.js`): - - Defines all routes to document - - Each route has path, title, and optional description +1. **Route Discovery**: + - Static routes are auto-scanned from `src/pages/**` via `scanPagesDirForRoutes()` + - Dynamic routes (e.g. `/blog/:slug`) must be expanded into concrete paths in the generator script 2. **Generation Script** (`scripts/generate-llms.js`): - Fetches each route from your running app @@ -88,7 +88,7 @@ my-react-app/ │ └── main.jsx # Entry point ├── scripts/ │ └── generate-llms.js # Documentation generator -├── llmtxt.routes.js # Route configuration +├── src/pages/ # Convention-based pages (used for auto-scan) └── package.json # Dependencies ``` @@ -98,7 +98,7 @@ my-react-app/ 1. Create a component in `src/pages/MyPage.jsx` 2. Add route to `App.jsx` -3. Add entry to `llmtxt.routes.js` +3. Add/update routes in `scripts/generate-llms.js` ### Customize Documentation Generation diff --git a/examples/my-react-app/llmtxt.routes.js b/examples/my-react-app/llmtxt.routes.js deleted file mode 100644 index 24964b9..0000000 --- a/examples/my-react-app/llmtxt.routes.js +++ /dev/null @@ -1,14 +0,0 @@ -export const routes = [ - { path: '/', title: 'Home', description: 'Welcome to our demo React application' }, - { path: '/docs', title: 'Documentation', description: 'Complete documentation and guides' }, - { path: '/docs/getting-started', title: 'Getting Started', description: 'Quick start guide' }, - { path: '/docs/api', title: 'API Reference', description: 'Full API documentation' }, - { path: '/features', title: 'Features', description: 'Core features and capabilities' }, - { path: '/pricing', title: 'Pricing', description: 'Pricing plans and billing' }, - { path: '/blog', title: 'Blog', description: 'Latest blog posts and articles' }, - { path: '/blog/introducing-v2', title: 'Introducing v2', description: 'Major release announcement' }, - { path: '/blog/best-practices', title: 'Best Practices', description: 'Development best practices' }, - { path: '/about', title: 'About', description: 'About our company and mission' }, - { path: '/contact', title: 'Contact', description: 'Get in touch with us' }, - { path: '/faq', title: 'FAQ', description: 'Frequently asked questions' }, -] diff --git a/examples/my-react-app/public/llms-full.txt b/examples/my-react-app/public/llms-full.txt deleted file mode 100644 index dca08f9..0000000 --- a/examples/my-react-app/public/llms-full.txt +++ /dev/null @@ -1,101 +0,0 @@ -# llms-full.txt - -*Generated by @llmtxt/react · 2026-05-12T16:29:03.935Z · 12 pages* - ---- - -## Home - -http://localhost:5173 - -my-react-app - ---- - -## About - -http://localhost:5173/about - -my-react-app - ---- - -## Blog - -http://localhost:5173/blog - -my-react-app - ---- - -## Best Practices - -http://localhost:5173/blog/best-practices - -my-react-app - ---- - -## Introducing v2 - -http://localhost:5173/blog/introducing-v2 - -my-react-app - ---- - -## Contact - -http://localhost:5173/contact - -my-react-app - ---- - -## Documentation - -http://localhost:5173/docs - -my-react-app - ---- - -## API Reference - -http://localhost:5173/docs/api - -my-react-app - ---- - -## Getting Started - -http://localhost:5173/docs/getting-started - -my-react-app - ---- - -## FAQ - -http://localhost:5173/faq - -my-react-app - ---- - -## Features - -http://localhost:5173/features - -my-react-app - ---- - -## Pricing - -http://localhost:5173/pricing - -my-react-app - ---- diff --git a/examples/my-react-app/public/llms.txt b/examples/my-react-app/public/llms.txt deleted file mode 100644 index e52208b..0000000 --- a/examples/my-react-app/public/llms.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Documentation - -- [Home](http://localhost:5173): Welcome to our demo React application -- [About](http://localhost:5173/about): About our company and mission -- [Blog](http://localhost:5173/blog): Latest blog posts and articles -- [Best Practices](http://localhost:5173/blog/best-practices): Development best practices -- [Introducing v2](http://localhost:5173/blog/introducing-v2): Major release announcement -- [Contact](http://localhost:5173/contact): Get in touch with us -- [Documentation](http://localhost:5173/docs): Complete documentation and guides -- [API Reference](http://localhost:5173/docs/api): Full API documentation -- [Getting Started](http://localhost:5173/docs/getting-started): Quick start guide -- [FAQ](http://localhost:5173/faq): Frequently asked questions -- [Features](http://localhost:5173/features): Core features and capabilities -- [Pricing](http://localhost:5173/pricing): Pricing plans and billing - ---- -*Generated by @llmtxt/react · 2026-05-12T16:29:03.933Z · 12 pages* diff --git a/examples/my-react-app/scripts/generate-llms.js b/examples/my-react-app/scripts/generate-llms.js index f249f47..e2a2ba4 100644 --- a/examples/my-react-app/scripts/generate-llms.js +++ b/examples/my-react-app/scripts/generate-llms.js @@ -1,15 +1,15 @@ import path from 'path' -import { writeLlmsFiles } from '@llmtxt/react' -import { routes } from '../llmtxt.routes.js' +import { scanPagesDirForRoutes, writeLlmsFiles } from '@llmtxt/react' const baseUrl = process.env.PUBLIC_SITE_URL || 'http://localhost:5173' const outDir = path.join(process.cwd(), 'public') const renderMode = (process.env.LLMTXT_RENDER || '').toLowerCase() +const pagesDir = path.join(process.cwd(), 'src/pages') console.log('Generating llms.txt files...') console.log(` Base URL: ${baseUrl}`) console.log(` Output: ${outDir}`) -console.log(` Routes: ${routes.length}`) +console.log(` Pages dir: ${pagesDir}`) async function fetchHtmlWithPlaywright(url, timeoutMs) { const { chromium } = await import('playwright') @@ -24,8 +24,18 @@ async function fetchHtmlWithPlaywright(url, timeoutMs) { } } +const scannedRoutes = await scanPagesDirForRoutes({ pagesDir, skipDynamic: true }) +console.log(` Scanned routes: ${scannedRoutes.length}`) + await writeLlmsFiles({ - routes, + routes: [ + ...scannedRoutes, + // Dynamic routes must be expanded into real paths. + { path: '/blog/introducing-v2', title: 'Introducing v2', description: 'Major release announcement' }, + { path: '/blog/best-practices', title: 'Best Practices', description: 'Development best practices' }, + { path: '/blog/performance-tips', title: 'Performance Tips', description: 'Tips for large sites' }, + { path: '/blog/integrations', title: 'New Integrations', description: 'New integrations available' }, + ], baseUrl, outDir, title: 'React Demo App', @@ -40,4 +50,3 @@ await writeLlmsFiles({ }) console.log('✓ Generated llms.txt and llms-full.txt') - diff --git a/examples/my-react-app/src/App.jsx b/examples/my-react-app/src/App.jsx index fe5b4c6..03e129d 100644 --- a/examples/my-react-app/src/App.jsx +++ b/examples/my-react-app/src/App.jsx @@ -1,16 +1,16 @@ import { BrowserRouter, Routes, Route, Link } from 'react-router-dom' import './App.css' -import Home from './pages/Home' -import Docs from './pages/Docs' -import DocsGettingStarted from './pages/DocsGettingStarted' -import DocsAPI from './pages/DocsAPI' -import Features from './pages/Features' -import Pricing from './pages/Pricing' -import Blog from './pages/Blog' -import BlogPost from './pages/BlogPost' -import About from './pages/About' -import Contact from './pages/Contact' -import FAQ from './pages/FAQ' +import Home from './pages' +import Docs from './pages/docs' +import DocsGettingStarted from './pages/docs/getting-started' +import DocsAPI from './pages/docs/api' +import Features from './pages/features' +import Pricing from './pages/pricing' +import Blog from './pages/blog' +import BlogPost from './pages/blog/[slug]' +import About from './pages/about' +import Contact from './pages/contact' +import FAQ from './pages/faq' function App() { return ( @@ -48,7 +48,7 @@ function App() {