openvibers/openvibe.contracts Commits

v0.5.1: every running service's manifest accepts >=0.2.0 <1.0.0; openvibe-contracts-check also reads { capability: 'x' } route options

OP OpenVibers committed 22 Sept 2026 · 62b10e4ab2 · 8 files, +12 −9


Changes

ddiff --git a/bin/check-service.js b/bin/check-service.js
iindex 23cf5328..edafcf93 100755
---- a/bin/check-service.js
++++ b/bin/check-service.js
@@@ -7,7 +7,8 @@
*
* Fails when
* - the installed openvibe-contracts version is outside the service manifest's contractRanges
-- * - the code guards a capability (requireCapability('x') / guard('x') / capabilities.check(.., 'x'))
++ * - the code guards a capability (requireCapability('x') / guard('x') / capabilities.check(.., 'x') /
++ * { capability: 'x' } route options)
* that the contracts don't define, that is retired, or that another service owns
* - the code validates against a contract id (validate('x') / assertValid('x')) that doesn't exist
* Prints what it checked so a green run says something.
@@@ -56,14 +57,14 @@ for (const d of srcDirs) (function walk(dir) {
}
})(d);
--const CAP_RE = /\b(?:requireCapability|guard)\(\s*['"]([a-z][a-z0-9_.]+)['"]|capabilities\.check\([^,]+,\s*['"]([a-z][a-z0-9_.]+)['"]/g;
++const CAP_RE = /\b(?:requireCapability|guard)\(\s*['"]([a-z][a-z0-9_.]+)['"]|capabilities\.check\([^,]+,\s*['"]([a-z][a-z0-9_.]+)['"]|\bcapability:\s*['"]([a-z][a-z0-9_.]+)['"]/g;
const CONTRACT_RE = /\b(?:validate|assertValid)\(\s*['"]([a-z][a-z0-9-]*\.[a-z0-9-]+(?:@\d+)?)['"]/g;
const used = new Map();
const refs = new Map();
for (const f of files) {
const text = fs.readFileSync(f, 'utf8');
let m;
-- while ((m = CAP_RE.exec(text))) { const id = m[1] || m[2]; (used.get(id) || used.set(id, []).get(id)).push(path.relative(process.cwd(), f)); }
++ while ((m = CAP_RE.exec(text))) { const id = m[1] || m[2] || m[3]; (used.get(id) || used.set(id, []).get(id)).push(path.relative(process.cwd(), f)); }
while ((m = CONTRACT_RE.exec(text))) { (refs.get(m[1]) || refs.set(m[1], []).get(m[1])).push(path.relative(process.cwd(), f)); }
}
for (const [id, where] of used) {
ddiff --git a/manifests/services/contracts.json b/manifests/services/contracts.json
iindex 2d2f02fe..9436981c 100644
---- a/manifests/services/contracts.json
++++ b/manifests/services/contracts.json
@@@ -1,7 +1,7 @@
{
"version": "0.1.0",
"contractRanges": {
-- "openvibe-contracts": "^0.1.0"
++ "openvibe-contracts": ">=0.2.0 <1.0.0"
},
"id": "contracts",
"name": "OpenVibe.Contracts",
ddiff --git a/manifests/services/games.json b/manifests/services/games.json
iindex 78604970..849f440a 100644
---- a/manifests/services/games.json
++++ b/manifests/services/games.json
@@@ -1,7 +1,7 @@
{
"version": "0.1.0",
"contractRanges": {
-- "openvibe-contracts": "^0.1.0"
++ "openvibe-contracts": ">=0.2.0 <1.0.0"
},
"id": "games",
"name": "OpenVibe.Games",
ddiff --git a/manifests/services/media.json b/manifests/services/media.json
iindex 00366525..f2a44441 100644
---- a/manifests/services/media.json
++++ b/manifests/services/media.json
@@@ -1,7 +1,7 @@
{
"version": "0.1.0",
"contractRanges": {
-- "openvibe-contracts": "^0.1.0"
++ "openvibe-contracts": ">=0.2.0 <1.0.0"
},
"id": "media",
"name": "OpenVibe.Media",
ddiff --git a/manifests/services/sites.json b/manifests/services/sites.json
iindex 5d3c453c..d7a4ee13 100644
---- a/manifests/services/sites.json
++++ b/manifests/services/sites.json
@@@ -1,7 +1,7 @@
{
"version": "0.1.0",
"contractRanges": {
-- "openvibe-contracts": "^0.1.0"
++ "openvibe-contracts": ">=0.2.0 <1.0.0"
},
"id": "sites",
"name": "OpenVibe.Sites",
ddiff --git a/manifests/services/tools.json b/manifests/services/tools.json
iindex 0519a2ab..b527e82c 100644
---- a/manifests/services/tools.json
++++ b/manifests/services/tools.json
@@@ -1,7 +1,7 @@
{
"version": "0.1.0",
"contractRanges": {
-- "openvibe-contracts": "^0.1.0"
++ "openvibe-contracts": ">=0.2.0 <1.0.0"
},
"id": "tools",
"name": "OpenVibe.Tools",
ddiff --git a/package.json b/package.json
iindex 3335503a..c4d3cf98 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.5.0",
++ "version": "0.5.1",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
ddiff --git a/test/run.js b/test/run.js
iindex 75775c2c..fd7fbee0 100644
---- a/test/run.js
++++ b/test/run.js
@@@ -190,6 +190,8 @@ await assert.rejects(failing.getToken(), /401: invalid_client/);
};
let c = check({ 'a.js': "router.post('/x', guard('network.coins.credit'), h); validate('identity.subject-ref@1', v);" });
ok(c.code === 0 && /1 capabilities enforced \[network.coins.credit\]/.test(c.out), 'owned capability passes: ' + c.out);
++ c = check({ 'a.js': "router.post('/', tenantAuth({ capability: 'media.object.upload' }), h)" }, 'media');
++ ok(c.code === 0 && /\[media.object.upload\]/.test(c.out), 'route-option capabilities are checked too');
c = check({ 'a.js': "requireCapability('network.coins.mint')" });
ok(c.code === 1 && /not defined/.test(c.out), 'unknown capability fails');
c = check({ 'a.js': "requireCapability('media.object.upload')" });