openvibers/openvibe.network Commits

openvibe-contracts v0.34.1 (Tools platform S7): sandbox apps hold tools.tool.read and tools.tool.run by default (the run API is live); the self-service catalog lists public capabilities only (partner ones like tools.net.probe are staff-granted); the publishing library joins the registry's libraries; realtime is retired (ADR-005) in the registry tests

OP OpenVibers committed 24 Sept 2026 · 1664d0427a · 8 files, +17 −14


Changes

ddiff --git a/package-lock.json b/package-lock.json
iindex 226b942c..5215b8ae 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -20,7 +20,7 @@
"helmet": "^8.1.0",
"jsonwebtoken": "^9.0.0",
"multer": "^1.4.5-lts.1",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.33.1",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.34.1",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1",
"uuid": "^11.1.0",
@@@ -1465,9 +1465,9 @@
}
},
"node_modules/openvibe-contracts": {
-- "version": "0.33.1",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.33.1",
-- "integrity": "sha512-0S6SubDzdBmmIMbb4x1gWjWieqCl9W6nuvKrv/voUBpEvJChMGKlRmWnhLQV0KU7IZGxZcDahoYe9vI03pmf+A==",
++ "version": "0.34.1",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.34.1",
++ "integrity": "sha512-Lzb5nrT24AbUpwMmRsf3vEDcQtLlIgC0XJUmknCR8yqGUe5jfyyMFXdfVvEa8t7elAm53mw5hdz7YC6QMz/c0w==",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 0f869c07..3ac2c917 100644
---- a/package.json
++++ b/package.json
@@@ -23,7 +23,7 @@
"helmet": "^8.1.0",
"jsonwebtoken": "^9.0.0",
"multer": "^1.4.5-lts.1",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.33.1",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.34.1",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.1",
"uuid": "^11.1.0",
ddiff --git a/server/developer/policy.js b/server/developer/policy.js
iindex 3fe9fb4f..a26fbbff 100644
---- a/server/developer/policy.js
++++ b/server/developer/policy.js
@@@ -37,7 +37,8 @@ function audienceOf(id) {
/** Capabilities an app could ever be granted (the catalog view Codes shows). */
function grantableCatalog() {
-- return capabilities.manifests.filter(c => isGrantable(c.id)).map(c => ({
++ // What an app may ask for itself: public capabilities. Partner ones (e.g. tools.net.probe) are granted by staff only.
++ return capabilities.manifests.filter(c => isGrantable(c.id) && c.visibility === 'public').map(c => ({
id: c.id, owner: c.owner, audience: `openvibe.${c.owner}`, visibility: c.visibility, description: c.description || '',
resourceConstraints: c.resourceConstraints, quotaClass: c.quotaClass,
}));
@@@ -59,7 +60,7 @@ const DEFAULT_SANDBOX_AUDIENCES = Object.freeze(['openvibe.media', 'openvibe.eve
const DEFAULT_SANDBOX_ALLOWANCE = Object.freeze([
'media.object.upload', 'media.object.read',
'events.app.publish', 'events.app.read', 'events.app.subscribe',
-- 'tools.job.create', 'tools.job.read', 'tools.job.cancel',
++ 'tools.job.create', 'tools.job.read', 'tools.job.cancel', 'tools.tool.read', 'tools.tool.run',
]);
/** Public + grantable only (the rule for every allowance that is not set by staff by hand). */
ddiff --git a/server/registry/exposure.js b/server/registry/exposure.js
iindex c58104cb..49795921 100644
---- a/server/registry/exposure.js
++++ b/server/registry/exposure.js
@@@ -88,6 +88,7 @@ const EXPOSURE = {
sdk: library('openvibe-sdk', 'OpenVibe.SDK'),
shared: library('openvibe-shared', 'OpenVibe.Shared', 'also served at /shared/* by each site'),
contracts: library('openvibe-contracts', 'OpenVibe.Contracts', 'schemas are also served by this registry at their $id URLs'),
++ publishing: library('openvibe-publishing', 'OpenVibe.Publishing', 'the shared publishing runtime used by Wiki, Blog, News, Reviews, Deals, Coupons and Trade'),
examples: { state: 'repository', public_site: null, note: 'example apps with CI in OpenVibers/OpenVibe.Examples; not published as a package' },
realtime: { state: 'placeholder', public_site: null },
ddiff --git a/test/developer-defaults.test.js b/test/developer-defaults.test.js
iindex a75206d5..f8ce7112 100644
---- a/test/developer-defaults.test.js
++++ b/test/developer-defaults.test.js
@@@ -69,7 +69,7 @@ async function withoutCatalog(hidden, fn) {
assert.deepStrictEqual([...s.sandboxAudiences].sort(), ['openvibe.events', 'openvibe.media', 'openvibe.tools']);
assert.ok(!s.sandboxAudiences.has('openvibe.network'), 'Network itself never defaults to accepting sandbox tokens');
assert.deepStrictEqual(s.sandboxAllowance, ['events.app.publish', 'events.app.read', 'events.app.subscribe',
-- 'media.object.read', 'media.object.upload', 'tools.job.cancel', 'tools.job.create', 'tools.job.read'], 'the default sandbox allowance');
++ 'media.object.read', 'media.object.upload', 'tools.job.cancel', 'tools.job.create', 'tools.job.read', 'tools.tool.read', 'tools.tool.run'], 'the default sandbox allowance');
assert.deepStrictEqual(policy.DEFAULT_SANDBOX_ALLOWANCE.filter(id => id.startsWith('events.')), ['events.app.publish', 'events.app.read', 'events.app.subscribe']);
s = policy.settings({ developer: { sandboxAudiences: '', sandboxAllowance: '' } });
assert.strictEqual(s.sandboxAudiences.size, 0, 'set-but-empty means none');
ddiff --git a/test/registry-ecosystem.test.js b/test/registry-ecosystem.test.js
iindex f4e6d881..1ab20b46 100644
---- a/test/registry-ecosystem.test.js
++++ b/test/registry-ecosystem.test.js
@@@ -33,9 +33,10 @@ const { createEcosystemRegistry } = require('../server/registry/ecosystem');
assert.strictEqual(byId.realtime.runtime.status, 'not-running', 'placeholders are never shown as running');
assert.ok(r.body.services.every(s => contracts.validate('registry.service-manifest@1', Object.fromEntries(Object.entries(s).filter(([k]) => !['runtime', 'exposure', 'observed'].includes(k)))).valid));
r = await get('/api/v1/registry/services?status=placeholder');
-- // openvibe-contracts 0.30: realtime is the only placeholder manifest left (AI, SDK, Shared, Examples are alpha).
-- assert.ok(r.body.services.length >= 1 && r.body.services.every(s => s.status === 'placeholder'));
-- assert.ok(r.body.services.some(s => s.id === 'realtime'));
++ assert.ok(r.body.services.every(s => s.status === 'placeholder'), 'the status filter only returns that status');
++ // openvibe-contracts 0.34: realtime is retired (ADR-005 folded it into Events).
++ r = await get('/api/v1/registry/services?status=retired');
++ assert.ok(r.body.services.some(s => s.id === 'realtime') && r.body.services.every(s => s.status === 'retired'));
r = await get('/api/v1/registry/services/network');
assert.ok(r.body.capability_details.some(c => c.id === 'network.coins.credit'));
ddiff --git a/test/registry-exposure.test.js b/test/registry-exposure.test.js
iindex 66d35f89..32bdd099 100644
---- a/test/registry-exposure.test.js
++++ b/test/registry-exposure.test.js
@@@ -19,7 +19,7 @@ const PINNED = {
billing: 'live', codes: 'live', blog: 'live', wiki: 'live', sites: 'live',
news: 'internal', reviews: 'internal', deals: 'internal', coupons: 'internal', trade: 'internal', host: 'internal',
tips: 'internal', vip: 'internal', openre: 'internal', search: 'live', sources: 'internal', chat: 'internal', ai: 'internal',
-- sdk: 'library', shared: 'library', contracts: 'library',
++ sdk: 'library', shared: 'library', contracts: 'library', publishing: 'library',
examples: 'repository',
realtime: 'placeholder',
};
@@@ -101,7 +101,7 @@ const ready = [200, { ready: true, status: 'ready', failed: [], degraded: [], ch
assert.strictEqual(sBy.live.label, 'up');
assert.strictEqual(sBy.live.origin, 'https://openvibe.live');
assert.strictEqual(sBy.shared.label, `not running (library, released v${require('openvibe-shared/package.json').version})`);
-- assert.deepStrictEqual(st.exposure_summary, { live: 13, internal: 12, library: 3, repository: 1, placeholder: 1 });
++ assert.deepStrictEqual(st.exposure_summary, { live: 13, internal: 12, library: 4, repository: 1, placeholder: 1 });
// The page: no row for a service whose domain serves a placeholder shows a bare "Up".
const html = await fetch(base + '/status').then(x => x.text());
ddiff --git a/test/registry-topics.test.js b/test/registry-topics.test.js
iindex 3f883c2c..15b23b18 100644
---- a/test/registry-topics.test.js
++++ b/test/registry-topics.test.js
@@@ -102,7 +102,7 @@ const rel = (contractsVersion, packages) => [200, { service: 'x', release: 'abcd
r = await get('/api/v1/registry/releases');
const rel2 = Object.fromEntries(r.body.services.map(s => [s.id, s]));
assert.ok(r.body.checked_at);
-- assert.deepStrictEqual(r.body.libraries.map(l => l.id).sort(), ['contracts', 'sdk', 'shared']);
++ assert.deepStrictEqual(r.body.libraries.map(l => l.id).sort(), ['contracts', 'publishing', 'sdk', 'shared']);
assert.ok(!rel2.sdk && !rel2.contracts, 'libraries are not services');
assert.strictEqual(rel2.live.release, 'abcdef123456');
assert.strictEqual(rel2.live.contracts_version, '0.28.0');