openvibers/openvibe.sites Commits
realtime.openvibe.network: closed notice instead of a product placeholder
Changes
@@@ -77,7 +77,7 @@ function statusText(site) {const o = f.registry.origin;return `${repo} is live at <a href="${esc(o)}/">${esc(o.replace(/^https?:\/\//, ''))}</a>; this subdomain is not routed to it yet, so it serves this placeholder.`;}-- if (k === 'closed') return `${repo} is closed, so no product launches here; this page is a placeholder.`;++ if (k === 'closed') return `${repo} is closed and stays as a decision record; no product launches at this address.`;return `${repo}: charter only, no code yet; this page is a placeholder.${waits}`;}const today = new Date().toISOString().slice(0, 10);@@@ -92,7 +92,11 @@ function page(site) {const title = `${site.name} — ${site.tagline}`;const ogImage = `${NET.networkUrl}/assets/logo-512.png`;const others = NET.liveSites.filter(s => s.url !== url.slice(0, -1));-- const siblings = catalog.sites.filter(s => s.domain !== site.domain);++ // A notice (site.kind: closed) is not a placeholder for a product: it says where the work went, is not++ // indexed and is not listed among the domains still to open.++ const notice = !!site.kind;++ const siblings = catalog.sites.filter(s => s.domain !== site.domain && !s.kind);++ const primary = notice && site.links && site.links[0];const ld = {'@context': 'https://schema.org','@graph': [@@@ -111,7 +115,7 @@ function page(site) {<title>${esc(title)}</title><meta name="description" content="${esc(site.description)}"><meta name="keywords" content="${esc(site.keywords || '')}">--<meta name="robots" content="index, follow, max-image-preview:large">++<meta name="robots" content="${notice ? 'noindex, follow' : 'index, follow, max-image-preview:large'}"><meta name="theme-color" content="${esc(site.accent)}"><link rel="canonical" href="${url}">${require('openvibe-shared/app-icon').headTags({ site: 'network' }).split('\n')[0]}@@@ -202,14 +206,21 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<div class="tag">${esc(site.tagline)}</div><p class="lead">${esc(site.description)}</p><div class="ctas">-- <a class="btn btn-primary" href="${NET.networkUrl}/login?return=${encodeURIComponent(url)}"><i class="fa-solid fa-right-to-bracket"></i> Sign in with OpenVibe</a>++ ${primary ? `<a class="btn btn-primary" href="${esc(primary[1])}"><i class="fa-solid fa-arrow-right"></i> ${esc(primary[0])}</a>` : `<a class="btn btn-primary" href="${NET.networkUrl}/login?return=${encodeURIComponent(url)}"><i class="fa-solid fa-right-to-bracket"></i> Sign in with OpenVibe</a>`}<a class="btn" href="${NET.networkUrl}/#network"><i class="fa-solid fa-circle-nodes"></i> The whole network</a><a class="btn" href="${esc(NET.discord)}" rel="noopener"><i class="fa-brands fa-discord"></i> Follow the build</a></div><p class="status"><i class="fa-solid fa-clock" aria-hidden="true"></i> Status: <b>${esc(STANDING[standing(site)].label)}</b> · ${statusText(site)} · as of ${esc(facts.generated)} · <a href="/status.json">status.json</a></p></header>-- <section id="what">++${notice ? ` <section id="what" class="meanwhile">++ <h2>Where to go</h2>++ <p class="lead2">${esc(site.linksLead || 'What this address used to stand for lives here now.')}</p>++ <div class="grid">++ ${site.links.map(([h, href, d]) => `<a class="card" href="${esc(href)}"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>${esc(h)}</b><span>${esc(d)}</span><span class="go">${esc(href.replace(/^https?:\/\//, '').replace(/\/$/, ''))} →</span></a>`).join('\n ')}++ </div>++ </section>++` : ` <section id="what"><h2>What ${esc(site.name)} will be</h2><p class="lead2">Same account, same themes, same navbar as every other OpenVibe site — built in the open, run by its community.</p><div class="grid">@@@ -224,7 +235,7 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo${(site.meanwhile || []).map(([h, href, d]) => `<a class="card" href="${esc(href)}"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>${esc(h)}</b><span>${esc(d)}</span><span class="go">${esc(href.replace(/^https?:\/\//, '').replace(/\/$/, ''))} →</span></a>`).join('\n ')}</div></section>--++`}<section class="net"><h2>The OpenVibe network</h2><p class="lead2">One account for all of it. Sign in once and every site signs you in.</p>@@@ -250,7 +261,7 @@ ${require('openvibe-shared/footer').ssr({ service: 'network', variant: 'full' })<script src="${NET.networkUrl}/shared/footer.js"></script><script>(function () {-- if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: '${esc(site.tld)}', apiBase: '${NET.networkUrl}', links: [{ label: 'What it will be', href: '#what' }, { label: 'The network', href: '${NET.networkUrl}/#network', external: false }], history: { type: 'page', title: '${esc(site.name)}' } }); } catch (e) {} }++ if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: '${esc(site.tld)}', apiBase: '${NET.networkUrl}', links: [{ label: '${notice ? 'Where to go' : 'What it will be'}', href: '#what' }, { label: 'The network', href: '${NET.networkUrl}/#network', external: false }], history: { type: 'page', title: '${esc(site.name)}' } }); } catch (e) {} }if (window.OpenVibeFooter) { try { OpenVibeFooter.init({ service: '${esc(site.tld)}', variant: 'full', links: [{ heading: '${esc(site.name)}', items: [{ name: 'Sign in', url: '${NET.networkUrl}/login?return=${encodeURIComponent(url)}' }, { name: 'The network', url: '${NET.networkUrl}/#network' }, { name: 'Discord', url: '${esc(NET.discord)}' }] }] }); } catch (e) {} }})();</script>@@@ -259,7 +270,8 @@ ${require('openvibe-shared/footer').ssr({ service: 'network', variant: 'full' })`;}--function robots(site) { return `User-agent: *\nAllow: /\nDisallow: /auth/\nSitemap: https://${site.domain}/sitemap.xml\n`; }++// A notice page is noindex and has no sitemap; a placeholder lists its one page.++function robots(site) { return `User-agent: *\nAllow: /\nDisallow: /auth/\n${site.kind ? '' : `Sitemap: https://${site.domain}/sitemap.xml\n`}`; }function sitemap(site) { return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n <url><loc>https://${site.domain}/</loc><lastmod>${today}</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>\n</urlset>\n`; }function manifest(site) { return JSON.stringify(require('openvibe-shared/app-icon').manifest({ site: 'network', name: site.name, shortName: site.name.split('.').pop(), description: site.tagline, iconBase: `${NET.networkUrl}/assets` }), null, 2) + '\n'; }@@@ -349,7 +361,7 @@ function build() {for (const site of catalog.sites) {out[`${site.domain}/index.html`] = page(site);out[`${site.domain}/robots.txt`] = robots(site);-- out[`${site.domain}/sitemap.xml`] = sitemap(site);++ if (!site.kind) out[`${site.domain}/sitemap.xml`] = sitemap(site);out[`${site.domain}/manifest.webmanifest`] = manifest(site);out[`${site.domain}/status.json`] = statusJson(site);for (const kind of ['terms', 'privacy', 'dmca']) out[`${site.domain}/${kind}.html`] = legal.page(kind, legalSite(site));@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a><a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a></div></section>@@@ -151,7 +151,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a><a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -3,10 +3,10 @@<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">--<title>realtime.openvibe.network — Authorized live updates, resumable.</title>--<meta name="description" content="realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.">--<meta name="keywords" content="openvibe realtime, openvibe network realtime, openvibe platform">--<meta name="robots" content="index, follow, max-image-preview:large">++<title>realtime.openvibe.network — Closed: realtime delivery is part of OpenVibe.Events.</title>++<meta name="description" content="OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.">++<meta name="keywords" content="openvibe realtime, openvibe events, server-sent events">++<meta name="robots" content="noindex, follow"><meta name="theme-color" content="#34d399"><link rel="canonical" href="https://realtime.openvibe.network/"><link rel="icon" type="image/svg+xml" data-ov-icon="network" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%22-32%20-32%2064%2064%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22ring%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%232563eb%22%2F%3E%3C%2FlinearGradient%3E%0A%3CradialGradient%20id%3D%22glow%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%22.34%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%0A%3CradialGradient%20id%3D%22bg%22%20cx%3D%22.5%22%20cy%3D%22.38%22%20r%3D%22.8%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2316223a%22%2F%3E%3Cstop%20offset%3D%22.6%22%20stop-color%3D%22%230a0f1c%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23060912%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20x%3D%22-32%22%20y%3D%22-32%22%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2215%22%20fill%3D%22url(%23bg)%22%2F%3E%3Cg%20transform%3D%22scale(1.22)%22%3E%0A%3Ccircle%20r%3D%2221%22%20fill%3D%22url(%23glow)%22%2F%3E%0A%3Ccircle%20r%3D%2218%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224%22%20opacity%3D%22.38%22%2F%3E%0A%3Cpath%20d%3D%22M0%2C-18%20A18%2C18%200%200%2C1%2017.4%2C4.6%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224.4%22%20stroke-linecap%3D%22round%22%2F%3E%0A%3Cpath%20d%3D%22M-9.5%2C-7%20L0%2C10%20L9.5%2C-7%22%20fill%3D%22none%22%20stroke%3D%22%23fff%22%20stroke-width%3D%224.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%0A%3Ccircle%20cx%3D%2217.4%22%20cy%3D%224.6%22%20r%3D%223.2%22%20fill%3D%22%23ffffff%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">@@@ -16,15 +16,15 @@<meta property="og:type" content="website"><meta property="og:site_name" content="realtime.openvibe.network"><meta property="og:url" content="https://realtime.openvibe.network/">--<meta property="og:title" content="realtime.openvibe.network — Authorized live updates, resumable.">--<meta property="og:description" content="realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.">++<meta property="og:title" content="realtime.openvibe.network — Closed: realtime delivery is part of OpenVibe.Events.">++<meta property="og:description" content="OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice."><meta property="og:image" content="https://openvibe.network/assets/logo-512.png"><meta property="og:image:alt" content="OpenVibe"><meta name="twitter:card" content="summary">--<meta name="twitter:title" content="realtime.openvibe.network — Authorized live updates, resumable.">--<meta name="twitter:description" content="realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.">++<meta name="twitter:title" content="realtime.openvibe.network — Closed: realtime delivery is part of OpenVibe.Events.">++<meta name="twitter:description" content="OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice."><meta name="twitter:image" content="https://openvibe.network/assets/logo-512.png">--<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://realtime.openvibe.network/#site","url":"https://realtime.openvibe.network/","name":"realtime.openvibe.network","description":"realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.","inLanguage":"en","publisher":{"@type":"Organization","@id":"https://openvibe.network/#org","name":"OpenVibe","url":"https://openvibe.network/","logo":"https://openvibe.network/assets/logo-512.png","sameAs":["https://github.com/OpenVibers","https://discord.gg/M6MuRUaeJj"]},"isPartOf":{"@type":"WebSite","@id":"https://openvibe.network/#site","name":"OpenVibe.Network","url":"https://openvibe.network/"}},{"@type":"WebPage","@id":"https://realtime.openvibe.network/#page","url":"https://realtime.openvibe.network/","name":"realtime.openvibe.network — Authorized live updates, resumable.","description":"realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.","isPartOf":{"@id":"https://realtime.openvibe.network/#site"},"datePublished":"2026-09-17","dateModified":"2026-09-24","breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"OpenVibe","item":"https://openvibe.network/"},{"@type":"ListItem","position":2,"name":"realtime.openvibe.network","item":"https://realtime.openvibe.network/"}]}}]}</script>++<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://realtime.openvibe.network/#site","url":"https://realtime.openvibe.network/","name":"realtime.openvibe.network","description":"OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.","inLanguage":"en","publisher":{"@type":"Organization","@id":"https://openvibe.network/#org","name":"OpenVibe","url":"https://openvibe.network/","logo":"https://openvibe.network/assets/logo-512.png","sameAs":["https://github.com/OpenVibers","https://discord.gg/M6MuRUaeJj"]},"isPartOf":{"@type":"WebSite","@id":"https://openvibe.network/#site","name":"OpenVibe.Network","url":"https://openvibe.network/"}},{"@type":"WebPage","@id":"https://realtime.openvibe.network/#page","url":"https://realtime.openvibe.network/","name":"realtime.openvibe.network — Closed: realtime delivery is part of OpenVibe.Events.","description":"OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.","isPartOf":{"@id":"https://realtime.openvibe.network/#site"},"datePublished":"2026-09-17","dateModified":"2026-09-24","breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"OpenVibe","item":"https://openvibe.network/"},{"@type":"ListItem","position":2,"name":"realtime.openvibe.network","item":"https://realtime.openvibe.network/"}]}}]}</script><script>(function(){try{var raw=localStorage.getItem('ov_theme');if(!raw)return;var t=JSON.parse(raw),v=t&&t.variables;if(!v)return;var el=document.documentElement;for(var k in v)if(k.charAt(0)==='-')el.style.setProperty(k,v[k]);if(t.id)el.setAttribute('data-theme',t.id);}catch(_){}})();</script><script src="https://openvibe.network/shared/theme-loader.js" defer></script><link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>@@@ -94,32 +94,23 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<div class="mark"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><div class="badge"><span class="ov-mark" data-size="16" data-variant="realtime"></span> Part of the OpenVibe network · <b>closed</b></div><h1><span class="d">realtime</span><span class="tld">.openvibe.network</span></h1>-- <div class="tag">Authorized live updates, resumable.</div>-- <p class="lead">realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.</p>++ <div class="tag">Closed: realtime delivery is part of OpenVibe.Events.</div>++ <p class="lead">OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.</p><div class="ctas">-- <a class="btn btn-primary" href="https://openvibe.network/login?return=https%3A%2F%2Frealtime.openvibe.network%2F"><i class="fa-solid fa-right-to-bracket"></i> Sign in with OpenVibe</a>++ <a class="btn btn-primary" href="https://events.openvibe.network/"><i class="fa-solid fa-arrow-right"></i> OpenVibe.Events</a><a class="btn" href="https://openvibe.network/#network"><i class="fa-solid fa-circle-nodes"></i> The whole network</a><a class="btn" href="https://discord.gg/M6MuRUaeJj" rel="noopener"><i class="fa-brands fa-discord"></i> Follow the build</a></div>-- <p class="status"><i class="fa-solid fa-clock" aria-hidden="true"></i> Status: <b>closed</b> · <a href="https://github.com/OpenVibers/OpenVibe.Realtime" rel="noopener"><code>OpenVibers/OpenVibe.Realtime</code></a> is closed, so no product launches here; this page is a placeholder. · as of 2026-09-24 · <a href="/status.json">status.json</a></p>++ <p class="status"><i class="fa-solid fa-clock" aria-hidden="true"></i> Status: <b>closed</b> · <a href="https://github.com/OpenVibers/OpenVibe.Realtime" rel="noopener"><code>OpenVibers/OpenVibe.Realtime</code></a> is closed and stays as a decision record; no product launches at this address. · as of 2026-09-24 · <a href="/status.json">status.json</a></p></header>-- <section id="what">-- <h2>What realtime.openvibe.network will be</h2>-- <p class="lead2">Same account, same themes, same navbar as every other OpenVibe site — built in the open, run by its community.</p>++ <section id="what" class="meanwhile">++ <h2>Where to go</h2>++ <p class="lead2">Realtime delivery for browsers is a part of OpenVibe.Events; the decision and its record are public.</p><div class="grid">-- <div class="card"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Topics</b><span>Subscribe to exactly the streams your account may see.</span></div>-- <div class="card"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Resume</b><span>Reconnect from a cursor and get what you missed.</span></div>-- <div class="card"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Presence</b><span>Who is here, without polling.</span></div>-- <div class="card"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Not media</b><span>Video and audio keep their own transports.</span></div>-- </div>-- </section>---- <section class="meanwhile">-- <h2>Meanwhile, on the network</h2>-- <p class="lead2">Most of this already exists somewhere on OpenVibe — start there today.</p>-- <div class="grid">-- <a class="card" href="https://openvibe.live"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>Chat and stream updates</b><span>Realtime today runs inside OpenVibe.Live.</span><span class="go">openvibe.live →</span></a>++ <a class="card" href="https://events.openvibe.network/"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>OpenVibe.Events</b><span>Durable events, subscriptions and signed delivery; browsers subscribe at /realtime/stream.</span><span class="go">events.openvibe.network →</span></a>++ <a class="card" href="https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-005-realtime.md"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>ADR-005: realtime</b><span>The decision, and when a separate realtime service would be reconsidered.</span><span class="go">github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-005-realtime.md →</span></a>++ <a class="card" href="https://github.com/OpenVibers/OpenVibe.Realtime"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>OpenVibe.Realtime</b><span>The repository stays as the decision record.</span><span class="go">github.com/OpenVibers/OpenVibe.Realtime →</span></a></div></section>@@@ -253,7 +244,7 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<script src="https://openvibe.network/shared/footer.js"></script><script>(function () {-- if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: 'realtime', apiBase: 'https://openvibe.network', links: [{ label: 'What it will be', href: '#what' }, { label: 'The network', href: 'https://openvibe.network/#network', external: false }], history: { type: 'page', title: 'realtime.openvibe.network' } }); } catch (e) {} }++ if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: 'realtime', apiBase: 'https://openvibe.network', links: [{ label: 'Where to go', href: '#what' }, { label: 'The network', href: 'https://openvibe.network/#network', external: false }], history: { type: 'page', title: 'realtime.openvibe.network' } }); } catch (e) {} }if (window.OpenVibeFooter) { try { OpenVibeFooter.init({ service: 'realtime', variant: 'full', links: [{ heading: 'realtime.openvibe.network', items: [{ name: 'Sign in', url: 'https://openvibe.network/login?return=https%3A%2F%2Frealtime.openvibe.network%2F' }, { name: 'The network', url: 'https://openvibe.network/#network' }, { name: 'Discord', url: 'https://discord.gg/M6MuRUaeJj' }] }] }); } catch (e) {} }})();</script>@@@ -1,7 +1,7 @@{"name": "realtime.openvibe.network","short_name": "network",-- "description": "Authorized live updates, resumable.",++ "description": "Closed: realtime delivery is part of OpenVibe.Events.","start_url": "/","scope": "/","display": "standalone",@@@ -1,4 +1,3 @@User-agent: *Allow: /Disallow: /auth/--Sitemap: https://realtime.openvibe.network/sitemap.xmlddeleted file mode 100644@@@ -1,4 +0,0 @@--<?xml version="1.0" encoding="UTF-8"?>--<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">-- <url><loc>https://realtime.openvibe.network/</loc><lastmod>2026-09-24</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>--</urlset>@@@ -1,7 +1,7 @@{"domain": "realtime.openvibe.network","name": "realtime.openvibe.network",-- "stage": "placeholder",++ "stage": "closed","live": false,"plannedRepo": "OpenVibers/OpenVibe.Realtime","repoUrl": "https://github.com/OpenVibers/OpenVibe.Realtime",@@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a><a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a><a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>-- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a><a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a></div></section>@@@ -627,39 +627,33 @@"openvibe.network"],"tld": "realtime",++ "kind": "closed","name": "realtime.openvibe.network","icon": "fa-satellite-dish","accent": "#34d399","plannedRepo": "OpenVibe.Realtime","legalProfile": "info",-- "tagline": "Authorized live updates, resumable.",-- "description": "realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.",-- "pillars": [++ "tagline": "Closed: realtime delivery is part of OpenVibe.Events.",++ "description": "OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.",++ "linksLead": "Realtime delivery for browsers is a part of OpenVibe.Events; the decision and its record are public.",++ "links": [[-- "Topics",-- "Subscribe to exactly the streams your account may see."++ "OpenVibe.Events",++ "https://events.openvibe.network/",++ "Durable events, subscriptions and signed delivery; browsers subscribe at /realtime/stream."],[-- "Resume",-- "Reconnect from a cursor and get what you missed."++ "ADR-005: realtime",++ "https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-005-realtime.md",++ "The decision, and when a separate realtime service would be reconsidered."],[-- "Presence",-- "Who is here, without polling."-- ],-- [-- "Not media",-- "Video and audio keep their own transports."-- ]-- ],-- "meanwhile": [-- [-- "Chat and stream updates",-- "https://openvibe.live",-- "Realtime today runs inside OpenVibe.Live."++ "OpenVibe.Realtime",++ "https://github.com/OpenVibers/OpenVibe.Realtime",++ "The repository stays as the decision record."]],-- "keywords": "openvibe realtime, openvibe network realtime, openvibe platform"++ "keywords": "openvibe realtime, openvibe events, server-sent events"},{"domain": "ai.openvibe.network",@@@ -26,15 +26,30 @@ for (const site of catalog.sites) {pages++;assert.match(html, /<title>[^<]+<\/title>/, `${d}: title`);assert.match(html, new RegExp(`<link rel="canonical" href="https://${d.replace(/\./g, '\\.')}/?"`), `${d}: canonical`);-- assert.match(html, /placeholder/i, `${d}: says it is a placeholder (never claim a product is live)`);++ if (!site.kind) assert.match(html, /placeholder/i, `${d}: says it is a placeholder (never claim a product is live)`);assert.doesNotMatch(html, PRICING, `${d}: pricing copy`);assert.doesNotMatch(html, UNBACKED, `${d}: claims a hosting product that does not exist`);for (const m of html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)) {assert.doesNotThrow(() => JSON.parse(m[1]), `${d}: JSON-LD parses`);}-- for (const f of ['robots.txt', 'sitemap.xml', 'manifest.webmanifest']) {++ for (const f of ['robots.txt', 'manifest.webmanifest', 'status.json', ...(site.kind ? [] : ['sitemap.xml'])]) {assert.ok(fs.existsSync(path.join(ROOT, 'dist', d, f)), `${d}: ${f}`);}++ if (site.kind) {++ // A notice (a closed product, a pointer) is not indexed, has no sitemap and is not listed as opening.++ assert.match(html, /<meta name="robots" content="noindex, follow">/, `${d}: notice is noindex`);++ assert.ok(!fs.existsSync(path.join(ROOT, 'dist', d, 'sitemap.xml')), `${d}: notice has no sitemap`);++ assert.doesNotMatch(read(`dist/${d}/robots.txt`), /Sitemap:/, `${d}: robots.txt names no sitemap`);++ assert.ok(Array.isArray(site.links) && site.links.length, `${d}: notice links where to go`);++ for (const [, href] of site.links) assert.ok(html.includes(`href="${href}"`), `${d}: links ${href}`);++ for (const other of catalog.sites) {++ if (other.domain !== d) assert.ok(!read(`dist/${other.domain}/index.html`).includes(`href="https://${d}/"`), `${other.domain}: does not list the ${site.kind} ${d} as a domain still to open`);++ }++ }++ if (site.kind === 'closed') {++ assert.match(html, /Status: <b>closed<\/b>/, `${d}: says closed`);++ assert.doesNotMatch(html, /will be|opening soon|coming soon/i, `${d}: a closed product is never described as coming`);++ }const conf = read(`deploy/nginx/${d}.conf`);assert.ok(conf.includes(`server_name ${d}`), `${d}: vhost server_name`);assert.ok(conf.includes(`root /opt/openvibe.sites/dist/${d};`), `${d}: vhost root`);@@@ -53,6 +68,7 @@ for (const site of catalog.sites) {const html = read(`dist/${d}/index.html`);const status = JSON.parse(read(`dist/${d}/status.json`));const st = f.status || {}; const rg = f.registry || {};++ if (st.stage === 'closed') assert.strictEqual(site.kind, 'closed', `${d}: ${site.plannedRepo} is closed (STATUS.json), so its page is a closed notice, not a placeholder`);const hasCode = st.code === true || ['live', 'internal'].includes(rg.state);if (hasCode) {assert.doesNotMatch(html, NO_CODE, `${d}: ${site.plannedRepo} has code, so the page never says "charter only, no code yet"`);
@@ -77,7 +77,7 @@ function statusText(site) {
@@ -77,7 +77,7 @@ function statusText(site) {
const o = f.registry.origin;
const o = f.registry.origin;
return `${repo} is live at <a href="${esc(o)}/">${esc(o.replace(/^https?:\/\//, ''))}</a>; this subdomain is not routed to it yet, so it serves this placeholder.`;
return `${repo} is live at <a href="${esc(o)}/">${esc(o.replace(/^https?:\/\//, ''))}</a>; this subdomain is not routed to it yet, so it serves this placeholder.`;
}
}
- if (k === 'closed') return `${repo} is closed, so no product launches here; this page is a placeholder.`;
+ if (k === 'closed') return `${repo} is closed and stays as a decision record; no product launches at this address.`;
return `${repo}: charter only, no code yet; this page is a placeholder.${waits}`;
return `${repo}: charter only, no code yet; this page is a placeholder.${waits}`;
}
}
const today = new Date().toISOString().slice(0, 10);
const today = new Date().toISOString().slice(0, 10);
@@ -92,7 +92,11 @@ function page(site) {
@@ -92,7 +92,11 @@ function page(site) {
const title = `${site.name} — ${site.tagline}`;
const title = `${site.name} — ${site.tagline}`;
const ogImage = `${NET.networkUrl}/assets/logo-512.png`;
const ogImage = `${NET.networkUrl}/assets/logo-512.png`;
const others = NET.liveSites.filter(s => s.url !== url.slice(0, -1));
const others = NET.liveSites.filter(s => s.url !== url.slice(0, -1));
- const siblings = catalog.sites.filter(s => s.domain !== site.domain);
+ // A notice (site.kind: closed) is not a placeholder for a product: it says where the work went, is not
+ // indexed and is not listed among the domains still to open.
+ const notice = !!site.kind;
+ const siblings = catalog.sites.filter(s => s.domain !== site.domain && !s.kind);
+ const primary = notice && site.links && site.links[0];
const ld = {
const ld = {
'@context': 'https://schema.org',
'@context': 'https://schema.org',
'@graph': [
'@graph': [
@@ -111,7 +115,7 @@ function page(site) {
@@ -111,7 +115,7 @@ function page(site) {
<title>${esc(title)}</title>
<title>${esc(title)}</title>
<meta name="description" content="${esc(site.description)}">
<meta name="description" content="${esc(site.description)}">
<meta name="keywords" content="${esc(site.keywords || '')}">
<meta name="keywords" content="${esc(site.keywords || '')}">
-<meta name="robots" content="index, follow, max-image-preview:large">
+<meta name="robots" content="${notice ? 'noindex, follow' : 'index, follow, max-image-preview:large'}">
<meta name="theme-color" content="${esc(site.accent)}">
<meta name="theme-color" content="${esc(site.accent)}">
<link rel="canonical" href="${url}">
<link rel="canonical" href="${url}">
${require('openvibe-shared/app-icon').headTags({ site: 'network' }).split('\n')[0]}
${require('openvibe-shared/app-icon').headTags({ site: 'network' }).split('\n')[0]}
@@ -202,14 +206,21 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -202,14 +206,21 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<div class="tag">${esc(site.tagline)}</div>
<div class="tag">${esc(site.tagline)}</div>
<p class="lead">${esc(site.description)}</p>
<p class="lead">${esc(site.description)}</p>
<div class="ctas">
<div class="ctas">
- <a class="btn btn-primary" href="${NET.networkUrl}/login?return=${encodeURIComponent(url)}"><i class="fa-solid fa-right-to-bracket"></i> Sign in with OpenVibe</a>
+ ${primary ? `<a class="btn btn-primary" href="${esc(primary[1])}"><i class="fa-solid fa-arrow-right"></i> ${esc(primary[0])}</a>` : `<a class="btn btn-primary" href="${NET.networkUrl}/login?return=${encodeURIComponent(url)}"><i class="fa-solid fa-right-to-bracket"></i> Sign in with OpenVibe</a>`}
<a class="btn" href="${NET.networkUrl}/#network"><i class="fa-solid fa-circle-nodes"></i> The whole network</a>
<a class="btn" href="${NET.networkUrl}/#network"><i class="fa-solid fa-circle-nodes"></i> The whole network</a>
<a class="btn" href="${esc(NET.discord)}" rel="noopener"><i class="fa-brands fa-discord"></i> Follow the build</a>
<a class="btn" href="${esc(NET.discord)}" rel="noopener"><i class="fa-brands fa-discord"></i> Follow the build</a>
</div>
</div>
<p class="status"><i class="fa-solid fa-clock" aria-hidden="true"></i> Status: <b>${esc(STANDING[standing(site)].label)}</b> · ${statusText(site)} · as of ${esc(facts.generated)} · <a href="/status.json">status.json</a></p>
<p class="status"><i class="fa-solid fa-clock" aria-hidden="true"></i> Status: <b>${esc(STANDING[standing(site)].label)}</b> · ${statusText(site)} · as of ${esc(facts.generated)} · <a href="/status.json">status.json</a></p>
</header>
</header>
- <section id="what">
+${notice ? ` <section id="what" class="meanwhile">
+ <h2>Where to go</h2>
+ <p class="lead2">${esc(site.linksLead || 'What this address used to stand for lives here now.')}</p>
+ <div class="grid">
+ ${site.links.map(([h, href, d]) => `<a class="card" href="${esc(href)}"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>${esc(h)}</b><span>${esc(d)}</span><span class="go">${esc(href.replace(/^https?:\/\//, '').replace(/\/$/, ''))} →</span></a>`).join('\n ')}
+ </div>
+ </section>
+` : ` <section id="what">
<h2>What ${esc(site.name)} will be</h2>
<h2>What ${esc(site.name)} will be</h2>
<p class="lead2">Same account, same themes, same navbar as every other OpenVibe site — built in the open, run by its community.</p>
<p class="lead2">Same account, same themes, same navbar as every other OpenVibe site — built in the open, run by its community.</p>
<div class="grid">
<div class="grid">
@@ -224,7 +235,7 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -224,7 +235,7 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
${(site.meanwhile || []).map(([h, href, d]) => `<a class="card" href="${esc(href)}"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>${esc(h)}</b><span>${esc(d)}</span><span class="go">${esc(href.replace(/^https?:\/\//, '').replace(/\/$/, ''))} →</span></a>`).join('\n ')}
${(site.meanwhile || []).map(([h, href, d]) => `<a class="card" href="${esc(href)}"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>${esc(h)}</b><span>${esc(d)}</span><span class="go">${esc(href.replace(/^https?:\/\//, '').replace(/\/$/, ''))} →</span></a>`).join('\n ')}
</div>
</div>
</section>
</section>
-
+`}
<section class="net">
<section class="net">
<h2>The OpenVibe network</h2>
<h2>The OpenVibe network</h2>
<p class="lead2">One account for all of it. Sign in once and every site signs you in.</p>
<p class="lead2">One account for all of it. Sign in once and every site signs you in.</p>
@@ -250,7 +261,7 @@ ${require('openvibe-shared/footer').ssr({ service: 'network', variant: 'full' })
@@ -250,7 +261,7 @@ ${require('openvibe-shared/footer').ssr({ service: 'network', variant: 'full' })
<script src="${NET.networkUrl}/shared/footer.js"></script>
<script src="${NET.networkUrl}/shared/footer.js"></script>
<script>
<script>
(function () {
(function () {
- if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: '${esc(site.tld)}', apiBase: '${NET.networkUrl}', links: [{ label: 'What it will be', href: '#what' }, { label: 'The network', href: '${NET.networkUrl}/#network', external: false }], history: { type: 'page', title: '${esc(site.name)}' } }); } catch (e) {} }
+ if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: '${esc(site.tld)}', apiBase: '${NET.networkUrl}', links: [{ label: '${notice ? 'Where to go' : 'What it will be'}', href: '#what' }, { label: 'The network', href: '${NET.networkUrl}/#network', external: false }], history: { type: 'page', title: '${esc(site.name)}' } }); } catch (e) {} }
if (window.OpenVibeFooter) { try { OpenVibeFooter.init({ service: '${esc(site.tld)}', variant: 'full', links: [{ heading: '${esc(site.name)}', items: [{ name: 'Sign in', url: '${NET.networkUrl}/login?return=${encodeURIComponent(url)}' }, { name: 'The network', url: '${NET.networkUrl}/#network' }, { name: 'Discord', url: '${esc(NET.discord)}' }] }] }); } catch (e) {} }
if (window.OpenVibeFooter) { try { OpenVibeFooter.init({ service: '${esc(site.tld)}', variant: 'full', links: [{ heading: '${esc(site.name)}', items: [{ name: 'Sign in', url: '${NET.networkUrl}/login?return=${encodeURIComponent(url)}' }, { name: 'The network', url: '${NET.networkUrl}/#network' }, { name: 'Discord', url: '${esc(NET.discord)}' }] }] }); } catch (e) {} }
})();
})();
</script>
</script>
@@ -259,7 +270,8 @@ ${require('openvibe-shared/footer').ssr({ service: 'network', variant: 'full' })
@@ -259,7 +270,8 @@ ${require('openvibe-shared/footer').ssr({ service: 'network', variant: 'full' })
`;
`;
}
}
-function robots(site) { return `User-agent: *\nAllow: /\nDisallow: /auth/\nSitemap: https://${site.domain}/sitemap.xml\n`; }
+// A notice page is noindex and has no sitemap; a placeholder lists its one page.
+function robots(site) { return `User-agent: *\nAllow: /\nDisallow: /auth/\n${site.kind ? '' : `Sitemap: https://${site.domain}/sitemap.xml\n`}`; }
function sitemap(site) { return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n <url><loc>https://${site.domain}/</loc><lastmod>${today}</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>\n</urlset>\n`; }
function sitemap(site) { return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n <url><loc>https://${site.domain}/</loc><lastmod>${today}</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>\n</urlset>\n`; }
function manifest(site) { return JSON.stringify(require('openvibe-shared/app-icon').manifest({ site: 'network', name: site.name, shortName: site.name.split('.').pop(), description: site.tagline, iconBase: `${NET.networkUrl}/assets` }), null, 2) + '\n'; }
function manifest(site) { return JSON.stringify(require('openvibe-shared/app-icon').manifest({ site: 'network', name: site.name, shortName: site.name.split('.').pop(), description: site.tagline, iconBase: `${NET.networkUrl}/assets` }), null, 2) + '\n'; }
@@ -349,7 +361,7 @@ function build() {
@@ -349,7 +361,7 @@ function build() {
for (const site of catalog.sites) {
for (const site of catalog.sites) {
out[`${site.domain}/index.html`] = page(site);
out[`${site.domain}/index.html`] = page(site);
out[`${site.domain}/robots.txt`] = robots(site);
out[`${site.domain}/robots.txt`] = robots(site);
- out[`${site.domain}/sitemap.xml`] = sitemap(site);
+ if (!site.kind) out[`${site.domain}/sitemap.xml`] = sitemap(site);
out[`${site.domain}/manifest.webmanifest`] = manifest(site);
out[`${site.domain}/manifest.webmanifest`] = manifest(site);
out[`${site.domain}/status.json`] = statusJson(site);
out[`${site.domain}/status.json`] = statusJson(site);
for (const kind of ['terms', 'privacy', 'dmca']) out[`${site.domain}/${kind}.html`] = legal.page(kind, legalSite(site));
for (const kind of ['terms', 'privacy', 'dmca']) out[`${site.domain}/${kind}.html`] = legal.page(kind, legalSite(site));
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a>
<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -151,7 +151,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -151,7 +151,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a>
<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -150,7 +150,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
<a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -3,10 +3,10 @@
@@ -3,10 +3,10 @@
<head>
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>realtime.openvibe.network — Authorized live updates, resumable.</title>
-<meta name="description" content="realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.">
-<meta name="keywords" content="openvibe realtime, openvibe network realtime, openvibe platform">
-<meta name="robots" content="index, follow, max-image-preview:large">
+<title>realtime.openvibe.network — Closed: realtime delivery is part of OpenVibe.Events.</title>
+<meta name="description" content="OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.">
+<meta name="keywords" content="openvibe realtime, openvibe events, server-sent events">
+<meta name="robots" content="noindex, follow">
<meta name="theme-color" content="#34d399">
<meta name="theme-color" content="#34d399">
<link rel="canonical" href="https://realtime.openvibe.network/">
<link rel="canonical" href="https://realtime.openvibe.network/">
<link rel="icon" type="image/svg+xml" data-ov-icon="network" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%22-32%20-32%2064%2064%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22ring%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%232563eb%22%2F%3E%3C%2FlinearGradient%3E%0A%3CradialGradient%20id%3D%22glow%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%22.34%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%0A%3CradialGradient%20id%3D%22bg%22%20cx%3D%22.5%22%20cy%3D%22.38%22%20r%3D%22.8%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2316223a%22%2F%3E%3Cstop%20offset%3D%22.6%22%20stop-color%3D%22%230a0f1c%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23060912%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20x%3D%22-32%22%20y%3D%22-32%22%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2215%22%20fill%3D%22url(%23bg)%22%2F%3E%3Cg%20transform%3D%22scale(1.22)%22%3E%0A%3Ccircle%20r%3D%2221%22%20fill%3D%22url(%23glow)%22%2F%3E%0A%3Ccircle%20r%3D%2218%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224%22%20opacity%3D%22.38%22%2F%3E%0A%3Cpath%20d%3D%22M0%2C-18%20A18%2C18%200%200%2C1%2017.4%2C4.6%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224.4%22%20stroke-linecap%3D%22round%22%2F%3E%0A%3Cpath%20d%3D%22M-9.5%2C-7%20L0%2C10%20L9.5%2C-7%22%20fill%3D%22none%22%20stroke%3D%22%23fff%22%20stroke-width%3D%224.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%0A%3Ccircle%20cx%3D%2217.4%22%20cy%3D%224.6%22%20r%3D%223.2%22%20fill%3D%22%23ffffff%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">
<link rel="icon" type="image/svg+xml" data-ov-icon="network" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%22-32%20-32%2064%2064%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22ring%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%232563eb%22%2F%3E%3C%2FlinearGradient%3E%0A%3CradialGradient%20id%3D%22glow%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%22.34%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%0A%3CradialGradient%20id%3D%22bg%22%20cx%3D%22.5%22%20cy%3D%22.38%22%20r%3D%22.8%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2316223a%22%2F%3E%3Cstop%20offset%3D%22.6%22%20stop-color%3D%22%230a0f1c%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23060912%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20x%3D%22-32%22%20y%3D%22-32%22%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2215%22%20fill%3D%22url(%23bg)%22%2F%3E%3Cg%20transform%3D%22scale(1.22)%22%3E%0A%3Ccircle%20r%3D%2221%22%20fill%3D%22url(%23glow)%22%2F%3E%0A%3Ccircle%20r%3D%2218%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224%22%20opacity%3D%22.38%22%2F%3E%0A%3Cpath%20d%3D%22M0%2C-18%20A18%2C18%200%200%2C1%2017.4%2C4.6%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224.4%22%20stroke-linecap%3D%22round%22%2F%3E%0A%3Cpath%20d%3D%22M-9.5%2C-7%20L0%2C10%20L9.5%2C-7%22%20fill%3D%22none%22%20stroke%3D%22%23fff%22%20stroke-width%3D%224.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%0A%3Ccircle%20cx%3D%2217.4%22%20cy%3D%224.6%22%20r%3D%223.2%22%20fill%3D%22%23ffffff%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">
@@ -16,15 +16,15 @@
@@ -16,15 +16,15 @@
<meta property="og:type" content="website">
<meta property="og:type" content="website">
<meta property="og:site_name" content="realtime.openvibe.network">
<meta property="og:site_name" content="realtime.openvibe.network">
<meta property="og:url" content="https://realtime.openvibe.network/">
<meta property="og:url" content="https://realtime.openvibe.network/">
-<meta property="og:title" content="realtime.openvibe.network — Authorized live updates, resumable.">
-<meta property="og:description" content="realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.">
+<meta property="og:title" content="realtime.openvibe.network — Closed: realtime delivery is part of OpenVibe.Events.">
+<meta property="og:description" content="OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.">
<meta property="og:image" content="https://openvibe.network/assets/logo-512.png">
<meta property="og:image" content="https://openvibe.network/assets/logo-512.png">
<meta property="og:image:alt" content="OpenVibe">
<meta property="og:image:alt" content="OpenVibe">
<meta name="twitter:card" content="summary">
<meta name="twitter:card" content="summary">
-<meta name="twitter:title" content="realtime.openvibe.network — Authorized live updates, resumable.">
-<meta name="twitter:description" content="realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.">
+<meta name="twitter:title" content="realtime.openvibe.network — Closed: realtime delivery is part of OpenVibe.Events.">
+<meta name="twitter:description" content="OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.">
<meta name="twitter:image" content="https://openvibe.network/assets/logo-512.png">
<meta name="twitter:image" content="https://openvibe.network/assets/logo-512.png">
-<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://realtime.openvibe.network/#site","url":"https://realtime.openvibe.network/","name":"realtime.openvibe.network","description":"realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.","inLanguage":"en","publisher":{"@type":"Organization","@id":"https://openvibe.network/#org","name":"OpenVibe","url":"https://openvibe.network/","logo":"https://openvibe.network/assets/logo-512.png","sameAs":["https://github.com/OpenVibers","https://discord.gg/M6MuRUaeJj"]},"isPartOf":{"@type":"WebSite","@id":"https://openvibe.network/#site","name":"OpenVibe.Network","url":"https://openvibe.network/"}},{"@type":"WebPage","@id":"https://realtime.openvibe.network/#page","url":"https://realtime.openvibe.network/","name":"realtime.openvibe.network — Authorized live updates, resumable.","description":"realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.","isPartOf":{"@id":"https://realtime.openvibe.network/#site"},"datePublished":"2026-09-17","dateModified":"2026-09-24","breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"OpenVibe","item":"https://openvibe.network/"},{"@type":"ListItem","position":2,"name":"realtime.openvibe.network","item":"https://realtime.openvibe.network/"}]}}]}</script>
+<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://realtime.openvibe.network/#site","url":"https://realtime.openvibe.network/","name":"realtime.openvibe.network","description":"OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.","inLanguage":"en","publisher":{"@type":"Organization","@id":"https://openvibe.network/#org","name":"OpenVibe","url":"https://openvibe.network/","logo":"https://openvibe.network/assets/logo-512.png","sameAs":["https://github.com/OpenVibers","https://discord.gg/M6MuRUaeJj"]},"isPartOf":{"@type":"WebSite","@id":"https://openvibe.network/#site","name":"OpenVibe.Network","url":"https://openvibe.network/"}},{"@type":"WebPage","@id":"https://realtime.openvibe.network/#page","url":"https://realtime.openvibe.network/","name":"realtime.openvibe.network — Closed: realtime delivery is part of OpenVibe.Events.","description":"OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.","isPartOf":{"@id":"https://realtime.openvibe.network/#site"},"datePublished":"2026-09-17","dateModified":"2026-09-24","breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"OpenVibe","item":"https://openvibe.network/"},{"@type":"ListItem","position":2,"name":"realtime.openvibe.network","item":"https://realtime.openvibe.network/"}]}}]}</script>
<script>(function(){try{var raw=localStorage.getItem('ov_theme');if(!raw)return;var t=JSON.parse(raw),v=t&&t.variables;if(!v)return;var el=document.documentElement;for(var k in v)if(k.charAt(0)==='-')el.style.setProperty(k,v[k]);if(t.id)el.setAttribute('data-theme',t.id);}catch(_){}})();</script>
<script>(function(){try{var raw=localStorage.getItem('ov_theme');if(!raw)return;var t=JSON.parse(raw),v=t&&t.variables;if(!v)return;var el=document.documentElement;for(var k in v)if(k.charAt(0)==='-')el.style.setProperty(k,v[k]);if(t.id)el.setAttribute('data-theme',t.id);}catch(_){}})();</script>
<script src="https://openvibe.network/shared/theme-loader.js" defer></script>
<script src="https://openvibe.network/shared/theme-loader.js" defer></script>
<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>
<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>
@@ -94,32 +94,23 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -94,32 +94,23 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<div class="mark"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div>
<div class="mark"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div>
<div class="badge"><span class="ov-mark" data-size="16" data-variant="realtime"></span> Part of the OpenVibe network · <b>closed</b></div>
<div class="badge"><span class="ov-mark" data-size="16" data-variant="realtime"></span> Part of the OpenVibe network · <b>closed</b></div>
<h1><span class="d">realtime</span><span class="tld">.openvibe.network</span></h1>
<h1><span class="d">realtime</span><span class="tld">.openvibe.network</span></h1>
- <div class="tag">Authorized live updates, resumable.</div>
- <p class="lead">realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.</p>
+ <div class="tag">Closed: realtime delivery is part of OpenVibe.Events.</div>
+ <p class="lead">OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.</p>
<div class="ctas">
<div class="ctas">
- <a class="btn btn-primary" href="https://openvibe.network/login?return=https%3A%2F%2Frealtime.openvibe.network%2F"><i class="fa-solid fa-right-to-bracket"></i> Sign in with OpenVibe</a>
+ <a class="btn btn-primary" href="https://events.openvibe.network/"><i class="fa-solid fa-arrow-right"></i> OpenVibe.Events</a>
<a class="btn" href="https://openvibe.network/#network"><i class="fa-solid fa-circle-nodes"></i> The whole network</a>
<a class="btn" href="https://openvibe.network/#network"><i class="fa-solid fa-circle-nodes"></i> The whole network</a>
<a class="btn" href="https://discord.gg/M6MuRUaeJj" rel="noopener"><i class="fa-brands fa-discord"></i> Follow the build</a>
<a class="btn" href="https://discord.gg/M6MuRUaeJj" rel="noopener"><i class="fa-brands fa-discord"></i> Follow the build</a>
</div>
</div>
- <p class="status"><i class="fa-solid fa-clock" aria-hidden="true"></i> Status: <b>closed</b> · <a href="https://github.com/OpenVibers/OpenVibe.Realtime" rel="noopener"><code>OpenVibers/OpenVibe.Realtime</code></a> is closed, so no product launches here; this page is a placeholder. · as of 2026-09-24 · <a href="/status.json">status.json</a></p>
+ <p class="status"><i class="fa-solid fa-clock" aria-hidden="true"></i> Status: <b>closed</b> · <a href="https://github.com/OpenVibers/OpenVibe.Realtime" rel="noopener"><code>OpenVibers/OpenVibe.Realtime</code></a> is closed and stays as a decision record; no product launches at this address. · as of 2026-09-24 · <a href="/status.json">status.json</a></p>
</header>
</header>
- <section id="what">
- <h2>What realtime.openvibe.network will be</h2>
- <p class="lead2">Same account, same themes, same navbar as every other OpenVibe site — built in the open, run by its community.</p>
+ <section id="what" class="meanwhile">
+ <h2>Where to go</h2>
+ <p class="lead2">Realtime delivery for browsers is a part of OpenVibe.Events; the decision and its record are public.</p>
<div class="grid">
<div class="grid">
- <div class="card"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Topics</b><span>Subscribe to exactly the streams your account may see.</span></div>
- <div class="card"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Resume</b><span>Reconnect from a cursor and get what you missed.</span></div>
- <div class="card"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Presence</b><span>Who is here, without polling.</span></div>
- <div class="card"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Not media</b><span>Video and audio keep their own transports.</span></div>
- </div>
- </section>
-
- <section class="meanwhile">
- <h2>Meanwhile, on the network</h2>
- <p class="lead2">Most of this already exists somewhere on OpenVibe — start there today.</p>
- <div class="grid">
- <a class="card" href="https://openvibe.live"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>Chat and stream updates</b><span>Realtime today runs inside OpenVibe.Live.</span><span class="go">openvibe.live →</span></a>
+ <a class="card" href="https://events.openvibe.network/"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>OpenVibe.Events</b><span>Durable events, subscriptions and signed delivery; browsers subscribe at /realtime/stream.</span><span class="go">events.openvibe.network →</span></a>
+ <a class="card" href="https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-005-realtime.md"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>ADR-005: realtime</b><span>The decision, and when a separate realtime service would be reconsidered.</span><span class="go">github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-005-realtime.md →</span></a>
+ <a class="card" href="https://github.com/OpenVibers/OpenVibe.Realtime"><div class="ic"><i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i></div><b>OpenVibe.Realtime</b><span>The repository stays as the decision record.</span><span class="go">github.com/OpenVibers/OpenVibe.Realtime →</span></a>
</div>
</div>
</section>
</section>
@@ -253,7 +244,7 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -253,7 +244,7 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/footer.js"></script>
<script>
<script>
(function () {
(function () {
- if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: 'realtime', apiBase: 'https://openvibe.network', links: [{ label: 'What it will be', href: '#what' }, { label: 'The network', href: 'https://openvibe.network/#network', external: false }], history: { type: 'page', title: 'realtime.openvibe.network' } }); } catch (e) {} }
+ if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: 'realtime', apiBase: 'https://openvibe.network', links: [{ label: 'Where to go', href: '#what' }, { label: 'The network', href: 'https://openvibe.network/#network', external: false }], history: { type: 'page', title: 'realtime.openvibe.network' } }); } catch (e) {} }
if (window.OpenVibeFooter) { try { OpenVibeFooter.init({ service: 'realtime', variant: 'full', links: [{ heading: 'realtime.openvibe.network', items: [{ name: 'Sign in', url: 'https://openvibe.network/login?return=https%3A%2F%2Frealtime.openvibe.network%2F' }, { name: 'The network', url: 'https://openvibe.network/#network' }, { name: 'Discord', url: 'https://discord.gg/M6MuRUaeJj' }] }] }); } catch (e) {} }
if (window.OpenVibeFooter) { try { OpenVibeFooter.init({ service: 'realtime', variant: 'full', links: [{ heading: 'realtime.openvibe.network', items: [{ name: 'Sign in', url: 'https://openvibe.network/login?return=https%3A%2F%2Frealtime.openvibe.network%2F' }, { name: 'The network', url: 'https://openvibe.network/#network' }, { name: 'Discord', url: 'https://discord.gg/M6MuRUaeJj' }] }] }); } catch (e) {} }
})();
})();
</script>
</script>
@@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
{
{
"name": "realtime.openvibe.network",
"name": "realtime.openvibe.network",
"short_name": "network",
"short_name": "network",
- "description": "Authorized live updates, resumable.",
+ "description": "Closed: realtime delivery is part of OpenVibe.Events.",
"start_url": "/",
"start_url": "/",
"scope": "/",
"scope": "/",
"display": "standalone",
"display": "standalone",
@@ -1,4 +1,3 @@
@@ -1,4 +1,3 @@
User-agent: *
User-agent: *
Allow: /
Allow: /
Disallow: /auth/
Disallow: /auth/
-Sitemap: https://realtime.openvibe.network/sitemap.xml
deleted file mode 100644
deleted file mode 100644
@@ -1,4 +0,0 @@
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
- <url><loc>https://realtime.openvibe.network/</loc><lastmod>2026-09-24</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>
-</urlset>
@@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
{
{
"domain": "realtime.openvibe.network",
"domain": "realtime.openvibe.network",
"name": "realtime.openvibe.network",
"name": "realtime.openvibe.network",
- "stage": "placeholder",
+ "stage": "closed",
"live": false,
"live": false,
"plannedRepo": "OpenVibers/OpenVibe.Realtime",
"plannedRepo": "OpenVibers/OpenVibe.Realtime",
"repoUrl": "https://github.com/OpenVibers/OpenVibe.Realtime",
"repoUrl": "https://github.com/OpenVibers/OpenVibe.Realtime",
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
@@ -149,7 +149,6 @@ a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);bo
<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a>
<a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
<a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
- <a href="https://realtime.openvibe.network/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>realtime.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
<a href="https://ai.openvibe.network/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.network</a>
</div>
</div>
</section>
</section>
@@ -627,39 +627,33 @@
@@ -627,39 +627,33 @@
"openvibe.network"
"openvibe.network"
],
],
"tld": "realtime",
"tld": "realtime",
+ "kind": "closed",
"name": "realtime.openvibe.network",
"name": "realtime.openvibe.network",
"icon": "fa-satellite-dish",
"icon": "fa-satellite-dish",
"accent": "#34d399",
"accent": "#34d399",
"plannedRepo": "OpenVibe.Realtime",
"plannedRepo": "OpenVibe.Realtime",
"legalProfile": "info",
"legalProfile": "info",
- "tagline": "Authorized live updates, resumable.",
- "description": "realtime.openvibe.network will be the browser delivery plane for events: WebSocket and SSE subscriptions with cursors, presence and gap recovery, separate from the durable event store.",
- "pillars": [
+ "tagline": "Closed: realtime delivery is part of OpenVibe.Events.",
+ "description": "OpenVibe.Realtime was planned as a separate service for live updates in the browser. Decision record ADR-005 (accepted 2026-09-22) closed it: browser realtime is part of OpenVibe.Events, as server-sent events with cursor resume at events.openvibe.network/realtime/stream. This address serves only this notice.",
+ "linksLead": "Realtime delivery for browsers is a part of OpenVibe.Events; the decision and its record are public.",
+ "links": [
[
[
- "Topics",
- "Subscribe to exactly the streams your account may see."
+ "OpenVibe.Events",
+ "https://events.openvibe.network/",
+ "Durable events, subscriptions and signed delivery; browsers subscribe at /realtime/stream."
],
],
[
[
- "Resume",
- "Reconnect from a cursor and get what you missed."
+ "ADR-005: realtime",
+ "https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-005-realtime.md",
+ "The decision, and when a separate realtime service would be reconsidered."
],
],
[
[
- "Presence",
- "Who is here, without polling."
- ],
- [
- "Not media",
- "Video and audio keep their own transports."
- ]
- ],
- "meanwhile": [
- [
- "Chat and stream updates",
- "https://openvibe.live",
- "Realtime today runs inside OpenVibe.Live."
+ "OpenVibe.Realtime",
+ "https://github.com/OpenVibers/OpenVibe.Realtime",
+ "The repository stays as the decision record."
]
]
],
],
- "keywords": "openvibe realtime, openvibe network realtime, openvibe platform"
+ "keywords": "openvibe realtime, openvibe events, server-sent events"
},
},
{
{
"domain": "ai.openvibe.network",
"domain": "ai.openvibe.network",
@@ -26,15 +26,30 @@ for (const site of catalog.sites) {
@@ -26,15 +26,30 @@ for (const site of catalog.sites) {
pages++;
pages++;
assert.match(html, /<title>[^<]+<\/title>/, `${d}: title`);
assert.match(html, /<title>[^<]+<\/title>/, `${d}: title`);
assert.match(html, new RegExp(`<link rel="canonical" href="https://${d.replace(/\./g, '\\.')}/?"`), `${d}: canonical`);
assert.match(html, new RegExp(`<link rel="canonical" href="https://${d.replace(/\./g, '\\.')}/?"`), `${d}: canonical`);
- assert.match(html, /placeholder/i, `${d}: says it is a placeholder (never claim a product is live)`);
+ if (!site.kind) assert.match(html, /placeholder/i, `${d}: says it is a placeholder (never claim a product is live)`);
assert.doesNotMatch(html, PRICING, `${d}: pricing copy`);
assert.doesNotMatch(html, PRICING, `${d}: pricing copy`);
assert.doesNotMatch(html, UNBACKED, `${d}: claims a hosting product that does not exist`);
assert.doesNotMatch(html, UNBACKED, `${d}: claims a hosting product that does not exist`);
for (const m of html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)) {
for (const m of html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)) {
assert.doesNotThrow(() => JSON.parse(m[1]), `${d}: JSON-LD parses`);
assert.doesNotThrow(() => JSON.parse(m[1]), `${d}: JSON-LD parses`);
}
}
- for (const f of ['robots.txt', 'sitemap.xml', 'manifest.webmanifest']) {
+ for (const f of ['robots.txt', 'manifest.webmanifest', 'status.json', ...(site.kind ? [] : ['sitemap.xml'])]) {
assert.ok(fs.existsSync(path.join(ROOT, 'dist', d, f)), `${d}: ${f}`);
assert.ok(fs.existsSync(path.join(ROOT, 'dist', d, f)), `${d}: ${f}`);
}
}
+ if (site.kind) {
+ // A notice (a closed product, a pointer) is not indexed, has no sitemap and is not listed as opening.
+ assert.match(html, /<meta name="robots" content="noindex, follow">/, `${d}: notice is noindex`);
+ assert.ok(!fs.existsSync(path.join(ROOT, 'dist', d, 'sitemap.xml')), `${d}: notice has no sitemap`);
+ assert.doesNotMatch(read(`dist/${d}/robots.txt`), /Sitemap:/, `${d}: robots.txt names no sitemap`);
+ assert.ok(Array.isArray(site.links) && site.links.length, `${d}: notice links where to go`);
+ for (const [, href] of site.links) assert.ok(html.includes(`href="${href}"`), `${d}: links ${href}`);
+ for (const other of catalog.sites) {
+ if (other.domain !== d) assert.ok(!read(`dist/${other.domain}/index.html`).includes(`href="https://${d}/"`), `${other.domain}: does not list the ${site.kind} ${d} as a domain still to open`);
+ }
+ }
+ if (site.kind === 'closed') {
+ assert.match(html, /Status: <b>closed<\/b>/, `${d}: says closed`);
+ assert.doesNotMatch(html, /will be|opening soon|coming soon/i, `${d}: a closed product is never described as coming`);
+ }
const conf = read(`deploy/nginx/${d}.conf`);
const conf = read(`deploy/nginx/${d}.conf`);
assert.ok(conf.includes(`server_name ${d}`), `${d}: vhost server_name`);
assert.ok(conf.includes(`server_name ${d}`), `${d}: vhost server_name`);
assert.ok(conf.includes(`root /opt/openvibe.sites/dist/${d};`), `${d}: vhost root`);
assert.ok(conf.includes(`root /opt/openvibe.sites/dist/${d};`), `${d}: vhost root`);
@@ -53,6 +68,7 @@ for (const site of catalog.sites) {
@@ -53,6 +68,7 @@ for (const site of catalog.sites) {
const html = read(`dist/${d}/index.html`);
const html = read(`dist/${d}/index.html`);
const status = JSON.parse(read(`dist/${d}/status.json`));
const status = JSON.parse(read(`dist/${d}/status.json`));
const st = f.status || {}; const rg = f.registry || {};
const st = f.status || {}; const rg = f.registry || {};
+ if (st.stage === 'closed') assert.strictEqual(site.kind, 'closed', `${d}: ${site.plannedRepo} is closed (STATUS.json), so its page is a closed notice, not a placeholder`);
const hasCode = st.code === true || ['live', 'internal'].includes(rg.state);
const hasCode = st.code === true || ['live', 'internal'].includes(rg.state);
if (hasCode) {
if (hasCode) {
assert.doesNotMatch(html, NO_CODE, `${d}: ${site.plannedRepo} has code, so the page never says "charter only, no code yet"`);
assert.doesNotMatch(html, NO_CODE, `${d}: ${site.plannedRepo} has code, so the page never says "charter only, no code yet"`);