openvibers/openvibe.contracts Commits

Describe Media multipart uploads in contracts and OpenAPI (#377)

OP OpenVibers committed 4 days ago · 2de4d3ce7c · 72 files, +1437 −110

* Describe Media multipart uploads in contracts and OpenAPI

* Merge main

* 0.359.0: on top of main (Media multipart uploads in contracts and OpenAPI)

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex bf670cb3..6ca44a51 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,5 +1,9 @@
# Changelog
++## 0.359.0 — 2026-11-09
++
++- Media multipart uploads in contracts and OpenAPI
++
## 0.358.0 — 2026-11-09
- Chat view preference (bubbles or room)
ddiff --git a/contracts/capabilities/capability.v1.json b/contracts/capabilities/capability.v1.json
iindex 33751258..552e10c5 100644
---- a/contracts/capabilities/capability.v1.json
++++ b/contracts/capabilities/capability.v1.json
@@@ -20,6 +20,7 @@
"quotaClass": { "type": "string" },
"events": { "type": "array", "items": { "type": "string" } },
"implementedBy": { "type": "array", "items": { "type": "string" }, "description": "Current route(s) that perform this action today, e.g. 'POST /api/v1/:app/files'." },
++ "routeSchemas": { "type": "object", "description": "Input and output contract overrides for a route when one capability covers several operations.", "additionalProperties": { "type": "object", "additionalProperties": false, "properties": { "inputSchema": { "type": "string" }, "outputSchema": { "type": "string" } } } },
"sensitive": { "type": "boolean", "description": "The action has an external side effect (money, sending as the person, publishing, applying, deleting, physical control): an agent needs its owner's confirmation unless a standing rule covers it (roadmap WS-Z2)." }
}
}
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex 44f05503..7e37b6bf 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -365,6 +365,51 @@
"compatibility": "backward",
"status": "active"
},
++ {
++ "id": "media.upload",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/upload.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "media.upload-create",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/upload-create.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "media.upload-init",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/upload-init.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "media.upload-part",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/upload-part.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "media.upload-complete",
++ "version": "1.0.0",
++ "owner": "media",
++ "schema": "media/upload-complete.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
{
"id": "search.index-document",
"version": "1.0.0",
ddiff --git a/contracts/media/upload-complete.v1.json b/contracts/media/upload-complete.v1.json
nnew file mode 100644
iindex 00000000..8f39bb0b
---- /dev/null
++++ b/contracts/media/upload-complete.v1.json
@@@ -0,0 +1,12 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload-complete.v1.json",
++ "title": "MediaUploadComplete",
++ "description": "Complete an upload after all parts arrive. Media assembles the bytes, verifies the optional hashes and content type, and returns the ready object.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "content_hash": { "type": "string", "pattern": "^[a-fA-F0-9]{64}$" },
++ "parts": { "type": "array", "items": { "type": "object", "required": ["part_number", "sha256"], "additionalProperties": false, "properties": { "part_number": { "type": "integer", "minimum": 1 }, "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" } } } }
++ }
++}
ddiff --git a/contracts/media/upload-create.v1.json b/contracts/media/upload-create.v1.json
nnew file mode 100644
iindex 00000000..ee1acc1d
---- /dev/null
++++ b/contracts/media/upload-create.v1.json
@@@ -0,0 +1,22 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload-create.v1.json",
++ "title": "MediaUploadCreate",
++ "description": "Create a Media object with a multipart upload session. The caller needs media.object.upload for the tenant namespace; the upload token then authorizes parts and completion.",
++ "type": "object",
++ "required": ["kind", "size_bytes", "multipart"],
++ "additionalProperties": true,
++ "properties": {
++ "kind": { "type": "string", "enum": ["vod", "clip", "file", "thumbnail", "screenshot", "avatar", "asset"] },
++ "size_bytes": { "type": "integer", "minimum": 1 },
++ "multipart": { "const": true },
++ "part_size": { "type": "integer", "minimum": 5242880, "description": "Use 8388608 for 8 MiB parts; the service may increase it to stay below 10000 parts." },
++ "visibility": { "type": "string", "enum": ["public", "unlisted", "private"] },
++ "mime_type": { "type": "string" },
++ "filename": { "type": "string" },
++ "content_hash": { "type": "string", "pattern": "^[a-fA-F0-9]{64}$" },
++ "namespace": { "type": "string" },
++ "user_id": { "type": ["string", "integer"] },
++ "metadata": { "type": "object" }
++ }
++}
ddiff --git a/contracts/media/upload-init.v1.json b/contracts/media/upload-init.v1.json
nnew file mode 100644
iindex 00000000..b5a0b961
---- /dev/null
++++ b/contracts/media/upload-init.v1.json
@@@ -0,0 +1,24 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload-init.v1.json",
++ "title": "MediaUploadInit",
++ "description": "The object and its presigned multipart session after POST /api/v2/:app/objects. Send parts to part_url_template in any order, then complete.",
++ "type": "object",
++ "required": ["id", "object", "upload"],
++ "additionalProperties": true,
++ "properties": {
++ "id": { "type": "string" },
++ "object": { "$ref": "object.v1.json" },
++ "upload": {
++ "type": "object",
++ "required": ["method", "multipart", "complete_url"],
++ "additionalProperties": true,
++ "properties": {
++ "method": { "const": "multipart" },
++ "multipart": { "$ref": "upload.v1.json" },
++ "complete_url": { "type": "string" },
++ "multipart_url": { "type": "string" }
++ }
++ }
++ }
++}
ddiff --git a/contracts/media/upload-part.v1.json b/contracts/media/upload-part.v1.json
nnew file mode 100644
iindex 00000000..b38f244f
---- /dev/null
++++ b/contracts/media/upload-part.v1.json
@@@ -0,0 +1,14 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload-part.v1.json",
++ "title": "MediaUploadPart",
++ "description": "A verified part received by Media. PUT the raw bytes to the presigned URL; X-Content-SHA256 is optional.",
++ "type": "object",
++ "required": ["part_number", "size_bytes", "sha256"],
++ "additionalProperties": true,
++ "properties": {
++ "part_number": { "type": "integer", "minimum": 1 },
++ "size_bytes": { "type": "integer", "minimum": 1 },
++ "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
++ }
++}
ddiff --git a/contracts/media/upload.v1.json b/contracts/media/upload.v1.json
nnew file mode 100644
iindex 00000000..56003846
---- /dev/null
++++ b/contracts/media/upload.v1.json
@@@ -0,0 +1,27 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload.v1.json",
++ "title": "MediaUpload",
++ "description": "media.upload@1: a resumable multipart session. Store upload_id and object_id to resume after a reload; GET status lists received and missing parts. URLs contain a short-lived upload token and should not be logged.",
++ "type": "object",
++ "required": ["upload_id", "object_id", "status", "part_size", "total_size", "parts_expected", "expires_at", "created_at"],
++ "additionalProperties": true,
++ "properties": {
++ "upload_id": { "type": "string", "pattern": "^mup_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "object_id": { "type": "string", "pattern": "^med_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "status": { "type": "string", "enum": ["active", "completing", "completed", "aborted", "expired"] },
++ "part_size": { "type": "integer", "minimum": 5242880 },
++ "total_size": { "type": "integer", "minimum": 1 },
++ "parts_expected": { "type": "integer", "minimum": 1, "maximum": 10000 },
++ "expires_at": { "type": "string", "format": "date-time" },
++ "created_at": { "type": "string" },
++ "parts": { "type": "array", "items": { "$ref": "upload-part.v1.json" } },
++ "received_bytes": { "type": "integer", "minimum": 0 },
++ "missing": { "type": "array", "items": { "type": "integer", "minimum": 1 } },
++ "token": { "type": "string" },
++ "part_url_template": { "type": "string" },
++ "status_url": { "type": "string" },
++ "complete_url": { "type": "string" },
++ "abort_url": { "type": "string" }
++ }
++}
ddiff --git a/fixtures/media.upload-complete/invalid/basic.json b/fixtures/media.upload-complete/invalid/basic.json
nnew file mode 100644
iindex 00000000..628f5142
---- /dev/null
++++ b/fixtures/media.upload-complete/invalid/basic.json
@@@ -0,0 +1,5 @@
++{
++ "parts": [
++ {}
++ ]
++}
ddiff --git a/fixtures/media.upload-complete/valid/basic.json b/fixtures/media.upload-complete/valid/basic.json
nnew file mode 100644
iindex 00000000..71e4553b
---- /dev/null
++++ b/fixtures/media.upload-complete/valid/basic.json
@@@ -0,0 +1,8 @@
++{
++ "parts": [
++ {
++ "part_number": 1,
++ "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
++ }
++ ]
++}
ddiff --git a/fixtures/media.upload-create/invalid/basic.json b/fixtures/media.upload-create/invalid/basic.json
nnew file mode 100644
iindex 00000000..839c5524
---- /dev/null
++++ b/fixtures/media.upload-create/invalid/basic.json
@@@ -0,0 +1,5 @@
++{
++ "kind": "file",
++ "size_bytes": 0,
++ "multipart": false
++}
ddiff --git a/fixtures/media.upload-create/valid/basic.json b/fixtures/media.upload-create/valid/basic.json
nnew file mode 100644
iindex 00000000..47fa0e04
---- /dev/null
++++ b/fixtures/media.upload-create/valid/basic.json
@@@ -0,0 +1,7 @@
++{
++ "kind": "file",
++ "size_bytes": 8388608,
++ "multipart": true,
++ "part_size": 8388608,
++ "visibility": "private"
++}
ddiff --git a/fixtures/media.upload-init/invalid/basic.json b/fixtures/media.upload-init/invalid/basic.json
nnew file mode 100644
iindex 00000000..e5e1858c
---- /dev/null
++++ b/fixtures/media.upload-init/invalid/basic.json
@@@ -0,0 +1,6 @@
++{
++ "id": "med_01K5WZX7S7Q4D2B8N3M6V1C9TZ",
++ "upload": {
++ "method": "multipart"
++ }
++}
ddiff --git a/fixtures/media.upload-init/valid/basic.json b/fixtures/media.upload-init/valid/basic.json
nnew file mode 100644
iindex 00000000..dbe04f8a
---- /dev/null
++++ b/fixtures/media.upload-init/valid/basic.json
@@@ -0,0 +1,66 @@
++{
++ "id": "med_01K5WZX7S7Q4D2B8N3M6V1C9TZ",
++ "object": {
++ "id": "med_01K5WZX7S7Q4D2B8N3M6V1C9TZ",
++ "media_ref": {
++ "media_id": "med_01K5WZX7S7Q4D2B8N3M6V1C9TZ"
++ },
++ "legacy_ref": null,
++ "app_id": "prj_01K5WZX7S7Q4D2B8N3M6V1C9TA",
++ "namespace": "app.prj_01K5WZX7S7Q4D2B8N3M6V1C9TA.avatars",
++ "kind": "file",
++ "owner": {
++ "subject": null,
++ "app": "prj_01K5WZX7S7Q4D2B8N3M6V1C9TA",
++ "user_id": null
++ },
++ "visibility": "private",
++ "lifecycle_status": "ready",
++ "mime_type": "image/png",
++ "size_bytes": 48213,
++ "content_hash": "3f1c0b8e2a9d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f1e0d9c8b7a6f5e4d3c2b",
++ "metadata": {
++ "filename": "a.png"
++ },
++ "held": false,
++ "readiness": {
++ "metadata": true,
++ "bytes_verified": true,
++ "playable": false,
++ "reason": "not_playback_kind"
++ },
++ "public_url": null,
++ "created_at": "2026-09-26 08:00:00",
++ "updated_at": "2026-09-26 08:00:01",
++ "deleted_at": null,
++ "locations": [
++ {
++ "provider": "local",
++ "storage_class": "hot",
++ "state": "present",
++ "size_bytes": 48213,
++ "verified_at": "2026-09-26 08:00:01",
++ "canonical": true
++ }
++ ]
++ },
++ "upload": {
++ "method": "multipart",
++ "complete_url": "https://openvibe.media/api/v2/demo/objects/med_01K5WZX7S7Q4D2B8N3M6V1C9TZ/complete",
++ "multipart": {
++ "upload_id": "mup_01K5WZX7S7Q4D2B8N3M6V1C9TZ",
++ "object_id": "med_01K5WZX7S7Q4D2B8N3M6V1C9TZ",
++ "status": "active",
++ "part_size": 8388608,
++ "total_size": 8388608,
++ "parts_expected": 1,
++ "expires_at": "2026-11-10T00:00:00Z",
++ "created_at": "2026-11-09 00:00:00",
++ "parts": [],
++ "received_bytes": 0,
++ "missing": [
++ 1
++ ]
++ }
++ }
++}
ddiff --git a/fixtures/media.upload-part/invalid/basic.json b/fixtures/media.upload-part/invalid/basic.json
nnew file mode 100644
iindex 00000000..91be20f5
---- /dev/null
++++ b/fixtures/media.upload-part/invalid/basic.json
@@@ -0,0 +1,5 @@
++{
++ "part_number": 0,
++ "size_bytes": 0,
++ "sha256": "bad"
++}
ddiff --git a/fixtures/media.upload-part/valid/basic.json b/fixtures/media.upload-part/valid/basic.json
nnew file mode 100644
iindex 00000000..0a8f887f
---- /dev/null
++++ b/fixtures/media.upload-part/valid/basic.json
@@@ -0,0 +1,5 @@
++{
++ "part_number": 1,
++ "size_bytes": 8388608,
++ "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
++}
ddiff --git a/fixtures/media.upload/invalid/basic.json b/fixtures/media.upload/invalid/basic.json
nnew file mode 100644
iindex 00000000..a0866813
---- /dev/null
++++ b/fixtures/media.upload/invalid/basic.json
@@@ -0,0 +1,3 @@
++{
++ "upload_id": "wrong"
++}
ddiff --git a/fixtures/media.upload/valid/basic.json b/fixtures/media.upload/valid/basic.json
nnew file mode 100644
iindex 00000000..50fc6780
---- /dev/null
++++ b/fixtures/media.upload/valid/basic.json
@@@ -0,0 +1,15 @@
++{
++ "upload_id": "mup_01K5WZX7S7Q4D2B8N3M6V1C9TZ",
++ "object_id": "med_01K5WZX7S7Q4D2B8N3M6V1C9TZ",
++ "status": "active",
++ "part_size": 8388608,
++ "total_size": 8388608,
++ "parts_expected": 1,
++ "expires_at": "2026-11-10T00:00:00Z",
++ "created_at": "2026-11-09 00:00:00",
++ "parts": [],
++ "received_bytes": 0,
++ "missing": [
++ 1
++ ]
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex 49af0e38..17a331a4 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -2491,6 +2491,22 @@
},
"description": "Current route(s) that perform this action today, e.g. 'POST /api/v1/:app/files'."
},
++ "routeSchemas": {
++ "type": "object",
++ "description": "Input and output contract overrides for a route when one capability covers several operations.",
++ "additionalProperties": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "inputSchema": {
++ "type": "string"
++ },
++ "outputSchema": {
++ "type": "string"
++ }
++ }
++ }
++ },
"sensitive": {
"type": "boolean",
"description": "The action has an external side effect (money, sending as the person, publishing, applying, deleting, physical control): an agent needs its owner's confirmation unless a standing rule covers it (roadmap WS-Z2)."
@@@ -4249,6 +4265,296 @@
}
}
},
++ "media.upload": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload.v1.json",
++ "title": "MediaUpload",
++ "description": "media.upload@1: a resumable multipart session. Store upload_id and object_id to resume after a reload; GET status lists received and missing parts. URLs contain a short-lived upload token and should not be logged.",
++ "type": "object",
++ "required": [
++ "upload_id",
++ "object_id",
++ "status",
++ "part_size",
++ "total_size",
++ "parts_expected",
++ "expires_at",
++ "created_at"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "upload_id": {
++ "type": "string",
++ "pattern": "^mup_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "object_id": {
++ "type": "string",
++ "pattern": "^med_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "status": {
++ "type": "string",
++ "enum": [
++ "active",
++ "completing",
++ "completed",
++ "aborted",
++ "expired"
++ ]
++ },
++ "part_size": {
++ "type": "integer",
++ "minimum": 5242880
++ },
++ "total_size": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "parts_expected": {
++ "type": "integer",
++ "minimum": 1,
++ "maximum": 10000
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "created_at": {
++ "type": "string"
++ },
++ "parts": {
++ "type": "array",
++ "items": {
++ "$ref": "upload-part.v1.json"
++ }
++ },
++ "received_bytes": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "missing": {
++ "type": "array",
++ "items": {
++ "type": "integer",
++ "minimum": 1
++ }
++ },
++ "token": {
++ "type": "string"
++ },
++ "part_url_template": {
++ "type": "string"
++ },
++ "status_url": {
++ "type": "string"
++ },
++ "complete_url": {
++ "type": "string"
++ },
++ "abort_url": {
++ "type": "string"
++ }
++ }
++ }
++ },
++ "media.upload-create": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload-create.v1.json",
++ "title": "MediaUploadCreate",
++ "description": "Create a Media object with a multipart upload session. The caller needs media.object.upload for the tenant namespace; the upload token then authorizes parts and completion.",
++ "type": "object",
++ "required": [
++ "kind",
++ "size_bytes",
++ "multipart"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "kind": {
++ "type": "string",
++ "enum": [
++ "vod",
++ "clip",
++ "file",
++ "thumbnail",
++ "screenshot",
++ "avatar",
++ "asset"
++ ]
++ },
++ "size_bytes": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "multipart": {
++ "const": true
++ },
++ "part_size": {
++ "type": "integer",
++ "minimum": 5242880,
++ "description": "Use 8388608 for 8 MiB parts; the service may increase it to stay below 10000 parts."
++ },
++ "visibility": {
++ "type": "string",
++ "enum": [
++ "public",
++ "unlisted",
++ "private"
++ ]
++ },
++ "mime_type": {
++ "type": "string"
++ },
++ "filename": {
++ "type": "string"
++ },
++ "content_hash": {
++ "type": "string",
++ "pattern": "^[a-fA-F0-9]{64}$"
++ },
++ "namespace": {
++ "type": "string"
++ },
++ "user_id": {
++ "type": [
++ "string",
++ "integer"
++ ]
++ },
++ "metadata": {
++ "type": "object"
++ }
++ }
++ }
++ },
++ "media.upload-init": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload-init.v1.json",
++ "title": "MediaUploadInit",
++ "description": "The object and its presigned multipart session after POST /api/v2/:app/objects. Send parts to part_url_template in any order, then complete.",
++ "type": "object",
++ "required": [
++ "id",
++ "object",
++ "upload"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "id": {
++ "type": "string"
++ },
++ "object": {
++ "$ref": "object.v1.json"
++ },
++ "upload": {
++ "type": "object",
++ "required": [
++ "method",
++ "multipart",
++ "complete_url"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "method": {
++ "const": "multipart"
++ },
++ "multipart": {
++ "$ref": "upload.v1.json"
++ },
++ "complete_url": {
++ "type": "string"
++ },
++ "multipart_url": {
++ "type": "string"
++ }
++ }
++ }
++ }
++ }
++ },
++ "media.upload-part": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload-part.v1.json",
++ "title": "MediaUploadPart",
++ "description": "A verified part received by Media. PUT the raw bytes to the presigned URL; X-Content-SHA256 is optional.",
++ "type": "object",
++ "required": [
++ "part_number",
++ "size_bytes",
++ "sha256"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "part_number": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "size_bytes": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "sha256": {
++ "type": "string",
++ "pattern": "^[a-f0-9]{64}$"
++ }
++ }
++ }
++ },
++ "media.upload-complete": {
++ "version": "1.0.0",
++ "owner": "media",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/media/upload-complete.v1.json",
++ "title": "MediaUploadComplete",
++ "description": "Complete an upload after all parts arrive. Media assembles the bytes, verifies the optional hashes and content type, and returns the ready object.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "content_hash": {
++ "type": "string",
++ "pattern": "^[a-fA-F0-9]{64}$"
++ },
++ "parts": {
++ "type": "array",
++ "items": {
++ "type": "object",
++ "required": [
++ "part_number",
++ "sha256"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "part_number": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "sha256": {
++ "type": "string",
++ "pattern": "^[a-f0-9]{64}$"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"search.index-document": {
"version": "1.0.0",
"owner": "search",
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex db56d0f9..b02f60ea 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.358.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 4b5ddfa1..d8eaba9e 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.358.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 42d29b38..a252a00e 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.358.0",
-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 b3afd34d..fd70e123 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.358.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 2bbc8f4b..be19d7b2 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.358.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 91079831..03ce46e4 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.358.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 21069961..b1ee4954 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.358.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 2e0dfeb5..af38aabe 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.358.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 705fad25..8c2b465c 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.358.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 6a3b9b88..26f418ba 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.358.0",
-- "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 eb0536d6..09ee4007 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.358.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 0f026db0..37d4b4d6 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.358.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 4657b419..4ac6fc74 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.358.0",
-- "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 36630848..b312c0b1 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.358.0",
-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 5d1c66cf..df721994 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.358.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 f5660268..266acec5 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.358.0",
-- "description": "Routes of OpenVibe.Exchange as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Exchange as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 41de4e5a..759f26ae 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.358.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 528b908b..bbc0928f 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.358.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 e09f67a9..99a3766d 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.358.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 457e2a3a..da581977 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -159,7 +159,7 @@
"service": "media",
"name": "OpenVibe.Media",
"origin": "https://openvibe.media",
-- "operations": 19,
++ "operations": 24,
"capabilities": 14
},
{
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex 58c5b1f8..3d6ee465 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.358.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 1741f560..22397831 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.358.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 bf519fc0..d4e80019 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.358.0",
-- "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 30447609..736c0628 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.358.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 ae13c182..c227567b 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.358.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.359.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"
@@@ -662,30 +662,393 @@
}
}
}
++ },
++ "post": {
++ "operationId": "post_api_v2_app_objects",
++ "summary": "Upload a file object into an app namespace.",
++ "description": "**media.object.upload** (public): Upload a file object into an app namespace.",
++ "tags": [
++ "media.object"
++ ],
++ "x-openvibe-capabilities": [
++ "media.object.upload"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "media-upload",
++ "security": [
++ {
++ "openvibeToken": [
++ "media.object.upload"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.upload-create.v1"
++ }
++ }
++ }
++ },
++ "parameters": [
++ {
++ "name": "app",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.upload-init.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v2/{app}/objects/{id}": {
++ "delete": {
++ "operationId": "delete_api_v2_app_objects_id",
++ "summary": "Delete an object in a namespace (the delete verb of Media's namespace grants, WS-G task 2): a soft delete that keeps the bytes for the retention period, and the restore that undoes it within that peri",
++ "description": "**media.object.delete** (public): Delete an object in a namespace (the delete verb of Media's namespace grants, WS-G task 2): a soft delete that keeps the bytes for the retention period, and the restore that undoes it within that period (checked against the namespace's quotas); refused while the object is under a retention hold. The same verb guards the v1 file delete (DELETE /api/v1/:app/files/:key). media.object.upload also grants it, for tokens issued before the verbs were split, unless the namespace's policy is strict_verbs.",
++ "tags": [
++ "media.object"
++ ],
++ "x-openvibe-capabilities": [
++ "media.object.delete"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "media-write",
++ "security": [
++ {
++ "openvibeToken": [
++ "media.object.delete"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "app",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ },
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.object.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v2/{app}/objects/{id}/multipart/{uploadId}": {
++ "delete": {
++ "operationId": "delete_api_v2_app_objects_id_multipart_uploadId",
++ "summary": "Upload a file object into an app namespace.",
++ "description": "**media.object.upload** (public): Upload a file object into an app namespace.",
++ "tags": [
++ "media.object"
++ ],
++ "x-openvibe-capabilities": [
++ "media.object.upload"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "media-upload",
++ "security": [
++ {
++ "openvibeToken": [
++ "media.object.upload"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "app",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ },
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ },
++ {
++ "name": "uploadId",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.upload.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ },
++ "get": {
++ "operationId": "get_api_v2_app_objects_id_multipart_uploadId",
++ "summary": "Upload a file object into an app namespace.",
++ "description": "**media.object.upload** (public): Upload a file object into an app namespace.",
++ "tags": [
++ "media.object"
++ ],
++ "x-openvibe-capabilities": [
++ "media.object.upload"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "media-upload",
++ "security": [
++ {
++ "openvibeToken": [
++ "media.object.upload"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "app",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ },
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ },
++ {
++ "name": "uploadId",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.upload.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v2/{app}/objects/{id}/multipart/{uploadId}/complete": {
++ "post": {
++ "operationId": "post_api_v2_app_objects_id_multipart_uploadId_complete",
++ "summary": "Upload a file object into an app namespace.",
++ "description": "**media.object.upload** (public): Upload a file object into an app namespace.",
++ "tags": [
++ "media.object"
++ ],
++ "x-openvibe-capabilities": [
++ "media.object.upload"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "media-upload",
++ "security": [
++ {
++ "openvibeToken": [
++ "media.object.upload"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.upload-complete.v1"
++ }
++ }
++ }
++ },
++ "parameters": [
++ {
++ "name": "app",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ },
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ },
++ {
++ "name": "uploadId",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/media.object.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
}
},
-- "/api/v2/{app}/objects/{id}": {
-- "delete": {
-- "operationId": "delete_api_v2_app_objects_id",
-- "summary": "Delete an object in a namespace (the delete verb of Media's namespace grants, WS-G task 2): a soft delete that keeps the bytes for the retention period, and the restore that undoes it within that peri",
-- "description": "**media.object.delete** (public): Delete an object in a namespace (the delete verb of Media's namespace grants, WS-G task 2): a soft delete that keeps the bytes for the retention period, and the restore that undoes it within that period (checked against the namespace's quotas); refused while the object is under a retention hold. The same verb guards the v1 file delete (DELETE /api/v1/:app/files/:key). media.object.upload also grants it, for tokens issued before the verbs were split, unless the namespace's policy is strict_verbs.",
++ "/api/v2/{app}/objects/{id}/multipart/{uploadId}/parts/{n}": {
++ "put": {
++ "operationId": "put_api_v2_app_objects_id_multipart_uploadId_parts_n",
++ "summary": "Upload a file object into an app namespace.",
++ "description": "**media.object.upload** (public): Upload a file object into an app namespace.",
"tags": [
"media.object"
],
"x-openvibe-capabilities": [
-- "media.object.delete"
++ "media.object.upload"
],
"x-openvibe-visibility": [
"public"
],
-- "x-openvibe-quota-class": "media-write",
++ "x-openvibe-quota-class": "media-upload",
"security": [
{
"openvibeToken": [
-- "media.object.delete"
++ "media.object.upload"
]
}
],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/octet-stream": {
++ "schema": {
++ "type": "string",
++ "contentEncoding": "binary"
++ }
++ }
++ }
++ },
"parameters": [
{
"name": "app",
@@@ -702,6 +1065,22 @@
"schema": {
"type": "string"
}
++ },
++ {
++ "name": "uploadId",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ },
++ {
++ "name": "n",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
}
],
"responses": {
@@@ -710,7 +1089,7 @@
"content": {
"application/json": {
"schema": {
-- "$ref": "#/components/schemas/media.object.v1"
++ "$ref": "#/components/schemas/media.upload-part.v1"
}
}
}
@@@ -2688,6 +3067,261 @@
}
}
},
++ "media.upload-complete.v1": {
++ "title": "MediaUploadComplete",
++ "description": "Complete an upload after all parts arrive. Media assembles the bytes, verifies the optional hashes and content type, and returns the ready object.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "content_hash": {
++ "type": "string",
++ "pattern": "^[a-fA-F0-9]{64}$"
++ },
++ "parts": {
++ "type": "array",
++ "items": {
++ "type": "object",
++ "required": [
++ "part_number",
++ "sha256"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "part_number": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "sha256": {
++ "type": "string",
++ "pattern": "^[a-f0-9]{64}$"
++ }
++ }
++ }
++ }
++ }
++ },
++ "media.upload-create.v1": {
++ "title": "MediaUploadCreate",
++ "description": "Create a Media object with a multipart upload session. The caller needs media.object.upload for the tenant namespace; the upload token then authorizes parts and completion.",
++ "type": "object",
++ "required": [
++ "kind",
++ "size_bytes",
++ "multipart"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "kind": {
++ "type": "string",
++ "enum": [
++ "vod",
++ "clip",
++ "file",
++ "thumbnail",
++ "screenshot",
++ "avatar",
++ "asset"
++ ]
++ },
++ "size_bytes": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "multipart": {
++ "const": true
++ },
++ "part_size": {
++ "type": "integer",
++ "minimum": 5242880,
++ "description": "Use 8388608 for 8 MiB parts; the service may increase it to stay below 10000 parts."
++ },
++ "visibility": {
++ "type": "string",
++ "enum": [
++ "public",
++ "unlisted",
++ "private"
++ ]
++ },
++ "mime_type": {
++ "type": "string"
++ },
++ "filename": {
++ "type": "string"
++ },
++ "content_hash": {
++ "type": "string",
++ "pattern": "^[a-fA-F0-9]{64}$"
++ },
++ "namespace": {
++ "type": "string"
++ },
++ "user_id": {
++ "type": [
++ "string",
++ "integer"
++ ]
++ },
++ "metadata": {
++ "type": "object"
++ }
++ }
++ },
++ "media.upload-init.v1": {
++ "title": "MediaUploadInit",
++ "description": "The object and its presigned multipart session after POST /api/v2/:app/objects. Send parts to part_url_template in any order, then complete.",
++ "type": "object",
++ "required": [
++ "id",
++ "object",
++ "upload"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "id": {
++ "type": "string"
++ },
++ "object": {
++ "$ref": "#/components/schemas/media.object.v1"
++ },
++ "upload": {
++ "type": "object",
++ "required": [
++ "method",
++ "multipart",
++ "complete_url"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "method": {
++ "const": "multipart"
++ },
++ "multipart": {
++ "$ref": "#/components/schemas/media.upload.v1"
++ },
++ "complete_url": {
++ "type": "string"
++ },
++ "multipart_url": {
++ "type": "string"
++ }
++ }
++ }
++ }
++ },
++ "media.upload-part.v1": {
++ "title": "MediaUploadPart",
++ "description": "A verified part received by Media. PUT the raw bytes to the presigned URL; X-Content-SHA256 is optional.",
++ "type": "object",
++ "required": [
++ "part_number",
++ "size_bytes",
++ "sha256"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "part_number": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "size_bytes": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "sha256": {
++ "type": "string",
++ "pattern": "^[a-f0-9]{64}$"
++ }
++ }
++ },
++ "media.upload.v1": {
++ "title": "MediaUpload",
++ "description": "media.upload@1: a resumable multipart session. Store upload_id and object_id to resume after a reload; GET status lists received and missing parts. URLs contain a short-lived upload token and should not be logged.",
++ "type": "object",
++ "required": [
++ "upload_id",
++ "object_id",
++ "status",
++ "part_size",
++ "total_size",
++ "parts_expected",
++ "expires_at",
++ "created_at"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "upload_id": {
++ "type": "string",
++ "pattern": "^mup_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "object_id": {
++ "type": "string",
++ "pattern": "^med_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "status": {
++ "type": "string",
++ "enum": [
++ "active",
++ "completing",
++ "completed",
++ "aborted",
++ "expired"
++ ]
++ },
++ "part_size": {
++ "type": "integer",
++ "minimum": 5242880
++ },
++ "total_size": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "parts_expected": {
++ "type": "integer",
++ "minimum": 1,
++ "maximum": 10000
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "created_at": {
++ "type": "string"
++ },
++ "parts": {
++ "type": "array",
++ "items": {
++ "$ref": "#/components/schemas/media.upload-part.v1"
++ }
++ },
++ "received_bytes": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "missing": {
++ "type": "array",
++ "items": {
++ "type": "integer",
++ "minimum": 1
++ }
++ },
++ "token": {
++ "type": "string"
++ },
++ "part_url_template": {
++ "type": "string"
++ },
++ "status_url": {
++ "type": "string"
++ },
++ "complete_url": {
++ "type": "string"
++ },
++ "abort_url": {
++ "type": "string"
++ }
++ }
++ },
"zone.object-zone.v1": {
"title": "ObjectZone",
"description": "zone.object-zone@1 (ADR-031 amendment 2026-10-02): one named object zone, as OpenVibe.Zone's control API returns it (GET /api/v1/zones/{zone_id}, the list under /api/v1/projects/{project_id}/zones, and the 201 of a create). Zone owns this record: its name, environment, state, access policy and per-zone quota setting. Media owns everything inside it: the objects (ordinary med_ objects in the namespace media_namespace), their keys, bytes and replicas, quota enforcement, usage counting and the one deletion path. Zone never lists keys or holds bytes. The S3 bucket name is `name`, resolved within the project and environment of the access key that signs the request, at https://s3.openvibe.media/<name>/<key>. `ovrn` is ovrn:zone:<project_id>:object-zone/<id>, with the same project_id and id as this record. The id is never reused, and neither is a name: within one project environment a name belongs to one zone for ever, deleted or not, so a signed request names exactly one zone id. Name and env are immutable. Every environment has exactly one `default` zone, whose media_namespace is the environment root. Zone creates it with the environment, and it cannot be deleted on its own. Its access is per-object, and every other zone's is private. JSON Schema cannot compare fields: contracts.zones.checkObjectZone also requires that ovrn names this project_id and id, and that media_namespace is the environment root of project_id and env, followed by .<id> unless the zone is the default. More fields may be added.",
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex 9224d0f4..6a3be0b9 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.358.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 503c9b34..d07da6dc 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.358.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 5808c1b6..9cad7e83 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.358.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 5b56696c..92ef7b46 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.358.0",
-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 d22e1e68..c23c667a 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.358.0",
-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 82ac4cd5..923ce945 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.358.0",
-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 cb4a5927..6b26be41 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.358.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 b398e5a3..1de03385 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.358.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 a0593640..92502e64 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.358.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 4f5a6be5..1d30acd2 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.358.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 96af30cb..007c0702 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.358.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 aaf2977a..966d66d7 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.358.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 561a56d4..d65aca2f 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.358.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 10a1db93..203a92d3 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.358.0",
-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 10a3508b..ee19891b 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.358.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 fea157a0..724de55e 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.358.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 f6381465..30956f97 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.358.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 e5b711f8..e4c0db1e 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.358.0",
-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 7949b3d9..af334a77 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.358.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 6a8a08e3..712114f2 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.358.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 e466dd80..a815a897 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.358.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 c0985a62..5ce253e3 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.358.0",
-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.358.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.359.0",
++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.359.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 3c4732c9..f14bb2f5 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -4849,6 +4849,17 @@ export interface Capability {
* Current route(s) that perform this action today, e.g. 'POST /api/v1/:app/files'.
*/
implementedBy?: string[];
++ /**
++ * Input and output contract overrides for a route when one capability covers several operations.
++ */
++ routeSchemas?: {
++ [k: string]:
++ | {
++ inputSchema?: string;
++ outputSchema?: string;
++ }
++ | undefined;
++ };
/**
* The action has an external side effect (money, sending as the person, publishing, applying, deleting, physical control): an agent needs its owner's confirmation unless a standing rule covers it (roadmap WS-Z2).
*/
@@@ -6688,6 +6699,92 @@ export interface MediaFileUpload {
[k: string]: unknown | undefined;
}
++/** [email protected] (owner: media) */
++/**
++ * media.upload@1: a resumable multipart session. Store upload_id and object_id to resume after a reload; GET status lists received and missing parts. URLs contain a short-lived upload token and should not be logged.
++ */
++export interface MediaUpload {
++ upload_id: string;
++ object_id: string;
++ status: "active" | "completing" | "completed" | "aborted" | "expired";
++ part_size: number;
++ total_size: number;
++ parts_expected: number;
++ expires_at: string;
++ created_at: string;
++ parts?: MediaUploadPart[];
++ received_bytes?: number;
++ missing?: number[];
++ token?: string;
++ part_url_template?: string;
++ status_url?: string;
++ complete_url?: string;
++ abort_url?: string;
++ [k: string]: unknown | undefined;
++}
++
++/** [email protected] (owner: media) */
++/**
++ * Create a Media object with a multipart upload session. The caller needs media.object.upload for the tenant namespace; the upload token then authorizes parts and completion.
++ */
++export interface MediaUploadCreate {
++ kind: "vod" | "clip" | "file" | "thumbnail" | "screenshot" | "avatar" | "asset";
++ size_bytes: number;
++ multipart: true;
++ /**
++ * Use 8388608 for 8 MiB parts; the service may increase it to stay below 10000 parts.
++ */
++ part_size?: number;
++ visibility?: "public" | "unlisted" | "private";
++ mime_type?: string;
++ filename?: string;
++ content_hash?: string;
++ namespace?: string;
++ user_id?: string | number;
++ metadata?: {};
++ [k: string]: unknown | undefined;
++}
++
++/** [email protected] (owner: media) */
++/**
++ * The object and its presigned multipart session after POST /api/v2/:app/objects. Send parts to part_url_template in any order, then complete.
++ */
++export interface MediaUploadInit {
++ id: string;
++ object: MediaObject;
++ upload: {
++ method: "multipart";
++ multipart: MediaUpload;
++ complete_url: string;
++ multipart_url?: string;
++ [k: string]: unknown | undefined;
++ };
++ [k: string]: unknown | undefined;
++}
++
++/** [email protected] (owner: media) */
++/**
++ * A verified part received by Media. PUT the raw bytes to the presigned URL; X-Content-SHA256 is optional.
++ */
++export interface MediaUploadPart {
++ part_number: number;
++ size_bytes: number;
++ sha256: string;
++ [k: string]: unknown | undefined;
++}
++
++/** [email protected] (owner: media) */
++/**
++ * Complete an upload after all parts arrive. Media assembles the bytes, verifies the optional hashes and content type, and returns the ready object.
++ */
++export interface MediaUploadComplete {
++ content_hash?: string;
++ parts?: {
++ part_number: number;
++ sha256: string;
++ }[];
++}
++
/** [email protected] (owner: search) */
/**
* What an owning service tells OpenVibe.Search about one of its resources (roadmap §15.12, §4.2 A). The owner stays the source of truth; Search keeps a revision-ordered, permission-aware copy for discovery. A document with deleted=true is a tombstone: it removes the resource from every result and wins over any upsert with the same or an older revision.
ddiff --git a/lib/openapi.js b/lib/openapi.js
iindex 5b9cb5e0..af0d5baf 100644
---- a/lib/openapi.js
++++ b/lib/openapi.js
@@@ -119,12 +119,15 @@ function buildOpenApi({ catalog, capabilities, services, version } = load()) {
for (const route of cap.implementedBy || []) {
const m = HTTP_RE.exec(String(route).trim());
if (!m) { other.push({ capability: cap.id, binding: route }); continue; }
++ // A capability may expose several operations with different bodies and answers.
++ const shape = cap.routeSchemas && cap.routeSchemas[route];
++ const binding = shape ? { ...cap, ...shape } : cap;
const p = m[2].replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, '{$1}').replace(/\/+$/, '') || '/';
for (const method of m[1].toLowerCase().split('|')) {
const k = `${method} ${p}`;
if (!ops.has(k)) ops.set(k, { method, path: p, caps: [], notes: [] });
const op = ops.get(k);
-- if (!op.caps.includes(cap)) op.caps.push(cap);
++ if (!op.caps.some((c) => c.id === cap.id)) op.caps.push(binding);
if (m[3]) op.notes.push(m[3]);
}
}
ddiff --git a/manifests/capabilities/media.object.upload.json b/manifests/capabilities/media.object.upload.json
iindex 23188e46..6ce5ba08 100644
---- a/manifests/capabilities/media.object.upload.json
++++ b/manifests/capabilities/media.object.upload.json
@@@ -18,7 +18,19 @@
"media.object.uploaded"
],
"implementedBy": [
-- "POST /api/v1/:app/files"
++ "POST /api/v1/:app/files",
++ "POST /api/v2/:app/objects",
++ "GET /api/v2/:app/objects/:id/multipart/:uploadId",
++ "PUT /api/v2/:app/objects/:id/multipart/:uploadId/parts/:n",
++ "POST /api/v2/:app/objects/:id/multipart/:uploadId/complete",
++ "DELETE /api/v2/:app/objects/:id/multipart/:uploadId"
],
-- "inputSchema": "media.file-upload@1"
++ "inputSchema": "media.file-upload@1",
++ "routeSchemas": {
++ "POST /api/v2/:app/objects": { "inputSchema": "media.upload-create@1", "outputSchema": "media.upload-init@1" },
++ "GET /api/v2/:app/objects/:id/multipart/:uploadId": { "inputSchema": "common.no-body@1", "outputSchema": "media.upload@1" },
++ "PUT /api/v2/:app/objects/:id/multipart/:uploadId/parts/:n": { "inputSchema": "common.binary@1", "outputSchema": "media.upload-part@1" },
++ "POST /api/v2/:app/objects/:id/multipart/:uploadId/complete": { "inputSchema": "media.upload-complete@1", "outputSchema": "media.object@1" },
++ "DELETE /api/v2/:app/objects/:id/multipart/:uploadId": { "inputSchema": "common.no-body@1", "outputSchema": "media.upload@1" }
++ }
}
ddiff --git a/package-lock.json b/package-lock.json
iindex c8575056..eac4adc8 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-contracts",
-- "version": "0.358.0",
++ "version": "0.359.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.358.0",
++ "version": "0.359.0",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 674a9b5c..7ae86dfa 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.358.0",
++ "version": "0.359.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/openapi.test.js b/test/openapi.test.js
iindex 710a4515..81b8f4a0 100644
---- a/test/openapi.test.js
++++ b/test/openapi.test.js
@@@ -65,8 +65,9 @@ const ROOT = path.join(__dirname, '..');
assert.ok(op && op['x-openvibe-capabilities'].includes(cap.id), `${cap.id}: ${method.toUpperCase()} ${p} in ${cap.owner}'s document`);
const text = JSON.stringify(op);
const key = (ref) => `${ref.replace(/@(\d+)$/, '.v$1')}`;
-- if (cap.outputSchema && !['common.binary@1', 'common.no-body@1'].includes(cap.outputSchema)) assert.ok(text.includes(`#/components/schemas/${key(cap.outputSchema)}"`), `${cap.id} ${method} ${p}: output ${cap.outputSchema}`);
-- if (cap.inputSchema && !['common.binary@1', 'common.no-body@1'].includes(cap.inputSchema)) assert.ok(text.includes(`#/components/schemas/${key(cap.inputSchema)}"`), `${cap.id} ${method} ${p}: input ${cap.inputSchema}`);
++ const shape = { ...cap, ...(cap.routeSchemas && cap.routeSchemas[route]) };
++ if (shape.outputSchema && !['common.binary@1', 'common.no-body@1'].includes(shape.outputSchema)) assert.ok(text.includes(`#/components/schemas/${key(shape.outputSchema)}"`), `${cap.id} ${method} ${p}: output ${shape.outputSchema}`);
++ if (shape.inputSchema && !['common.binary@1', 'common.no-body@1'].includes(shape.inputSchema)) assert.ok(text.includes(`#/components/schemas/${key(shape.inputSchema)}"`), `${cap.id} ${method} ${p}: input ${shape.inputSchema}`);
}
}
}