openvibers/openvibe.codes Commits

The Codes home is built from the showcase kit (plan T11, D92; openvibe-shared v2.3.1): a hero with where to start and a working SDK sample, what an integration gets (credentials, grants, events, generated reference, playgrounds, the SDK), the path from account to integration, the limits a project really gets read live from OpenVibe.Events' /limits.json (never restated; the section is left out when Events does not answer), the reference, recent releases and a closing call to action. The kit's stylesheet is linked (cached, loaded styles-first on a boost swap). Home budgets raised as a decision: HTML 30 KB (measured 27.0: sections and six inline ring icons), CSS 19 KB with the shared stylesheet. 33/33.

OP OpenVibers committed 29 Sept 2026 · f15150db77 · 7 files, +81 −28


Changes

ddiff --git a/STATUS.json b/STATUS.json
iindex 11dbabd..1a1b6e8 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -11,7 +11,7 @@
"packages": [
"openvibe-contracts v0.79.0",
"openvibe-sdk v0.25.0",
-- "openvibe-shared v2.2.0"
++ "openvibe-shared v2.3.1"
],
"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 c954d33..90b4a9d 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.79.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.25.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.2.0",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.3.1",
"pg": "^8.23.0"
},
"devDependencies": {
@@@ -1202,9 +1202,9 @@
}
},
"node_modules/openvibe-shared": {
-- "version": "2.2.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.2.0",
-- "integrity": "sha512-1q+iUuUxzPeylTYmithW4jR++Jccvn5GEOrB1B3D18Dgn6OXQhPpvhPQAa1D1k1p+dWIa1/SmggyJwSGFnTNtw==",
++ "version": "2.3.1",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.3.1",
++ "integrity": "sha512-K+MXnB4O+8xIFi+NQGC2SDTvDq3RkzfxQ3bTVx76Y/Rbuq7kC/L5kL3c/06xr9sPYcjyzF3Bhpv5yH2YNfR4Zw==",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0"
ddiff --git a/package.json b/package.json
iindex e75a691..738bde2 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.79.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.25.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.2.0",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.3.1",
"pg": "^8.23.0"
},
"engines": {
ddiff --git a/public/css/codes.css b/public/css/codes.css
iindex 09f4e9c..d55b547 100644
---- a/public/css/codes.css
++++ b/public/css/codes.css
@@@ -74,3 +74,8 @@ fieldset { border: 1px solid var(--border, #1f2d47); border-radius: 8px; display
@media (max-width: 640px) { .facts { grid-template-columns: 1fr; } .facts dt { margin-top: 6px; } .toc ul { columns: 1; } }
.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
meter.headroom { width: 8rem; max-width: 100%; vertical-align: middle; }
++
++/* The home page's showcase sections (openvibe-shared/showcase.css) sit inside .page, which has its own gutter. */
++.page .sc-hero, .page .sc-sec, .page .sc-cta { padding-left: 0; padding-right: 0; }
++.page .sc-ic .ov-icon { --ovi-size: 28px !important; }
++.codes-hero-code { margin: 0; padding: 16px; border-radius: 14px; border: 1px solid var(--border, #1f2d47); background: var(--bg-primary, #0a0f1c); font-size: 13px; line-height: 1.6; overflow: auto; }
ddiff --git a/server/http/pages.js b/server/http/pages.js
iindex fa41661..6628e72 100644
---- a/server/http/pages.js
++++ b/server/http/pages.js
@@@ -14,6 +14,7 @@
const fs = require('fs');
const ovServe = require('openvibe-shared/serve');
const frame = require('openvibe-shared/frame');
++const showcase = require('openvibe-shared/showcase');
const path = require('path');
const express = require('express');
const { asyncRouter } = require('./router');
@@@ -50,6 +51,13 @@ function loadGovernance() {
});
}
++/** A limit as its service states it: a number with its unit, or unlimited/none. */
++function limitAmount(v, unit) {
++ if (v === null || v === undefined) return 'unlimited';
++ if (v === 0) return 'none';
++ return unit ? `${Number(v).toLocaleString('en-US')} ${unit}` : Number(v).toLocaleString('en-US');
++}
++
function createPageRoutes(ctx) {
const { config, docs, releases, trust, network, sso } = ctx;
const r = asyncRouter();
@@@ -60,28 +68,67 @@ function createPageRoutes(ctx) {
r.get('/', async (req, res) => {
const recent = await releases.recentPublic(10);
++ // The limits a developer's project really gets, from the service that enforces them (never restated here).
++ const eventsSource = ctx.limits && ctx.limits.bySource ? ctx.limits.bySource('events') : null;
++ const eventsLimits = eventsSource ? await ctx.limits.read(eventsSource) : null;
++ const limitRows = eventsLimits && eventsLimits.body ? eventsLimits.body.limits.slice(0, 6).map((l) => ({ label: l.label, values: [limitAmount(l.sandbox, l.unit), limitAmount(l.production, l.unit)] })) : [];
++ const snippet = `// openvibe-sdk v${docs.sdkVersion} (install: /docs/sdk)
++const { createClient } = require('openvibe-sdk');
++const { createServiceTokenClient } =
++ require('openvibe-sdk/auth');
++
++const ov = createClient({
++ tokenProvider: createServiceTokenClient({
++ clientId, clientSecret,
++ }),
++});
++const services = await ov.registry.services();`;
page(req, res, {
index: true, cache: PUBLIC_CACHE,
jsonLd: homeJsonLd(config),
-- body: html`<h1>Build on OpenVibe</h1>
--<p class="lead">OpenVibe.Codes is the developer portal: create a project and apps in OpenVibe.Network, get scoped credentials, request capability grants, and read reference docs generated from the exact contract and SDK versions the platform runs.</p>
--<div class="notice">Status: alpha. What works and what does not is listed on the <a href="/policy/transparency">transparency page</a>. Network owns projects, apps, credentials, grants and quotas; Codes is a portal over its API and never stores a secret.</div>
--<h2>From account to integration</h2>
--<ol class="steps">
--<li><a href="/projects">Create a project</a> (signed in with your OpenVibe account). New projects are sandbox-only; staff enable production.</li>
--<li>Add a <strong>sandbox app</strong>. A confidential app gets a client secret, shown once.</li>
--<li><a href="/docs/capabilities?grantable=1">Pick capabilities</a> and request them for the app. They are approved only inside the project's allowance.</li>
--<li>Install <a href="/docs/sdk">openvibe-sdk</a>; get a token with <code>createServiceTokenClient()</code> (client credentials) or sign people in with <a href="/oauth">authorization code + PKCE</a>.</li>
--<li>Receive events: subscribe, then verify each delivery's signature (<a href="/tools/webhooks">tester</a>).</li>
--<li>Try calls in the app's playground with the app's own credentials: it cannot do anything the app is not granted.</li>
--<li>Publish release metadata with a <a href="/manifests/validate">validated manifest</a>; rotate or revoke credentials any time.</li>
--</ol>
--<h2>Reference</h2>
--<p>Generated from <code>openvibe-contracts v${docs.contractsVersion}</code> and <code>openvibe-sdk v${docs.sdkVersion}</code>: <a href="/docs/api">API explorer</a> · <a href="/docs/contracts">contracts</a> · <a href="/docs/capabilities">capabilities</a> · <a href="/docs/events">events</a> · <a href="/docs/services">services</a> · <a href="/docs/tools">tools</a> · <a href="/docs/sdk">SDK</a>.</p>
--<h2>Recent releases</h2>
++ styles: [showcase.STYLESHEET],
++ body: html`${raw(showcase.hero({
++ eyebrow: 'OpenVibe.Codes · the developer portal · alpha',
++ title: 'Build on', accent: 'OpenVibe',
++ lede: 'Create a project, get scoped credentials, request capability grants, and read reference docs generated from the exact contract and SDK versions the platform runs.',
++ actions: [{ label: 'Create a project', href: '/projects', primary: true }, { label: 'Read the docs', href: '/docs' }],
++ note: 'Network owns projects, apps, credentials, grants and quotas; Codes is a portal over its API and never stores a secret.',
++ aside: { html: `<pre class="codes-hero-code"><code>${showcase.esc(snippet)}</code></pre>` },
++ }))}
++<div class="notice">Status: alpha. What works and what does not is listed on the <a href="/policy/transparency">transparency page</a>.</div>
++${raw(showcase.features({
++ title: 'Everything an integration needs', lede: 'Each piece is a public API with a reference generated from what production runs.',
++ items: [
++ { icon: 'ov:account', title: 'Scoped credentials', text: 'A confidential app gets a client secret, shown once; rotate or revoke it any time.', href: '/projects' },
++ { icon: 'ov:check', title: 'Capability grants', text: 'Ask for exactly what your app does; grants are approved inside the project\'s allowance.', href: '/docs/capabilities?grantable=1' },
++ { icon: 'ov:bell', title: 'Events and webhooks', text: 'Subscribe to the network and verify every delivery\'s signature.', href: '/tools/webhooks' },
++ { icon: 'ov:docs', title: 'Generated reference', text: `Contracts, capabilities, events and APIs from openvibe-contracts v${docs.contractsVersion}.`, href: '/docs' },
++ { icon: 'ov:code', title: 'Playgrounds', text: 'Try calls with your app\'s own credentials: it cannot do anything the app is not granted.', href: '/oauth' },
++ { icon: 'ov:json', title: 'The SDK', text: `openvibe-sdk v${docs.sdkVersion}: one package for browser and server, typed.`, href: '/docs/sdk' },
++ ],
++ }))}
++${raw(showcase.steps({
++ title: 'From account to integration',
++ items: [
++ { title: 'Create a project', text: 'Signed in with your OpenVibe account. New projects are sandbox-only; staff enable production.', href: '/projects' },
++ { title: 'Add a sandbox app', text: 'A confidential app gets a client secret, shown once.' },
++ { title: 'Pick capabilities', text: 'Request them for the app; they are approved only inside the project\'s allowance.', href: '/docs/capabilities?grantable=1' },
++ { title: 'Get a token', text: 'createServiceTokenClient() for client credentials, or sign people in with authorization code + PKCE.', href: '/oauth' },
++ { title: 'Receive events', text: 'Subscribe, then verify each delivery\'s signature.', href: '/tools/webhooks' },
++ { title: 'Publish a release', text: 'Validated release metadata; rotate or revoke credentials any time.', href: '/manifests/validate' },
++ ],
++ }))}
++${raw(showcase.limits({
++ title: 'What a project gets', lede: 'Pricing is the limits: these are the numbers OpenVibe.Events enforces for every project today.',
++ columns: ['Sandbox', 'Production'], rows: limitRows, source: eventsSource && eventsSource.public,
++ }))}
++<section class="sc-sec" aria-labelledby="h-ref"><h2 id="h-ref">Reference</h2>
++<p class="sc-lede">Generated from <code>openvibe-contracts v${docs.contractsVersion}</code> and <code>openvibe-sdk v${docs.sdkVersion}</code>: <a href="/docs/api">API explorer</a> · <a href="/docs/contracts">contracts</a> · <a href="/docs/capabilities">capabilities</a> · <a href="/docs/events">events</a> · <a href="/docs/services">services</a> · <a href="/docs/tools">tools</a> · <a href="/docs/sdk">SDK</a> · <a href="/docs/limits">all limits</a>.</p></section>
++<section class="sc-sec" aria-labelledby="h-rel"><h2 id="h-rel">Recent releases</h2>
${table(['App', 'Kind', 'Version', 'Status', 'Trust', 'Published'], recent.map((x) => [
html`<a href="/apps/${x.app_id}">${x.name}</a>`, x.kind, html`<a href="/releases/${x.id}">${x.version}</a>`, x.status, x.trust.tier, time(x.published_at),
-- ]), { empty: 'No releases have been published yet.' })}`,
++ ]), { empty: 'No releases have been published yet.' })}</section>
++${raw(showcase.cta({ title: 'Start building', text: 'Sign in with your OpenVibe account; your first project takes a minute.', actions: [{ label: 'Create a project', href: '/projects', primary: true }] }))}`,
});
});
ddiff --git a/server/render/layout.js b/server/render/layout.js
iindex 6dbb84a..3e3355b 100644
---- a/server/render/layout.js
++++ b/server/render/layout.js
@@@ -46,7 +46,7 @@ function setRelease(id) { if (id) RELEASE = String(id); }
/**
* o: title, description, body (html), viewer, config, path, index (default false), scripts [rel],
-- * crumbs [{ label, href }], jsonLd [nodes] (serialised by openvibe-shared/seo)
++ * crumbs [{ label, href }], jsonLd [nodes] (serialised by openvibe-shared/seo), styles [openvibe-shared stylesheet names]
*/
function renderPage(o) {
const viewer = o.viewer || { kind: 'anonymous' };
@@@ -90,6 +90,7 @@ function renderPage(o) {
${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>
ddiff --git a/test/perf-budget.test.js b/test/perf-budget.test.js
iindex 3de13f6..944a36a 100644
---- a/test/perf-budget.test.js
++++ b/test/perf-budget.test.js
@@@ -12,14 +12,14 @@ const { spawn } = require('child_process');
const { measure, check, format } = require('openvibe-shared/perf-budget');
const BUDGETS = {
-- htmlRawKB: 21, // measured 19.5 (fresh database)
-- htmlBrotliKB: 5.6, // 5.1
++ 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
cssFiles: 2, // 1
-- cssRawKB: 7.5, // 6.6
-- cssBrotliKB: 2, // 1.6
++ cssRawKB: 19, // 17.3 (codes.css + the cached /shared/showcase.css)
++ cssBrotliKB: 5, // 4.1
externalFiles: 2, // 0
};