openvibers/openvibe.today Commits
openvibe-shared v4.108.0 (was v4.107.4) (#89)
Changes
@@@ -266,5 +266,5 @@ AGPL-3.0-only. See [LICENSE](LICENSE).<!-- versions:start -->- openvibe-contracts: v0.280.0- openvibe-sdk: v0.82.0--- openvibe-shared: v4.107.4++- openvibe-shared: v4.108.0<!-- versions:end -->@@@ -10,11 +10,11 @@"domain": "openvibe.today","contracts": "openvibe-contracts v0.280.0","sdk": "openvibe-sdk v0.82.0",-- "shared": "openvibe-shared v4.107.4",++ "shared": "openvibe-shared v4.108.0","packages": ["openvibe-contracts v0.280.0","openvibe-sdk v0.82.0",-- "openvibe-shared v4.107.4"++ "openvibe-shared v4.108.0"],"summary": "OpenVibe.Today is the network's time bus and calendar authority. A person schedules a stream (on their Live channel) or a plain event; the public schedule and a channel's ICS feed are readable without an account, a private token feed is one URL per person and rotation invalidates the old one, and reminders arrive through OpenVibe.Network. Events move from scheduled to live and done as OpenVibe.Live says so over OpenVibe.Events, while the daily brief is built from the agenda, today's reminders and OpenVibe.Live's public Rundown.","works": [@@@ -17,7 +17,7 @@"iovalkey": "^0.4.0","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.280.0","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": {@@@ -1194,9 +1194,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",@@@ -25,7 +25,7 @@"iovalkey": "^0.4.0","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.280.0","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": {@@@ -71,6 +71,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/, /ics/ and /.well-known/ paths and other sites' links as they are).++ markdown: true,++ base: site,summary: 'OpenVibe.Today is the network\'s time bus and calendar authority: a public schedule of streams and events, reminders sent through OpenVibe.Network, a private ICS feed per person, and a daily brief that includes what OpenVibe.Live\'s Rundown talked about yesterday.',details: 'GET /api/v1/events lists public events (soonest first). GET /api/v1/events/:id is one event with JSON-LD on its page. A signed-in person schedules a stream or an event, changes it, cancels it and sets a reminder. GET /ics/@<username>.ics is a channel\'s public calendar; a person\'s private feed is at GET /ics/<token>.ics. Events are published as today.event.scheduled|updated|cancelled and live.stream.started|ended is consumed to move an event live and then done.',sections: [@@@ -79,17 +83,16 @@ function createDiscoveryRoutes(ctx) {{ title: 'The API', url: abs('/developers') },{ title: 'Public events (JSON)', url: abs('/api/v1/events') },] },-- { title: 'Machine-readable', links: [-- { 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.Network', url: 'https://openvibe.network', note: 'accounts, follows and notifications' },-- { title: 'OpenVibe.Live', url: 'https://openvibe.live', note: 'where a stream happens' },-- { title: 'OpenVibe.Events', url: 'https://openvibe.events', note: 'the durable event backbone' },-- { title: 'OpenVibe.Services', url: 'https://openvibe.services', note: 'apps, keys and capability grants' },-- ] },++ ],++ // 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.Network', url: 'https://openvibe.network', note: 'accounts, follows and notifications' },++ { title: 'OpenVibe.Live', url: 'https://openvibe.live', note: 'where a stream happens' },++ { title: 'OpenVibe.Events', url: 'https://openvibe.events', note: 'the durable event backbone' },++ { title: 'OpenVibe.Services', url: 'https://openvibe.services', note: 'apps, keys and capability grants' },],}));});@@@ -43,10 +43,22 @@ const PRIVATE = ['/auth/', '/api/', '/me', '/brief', '/schedule', '/internal'];assert.strictEqual(r.status, 200);assert.match(r.headers.get('content-type'), /^text\/plain/);assert.ok(r.text.startsWith('# OpenVibe.Today'));-- assert.ok(r.text.includes('(https://openvibe.today/developers)'));++ assert.ok(r.text.includes('(https://openvibe.today/developers.md)'), 'the API page at its twin');assert.ok(r.text.includes('https://openvibe.today/sitemap.xml'));assert.ok(r.text.includes('(https://openvibe.today/llms-full.txt)'));for (const p of ['/auth/', '/me', '/brief']) assert.ok(!r.text.includes(`https://openvibe.today${p}`), `private path in llms.txt: ${p}`);++ // AGT-5: the home at /index.md, each page at its twin, Optional last.++ assert.ok(r.text.includes('[OpenVibe.Today](https://openvibe.today/index.md)'), 'the home is /index.md');++ assert.ok(r.text.includes('(https://openvibe.today/api/v1/events)'), 'an API URL keeps its URL');++ assert.ok(/\n## Optional\n/.test(r.text), 'no Optional section');++ assert.ok(/\n## Optional\n\n[\s\S]*\[Sitemap\]\(https:\/\/openvibe\.today\/sitemap\.xml\)/.test(r.text));++ assert.strictEqual(r.text.lastIndexOf('\n## '), r.text.indexOf('\n## Optional'), 'Optional is the last section');++ const own = [...r.text.matchAll(/\]\((https:\/\/openvibe\.today[^)\s]*)\)( \(HTML\))?/g)];++ assert.ok(own.length > 4, 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)`);++ }});await check('llms-full.txt: every page the sitemap lists', async () => {
@@ -266,5 +266,5 @@ AGPL-3.0-only. See [LICENSE](LICENSE).
@@ -266,5 +266,5 @@ AGPL-3.0-only. See [LICENSE](LICENSE).
<!-- versions:start -->
<!-- versions:start -->
- openvibe-contracts: v0.280.0
- openvibe-contracts: v0.280.0
- openvibe-sdk: v0.82.0
- openvibe-sdk: v0.82.0
-- openvibe-shared: v4.107.4
+- openvibe-shared: v4.108.0
<!-- versions:end -->
<!-- versions:end -->
@@ -10,11 +10,11 @@
@@ -10,11 +10,11 @@
"domain": "openvibe.today",
"domain": "openvibe.today",
"contracts": "openvibe-contracts v0.280.0",
"contracts": "openvibe-contracts v0.280.0",
"sdk": "openvibe-sdk v0.82.0",
"sdk": "openvibe-sdk v0.82.0",
- "shared": "openvibe-shared v4.107.4",
+ "shared": "openvibe-shared v4.108.0",
"packages": [
"packages": [
"openvibe-contracts v0.280.0",
"openvibe-contracts v0.280.0",
"openvibe-sdk v0.82.0",
"openvibe-sdk v0.82.0",
- "openvibe-shared v4.107.4"
+ "openvibe-shared v4.108.0"
],
],
"summary": "OpenVibe.Today is the network's time bus and calendar authority. A person schedules a stream (on their Live channel) or a plain event; the public schedule and a channel's ICS feed are readable without an account, a private token feed is one URL per person and rotation invalidates the old one, and reminders arrive through OpenVibe.Network. Events move from scheduled to live and done as OpenVibe.Live says so over OpenVibe.Events, while the daily brief is built from the agenda, today's reminders and OpenVibe.Live's public Rundown.",
"summary": "OpenVibe.Today is the network's time bus and calendar authority. A person schedules a stream (on their Live channel) or a plain event; the public schedule and a channel's ICS feed are readable without an account, a private token feed is one URL per person and rotation invalidates the old one, and reminders arrive through OpenVibe.Network. Events move from scheduled to live and done as OpenVibe.Live says so over OpenVibe.Events, while the daily brief is built from the agenda, today's reminders and OpenVibe.Live's public Rundown.",
"works": [
"works": [
@@ -17,7 +17,7 @@
@@ -17,7 +17,7 @@
"iovalkey": "^0.4.0",
"iovalkey": "^0.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.280.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.280.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
"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"
"pg": "^8.23.0"
},
},
"devDependencies": {
"devDependencies": {
@@ -1194,9 +1194,9 @@
@@ -1194,9 +1194,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"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",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0",
"jsonwebtoken": "^9.0.0",
@@ -25,7 +25,7 @@
@@ -25,7 +25,7 @@
"iovalkey": "^0.4.0",
"iovalkey": "^0.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.280.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.280.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
"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"
"pg": "^8.23.0"
},
},
"engines": {
"engines": {
@@ -71,6 +71,10 @@ function createDiscoveryRoutes(ctx) {
@@ -71,6 +71,10 @@ function createDiscoveryRoutes(ctx) {
r.get('/llms.txt', (_req, res) => {
r.get('/llms.txt', (_req, res) => {
res.type('text/plain').set('Cache-Control', TEXT).send(seo.llmsTxt({
res.type('text/plain').set('Cache-Control', TEXT).send(seo.llmsTxt({
name: SITE_NAME,
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/, /ics/ and /.well-known/ paths and other sites' links as they are).
+ markdown: true,
+ base: site,
summary: 'OpenVibe.Today is the network\'s time bus and calendar authority: a public schedule of streams and events, reminders sent through OpenVibe.Network, a private ICS feed per person, and a daily brief that includes what OpenVibe.Live\'s Rundown talked about yesterday.',
summary: 'OpenVibe.Today is the network\'s time bus and calendar authority: a public schedule of streams and events, reminders sent through OpenVibe.Network, a private ICS feed per person, and a daily brief that includes what OpenVibe.Live\'s Rundown talked about yesterday.',
details: 'GET /api/v1/events lists public events (soonest first). GET /api/v1/events/:id is one event with JSON-LD on its page. A signed-in person schedules a stream or an event, changes it, cancels it and sets a reminder. GET /ics/@<username>.ics is a channel\'s public calendar; a person\'s private feed is at GET /ics/<token>.ics. Events are published as today.event.scheduled|updated|cancelled and live.stream.started|ended is consumed to move an event live and then done.',
details: 'GET /api/v1/events lists public events (soonest first). GET /api/v1/events/:id is one event with JSON-LD on its page. A signed-in person schedules a stream or an event, changes it, cancels it and sets a reminder. GET /ics/@<username>.ics is a channel\'s public calendar; a person\'s private feed is at GET /ics/<token>.ics. Events are published as today.event.scheduled|updated|cancelled and live.stream.started|ended is consumed to move an event live and then done.',
sections: [
sections: [
@@ -79,17 +83,16 @@ function createDiscoveryRoutes(ctx) {
@@ -79,17 +83,16 @@ function createDiscoveryRoutes(ctx) {
{ title: 'The API', url: abs('/developers') },
{ title: 'The API', url: abs('/developers') },
{ title: 'Public events (JSON)', url: abs('/api/v1/events') },
{ title: 'Public events (JSON)', url: abs('/api/v1/events') },
] },
] },
- { title: 'Machine-readable', links: [
- { 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.Network', url: 'https://openvibe.network', note: 'accounts, follows and notifications' },
- { title: 'OpenVibe.Live', url: 'https://openvibe.live', note: 'where a stream happens' },
- { title: 'OpenVibe.Events', url: 'https://openvibe.events', note: 'the durable event backbone' },
- { title: 'OpenVibe.Services', url: 'https://openvibe.services', note: 'apps, keys and capability grants' },
- ] },
+ ],
+ // 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.Network', url: 'https://openvibe.network', note: 'accounts, follows and notifications' },
+ { title: 'OpenVibe.Live', url: 'https://openvibe.live', note: 'where a stream happens' },
+ { title: 'OpenVibe.Events', url: 'https://openvibe.events', note: 'the durable event backbone' },
+ { title: 'OpenVibe.Services', url: 'https://openvibe.services', note: 'apps, keys and capability grants' },
],
],
}));
}));
});
});
@@ -43,10 +43,22 @@ const PRIVATE = ['/auth/', '/api/', '/me', '/brief', '/schedule', '/internal'];
@@ -43,10 +43,22 @@ const PRIVATE = ['/auth/', '/api/', '/me', '/brief', '/schedule', '/internal'];
assert.strictEqual(r.status, 200);
assert.strictEqual(r.status, 200);
assert.match(r.headers.get('content-type'), /^text\/plain/);
assert.match(r.headers.get('content-type'), /^text\/plain/);
assert.ok(r.text.startsWith('# OpenVibe.Today'));
assert.ok(r.text.startsWith('# OpenVibe.Today'));
- assert.ok(r.text.includes('(https://openvibe.today/developers)'));
+ assert.ok(r.text.includes('(https://openvibe.today/developers.md)'), 'the API page at its twin');
assert.ok(r.text.includes('https://openvibe.today/sitemap.xml'));
assert.ok(r.text.includes('https://openvibe.today/sitemap.xml'));
assert.ok(r.text.includes('(https://openvibe.today/llms-full.txt)'));
assert.ok(r.text.includes('(https://openvibe.today/llms-full.txt)'));
for (const p of ['/auth/', '/me', '/brief']) assert.ok(!r.text.includes(`https://openvibe.today${p}`), `private path in llms.txt: ${p}`);
for (const p of ['/auth/', '/me', '/brief']) assert.ok(!r.text.includes(`https://openvibe.today${p}`), `private path in llms.txt: ${p}`);
+ // AGT-5: the home at /index.md, each page at its twin, Optional last.
+ assert.ok(r.text.includes('[OpenVibe.Today](https://openvibe.today/index.md)'), 'the home is /index.md');
+ assert.ok(r.text.includes('(https://openvibe.today/api/v1/events)'), 'an API URL keeps its URL');
+ assert.ok(/\n## Optional\n/.test(r.text), 'no Optional section');
+ assert.ok(/\n## Optional\n\n[\s\S]*\[Sitemap\]\(https:\/\/openvibe\.today\/sitemap\.xml\)/.test(r.text));
+ assert.strictEqual(r.text.lastIndexOf('\n## '), r.text.indexOf('\n## Optional'), 'Optional is the last section');
+ const own = [...r.text.matchAll(/\]\((https:\/\/openvibe\.today[^)\s]*)\)( \(HTML\))?/g)];
+ assert.ok(own.length > 4, 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)`);
+ }
});
});
await check('llms-full.txt: every page the sitemap lists', async () => {
await check('llms-full.txt: every page the sitemap lists', async () => {