openvibers/openvibe.network Commits
The network's share card on /login, the account hub, /updates and /status (SEO-21) (#545)
Changes
@@@ -11,6 +11,15 @@<link rel="apple-touch-icon" href="/assets/logo-192.png"><link rel="manifest" href="/manifest.webmanifest"><meta name="description" content="Sign in to OpenVibe — one account across OpenVibe.Live, OpenVibe.Tools, OpenVibe.Games, and OpenVibe.Media.">++<meta property="og:type" content="website">++<meta property="og:url" content="https://openvibe.network/login">++<meta property="og:title" content="Sign in to OpenVibe">++<meta property="og:description" content="Sign in to OpenVibe — one account across OpenVibe.Live, OpenVibe.Tools, OpenVibe.Games, and OpenVibe.Media.">++<meta property="og:site_name" content="OpenVibe.Network">++<meta property="og:image" content="https://openvibe.network/shared/social/network.jpg">++<meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site">++<meta name="twitter:card" content="summary_large_image">++<meta name="twitter:image" content="https://openvibe.network/shared/social/network.jpg"><link rel="stylesheet" href="/css/login.css"><!-- The OpenVibe glyphs draw every fa- icon here (no Font Awesome since 2026-11-01). --><script src="/shared/ov-glyphs.js" defer></script>@@@ -18,6 +18,10 @@<meta property="og:title" content="My Account - OpenVibe"><meta property="og:description" content="Personal dashboard for managing your OpenVibe account and preferences."><meta property="og:site_name" content="OpenVibe">++<meta property="og:image" content="https://openvibe.network/shared/social/network.jpg">++<meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site">++<meta name="twitter:card" content="summary_large_image">++<meta name="twitter:image" content="https://openvibe.network/shared/social/network.jpg"><link rel="canonical" href="https://openvibe.network/my"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="mobile-web-app-capable" content="yes">@@@ -1,4 +1,7 @@'use strict';++++// The network's share card (SEO-21): a status link pasted in chat shows it.++const SHARE_CARD = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');/*** Operator status (roadmap Track O): what each OpenVibe service is doing right now, stated as* observed rather than hoped.@@@ -189,6 +192,7 @@ function renderPage(list, slo, generatedAt, devPath = null, toolsJob = null, hea<title>Status · OpenVibe.Network</title><meta name="description" content="Observed status of each OpenVibe service: readiness, release and when it was last checked."><meta name="robots" content="noindex, nofollow">++<meta property="og:title" content="Status · OpenVibe.Network"><meta property="og:description" content="Observed status of each OpenVibe service."><meta property="og:url" content="https://openvibe.network/status"><meta property="og:type" content="website"><meta property="og:site_name" content="OpenVibe.Network"><meta property="og:image" content="${SHARE_CARD}"><meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="${SHARE_CARD}">${boost.meta(releaseId)}${require('openvibe-shared/app-icon').headTags({ site: 'network', iconBase: '/assets' })}<meta name="color-scheme" content="dark light">@@@ -1,4 +1,7 @@'use strict';++++// The network's share card (SEO-21): link previews of this page show it, as the home and legal pages do.++const SHARE_CARD = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');const cache = require('openvibe-shared/cache-policy');/*** What shipped, network-wide (roadmap WS-A):@@@ -121,6 +124,7 @@ function renderPage({ site, filtered, body, releaseId = '' }) {<meta name="viewport" content="width=device-width, initial-scale=1"><title>${esc(title)} · OpenVibe.Network</title><meta name="description" content="Every change deployed to the OpenVibe network, newest first: each site's commits as they ship, and the Patch notes posts that gather them.">++<meta property="og:title" content="${esc(title)} · OpenVibe.Network"><meta property="og:description" content="Every change deployed to the OpenVibe network, newest first."><meta property="og:url" content="https://openvibe.network/updates"><meta property="og:type" content="website"><meta property="og:site_name" content="OpenVibe.Network"><meta property="og:image" content="${SHARE_CARD}"><meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="${SHARE_CARD}"><link rel="canonical" href="https://openvibe.network/updates${filtered && site ? `?site=${esc(site)}` : ''}">${filtered ? '<meta name="robots" content="noindex, follow">' : ''}<link rel="alternate" type="application/json" href="/api/v1/changelog${site ? `?service=${esc(site)}` : ''}">nnew file mode 100644@@@ -0,0 +1,24 @@++'use strict';++// SEO-21: the network's share card on the five pages that had none (11-03 check: /login, /machines, /themes, /updates++// and /status answered 200 without og:image, so a link pasted in chat showed no picture). The home, legal, sites and++// stats pages already carry it.++const assert = require('assert');++const fs = require('fs');++const path = require('path');++const read = (f) => fs.readFileSync(path.join(__dirname, '..', f), 'utf8');++++for (const f of ['public/login.html', 'public/my.html']) {++ const html = read(f);++ assert.match(html, /<meta property="og:image" content="https:\/\/openvibe\.network\/shared\/social\/network\.jpg">/, `${f}: the card`);++ assert.match(html, /<meta name="twitter:card" content="summary_large_image">/, `${f}: the large card`);++ assert.strictEqual((html.match(/property="og:image"/g) || []).length, 1, `${f}: once`);++}++assert.match(read('public/login.html'), /<meta property="og:title" content="Sign in to OpenVibe">/);++for (const f of ['server/updates/routes.js', 'server/status/routes.js']) {++ const src = read(f);++ assert.match(src, /const SHARE_CARD = require\('openvibe-shared\/social'\)\.url\('network', 'https:\/\/openvibe\.network\/shared'\);/, `${f}: the card's hashed URL`);++ assert.match(src, /<meta property="og:image" content="\$\{SHARE_CARD\}">/, `${f}: in the head`);++}++const card = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');++assert.match(card, /^https:\/\/openvibe\.network\/shared\/social\/network\.jpg/, 'the card resolves');++console.log('share card pages: ok');
@@ -11,6 +11,15 @@
@@ -11,6 +11,15 @@
<link rel="apple-touch-icon" href="/assets/logo-192.png">
<link rel="apple-touch-icon" href="/assets/logo-192.png">
<link rel="manifest" href="/manifest.webmanifest">
<link rel="manifest" href="/manifest.webmanifest">
<meta name="description" content="Sign in to OpenVibe — one account across OpenVibe.Live, OpenVibe.Tools, OpenVibe.Games, and OpenVibe.Media.">
<meta name="description" content="Sign in to OpenVibe — one account across OpenVibe.Live, OpenVibe.Tools, OpenVibe.Games, and OpenVibe.Media.">
+<meta property="og:type" content="website">
+<meta property="og:url" content="https://openvibe.network/login">
+<meta property="og:title" content="Sign in to OpenVibe">
+<meta property="og:description" content="Sign in to OpenVibe — one account across OpenVibe.Live, OpenVibe.Tools, OpenVibe.Games, and OpenVibe.Media.">
+<meta property="og:site_name" content="OpenVibe.Network">
+<meta property="og:image" content="https://openvibe.network/shared/social/network.jpg">
+<meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:image" content="https://openvibe.network/shared/social/network.jpg">
<link rel="stylesheet" href="/css/login.css">
<link rel="stylesheet" href="/css/login.css">
<!-- The OpenVibe glyphs draw every fa- icon here (no Font Awesome since 2026-11-01). -->
<!-- The OpenVibe glyphs draw every fa- icon here (no Font Awesome since 2026-11-01). -->
<script src="/shared/ov-glyphs.js" defer></script>
<script src="/shared/ov-glyphs.js" defer></script>
@@ -18,6 +18,10 @@
@@ -18,6 +18,10 @@
<meta property="og:title" content="My Account - OpenVibe">
<meta property="og:title" content="My Account - OpenVibe">
<meta property="og:description" content="Personal dashboard for managing your OpenVibe account and preferences.">
<meta property="og:description" content="Personal dashboard for managing your OpenVibe account and preferences.">
<meta property="og:site_name" content="OpenVibe">
<meta property="og:site_name" content="OpenVibe">
+<meta property="og:image" content="https://openvibe.network/shared/social/network.jpg">
+<meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:image" content="https://openvibe.network/shared/social/network.jpg">
<link rel="canonical" href="https://openvibe.network/my">
<link rel="canonical" href="https://openvibe.network/my">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
@@ -1,4 +1,7 @@
@@ -1,4 +1,7 @@
'use strict';
'use strict';
+
+// The network's share card (SEO-21): a status link pasted in chat shows it.
+const SHARE_CARD = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');
/**
/**
* Operator status (roadmap Track O): what each OpenVibe service is doing right now, stated as
* Operator status (roadmap Track O): what each OpenVibe service is doing right now, stated as
* observed rather than hoped.
* observed rather than hoped.
@@ -189,6 +192,7 @@ function renderPage(list, slo, generatedAt, devPath = null, toolsJob = null, hea
@@ -189,6 +192,7 @@ function renderPage(list, slo, generatedAt, devPath = null, toolsJob = null, hea
<title>Status · OpenVibe.Network</title>
<title>Status · OpenVibe.Network</title>
<meta name="description" content="Observed status of each OpenVibe service: readiness, release and when it was last checked.">
<meta name="description" content="Observed status of each OpenVibe service: readiness, release and when it was last checked.">
<meta name="robots" content="noindex, nofollow">
<meta name="robots" content="noindex, nofollow">
+<meta property="og:title" content="Status · OpenVibe.Network"><meta property="og:description" content="Observed status of each OpenVibe service."><meta property="og:url" content="https://openvibe.network/status"><meta property="og:type" content="website"><meta property="og:site_name" content="OpenVibe.Network"><meta property="og:image" content="${SHARE_CARD}"><meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="${SHARE_CARD}">
${boost.meta(releaseId)}
${boost.meta(releaseId)}
${require('openvibe-shared/app-icon').headTags({ site: 'network', iconBase: '/assets' })}
${require('openvibe-shared/app-icon').headTags({ site: 'network', iconBase: '/assets' })}
<meta name="color-scheme" content="dark light">
<meta name="color-scheme" content="dark light">
@@ -1,4 +1,7 @@
@@ -1,4 +1,7 @@
'use strict';
'use strict';
+
+// The network's share card (SEO-21): link previews of this page show it, as the home and legal pages do.
+const SHARE_CARD = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');
const cache = require('openvibe-shared/cache-policy');
const cache = require('openvibe-shared/cache-policy');
/**
/**
* What shipped, network-wide (roadmap WS-A):
* What shipped, network-wide (roadmap WS-A):
@@ -121,6 +124,7 @@ function renderPage({ site, filtered, body, releaseId = '' }) {
@@ -121,6 +124,7 @@ function renderPage({ site, filtered, body, releaseId = '' }) {
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${esc(title)} · OpenVibe.Network</title>
<title>${esc(title)} · OpenVibe.Network</title>
<meta name="description" content="Every change deployed to the OpenVibe network, newest first: each site's commits as they ship, and the Patch notes posts that gather them.">
<meta name="description" content="Every change deployed to the OpenVibe network, newest first: each site's commits as they ship, and the Patch notes posts that gather them.">
+<meta property="og:title" content="${esc(title)} · OpenVibe.Network"><meta property="og:description" content="Every change deployed to the OpenVibe network, newest first."><meta property="og:url" content="https://openvibe.network/updates"><meta property="og:type" content="website"><meta property="og:site_name" content="OpenVibe.Network"><meta property="og:image" content="${SHARE_CARD}"><meta property="og:image:alt" content="OpenVibe.Network: one account for every OpenVibe site"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="${SHARE_CARD}">
<link rel="canonical" href="https://openvibe.network/updates${filtered && site ? `?site=${esc(site)}` : ''}">
<link rel="canonical" href="https://openvibe.network/updates${filtered && site ? `?site=${esc(site)}` : ''}">
${filtered ? '<meta name="robots" content="noindex, follow">' : ''}
${filtered ? '<meta name="robots" content="noindex, follow">' : ''}
<link rel="alternate" type="application/json" href="/api/v1/changelog${site ? `?service=${esc(site)}` : ''}">
<link rel="alternate" type="application/json" href="/api/v1/changelog${site ? `?service=${esc(site)}` : ''}">
new file mode 100644
new file mode 100644
@@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
+'use strict';
+// SEO-21: the network's share card on the five pages that had none (11-03 check: /login, /machines, /themes, /updates
+// and /status answered 200 without og:image, so a link pasted in chat showed no picture). The home, legal, sites and
+// stats pages already carry it.
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+const read = (f) => fs.readFileSync(path.join(__dirname, '..', f), 'utf8');
+
+for (const f of ['public/login.html', 'public/my.html']) {
+ const html = read(f);
+ assert.match(html, /<meta property="og:image" content="https:\/\/openvibe\.network\/shared\/social\/network\.jpg">/, `${f}: the card`);
+ assert.match(html, /<meta name="twitter:card" content="summary_large_image">/, `${f}: the large card`);
+ assert.strictEqual((html.match(/property="og:image"/g) || []).length, 1, `${f}: once`);
+}
+assert.match(read('public/login.html'), /<meta property="og:title" content="Sign in to OpenVibe">/);
+for (const f of ['server/updates/routes.js', 'server/status/routes.js']) {
+ const src = read(f);
+ assert.match(src, /const SHARE_CARD = require\('openvibe-shared\/social'\)\.url\('network', 'https:\/\/openvibe\.network\/shared'\);/, `${f}: the card's hashed URL`);
+ assert.match(src, /<meta property="og:image" content="\$\{SHARE_CARD\}">/, `${f}: in the head`);
+}
+const card = require('openvibe-shared/social').url('network', 'https://openvibe.network/shared');
+assert.match(card, /^https:\/\/openvibe\.network\/shared\/social\/network\.jpg/, 'the card resolves');
+console.log('share card pages: ok');