openvibers/openvibe.zone Commits

/llms-full.txt holds the guide in full (SEO-33) (#140)

OP OpenVibers committed 10 days ago · cfac87401d · 3 files, +15 −3

It was one line a page, 493 characters. The /docs guide now goes in as text, from the
page's own builder (ctx.publicViews, read at request time).

Changes

ddiff --git a/server/app.js b/server/app.js
iindex 0e3d35b..0e66cda 100644
---- a/server/app.js
++++ b/server/app.js
@@@ -171,6 +171,8 @@ async function createApp(opts = {}) {
// ── Pages ───────────────────────────────────────────────
app.use(rateLimit({ windowMs: 60_000, limit: Number(process.env.ZONE_RATE_LIMIT_PER_MIN) || 300, standardHeaders: true, legacyHeaders: false }));
const pageRoutes = createPageRoutes(ctx);
++ // The guide in full for /llms-full.txt (http/discovery.js reads it at request time; SEO-33).
++ ctx.publicViews = pageRoutes.publicViews;
// The agent layer (openvibe-shared/agent-layer): /.well-known/agent.json and the Markdown twins of the public
// pages. The pages keep their own routes — a signed-in person's projects and forms are theirs — so only the
// manifest and twin requests reach this mount; the pages advertise the twin themselves.
ddiff --git a/server/http/discovery.js b/server/http/discovery.js
iindex 10281df..f9c9d34 100644
---- a/server/http/discovery.js
++++ b/server/http/discovery.js
@@@ -83,10 +83,16 @@ function createDiscoveryRoutes(ctx) {
}));
});
-- r.get('/llms-full.txt', (_req, res) => {
-- const pages = publicPages().map((e) => ({ url: e.path, title: PAGE_TEXT[e.path][0], text: PAGE_TEXT[e.path][1] }));
++ r.get('/llms-full.txt', async (_req, res) => {
++ // The guide (/docs) in full, from the page's own builder; the other pages one line each (SEO-33: it was 493
++ // characters in all).
++ let docs = null;
++ try { docs = ctx.publicViews ? await ctx.publicViews.docs() : null; } catch { /* the one-line description stands */ }
++ const pages = publicPages().map((e) => (e.path === '/docs' && docs && docs.body
++ ? { url: e.path, title: PAGE_TEXT[e.path][0], html: String(docs.body) }
++ : { url: e.path, title: PAGE_TEXT[e.path][0], text: PAGE_TEXT[e.path][1] }));
res.type('text/plain').set('Cache-Control', TEXT).send(seo.llmsFull({
-- site: SITE_NAME, summary: 'Every public page of OpenVibe.Zone, one line each.', base: site, maxBytes: 64 * 1024,
++ site: SITE_NAME, summary: 'Every public page of OpenVibe.Zone, the guide in full.', base: site, maxBytes: 64 * 1024,
sections: [{ title: 'Pages', pages }],
}));
});
ddiff --git a/test/discovery.test.js b/test/discovery.test.js
iindex aee12fc..7c8b1a1 100644
---- a/test/discovery.test.js
++++ b/test/discovery.test.js
@@@ -32,6 +32,10 @@ const { boot, check, done } = require('./helpers/boot');
await check('llms-full.txt lists every public page', async () => {
const r = await t.get('/llms-full.txt');
for (const s of ['OpenVibe.Zone home', 'Using OpenVibe.Zone', 'What shipped on OpenVibe.Zone']) assert.ok(r.text.includes(s), s);
++ // SEO-33: the guide in full, as text (it was one line a page, 493 characters).
++ assert.match(r.text, /The S3 endpoint/);
++ assert.ok(r.text.length > 2000, `${r.text.length} characters`);
++ assert.ok(!/<\/?(h1|h2|p|ul|li|code|section)\b[^>]*>/i.test(r.text), 'text, no markup');
});
} finally { await t.close(); }
done();