openvibers/openvibe.contracts Commits

Avatar references: media.avatar.adopt and media.avatar.release (0.302.0) (#312)

OP OpenVibers committed 6 days ago · 899c2ee10f · 67 files, +1052 −87

Media records which avatar object each profile slot points at, and refuses to delete one a working profile still
shows (incident 2026-11-06). The two internal routes it adds for that get their capabilities, request and result
schemas, fixtures and a place in Media's manifest. Additive.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex eab941e8..22919b90 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,5 +1,11 @@
# Changelog
++## 0.302.0 — 2026-11-06
++
++- Add the capabilities `media.avatar.adopt` and `media.avatar.release` (internal), and name both in Media's service manifest. After the 2026-11-06 incident (eleven avatars were soft-deleted with the public screenshot copies), Media records which avatar object each profile slot points at, and its delete refuses an object a working profile still shows. A product (Network for `users.avatar_url`, Live for its own copy and the channel banner) records a slot with `POST /internal/avatar-adopt` and drops it with `POST /internal/avatar-release`.
++- Add `media.avatar-adopt-request@1` / `media.avatar-adopt-result@1` (the slot: `object_id` `med_…`, `product`, `ref`, the optional `subject`; the answer is the active reference) and `media.avatar-release-request@1` / `media.avatar-release-result@1` (a slot, an object or a person; the answer counts the released references, 0 when there were none).
++- Additive: nothing that exists changes. Fixtures cover a missing ref, an object id that is not `med_…`, a release that names nothing, a product without its ref and a negative count.
++
## 0.301.0 — 2026-11-06
- Add `live.agent-stream-state@2` (Agent Streams S4): the state the desk polls gains the voice (`mode` watch or narrated, the `voice`, the `personality` calm, hype, dry or roast, `muted`, `paused` with its reason), the newest `lines` to speak, and `captions_url` (the stream's WebVTT). `@1` is unchanged.
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex f1ddc494..be3abdce 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -5116,6 +5116,42 @@
"compatibility": "backward",
"status": "active"
},
++ {
++ "id": "media.avatar-adopt-request",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/avatar-adopt-request.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "media.avatar-adopt-result",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/avatar-adopt-result.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "media.avatar-release-request",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/avatar-release-request.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "media.avatar-release-result",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/avatar-release-result.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
{
"id": "media.file-read-result",
"version": "1.0.0",
ddiff --git a/contracts/media/avatar-adopt-request.v1.json b/contracts/media/avatar-adopt-request.v1.json
nnew file mode 100644
iindex 00000000..a87a2b15
---- /dev/null
++++ b/contracts/media/avatar-adopt-request.v1.json
@@@ -0,0 +1,39 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/avatar-adopt-request.v1.json",
++ "title": "MediaAvatarAdoptRequest",
++ "description": "media.avatar-adopt-request@1: the body of POST /internal/avatar-adopt on OpenVibe.Media (capability media.avatar.adopt). A product records that one of its profile slots points at an avatar object, so a cleanup can never delete the picture a working profile shows (incident 2026-11-06: eleven avatars were deleted with the public screenshot copies). Recording a slot releases the slot's previous reference in the same transaction. Ingest records the reference itself; this route is for a picture the product already holds. Refusals are { ok: false, error }: 400 without object_id, product or ref, 404 for an unknown object, 409 for an object that is not ready, 422 for an object that is not an avatar or belongs to someone else.",
++ "type": "object",
++ "required": [
++ "object_id",
++ "product",
++ "ref"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "object_id": {
++ "type": "string",
++ "pattern": "^med_",
++ "description": "The avatar object (med_…) the slot points at."
++ },
++ "product": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{1,31}$",
++ "description": "The product whose profile holds the picture: network (users.avatar_url) or live (its own users.avatar_url, a channel banner)."
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 64,
++ "description": "The slot in that product: the person's id there, or the id and the slot (for example 42:banner)."
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ }
++ }
++}
ddiff --git a/contracts/media/avatar-adopt-result.v1.json b/contracts/media/avatar-adopt-result.v1.json
nnew file mode 100644
iindex 00000000..7e5d122f
---- /dev/null
++++ b/contracts/media/avatar-adopt-result.v1.json
@@@ -0,0 +1,68 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/avatar-adopt-result.v1.json",
++ "title": "MediaAvatarAdoptResult",
++ "description": "media.avatar-adopt-result@1: the answer of POST /internal/avatar-adopt on OpenVibe.Media: { ok: true, ref }, the active reference the slot now holds. A reference is released, never deleted, so Media keeps the history of the objects a person's picture moved through.",
++ "type": "object",
++ "required": [
++ "ok",
++ "ref"
++ ],
++ "properties": {
++ "ok": {
++ "const": true
++ },
++ "ref": {
++ "type": "object",
++ "required": [
++ "object_id",
++ "product",
++ "ref",
++ "created_at"
++ ],
++ "properties": {
++ "id": {
++ "type": [
++ "integer",
++ "string"
++ ]
++ },
++ "object_id": {
++ "type": "string",
++ "pattern": "^med_",
++ "description": "The avatar object (med_…) the slot points at."
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ },
++ "product": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{1,31}$",
++ "description": "The product whose profile holds the picture: network (users.avatar_url) or live (its own users.avatar_url, a channel banner)."
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 64,
++ "description": "The slot in that product: the person's id there, or the id and the slot (for example 42:banner)."
++ },
++ "created_at": {
++ "type": "string",
++ "description": "When the slot started pointing at the object."
++ },
++ "released_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "description": "Always null in this answer: the reference is the active one."
++ }
++ }
++ }
++ }
++}
ddiff --git a/contracts/media/avatar-release-request.v1.json b/contracts/media/avatar-release-request.v1.json
nnew file mode 100644
iindex 00000000..2f91c5a6
---- /dev/null
++++ b/contracts/media/avatar-release-request.v1.json
@@@ -0,0 +1,75 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/avatar-release-request.v1.json",
++ "title": "MediaAvatarReleaseRequest",
++ "description": "media.avatar-release-request@1: the body of POST /internal/avatar-release on OpenVibe.Media (capability media.avatar.release). The product says a slot no longer points at its picture (the person removed it), or that one object or one person's references are gone (an account deletion), and the object can then be deleted like any other. It names a slot (product and ref), an object_id or a subject; with none, Media answers 400 { ok: false, error }.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "object_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^med_"
++ },
++ "product": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^[a-z][a-z0-9-]{1,31}$"
++ },
++ "ref": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 64
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ }
++ },
++ "anyOf": [
++ {
++ "required": [
++ "object_id"
++ ],
++ "properties": {
++ "object_id": {
++ "type": "string"
++ }
++ }
++ },
++ {
++ "required": [
++ "product",
++ "ref"
++ ],
++ "properties": {
++ "product": {
++ "type": "string"
++ },
++ "ref": {
++ "type": "string"
++ }
++ }
++ },
++ {
++ "required": [
++ "subject"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string"
++ }
++ }
++ }
++ ]
++}
ddiff --git a/contracts/media/avatar-release-result.v1.json b/contracts/media/avatar-release-result.v1.json
nnew file mode 100644
iindex 00000000..9d7807a9
---- /dev/null
++++ b/contracts/media/avatar-release-result.v1.json
@@@ -0,0 +1,21 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/avatar-release-result.v1.json",
++ "title": "MediaAvatarReleaseResult",
++ "description": "media.avatar-release-result@1: the answer of POST /internal/avatar-release on OpenVibe.Media: { ok: true, released }, how many active references were released (0 when there were none: releasing twice is not an error).",
++ "type": "object",
++ "required": [
++ "ok",
++ "released"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "ok": {
++ "const": true
++ },
++ "released": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++}
ddiff --git a/fixtures/media.avatar-adopt-request/invalid/no-ref.json b/fixtures/media.avatar-adopt-request/invalid/no-ref.json
nnew file mode 100644
iindex 00000000..656ea12c
---- /dev/null
++++ b/fixtures/media.avatar-adopt-request/invalid/no-ref.json
@@@ -0,0 +1,4 @@
++{
++ "object_id": "med_01JC5Z8K2Q4X7V9B3N6M1R0T2Y",
++ "product": "network"
++}
ddiff --git a/fixtures/media.avatar-adopt-request/invalid/not-an-object.json b/fixtures/media.avatar-adopt-request/invalid/not-an-object.json
nnew file mode 100644
iindex 00000000..ad44947c
---- /dev/null
++++ b/fixtures/media.avatar-adopt-request/invalid/not-an-object.json
@@@ -0,0 +1,5 @@
++{
++ "object_id": "https://example.com/a.png",
++ "product": "network",
++ "ref": "42"
++}
ddiff --git a/fixtures/media.avatar-adopt-request/valid/live-banner.json b/fixtures/media.avatar-adopt-request/valid/live-banner.json
nnew file mode 100644
iindex 00000000..00cf229e
---- /dev/null
++++ b/fixtures/media.avatar-adopt-request/valid/live-banner.json
@@@ -0,0 +1,5 @@
++{
++ "object_id": "med_01JC5Z8K2Q4X7V9B3N6M1R0T2Y",
++ "product": "live",
++ "ref": "42:banner"
++}
ddiff --git a/fixtures/media.avatar-adopt-request/valid/network-profile.json b/fixtures/media.avatar-adopt-request/valid/network-profile.json
nnew file mode 100644
iindex 00000000..e4af8954
---- /dev/null
++++ b/fixtures/media.avatar-adopt-request/valid/network-profile.json
@@@ -0,0 +1,6 @@
++{
++ "object_id": "med_01JC5Z8K2Q4X7V9B3N6M1R0T2Y",
++ "product": "network",
++ "ref": "42",
++ "subject": "usr_01JC5Z8K2Q4X7V9B3N6M1R0T2Y"
++}
ddiff --git a/fixtures/media.avatar-adopt-result/invalid/no-ref.json b/fixtures/media.avatar-adopt-result/invalid/no-ref.json
nnew file mode 100644
iindex 00000000..0287aedd
---- /dev/null
++++ b/fixtures/media.avatar-adopt-result/invalid/no-ref.json
@@@ -0,0 +1,3 @@
++{
++ "ok": true
++}
ddiff --git a/fixtures/media.avatar-adopt-result/valid/active.json b/fixtures/media.avatar-adopt-result/valid/active.json
nnew file mode 100644
iindex 00000000..15d3901f
---- /dev/null
++++ b/fixtures/media.avatar-adopt-result/valid/active.json
@@@ -0,0 +1,12 @@
++{
++ "ok": true,
++ "ref": {
++ "id": 7,
++ "object_id": "med_01JC5Z8K2Q4X7V9B3N6M1R0T2Y",
++ "subject": null,
++ "product": "network",
++ "ref": "42",
++ "created_at": "2026-11-06 22:40:00",
++ "released_at": null
++ }
++}
ddiff --git a/fixtures/media.avatar-release-request/invalid/nothing.json b/fixtures/media.avatar-release-request/invalid/nothing.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/media.avatar-release-request/invalid/nothing.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/media.avatar-release-request/invalid/product-without-ref.json b/fixtures/media.avatar-release-request/invalid/product-without-ref.json
nnew file mode 100644
iindex 00000000..ae850f46
---- /dev/null
++++ b/fixtures/media.avatar-release-request/invalid/product-without-ref.json
@@@ -0,0 +1,3 @@
++{
++ "product": "network"
++}
ddiff --git a/fixtures/media.avatar-release-request/valid/object.json b/fixtures/media.avatar-release-request/valid/object.json
nnew file mode 100644
iindex 00000000..8495f9df
---- /dev/null
++++ b/fixtures/media.avatar-release-request/valid/object.json
@@@ -0,0 +1,3 @@
++{
++ "object_id": "med_01JC5Z8K2Q4X7V9B3N6M1R0T2Y"
++}
ddiff --git a/fixtures/media.avatar-release-request/valid/slot.json b/fixtures/media.avatar-release-request/valid/slot.json
nnew file mode 100644
iindex 00000000..a14825cb
---- /dev/null
++++ b/fixtures/media.avatar-release-request/valid/slot.json
@@@ -0,0 +1,4 @@
++{
++ "product": "network",
++ "ref": "42"
++}
ddiff --git a/fixtures/media.avatar-release-result/invalid/negative.json b/fixtures/media.avatar-release-result/invalid/negative.json
nnew file mode 100644
iindex 00000000..2344b0f1
---- /dev/null
++++ b/fixtures/media.avatar-release-result/invalid/negative.json
@@@ -0,0 +1,4 @@
++{
++ "ok": true,
++ "released": -1
++}
ddiff --git a/fixtures/media.avatar-release-result/valid/released.json b/fixtures/media.avatar-release-result/valid/released.json
nnew file mode 100644
iindex 00000000..5ee40241
---- /dev/null
++++ b/fixtures/media.avatar-release-result/valid/released.json
@@@ -0,0 +1,4 @@
++{
++ "ok": true,
++ "released": 1
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex 1e0d2d4e..7a1953c0 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -56333,6 +56333,229 @@
}
}
},
++ "media.avatar-adopt-request": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/avatar-adopt-request.v1.json",
++ "title": "MediaAvatarAdoptRequest",
++ "description": "media.avatar-adopt-request@1: the body of POST /internal/avatar-adopt on OpenVibe.Media (capability media.avatar.adopt). A product records that one of its profile slots points at an avatar object, so a cleanup can never delete the picture a working profile shows (incident 2026-11-06: eleven avatars were deleted with the public screenshot copies). Recording a slot releases the slot's previous reference in the same transaction. Ingest records the reference itself; this route is for a picture the product already holds. Refusals are { ok: false, error }: 400 without object_id, product or ref, 404 for an unknown object, 409 for an object that is not ready, 422 for an object that is not an avatar or belongs to someone else.",
++ "type": "object",
++ "required": [
++ "object_id",
++ "product",
++ "ref"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "object_id": {
++ "type": "string",
++ "pattern": "^med_",
++ "description": "The avatar object (med_…) the slot points at."
++ },
++ "product": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{1,31}$",
++ "description": "The product whose profile holds the picture: network (users.avatar_url) or live (its own users.avatar_url, a channel banner)."
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 64,
++ "description": "The slot in that product: the person's id there, or the id and the slot (for example 42:banner)."
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ }
++ }
++ }
++ },
++ "media.avatar-adopt-result": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/avatar-adopt-result.v1.json",
++ "title": "MediaAvatarAdoptResult",
++ "description": "media.avatar-adopt-result@1: the answer of POST /internal/avatar-adopt on OpenVibe.Media: { ok: true, ref }, the active reference the slot now holds. A reference is released, never deleted, so Media keeps the history of the objects a person's picture moved through.",
++ "type": "object",
++ "required": [
++ "ok",
++ "ref"
++ ],
++ "properties": {
++ "ok": {
++ "const": true
++ },
++ "ref": {
++ "type": "object",
++ "required": [
++ "object_id",
++ "product",
++ "ref",
++ "created_at"
++ ],
++ "properties": {
++ "id": {
++ "type": [
++ "integer",
++ "string"
++ ]
++ },
++ "object_id": {
++ "type": "string",
++ "pattern": "^med_",
++ "description": "The avatar object (med_…) the slot points at."
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ },
++ "product": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{1,31}$",
++ "description": "The product whose profile holds the picture: network (users.avatar_url) or live (its own users.avatar_url, a channel banner)."
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 64,
++ "description": "The slot in that product: the person's id there, or the id and the slot (for example 42:banner)."
++ },
++ "created_at": {
++ "type": "string",
++ "description": "When the slot started pointing at the object."
++ },
++ "released_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "description": "Always null in this answer: the reference is the active one."
++ }
++ }
++ }
++ }
++ }
++ },
++ "media.avatar-release-request": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/avatar-release-request.v1.json",
++ "title": "MediaAvatarReleaseRequest",
++ "description": "media.avatar-release-request@1: the body of POST /internal/avatar-release on OpenVibe.Media (capability media.avatar.release). The product says a slot no longer points at its picture (the person removed it), or that one object or one person's references are gone (an account deletion), and the object can then be deleted like any other. It names a slot (product and ref), an object_id or a subject; with none, Media answers 400 { ok: false, error }.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "object_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^med_"
++ },
++ "product": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^[a-z][a-z0-9-]{1,31}$"
++ },
++ "ref": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 64
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ }
++ },
++ "anyOf": [
++ {
++ "required": [
++ "object_id"
++ ],
++ "properties": {
++ "object_id": {
++ "type": "string"
++ }
++ }
++ },
++ {
++ "required": [
++ "product",
++ "ref"
++ ],
++ "properties": {
++ "product": {
++ "type": "string"
++ },
++ "ref": {
++ "type": "string"
++ }
++ }
++ },
++ {
++ "required": [
++ "subject"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string"
++ }
++ }
++ }
++ ]
++ }
++ },
++ "media.avatar-release-result": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/avatar-release-result.v1.json",
++ "title": "MediaAvatarReleaseResult",
++ "description": "media.avatar-release-result@1: the answer of POST /internal/avatar-release on OpenVibe.Media: { ok: true, released }, how many active references were released (0 when there were none: releasing twice is not an error).",
++ "type": "object",
++ "required": [
++ "ok",
++ "released"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "ok": {
++ "const": true
++ },
++ "released": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ }
++ },
"media.file-read-result": {
"version": "1.0.0",
"owner": "media",
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex 7458a8ed..6daed289 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.301.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 62b42b3e..85afb4bd 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.301.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 1a808636..6e0718ab 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.301.0",
-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 28534a14..0a7efb29 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.301.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 c66b14d5..c2bf39c4 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.301.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 f3535ab6..92ebd4bc 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.301.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 8e60460d..e7569cb2 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.301.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 6daf385b..2f8fd401 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.301.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 764e82d4..d19ab1a0 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.301.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 a81f5e8f..fe491e91 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.301.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 d17bf32a..1a48f811 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.301.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 471a1302..c4cd4716 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.301.0",
-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 8c38e3fd..6bba89ef 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.301.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 770984fb..eb0e7d93 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.301.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 a0b98f85..85c29ff6 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.301.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 db2aafcc..75a2f2b2 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.301.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 70461f57..e6660806 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -131,8 +131,8 @@
"service": "media",
"name": "OpenVibe.Media",
"origin": "https://openvibe.media",
-- "operations": 17,
-- "capabilities": 12
++ "operations": 19,
++ "capabilities": 14
},
{
"service": "media-hub",
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex ab2a49b0..c9af34a5 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.301.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 6fb74b0d..50d8d4e7 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.301.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 dbe50410..658c7c2f 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.301.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 8c1bb222..293f42ef 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.301.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.302.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"
@@@ -962,6 +962,62 @@
}
}
},
++ "/internal/avatar-adopt": {
++ "post": {
++ "operationId": "post_internal_avatar_adopt",
++ "summary": "A product (Network, Live) records that one of its profile slots points at an avatar object on openvibe.media, so a cleanup refuses to delete a picture that a working profile shows.",
++ "description": "**media.avatar.adopt** (internal): A product (Network, Live) records that one of its profile slots points at an avatar object on openvibe.media, so a cleanup refuses to delete a picture that a working profile shows. Recording a slot releases its previous reference.",
++ "tags": [
++ "media.avatar"
++ ],
++ "x-openvibe-capabilities": [
++ "media.avatar.adopt"
++ ],
++ "x-openvibe-visibility": [
++ "internal"
++ ],
++ "x-openvibe-quota-class": "standard",
++ "security": [
++ {
++ "openvibeToken": [
++ "media.avatar.adopt"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.avatar-adopt-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.avatar-adopt-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/internal/avatar-ingest": {
"post": {
"operationId": "post_internal_avatar_ingest",
@@@ -1018,6 +1074,62 @@
}
}
},
++ "/internal/avatar-release": {
++ "post": {
++ "operationId": "post_internal_avatar_release",
++ "summary": "A product says a profile slot no longer points at its picture, or that an object's or a person's references are gone, so the object can be deleted normally.",
++ "description": "**media.avatar.release** (internal): A product says a profile slot no longer points at its picture, or that an object's or a person's references are gone, so the object can be deleted normally.",
++ "tags": [
++ "media.avatar"
++ ],
++ "x-openvibe-capabilities": [
++ "media.avatar.release"
++ ],
++ "x-openvibe-visibility": [
++ "internal"
++ ],
++ "x-openvibe-quota-class": "standard",
++ "security": [
++ {
++ "openvibeToken": [
++ "media.avatar.release"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.avatar-release-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.avatar-release-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/internal/zones/{zone_id}": {
"get": {
"operationId": "get_internal_zones_zone_id",
@@@ -1966,6 +2078,109 @@
}
}
},
++ "media.avatar-adopt-request.v1": {
++ "title": "MediaAvatarAdoptRequest",
++ "description": "media.avatar-adopt-request@1: the body of POST /internal/avatar-adopt on OpenVibe.Media (capability media.avatar.adopt). A product records that one of its profile slots points at an avatar object, so a cleanup can never delete the picture a working profile shows (incident 2026-11-06: eleven avatars were deleted with the public screenshot copies). Recording a slot releases the slot's previous reference in the same transaction. Ingest records the reference itself; this route is for a picture the product already holds. Refusals are { ok: false, error }: 400 without object_id, product or ref, 404 for an unknown object, 409 for an object that is not ready, 422 for an object that is not an avatar or belongs to someone else.",
++ "type": "object",
++ "required": [
++ "object_id",
++ "product",
++ "ref"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "object_id": {
++ "type": "string",
++ "pattern": "^med_",
++ "description": "The avatar object (med_…) the slot points at."
++ },
++ "product": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{1,31}$",
++ "description": "The product whose profile holds the picture: network (users.avatar_url) or live (its own users.avatar_url, a channel banner)."
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 64,
++ "description": "The slot in that product: the person's id there, or the id and the slot (for example 42:banner)."
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ }
++ }
++ },
++ "media.avatar-adopt-result.v1": {
++ "title": "MediaAvatarAdoptResult",
++ "description": "media.avatar-adopt-result@1: the answer of POST /internal/avatar-adopt on OpenVibe.Media: { ok: true, ref }, the active reference the slot now holds. A reference is released, never deleted, so Media keeps the history of the objects a person's picture moved through.",
++ "type": "object",
++ "required": [
++ "ok",
++ "ref"
++ ],
++ "properties": {
++ "ok": {
++ "const": true
++ },
++ "ref": {
++ "type": "object",
++ "required": [
++ "object_id",
++ "product",
++ "ref",
++ "created_at"
++ ],
++ "properties": {
++ "id": {
++ "type": [
++ "integer",
++ "string"
++ ]
++ },
++ "object_id": {
++ "type": "string",
++ "pattern": "^med_",
++ "description": "The avatar object (med_…) the slot points at."
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ },
++ "product": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{1,31}$",
++ "description": "The product whose profile holds the picture: network (users.avatar_url) or live (its own users.avatar_url, a channel banner)."
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 64,
++ "description": "The slot in that product: the person's id there, or the id and the slot (for example 42:banner)."
++ },
++ "created_at": {
++ "type": "string",
++ "description": "When the slot started pointing at the object."
++ },
++ "released_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "description": "Always null in this answer: the reference is the active one."
++ }
++ }
++ }
++ }
++ },
"media.avatar-ingest-request.v1": {
"title": "MediaAvatarIngestRequest",
"description": "media.avatar-ingest-request@1: the body of POST /internal/avatar-ingest on OpenVibe.Media (capability media.avatar.ingest; Network calls it while adopting an avatar a person pointed at somewhere else on the web). Media fetches the URL once through its egress guard (https only, public addresses only, at most 8 MB and 10 s), re-encodes it to a 512×512 WebP and stores it as an unlisted screenshot paste owned by user_id, so no OpenVibe site ever serves or stores a third-party address. Refusals are { ok: false, error } (400 without url or user_id, 422 when the link is not a usable picture).",
@@@ -2032,6 +2247,98 @@
}
}
},
++ "media.avatar-release-request.v1": {
++ "title": "MediaAvatarReleaseRequest",
++ "description": "media.avatar-release-request@1: the body of POST /internal/avatar-release on OpenVibe.Media (capability media.avatar.release). The product says a slot no longer points at its picture (the person removed it), or that one object or one person's references are gone (an account deletion), and the object can then be deleted like any other. It names a slot (product and ref), an object_id or a subject; with none, Media answers 400 { ok: false, error }.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "object_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^med_"
++ },
++ "product": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^[a-z][a-z0-9-]{1,31}$"
++ },
++ "ref": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 64
++ },
++ "subject": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^usr_",
++ "description": "The person (usr_…) when the product knows it; Media refuses an object owned by someone else."
++ }
++ },
++ "anyOf": [
++ {
++ "required": [
++ "object_id"
++ ],
++ "properties": {
++ "object_id": {
++ "type": "string"
++ }
++ }
++ },
++ {
++ "required": [
++ "product",
++ "ref"
++ ],
++ "properties": {
++ "product": {
++ "type": "string"
++ },
++ "ref": {
++ "type": "string"
++ }
++ }
++ },
++ {
++ "required": [
++ "subject"
++ ],
++ "properties": {
++ "subject": {
++ "type": "string"
++ }
++ }
++ }
++ ]
++ },
++ "media.avatar-release-result.v1": {
++ "title": "MediaAvatarReleaseResult",
++ "description": "media.avatar-release-result@1: the answer of POST /internal/avatar-release on OpenVibe.Media: { ok: true, released }, how many active references were released (0 when there were none: releasing twice is not an error).",
++ "type": "object",
++ "required": [
++ "ok",
++ "released"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "ok": {
++ "const": true
++ },
++ "released": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
"media.file-read-result.v1": {
"title": "MediaFileReadResult",
"description": "media.file-read-result@1: answers of media.object.read on OpenVibe.Media. GET /api/v1/:app/files/:key → media.file@1 (the file's metadata; 404 when it is not the tenant's); GET /f/:key → the bytes, with Content-Type and Range (a sandbox file only through its signed URL).",
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex ff5d5326..cb0e0791 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.301.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.302.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/news.json b/generated/openapi/news.json
iindex 0a8c45c7..2b09c498 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.301.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 cdc13ec4..ad2937c6 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.301.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 ac8555bb..0af4b9ad 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.301.0",
-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 02268bee..96262108 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.301.0",
-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 8ebd09ea..51151dfb 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.301.0",
-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 ac15a89c..1f424b68 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.301.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 0e3715fa..d2ff1b99 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.301.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 c830d7c2..7241bead 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.301.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 f36d2d98..29c2ea7c 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.301.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 2b0b626c..8c20ea97 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.301.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 2e01815f..605b2497 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.301.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 191f4e80..5b157fdf 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.301.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 3fe5dcf4..3b27b73c 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.301.0",
-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 99cb5106..7e268977 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.301.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 10efbbfa..e015b5a9 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.301.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 5ba6e86d..7f5a6c1c 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.301.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 90c6e442..2b192c3e 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.301.0",
-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 29d6f620..b8d4057d 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.301.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 b0295894..c239dc5e 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.301.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 b49e10ee..45edef6b 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.301.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 4e9faa26..f1ddca58 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.301.0",
-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.301.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.302.0",
++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.302.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 e66a4157..75fb08e6 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -203885,6 +203885,98 @@ export interface MediaAvatarIngestResult {
bytes: number;
}
++/** [email protected] (owner: media) */
++/**
++ * media.avatar-adopt-request@1: the body of POST /internal/avatar-adopt on OpenVibe.Media (capability media.avatar.adopt). A product records that one of its profile slots points at an avatar object, so a cleanup can never delete the picture a working profile shows (incident 2026-11-06: eleven avatars were deleted with the public screenshot copies). Recording a slot releases the slot's previous reference in the same transaction. Ingest records the reference itself; this route is for a picture the product already holds. Refusals are { ok: false, error }: 400 without object_id, product or ref, 404 for an unknown object, 409 for an object that is not ready, 422 for an object that is not an avatar or belongs to someone else.
++ */
++export interface MediaAvatarAdoptRequest {
++ /**
++ * The avatar object (med_…) the slot points at.
++ */
++ object_id: string;
++ /**
++ * The product whose profile holds the picture: network (users.avatar_url) or live (its own users.avatar_url, a channel banner).
++ */
++ product: string;
++ /**
++ * The slot in that product: the person's id there, or the id and the slot (for example 42:banner).
++ */
++ ref: string;
++ /**
++ * The person (usr_…) when the product knows it; Media refuses an object owned by someone else.
++ */
++ subject?: string | null;
++}
++
++/** [email protected] (owner: media) */
++/**
++ * media.avatar-adopt-result@1: the answer of POST /internal/avatar-adopt on OpenVibe.Media: { ok: true, ref }, the active reference the slot now holds. A reference is released, never deleted, so Media keeps the history of the objects a person's picture moved through.
++ */
++export interface MediaAvatarAdoptResult {
++ ok: true;
++ ref: {
++ id?: number | string;
++ /**
++ * The avatar object (med_…) the slot points at.
++ */
++ object_id: string;
++ /**
++ * The person (usr_…) when the product knows it; Media refuses an object owned by someone else.
++ */
++ subject?: string | null;
++ /**
++ * The product whose profile holds the picture: network (users.avatar_url) or live (its own users.avatar_url, a channel banner).
++ */
++ product: string;
++ /**
++ * The slot in that product: the person's id there, or the id and the slot (for example 42:banner).
++ */
++ ref: string;
++ /**
++ * When the slot started pointing at the object.
++ */
++ created_at: string;
++ /**
++ * Always null in this answer: the reference is the active one.
++ */
++ released_at?: string | null;
++ };
++}
++
++/** [email protected] (owner: media) */
++/**
++ * media.avatar-release-request@1: the body of POST /internal/avatar-release on OpenVibe.Media (capability media.avatar.release). The product says a slot no longer points at its picture (the person removed it), or that one object or one person's references are gone (an account deletion), and the object can then be deleted like any other. It names a slot (product and ref), an object_id or a subject; with none, Media answers 400 { ok: false, error }.
++ */
++export type MediaAvatarReleaseRequest = (
++ | {
++ object_id: string;
++ }
++ | {
++ product: string;
++ ref: string;
++ }
++ | {
++ subject: string;
++ }
++) & {
++ object_id?: string | null;
++ product?: string | null;
++ ref?: string | null;
++ /**
++ * The person (usr_…) when the product knows it; Media refuses an object owned by someone else.
++ */
++ subject?: string | null;
++};
++
++/** [email protected] (owner: media) */
++/**
++ * media.avatar-release-result@1: the answer of POST /internal/avatar-release on OpenVibe.Media: { ok: true, released }, how many active references were released (0 when there were none: releasing twice is not an error).
++ */
++export interface MediaAvatarReleaseResult {
++ ok: true;
++ released: number;
++}
++
/** [email protected] (owner: media) */
/**
* media.file-read-result@1: answers of media.object.read on OpenVibe.Media. GET /api/v1/:app/files/:key → media.file@1 (the file's metadata; 404 when it is not the tenant's); GET /f/:key → the bytes, with Content-Type and Range (a sandbox file only through its signed URL).
ddiff --git a/manifests/capabilities/media.avatar.adopt.json b/manifests/capabilities/media.avatar.adopt.json
nnew file mode 100644
iindex 00000000..452abd98
---- /dev/null
++++ b/manifests/capabilities/media.avatar.adopt.json
@@@ -0,0 +1,21 @@
++{
++ "id": "media.avatar.adopt",
++ "version": "1.0",
++ "owner": "media",
++ "status": "active",
++ "visibility": "internal",
++ "description": "A product (Network, Live) records that one of its profile slots points at an avatar object on openvibe.media, so a cleanup refuses to delete a picture that a working profile shows. Recording a slot releases its previous reference.",
++ "permissions": [
++ "avatars:refs"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /internal/avatar-adopt"
++ ],
++ "inputSchema": "media.avatar-adopt-request@1",
++ "outputSchema": "media.avatar-adopt-result@1"
++}
ddiff --git a/manifests/capabilities/media.avatar.release.json b/manifests/capabilities/media.avatar.release.json
nnew file mode 100644
iindex 00000000..d214a8da
---- /dev/null
++++ b/manifests/capabilities/media.avatar.release.json
@@@ -0,0 +1,21 @@
++{
++ "id": "media.avatar.release",
++ "version": "1.0",
++ "owner": "media",
++ "status": "active",
++ "visibility": "internal",
++ "description": "A product says a profile slot no longer points at its picture, or that an object's or a person's references are gone, so the object can be deleted normally.",
++ "permissions": [
++ "avatars:refs"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /internal/avatar-release"
++ ],
++ "inputSchema": "media.avatar-release-request@1",
++ "outputSchema": "media.avatar-release-result@1"
++}
ddiff --git a/manifests/services/media.json b/manifests/services/media.json
iindex f3943a8e..64d5248a 100644
---- a/manifests/services/media.json
++++ b/manifests/services/media.json
@@@ -40,7 +40,9 @@
},
"capabilities": [
"media.access_key.manage",
++ "media.avatar.adopt",
"media.avatar.ingest",
++ "media.avatar.release",
"media.derivative.create",
"media.derivative.read",
"media.lifecycle.read",
ddiff --git a/package.json b/package.json
iindex 5a023435..99fdb35b 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.301.0",
++ "version": "0.302.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",