openvibers/openvibe.tours Commits

openvibe-shared v4.108.0 (was v4.107.4) (#66)

OP OpenVibers committed 10 days ago · ee339869ae · 6 files, +35 −17

* openvibe-shared v4.108.0 (was v4.107.4)

Opened by scripts/pin-bump.js in OpenVibers/OpenVibe.Shared after the v4.108.0 release.

* llms.txt links each page at its Markdown twin, with an ## Optional section (AGT-5)

Changes

ddiff --git a/README.md b/README.md
iindex 85cf348..bbc4dc6 100644
---- a/README.md
++++ b/README.md
@@@ -177,6 +177,6 @@ AGPL-3.0-only. See [LICENSE](LICENSE).
<!-- versions:start -->
- openvibe-contracts: v0.274.0
- openvibe-sdk: v0.82.0
--- openvibe-shared: v4.107.4
++- openvibe-shared: v4.108.0
- openvibe-publishing: v1.4.1
<!-- versions:end -->
ddiff --git a/STATUS.json b/STATUS.json
iindex ff1454e..8b4362c 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -10,12 +10,12 @@
"domain": "openvibe.tours",
"contracts": "openvibe-contracts v0.274.0",
"sdk": "openvibe-sdk v0.82.0",
-- "shared": "openvibe-shared v4.107.4",
++ "shared": "openvibe-shared v4.108.0",
"packages": [
"openvibe-contracts v0.274.0",
"openvibe-publishing v1.4.1",
"openvibe-sdk v0.82.0",
-- "openvibe-shared v4.107.4"
++ "openvibe-shared v4.108.0"
],
"summary": "OpenVibe.Tours is the travel room. The top 100 cities come from Wikidata coordinates and Wikivoyage pages; places are OpenStreetMap tourism=* through one bounded Overpass query per city; self-guided routes are generated from Wikivoyage See lists, marked as generated, and cite every stop. IRL streams, VODs and clips come from OpenVibe.Live's public list, stays from OpenVibe.Rent's public listings. There is no flight API key in v1: the form links the official airline-neutral search with the city pair filled in and no affiliate. A signed-in person can make a trip with a city, dates, saved places, one route and stays, and share it read-only. No route needs a service token; the source jobs are off under TOURS_DRILL.",
"works": [
ddiff --git a/package-lock.json b/package-lock.json
iindex 1d91e4a..65f5807 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -18,7 +18,7 @@
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.274.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.1",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
"pg": "^8.23.0"
},
"devDependencies": {
@@@ -1217,9 +1217,9 @@
}
},
"node_modules/openvibe-shared": {
-- "version": "4.107.4",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
-- "integrity": "sha512-tThN0m3KMncEHVcBOvE+ysHjsZTlVIDLG1P+/i2Mulmxfc/AUpebAXhpWWrut50OChZ8o+HeePxsSrPI8mUQOQ==",
++ "version": "4.108.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
++ "integrity": "sha512-NPzwjxpzGIpFpIm4uw3+VwHfsxbJ2+cD9yuhRzSwolSwqv2kCmwaVtHJ0DA9gKO3K8PCBfIP3UpKzpuSbYEJ+g==",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0",
ddiff --git a/package.json b/package.json
iindex 8b294d6..6d543ed 100644
---- a/package.json
++++ b/package.json
@@@ -26,7 +26,7 @@
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.274.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.1",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
"pg": "^8.23.0"
},
"engines": {
ddiff --git a/server/http/discovery.js b/server/http/discovery.js
iindex 4c3815a..95a3d11 100644
---- a/server/http/discovery.js
++++ b/server/http/discovery.js
@@@ -60,6 +60,10 @@ function createDiscoveryRoutes(ctx) {
r.get('/llms.txt', (_req, res) => {
res.type('text/plain').set('Cache-Control', TEXT).send(seo.llmsTxt({
name: SITE_NAME,
++ // Each of this site's own pages is linked at its Markdown twin (AGT-5; openvibe-shared 4.108.0 leaves
++ // files, /api/ and /.well-known/ paths and other sites' links as they are).
++ markdown: true,
++ base: site,
summary: DESCRIPTION,
details: 'GET /api/v1/cities?limit=&offset=&q= lists the top cities; GET /api/v1/cities/:slug adds its places, routes, live tours and stays. GET /api/v1/places/:id and GET /api/v1/routes/:id return one place or one route with its ordered stops. GET /api/v1/live returns IRL tours now and recent IRL VODs. Trips are a signed-in person\'s own: the tours_at session cookie or a Network Bearer token. Every place is OpenStreetMap (ODbL) with its osm.org link and fetch time; route stops cite the Wikivoyage page (CC BY-SA); city images say their Commons licence. No route needs a service token. Flights have no API key in v1; the form only links the official airline-neutral search, with no affiliate.',
sections: [
@@@ -69,21 +73,22 @@ function createDiscoveryRoutes(ctx) {
{ title: 'Routes', url: abs('/routes') },
{ title: 'Live tours', url: abs('/live') },
{ title: 'The API', url: abs('/developers') },
-- { title: 'OpenAPI', url: abs('/api/v1/openapi.json') },
] },
{ title: 'Machine-readable', links: [
{ title: 'Cities (JSON)', url: abs('/api/v1/cities') },
{ title: 'Live (JSON)', url: abs('/api/v1/live') },
-- { title: 'Sitemap', url: abs('/sitemap.xml') },
-- { title: 'Full text for language models', url: abs('/llms-full.txt') },
-- { title: 'Release metadata (JSON)', url: abs('/release.json') },
-- ] },
-- { title: 'Elsewhere', links: [
-- { title: 'OpenVibe.Live', url: 'https://openvibe.live', note: 'the IRL streams' },
-- { title: 'OpenVibe.Rent', url: 'https://openvibe.rent', note: 'the listings' },
-- { title: 'OpenVibe.Network', url: 'https://openvibe.network', note: 'accounts and sign-in' },
++ { title: 'OpenAPI', url: abs('/api/v1/openapi.json') },
] },
],
++ // llmstxt.org's "## Optional": what an agent may skip when it needs a shorter context.
++ optional: [
++ { title: 'Sitemap', url: abs('/sitemap.xml') },
++ { title: 'Full text for language models', url: abs('/llms-full.txt') },
++ { title: 'Release metadata (JSON)', url: abs('/release.json') },
++ { title: 'OpenVibe.Live', url: 'https://openvibe.live', note: 'the IRL streams' },
++ { title: 'OpenVibe.Rent', url: 'https://openvibe.rent', note: 'the listings' },
++ { title: 'OpenVibe.Network', url: 'https://openvibe.network', note: 'accounts and sign-in' },
++ ],
}));
});
ddiff --git a/test/pages.test.js b/test/pages.test.js
iindex df05cc9..f063aba 100644
---- a/test/pages.test.js
++++ b/test/pages.test.js
@@@ -125,6 +125,19 @@ const { seed } = require('./helpers/seed');
const llms = await t.get('/llms.txt');
assert.strictEqual(llms.status, 200);
assert.match(llms.text, /OpenVibe\.Tours/);
++ // AGT-5: the home at /index.md, each page at its twin, Optional last.
++ assert.match(llms.text, /\[OpenVibe\.Tours\]\(https:\/\/openvibe\.tours\/index\.md\)/, 'the home is /index.md');
++ assert.match(llms.text, /\[Cities\]\(https:\/\/openvibe\.tours\/cities\.md\)/, 'a page is its twin');
++ assert.match(llms.text, /\[Cities \(JSON\)\]\(https:\/\/openvibe\.tours\/api\/v1\/cities\)/, 'an API URL keeps its URL');
++ assert.match(llms.text, /\n## Optional\n/);
++ assert.match(llms.text, /\n## Optional\n\n[\s\S]*\[Sitemap\]\(https:\/\/openvibe\.tours\/sitemap\.xml\)/);
++ assert.strictEqual(llms.text.lastIndexOf('\n## '), llms.text.indexOf('\n## Optional'), 'Optional is the last section');
++ const own = [...llms.text.matchAll(/\]\((https:\/\/openvibe\.tours[^)\s]*)\)( \(HTML\))?/g)];
++ assert.ok(own.length > 5, String(own.length));
++ for (const [, url, html] of own) {
++ const p = new URL(url).pathname;
++ assert.ok(p.endsWith('.md') || /\.[a-z0-9]+$/.test(p) || p.startsWith('/api/') || html, `${url} is a twin, a file or marked (HTML)`);
++ }
const full = await t.get('/llms-full.txt');
assert.strictEqual(full.status, 200);
assert.match(full.text, /Lisbon/);