Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/HeadSEO.astro
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const getAlternateHref = (lang: string, slug: string) => {
---

<link rel="canonical" href={canonicalURL} />
<link rel="alternate" type="text/markdown" href={`${removeTrailingSlash(canonicalURL.href)}.md`} />

{
translatedPages
Expand Down
74 changes: 74 additions & 0 deletions src/pages/[lang]/[...path]/llms.txt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { APIRoute, GetStaticPaths } from 'astro';

import { LANGS, type Lang } from '~/nav/schema';
import {
getMachineIndex,
llmsEntry,
type IndexedTree,
type MachineIndex,
} from '~/util/machineIndex';

/** llms.txt at the docs root (one entry per section) and at every section root (every
* page it lists). The site root belongs to the marketing site, so the docs root is the
* conventional path here. Entries link the Markdown twin of each page. */

const SUMMARY: Record<Lang, string> = {
en: "Documentation for the Azion Web Platform: build, store, secure, and observe applications on Azion's distributed infrastructure. Every page is served as Markdown at its URL with .md appended, and every section publishes its own llms.txt.",
'pt-br':
'Documentação da Azion Web Platform: construa, armazene, proteja e observe aplicações na infraestrutura distribuída da Azion. Toda página é servida como Markdown na própria URL com .md ao final, e toda seção publica o próprio llms.txt.',
};

const TITLE: Record<Lang, string> = { en: 'Azion documentation', 'pt-br': 'Documentação Azion' };
const INDEX_NOTE: Record<Lang, string> = { en: 'Section index', 'pt-br': 'Índice da seção' };
const PAGES: Record<Lang, string> = { en: 'Pages', 'pt-br': 'Páginas' };

function renderRoot(index: MachineIndex): string {
const lines = [`# ${TITLE[index.lang]}`, '', `> ${SUMMARY[index.lang]}`, ''];
for (const group of index.rootGroups) {
lines.push(`## ${group.label ?? group.listed.join(', ')}`, '');
for (const tree of group.trees) {
const root = tree.pages[0];
const note = [tree.description, `${INDEX_NOTE[index.lang]}: ${tree.llmsUrl}`]
.filter(Boolean)
.join('. ');
lines.push(llmsEntry(tree.title, root ? root.markdownUrl : tree.llmsUrl, note));
}
lines.push('');
}
return lines.join('\n');
}

function renderTree(index: MachineIndex, tree: IndexedTree): string {
const lines = [`# ${tree.title}`, ''];
if (tree.description) lines.push(`> ${tree.description}`, '');
for (const group of tree.groups) {
lines.push(`## ${group.label ?? PAGES[index.lang]}`, '');
for (const page of group.pages)
lines.push(llmsEntry(page.title, page.markdownUrl, page.description));
lines.push('');
}
return lines.join('\n');
}

export const getStaticPaths = (async () => {
const paths: { params: { lang: Lang; path: string }; props: { tree?: string } }[] = [];
for (const lang of LANGS) {
const index = await getMachineIndex(lang);
paths.push({ params: { lang, path: index.docsBase }, props: {} });
for (const tree of index.trees) {
paths.push({
params: { lang, path: `${index.docsBase}/${tree.path}` },
props: { tree: tree.id },
});
}
}
return paths;
}) satisfies GetStaticPaths;

export const GET: APIRoute = async ({ params, props }) => {
const index = await getMachineIndex(params.lang as Lang);
const treeId = (props as { tree?: string }).tree;
const tree = treeId ? index.trees.find((t) => t.id === treeId) : undefined;
const body = tree ? renderTree(index, tree) : renderRoot(index);
return new Response(body, { headers: { 'Content-Type': 'text/markdown; charset=utf-8' } });
};
61 changes: 61 additions & 0 deletions src/pages/[lang]/[docs]/sitemap.md.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { APIRoute, GetStaticPaths } from 'astro';

import { DOCS_BASE } from '~/nav/resolve';
import { LANGS, type Lang } from '~/nav/schema';
import { getMachineIndex } from '~/util/machineIndex';

/** sitemap.md at the docs root: one entry per page with the metadata an agent filters
* on before fetching (type, section, topics, last change, summary), all of it already
* held by the nav and the frontmatter. */

const LABELS: Record<Lang, Record<string, string>> = {
en: {
title: 'Azion documentation sitemap',
summary:
'Every documentation page in navigation order. Each entry carries the page type, its section, the products it covers, the date of its last change, and its summary. The URL serves HTML; append .md for Markdown.',
type: 'type',
section: 'section',
topics: 'topics',
updated: 'updated',
summaryKey: 'summary',
markdown: 'markdown',
},
'pt-br': {
title: 'Mapa da documentação Azion',
summary:
'Todas as páginas da documentação na ordem da navegação. Cada entrada traz o tipo da página, a seção, os produtos que ela cobre, a data da última alteração e o resumo. A URL serve HTML; acrescente .md para Markdown.',
type: 'tipo',
section: 'seção',
topics: 'tópicos',
updated: 'atualizado',
summaryKey: 'resumo',
markdown: 'markdown',
},
};

export const getStaticPaths = (() =>
LANGS.map((lang) => ({ params: { lang, docs: DOCS_BASE[lang] } }))) satisfies GetStaticPaths;

export const GET: APIRoute = async ({ params }) => {
const lang = params.lang as Lang;
const index = await getMachineIndex(lang);
const l = LABELS[lang];
const lines = [`# ${l.title}`, '', `> ${l.summary}`, ''];
for (const tree of index.trees) {
lines.push(`## ${tree.title}`, '');
for (const page of tree.pages) {
lines.push(`- [${page.title.trim()}](${page.url})`);
if (page.kind) lines.push(` - ${l.type}: ${page.kind}`);
lines.push(` - ${l.section}: ${page.section.join(' > ')}`);
if (page.topics.length) lines.push(` - ${l.topics}: ${page.topics.join(', ')}`);
if (page.updated) lines.push(` - ${l.updated}: ${page.updated}`);
if (page.description)
lines.push(` - ${l.summaryKey}: ${page.description.replace(/\s+/g, ' ').trim()}`);
lines.push(` - ${l.markdown}: ${page.markdownUrl}`);
}
lines.push('');
}
return new Response(lines.join('\n'), {
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
});
};
46 changes: 0 additions & 46 deletions src/pages/[lang]/docs-llms.txt.js

This file was deleted.

40 changes: 40 additions & 0 deletions src/pages/[lang]/docs-llms.txt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { APIRoute, GetStaticPaths } from 'astro';

import { SITE_URL } from '~/consts';
import { LANGS, type Lang } from '~/nav/schema';
import { getMachineIndex, llmsEntry } from '~/util/machineIndex';

/**
* The full page list, one section per navigation tree. This path predates the
* per-section files and stays because the agent-setup pages and prompts cite it;
* /{lang}/{docs}/llms.txt is the conventional entry point and links here.
*/

const TITLE: Record<Lang, string> = {
en: 'Azion documentation, every page',
'pt-br': 'Documentação Azion, todas as páginas',
};
const SUMMARY: Record<Lang, string> = {
en: 'Every page the documentation navigation lists, in sidebar order, linked as Markdown. The section index is at',
'pt-br':
'Todas as páginas que a navegação da documentação lista, na ordem do menu, com links em Markdown. O índice de seções está em',
};

export const getStaticPaths = (() =>
LANGS.map((lang) => ({ params: { lang } }))) satisfies GetStaticPaths;

export const GET: APIRoute = async ({ params }) => {
const lang = params.lang as Lang;
const index = await getMachineIndex(lang);
const sectionIndex = `${SITE_URL}/${lang}/${index.docsBase}/llms.txt`;
const lines = [`# ${TITLE[lang]}`, '', `> ${SUMMARY[lang]} ${sectionIndex}`, ''];
for (const tree of index.trees) {
lines.push(`## ${tree.title}`, '');
for (const page of tree.pages)
lines.push(llmsEntry(page.title, page.markdownUrl, page.description));
lines.push('');
}
return new Response(lines.join('\n'), {
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
});
};
Loading
Loading