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
Changes
@@@ -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"@@@ -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"@@@ -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);@@@ -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) { /* */ }nnew file mode 100644@@@ -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); });
@@ -15,9 +15,9 @@
@@ -15,9 +15,9 @@
"express": "^4.21.2",
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
"express-rate-limit": "^7.5.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.33.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-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": {
"engines": {
"node": ">=22.0.0"
"node": ">=22.0.0"
@@ -1015,12 +1015,12 @@
@@ -1015,12 +1015,12 @@
}
}
},
},
"node_modules/openvibe-publishing": {
"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",
"license": "MIT",
"dependencies": {
"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": {
"engines": {
"node": ">=20"
"node": ">=20"
@@ -1034,15 +1034,6 @@
@@ -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": {
"node_modules/openvibe-sdk": {
"version": "0.5.0",
"version": "0.5.0",
"resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
"resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
@@ -1053,9 +1044,9 @@
@@ -1053,9 +1044,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"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",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0"
"jsonwebtoken": "^9.0.0"
@@ -21,9 +21,9 @@
@@ -21,9 +21,9 @@
"express": "^4.21.2",
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
"express-rate-limit": "^7.5.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.33.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-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": {
"engines": {
"node": ">=22.0.0"
"node": ">=22.0.0"
@@ -31,6 +31,7 @@ const seo = require('openvibe-publishing/seo');
@@ -31,6 +31,7 @@ const seo = require('openvibe-publishing/seo');
const ssr = require('openvibe-publishing/ssr');
const ssr = require('openvibe-publishing/ssr');
const { renderPage } = require('../render/layout');
const { renderPage } = require('../render/layout');
const views = require('../render/views');
const views = require('../render/views');
+const chromeSsr = require('openvibe-shared/chrome-ssr');
const content = require('../wiki/content');
const content = require('../wiki/content');
const { actorMiddleware, resolveCitations, resolveBundleCitations, citationsFromForm } = require('./common');
const { actorMiddleware, resolveCitations, resolveBundleCitations, citationsFromForm } = require('./common');
const importer = require('../wiki/import');
const importer = require('../wiki/import');
@@ -96,11 +97,13 @@ function createPages({ svc, viewers, platform, config, log = console }) {
@@ -96,11 +97,13 @@ function createPages({ svc, viewers, platform, config, log = console }) {
router.get('/', (req, res) => {
router.get('/', (req, res) => {
const spaces = svc.listSpaces(req.actor);
const spaces = svc.listSpaces(req.actor);
const recent = svc.recentChanges(10);
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: '/',
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.' }),
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('/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) => {
router.get('/search', (req, res) => {
const query = String(req.query.q || '').slice(0, 200);
const query = String(req.query.q || '').slice(0, 200);
@@ -42,6 +42,7 @@ function navConfig(o, config) {
@@ -42,6 +42,7 @@ function navConfig(o, config) {
silentLogin: `${config.baseUrl}/auth/login?silent=1&next={url}`,
silentLogin: `${config.baseUrl}/auth/login?silent=1&next={url}`,
sessionUrl: '/auth/me',
sessionUrl: '/auth/me',
loginUrl: `/auth/login?next=${encodeURIComponent(o.path || '/')}`,
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)
@@ -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>
<a class="wk-skip" href="#main">Skip to content</a>
<div id="navbar-mount"></div>
<div id="navbar-mount"></div>
${chrome.noscriptNav({ name: SITE_NAME, home: '/', links: [{ label: 'Spaces', href: '/' }, { label: 'Recent changes', href: '/recent' }, { label: 'Search', href: '/search' }] })}
${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">
<main id="main" class="wk-main">
${o.body || ''}
${o.body || ''}
</main>
</main>
-${chrome.footer({ service: 'wiki', variant: 'full' })}
+${chrome.footer({ service: 'wiki', variant: 'full', updates: '/updates' })}
<script>
<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 () {
document.addEventListener('DOMContentLoaded', function () {
try { if (window.OpenVibeNavbar) OpenVibeNavbar.init(window.__OV_PAGE.navbar); } catch (e) { /* chrome is optional */ }
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) { /* */ }
try { if (window.OpenVibeFooter) OpenVibeFooter.init(window.__OV_PAGE.footer); } catch (e) { /* */ }
new file mode 100644
new file mode 100644
@@ -0,0 +1,24 @@
@@ -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); });