openvibers/openvibe.contracts Commits

One Network level: curve, named reasons and contracts (#407)

OP OpenVibers committed 3 days ago · eba0ec204a · 73 files, +2389 −101

* Define the shared Network experience curve and level contracts

* Merge remote-tracking branch 'origin/main' into feat/levels-contracts-1109

* Release levels contracts as 0.391.0 after the footer manifest release

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 169354f0..b8bd24c1 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,3 +1,7 @@
++## 0.391.0 — 2026-11-09
++
++- One Network experience curve, named reasons, level reads and capped service awards.
++
# Changelog
## 0.390.0 — 2026-11-10
ddiff --git a/README.md b/README.md
iindex 32104a24..acb578f1 100644
---- a/README.md
++++ b/README.md
@@@ -5,7 +5,7 @@
**Docs:** https://openvibe.services · **For AI:** https://openvibe.services/llms.txt
**Install and test:** `npm ci && npm test` (Node 20 or newer)
--**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.389.0: 1210 schemas in `contracts/catalog.json`, 65 service manifests, 511 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
++**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.391.0: 1214 schemas in `contracts/catalog.json`, 65 service manifests, 512 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).
**License:** AGPL-3.0 (same as every OpenVibe service).
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex b6b584cb..652b2d0e 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -11159,6 +11159,42 @@
"visibility": "public",
"compatibility": "backward",
"status": "active"
++ },
++ {
++ "id": "network.level",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "network/level.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "network.level-award",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "network/level-award.v1.json",
++ "visibility": "internal",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "network.level-batch",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "network/level-batch.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "network.level-board",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "network/level-board.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
}
]
}
ddiff --git a/contracts/network/level-award.v1.json b/contracts/network/level-award.v1.json
nnew file mode 100644
iindex 00000000..8817646c
---- /dev/null
++++ b/contracts/network/level-award.v1.json
@@@ -0,0 +1,38 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/network/level-award.v1.json",
++ "title": "NetworkLevelAward",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "subject",
++ "reason",
++ "amount",
++ "idempotency_key"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "reason": {
++ "enum": [
++ "quest.completed",
++ "coins.earned",
++ "video.published",
++ "stream.watched"
++ ]
++ },
++ "amount": {
++ "type": "integer",
++ "minimum": 1,
++ "maximum": 10000
++ },
++ "idempotency_key": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 160
++ }
++ },
++ "description": "NetworkLevelAward: one earned platform level owned by Network; experience is never bought or spent."
++}
ddiff --git a/contracts/network/level-batch.v1.json b/contracts/network/level-batch.v1.json
nnew file mode 100644
iindex 00000000..fe6237b4
---- /dev/null
++++ b/contracts/network/level-batch.v1.json
@@@ -0,0 +1,21 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/network/level-batch.v1.json",
++ "title": "NetworkLevelBatch",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "levels"
++ ],
++ "properties": {
++ "levels": {
++ "type": "object",
++ "maxProperties": 100,
++ "additionalProperties": {
++ "type": "integer",
++ "minimum": 1
++ }
++ }
++ },
++ "description": "NetworkLevelBatch: one earned platform level owned by Network; experience is never bought or spent."
++}
ddiff --git a/contracts/network/level-board.v1.json b/contracts/network/level-board.v1.json
nnew file mode 100644
iindex 00000000..415ca827
---- /dev/null
++++ b/contracts/network/level-board.v1.json
@@@ -0,0 +1,276 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/network/level-board.v1.json",
++ "title": "NetworkLevelBoard",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "all_time",
++ "week"
++ ],
++ "properties": {
++ "all_time": {
++ "type": "object",
++ "required": [
++ "top",
++ "me",
++ "around"
++ ],
++ "properties": {
++ "top": {
++ "type": "array",
++ "maxItems": 50,
++ "items": {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ },
++ "me": {
++ "anyOf": [
++ {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ },
++ {
++ "type": "null"
++ }
++ ]
++ },
++ "around": {
++ "type": "array",
++ "maxItems": 11,
++ "items": {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ }
++ },
++ "additionalProperties": false
++ },
++ "week": {
++ "type": "object",
++ "required": [
++ "top",
++ "me",
++ "around"
++ ],
++ "properties": {
++ "top": {
++ "type": "array",
++ "maxItems": 50,
++ "items": {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ },
++ "me": {
++ "anyOf": [
++ {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ },
++ {
++ "type": "null"
++ }
++ ]
++ },
++ "around": {
++ "type": "array",
++ "maxItems": 11,
++ "items": {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ }
++ },
++ "additionalProperties": false
++ }
++ },
++ "description": "NetworkLevelBoard: one earned platform level owned by Network; experience is never bought or spent."
++}
ddiff --git a/contracts/network/level.v1.json b/contracts/network/level.v1.json
nnew file mode 100644
iindex 00000000..145b83de
---- /dev/null
++++ b/contracts/network/level.v1.json
@@@ -0,0 +1,78 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/network/level.v1.json",
++ "title": "NetworkLevel",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "level",
++ "xp",
++ "into",
++ "span",
++ "next_at",
++ "rank",
++ "recent"
++ ],
++ "properties": {
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "into": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "span": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "next_at": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 1
++ },
++ "recent": {
++ "type": "array",
++ "maxItems": 5,
++ "items": {
++ "type": "object",
++ "required": [
++ "name",
++ "at",
++ "amount"
++ ],
++ "properties": {
++ "name": {
++ "type": "string"
++ },
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "amount": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ }
++ },
++ "description": "NetworkLevel: one earned platform level owned by Network; experience is never bought or spent."
++}
ddiff --git a/fixtures/network.level-award/invalid/example.json b/fixtures/network.level-award/invalid/example.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/network.level-award/invalid/example.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/network.level-award/valid/example.json b/fixtures/network.level-award/valid/example.json
nnew file mode 100644
iindex 00000000..9de0043e
---- /dev/null
++++ b/fixtures/network.level-award/valid/example.json
@@@ -0,0 +1,6 @@
++{
++ "subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNP1",
++ "reason": "quest.completed",
++ "amount": 25,
++ "idempotency_key": "completion:1"
++}
ddiff --git a/fixtures/network.level-batch/invalid/example.json b/fixtures/network.level-batch/invalid/example.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/network.level-batch/invalid/example.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/network.level-batch/valid/example.json b/fixtures/network.level-batch/valid/example.json
nnew file mode 100644
iindex 00000000..cfa0e9bf
---- /dev/null
++++ b/fixtures/network.level-batch/valid/example.json
@@@ -0,0 +1,3 @@
++{
++ "levels": {}
++}
ddiff --git a/fixtures/network.level-board/invalid/example.json b/fixtures/network.level-board/invalid/example.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/network.level-board/invalid/example.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/network.level-board/valid/example.json b/fixtures/network.level-board/valid/example.json
nnew file mode 100644
iindex 00000000..761295a7
---- /dev/null
++++ b/fixtures/network.level-board/valid/example.json
@@@ -0,0 +1,12 @@
++{
++ "all_time": {
++ "top": [],
++ "me": null,
++ "around": []
++ },
++ "week": {
++ "top": [],
++ "me": null,
++ "around": []
++ }
++}
ddiff --git a/fixtures/network.level/invalid/example.json b/fixtures/network.level/invalid/example.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/network.level/invalid/example.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/network.level/valid/example.json b/fixtures/network.level/valid/example.json
nnew file mode 100644
iindex 00000000..05e0989c
---- /dev/null
++++ b/fixtures/network.level/valid/example.json
@@@ -0,0 +1,9 @@
++{
++ "level": 1,
++ "xp": 0,
++ "into": 0,
++ "span": 100,
++ "next_at": 100,
++ "rank": null,
++ "recent": []
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex 5d3d306d..60375da0 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -122992,6 +122992,439 @@
}
}
}
++ },
++ "network.level": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/network/level.v1.json",
++ "title": "NetworkLevel",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "level",
++ "xp",
++ "into",
++ "span",
++ "next_at",
++ "rank",
++ "recent"
++ ],
++ "properties": {
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "into": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "span": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "next_at": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 1
++ },
++ "recent": {
++ "type": "array",
++ "maxItems": 5,
++ "items": {
++ "type": "object",
++ "required": [
++ "name",
++ "at",
++ "amount"
++ ],
++ "properties": {
++ "name": {
++ "type": "string"
++ },
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "amount": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ }
++ },
++ "description": "NetworkLevel: one earned platform level owned by Network; experience is never bought or spent."
++ }
++ },
++ "network.level-award": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/network/level-award.v1.json",
++ "title": "NetworkLevelAward",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "subject",
++ "reason",
++ "amount",
++ "idempotency_key"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "reason": {
++ "enum": [
++ "quest.completed",
++ "coins.earned",
++ "video.published",
++ "stream.watched"
++ ]
++ },
++ "amount": {
++ "type": "integer",
++ "minimum": 1,
++ "maximum": 10000
++ },
++ "idempotency_key": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 160
++ }
++ },
++ "description": "NetworkLevelAward: one earned platform level owned by Network; experience is never bought or spent."
++ }
++ },
++ "network.level-batch": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/network/level-batch.v1.json",
++ "title": "NetworkLevelBatch",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "levels"
++ ],
++ "properties": {
++ "levels": {
++ "type": "object",
++ "maxProperties": 100,
++ "additionalProperties": {
++ "type": "integer",
++ "minimum": 1
++ }
++ }
++ },
++ "description": "NetworkLevelBatch: one earned platform level owned by Network; experience is never bought or spent."
++ }
++ },
++ "network.level-board": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/network/level-board.v1.json",
++ "title": "NetworkLevelBoard",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "all_time",
++ "week"
++ ],
++ "properties": {
++ "all_time": {
++ "type": "object",
++ "required": [
++ "top",
++ "me",
++ "around"
++ ],
++ "properties": {
++ "top": {
++ "type": "array",
++ "maxItems": 50,
++ "items": {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ },
++ "me": {
++ "anyOf": [
++ {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ },
++ {
++ "type": "null"
++ }
++ ]
++ },
++ "around": {
++ "type": "array",
++ "maxItems": 11,
++ "items": {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ }
++ },
++ "additionalProperties": false
++ },
++ "week": {
++ "type": "object",
++ "required": [
++ "top",
++ "me",
++ "around"
++ ],
++ "properties": {
++ "top": {
++ "type": "array",
++ "maxItems": 50,
++ "items": {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ },
++ "me": {
++ "anyOf": [
++ {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ },
++ {
++ "type": "null"
++ }
++ ]
++ },
++ "around": {
++ "type": "array",
++ "maxItems": 11,
++ "items": {
++ "type": "object",
++ "required": [
++ "subject",
++ "username",
++ "level",
++ "xp",
++ "rank"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "username": {
++ "type": "string"
++ },
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ }
++ },
++ "additionalProperties": false
++ }
++ },
++ "description": "NetworkLevelBoard: one earned platform level owned by Network; experience is never bought or spent."
++ }
}
}
}
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex 1c7f4310..aa4a3f67 100644
---- a/generated/openapi/actor.json
++++ b/generated/openapi/actor.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Actor API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex 55b8f76b..b0484e10 100644
---- a/generated/openapi/ai.json
++++ b/generated/openapi/ai.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.AI API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bench.json b/generated/openapi/bench.json
iindex 804ed44a..54c72fb3 100644
---- a/generated/openapi/bench.json
++++ b/generated/openapi/bench.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bench API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/billing.json b/generated/openapi/billing.json
iindex cffa188c..bd10b291 100644
---- a/generated/openapi/billing.json
++++ b/generated/openapi/billing.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Billing API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex c5d2bf20..cd66653a 100644
---- a/generated/openapi/blog.json
++++ b/generated/openapi/blog.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Blog API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bot.json b/generated/openapi/bot.json
iindex c074c413..7f5366a5 100644
---- a/generated/openapi/bot.json
++++ b/generated/openapi/bot.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bot API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/chat.json b/generated/openapi/chat.json
iindex 582c6363..b2585cf5 100644
---- a/generated/openapi/chat.json
++++ b/generated/openapi/chat.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Chat API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/codes.json b/generated/openapi/codes.json
iindex 8715c520..a7e8f552 100644
---- a/generated/openapi/codes.json
++++ b/generated/openapi/codes.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Codes API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/community.json b/generated/openapi/community.json
iindex 752345a3..b0d585ff 100644
---- a/generated/openapi/community.json
++++ b/generated/openapi/community.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Community API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/connect.json b/generated/openapi/connect.json
iindex 0e307d0e..1f9caeee 100644
---- a/generated/openapi/connect.json
++++ b/generated/openapi/connect.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe Connect API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/coupons.json b/generated/openapi/coupons.json
iindex be922030..1c2c2ab5 100644
---- a/generated/openapi/coupons.json
++++ b/generated/openapi/coupons.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Coupons API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/deals.json b/generated/openapi/deals.json
iindex fc55b814..cb9fe1e6 100644
---- a/generated/openapi/deals.json
++++ b/generated/openapi/deals.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Deals API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/design.json b/generated/openapi/design.json
iindex 2e0da81d..64951c68 100644
---- a/generated/openapi/design.json
++++ b/generated/openapi/design.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Design API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/domains.json b/generated/openapi/domains.json
iindex 9e1ef586..ea84023b 100644
---- a/generated/openapi/domains.json
++++ b/generated/openapi/domains.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Domains API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/events.json b/generated/openapi/events.json
iindex 95ae87b9..fd1fd3b9 100644
---- a/generated/openapi/events.json
++++ b/generated/openapi/events.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Events API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/exchange.json b/generated/openapi/exchange.json
iindex 8a4222eb..83cddde0 100644
---- a/generated/openapi/exchange.json
++++ b/generated/openapi/exchange.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Exchange API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Exchange as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Exchange as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/food.json b/generated/openapi/food.json
iindex 41cbfd34..b220805f 100644
---- a/generated/openapi/food.json
++++ b/generated/openapi/food.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Food API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/games.json b/generated/openapi/games.json
iindex 90573b26..29766c9c 100644
---- a/generated/openapi/games.json
++++ b/generated/openapi/games.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Games API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/git.json b/generated/openapi/git.json
iindex 1918c497..b85b6554 100644
---- a/generated/openapi/git.json
++++ b/generated/openapi/git.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Git API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Git as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Git as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/host.json b/generated/openapi/host.json
iindex 3dd4e79b..011061c8 100644
---- a/generated/openapi/host.json
++++ b/generated/openapi/host.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Host API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/index.json b/generated/openapi/index.json
iindex d18d024d..4e11a24f 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -180,8 +180,8 @@
"service": "network",
"name": "OpenVibe.Network",
"origin": "https://openvibe.network",
-- "operations": 68,
-- "capabilities": 39
++ "operations": 69,
++ "capabilities": 40
},
{
"service": "news",
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex f13eb682..8750215d 100644
---- a/generated/openapi/inventory.json
++++ b/generated/openapi/inventory.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Inventory API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/live.json b/generated/openapi/live.json
iindex d1c21f63..df509bbc 100644
---- a/generated/openapi/live.json
++++ b/generated/openapi/live.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Live API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/mail.json b/generated/openapi/mail.json
iindex 7ae8769f..65dd9746 100644
---- a/generated/openapi/mail.json
++++ b/generated/openapi/mail.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Mail API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media-hub.json b/generated/openapi/media-hub.json
iindex 6d391ba7..4c9245e7 100644
---- a/generated/openapi/media-hub.json
++++ b/generated/openapi/media-hub.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.MediaHub API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media.json b/generated/openapi/media.json
iindex a40e7cbe..79246009 100644
---- a/generated/openapi/media.json
++++ b/generated/openapi/media.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Media API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex 3131a200..7ebd3140 100644
---- a/generated/openapi/network.json
++++ b/generated/openapi/network.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Network API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
@@@ -2971,6 +2971,62 @@
}
}
},
++ "/internal/levels/award": {
++ "post": {
++ "operationId": "post_internal_levels_award",
++ "summary": "Award earned, non-spendable experience.",
++ "description": "**network.levels.award** (internal): Award earned, non-spendable experience. Service identity comes from the credential; duplicates are refused with 409. Daily service and person caps apply.",
++ "tags": [
++ "network.levels"
++ ],
++ "x-openvibe-capabilities": [
++ "network.levels.award"
++ ],
++ "x-openvibe-visibility": [
++ "internal"
++ ],
++ "x-openvibe-quota-class": "ledger-write",
++ "security": [
++ {
++ "openvibeToken": [
++ "network.levels.award"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/network.level-award.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/network.level.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/internal/link-pairings": {
"post": {
"operationId": "post_internal_link_pairings",
@@@ -6730,6 +6786,118 @@
}
}
},
++ "network.level-award.v1": {
++ "title": "NetworkLevelAward",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "subject",
++ "reason",
++ "amount",
++ "idempotency_key"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "reason": {
++ "enum": [
++ "quest.completed",
++ "coins.earned",
++ "video.published",
++ "stream.watched"
++ ]
++ },
++ "amount": {
++ "type": "integer",
++ "minimum": 1,
++ "maximum": 10000
++ },
++ "idempotency_key": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 160
++ }
++ },
++ "description": "NetworkLevelAward: one earned platform level owned by Network; experience is never bought or spent."
++ },
++ "network.level.v1": {
++ "title": "NetworkLevel",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "level",
++ "xp",
++ "into",
++ "span",
++ "next_at",
++ "rank",
++ "recent"
++ ],
++ "properties": {
++ "level": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "xp": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "into": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "span": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "next_at": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ },
++ "rank": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 1
++ },
++ "recent": {
++ "type": "array",
++ "maxItems": 5,
++ "items": {
++ "type": "object",
++ "required": [
++ "name",
++ "at",
++ "amount"
++ ],
++ "properties": {
++ "name": {
++ "type": "string"
++ },
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "amount": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 1000000000000
++ }
++ },
++ "additionalProperties": false
++ }
++ }
++ },
++ "description": "NetworkLevel: one earned platform level owned by Network; experience is never bought or spent."
++ },
"network.link-list-result.v1": {
"title": "NetworkLinkListResult",
"description": "network.link-list-result@1: GET /api/v1/links on OpenVibe.Network (public, cacheable): every node of the platform, filterable by ?role= and ?region=. The input of openvibe-sdk/geo's nearest().",
ddiff --git a/generated/openapi/news.json b/generated/openapi/news.json
iindex 37b05246..20b86cf7 100644
---- a/generated/openapi/news.json
++++ b/generated/openapi/news.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.News API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/openre.json b/generated/openapi/openre.json
iindex 48306ad9..1524e19a 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRestream API",
-- "version": "0.390.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/play.json b/generated/openapi/play.json
iindex 63210460..4cf8927f 100644
---- a/generated/openapi/play.json
++++ b/generated/openapi/play.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Play API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/quest.json b/generated/openapi/quest.json
iindex 9efacb2e..71f0faa5 100644
---- a/generated/openapi/quest.json
++++ b/generated/openapi/quest.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Quest API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/report.json b/generated/openapi/report.json
iindex 4b06e68a..7c5e4cda 100644
---- a/generated/openapi/report.json
++++ b/generated/openapi/report.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Report API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/reviews.json b/generated/openapi/reviews.json
iindex fbec00d4..e25713ed 100644
---- a/generated/openapi/reviews.json
++++ b/generated/openapi/reviews.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Reviews API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/run.json b/generated/openapi/run.json
iindex efe9cf2d..60a7aaed 100644
---- a/generated/openapi/run.json
++++ b/generated/openapi/run.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Run API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/search.json b/generated/openapi/search.json
iindex 9079f6d6..af14a2d9 100644
---- a/generated/openapi/search.json
++++ b/generated/openapi/search.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Search API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/services.json b/generated/openapi/services.json
iindex 2d715e2c..e5bf4775 100644
---- a/generated/openapi/services.json
++++ b/generated/openapi/services.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Services API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/sources.json b/generated/openapi/sources.json
iindex f767ff51..e6707778 100644
---- a/generated/openapi/sources.json
++++ b/generated/openapi/sources.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Sources API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/space.json b/generated/openapi/space.json
iindex 56e0c51f..41e6fa00 100644
---- a/generated/openapi/space.json
++++ b/generated/openapi/space.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Space API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tips.json b/generated/openapi/tips.json
iindex 3ae95e0d..23b344a5 100644
---- a/generated/openapi/tips.json
++++ b/generated/openapi/tips.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tips API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/today.json b/generated/openapi/today.json
iindex 43d5fb02..115b33df 100644
---- a/generated/openapi/today.json
++++ b/generated/openapi/today.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Today API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tools.json b/generated/openapi/tools.json
iindex cb097832..687e03bb 100644
---- a/generated/openapi/tools.json
++++ b/generated/openapi/tools.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tools API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/trade.json b/generated/openapi/trade.json
iindex 0a897f03..1306d666 100644
---- a/generated/openapi/trade.json
++++ b/generated/openapi/trade.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Trade API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vip.json b/generated/openapi/vip.json
iindex d469f0a6..183fc053 100644
---- a/generated/openapi/vip.json
++++ b/generated/openapi/vip.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.VIP API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vision.json b/generated/openapi/vision.json
iindex 0d3ba4e1..16db936f 100644
---- a/generated/openapi/vision.json
++++ b/generated/openapi/vision.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Vision API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/watch.json b/generated/openapi/watch.json
iindex 21aadbae..45c37a09 100644
---- a/generated/openapi/watch.json
++++ b/generated/openapi/watch.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Watch API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/wiki.json b/generated/openapi/wiki.json
iindex 039fa2bf..2adedb82 100644
---- a/generated/openapi/wiki.json
++++ b/generated/openapi/wiki.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Wiki API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/work.json b/generated/openapi/work.json
iindex af2e9ae7..b2f2b867 100644
---- a/generated/openapi/work.json
++++ b/generated/openapi/work.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Work API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/zone.json b/generated/openapi/zone.json
iindex b7e6e968..8c9f1dbf 100644
---- a/generated/openapi/zone.json
++++ b/generated/openapi/zone.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Zone API",
-- "version": "0.390.0",
-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.390.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.391.0",
++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.391.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex aacbd51a..beadfe9d 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -328190,3 +328190,1150 @@ export interface AiAdvice {
words?: number;
created_at: string;
}
++
++/** [email protected] (owner: network) */
++/**
++ * NetworkLevel: one earned platform level owned by Network; experience is never bought or spent.
++ */
++export interface NetworkLevel {
++ level: number;
++ xp: number;
++ into: number;
++ span: number;
++ next_at: number;
++ rank: number | null;
++ /**
++ * @maxItems 5
++ */
++ recent:
++ | []
++ | [
++ {
++ name: string;
++ at: string;
++ amount: number;
++ }
++ ]
++ | [
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ }
++ ]
++ | [
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ }
++ ]
++ | [
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ }
++ ]
++ | [
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ },
++ {
++ name: string;
++ at: string;
++ amount: number;
++ }
++ ];
++}
++
++/** [email protected] (owner: network) */
++/**
++ * NetworkLevelAward: one earned platform level owned by Network; experience is never bought or spent.
++ */
++export interface NetworkLevelAward {
++ subject: string;
++ reason: "quest.completed" | "coins.earned" | "video.published" | "stream.watched";
++ amount: number;
++ idempotency_key: string;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * NetworkLevelBatch: one earned platform level owned by Network; experience is never bought or spent.
++ */
++export interface NetworkLevelBatch {
++ levels: {
++ [k: string]: number | undefined;
++ };
++}
++
++/** [email protected] (owner: network) */
++/**
++ * NetworkLevelBoard: one earned platform level owned by Network; experience is never bought or spent.
++ */
++export interface NetworkLevelBoard {
++ all_time: {
++ /**
++ * @maxItems 50
++ */
++ top: {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }[];
++ me: {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ } | null;
++ /**
++ * @maxItems 11
++ */
++ around:
++ | []
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ];
++ };
++ week: {
++ /**
++ * @maxItems 50
++ */
++ top: {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }[];
++ me: {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ } | null;
++ /**
++ * @maxItems 11
++ */
++ around:
++ | []
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ]
++ | [
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ },
++ {
++ subject: string;
++ username: string;
++ level: number;
++ xp: number;
++ rank: number;
++ }
++ ];
++ };
++}
ddiff --git a/index.js b/index.js
iindex 056f6c7e..934cbe59 100644
---- a/index.js
++++ b/index.js
@@@ -13,6 +13,7 @@
const registry = require('./lib/registry');
module.exports = {
++ levels: require('./lib/levels'),
catalog: registry.catalog,
resolve: registry.resolve,
validate: registry.validate,
ddiff --git a/lib/levels.js b/lib/levels.js
nnew file mode 100644
iindex 00000000..9e02ef79
---- /dev/null
++++ b/lib/levels.js
@@@ -0,0 +1,16 @@
++'use strict';
++/** One platform level. Experience is an earned, non-spendable whole number. */
++function levelOf(xp) {
++ if (!Number.isSafeInteger(xp) || xp < 0 || xp > 1000000000000) throw new RangeError('xp must be an integer from 0 to 1000000000000');
++ const level = Math.floor((1 + Math.sqrt(1 + xp / 12.5)) / 2);
++ const start = 50 * level * (level - 1);
++ return { level, into: xp - start, span: 100 * level, next_at: 50 * level * (level + 1) };
++}
++const reasons = Object.freeze({
++ 'quest.completed': Object.freeze({ name: 'Finished a quest' }),
++ 'coins.earned': Object.freeze({ name: 'Earned OpenCoins' }),
++ 'video.published': Object.freeze({ name: 'Published a video' }),
++ 'stream.watched': Object.freeze({ name: 'Watched a stream' }),
++});
++function reasonName(code) { return reasons[code]?.name || 'Earned experience'; }
++module.exports = { levelOf, reasons, reasonName };
ddiff --git a/manifests/capabilities/network.levels.award.json b/manifests/capabilities/network.levels.award.json
nnew file mode 100644
iindex 00000000..4e71d4b6
---- /dev/null
++++ b/manifests/capabilities/network.levels.award.json
@@@ -0,0 +1,19 @@
++{
++ "id": "network.levels.award",
++ "version": "1.0",
++ "owner": "network",
++ "status": "active",
++ "visibility": "internal",
++ "description": "Award earned, non-spendable experience. Service identity comes from the credential; duplicates are refused with 409. Daily service and person caps apply.",
++ "permissions": [
++ "levels:write"
++ ],
++ "resourceConstraints": [],
++ "quotaClass": "ledger-write",
++ "events": [],
++ "implementedBy": [
++ "POST /internal/levels/award"
++ ],
++ "inputSchema": "network.level-award@1",
++ "outputSchema": "network.level@1"
++}
ddiff --git a/manifests/services/network.json b/manifests/services/network.json
iindex da77c56f..241348d8 100644
---- a/manifests/services/network.json
++++ b/manifests/services/network.json
@@@ -89,7 +89,8 @@
"network.consent.manage",
"network.machines.read",
"network.machines.manage",
-- "network.presence.read"
++ "network.presence.read",
++ "network.levels.award"
],
"eventsProduced": [
"network.account.deleted",
ddiff --git a/package-lock.json b/package-lock.json
iindex 2faf0469..c18083ee 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-contracts",
-- "version": "0.384.0",
++ "version": "0.391.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.384.0",
++ "version": "0.391.0",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex a3e5a319..72af731b 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.390.0",
++ "version": "0.391.0",
"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/levels.test.js b/test/levels.test.js
nnew file mode 100644
iindex 00000000..2f303f8f
---- /dev/null
++++ b/test/levels.test.js
@@@ -0,0 +1,15 @@
++'use strict';
++const assert = require('assert');
++const { levels, validate } = require('..');
++for (let l = 1; l <= 10000; l++) {
++ const at = 50*l*(l-1);
++ assert.equal(levels.levelOf(at).level, l);
++ if (at) assert.equal(levels.levelOf(at-1).level, l-1);
++ assert.equal(levels.levelOf(at).into, 0);
++ assert.equal(levels.levelOf(at).span, 100*l);
++}
++for (const x of [-1, 1.5, NaN, Infinity, '100']) assert.throws(() => levels.levelOf(x));
++assert.equal(levels.reasonName('quest.completed'), 'Finished a quest');
++assert.equal(levels.reasonName('private:raw-code'), 'Earned experience');
++assert(validate('network.level@1', {...levels.levelOf(300), xp:300, rank:null, recent:[]}).valid);
++console.log('levels: curve boundaries and named reasons passed');
ddiff --git a/test/run.js b/test/run.js
iindex 24db4e2e..1540c993 100644
---- a/test/run.js
++++ b/test/run.js
@@@ -1,3 +1,4 @@
++require('./levels.test');
'use strict';
const assert = require('assert');
const fs = require('fs');