Files
mfahampshire f648349e82 Max/docs-diataxis-ify (#6494)
* Diatixisify!

* First pass at Typedoc generation for TS SDK

* Remove overview pages

* Fix typos and remove codebase references from docs

Fix typos across network and developer docs: Quorum, available,
cryptosystem, transaction, proportional, Standalone. Remove TODO
placeholder from dVPN protocol page. Strip GitHub source links
from network docs to decouple documentation from repo structure.

* Expand thin landing pages across network and developer docs

- Add intro content to network overview, infrastructure, and reference landing pages
- Expand developer index with "where to start" guide
- Add usage instructions and explanations to all five TS playground pages
- Expand WebSocket client page with setup and message format examples

* Restructure Rust SDK developer docs

- Delete redundant mixnet example, message-helpers, and message-types subpages
- Delete client-pool architecture and example subpages (content folded into landing)
- Delete tcpproxy troubleshooting (folded into landing page)
- Add deprecation notices to TcpProxy pages, pointing to Stream module
- Add stream module docs: landing page, architecture, tutorial, and 4 example pages
- Add mixnet and client-pool tutorials
- Add SDK tour page
- Update navigation and landing pages with docs.rs links

* Restructure TS SDK developer docs

- Merge overview, installation, and getting started into TS SDK landing page
- Fold FAQ content into bundling/troubleshooting section
- Delete redundant overview, installation, start, and FAQ pages
- Update internal links in browsers.mdx and native.mdx
- Update navigation and example page imports

* Flatten and expand APIs section

- Collapse nested API subpages into single pages with inline Redoc embeds
- Rewrite introduction as landing page with decision table
- Add endpoint categories, quick curl examples to each API page
- Mark Explorer API as deprecated
- Move NS API deployment guide to operators/performance-and-testing
- Fix dangling /apis/nym-api/mainnet link in network-components
- Remove sandbox endpoints from all API pages

* Add redirects for moved and deleted pages

- Add 25 redirects covering TS SDK, Rust SDK, APIs, and network sections
- Fix dangling /developers/typescript/start link in operators changelog

* Replace individual example doc pages with GitHub-linked tables, expand tutorials

- replace individual example doc pages with GitHub-linked tables
- expand mixnet tutorial with persistent identity and split_sender sections
- add tcpproxy tutorial
- rename "API Reference" to "TypeDoc Reference" in TS SDK sidebar
- rename "Misc" to "Extras" in developer sidebar, move VPN CLI up
- remove echo server from tools
- update message-queue callout to reference actual modules
- fix mixnet/examples redirect collision

* Add SEO frontmatter, validate encryption standards, clean up URLs

- add title/description/schemaType/section/lastUpdated frontmatter to 48
  pages across developers, network, and APIs sections
- remove network/.archive/ directory (compare against develop instead)
- update nymtech.net → nym.com for website/blog links (keep infra URLs)
- add native proxy "in progress" callout for Rust/C/Go

* API-scraper update (#6598)

* read nodes and locations

* update python-prebuild.sh

* Address PR #6494 review feedback
- Use "mode" consistently instead of "role" on nym-nodes page
- Replace "staking" with "bonding" for NYM token collateral
- Wire up auto-scraped node counts via TimeNow + nodes-count.json
- Fix broken licensing images: download CC icons locally, replace inline HTML
- Fix 9 stale redirects pointing through deleted /network/architecture path

* Fix linkcheck errors
- Fix stale cross-links: /network/concepts/ → /network/mixnet-mode/
- Replace README.md references with globals.md in TypeDoc output
- Add entryFileName: globals to typedoc.json configs to prevent recurrence

* Fix remaining stale /network/architecture links
- zk-nym-overview: architecture/nyx#nym-api → /network/infrastructure/nyx#nym-api
- setup: network/architecture → /network/overview

* Remove accidentally re-included architecture.md file from rebase

* Standardize tutorials, document examples, add llms.txt, apply tone fixes

- Expand Rust SDK tutorials with step-by-step structure; document all SDK examples across mixnet, client-pool, and tcpproxy pages
- Add llms.txt generation script, wire into build and CI workflows
- Apply tone/style fixes: deduplicate callouts, vary sentence structure, standardize voice consistency across changed pages

* Consolidate redundant network overview docs

* Trim dev docs: git-first imports, stream notice, collapse TcpProxy

* Update tutorial

* Refresh auto-generated API and command outputs

* Update network section docs

* Update developer and API docs: reusable components, stream protocol, conventions, tutorial fixes

* Fix Rust SDK tutorial bugs: setup_env, port conflicts, logging,
open_stream race condition

* Update stream.mdx

* Remove docs.rs link from Stream overview for the moment

* add llms.txt and llms-full.txt note to readme

---------

Co-authored-by: import this <97586125+serinko@users.noreply.github.com>
2026-04-09 15:25:31 +00:00

177 lines
5.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Generates public/llms-full.txt by walking pages/, reading _meta.json
* for ordering, and concatenating all MDX/MD content as clean Markdown
* with per-page frontmatter (Next.js llms-full.txt format).
*
* Run from repo root or documentation/docs/:
* node documentation/scripts/next-scripts/generate-llms-txt.mjs
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PAGES_DIR = path.resolve(__dirname, '../../docs/pages');
const OUTPUT_FILE = path.resolve(__dirname, '../../docs/public/llms-full.txt');
const SITE_URL = 'https://nym.com/docs';
// Directories to skip entirely (auto-generated API reference, archives, etc.)
const SKIP_DIRS = new Set(['api', 'archive', 'playground']);
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/** Read _meta.json for ordered keys; fall back to alphabetical. */
function getPageOrder(dir) {
const metaPath = path.join(dir, '_meta.json');
if (fs.existsSync(metaPath)) {
try {
const meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
return Object.keys(meta);
} catch { /* fall through */ }
}
return fs.readdirSync(dir)
.filter(f => !f.startsWith('_') && !f.startsWith('.'))
.map(f => f.replace(/\.mdx?$/, ''))
.filter((v, i, a) => a.indexOf(v) === i)
.sort();
}
/** Extract title from frontmatter or first H1. */
function extractTitle(content, fallback) {
const fm = content.match(/^---[\s\S]*?title:\s*["']?(.+?)["']?\s*$/m);
if (fm) return fm[1];
const h1 = content.match(/^#\s+(.+)$/m);
if (h1) return h1[1];
return fallback.replace(/[-_]/g, ' ');
}
/** Extract description from frontmatter. */
function extractDescription(content) {
const fm = content.match(/^---[\s\S]*?description:\s*["']?(.+?)["']?\s*$/m);
return fm ? fm[1] : '';
}
/** Strip frontmatter, imports, and JSX from MDX, leaving clean Markdown. */
function stripMdx(content) {
let s = content;
// Frontmatter
s = s.replace(/^---[\s\S]*?---\n*/m, '');
// Import statements
s = s.replace(/^import\s+.*$/gm, '');
// Self-closing JSX tags: <Component ... />
s = s.replace(/^\s*<\w[\w.-]*(?:\s[^>]*)?\s*\/>\s*$/gm, '');
// JSX block tags on their own line: <Callout type="info">, </Callout>, etc.
// Keep the children — only remove the tag lines themselves.
s = s.replace(/^\s*<\/?\w[\w.-]*(?:\s[^>]*)?\s*>\s*$/gm, '');
// Collapse 3+ blank lines → 2
s = s.replace(/\n{3,}/g, '\n\n');
return s.trim();
}
/** Convert file path to URL. */
function fileToUrl(filePath) {
let rel = path.relative(PAGES_DIR, filePath)
.replace(/\.mdx?$/, '')
.replace(/\/index$/, '');
return `${SITE_URL}/${rel}`;
}
// ---------------------------------------------------------------------------
// Recursive page collector
// ---------------------------------------------------------------------------
function collectPages(dir) {
const pages = [];
const order = getPageOrder(dir);
for (const key of order) {
const subDir = path.join(dir, key);
// Skip excluded directories
if (SKIP_DIRS.has(key) && fs.existsSync(subDir) && fs.statSync(subDir).isDirectory()) {
continue;
}
// Find the page file (.mdx preferred over .md)
let filePath = null;
for (const ext of ['.mdx', '.md']) {
const p = path.join(dir, `${key}${ext}`);
if (fs.existsSync(p)) { filePath = p; break; }
}
// Or an index file inside a subdirectory
if (!filePath && fs.existsSync(subDir) && fs.statSync(subDir).isDirectory()) {
for (const ext of ['.mdx', '.md']) {
const p = path.join(subDir, `index${ext}`);
if (fs.existsSync(p)) { filePath = p; break; }
}
}
if (filePath) {
const raw = fs.readFileSync(filePath, 'utf-8');
const title = extractTitle(raw, key);
const description = extractDescription(raw);
const body = stripMdx(raw);
if (body.length > 0) {
pages.push({ title, description, url: fileToUrl(filePath), body });
}
}
// Recurse into subdirectory
if (fs.existsSync(subDir) && fs.statSync(subDir).isDirectory()) {
pages.push(...collectPages(subDir));
}
}
return pages;
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
console.log(`Scanning ${PAGES_DIR} ...`);
const pages = collectPages(PAGES_DIR);
const lines = [];
// Global header
lines.push(`# Nym Documentation\n`);
lines.push(`@version: 1.20.4`);
lines.push(`@generated: ${new Date().toISOString().split('T')[0]}`);
lines.push(`@pages: ${pages.length}`);
lines.push(`@source: https://github.com/nymtech/nym/tree/develop/documentation/docs`);
lines.push('');
// Per-page blocks
for (const page of pages) {
lines.push('---');
lines.push(`title: ${page.title}`);
if (page.description) {
lines.push(`description: ${page.description}`);
}
lines.push(`url: ${page.url}`);
lines.push('---');
lines.push('');
lines.push(page.body);
lines.push('');
}
const output = lines.join('\n');
fs.writeFileSync(OUTPUT_FILE, output);
const sizeKb = (Buffer.byteLength(output, 'utf-8') / 1024).toFixed(0);
console.log(`Wrote ${pages.length} pages to ${OUTPUT_FILE} (${sizeKb} KB)`);