openvibers/openvibe.shared Commits
v1.17.1: release-watch acts on a release notification only when its origin (when given) is the page's own; Sites' placeholders reuse product service ids
Changes
@@@ -4,6 +4,10 @@ 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).++## 1.17.1 — 2026-09-26++++Fix: `release-watch.js` acts on a `host.release.published` event only when its `origin` (when present) is the page's own. A service id alone is not unique across the network: Sites' placeholder pages reuse product ids (`ai`, `coupons`, …), so a placeholder's release made the real product's tabs check for nothing.++## 1.17.0 — 2026-09-26**Release notifications in `release-watch.js`** (roadmap WS-P task 9, ADR-016 amendment 1). When a release goes live, OpenVibe.Host publishes `host.release.published` to OpenVibe.Events (contract `host.release.published@1`, openvibe-contracts 0.58.0; `ovhost deploy` and `ovhost announce`). The event is public, has subject `release` and carries `service`, `release`, `commit` and `origin`. Tabs now hear about a release within seconds instead of at their next poll:@@@ -1,12 +1,12 @@{"name": "openvibe-shared",-- "version": "1.17.0",++ "version": "1.17.1","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-shared",-- "version": "1.17.0",++ "version": "1.17.1","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0"@@@ -1,6 +1,6 @@{"name": "openvibe-shared",-- "version": "1.17.0",++ "version": "1.17.1","description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site","main": "index.js","exports": {@@@ -224,6 +224,9 @@if (!p || ev.event_type !== TOPIC) return;if (typeof m.seq === 'number') { if (rt.lastSeq != null && m.seq <= rt.lastSeq) return; rt.lastSeq = m.seq; }if (p.service !== rt.service || typeof p.release !== 'string') return;++ // A service id alone is not unique across the network (Sites' placeholder pages reuse product ids),++ // so when the event names the origin it went live on, it must be this page's.++ if (p.origin) { try { if (new URL(p.origin).origin !== root.location.origin) { rt.ignored++; return; } } catch { return; } }rt.events++;if (seen.includes(ev.event_id) || same(p.release, current) || same(p.release, latest && latest.release) || same(p.release, queued)) { rt.ignored++; return; }seen = seen.concat(ev.event_id).slice(-20);@@@ -71,8 +71,10 @@ async function open({ url = 'https://openvibe.live/', html = PAGE(), config = nus.send(3, released('live', A));s.send(4, released('live', 'aaaaaaa'));s.send(5, { ...released('live', B), event_type: 'live.stream.started' });++ // The same service id on another origin (Sites' placeholder pages reuse product ids): not this page's.++ s.send(5.5, { ...released('live', B), payload: { ...released('live', B).payload, origin: 'https://placeholder.openvibe.network' } });assert.deepStrictEqual(p.timeouts(), [], 'none of those schedules a check');-- assert.deepStrictEqual([p.rt().events, p.rt().ignored], [2, 2]);++ assert.deepStrictEqual([p.rt().events, p.rt().ignored], [2, 3]);// A new release: one check after the jitter (random 0.5 → 10 s); a burst collapses into it.const before = p.fetches();
@@ -4,6 +4,10 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semve
@@ -4,6 +4,10 @@ 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).
+## 1.17.1 — 2026-09-26
+
+Fix: `release-watch.js` acts on a `host.release.published` event only when its `origin` (when present) is the page's own. A service id alone is not unique across the network: Sites' placeholder pages reuse product ids (`ai`, `coupons`, …), so a placeholder's release made the real product's tabs check for nothing.
+
## 1.17.0 — 2026-09-26
## 1.17.0 — 2026-09-26
**Release notifications in `release-watch.js`** (roadmap WS-P task 9, ADR-016 amendment 1). When a release goes live, OpenVibe.Host publishes `host.release.published` to OpenVibe.Events (contract `host.release.published@1`, openvibe-contracts 0.58.0; `ovhost deploy` and `ovhost announce`). The event is public, has subject `release` and carries `service`, `release`, `commit` and `origin`. Tabs now hear about a release within seconds instead of at their next poll:
**Release notifications in `release-watch.js`** (roadmap WS-P task 9, ADR-016 amendment 1). When a release goes live, OpenVibe.Host publishes `host.release.published` to OpenVibe.Events (contract `host.release.published@1`, openvibe-contracts 0.58.0; `ovhost deploy` and `ovhost announce`). The event is public, has subject `release` and carries `service`, `release`, `commit` and `origin`. Tabs now hear about a release within seconds instead of at their next poll:
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-shared",
"name": "openvibe-shared",
- "version": "1.17.0",
+ "version": "1.17.1",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-shared",
"name": "openvibe-shared",
- "version": "1.17.0",
+ "version": "1.17.1",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0"
"jsonwebtoken": "^9.0.0"
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-shared",
"name": "openvibe-shared",
- "version": "1.17.0",
+ "version": "1.17.1",
"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",
"exports": {
"exports": {
@@ -224,6 +224,9 @@
@@ -224,6 +224,9 @@
if (!p || ev.event_type !== TOPIC) return;
if (!p || ev.event_type !== TOPIC) return;
if (typeof m.seq === 'number') { if (rt.lastSeq != null && m.seq <= rt.lastSeq) return; rt.lastSeq = m.seq; }
if (typeof m.seq === 'number') { if (rt.lastSeq != null && m.seq <= rt.lastSeq) return; rt.lastSeq = m.seq; }
if (p.service !== rt.service || typeof p.release !== 'string') return;
if (p.service !== rt.service || typeof p.release !== 'string') return;
+ // A service id alone is not unique across the network (Sites' placeholder pages reuse product ids),
+ // so when the event names the origin it went live on, it must be this page's.
+ if (p.origin) { try { if (new URL(p.origin).origin !== root.location.origin) { rt.ignored++; return; } } catch { return; } }
rt.events++;
rt.events++;
if (seen.includes(ev.event_id) || same(p.release, current) || same(p.release, latest && latest.release) || same(p.release, queued)) { rt.ignored++; return; }
if (seen.includes(ev.event_id) || same(p.release, current) || same(p.release, latest && latest.release) || same(p.release, queued)) { rt.ignored++; return; }
seen = seen.concat(ev.event_id).slice(-20);
seen = seen.concat(ev.event_id).slice(-20);
@@ -71,8 +71,10 @@ async function open({ url = 'https://openvibe.live/', html = PAGE(), config = nu
@@ -71,8 +71,10 @@ async function open({ url = 'https://openvibe.live/', html = PAGE(), config = nu
s.send(3, released('live', A));
s.send(3, released('live', A));
s.send(4, released('live', 'aaaaaaa'));
s.send(4, released('live', 'aaaaaaa'));
s.send(5, { ...released('live', B), event_type: 'live.stream.started' });
s.send(5, { ...released('live', B), event_type: 'live.stream.started' });
+ // The same service id on another origin (Sites' placeholder pages reuse product ids): not this page's.
+ s.send(5.5, { ...released('live', B), payload: { ...released('live', B).payload, origin: 'https://placeholder.openvibe.network' } });
assert.deepStrictEqual(p.timeouts(), [], 'none of those schedules a check');
assert.deepStrictEqual(p.timeouts(), [], 'none of those schedules a check');
- assert.deepStrictEqual([p.rt().events, p.rt().ignored], [2, 2]);
+ assert.deepStrictEqual([p.rt().events, p.rt().ignored], [2, 3]);
// A new release: one check after the jitter (random 0.5 → 10 s); a burst collapses into it.
// A new release: one check after the jitter (random 0.5 → 10 s); a burst collapses into it.
const before = p.fetches();
const before = p.fetches();