openvibers/openvibe.shared Commits
4.85.0: share cards for fourteen more sites (#239)
Changes
@@@ -4,6 +4,19 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semvebreaking change to any exported module, browser global or served file name is a new major.A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).++## 4.85.0 — 2026-11-01++++- **Share cards for fourteen more sites.**++ - Bench, Cam, Casino, Design, Domains, Exchange, Fun, Meme, Report, Surf, Today, Tours, Vision and Shoes had no++ `social/<service>.jpg`. A shared link to their homes showed no picture, because shell.page's og:image is++ `social.url(service)`.++ - Drawn by `scripts/build-social-cards.js --only …` from each manifest's `site` block (OpenVibe.Contracts main), the++ same way as every other card.++ - `icons/sites.json` names their app icons (`scripts/build-icons.js`): installable apps and the app-icons test++ need an entry for every site with a card.++ - The update log (`shipped.js`) knows the fourteen as sites, so each one's own feed is shown. A Services subdomain++ (`ai.`, `bench.openvibe.services`) and `open.shoes` resolve to their own site, the way Network's subdomains do.++## 4.84.0 — 2026-11-01- **A page with no stylesheet of its own reads in the network's type.**@@@ -2,7 +2,7 @@> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.--**Status:** alpha, v4.84.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed++**Status:** alpha, v4.85.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployedconsumer installs a tagged release and none keeps a vendored copy([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` namesthe tag it pins.@@@ -4,7 +4,7 @@"code": true,"wave": "W2","package": "openvibe-shared",-- "version": "4.84.0",++ "version": "4.85.0","plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)","deployed": false,"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",@@@ -9,6 +9,11 @@"description": "Many models, one API. Every answer explained.","icon": "ai"},++ "bench": {++ "name": "OpenVibe.Bench",++ "description": "One AI benchmark and comparison engine for every room.",++ "icon": "network"++ },"blog": {"name": "OpenVibe.Blog","description": "Long-form, yours to keep",@@@ -19,6 +24,16 @@"description": "Drive any robot from your browser","icon": "network"},++ "cam": {++ "name": "OpenVibe.Cam",++ "description": "Your camera, your cameras, and Live's cam button",++ "icon": "network"++ },++ "casino": {++ "name": "OpenVibe.Casino",++ "description": "Learn it, play it, never pay it",++ "icon": "network"++ },"chat": {"name": "OpenVibe.Chat","description": "Chat with Vibe, friends and groups",@@@ -44,16 +59,36 @@"description": "Deals worth sharing","icon": "network"},++ "design": {++ "name": "OpenVibe.Design",++ "description": "Make it yours",++ "icon": "network"++ },++ "domains": {++ "name": "OpenVibe.Domains",++ "description": "Name it, price it, run it",++ "icon": "network"++ },"events": {"name": "OpenVibe.Events","description": "Events your services can count on.","icon": "network"},++ "exchange": {++ "name": "OpenVibe.Exchange",++ "description": "Trade what people make",++ "icon": "network"++ },"food": {"name": "OpenVibe.Food","description": "What should we eat?","icon": "network"},++ "fun": {++ "name": "OpenVibe.Fun",++ "description": "Something to do, alone, together, or live",++ "icon": "network"++ },"games": {"name": "OpenVibe.Games","description": "Browser games, and games you make",@@@ -89,6 +124,11 @@"description": "Videos, pictures and your files","icon": "media"},++ "meme": {++ "name": "OpenVibe.Meme",++ "description": "The internet's meme database",++ "icon": "network"++ },"network": {"name": "OpenVibe.Network","description": "Account and themes",@@@ -119,6 +159,11 @@"description": "Every rental site, one search","icon": "network"},++ "report": {++ "name": "OpenVibe.Report",++ "description": "Every number on OpenVibe, honest",++ "icon": "network"++ },"reviews": {"name": "OpenVibe.Reviews","description": "Reviews with receipts",@@@ -139,21 +184,41 @@"description": "Build on OpenVibe","icon": "network"},++ "shoes": {++ "name": "OpenVibe.Shoes",++ "description": "Every shoe, every market, the right price",++ "icon": "network"++ },"space": {"name": "OpenVibe.Space","description": "Make a space: an app on your account","icon": "space"},++ "surf": {++ "name": "OpenVibe.Surf",++ "description": "Ride, browse, watch",++ "icon": "network"++ },"tips": {"name": "OpenVibe.Tips","description": "Tips, paid messages and alerts for any stream","icon": "network"},++ "today": {++ "name": "OpenVibe.Today",++ "description": "Everything happening for you, today",++ "icon": "network"++ },"tools": {"name": "OpenVibe.Tools","description": "Every online tool","icon": "tools"},++ "tours": {++ "name": "OpenVibe.Tours",++ "description": "Go anywhere: fly, stay, walk, watch",++ "icon": "network"++ },"trade": {"name": "OpenVibe.Trade","description": "Watchlists and alerts",@@@ -164,6 +229,11 @@"description": "Memberships for creators and their software","icon": "network"},++ "vision": {++ "name": "OpenVibe.Vision",++ "description": "See with the best model for the job",++ "icon": "network"++ },"watch": {"name": "OpenVibe.Watch","description": "Know the moment it changes",@@@ -1,6 +1,6 @@{"name": "openvibe-shared",-- "version": "4.84.0",++ "version": "4.85.0","description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site","main": "index.js","bin": {@@@ -45,6 +45,8 @@video: 'Video', pics: 'Pics', rent: 'Rent', homes: 'Homes', work: 'Work', food: 'Food', help: 'Help', quest: 'Quest',website: 'Website', fund: 'Fund', 'media-hub': 'Media Hub', extensions: 'Extensions', contracts: 'Contracts', sdk: 'SDK',shared: 'Shared', examples: 'Examples', publishing: 'Publishing', play: 'Play', inventory: 'Inventory',++ bench: 'Bench', cam: 'Cam', casino: 'Casino', design: 'Design', domains: 'Domains', exchange: 'Exchange', fun: 'Fun',++ meme: 'Meme', report: 'Report', surf: 'Surf', today: 'Today', tours: 'Tours', vision: 'Vision', shoes: 'Shoes',};const STYLE_ID = 'ov-shipped-style';const TEXT = 'var(--text-primary,var(--text,inherit))';@@@ -143,6 +145,12 @@const sub = h.replace(/\.?openvibe\.network$/, '');return SITE_NAMES[sub] && sub !== 'network' ? sub : 'network';}++ // The Services family lives on its subdomains (ai., bench.openvibe.services), like the Network's.++ if (/(^|\.)openvibe\.services$/.test(h)) {++ const sub = h.replace(/\.?openvibe\.services$/, '');++ return SITE_NAMES[sub] && sub !== 'services' ? sub : 'services';++ }++ if (/(^|\.)open\.shoes$/.test(h)) return 'shoes';const m = /(?:^|\.)openvibe\.([a-z]+)$/.exec(h);return m && SITE_NAMES[m[1]] ? m[1] : null;}nnew file mode 100644BBinary files /dev/null and b/social/bench.jpg differnnew file mode 100644BBinary files /dev/null and b/social/cam.jpg differnnew file mode 100644BBinary files /dev/null and b/social/casino.jpg differnnew file mode 100644BBinary files /dev/null and b/social/design.jpg differnnew file mode 100644BBinary files /dev/null and b/social/domains.jpg differnnew file mode 100644BBinary files /dev/null and b/social/exchange.jpg differnnew file mode 100644BBinary files /dev/null and b/social/fun.jpg differnnew file mode 100644BBinary files /dev/null and b/social/meme.jpg differnnew file mode 100644BBinary files /dev/null and b/social/report.jpg differnnew file mode 100644BBinary files /dev/null and b/social/shoes.jpg differnnew file mode 100644BBinary files /dev/null and b/social/surf.jpg differnnew file mode 100644BBinary files /dev/null and b/social/today.jpg differnnew file mode 100644BBinary files /dev/null and b/social/tours.jpg differnnew file mode 100644BBinary files /dev/null and b/social/vision.jpg differ@@@ -116,6 +116,10 @@ const data = {assert.strictEqual(sf('bot'), 'bot');assert.strictEqual(sf('www.openvibe.live'), 'live');assert.strictEqual(sf('example.com'), null);++ assert.strictEqual(sf('bench.openvibe.services'), 'bench', 'a Services subdomain is its own site');++ assert.strictEqual(sf('ai.openvibe.services'), 'ai');++ assert.strictEqual(sf('openvibe.services'), 'services');++ assert.strictEqual(sf('open.shoes'), 'shoes');assert.strictEqual(sf('live'), 'live');// Every site with a share card and app icon (icons/sites.json, from the Contracts site blocks) is a registry id, so its// own feed is the one shown: play.openvibe.network showed Network's changes while 'play' was missing (2026-10-15).
@@ -4,6 +4,19 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semve
@@ -4,6 +4,19 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semve
breaking change to any exported module, browser global or served file name is a new major.
breaking change to any exported module, browser global or served file name is a new major.
A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
+## 4.85.0 — 2026-11-01
+
+- **Share cards for fourteen more sites.**
+ - Bench, Cam, Casino, Design, Domains, Exchange, Fun, Meme, Report, Surf, Today, Tours, Vision and Shoes had no
+ `social/<service>.jpg`. A shared link to their homes showed no picture, because shell.page's og:image is
+ `social.url(service)`.
+ - Drawn by `scripts/build-social-cards.js --only …` from each manifest's `site` block (OpenVibe.Contracts main), the
+ same way as every other card.
+ - `icons/sites.json` names their app icons (`scripts/build-icons.js`): installable apps and the app-icons test
+ need an entry for every site with a card.
+ - The update log (`shipped.js`) knows the fourteen as sites, so each one's own feed is shown. A Services subdomain
+ (`ai.`, `bench.openvibe.services`) and `open.shoes` resolve to their own site, the way Network's subdomains do.
+
## 4.84.0 — 2026-11-01
## 4.84.0 — 2026-11-01
- **A page with no stylesheet of its own reads in the network's type.**
- **A page with no stylesheet of its own reads in the network's type.**
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.
> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.
-**Status:** alpha, v4.84.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
+**Status:** alpha, v4.85.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
consumer installs a tagged release and none keeps a vendored copy
consumer installs a tagged release and none keeps a vendored copy
([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` names
([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` names
the tag it pins.
the tag it pins.
@@ -4,7 +4,7 @@
@@ -4,7 +4,7 @@
"code": true,
"code": true,
"wave": "W2",
"wave": "W2",
"package": "openvibe-shared",
"package": "openvibe-shared",
- "version": "4.84.0",
+ "version": "4.85.0",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)",
"deployed": false,
"deployed": false,
"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",
"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",
@@ -9,6 +9,11 @@
@@ -9,6 +9,11 @@
"description": "Many models, one API. Every answer explained.",
"description": "Many models, one API. Every answer explained.",
"icon": "ai"
"icon": "ai"
},
},
+ "bench": {
+ "name": "OpenVibe.Bench",
+ "description": "One AI benchmark and comparison engine for every room.",
+ "icon": "network"
+ },
"blog": {
"blog": {
"name": "OpenVibe.Blog",
"name": "OpenVibe.Blog",
"description": "Long-form, yours to keep",
"description": "Long-form, yours to keep",
@@ -19,6 +24,16 @@
@@ -19,6 +24,16 @@
"description": "Drive any robot from your browser",
"description": "Drive any robot from your browser",
"icon": "network"
"icon": "network"
},
},
+ "cam": {
+ "name": "OpenVibe.Cam",
+ "description": "Your camera, your cameras, and Live's cam button",
+ "icon": "network"
+ },
+ "casino": {
+ "name": "OpenVibe.Casino",
+ "description": "Learn it, play it, never pay it",
+ "icon": "network"
+ },
"chat": {
"chat": {
"name": "OpenVibe.Chat",
"name": "OpenVibe.Chat",
"description": "Chat with Vibe, friends and groups",
"description": "Chat with Vibe, friends and groups",
@@ -44,16 +59,36 @@
@@ -44,16 +59,36 @@
"description": "Deals worth sharing",
"description": "Deals worth sharing",
"icon": "network"
"icon": "network"
},
},
+ "design": {
+ "name": "OpenVibe.Design",
+ "description": "Make it yours",
+ "icon": "network"
+ },
+ "domains": {
+ "name": "OpenVibe.Domains",
+ "description": "Name it, price it, run it",
+ "icon": "network"
+ },
"events": {
"events": {
"name": "OpenVibe.Events",
"name": "OpenVibe.Events",
"description": "Events your services can count on.",
"description": "Events your services can count on.",
"icon": "network"
"icon": "network"
},
},
+ "exchange": {
+ "name": "OpenVibe.Exchange",
+ "description": "Trade what people make",
+ "icon": "network"
+ },
"food": {
"food": {
"name": "OpenVibe.Food",
"name": "OpenVibe.Food",
"description": "What should we eat?",
"description": "What should we eat?",
"icon": "network"
"icon": "network"
},
},
+ "fun": {
+ "name": "OpenVibe.Fun",
+ "description": "Something to do, alone, together, or live",
+ "icon": "network"
+ },
"games": {
"games": {
"name": "OpenVibe.Games",
"name": "OpenVibe.Games",
"description": "Browser games, and games you make",
"description": "Browser games, and games you make",
@@ -89,6 +124,11 @@
@@ -89,6 +124,11 @@
"description": "Videos, pictures and your files",
"description": "Videos, pictures and your files",
"icon": "media"
"icon": "media"
},
},
+ "meme": {
+ "name": "OpenVibe.Meme",
+ "description": "The internet's meme database",
+ "icon": "network"
+ },
"network": {
"network": {
"name": "OpenVibe.Network",
"name": "OpenVibe.Network",
"description": "Account and themes",
"description": "Account and themes",
@@ -119,6 +159,11 @@
@@ -119,6 +159,11 @@
"description": "Every rental site, one search",
"description": "Every rental site, one search",
"icon": "network"
"icon": "network"
},
},
+ "report": {
+ "name": "OpenVibe.Report",
+ "description": "Every number on OpenVibe, honest",
+ "icon": "network"
+ },
"reviews": {
"reviews": {
"name": "OpenVibe.Reviews",
"name": "OpenVibe.Reviews",
"description": "Reviews with receipts",
"description": "Reviews with receipts",
@@ -139,21 +184,41 @@
@@ -139,21 +184,41 @@
"description": "Build on OpenVibe",
"description": "Build on OpenVibe",
"icon": "network"
"icon": "network"
},
},
+ "shoes": {
+ "name": "OpenVibe.Shoes",
+ "description": "Every shoe, every market, the right price",
+ "icon": "network"
+ },
"space": {
"space": {
"name": "OpenVibe.Space",
"name": "OpenVibe.Space",
"description": "Make a space: an app on your account",
"description": "Make a space: an app on your account",
"icon": "space"
"icon": "space"
},
},
+ "surf": {
+ "name": "OpenVibe.Surf",
+ "description": "Ride, browse, watch",
+ "icon": "network"
+ },
"tips": {
"tips": {
"name": "OpenVibe.Tips",
"name": "OpenVibe.Tips",
"description": "Tips, paid messages and alerts for any stream",
"description": "Tips, paid messages and alerts for any stream",
"icon": "network"
"icon": "network"
},
},
+ "today": {
+ "name": "OpenVibe.Today",
+ "description": "Everything happening for you, today",
+ "icon": "network"
+ },
"tools": {
"tools": {
"name": "OpenVibe.Tools",
"name": "OpenVibe.Tools",
"description": "Every online tool",
"description": "Every online tool",
"icon": "tools"
"icon": "tools"
},
},
+ "tours": {
+ "name": "OpenVibe.Tours",
+ "description": "Go anywhere: fly, stay, walk, watch",
+ "icon": "network"
+ },
"trade": {
"trade": {
"name": "OpenVibe.Trade",
"name": "OpenVibe.Trade",
"description": "Watchlists and alerts",
"description": "Watchlists and alerts",
@@ -164,6 +229,11 @@
@@ -164,6 +229,11 @@
"description": "Memberships for creators and their software",
"description": "Memberships for creators and their software",
"icon": "network"
"icon": "network"
},
},
+ "vision": {
+ "name": "OpenVibe.Vision",
+ "description": "See with the best model for the job",
+ "icon": "network"
+ },
"watch": {
"watch": {
"name": "OpenVibe.Watch",
"name": "OpenVibe.Watch",
"description": "Know the moment it changes",
"description": "Know the moment it changes",
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-shared",
"name": "openvibe-shared",
- "version": "4.84.0",
+ "version": "4.85.0",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"main": "index.js",
"main": "index.js",
"bin": {
"bin": {
@@ -45,6 +45,8 @@
@@ -45,6 +45,8 @@
video: 'Video', pics: 'Pics', rent: 'Rent', homes: 'Homes', work: 'Work', food: 'Food', help: 'Help', quest: 'Quest',
video: 'Video', pics: 'Pics', rent: 'Rent', homes: 'Homes', work: 'Work', food: 'Food', help: 'Help', quest: 'Quest',
website: 'Website', fund: 'Fund', 'media-hub': 'Media Hub', extensions: 'Extensions', contracts: 'Contracts', sdk: 'SDK',
website: 'Website', fund: 'Fund', 'media-hub': 'Media Hub', extensions: 'Extensions', contracts: 'Contracts', sdk: 'SDK',
shared: 'Shared', examples: 'Examples', publishing: 'Publishing', play: 'Play', inventory: 'Inventory',
shared: 'Shared', examples: 'Examples', publishing: 'Publishing', play: 'Play', inventory: 'Inventory',
+ bench: 'Bench', cam: 'Cam', casino: 'Casino', design: 'Design', domains: 'Domains', exchange: 'Exchange', fun: 'Fun',
+ meme: 'Meme', report: 'Report', surf: 'Surf', today: 'Today', tours: 'Tours', vision: 'Vision', shoes: 'Shoes',
};
};
const STYLE_ID = 'ov-shipped-style';
const STYLE_ID = 'ov-shipped-style';
const TEXT = 'var(--text-primary,var(--text,inherit))';
const TEXT = 'var(--text-primary,var(--text,inherit))';
@@ -143,6 +145,12 @@
@@ -143,6 +145,12 @@
const sub = h.replace(/\.?openvibe\.network$/, '');
const sub = h.replace(/\.?openvibe\.network$/, '');
return SITE_NAMES[sub] && sub !== 'network' ? sub : 'network';
return SITE_NAMES[sub] && sub !== 'network' ? sub : 'network';
}
}
+ // The Services family lives on its subdomains (ai., bench.openvibe.services), like the Network's.
+ if (/(^|\.)openvibe\.services$/.test(h)) {
+ const sub = h.replace(/\.?openvibe\.services$/, '');
+ return SITE_NAMES[sub] && sub !== 'services' ? sub : 'services';
+ }
+ if (/(^|\.)open\.shoes$/.test(h)) return 'shoes';
const m = /(?:^|\.)openvibe\.([a-z]+)$/.exec(h);
const m = /(?:^|\.)openvibe\.([a-z]+)$/.exec(h);
return m && SITE_NAMES[m[1]] ? m[1] : null;
return m && SITE_NAMES[m[1]] ? m[1] : null;
}
}
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/bench.jpg differ
Binary files /dev/null and b/social/bench.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/cam.jpg differ
Binary files /dev/null and b/social/cam.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/casino.jpg differ
Binary files /dev/null and b/social/casino.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/design.jpg differ
Binary files /dev/null and b/social/design.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/domains.jpg differ
Binary files /dev/null and b/social/domains.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/exchange.jpg differ
Binary files /dev/null and b/social/exchange.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/fun.jpg differ
Binary files /dev/null and b/social/fun.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/meme.jpg differ
Binary files /dev/null and b/social/meme.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/report.jpg differ
Binary files /dev/null and b/social/report.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/shoes.jpg differ
Binary files /dev/null and b/social/shoes.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/surf.jpg differ
Binary files /dev/null and b/social/surf.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/today.jpg differ
Binary files /dev/null and b/social/today.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/tours.jpg differ
Binary files /dev/null and b/social/tours.jpg differ
new file mode 100644
new file mode 100644
Binary files /dev/null and b/social/vision.jpg differ
Binary files /dev/null and b/social/vision.jpg differ
@@ -116,6 +116,10 @@ const data = {
@@ -116,6 +116,10 @@ const data = {
assert.strictEqual(sf('bot'), 'bot');
assert.strictEqual(sf('bot'), 'bot');
assert.strictEqual(sf('www.openvibe.live'), 'live');
assert.strictEqual(sf('www.openvibe.live'), 'live');
assert.strictEqual(sf('example.com'), null);
assert.strictEqual(sf('example.com'), null);
+ assert.strictEqual(sf('bench.openvibe.services'), 'bench', 'a Services subdomain is its own site');
+ assert.strictEqual(sf('ai.openvibe.services'), 'ai');
+ assert.strictEqual(sf('openvibe.services'), 'services');
+ assert.strictEqual(sf('open.shoes'), 'shoes');
assert.strictEqual(sf('live'), 'live');
assert.strictEqual(sf('live'), 'live');
// Every site with a share card and app icon (icons/sites.json, from the Contracts site blocks) is a registry id, so its
// Every site with a share card and app icon (icons/sites.json, from the Contracts site blocks) is a registry id, so its
// own feed is the one shown: play.openvibe.network showed Network's changes while 'play' was missing (2026-10-15).
// own feed is the one shown: play.openvibe.network showed Network's changes while 'play' was missing (2026-10-15).