From a7893843c2dbbcbff00568e787c261c27ef77b7e Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Wed, 20 May 2026 14:16:46 +0200 Subject: [PATCH 1/2] feat: automate llms.txt and developers/docs/llms.txt generation --- .claude/commands/update-llms-txt.md | 87 ------ app/developers/docs/llms.txt/route.ts | 46 +++ app/llms.txt/route.ts | 42 +++ .../architecture/llms-txt-automation.md | 73 +++++ public/llms.txt | 263 ----------------- src/components/Footer/index.tsx | 274 +----------------- src/lib/llms-txt/frontmatter.ts | 55 ++++ src/lib/llms-txt/render.ts | 143 +++++++++ src/lib/nav/footerLinks.ts | 115 ++++++++ 9 files changed, 482 insertions(+), 616 deletions(-) delete mode 100644 .claude/commands/update-llms-txt.md create mode 100644 app/developers/docs/llms.txt/route.ts create mode 100644 app/llms.txt/route.ts create mode 100644 docs/solutions/architecture/llms-txt-automation.md delete mode 100644 public/llms.txt create mode 100644 src/lib/llms-txt/frontmatter.ts create mode 100644 src/lib/llms-txt/render.ts create mode 100644 src/lib/nav/footerLinks.ts diff --git a/.claude/commands/update-llms-txt.md b/.claude/commands/update-llms-txt.md deleted file mode 100644 index 854340da82e..00000000000 --- a/.claude/commands/update-llms-txt.md +++ /dev/null @@ -1,87 +0,0 @@ -# Update LLMS.txt Command - -This command helps maintain the `public/llms.txt` file by monitoring key navigation files: - -1. **Main Navigation**: `src/components/Nav/useNavigation.ts` -2. **Developer Docs**: `src/data/developer-docs-links.yaml` -3. **Footer Links**: `src/components/Footer.tsx` - -## How it works - -- Adds missing links to appropriate sections -- Preserves existing descriptions and organization -- Follows established llms.txt structure -- **Prefers static markdown files URLs over html URLs** for better LLM comprehension - -## Implementation - -When this command is executed, I will: - -### Step 1: Parse Navigation Files - -**Main Navigation** (`src/components/Nav/useNavigation.ts`): - -```javascript -// Extract linkSections object structure -// Parse learn, use, build, participate sections -// Get href, label, and description for each link -``` - -**Developer Docs** (`src/data/developer-docs-links.yaml`): - -```yaml -# Parse foundational-topics, ethereum-stack, advanced, design-fundamentals -# Extract href and id mappings -# Build hierarchical structure -``` - -**Footer Links** (`src/components/Footer.tsx`): - -```javascript -// Extract linkSections and dipperLinks arrays -// Get all footer navigation items -// Include external links (blog, ESP, Devcon) -``` - -### Step 2: Analyze Current llms.txt - -- Parse existing sections and their links -- Extract current URLs and descriptions -- Identify section organization and hierarchy - -### Step 3: URL to Markdown File Mapping - -**Priority: Static markdown files URLs over web html URLs** - -For each link, I will: - -1. Check if corresponding markdown file exists in `public/content/`. **Ignore translations**: Skip `public/content/translations/` directory (60+ language versions) -2. Use a URL pointing to the markdown file for the page: `https://ethereum.org/content/[page]/index.md` -3. Fall back to web URL only if no markdown file exists -4. Example: `https://ethereum.org/learn/` → `https://ethereum.org/content/learn/index.md` -5. Example2: `https://ethereum.org/guides/how-to-use-a-wallet/` → `https://ethereum.org/content/guides/how-to-use-a-wallet/index.md` - -### Step 4: Smart Link Categorization - -New links are categorized using these rules: - -1. **Learn Section**: `/learn/`, `/what-is-*`, `/guides/`, `/quizzes/`, `/glossary/` -2. **Use Section**: `/get-eth`, `/wallets/`, `/dapps/`, `/staking/`, use cases -3. **Build Section**: `/developers/`, `/enterprise/`, developer tools -4. **Participate Section**: `/community/`, `/contributing/`, `/foundation/` -5. **Research Section**: `/whitepaper`, `/roadmap/`, `/eips/`, `/governance/` - -### Step 5: Validation & Quality Checks - -- Verify all markdown files exist in `public/content/` -- Check for duplicate links within sections -- Validate section organization and hierarchy -- Ensure descriptions are informative and concise - -### Step 6: Execute Action - -Update llms.txt file with improved structure and validated links - ---- - -The command ensures the llms.txt file remains comprehensive and current with minimal manual maintenance. diff --git a/app/developers/docs/llms.txt/route.ts b/app/developers/docs/llms.txt/route.ts new file mode 100644 index 00000000000..a79dca91825 --- /dev/null +++ b/app/developers/docs/llms.txt/route.ts @@ -0,0 +1,46 @@ +import { getTranslations } from "next-intl/server" + +import docLinks from "@/data/developer-docs-links.yaml" + +import { + type DocLink, + renderDocsNode, + type Translator, +} from "@/lib/llms-txt/render" + +export const dynamic = "force-static" + +const INTRO = `# Ethereum Developer Documentation + +> Technical reference for building on Ethereum: protocol concepts, the Ethereum stack, smart contracts, scaling solutions, and developer tooling. + +This file indexes the developer documentation under https://ethereum.org/developers/docs/. For the full ethereum.org index including learner content, guides, and community resources, see https://ethereum.org/llms.txt.` + +const links = docLinks as unknown as DocLink[] + +const renderTopGroup = (group: DocLink, t: Translator): string => { + const lines = [`## ${t(group.id)}`, ""] + for (const item of group.items ?? []) { + lines.push(...renderDocsNode(item, 0, t)) + } + return lines.join("\n") +} + +export const GET = async () => { + const t = await getTranslations({ + locale: "en", + namespace: "page-developers-docs", + }) + + const sections = links.map((entry) => + entry.items + ? renderTopGroup(entry, t) + : renderDocsNode(entry, 0, t).join("\n") + ) + + const body = [INTRO, ...sections, ""].join("\n\n") + + return new Response(body, { + headers: { "content-type": "text/plain; charset=utf-8" }, + }) +} diff --git a/app/llms.txt/route.ts b/app/llms.txt/route.ts new file mode 100644 index 00000000000..9e479379592 --- /dev/null +++ b/app/llms.txt/route.ts @@ -0,0 +1,42 @@ +import { getTranslations } from "next-intl/server" + +import { renderLegalSection, renderNavSection } from "@/lib/llms-txt/render" +import { buildNavigation } from "@/lib/nav/buildNavigation" +import { + buildFooterDipperLinks, + buildFooterLinkSections, +} from "@/lib/nav/footerLinks" + +export const dynamic = "force-static" + +const INTRO = `# Ethereum.org + +> The official Ethereum website providing comprehensive education, resources, and community information about Ethereum — the decentralized world computer that enables smart contracts and decentralized applications. + +Ethereum.org is the primary educational hub for Ethereum, offering beginner-friendly explanations alongside advanced technical documentation. The site covers everything from basic concepts like "What is Ethereum?" to detailed developer guides, staking information, and protocol research. For the developer-documentation-only index, see https://ethereum.org/developers/docs/llms.txt.` + +export const GET = async () => { + const t = await getTranslations({ locale: "en", namespace: "common" }) + + const nav = buildNavigation(t) + const footerSections = buildFooterLinkSections(t) + const dipperLinks = buildFooterDipperLinks(t) + + const findFooter = (title: string) => + footerSections.find((s) => s.title === title) + + const body = [ + INTRO, + renderNavSection(nav.learn, findFooter(nav.learn.label)), + renderNavSection(nav.use, findFooter(nav.use.label)), + renderNavSection(nav.build, findFooter(nav.build.label)), + renderNavSection(nav.participate, findFooter(nav.participate.label)), + renderNavSection(nav.research, findFooter(nav.research.label)), + renderLegalSection(dipperLinks), + "", + ].join("\n\n") + + return new Response(body, { + headers: { "content-type": "text/plain; charset=utf-8" }, + }) +} diff --git a/docs/solutions/architecture/llms-txt-automation.md b/docs/solutions/architecture/llms-txt-automation.md new file mode 100644 index 00000000000..822a1ee6b67 --- /dev/null +++ b/docs/solutions/architecture/llms-txt-automation.md @@ -0,0 +1,73 @@ +--- +title: "Automated llms.txt and developers/docs/llms.txt Generation" +date: 2026-05-20 +category: architecture +module: app/llms.txt, app/developers/docs/llms.txt, src/lib/llms-txt +tags: + - llms-txt + - seo + - automation + - nav +problem_type: "feature, automation, content-pipeline" +--- + +# Automated `llms.txt` Generation + +Two `force-static` App Router routes replace the hand-maintained `public/llms.txt`. They regenerate on every deploy; no manual maintenance. + +- `ethereum.org/llms.txt` — full site index, organized by main-nav top sections. +- `ethereum.org/developers/docs/llms.txt` — developer-docs-only index, organized by the docs sidebar. + +The split mirrors `nextjs.org/llms.txt` + `nextjs.org/docs/llms.txt`: the root file points at the docs file rather than inlining 100+ lines of deeply nested developer docs. + +## Strategy + +### What appears, and where it lives + +| Decision | Choice | +| ------------------ | ---------------------------------------------------------------------------------------------- | +| Which pages appear | Driven by nav files only (main nav, Footer, developer-docs YAML). Never walks `public/content/`. | +| Section structure | Mirrors the main-nav top sections 1:1 (Learn / Use / Build / Participate / Research) + Legal & Policies from Footer's secondary links. | +| Per-item label | The nav file's label (resolved via the existing i18n JSON). | +| Per-item URL | Always the page's pretty URL (`https://ethereum.org/{href}`). Never `/content/*/index.md`. | +| Per-item description | First non-empty of: page's frontmatter `description` → nav's description → label only. | +| Locale | English only at root. Per-locale variants are a later, opt-in extension (no code refactor needed). | + +### Per-section layout + +``` +## {section.label} ← top sections from main nav + +- {top-level leaf items} ← e.g. Overview, Quizzes, Videos + +### {sub-group label} ← e.g. Ethereum Explained, How Ethereum Works +- {sub-group items} + +### More ← Footer items not already in main nav, dedup'd by href +- ... +``` + +### Root file vs docs file + +- **Root file (`/llms.txt`)** treats the developer docs as one pointer (the four top-level Documentation entries from main nav) and links out to `/developers/docs/llms.txt` for the full tree. +- **Docs file (`/developers/docs/llms.txt`)** renders `developer-docs-links.yaml` directly — top groups as `##`, nested items as indented bullets at the depth they sit in the YAML. + +This keeps the root file scannable (~170 lines) and lets crawlers that want depth follow the cross-link. + +## Sources of truth + +| Source | Provides | +| --------------------------------------------- | ------------------------------------------------------------------------------------------ | +| `src/lib/nav/buildNavigation.ts` | Main-nav top sections + sub-groups + items + their nav descriptions. | +| `src/lib/nav/footerLinks.ts` | Footer link sections + dipper links (Legal & Policies). Extracted so Footer and llms.txt share one source. | +| `src/data/developer-docs-links.yaml` | The docs sidebar tree, including nested items. | +| `src/intl/en/common.json` + `page-developers-docs.json` | English labels and descriptions for the i18n keys above (via `getTranslations`). | +| `public/content/{slug}/index.md` frontmatter | The richer per-page `description` used preferentially over the nav description. | + +To change what appears in `llms.txt`, edit one of the sources above. The output regenerates on the next deploy. The generated `.txt` files are not in the repo — there is nothing to hand-edit. + +## Failure handling + +- Missing i18n key → falls back to the key string via the site-wide `getMessageFallback`. Same behavior as anywhere else on the site. +- Frontmatter `description` missing or unreadable → falls back to the nav description, then to label only. Never throws. +- Nav `href` points at a page with no `index.md` (JSX-only landings, external URLs) → no frontmatter lookup, nav description carries the entry. diff --git a/public/llms.txt b/public/llms.txt deleted file mode 100644 index 2f6a95bcaa9..00000000000 --- a/public/llms.txt +++ /dev/null @@ -1,263 +0,0 @@ -# Ethereum.org - -> The official Ethereum website providing comprehensive education, resources, and community information about Ethereum - the decentralized world computer that enables smart contracts and decentralized applications. - -Ethereum.org is the primary educational hub for Ethereum, offering beginner-friendly explanations alongside advanced technical documentation. The site covers everything from basic concepts like "What is Ethereum?" to detailed developer guides, staking information, and the latest protocol research. - -## Learn - -### Basics -- [What is Ethereum?](https://ethereum.org/what-is-ethereum/): Introduction to Ethereum and its core concepts -- [What is Ether (ETH)?](https://ethereum.org/eth/): Understanding Ethereum's native cryptocurrency -- [Ethereum Wallets](https://ethereum.org/wallets/): Guide to storing and managing ETH and tokens -- [What is Web3?](https://ethereum.org/content/web3/index.md): Understanding the decentralized web -- [Smart Contracts](https://ethereum.org/content/smart-contracts/index.md): Introduction to programmable contracts - -### Advanced Topics -- [Gas and Fees](https://ethereum.org/gas/): Understanding transaction costs -- [Bridges](https://ethereum.org/content/bridges/index.md): Moving assets between blockchains -- [Zero Knowledge Proofs](https://ethereum.org/content/zero-knowledge-proofs/index.md): Privacy and scaling technology -- [Run a Node](https://ethereum.org/run-a-node/): Operating Ethereum infrastructure -- [Ethereum Security](https://ethereum.org/content/security/index.md): Protecting yourself in the ecosystem - -### Educational Resources -- [Quizzes](https://ethereum.org/quizzes/): Test your Ethereum knowledge -- [Glossary](https://ethereum.org/glossary/): Definitions of key terms - -## Use - -### Getting Started -- [Start with Crypto](https://ethereum.org/start/): Complete beginner's guide -- [Find a Wallet](https://ethereum.org/wallets/find-wallet/): Wallet selection tool -- [Get ETH](https://ethereum.org/get-eth/): How to acquire Ethereum -- [Decentralized Apps (DApps)](https://ethereum.org/dapps/): Applications built on Ethereum - -### Practical Guides -- [Guides Overview](https://ethereum.org/content/guides/index.md): Complete guide collection -- [How to Create an Ethereum Account](https://ethereum.org/content/guides/how-to-create-an-ethereum-account/index.md) -- [How to Use a Wallet](https://ethereum.org/content/guides/how-to-use-a-wallet/index.md): Managing your crypto wallet -- [How to Swap Tokens](https://ethereum.org/content/guides/how-to-swap-tokens/index.md): Exchanging tokens on decentralized exchanges -- [How to Use a Bridge](https://ethereum.org/content/guides/how-to-use-a-bridge/index.md): Moving assets between blockchains -- [How to Revoke Token Access](https://ethereum.org/content/guides/how-to-revoke-token-access/index.md): Managing token permissions - -### Use Cases -- [Stablecoins](https://ethereum.org/stablecoins/): Dollar-pegged cryptocurrencies -- [NFTs](https://ethereum.org/content/nft/index.md): Non-fungible tokens and digital ownership -- [DeFi](https://ethereum.org/content/defi/index.md): Decentralized finance applications -- [Payments](https://ethereum.org/content/payments/index.md): Using ETH for transactions -- [DAOs](https://ethereum.org/content/dao/index.md): Decentralized autonomous organizations - -### Emerging Applications -- [Decentralized Identity](https://ethereum.org/content/decentralized-identity/index.md): Self-sovereign identity -- [Decentralized Social Networks](https://ethereum.org/content/social-networks/index.md): Web3 social platforms -- [Decentralized Science (DeSci)](https://ethereum.org/content/desci/index.md): Research and collaboration -- [Regenerative Finance (ReFi)](https://ethereum.org/content/refi/index.md): Sustainable finance -- [AI Agents](https://ethereum.org/content/ai-agents/index.md): Autonomous AI on blockchain -- [Prediction Markets](https://ethereum.org/content/prediction-markets/index.md): Forecasting platforms -- [Real World Assets](https://ethereum.org/content/real-world-assets/index.md): Tokenizing physical assets - -### Staking -- [Staking Overview](https://ethereum.org/staking/): Earning rewards by validating -- [Solo Staking](https://ethereum.org/content/staking/solo/index.md): Run your own validator for maximum rewards and control -- [Staking as a Service](https://ethereum.org/content/staking/saas/index.md): Managed staking solutions with professional operators -- [Pooled Staking](https://ethereum.org/content/staking/pools/index.md): Stake with others to meet 32 ETH requirement - -### Layer 2 Networks -- [Layer 2 Introduction](https://ethereum.org/layer-2/): Scaling solutions overview -- [Explore Networks](https://ethereum.org/layer-2/networks/): Available L2 options -- [Learn about L2](https://ethereum.org/layer-2/learn/): Technical deep dive - -## Build - -### Developer Hub -- [Developer Home](https://ethereum.org/developers/): Central hub for builders -- [Developer Documentation](https://ethereum.org/developers/docs/): Technical documentation -- [Tutorials](https://ethereum.org/developers/tutorials/): Step-by-step guides -- [Learning Tools](https://ethereum.org/developers/learning-tools/): Interactive education -- [Local Development](https://ethereum.org/developers/local-environment/): Setup guides -- [Community Grants](https://ethereum.org/content/community/grants/index.md): Funding opportunities for developers - -### Documentation -- [Developer Documentation](https://ethereum.org/content/developers/docs/index.md): Complete technical reference - -#### Foundational Topics -- [Intro to Ethereum](https://ethereum.org/content/developers/docs/intro-to-ethereum/index.md): Developer-focused introduction -- [Intro to Ether](https://ethereum.org/content/developers/docs/intro-to-ether/index.md): Understanding ETH as a developer -- [Intro to DApps](https://ethereum.org/content/developers/docs/dapps/index.md): Decentralized applications -- [Web2 vs Web3](https://ethereum.org/content/developers/docs/web2-vs-web3/index.md): Comparing paradigms -- [Accounts](https://ethereum.org/content/developers/docs/accounts/index.md): Externally owned and contract accounts -- [Transactions](https://ethereum.org/content/developers/docs/transactions/index.md): State changes and execution -- [Blocks](https://ethereum.org/content/developers/docs/blocks/index.md): Transaction batching and ordering -- [Ethereum Virtual Machine (EVM)](https://ethereum.org/content/developers/docs/evm/index.md): The execution environment - - [EVM Opcodes](https://ethereum.org/content/developers/docs/evm/opcodes/index.md): Low-level instructions -- [Gas and Fees](https://ethereum.org/content/developers/docs/gas/index.md): Transaction costs and optimization -- [Nodes and Clients](https://ethereum.org/content/developers/docs/nodes-and-clients/index.md): Network infrastructure - - [Running a Node](https://ethereum.org/content/developers/docs/nodes-and-clients/run-a-node/index.md): Setting up infrastructure - - [Client Diversity](https://ethereum.org/content/developers/docs/nodes-and-clients/client-diversity/index.md): Network resilience - - [Nodes as a Service](https://ethereum.org/content/developers/docs/nodes-and-clients/nodes-as-a-service/index.md): Managed node providers - - [Node Architecture](https://ethereum.org/content/developers/docs/nodes-and-clients/node-architecture/index.md): System design - - [Light Clients](https://ethereum.org/content/developers/docs/nodes-and-clients/light-clients/index.md): Lightweight verification - - [Archive Nodes](https://ethereum.org/content/developers/docs/nodes-and-clients/archive-nodes/index.md): Full historical data - - [Bootnodes](https://ethereum.org/content/developers/docs/nodes-and-clients/bootnodes/index.md): Network discovery -- [Networks](https://ethereum.org/content/developers/docs/networks/index.md): Mainnet, testnets, and local networks -- [Consensus Mechanisms](https://ethereum.org/content/developers/docs/consensus-mechanisms/index.md): Network agreement - - [Proof of Stake](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/index.md): Current consensus mechanism - - [Gasper](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/gasper/index.md): Ethereum's consensus protocol - - [Weak Subjectivity](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md): Security assumptions - - [Attestations](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/attestations/index.md): Validator voting mechanism - - [Rewards and Penalties](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md): Validator incentives - - [Attack and Defense](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/attack-and-defense/index.md): Security considerations - - [Keys](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/keys/index.md): Validator key management - - [PoS vs PoW](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md): Consensus comparison - - [Block Proposal](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/block-proposal/index.md): Block creation process - - [PoS FAQs](https://ethereum.org/content/developers/docs/consensus-mechanisms/pos/faqs/index.md): Frequently asked questions - - [Proof of Work](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/index.md): Historical consensus mechanism - - [Mining](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/index.md): Block production process - - [Mining Algorithms](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md): Cryptographic algorithms - - [Dagger-Hashimoto](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md): Original algorithm - - [Ethash](https://ethereum.org/content/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md): Production algorithm - - [Proof of Authority](https://ethereum.org/content/developers/docs/consensus-mechanisms/poa/index.md): Permissioned consensus - -#### Ethereum Stack -- [Ethereum Stack Overview](https://ethereum.org/content/developers/docs/ethereum-stack/index.md): Technology layers -- [Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/index.md): Self-executing programs - - [Smart Contract Languages](https://ethereum.org/content/developers/docs/smart-contracts/languages/index.md): Solidity, Vyper, and others - - [Smart Contract Anatomy](https://ethereum.org/content/developers/docs/smart-contracts/anatomy/index.md): Structure and components - - [Smart Contract Libraries](https://ethereum.org/content/developers/docs/smart-contracts/libraries/index.md): Reusable code - - [Testing Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/testing/index.md): Verification strategies - - [Compiling Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/compiling/index.md): Build process - - [Deploying Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/deploying/index.md): Deployment strategies - - [Verifying Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/verifying/index.md): Source code verification - - [Upgrading Smart Contracts](https://ethereum.org/content/developers/docs/smart-contracts/upgrading/index.md): Contract upgrade patterns - - [Smart Contract Security](https://ethereum.org/content/developers/docs/smart-contracts/security/index.md): Security best practices - - [Formal Verification](https://ethereum.org/content/developers/docs/smart-contracts/formal-verification/index.md): Mathematical proof methods - - [Composability](https://ethereum.org/content/developers/docs/smart-contracts/composability/index.md): Contract interaction patterns -- [Development Networks](https://ethereum.org/content/developers/docs/development-networks/index.md): Local and test environments -- [Development Frameworks](https://ethereum.org/content/developers/docs/frameworks/index.md): Hardhat, Truffle, and others -- [Ethereum Client APIs](https://ethereum.org/developers/docs/apis/): Interacting with Ethereum - - [JavaScript APIs](https://ethereum.org/content/developers/docs/apis/javascript/index.md): Web3.js and ethers.js - - [Backend APIs](https://ethereum.org/content/developers/docs/apis/backend/index.md): Server-side integration - - [JSON-RPC](https://ethereum.org/content/developers/docs/apis/json-rpc/index.md): Protocol specification -- [Data and Analytics](https://ethereum.org/content/developers/docs/data-and-analytics/index.md): Blockchain data access - - [Block Explorers](https://ethereum.org/content/developers/docs/data-and-analytics/block-explorers/index.md): Data visualization tools -- [Storage](https://ethereum.org/content/developers/docs/storage/index.md): Data persistence strategies -- [IDEs](https://ethereum.org/content/developers/docs/ides/index.md): Development environments -- [Programming Languages](https://ethereum.org/content/developers/docs/programming-languages/index.md): Language-specific resources - - [Dart](https://ethereum.org/content/developers/docs/programming-languages/dart/index.md): Flutter and mobile development - - [Delphi](https://ethereum.org/content/developers/docs/programming-languages/delphi/index.md): Object Pascal programming - - [.NET](https://ethereum.org/content/developers/docs/programming-languages/dot-net/index.md): Microsoft .NET framework - - [Elixir](https://ethereum.org/content/developers/docs/programming-languages/elixir/index.md): Functional programming language - - [Go](https://ethereum.org/content/developers/docs/programming-languages/golang/index.md): Google's programming language - - [Java](https://ethereum.org/content/developers/docs/programming-languages/java/index.md): Enterprise application development - - [JavaScript](https://ethereum.org/content/developers/docs/programming-languages/javascript/index.md): Web3 development - - [Python](https://ethereum.org/content/developers/docs/programming-languages/python/index.md): Backend development - - [Ruby](https://ethereum.org/content/developers/docs/programming-languages/ruby/index.md): Web application development - - [Rust](https://ethereum.org/content/developers/docs/programming-languages/rust/index.md): Systems programming - -#### Advanced Topics -- [Bridges](https://ethereum.org/content/developers/docs/bridges/index.md): Cross-chain interoperability -- [Standards](https://ethereum.org/content/developers/docs/standards/index.md): Ethereum Request for Comments (ERCs) - - [Token Standards](https://ethereum.org/content/developers/docs/standards/tokens/index.md): Ethereum token specifications - - [ERC-20](https://ethereum.org/content/developers/docs/standards/tokens/erc-20/index.md): Fungible token standard - - [ERC-721](https://ethereum.org/content/developers/docs/standards/tokens/erc-721/index.md): Non-fungible token standard - - [ERC-1155](https://ethereum.org/content/developers/docs/standards/tokens/erc-1155/index.md): Multi-token standard -- [MEV](https://ethereum.org/content/developers/docs/mev/index.md): Maximal Extractable Value -- [Oracles](https://ethereum.org/content/developers/docs/oracles/index.md): External data integration -- [Scaling](https://ethereum.org/content/developers/docs/scaling/index.md): Layer 2 solutions - - [Optimistic Rollups](https://ethereum.org/content/developers/docs/scaling/optimistic-rollups/index.md): Fraud proof scaling - - [ZK Rollups](https://ethereum.org/content/developers/docs/scaling/zk-rollups/index.md): Zero-knowledge scaling - - [State Channels](https://ethereum.org/content/developers/docs/scaling/state-channels/index.md): Off-chain computation - - [Sidechains](https://ethereum.org/content/developers/docs/scaling/sidechains/index.md): Independent blockchains - - [Plasma](https://ethereum.org/content/developers/docs/scaling/plasma/index.md): Child chain scaling solution - - [Validium](https://ethereum.org/content/developers/docs/scaling/validium/index.md): Off-chain data availability -- [Data Availability](https://ethereum.org/content/developers/docs/data-availability/index.md): Data accessibility solutions - - [Blockchain Data Storage Strategies](https://ethereum.org/content/developers/docs/data-availability/blockchain-data-storage-strategies/index.md): Storage optimization methods -- [Networking Layer](https://ethereum.org/content/developers/docs/networking-layer/index.md): P2P networking - - [Network Addresses](https://ethereum.org/content/developers/docs/networking-layer/network-addresses/index.md): Node identification - - [Portal Network](https://ethereum.org/content/developers/docs/networking-layer/portal-network/index.md): Light client networking -- [Data Structures and Encoding](https://ethereum.org/content/developers/docs/data-structures-and-encoding/index.md): Low-level data formats - - [Patricia Merkle Trie](https://ethereum.org/content/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md): Ethereum's data structure - - [RLP](https://ethereum.org/content/developers/docs/data-structures-and-encoding/rlp/index.md): Recursive Length Prefix encoding - - [SSZ](https://ethereum.org/content/developers/docs/data-structures-and-encoding/ssz/index.md): Simple Serialize format - - [Web3 Secret Storage](https://ethereum.org/content/developers/docs/data-structures-and-encoding/web3-secret-storage/index.md): Key storage specification - -#### Design Fundamentals -- [Design and UX](https://ethereum.org/content/developers/docs/design-and-ux/index.md): User experience for Web3 - - [Heuristics for Web3](https://ethereum.org/content/developers/docs/design-and-ux/heuristics-for-web3/index.md): UX design principles - - [DEX Design Best Practices](https://ethereum.org/content/developers/docs/design-and-ux/dex-design-best-practice/index.md): Decentralized exchange UX - -### Enterprise -- [Enterprise Ethereum](https://ethereum.org/enterprise/): Business adoption and use cases - -## Participate - -### Community -- [Community Hub](https://ethereum.org/community/): Get involved with Ethereum -- [Ethereum Online](https://ethereum.org/content/community/online/index.md): Virtual communities and platforms -- [Ethereum Events](https://ethereum.org/content/community/events/index.md): Meetups and conferences worldwide -- [Community Grants](https://ethereum.org/content/community/grants/index.md): Funding opportunities for ecosystem projects -- [Bug Bounty Program](https://ethereum.org/bug-bounty/): Security vulnerability rewards -- [Code of Conduct](https://ethereum.org/content/community/code-of-conduct/index.md): Community guidelines and expectations -- [Open Research](https://ethereum.org/content/community/research/index.md): Academic research and collaboration - -### Contributing -- [Contributing Guide](https://ethereum.org/content/contributing/index.md): How to contribute to ethereum.org -- [Translation Program](https://ethereum.org/content/contributing/translation-program/index.md): Localization efforts and language support -- [Content Resources](https://ethereum.org/content/contributing/content-resources/index.md): Writing guidelines and standards -- [Design Contributions](https://ethereum.org/content/contributing/design/index.md): Design resources and style guides - -### About -- [About Ethereum.org](https://ethereum.org/content/about/index.md): Mission, vision, and team -- [Ethereum Foundation](https://ethereum.org/content/foundation/index.md): Supporting organization and governance -- [Ethereum Brand Assets](https://ethereum.org/assets/): Official logos and branding guidelines - -### External Resources -- [Ethereum Foundation Blog](https://blog.ethereum.org/): Official announcements and updates -- [Ethereum Support Program (ESP)](https://esp.ethereum.foundation): Funding for ecosystem projects -- [Devcon](https://devcon.org/): Annual Ethereum developer conference - -## Research - -### Foundational Documents -- [Ethereum Whitepaper](https://ethereum.org/content/whitepaper/index.md): Original vision document by Vitalik Buterin -- [Ethereum Improvement Proposals (EIPs)](https://ethereum.org/content/eips/index.md): Protocol upgrade specifications -- [Ethereum History](https://ethereum.org/content/ethereum-forks/index.md): Timeline and key milestones - -### Protocol Development -- [Ethereum Roadmap](https://ethereum.org/roadmap/): Future development plans and priorities -- [Roadmap Security](https://ethereum.org/content/roadmap/security/index.md): Security improvements and cryptographic advances -- [Roadmap Scaling](https://ethereum.org/content/roadmap/scaling/index.md): Scalability solutions and layer 2 integration -- [Roadmap User Experience](https://ethereum.org/content/roadmap/user-experience/index.md): UX improvements and account abstraction -- [Roadmap Future-Proofing](https://ethereum.org/content/roadmap/future-proofing/index.md): Long-term sustainability and quantum resistance - -### Research Areas -- [Open Research](https://ethereum.org/content/community/research/index.md): Academic research and collaboration opportunities -- [Governance](https://ethereum.org/content/governance/index.md): Protocol governance and decision-making processes -- [Energy Consumption](https://ethereum.org/content/energy-consumption/index.md): Environmental impact and sustainability -- [Trillion Dollar Security](https://ethereum.org/trillion-dollar-security/): Ethereum security analysis and economics - -## Key Resources - -### Official Documentation -- [Developer Documentation](https://ethereum.org/content/developers/docs/index.md): Complete technical reference -- [Ethereum Improvement Proposals](https://ethereum.org/content/eips/index.md): Protocol specifications -- [Ethereum Whitepaper](https://ethereum.org/content/whitepaper/index.md): Original design document - -### Tools and Services -- [Wallet Finder](https://ethereum.org/wallets/find-wallet/): Wallet recommendation tool -- [DApp Browser](https://ethereum.org/dapps/): Decentralized application directory -- [Node Setup Guides](https://ethereum.org/run-a-node/): Infrastructure guides -- [Get ETH](https://ethereum.org/get-eth/): Acquisition methods - -### Educational Content -- [Beginner's Guide](https://ethereum.org/what-is-ethereum/): Start here for basics -- [Interactive Tutorials](https://ethereum.org/developers/tutorials/): Hands-on learning -- [Quiz Platform](https://ethereum.org/quizzes/): Knowledge assessment -- [Glossary](https://ethereum.org/glossary/): Comprehensive definitions - -## Legal and Policies - -### Terms and Policies -- [Privacy Policy](https://ethereum.org/content/privacy-policy/index.md): Data protection and privacy practices -- [Terms of Use](https://ethereum.org/content/terms-of-use/index.md): Website usage terms and conditions -- [Cookie Policy](https://ethereum.org/content/cookie-policy/index.md): Information about cookie usage and tracking diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx index 6a264eea5b2..3d0ee3f7484 100644 --- a/src/components/Footer/index.tsx +++ b/src/components/Footer/index.tsx @@ -1,6 +1,6 @@ import { getTranslations } from "next-intl/server" -import type { FooterLink, FooterLinkSection } from "@/lib/types" +import type { FooterLinkSection } from "@/lib/types" import Discord from "@/components/icons/discord.svg" import Farcaster from "@/components/icons/farcaster.svg" @@ -11,10 +11,13 @@ import { List, ListItem } from "@/components/ui/list" import { cn } from "@/lib/utils/cn" -import { ENTERPRISE_ETHEREUM_URL } from "@/lib/constants" - import GoToTopButton from "./GoToTopButton" +import { + buildFooterDipperLinks, + buildFooterLinkSections, +} from "@/lib/nav/footerLinks" + const socialLinks = [ { icon: Github, @@ -45,269 +48,8 @@ type FooterProps = { const Footer = async ({ lastDeployLocaleTimestamp }: FooterProps) => { const t = await getTranslations("common") - const linkSections: FooterLinkSection[] = [ - { - title: t("learn"), - links: [ - { - href: "/learn/", - text: t("learn-hub"), - }, - { - href: "/what-is-ethereum/", - text: t("what-is-ethereum"), - }, - { - href: "/what-is-ether/", - text: t("what-is-ether"), - }, - { - href: "/wallets/", - text: t("ethereum-wallets"), - }, - { - href: "/web3/", - text: t("web3"), - }, - { - href: "/smart-contracts/", - text: t("smart-contracts"), - }, - { - href: "/gas/", - text: "Gas fees", - }, - { - href: "/run-a-node/", - text: t("run-a-node"), - }, - { - href: "/security/", - text: t("ethereum-security"), - }, - { - href: "/quizzes/", - text: t("quizzes-title"), - }, - { - href: "/glossary/", - text: t("ethereum-glossary"), - }, - ], - }, - { - title: t("use"), - links: [ - { - href: "/guides/", - text: t("guides"), - }, - { - href: "/wallets/find-wallet/", - text: t("nav-find-wallet-label"), - }, - { - href: "/get-eth/", - text: t("get-eth"), - }, - { - href: "/apps/", - text: t("application-explorer"), - }, - { - href: "/stablecoins/", - text: t("stablecoins"), - }, - { - href: "/nft/", - text: t("nft-page"), - }, - { - href: "/defi/", - text: t("defi-page"), - }, - { - href: "/dao/", - text: t("dao-page"), - }, - { - href: "/decentralized-identity/", - text: t("decentralized-identity"), - }, - { - href: "/staking/", - text: t("stake-eth"), - }, - { - href: "/layer-2/", - text: t("layer-2"), - }, - ], - }, - { - title: t("build"), - links: [ - { - href: "/developers/", - text: t("nav-builders-home-label"), - isPartiallyActive: false, - }, - { - href: "/developers/tutorials/", - text: t("tutorials"), - }, - { - href: "/developers/docs/", - text: t("documentation"), - }, - { - href: "/developers/tools/", - text: t("start-building"), - }, - { - href: "/developers/tools/education/", - text: t("learn-ethereum-development"), - }, - { - href: "/community/grants/", - text: t("grants"), - }, - { - href: "/developers/docs/intro-to-ethereum/", - text: t("nav-docs-foundation-label"), - }, - { - href: "/developers/docs/design-and-ux/", - text: t("nav-docs-design-label"), - }, - { - href: ENTERPRISE_ETHEREUM_URL, - text: t("enterprise-mainnet"), - }, - { - href: "/founders/", - text: t("founders"), - }, - ], - }, - { - title: t("participate"), - links: [ - { - href: "/community/", - text: t("community-hub"), - }, - { - href: "/community/online/", - text: t("ethereum-online"), - }, - { - href: "/community/events/", - text: t("ethereum-events"), - }, - { - href: "/contributing/", - text: t("nav-contribute-label"), - }, - { - href: "/contributing/translation-program/", - text: t("translation-program"), - }, - { - href: "/bug-bounty/", - text: t("ethereum-bug-bounty"), - }, - { - href: "/foundation/", - text: t("ethereum-foundation"), - }, - { - href: "https://blog.ethereum.org/", - text: t("ef-blog"), - }, - { - href: "https://esp.ethereum.foundation", - text: t("esp"), - }, - { - href: "https://devcon.org/", - text: t("devcon"), - }, - ], - }, - { - title: t("research"), - links: [ - { - href: "/whitepaper/", - text: t("ethereum-whitepaper"), - }, - { - href: "/roadmap/", - text: t("ethereum-roadmap"), - }, - { - href: "/roadmap/security/", - text: t("nav-roadmap-security-label"), - }, - { - href: "/ethereum-forks/", - text: t("nav-history-label"), - }, - { - href: "/community/research/", - text: t("nav-open-research-label"), - }, - { - href: "/eips/", - text: t("eips"), - }, - { - href: "/governance/", - text: t("ethereum-governance"), - }, - { - href: "/trillion-dollar-security/", - text: t("trillion-dollar-security"), - }, - ], - }, - ] - - const dipperLinks: FooterLink[] = [ - { - href: "/about/", - text: t("about-us"), - }, - { - href: "/assets/", - text: t("ethereum-brand-assets"), - }, - { - href: "/community/code-of-conduct/", - text: t("nav-code-of-conduct"), - }, - { - href: "/about/#open-jobs", - text: t("jobs"), - }, - { - href: "/privacy-policy/", - text: t("privacy-policy"), - }, - { - href: "/terms-of-use/", - text: t("terms-of-use"), - }, - { - href: "/cookie-policy/", - text: t("cookie-policy"), - }, - { - href: "mailto:press@ethereum.org", - text: t("contact"), - }, - ] + const linkSections = buildFooterLinkSections(t) + const dipperLinks = buildFooterDipperLinks(t) const footerLinkClassName = "text-body-medium no-underline hover:text-primary hover:after:text-primary" diff --git a/src/lib/llms-txt/frontmatter.ts b/src/lib/llms-txt/frontmatter.ts new file mode 100644 index 00000000000..fe894839129 --- /dev/null +++ b/src/lib/llms-txt/frontmatter.ts @@ -0,0 +1,55 @@ +import fs from "fs" +import path from "path" + +import matter from "gray-matter" + +import { CONTENT_DIR } from "@/lib/constants" + +const REPO_ROOT = process.cwd() + +const cache = new Map() + +/** + * Read the `description` field from `public/content/{slug}/index.md` if it + * exists. Returns `null` for any miss — file absent, frontmatter parse error, + * or no description field. Warnings go to stderr; never throws. + */ +export const readFrontmatterDescription = (href: string): string | null => { + if (cache.has(href)) return cache.get(href) ?? null + + if (!href.startsWith("/") || href.startsWith("//")) { + cache.set(href, null) + return null + } + + const slug = href.replace(/^\/+|\/+$/g, "") + if (!slug) { + cache.set(href, null) + return null + } + + const bodyPath = path.join(REPO_ROOT, CONTENT_DIR, slug, "index.md") + let raw: string + try { + raw = fs.readFileSync(bodyPath, "utf-8") + } catch { + cache.set(href, null) + return null + } + + try { + const { data } = matter(raw) + const description = + typeof data.description === "string" && data.description.trim() + ? data.description.trim() + : null + cache.set(href, description) + return description + } catch (err) { + console.warn( + `[llms-txt] frontmatter parse failed for ${href}: ${(err as Error).message}` + ) + cache.set(href, null) + return null + } +} diff --git a/src/lib/llms-txt/render.ts b/src/lib/llms-txt/render.ts new file mode 100644 index 00000000000..0aec1d095f8 --- /dev/null +++ b/src/lib/llms-txt/render.ts @@ -0,0 +1,143 @@ +import type { getTranslations } from "next-intl/server" + +import type { FooterLink, FooterLinkSection } from "@/lib/types" + +import type { NavItem, NavSectionDetail } from "@/components/Nav/types" + +import { getFullUrl } from "@/lib/utils/url" + +import { readFrontmatterDescription } from "./frontmatter" + +export type DocLink = { + id: string + href?: string + path?: string + description?: string + items?: DocLink[] +} + +export type Translator = Awaited> + +/** + * Single bullet line. Frontmatter description wins; nav description is the + * fallback; label-only if neither exists. + */ +export const renderBullet = ( + label: string, + href: string, + navDescription: string | null, + indent = 0 +): string => { + const prefix = " ".repeat(indent) + const description = readFrontmatterDescription(href) ?? navDescription + const url = getFullUrl(undefined, href) + const tail = description ? `: ${description}` : "" + return `${prefix}- [${label}](${url})${tail}` +} + +const collectNavHrefs = (section: NavSectionDetail): Set => { + const set = new Set() + const walk = (items: NavItem[]) => { + for (const item of items) { + if (item.href) set.add(item.href) + if (item.items) walk(item.items) + } + } + walk(section.items) + return set +} + +/** + * Render one top-level nav section. + * + * Layout: + * ## {label} + * + * - {leaf items at top level} + * + * ### {group label} + * - {group items} + * + * ### More + * - {footer items not already covered} + */ +export const renderNavSection = ( + section: NavSectionDetail, + footerSection: FooterLinkSection | undefined +): string => { + const lines: string[] = [`## ${section.label}`, ""] + + const leaves = section.items.filter((item) => item.href) + const groups = section.items.filter((item) => item.items) + + for (const leaf of leaves) { + if (!leaf.href) continue + lines.push(renderBullet(leaf.label, leaf.href, leaf.description, 0)) + } + if (leaves.length > 0) lines.push("") + + for (const group of groups) { + if (!group.items) continue + lines.push(`### ${group.label}`, "") + for (const child of group.items) { + if (!child.href) continue + lines.push(renderBullet(child.label, child.href, child.description, 0)) + } + lines.push("") + } + + if (footerSection) { + const navHrefs = collectNavHrefs(section) + const extra = footerSection.links.filter((link) => !navHrefs.has(link.href)) + if (extra.length > 0) { + lines.push("### More", "") + for (const link of extra) { + lines.push(renderBullet(link.text, link.href, null, 0)) + } + lines.push("") + } + } + + return lines.join("\n").replace(/\n+$/, "") +} + +/** + * Render the Legal & Policies section from Footer's dipperLinks. + * Skips mailto: and other non-http(s) hrefs. + */ +export const renderLegalSection = (dipperLinks: FooterLink[]): string => { + const lines = ["## Legal & Policies", ""] + for (const link of dipperLinks) { + if (link.href.startsWith("mailto:")) continue + lines.push(renderBullet(link.text, link.href, null, 0)) + } + return lines.join("\n") +} + +/** + * Render a single docs-nav node and its descendants as indented bullets. + */ +export const renderDocsNode = ( + node: DocLink, + indent: number, + t: Translator +): string[] => { + const label = t(node.id) + const href = node.href ?? node.path + const description = + node.description && t.has(node.description) ? t(node.description) : null + + const lines: string[] = [] + if (href) { + lines.push(renderBullet(label, href, description, indent)) + } else { + lines.push(`${" ".repeat(indent)}- ${label}`) + } + + if (node.items) { + for (const child of node.items) { + lines.push(...renderDocsNode(child, indent + 1, t)) + } + } + return lines +} diff --git a/src/lib/nav/footerLinks.ts b/src/lib/nav/footerLinks.ts new file mode 100644 index 00000000000..836530a0551 --- /dev/null +++ b/src/lib/nav/footerLinks.ts @@ -0,0 +1,115 @@ +import type { FooterLink, FooterLinkSection } from "@/lib/types" + +import { ENTERPRISE_ETHEREUM_URL } from "@/lib/constants" + +type TranslateFn = (key: string) => string + +export const buildFooterLinkSections = ( + t: TranslateFn +): FooterLinkSection[] => [ + { + title: t("learn"), + links: [ + { href: "/learn/", text: t("learn-hub") }, + { href: "/what-is-ethereum/", text: t("what-is-ethereum") }, + { href: "/what-is-ether/", text: t("what-is-ether") }, + { href: "/wallets/", text: t("ethereum-wallets") }, + { href: "/web3/", text: t("web3") }, + { href: "/smart-contracts/", text: t("smart-contracts") }, + { href: "/gas/", text: "Gas fees" }, + { href: "/run-a-node/", text: t("run-a-node") }, + { href: "/security/", text: t("ethereum-security") }, + { href: "/quizzes/", text: t("quizzes-title") }, + { href: "/glossary/", text: t("ethereum-glossary") }, + ], + }, + { + title: t("use"), + links: [ + { href: "/guides/", text: t("guides") }, + { href: "/wallets/find-wallet/", text: t("nav-find-wallet-label") }, + { href: "/get-eth/", text: t("get-eth") }, + { href: "/apps/", text: t("application-explorer") }, + { href: "/stablecoins/", text: t("stablecoins") }, + { href: "/nft/", text: t("nft-page") }, + { href: "/defi/", text: t("defi-page") }, + { href: "/dao/", text: t("dao-page") }, + { href: "/decentralized-identity/", text: t("decentralized-identity") }, + { href: "/staking/", text: t("stake-eth") }, + { href: "/layer-2/", text: t("layer-2") }, + ], + }, + { + title: t("build"), + links: [ + { + href: "/developers/", + text: t("nav-builders-home-label"), + isPartiallyActive: false, + }, + { href: "/developers/tutorials/", text: t("tutorials") }, + { href: "/developers/docs/", text: t("documentation") }, + { href: "/developers/tools/", text: t("start-building") }, + { + href: "/developers/tools/education/", + text: t("learn-ethereum-development"), + }, + { href: "/community/grants/", text: t("grants") }, + { + href: "/developers/docs/intro-to-ethereum/", + text: t("nav-docs-foundation-label"), + }, + { + href: "/developers/docs/design-and-ux/", + text: t("nav-docs-design-label"), + }, + { href: ENTERPRISE_ETHEREUM_URL, text: t("enterprise-mainnet") }, + { href: "/founders/", text: t("founders") }, + ], + }, + { + title: t("participate"), + links: [ + { href: "/community/", text: t("community-hub") }, + { href: "/community/online/", text: t("ethereum-online") }, + { href: "/community/events/", text: t("ethereum-events") }, + { href: "/contributing/", text: t("nav-contribute-label") }, + { + href: "/contributing/translation-program/", + text: t("translation-program"), + }, + { href: "/bug-bounty/", text: t("ethereum-bug-bounty") }, + { href: "/foundation/", text: t("ethereum-foundation") }, + { href: "https://blog.ethereum.org/", text: t("ef-blog") }, + { href: "https://esp.ethereum.foundation", text: t("esp") }, + { href: "https://devcon.org/", text: t("devcon") }, + ], + }, + { + title: t("research"), + links: [ + { href: "/whitepaper/", text: t("ethereum-whitepaper") }, + { href: "/roadmap/", text: t("ethereum-roadmap") }, + { href: "/roadmap/security/", text: t("nav-roadmap-security-label") }, + { href: "/ethereum-forks/", text: t("nav-history-label") }, + { href: "/community/research/", text: t("nav-open-research-label") }, + { href: "/eips/", text: t("eips") }, + { href: "/governance/", text: t("ethereum-governance") }, + { + href: "/trillion-dollar-security/", + text: t("trillion-dollar-security"), + }, + ], + }, +] + +export const buildFooterDipperLinks = (t: TranslateFn): FooterLink[] => [ + { href: "/about/", text: t("about-us") }, + { href: "/assets/", text: t("ethereum-brand-assets") }, + { href: "/community/code-of-conduct/", text: t("nav-code-of-conduct") }, + { href: "/about/#open-jobs", text: t("jobs") }, + { href: "/privacy-policy/", text: t("privacy-policy") }, + { href: "/terms-of-use/", text: t("terms-of-use") }, + { href: "/cookie-policy/", text: t("cookie-policy") }, + { href: "mailto:press@ethereum.org", text: t("contact") }, +] From 9fbb3895ff386dc66ec7024d045b7e542644be56 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 26 May 2026 13:24:54 +0200 Subject: [PATCH 2/2] fix: use SITE_URL for llms.txt cross-references instead of hardcoded domain --- app/developers/docs/llms.txt/route.ts | 4 +++- app/llms.txt/route.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/developers/docs/llms.txt/route.ts b/app/developers/docs/llms.txt/route.ts index a79dca91825..03d9aba2076 100644 --- a/app/developers/docs/llms.txt/route.ts +++ b/app/developers/docs/llms.txt/route.ts @@ -2,6 +2,8 @@ import { getTranslations } from "next-intl/server" import docLinks from "@/data/developer-docs-links.yaml" +import { SITE_URL } from "@/lib/constants" + import { type DocLink, renderDocsNode, @@ -14,7 +16,7 @@ const INTRO = `# Ethereum Developer Documentation > Technical reference for building on Ethereum: protocol concepts, the Ethereum stack, smart contracts, scaling solutions, and developer tooling. -This file indexes the developer documentation under https://ethereum.org/developers/docs/. For the full ethereum.org index including learner content, guides, and community resources, see https://ethereum.org/llms.txt.` +This file indexes the developer documentation under ${SITE_URL}/developers/docs/. For the full ethereum.org index including learner content, guides, and community resources, see ${SITE_URL}/llms.txt.` const links = docLinks as unknown as DocLink[] diff --git a/app/llms.txt/route.ts b/app/llms.txt/route.ts index 9e479379592..713365f0569 100644 --- a/app/llms.txt/route.ts +++ b/app/llms.txt/route.ts @@ -1,5 +1,7 @@ import { getTranslations } from "next-intl/server" +import { SITE_URL } from "@/lib/constants" + import { renderLegalSection, renderNavSection } from "@/lib/llms-txt/render" import { buildNavigation } from "@/lib/nav/buildNavigation" import { @@ -13,7 +15,7 @@ const INTRO = `# Ethereum.org > The official Ethereum website providing comprehensive education, resources, and community information about Ethereum — the decentralized world computer that enables smart contracts and decentralized applications. -Ethereum.org is the primary educational hub for Ethereum, offering beginner-friendly explanations alongside advanced technical documentation. The site covers everything from basic concepts like "What is Ethereum?" to detailed developer guides, staking information, and protocol research. For the developer-documentation-only index, see https://ethereum.org/developers/docs/llms.txt.` +Ethereum.org is the primary educational hub for Ethereum, offering beginner-friendly explanations alongside advanced technical documentation. The site covers everything from basic concepts like "What is Ethereum?" to detailed developer guides, staking information, and protocol research. For the developer-documentation-only index, see ${SITE_URL}/developers/docs/llms.txt.` export const GET = async () => { const t = await getTranslations({ locale: "en", namespace: "common" })