openvibers/openvibe.codes Commits

Render every Codes page through openvibe-shared/shell v2.6.0

OP OpenVibers committed 4 Oct 2026 · cd29b7e94c · 7 files, +53 −41

Asked: Part of a cross-repository initiative (init-t11-step-2-first-batch-every-1004T0752): T11 step 2 (first batch): every server-rendered page in OpenVibe.Tips, OpenVibe.VIP, OpenVibe.Codes, OpenVibe.Search and OpenVibe.Community renders its document through openvibe-shared/shell (shell.page), released …
Harness job init-t11-step-2-first-0752-s3-082844 (plan T11).

Changes

ddiff --git a/README.md b/README.md
iindex 1d9ee31..09fd2f3 100644
---- a/README.md
++++ b/README.md
@@@ -48,7 +48,7 @@ Everything is server-rendered and usable without JavaScript. The only scripts of
- **OpenVibe.Events** — the outbox relay publishes `codes.app.*` with Codes' service token (`events.event.publish`); the Events playground calls it with the app's token (`events.app.publish`); the project archive pulls the project's app events with a Network export token (`events.app.read`).
- **OpenVibe.Media** — the Media playground uploads with the app's token into the project's namespace; the project archive lists the project's objects, namespaces and download URLs with a Network export token (`media.object.list`, `media.object.read`).
- **PostgreSQL 18 and Valkey 9** (OpenVibe.Host `roles/data/`, ADR-035): every read and write is async through `openvibe-sdk/db`; Valkey holds the per-actor limit counters (optional).
--- **openvibe-contracts** v0.86.0, **openvibe-sdk v0.26.0**, **openvibe-shared v2.5.0** (pinned tag tarballs; the docs show the tag and the package version, and say so when they differ).
++- **openvibe-contracts** v0.86.0, **openvibe-sdk v0.26.0**, **openvibe-shared v2.6.0** (pinned tag tarballs; the docs show the tag and the package version, and say so when they differ).
No path in Codes sends or accepts a shared loopback key (tested by grep and at runtime).
ddiff --git a/STATUS.json b/STATUS.json
iindex 88147d5..255dac4 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -11,7 +11,7 @@
"packages": [
"openvibe-contracts v0.86.0",
"openvibe-sdk v0.26.0",
-- "openvibe-shared v2.5.0"
++ "openvibe-shared v2.6.0"
],
"summary": "Deployed and public since 2026-09-23: https://openvibe.codes is served by this portal (deployed with `sudo ovhost deploy codes`, unit openvibe-codes on 127.0.0.1:4900 behind nginx), and the domain left OpenVibe.Sites. Sign-in uses the registered Network OAuth client `codes` (PKCE S256); the principal `codes` holds events.event.publish and the Events relay is configured. On 2026-09-23 production held 0 manifests, 0 releases and 0 playground runs. The external-developer path (account, project, sandbox app, grants, Media upload, app events) was run once on production on 2026-09-23 with public endpoints and curl, not through these playgrounds; that check is not committed to a repository or CI.",
"works": [
ddiff --git a/package-lock.json b/package-lock.json
iindex bc7fd4f..fa3ad5a 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -18,7 +18,7 @@
"iovalkey": "^0.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.86.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.26.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.5.0",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",
"pg": "^8.23.0"
},
"devDependencies": {
@@@ -1201,9 +1201,9 @@
}
},
"node_modules/openvibe-shared": {
-- "version": "2.5.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.5.0",
-- "integrity": "sha512-fHuUS6SXM7ezatfAyqLm1V8B6puV9YXSnz6aG6XQbWx28qghRCCHeUF3lr4nxiCGdn9SyikYtIyLGL5r1ycp9Q==",
++ "version": "2.6.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",
++ "integrity": "sha512-IKKvWTM/9UonQ4msrzM4yir0QcTUNbhyqeN1r5ywWavU4VTsL1sI5QdHQlxge7BAsMrQ4OvMEPlHjuAfUJM3rg==",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0"
ddiff --git a/package.json b/package.json
iindex db2a4b2..9d4b74a 100644
---- a/package.json
++++ b/package.json
@@@ -30,7 +30,7 @@
"iovalkey": "^0.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.86.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.26.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.5.0",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.6.0",
"pg": "^8.23.0"
},
"engines": {
ddiff --git a/server/render/layout.js b/server/render/layout.js
iindex 3dae154..4418941 100644
---- a/server/render/layout.js
++++ b/server/render/layout.js
@@@ -1,10 +1,11 @@
'use strict';
/**
-- * Page shell. Every page is server-rendered through this and is complete without JavaScript:
-- * - <head>: title, description, canonical, robots (portal pages are noindex), the shared app icon
-- * - the OpenVibe Frame: navbar.js and theme-loader.js from the Network (progressive), a <noscript>
-- * navigation bar and the server-rendered shared footer (openvibe-shared)
++ * Page shell. Every page is server-rendered through openvibe-shared/shell and is complete without JavaScript:
++ * - <head>: title, description, canonical, robots (portal pages are noindex), Open Graph/Twitter,
++ * JSON-LD (openvibe-shared/seo), plus Codes' extras: the shared app icon, stylesheets, the boost marker
++ * - the OpenVibe Frame: theme-loader, web-runtime, navbar and footer scripts (the shell boots the
++ * navbar; the footer is initialised below), a <noscript> navigation bar and the server-rendered footer
* - Codes' own script only where a page offers an optional in-browser convenience (webhook
* signature computed locally, copy buttons); every form works without it
*/
@@@ -14,7 +15,7 @@ const fs = require('fs');
const path = require('path');
const appIcon = require('openvibe-shared/app-icon');
const frame = require('openvibe-shared/frame');
--const seo = require('openvibe-shared/seo');
++const shell = require('openvibe-shared/shell');
const cache = require('openvibe-shared/cache-policy');
const { html, raw, esc } = require('./html');
@@@ -76,49 +77,43 @@ function renderPage(o) {
const crumbs = (o.crumbs || []).length
? html`<nav class="crumbs" aria-label="Breadcrumbs">${o.crumbs.map((c, i) => html`${i ? ' / ' : ''}${c.href ? html`<a href="${c.href}">${c.label}</a>` : c.label}`)}</nav>`
: '';
-- const title = o.title ? `${o.title} · ${SITE_NAME}` : `${SITE_NAME}: the OpenVibe developer portal`;
const scripts = (o.scripts || []).map((rel) => html`<script src="${asset(rel)}" defer></script>`);
-- return `<!DOCTYPE html>
--<html lang="en">
--<head>
--<meta charset="utf-8">
--<meta name="viewport" content="width=device-width, initial-scale=1">
--<title>${esc(title)}</title>
--<meta name="description" content="${esc(o.description || 'Build on OpenVibe: projects, apps and scoped credentials, generated contract and SDK docs, webhook and OAuth tools, and manifest validation.')}">
--<meta name="robots" content="${o.index ? 'index, follow' : 'noindex, nofollow'}">
--<link rel="canonical" href="${esc(canonical)}">
--<meta name="referrer" content="${o.noReferrer ? 'no-referrer' : 'strict-origin-when-cross-origin'}">
++ return shell.page({
++ name: SITE_NAME,
++ lang: 'en',
++ title: o.title || `${SITE_NAME}: the OpenVibe developer portal`,
++ titleSuffix: o.title ? ` · ${SITE_NAME}` : '',
++ siteName: SITE_NAME,
++ description: o.description || 'Build on OpenVibe: projects, apps and scoped credentials, generated contract and SDK docs, webhook and OAuth tools, and manifest validation.',
++ canonical,
++ robots: o.index ? 'index, follow' : 'noindex, nofollow',
++ jsonLd: (o.jsonLd || []).filter(Boolean),
++ home: '/',
++ navLinks: NAV,
++ navbar: nav,
++ footer,
++ head: `<meta name="referrer" content="${o.noReferrer ? 'no-referrer' : 'strict-origin-when-cross-origin'}">
${appIcon.headTags({ site: 'codes' })}
--${(o.jsonLd || []).filter(Boolean).map(seo.jsonLdTag).join('\n')}
<link rel="stylesheet" href="${asset('css/codes.css')}">
${(o.styles || []).map((name) => `<link rel="stylesheet" href="${esc(ovServe.url(name))}">`).join('\n')}
--<script src="${ovServe.url('theme-loader.js')}" defer></script>
--<script src="${ovServe.url('navbar.js')}" defer></script>
--<script src="${ovServe.url('footer.js')}" defer></script>
${render(scripts)}
<meta name="ov-boost" content="codes@${esc(RELEASE)}">
--<script src="${ovServe.url('boost.js')}" data-main="#main" defer></script>
--</head>
--<body>
--<a class="skip" href="#main">Skip to content</a>
++<script src="${ovServe.url('boost.js')}" data-main="#main" defer></script>`,
++ body: `<a class="skip" href="#main">Skip to content</a>
<div id="navbar-mount"></div>
--${frame.noscriptNav({ name: SITE_NAME, home: '/', links: NAV })}
<noscript><div class="account-bar" role="navigation" aria-label="Account">${render(account)}</div></noscript>
<main id="main" class="page">
${render(crumbs)}
${render(o.body)}
${o.path === '/' ? frame.shipped({ service: 'codes', title: `Recently shipped on ${SITE_NAME}` }) : ''}
</main>
--${frame.footer(footer)}
<script>
window.__OV_PAGE = ${JSON.stringify({ navbar: nav, footer }).replace(/</g, '\\u003c')};
document.addEventListener('DOMContentLoaded', function () {
-- try { if (window.OpenVibeNavbar) OpenVibeNavbar.init(window.__OV_PAGE.navbar); } catch (e) { /* the Frame 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) { /* the Frame is optional */ }
});
--</script>
--</body>
--</html>`;
++</script>`,
++ });
}
function render(v) { return require('./html').render(v); }
ddiff --git a/test/layout.test.js b/test/layout.test.js
iindex 775067a..5a34ebc 100644
---- a/test/layout.test.js
++++ b/test/layout.test.js
@@@ -35,6 +35,23 @@ const BOOST = /<script src="\/shared\/boost\.js\?v=[0-9a-f]{12}" data-main="#mai
assert.match(signedIn.text, BOOST, '/projects: no boost script');
});
++ await check('the home page head comes from openvibe-shared/shell with the same title, canonical, robots and JSON-LD', async () => {
++ const r = await t.get('/');
++ assert.strictEqual(r.status, 200);
++ const head = r.text.slice(0, r.text.indexOf('</head>'));
++ assert.strictEqual((r.text.match(/<title>/g) || []).length, 1, 'exactly one <title>');
++ assert.ok(head.includes('<title>OpenVibe.Codes: the OpenVibe developer portal</title>'), 'home title');
++ assert.ok(head.includes('<link rel="canonical" href="https://openvibe.codes/">'), 'canonical');
++ assert.ok(head.includes('<meta name="robots" content="index, follow">'), 'robots');
++ const ld = [...head.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)].map((m) => JSON.parse(m[1])['@type']);
++ assert.deepStrictEqual(ld, ['WebSite', 'WebApplication', 'WebPage'], 'the home JSON-LD');
++ for (const tag of ['<meta property="og:title"', 'data-ov-icon="codes"', '/css/codes.css?v=', '/shared/theme-loader.js', '/shared/navbar.js', '/shared/footer.js', '<meta name="referrer"']) {
++ assert.ok(head.includes(tag), `head has ${tag}`);
++ }
++ assert.ok(r.text.includes('id="ov-footer"'), 'the server-rendered footer');
++ assert.ok(r.text.includes('OpenVibeFooter.init(window.__OV_PAGE.footer)'), 'the footer is initialised');
++ });
++
await check('the navbar config uses the {path} login template, not the path baked in', async () => {
const r = await t.get('/docs');
assert.match(r.text, /"loginUrl":"\/auth\/login\?next=\{path\}"/);
ddiff --git a/test/perf-budget.test.js b/test/perf-budget.test.js
iindex 944a36a..77f3d90 100644
---- a/test/perf-budget.test.js
++++ b/test/perf-budget.test.js
@@@ -14,9 +14,9 @@ const { measure, check, format } = require('openvibe-shared/perf-budget');
const BUDGETS = {
htmlRawKB: 30, // measured 27.0 (fresh database; the showcase home, 2026-09-29: sections + six inline ring icons)
htmlBrotliKB: 7.5, // 6.7
-- jsFiles: 5, // 4
-- jsRawKB: 225, // 212.2
-- jsBrotliKB: 53, // 49.9
++ jsFiles: 5, // 5 (theme-loader, web-runtime, navbar, footer, boost: openvibe-shared/shell adds web-runtime, 2026-10-04)
++ jsRawKB: 245, // 239.1 (212.2 before openvibe-shared/shell's web-runtime.js)
++ jsBrotliKB: 59, // 56.3 (49.9 before web-runtime.js)
cssFiles: 2, // 1
cssRawKB: 19, // 17.3 (codes.css + the cached /shared/showcase.css)
cssBrotliKB: 5, // 4.1