openvibers/openvibe.wiki Commits

The shared update system and one account UI: home shows what shipped (openvibe-shared chrome-ssr shipped()), /updates is the shared log, the footer links it; the shared navbar handles sign in/out (logoutUrl ends this site's session) and the site's own account strip is only for no-JS visitors. openvibe-shared 1.10.0, openvibe-publishing 0.3.1

OP OpenVibers committed 24 Sept 2026 · fdcea62cd6 · 5 files, +43 −24


Changes

ddiff --git a/package-lock.json b/package-lock.json
iindex eb51be9..e1b3272 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -15,9 +15,9 @@
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.33.0",
-- "openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v0.2.2",
++ "openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v0.3.1",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.7.0"
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.10.0"
},
"engines": {
"node": ">=22.0.0"
@@@ -1015,12 +1015,12 @@
}
},
"node_modules/openvibe-publishing": {
-- "version": "0.2.2",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v0.2.2",
-- "integrity": "sha512-+aX5lcXQfvfczCY4Ca89B5uYugCS/uncu4gYI7U/mQoOioXZMHk/mCu2f1/+qxM1Ehi6EA2eB/0TCRv7jbuHbA==",
++ "version": "0.3.1",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v0.3.1",
++ "integrity": "sha512-fK7BqaLKLmTwpWTPL+1cQt13tbG6Tp407hIooVWJ8Hi5QvZIzJxQPWb3lnzdCDjAOUCCgxmNNQ0o+fQbohbUJg==",
"license": "MIT",
"dependencies": {
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1"
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.10.0"
},
"engines": {
"node": ">=20"
@@@ -1034,15 +1034,6 @@
}
}
},
-- "node_modules/openvibe-publishing/node_modules/openvibe-shared": {
-- "version": "1.5.1",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1",
-- "integrity": "sha512-1XWRFwN8br3iiy2Z8fmnXQMgR76VlfMpHjP1xr5uKLCJmtvtNSWO1BgA1kQmVtyBY7g+1n6YFIjahaD4qWbD/Q==",
-- "license": "MIT",
-- "dependencies": {
-- "jsonwebtoken": "^9.0.0"
-- }
-- },
"node_modules/openvibe-sdk": {
"version": "0.5.0",
"resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
@@@ -1053,9 +1044,9 @@
}
},
"node_modules/openvibe-shared": {
-- "version": "1.7.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.7.0",
-- "integrity": "sha512-gF1PABMEGHhtu0WMkJQHwJOvbYzWcdfOi3feGYrCUkLXIZhpeSvrSOD7SF0+nveWhfCQMFjqNU8Q0d90vv4s/A==",
++ "version": "1.10.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.10.0",
++ "integrity": "sha512-d2GkNuJkx6as4NKiryIBAGuff+7kY+eDMmGxK3AR91yLcgW8UYugML0foas/vdhqRNowE2I8JRVEnD01ZLhnrQ==",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0"
ddiff --git a/package.json b/package.json
iindex 9718205..ad8baec 100644
---- a/package.json
++++ b/package.json
@@@ -21,9 +21,9 @@
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.33.0",
-- "openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v0.2.2",
++ "openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v0.3.1",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.7.0"
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.10.0"
},
"engines": {
"node": ">=22.0.0"
ddiff --git a/server/http/pages.js b/server/http/pages.js
iindex e34deca..bc428a9 100644
---- a/server/http/pages.js
++++ b/server/http/pages.js
@@@ -31,6 +31,7 @@ const seo = require('openvibe-publishing/seo');
const ssr = require('openvibe-publishing/ssr');
const { renderPage } = require('../render/layout');
const views = require('../render/views');
++const chromeSsr = require('openvibe-shared/chrome-ssr');
const content = require('../wiki/content');
const { actorMiddleware, resolveCitations, resolveBundleCitations, citationsFromForm } = require('./common');
const importer = require('../wiki/import');
@@@ -96,11 +97,13 @@ function createPages({ svc, viewers, platform, config, log = console }) {
router.get('/', (req, res) => {
const spaces = svc.listSpaces(req.actor);
const recent = svc.recentChanges(10);
-- send(req, res, 200, views.home({ spaces, recent, actor: req.actor }), {
++ send(req, res, 200, views.home({ spaces, recent, actor: req.actor }) + chromeSsr.shipped({ service: 'wiki', title: 'Recently shipped on OpenVibe.Wiki' }), {
robots: 'index, follow', cache: 'public', active: 'home', path: '/',
jsonLd: seo.structuredData.webPage({ url: `${config.baseUrl}/`, name: 'OpenVibe.Wiki', description: 'Wiki spaces of the OpenVibe network.' }),
});
});
++ // What shipped on OpenVibe.Wiki: the shared update log every OpenVibe site has.
++ router.get('/updates', (req, res) => send(req, res, 200, chromeSsr.updatesBody({ service: 'wiki', siteName: 'OpenVibe.Wiki' }) + chromeSsr.shippedScript(), { title: 'What shipped on OpenVibe.Wiki', robots: 'index, follow', cache: 'public', path: '/updates' }));
router.get('/recent', (req, res) => send(req, res, 200, views.recentPage({ items: svc.recentChanges(100) }), { title: 'Recent changes', robots: 'noindex, follow', cache: 'public', active: 'recent' }));
router.get('/search', (req, res) => {
const query = String(req.query.q || '').slice(0, 200);
ddiff --git a/server/render/layout.js b/server/render/layout.js
iindex de6691a..7e4ff59 100644
---- a/server/render/layout.js
++++ b/server/render/layout.js
@@@ -42,6 +42,7 @@ function navConfig(o, config) {
silentLogin: `${config.baseUrl}/auth/login?silent=1&next={url}`,
sessionUrl: '/auth/me',
loginUrl: `/auth/login?next=${encodeURIComponent(o.path || '/')}`,
++ logoutUrl: '/auth/logout?next={path}', // Sign out in the shared navbar ends this site's session too
};
}
@@@ -82,13 +83,13 @@ ${feeds.map((f) => `<link rel="alternate" type="${f.type}" title="${esc(f.title)
<a class="wk-skip" href="#main">Skip to content</a>
<div id="navbar-mount"></div>
${chrome.noscriptNav({ name: SITE_NAME, home: '/', links: [{ label: 'Spaces', href: '/' }, { label: 'Recent changes', href: '/recent' }, { label: 'Search', href: '/search' }] })}
--<header class="wk-bar"><a class="wk-brand" href="/">${SITE_NAME}</a><form class="wk-search" action="/search" method="get" role="search"><label for="wk-q" class="wk-sr">Search the wiki</label><input id="wk-q" name="q" type="search" placeholder="Search the wiki" value="${esc(o.query || '')}"><button type="submit">Search</button></form><span class="wk-account">${who}</span></header>
++<header class="wk-bar"><a class="wk-brand" href="/">${SITE_NAME}</a><form class="wk-search" action="/search" method="get" role="search"><label for="wk-q" class="wk-sr">Search the wiki</label><input id="wk-q" name="q" type="search" placeholder="Search the wiki" value="${esc(o.query || '')}"><button type="submit">Search</button></form><noscript><span class="wk-account">${who}</span></noscript></header>
<main id="main" class="wk-main">
${o.body || ''}
</main>
--${chrome.footer({ service: 'wiki', variant: 'full' })}
++${chrome.footer({ service: 'wiki', variant: 'full', updates: '/updates' })}
<script>
--window.__OV_PAGE = ${JSON.stringify({ navbar: navConfig(o, config), footer: { service: 'wiki', variant: 'full', mount: '#ov-footer', brandName: SITE_NAME } }).replace(/</g, '\\u003c')};
++window.__OV_PAGE = ${JSON.stringify({ navbar: navConfig(o, config), footer: { service: 'wiki', variant: 'full', mount: '#ov-footer', brandName: SITE_NAME, updates: '/updates' } }).replace(/</g, '\\u003c')};
document.addEventListener('DOMContentLoaded', function () {
try { if (window.OpenVibeNavbar) OpenVibeNavbar.init(window.__OV_PAGE.navbar); } catch (e) { /* chrome is optional */ }
try { if (window.OpenVibeFooter) OpenVibeFooter.init(window.__OV_PAGE.footer); } catch (e) { /* */ }
ddiff --git a/test/shipped-pages.test.js b/test/shipped-pages.test.js
nnew file mode 100644
iindex 0000000..a52057f
---- /dev/null
++++ b/test/shipped-pages.test.js
@@@ -0,0 +1,24 @@
++'use strict';
++/**
++ * The shared update system on openvibe.wiki: the home shows what shipped, /updates is the log, the
++ * footer links it, and the shared navbar (not a second account strip) signs in and out.
++ */
++const assert = require('assert');
++const H = require('./helpers');
++
++(async () => {
++ const h = await H.boot();
++ try {
++ let r = await H.req(h, 'GET', '/');
++ assert.strictEqual(r.status, 200);
++ assert.ok(r.text.includes('data-ov-shipped="latest" data-service="wiki" href="/updates"'));
++ assert.ok(r.text.includes('"logoutUrl":"/auth/logout?next={path}"'));
++ assert.ok(/<noscript><span class="wk-account">/.test(r.text), 'the site account strip only without JavaScript');
++ assert.ok(r.text.includes('"updates":"/updates"'));
++ r = await H.req(h, 'GET', '/updates');
++ assert.strictEqual(r.status, 200);
++ assert.ok(r.text.includes('What shipped on OpenVibe.Wiki') && r.text.includes('data-ov-shipped="log" data-service="wiki"'));
++ assert.ok(r.text.includes('https://openvibe.network/updates?site=wiki'));
++ console.log('shipped pages: all checks passed');
++ } finally { await h.stop(); }
++})().catch((e) => { console.error(e); process.exit(1); });