openvibers/openvibe.network Commits

Network: the product at openre.stream is OpenRestream (owner, 2026-10-09) (#108)

OP OpenVibers committed 9 Oct 2026 · a29e20dc93 · 8 files, +21 −17

Every name people read says OpenRestream instead of OpenRe or OpenRe.Stream, and repository paths say
OpenVibers/OpenRestream (renamed on GitHub the same day). Ids are unchanged (openre, openre.*, ov_openre).

Network: the openre OAuth client is OpenRestream on the sign-in page; the seed renames a client still carrying a former
name (FORMER_NAMES), so production's row follows on the next boot. The history, updates and home names follow.

Changes

ddiff --git a/docs/platform-plan.md b/docs/platform-plan.md
iindex 91a22ec7..3041ee08 100644
---- a/docs/platform-plan.md
++++ b/docs/platform-plan.md
@@@ -66,7 +66,7 @@ helpers.
## 4. What the two old plans got right, and what changed
Kept from the *domain map*: the split between identity (network) and rooms; one job per domain;
--Community as the home of pastes/posts/comments; OpenRe.Stream as the ingest/restream layer
++Community as the home of pastes/posts/comments; OpenRestream as the ingest/restream layer
behind Live; Chat as the communication layer; content rooms (news/reviews/deals/coupons/trade)
being source-backed and honest. Kept from the *runtime prompt*: capability-style shared
contracts, real tests over route-existence, readiness that says yellow when it is yellow.
@@@ -83,7 +83,7 @@ cookies and CORS and buys nothing at this size. `my.openvibe.network` already re
1. **Community phase 2** — spaces, threads, posts, comments as reusable primitives
(`/api/comments?target=live:vod:123`) used by Live VOD/clip pages, Media, Blog and Wiki.
Discord relay tagging. Moderation shared with Live's tools.
--2. **OpenRe.Stream** — move the restream engine's *config UI and status API* to the domain
++2. **OpenRestream** — move the restream engine's *config UI and status API* to the domain
(Live keeps the ingest processes); a public "what's live where" status page.
3. **Chat** — `openvibe.chat` embeds Live's chat server with rooms not bound to a stream
(global rooms, DMs) and the voice channels; Live embeds it back. One `/ws/chat`, one moderation.
ddiff --git a/server/db/database.js b/server/db/database.js
iindex 5d34d8d4..fb14aad3 100644
---- a/server/db/database.js
++++ b/server/db/database.js
@@@ -75,6 +75,10 @@ async function setDb(db) { database = db; await attachHelpers(db); }
* concurrent writers: every write is an upsert, and the redirect-URI merge takes the row with
* SELECT … FOR UPDATE inside a transaction (decision 1).
*/
++// A site's former display names: the seed renames a client still carrying one. The product at openre.stream is
++// OpenRestream (owner, 2026-10-09), never "OpenRe.Stream".
++const FORMER_NAMES = { openre: ['OpenRe.Stream', 'OpenRe'] };
++
async function seedDb(db, { log = console } = {}) {
const warn = (m) => log.warn(`[DB] ${m}`);
@@@ -95,7 +99,7 @@ async function seedDb(db, { log = console } = {}) {
{ client_id: 'vip', name: 'OpenVibe.VIP', redirect_uris: ['https://openvibe.vip/auth/callback'] },
{ client_id: 'wiki', name: 'OpenVibe.Wiki', redirect_uris: ['https://openvibe.wiki/auth/callback'] },
{ client_id: 'blog', name: 'OpenVibe.Blog', redirect_uris: ['https://openvibe.blog/auth/callback'] },
-- { client_id: 'openre', name: 'OpenRe.Stream', redirect_uris: ['https://openre.stream/auth/callback'] },
++ { client_id: 'openre', name: 'OpenRestream', redirect_uris: ['https://openre.stream/auth/callback'] },
{ client_id: 'reviews', name: 'OpenVibe.Reviews', redirect_uris: ['https://openvibe.reviews/auth/callback'] },
{ client_id: 'news', name: 'OpenVibe.News', redirect_uris: ['https://openvibe.news/auth/callback'] },
{ client_id: 'trade', name: 'OpenVibe.Trade', redirect_uris: ['https://openvibe.trade/auth/callback'] },
@@@ -136,8 +140,8 @@ async function seedDb(db, { log = console } = {}) {
await mergeRedirectUris(db, c.client_id, c.redirect_uris, { log });
// A client created first as a service principal carries the placeholder name "OpenVibe.<id> (service)",
// which the sign-in page shows people ("Sign in to OpenVibe.food (service)"). Give it the site's name; a
-- // name someone chose stays.
-- if (existing.name === `OpenVibe.${c.client_id} (service)`) {
++ // name someone chose stays. A site's own former name is renamed too (FORMER_NAMES).
++ if (existing.name === `OpenVibe.${c.client_id} (service)` || (FORMER_NAMES[c.client_id] || []).includes(existing.name)) {
await db.prepare('UPDATE oauth_clients SET name = ? WHERE client_id = ?').run(c.name, c.client_id);
log.log(`[DB] OAuth2 client ${c.client_id} renamed to ${c.name}`);
}
ddiff --git a/server/frame/sites.js b/server/frame/sites.js
iindex f94309ea..504dca26 100644
---- a/server/frame/sites.js
++++ b/server/frame/sites.js
@@@ -12,7 +12,7 @@ const { exposureOf } = require('../registry/exposure');
// (state: internal = runs on loopback only, placeholder = planned). The two lists cannot disagree.
// Since openvibe-contracts 0.42.0 (WS-C task 1) the list is the manifests' `site` blocks, in `position` order:
// name, icon, tagline, what, the legal profile, and a host only while the manifest has no publicOrigin. A
--// site's id is its icon name (live, tools, …, stream for OpenRe.Stream).
++// site's id is its icon name (live, tools, …, stream for OpenRestream).
const RAW_SITES = contracts.services.manifests.filter((m) => m.site).sort((a, b) => (a.site.position ?? 999) - (b.site.position ?? 999)).map((m) => ({
id: m.site.icon, name: m.site.name, icon: m.site.icon, service: m.id, profile: m.site.legalProfile, tagline: m.site.tagline, what: m.site.what,
...(m.site.host ? { host: m.site.host } : {}),
ddiff --git a/server/history/routes.js b/server/history/routes.js
iindex 61033483..8c8a6d47 100644
---- a/server/history/routes.js
++++ b/server/history/routes.js
@@@ -18,7 +18,7 @@ const TYPES = new Set(['tool', 'stream', 'vod', 'clip', 'paste', 'game', 'page',
const SERVICE_LABELS = {
live: 'Live', tools: 'Tools', games: 'Games', media: 'Media', network: 'Network', community: 'Community', space: 'Space',
chat: 'Chat', codes: 'Codes', blog: 'Blog', wiki: 'Wiki', news: 'News', reviews: 'Reviews', tips: 'Tips',
-- vip: 'VIP', trade: 'Trade', host: 'Host', deals: 'Deals', coupons: 'Coupons', openre: 'OpenRe.Stream',
++ vip: 'VIP', trade: 'Trade', host: 'Host', deals: 'Deals', coupons: 'Coupons', openre: 'OpenRestream',
};
async function ensureSchema(db) { /* the schema is migrations/NNNN_*.sql (plan T2); nothing is created at runtime */ }
ddiff --git a/server/home/render.js b/server/home/render.js
iindex 76f27d2b..22285ed5 100644
---- a/server/home/render.js
++++ b/server/home/render.js
@@@ -64,7 +64,7 @@ function intents(catalog) {
}
// The network as a constellation: open sites on the inner ring, the ones opening next faint on the outer ring.
--const SHORT = (site) => (/^OpenRe\./.test(site.name) ? 'OpenRe' : site.name.replace(/^OpenVibe\./, ''));
++const SHORT = (site) => site.name.replace(/^OpenVibe\./, '');
function constellation() {
const ring = (list, r, start) => list.map((site, i) => {
const a = start + (i / list.length) * Math.PI * 2;
ddiff --git a/server/identity/principals.js b/server/identity/principals.js
iindex f6f6a36d..65a3a5a0 100644
---- a/server/identity/principals.js
++++ b/server/identity/principals.js
@@@ -78,8 +78,8 @@ const DEFAULT_GRANTS = [
['host', 'media.object.read', 'openvibe.media', ['host', 'host.*']],
['host', 'media.object.list', 'openvibe.media', ['host', 'host.*']],
['host', 'media.object.delete', 'openvibe.media', ['host', 'host.*']],
-- // Plan T4 (Media cleanup): Live and OpenRe reach Media with their own tokens instead of API keys. Live keeps
-- // its objects under the live namespace (VOD/clip/thumbnail uploads, reads, lists, deletes); OpenRe uploads the
++ // Plan T4 (Media cleanup): Live and OpenRestream reach Media with their own tokens instead of API keys. Live keeps
++ // its objects under the live namespace (VOD/clip/thumbnail uploads, reads, lists, deletes); OpenRestream uploads the
// recordings and thumbnails it produces there too.
...['media.object.read', 'media.object.list', 'media.object.upload', 'media.object.delete'].map(cap => ['live', cap, 'openvibe.media', ['live']]),
['openre', 'media.object.upload', 'openvibe.media', ['live']],
@@@ -118,7 +118,7 @@ const DEFAULT_GRANTS = [
['tips', 'chat.message.send', 'openvibe.chat', []],
['tips', 'chat.event.publish', 'openvibe.chat', []],
['live', 'tips.interaction.record', 'openvibe.tips', []],
-- // Wave 7: Live manages its slots' streams, keys and sessions on OpenRe.Stream; OpenRe publishes
++ // Wave 7: Live manages its slots' streams, keys and sessions on OpenRestream; OpenRestream publishes
// session/output events (Live consumes openre.session.* by webhook).
...['openre.stream.read', 'openre.stream.write', 'openre.key.rotate', 'openre.session.read'].map(c => ['live', c, 'openvibe.openre', []]),
['openre', 'events.event.publish', 'openvibe.events', []],
@@@ -194,7 +194,7 @@ const DEFAULT_GRANTS = [
['bot', 'network.node.manage', SELF_AUDIENCE, []],
// Plan T15: an owner adds an operator by @username on the robot's panel; Bot resolves it to the subject here.
['bot', 'identity.subject.resolve', SELF_AUDIENCE, []],
-- // Plan T15: Bot runs each robot's OpenRe stream for its owner (find/create/archive, key rotation), plays the live
++ // Plan T15: Bot runs each robot's OpenRestream stream for its owner (find/create/archive, key rotation), plays the live
// session in the panel (session.read), restreams out (output.*) and sets the owner's streaming and recording
// toggles on the stream, minting its own token with its Network client instead of a hand-set BOT_OPENRE_TOKEN.
...['openre.stream.read', 'openre.stream.write', 'openre.key.rotate', 'openre.session.read', 'openre.output.read', 'openre.output.write'].map(c => ['bot', c, 'openvibe.openre', []]),
@@@ -273,7 +273,7 @@ const DEFAULT_GRANTS = [
['live', 'community.paste.create', 'openvibe.community', []],
['live', 'community.paste.write', 'openvibe.community', []],
['live', 'community.paste.moderate', 'openvibe.community', []],
-- // One canonical channel/owner resolver (roadmap §10.5/§15.10, D20-R1): OpenRe, Media and Community (Pulse)
++ // One canonical channel/owner resolver (roadmap §10.5/§15.10, D20-R1): OpenRestream, Media and Community (Pulse)
// resolve channels, streams, VODs and clips through Live's /internal/lineage/resolve instead of their own
// channel mappings.
...['openre', 'media', 'community'].map(c => [c, 'live.lineage.resolve', 'openvibe.live', []]),
ddiff --git a/server/updates/routes.js b/server/updates/routes.js
iindex ef5b1d3c..20fd3cb9 100644
---- a/server/updates/routes.js
++++ b/server/updates/routes.js
@@@ -70,7 +70,7 @@ function createUpdatesRoutes({ blogUrl = 'http://127.0.0.1:4810', fetchImpl = gl
}
const SITES = ['live', 'network', 'tools', 'media', 'community', 'space', 'chat', 'games', 'blog', 'wiki', 'news', 'reviews', 'deals', 'coupons', 'trade', 'codes', 'services', 'host', 'ai', 'search', 'sources', 'events', 'billing', 'tips', 'vip', 'openre', 'bot', 'actor', 'food', 'help', 'work', 'quest', 'rent', 'watch', 'media-hub', 'inventory', 'sites'];
--const NAMES = { ai: 'AI', vip: 'VIP', openre: 'OpenRe' };
++const NAMES = { ai: 'AI', vip: 'VIP', openre: 'OpenRestream' };
const nameOf = (id) => NAMES[id] || (id ? id.charAt(0).toUpperCase() + id.slice(1) : '');
/** A registry id from an id or a hostname (openvibe.wiki → wiki, pdf.openvibe.tools → tools). */
ddiff --git a/test/principals.test.js b/test/principals.test.js
iindex 12a14b0c..973b0524 100644
---- a/test/principals.test.js
++++ b/test/principals.test.js
@@@ -95,7 +95,7 @@ const server = http.createServer(app);
await db.prepare("UPDATE oauth_clients SET client_secret = 'openre-secret' WHERE client_id = 'openre'").run();
t = await token({ client_id: 'openre', client_secret: 'openre-secret', audience: 'openvibe.network' });
assert.strictEqual(t.status, 400); assert.strictEqual(t.body.error, 'invalid_scope', 'a client with no grants gets no token');
-- // The canonical channel/owner resolver on Live (D20-R1): OpenRe, Media and Community hold it, nobody else.
++ // The canonical channel/owner resolver on Live (D20-R1): OpenRestream, Media and Community hold it, nobody else.
await db.prepare("UPDATE oauth_clients SET client_secret = 'community-secret' WHERE client_id = 'community'").run();
for (const [client, secret] of [['openre', 'openre-secret'], ['media', 'media-secret'], ['community', 'community-secret']]) {
t = await token({ client_id: client, client_secret: secret, audience: 'openvibe.live' });
@@@ -212,14 +212,14 @@ const server = http.createServer(app);
assert.strictEqual(ub.status, 200, `${client}: ${JSON.stringify(ub.body)}`);
assert.strictEqual(ub.body.scope, 'billing.usage.record', `${client} records usage on Billing and holds no money capability`);
}
-- // Plan T15: Bot mints its own OpenRe token for the robots' streams, sessions, outputs and toggles; nothing beyond OpenRe's
++ // Plan T15: Bot mints its own OpenRestream token for the robots' streams, sessions, outputs and toggles; nothing beyond OpenRestream's
// stream, key, session-read and output capabilities (never openre.session.end).
const bn = await token({ client_id: 'bot', client_secret: 'bot-secret', audience: 'openvibe.network', scope: 'identity.subject.resolve' });
assert.strictEqual(bn.status, 200, JSON.stringify(bn.body));
assert.strictEqual(bn.body.scope, 'identity.subject.resolve', 'Bot resolves an operator\'s @username');
const bo = await token({ client_id: 'bot', client_secret: 'bot-secret', audience: 'openvibe.openre' });
assert.strictEqual(bo.status, 200, JSON.stringify(bo.body));
-- assert.deepStrictEqual(bo.body.scope.split(' ').sort(), ['openre.key.rotate', 'openre.output.read', 'openre.output.write', 'openre.session.read', 'openre.stream.read', 'openre.stream.write'], "Bot runs its robots' OpenRe streams");
++ assert.deepStrictEqual(bo.body.scope.split(' ').sort(), ['openre.key.rotate', 'openre.output.read', 'openre.output.write', 'openre.session.read', 'openre.stream.read', 'openre.stream.write'], "Bot runs its robots' OpenRestream streams");
// Coupons subscribes to its Events sources with its own token (OpenVibe.Coupons scripts/subscribe.js).
await db.prepare("UPDATE oauth_clients SET client_secret = 'coupons-secret' WHERE client_id = 'coupons'").run();
const cps = await token({ client_id: 'coupons', client_secret: 'coupons-secret', audience: 'openvibe.events', scope: 'events.subscription.manage' });