openvibers/openvibe.contracts Commits
Contracts 0.113.0: the developer portal moves to OpenVibe.Services; Codes becomes the harness (#60)
Changes
@@@ -4,6 +4,21 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) thfrom `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,the notes were in the tag and commit messages (`git tag -n1`).++## 0.113.0 — 2026-10-08++++**The developer portal moves from OpenVibe.Codes to OpenVibe.Services; Codes becomes the open coding-agent harness**++(owner decision 2026-10-08; plan T13 and T16 notes). Codes' portal data in production is empty, so the names move at once.++- New in Services' namespace: `services.release.read` and `services.release.manage` (audience `openvibe.services`), the++ schemas `services.app-manifest@1`, `services.release@1`, `services.release-read-result@1`,++ `services.release-manage-request@1`, `services.release-manage-result@1`, the event payload `services.moderation.action@1`++ and the events `services.app.published|deprecated|revoked`. They are the `codes.*` ones under the new owner and audience.++- Retired, kept loadable: `codes.release.read`, `codes.release.manage`, `codes.resource.read` and the six `codes.*` schemas++ (`compatibility/deprecations.json` names each replacement). Network consumes `services.moderation.action`.++- `manifests/services/services.json`: live with `publicSite: service`; it owns manifests, releases, trust tiers and++ playground logs (kinds `services.manifest` `mfs_`, `services.release` `rel_`) besides the merged index; its site++ block is the developer platform's. `manifests/products/openvibe.services.json` describes the console and docs.++- `manifests/services/codes.json`: no capability or event; the site block describes the harness (position 22).++## 0.112.0 — 2026-10-07**Robots driven through the relay plugin.** `bot.robot-profile@1` is 1.1.0: `mapping.driver` gains `relay`, the@@@ -63,6 +63,48 @@"since": "0.110.0","removeAfter": "1.0.0","reason": "Community forum producer retired after the move to OpenVibe.Space; historical payload remains loadable"++ },++ {++ "id": "codes.app-manifest",++ "replacement": "services.app-manifest@1",++ "since": "0.113.0",++ "removeAfter": "1.0.0",++ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"++ },++ {++ "id": "codes.release-manage-result",++ "replacement": "services.release-manage-result@1",++ "since": "0.113.0",++ "removeAfter": "1.0.0",++ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"++ },++ {++ "id": "codes.release",++ "replacement": "services.release@1",++ "since": "0.113.0",++ "removeAfter": "1.0.0",++ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"++ },++ {++ "id": "codes.release-read-result",++ "replacement": "services.release-read-result@1",++ "since": "0.113.0",++ "removeAfter": "1.0.0",++ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"++ },++ {++ "id": "codes.release-manage-request",++ "replacement": "services.release-manage-request@1",++ "since": "0.113.0",++ "removeAfter": "1.0.0",++ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"++ },++ {++ "id": "codes.moderation.action",++ "replacement": "services.moderation.action@1",++ "since": "0.113.0",++ "removeAfter": "1.0.0",++ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"}]}@@@ -322,7 +322,7 @@"schema": "codes/app-manifest.v1.json","visibility": "public","compatibility": "backward",-- "status": "active",++ "status": "retired","adr": "ADR-014"},{@@@ -332,7 +332,7 @@"schema": "codes/release-manage-result.v1.json","visibility": "first-party","compatibility": "backward",-- "status": "active"++ "status": "retired"},{"id": "codes.release",@@@ -341,7 +341,7 @@"schema": "codes/release.v1.json","visibility": "first-party","compatibility": "backward",-- "status": "active"++ "status": "retired"},{"id": "codes.release-read-result",@@@ -350,7 +350,7 @@"schema": "codes/release-read-result.v1.json","visibility": "first-party","compatibility": "backward",-- "status": "active"++ "status": "retired"},{"id": "codes.release-manage-request",@@@ -359,7 +359,7 @@"schema": "codes/release-manage-request.v1.json","visibility": "first-party","compatibility": "backward",-- "status": "active"++ "status": "retired"},{"id": "codes.moderation.action",@@@ -368,6 +368,62 @@"schema": "events/payloads/codes.moderation.action.v1.json","visibility": "first-party","compatibility": "backward",++ "status": "retired",++ "adr": "ADR-022"++ },++ {++ "id": "services.app-manifest",++ "version": "1.0.0",++ "owner": "services",++ "schema": "services/app-manifest.v1.json",++ "visibility": "public",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-014"++ },++ {++ "id": "services.release-manage-result",++ "version": "1.0.0",++ "owner": "services",++ "schema": "services/release-manage-result.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "services.release",++ "version": "1.0.0",++ "owner": "services",++ "schema": "services/release.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "services.release-read-result",++ "version": "1.0.0",++ "owner": "services",++ "schema": "services/release-read-result.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "services.release-manage-request",++ "version": "1.0.0",++ "owner": "services",++ "schema": "services/release-manage-request.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "services.moderation.action",++ "version": "1.0.0",++ "owner": "services",++ "schema": "events/payloads/services.moderation.action.v1.json",++ "visibility": "first-party",++ "compatibility": "backward","status": "active","adr": "ADR-022"},nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/services.moderation.action.v1.json",++ "title": "ServicesModerationActionPayload",++ "description": "services.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Services, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++}nnew file mode 100644@@@ -0,0 +1,68 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/app-manifest.v1.json",++ "title": "AppManifest",++ "description": "PROPOSAL (OpenVibe.Services, roadmap Wave 20): an app release as the platform knows it. The app is a Network developer app (ADR-014): its id is the Network app id, its capabilities are only a request (the grants in Network are the authority), and trust tiers are metadata that never change a grant check. OpenVibe.Services validates with this schema, loaded into openvibe-contracts' validator, until Contracts publishes it as services.app-manifest@1.",++ "type": "object",++ "required": ["id", "name", "version", "publisher", "project_id", "capabilities", "compatibility"],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network app id (its client_id). Its principal subject is app:<id>."++ },++ "name": { "type": "string", "minLength": 1, "maxLength": 80 },++ "version": {++ "type": "string",++ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",++ "description": "Semantic version of this release."++ },++ "description": { "type": "string", "maxLength": 1000 },++ "publisher": {++ "$ref": "../identity/subject-ref.v1.json",++ "description": "Who publishes the release: the app itself or a member of its project."++ },++ "project_id": {++ "type": "string",++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network project that owns the app. Tenancy in other services is keyed by it (ADR-014)."++ },++ "environment": { "enum": ["sandbox", "production"], "description": "The app's environment. Apps never change environment." },++ "capabilities": {++ "description": "Capability ids the app asks for (3+ segments). Only active public (or partner, by staff allowance) capabilities can ever be granted to apps.",++ "type": "array",++ "maxItems": 64,++ "uniqueItems": true,++ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$" }++ },++ "events": {++ "type": "object",++ "additionalProperties": false,++ "properties": {++ "consumes": {++ "description": "Event types (or a trailing .* family) the app subscribes to.",++ "type": "array", "maxItems": 64, "uniqueItems": true,++ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$" }++ }++ }++ },++ "redirect_uris": {++ "description": "Informational copy of the redirect URIs registered in Network (Network's list is the authority).",++ "type": "array", "maxItems": 10, "uniqueItems": true,++ "items": { "type": "string", "maxLength": 500 }++ },++ "homepage": { "type": "string", "pattern": "^https://[^\\s]{1,2000}$" },++ "repository": { "type": "string", "pattern": "^https://[^\\s]{1,2000}$" },++ "license": { "type": "string", "minLength": 1, "maxLength": 100, "description": "SPDX license expression." },++ "compatibility": {++ "type": "object",++ "required": ["contracts"],++ "additionalProperties": false,++ "properties": {++ "contracts": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Semver range of openvibe-contracts releases it was built against." },++ "sdk": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Semver range of openvibe-sdk releases it uses." }++ }++ }++ }++}nnew file mode 100644@@@ -0,0 +1,62 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/release-manage-request.v1.json",++ "title": "ServicesReleaseManageRequest",++ "description": "services.release-manage-request@1: bodies of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as services.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "manifest"++ ],++ "properties": {++ "kind": {++ "type": "string",++ "description": "mod, or app (the default)."++ },++ "manifest": {++ "anyOf": [++ {++ "$ref": "app-manifest.v1.json"++ },++ {++ "$ref": "../mods/mod-manifest.v1.json"++ }++ ]++ },++ "notes": {++ "type": [++ "string",++ "null"++ ]++ },++ "publish": {++ "type": "boolean"++ }++ }++ },++ {++ "type": "object",++ "required": [++ "reason"++ ],++ "properties": {++ "reason": {++ "type": "string",++ "minLength": 1,++ "pattern": "\\S"++ },++ "replacement": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^(rel_[0-9A-HJKMNP-TV-Z]{26})?$"++ }++ }++ },++ {++ "$ref": "../common/no-body.v1.json"++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/release-manage-result.v1.json",++ "title": "ServicesReleaseManageResult",++ "description": "services.release-manage-result@1: answers of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.",++ "type": "object",++ "required": [++ "release"++ ],++ "properties": {++ "release": {++ "$ref": "release.v1.json"++ },++ "warnings": {++ "type": "array",++ "items": {}++ },++ "event_id": {++ "type": [++ "string",++ "null"++ ]++ }++ }++}nnew file mode 100644@@@ -0,0 +1,120 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/release-read-result.v1.json",++ "title": "ServicesReleaseReadResult",++ "description": "services.release-read-result@1: answers of services.release.read on OpenVibe.Services (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: services.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "app_id",++ "trust",++ "releases"++ ],++ "properties": {++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "trust": {++ "type": "object",++ "required": [++ "tier"++ ],++ "properties": {++ "tier": {++ "type": "string"++ },++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ },++ "releases": {++ "type": "array",++ "items": {++ "$ref": "release.v1.json"++ }++ }++ }++ },++ {++ "type": "object",++ "required": [++ "app_id",++ "tier",++ "note_on_authority"++ ],++ "properties": {++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "tier": {++ "type": "string"++ },++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "note_on_authority": {++ "type": "string"++ }++ }++ },++ {++ "type": "object",++ "required": [++ "release",++ "manifest"++ ],++ "properties": {++ "release": {++ "$ref": "release.v1.json"++ },++ "manifest": {++ "anyOf": [++ {++ "$ref": "app-manifest.v1.json"++ },++ {++ "$ref": "../mods/mod-manifest.v1.json"++ },++ {++ "type": "null"++ }++ ]++ }++ }++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,152 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/release.v1.json",++ "title": "ServicesRelease",++ "description": "services.release@1: one release of an app or mod as OpenVibe.Services presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (services.app-manifest@1).",++ "type": "object",++ "required": [++ "id",++ "app_id",++ "kind",++ "name",++ "version",++ "status",++ "manifest_id",++ "created_at",++ "trust"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^rel_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "project_id": {++ "type": [++ "string",++ "null"++ ]++ },++ "environment": {++ "enum": [++ "production",++ "sandbox"++ ]++ },++ "kind": {++ "enum": [++ "app",++ "mod"++ ]++ },++ "subject_id": {++ "type": [++ "string",++ "null"++ ]++ },++ "name": {++ "type": "string"++ },++ "version": {++ "type": "string"++ },++ "status": {++ "enum": [++ "draft",++ "published",++ "deprecated",++ "revoked"++ ]++ },++ "manifest_id": {++ "type": "string"++ },++ "compatibility": {++ "type": "object"++ },++ "notes": {++ "type": [++ "string",++ "null"++ ]++ },++ "created_at": {++ "type": "string"++ },++ "created_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "published_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "deprecated_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "deprecation_reason": {++ "type": [++ "string",++ "null"++ ]++ },++ "replacement": {++ "type": [++ "string",++ "null"++ ]++ },++ "revoked_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "revocation_reason": {++ "type": [++ "string",++ "null"++ ]++ },++ "trust": {++ "type": "object",++ "required": [++ "tier"++ ],++ "properties": {++ "tier": {++ "type": "string"++ },++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ }++}@@@ -90,11 +90,11 @@ below is in `lib/ids.js` except `act`, `run` and `zon`, which are proposed and n| Service | Kind | Id prefix ||---|---|---|| Actor | `actor.actor` | `act` (proposed, not in `lib/ids.js`) |--| Codes | `codes.manifest` | `mfs` |--| Codes | `codes.release` | `rel` || Events | `events.queue` | **future: when Events stores queues** || Events | `events.subscription` | `sub` || Media | `media.object` | `med` |++| Services | `services.manifest` | `mfs` (was `codes.manifest` until 0.113.0, when the developer portal moved from Codes to Services) |++| Services | `services.release` | `rel` (was `codes.release` until 0.113.0) || Run | `run.sandbox` | `run` (proposed, not in `lib/ids.js`; collides with the existing `run_` AI run ids, `contracts/ai/run.v1.json`) || Watch | `watch.watch` | `wch` || Zone | `zone.object-zone` | `zon` (proposed, not in `lib/ids.js`; today only a usage-recorded description field `<zon_id>`) |nnew file mode 100644@@@ -0,0 +1,16 @@++{++ "id": "app_lowercase",++ "name": "My app",++ "version": "0.1.0",++ "publisher": {++ "type": "app",++ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0"++ },++ "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0",++ "environment": "sandbox",++ "capabilities": [],++ "compatibility": {++ "contracts": "^0.26.0",++ "sdk": "^0.2.2"++ }++}\\ No newline at end of filennew file mode 100644@@@ -0,0 +1,13 @@++{++ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0",++ "name": "My app",++ "version": "0.1.0",++ "publisher": {++ "type": "app",++ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0"++ },++ "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0",++ "environment": "sandbox",++ "capabilities": [],++ "compatibility": {}++}\\ No newline at end of filennew file mode 100644@@@ -0,0 +1,16 @@++{++ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0",++ "name": "My app",++ "version": "0.1.0",++ "publisher": {++ "type": "app",++ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0"++ },++ "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0",++ "environment": "sandbox",++ "capabilities": [],++ "compatibility": {++ "contracts": "^0.26.0",++ "sdk": "^0.2.2"++ }++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "action": "release.revoked",++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "malware in 1.4.2"++}nnew file mode 100644@@@ -0,0 +1,14 @@++{++ "action": "release.revoked",++ "target": {++ "type": "release",++ "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPT",++ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"++ },++ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "reason": "malware in 1.4.2",++ "details": {++ "app": "app_3",++ "version": "1.4.2"++ }++}nnew file mode 100644@@@ -0,0 +1 @@++{ "reason": " ", "manifest": 5 }nnew file mode 100644@@@ -0,0 +1 @@++{ "kind": "app", "manifest": { "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0", "name": "My app", "version": "0.1.0", "publisher": { "type": "app", "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0" }, "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0", "environment": "sandbox", "capabilities": [], "compatibility": { "contracts": "^0.26.0", "sdk": "^0.2.2" }}, "notes": "First release.", "publish": true }nnew file mode 100644@@@ -0,0 +1 @@++{ "reason": "superseded by 1.5.0", "replacement": "rel_01JAB2C3D4E5F6G7H8J9K0MNPS" }nnew file mode 100644@@@ -0,0 +1 @@++{ "warnings": [] }nnew file mode 100644@@@ -0,0 +1 @@++{ "release": { "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }, "event_id": "evt_01JAB2C3D4E5F6G7H8J9K0MNPV" }nnew file mode 100644@@@ -0,0 +1 @@++{ "app_id": "not-an-app", "trust": { "tier": "unreviewed" }, "releases": [] }nnew file mode 100644@@@ -0,0 +1 @@++{ "release": { "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }, "manifest": "not a manifest" }nnew file mode 100644@@@ -0,0 +1 @@++{ "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null }, "releases": [ { "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } } ] }nnew file mode 100644@@@ -0,0 +1 @@++{ "release": { "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }, "manifest": { "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0", "name": "My app", "version": "0.1.0", "publisher": { "type": "app", "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0" }, "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0", "environment": "sandbox", "capabilities": [], "compatibility": { "contracts": "^0.26.0", "sdk": "^0.2.2" }} }nnew file mode 100644@@@ -0,0 +1 @@++{ "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "tier": "reviewed", "note": "checked 1.4.0", "set_by": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ", "set_at": "2026-09-25T10:00:00.000Z", "note_on_authority": "metadata only; grants in OpenVibe.Network are the authority" }nnew file mode 100644@@@ -0,0 +1 @@++{ "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "live", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }nnew file mode 100644@@@ -0,0 +1 @@++{ "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }@@@ -4674,7 +4674,7 @@"codes.app-manifest": {"version": "1.0.0","owner": "codes",-- "status": "active",++ "status": "retired","schema": {"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/codes/app-manifest.v1.json",@@@ -4804,7 +4804,7 @@"codes.release-manage-result": {"version": "1.0.0","owner": "codes",-- "status": "active",++ "status": "retired","schema": {"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/codes/release-manage-result.v1.json",@@@ -4834,7 +4834,7 @@"codes.release": {"version": "1.0.0","owner": "codes",-- "status": "active",++ "status": "retired","schema": {"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/codes/release.v1.json",@@@ -4991,7 +4991,7 @@"codes.release-read-result": {"version": "1.0.0","owner": "codes",-- "status": "active",++ "status": "retired","schema": {"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/codes/release-read-result.v1.json",@@@ -5116,7 +5116,7 @@"codes.release-manage-request": {"version": "1.0.0","owner": "codes",-- "status": "active",++ "status": "retired","schema": {"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/codes/release-manage-request.v1.json",@@@ -5183,7 +5183,7 @@"codes.moderation.action": {"version": "1.0.0","owner": "codes",-- "status": "active",++ "status": "retired","schema": {"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/events/payloads/codes.moderation.action.v1.json",@@@ -5192,6 +5192,527 @@"$ref": "../../common/moderation-action.v1.json"}},++ "services.app-manifest": {++ "version": "1.0.0",++ "owner": "services",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/app-manifest.v1.json",++ "title": "AppManifest",++ "description": "PROPOSAL (OpenVibe.Services, roadmap Wave 20): an app release as the platform knows it. The app is a Network developer app (ADR-014): its id is the Network app id, its capabilities are only a request (the grants in Network are the authority), and trust tiers are metadata that never change a grant check. OpenVibe.Services validates with this schema, loaded into openvibe-contracts' validator, until Contracts publishes it as services.app-manifest@1.",++ "type": "object",++ "required": [++ "id",++ "name",++ "version",++ "publisher",++ "project_id",++ "capabilities",++ "compatibility"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network app id (its client_id). Its principal subject is app:<id>."++ },++ "name": {++ "type": "string",++ "minLength": 1,++ "maxLength": 80++ },++ "version": {++ "type": "string",++ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",++ "description": "Semantic version of this release."++ },++ "description": {++ "type": "string",++ "maxLength": 1000++ },++ "publisher": {++ "$ref": "../identity/subject-ref.v1.json",++ "description": "Who publishes the release: the app itself or a member of its project."++ },++ "project_id": {++ "type": "string",++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network project that owns the app. Tenancy in other services is keyed by it (ADR-014)."++ },++ "environment": {++ "enum": [++ "sandbox",++ "production"++ ],++ "description": "The app's environment. Apps never change environment."++ },++ "capabilities": {++ "description": "Capability ids the app asks for (3+ segments). Only active public (or partner, by staff allowance) capabilities can ever be granted to apps.",++ "type": "array",++ "maxItems": 64,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"++ }++ },++ "events": {++ "type": "object",++ "additionalProperties": false,++ "properties": {++ "consumes": {++ "description": "Event types (or a trailing .* family) the app subscribes to.",++ "type": "array",++ "maxItems": 64,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"++ }++ }++ }++ },++ "redirect_uris": {++ "description": "Informational copy of the redirect URIs registered in Network (Network's list is the authority).",++ "type": "array",++ "maxItems": 10,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "maxLength": 500++ }++ },++ "homepage": {++ "type": "string",++ "pattern": "^https://[^\\s]{1,2000}$"++ },++ "repository": {++ "type": "string",++ "pattern": "^https://[^\\s]{1,2000}$"++ },++ "license": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "SPDX license expression."++ },++ "compatibility": {++ "type": "object",++ "required": [++ "contracts"++ ],++ "additionalProperties": false,++ "properties": {++ "contracts": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "Semver range of openvibe-contracts releases it was built against."++ },++ "sdk": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "Semver range of openvibe-sdk releases it uses."++ }++ }++ }++ }++ }++ },++ "services.release-manage-result": {++ "version": "1.0.0",++ "owner": "services",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/release-manage-result.v1.json",++ "title": "ServicesReleaseManageResult",++ "description": "services.release-manage-result@1: answers of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.",++ "type": "object",++ "required": [++ "release"++ ],++ "properties": {++ "release": {++ "$ref": "release.v1.json"++ },++ "warnings": {++ "type": "array",++ "items": {}++ },++ "event_id": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ },++ "services.release": {++ "version": "1.0.0",++ "owner": "services",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/release.v1.json",++ "title": "ServicesRelease",++ "description": "services.release@1: one release of an app or mod as OpenVibe.Services presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (services.app-manifest@1).",++ "type": "object",++ "required": [++ "id",++ "app_id",++ "kind",++ "name",++ "version",++ "status",++ "manifest_id",++ "created_at",++ "trust"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^rel_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "project_id": {++ "type": [++ "string",++ "null"++ ]++ },++ "environment": {++ "enum": [++ "production",++ "sandbox"++ ]++ },++ "kind": {++ "enum": [++ "app",++ "mod"++ ]++ },++ "subject_id": {++ "type": [++ "string",++ "null"++ ]++ },++ "name": {++ "type": "string"++ },++ "version": {++ "type": "string"++ },++ "status": {++ "enum": [++ "draft",++ "published",++ "deprecated",++ "revoked"++ ]++ },++ "manifest_id": {++ "type": "string"++ },++ "compatibility": {++ "type": "object"++ },++ "notes": {++ "type": [++ "string",++ "null"++ ]++ },++ "created_at": {++ "type": "string"++ },++ "created_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "published_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "deprecated_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "deprecation_reason": {++ "type": [++ "string",++ "null"++ ]++ },++ "replacement": {++ "type": [++ "string",++ "null"++ ]++ },++ "revoked_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "revocation_reason": {++ "type": [++ "string",++ "null"++ ]++ },++ "trust": {++ "type": "object",++ "required": [++ "tier"++ ],++ "properties": {++ "tier": {++ "type": "string"++ },++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ }++ }++ },++ "services.release-read-result": {++ "version": "1.0.0",++ "owner": "services",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/release-read-result.v1.json",++ "title": "ServicesReleaseReadResult",++ "description": "services.release-read-result@1: answers of services.release.read on OpenVibe.Services (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: services.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "app_id",++ "trust",++ "releases"++ ],++ "properties": {++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "trust": {++ "type": "object",++ "required": [++ "tier"++ ],++ "properties": {++ "tier": {++ "type": "string"++ },++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ },++ "releases": {++ "type": "array",++ "items": {++ "$ref": "release.v1.json"++ }++ }++ }++ },++ {++ "type": "object",++ "required": [++ "app_id",++ "tier",++ "note_on_authority"++ ],++ "properties": {++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "tier": {++ "type": "string"++ },++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "note_on_authority": {++ "type": "string"++ }++ }++ },++ {++ "type": "object",++ "required": [++ "release",++ "manifest"++ ],++ "properties": {++ "release": {++ "$ref": "release.v1.json"++ },++ "manifest": {++ "anyOf": [++ {++ "$ref": "app-manifest.v1.json"++ },++ {++ "$ref": "../mods/mod-manifest.v1.json"++ },++ {++ "type": "null"++ }++ ]++ }++ }++ }++ ]++ }++ },++ "services.release-manage-request": {++ "version": "1.0.0",++ "owner": "services",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/services/release-manage-request.v1.json",++ "title": "ServicesReleaseManageRequest",++ "description": "services.release-manage-request@1: bodies of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as services.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "manifest"++ ],++ "properties": {++ "kind": {++ "type": "string",++ "description": "mod, or app (the default)."++ },++ "manifest": {++ "anyOf": [++ {++ "$ref": "app-manifest.v1.json"++ },++ {++ "$ref": "../mods/mod-manifest.v1.json"++ }++ ]++ },++ "notes": {++ "type": [++ "string",++ "null"++ ]++ },++ "publish": {++ "type": "boolean"++ }++ }++ },++ {++ "type": "object",++ "required": [++ "reason"++ ],++ "properties": {++ "reason": {++ "type": "string",++ "minLength": 1,++ "pattern": "\\S"++ },++ "replacement": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^(rel_[0-9A-HJKMNP-TV-Z]{26})?$"++ }++ }++ },++ {++ "$ref": "../common/no-body.v1.json"++ }++ ]++ }++ },++ "services.moderation.action": {++ "version": "1.0.0",++ "owner": "services",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/services.moderation.action.v1.json",++ "title": "ServicesModerationActionPayload",++ "description": "services.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Services, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",++ "$ref": "../../common/moderation-action.v1.json"++ }++ },"events.redaction-directive": {"version": "1.0.0","owner": "events",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.AI API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Billing API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Blog API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Bot API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Chat API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"ddeleted file mode 100644@@@ -1,1665 +0,0 @@--{-- "openapi": "3.1.0",-- "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",-- "info": {-- "title": "OpenVibe.Codes API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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"-- }-- },-- "servers": [-- {-- "url": "https://openvibe.codes"-- }-- ],-- "paths": {-- "/api/v1/apps/{app}/releases": {-- "get": {-- "operationId": "get_api_v1_apps_app_releases",-- "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",-- "description": "**codes.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",-- "tags": [-- "codes.release"-- ],-- "x-openvibe-capabilities": [-- "codes.release.read"-- ],-- "x-openvibe-visibility": [-- "public"-- ],-- "x-openvibe-quota-class": "codes-read",-- "security": [-- {-- "openvibeToken": [-- "codes.release.read"-- ]-- }-- ],-- "parameters": [-- {-- "name": "app",-- "in": "path",-- "required": true,-- "schema": {-- "type": "string"-- }-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-read-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- },-- "post": {-- "operationId": "post_api_v1_apps_app_releases",-- "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replac",-- "description": "**codes.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",-- "tags": [-- "codes.release"-- ],-- "x-openvibe-capabilities": [-- "codes.release.manage"-- ],-- "x-openvibe-visibility": [-- "public"-- ],-- "x-openvibe-quota-class": "codes-release-write",-- "security": [-- {-- "openvibeToken": [-- "codes.release.manage"-- ]-- }-- ],-- "requestBody": {-- "required": false,-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-manage-request.v1"-- }-- }-- }-- },-- "parameters": [-- {-- "name": "app",-- "in": "path",-- "required": true,-- "schema": {-- "type": "string"-- }-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-manage-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- }-- },-- "/api/v1/apps/{app}/trust": {-- "get": {-- "operationId": "get_api_v1_apps_app_trust",-- "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",-- "description": "**codes.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",-- "tags": [-- "codes.release"-- ],-- "x-openvibe-capabilities": [-- "codes.release.read"-- ],-- "x-openvibe-visibility": [-- "public"-- ],-- "x-openvibe-quota-class": "codes-read",-- "security": [-- {-- "openvibeToken": [-- "codes.release.read"-- ]-- }-- ],-- "parameters": [-- {-- "name": "app",-- "in": "path",-- "required": true,-- "schema": {-- "type": "string"-- }-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-read-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- }-- },-- "/api/v1/releases/{id}": {-- "get": {-- "operationId": "get_api_v1_releases_id",-- "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",-- "description": "**codes.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",-- "tags": [-- "codes.release"-- ],-- "x-openvibe-capabilities": [-- "codes.release.read"-- ],-- "x-openvibe-visibility": [-- "public"-- ],-- "x-openvibe-quota-class": "codes-read",-- "security": [-- {-- "openvibeToken": [-- "codes.release.read"-- ]-- }-- ],-- "parameters": [-- {-- "name": "id",-- "in": "path",-- "required": true,-- "schema": {-- "type": "string"-- }-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-read-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- }-- },-- "/api/v1/releases/{id}/deprecate": {-- "post": {-- "operationId": "post_api_v1_releases_id_deprecate",-- "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replac",-- "description": "**codes.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",-- "tags": [-- "codes.release"-- ],-- "x-openvibe-capabilities": [-- "codes.release.manage"-- ],-- "x-openvibe-visibility": [-- "public"-- ],-- "x-openvibe-quota-class": "codes-release-write",-- "security": [-- {-- "openvibeToken": [-- "codes.release.manage"-- ]-- }-- ],-- "requestBody": {-- "required": false,-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-manage-request.v1"-- }-- }-- }-- },-- "parameters": [-- {-- "name": "id",-- "in": "path",-- "required": true,-- "schema": {-- "type": "string"-- }-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-manage-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- }-- },-- "/api/v1/releases/{id}/publish": {-- "post": {-- "operationId": "post_api_v1_releases_id_publish",-- "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replac",-- "description": "**codes.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",-- "tags": [-- "codes.release"-- ],-- "x-openvibe-capabilities": [-- "codes.release.manage"-- ],-- "x-openvibe-visibility": [-- "public"-- ],-- "x-openvibe-quota-class": "codes-release-write",-- "security": [-- {-- "openvibeToken": [-- "codes.release.manage"-- ]-- }-- ],-- "requestBody": {-- "required": false,-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-manage-request.v1"-- }-- }-- }-- },-- "parameters": [-- {-- "name": "id",-- "in": "path",-- "required": true,-- "schema": {-- "type": "string"-- }-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-manage-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- }-- },-- "/api/v1/releases/{id}/revoke": {-- "post": {-- "operationId": "post_api_v1_releases_id_revoke",-- "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replac",-- "description": "**codes.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",-- "tags": [-- "codes.release"-- ],-- "x-openvibe-capabilities": [-- "codes.release.manage"-- ],-- "x-openvibe-visibility": [-- "public"-- ],-- "x-openvibe-quota-class": "codes-release-write",-- "security": [-- {-- "openvibeToken": [-- "codes.release.manage"-- ]-- }-- ],-- "requestBody": {-- "required": false,-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-manage-request.v1"-- }-- }-- }-- },-- "parameters": [-- {-- "name": "id",-- "in": "path",-- "required": true,-- "schema": {-- "type": "string"-- }-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/codes.release-manage-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- }-- },-- "/api/v1/resources": {-- "get": {-- "operationId": "get_api_v1_resources",-- "summary": "Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:o",-- "description": "**codes.resource.read** (first-party): Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:ovrn reads one by its OVRN (common.resource-summary@1). Every authority serves these for OpenVibe.Services to fan out and merge; Codes' own resources are its validated app and mod manifests (kind codes.manifest, id mfs_<ULID>) and its releases (kind codes.release, id rel_<ULID>), each carrying the Network project it was created in as its tenancy boundary. Trust tiers are per-app metadata and playground run logs are audit records, neither a resource; Codes hosts no repositories, so the catalog carries no codes.repo kind. Planned until Codes ships the index.",-- "tags": [-- "codes.resource"-- ],-- "x-openvibe-capabilities": [-- "codes.resource.read"-- ],-- "x-openvibe-visibility": [-- "first-party"-- ],-- "x-openvibe-quota-class": "standard",-- "security": [-- {-- "openvibeToken": [-- "codes.resource.read"-- ]-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/common.resource-list-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- }-- },-- "/api/v1/resources/{ovrn}": {-- "get": {-- "operationId": "get_api_v1_resources_ovrn",-- "summary": "Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:o",-- "description": "**codes.resource.read** (first-party): Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:ovrn reads one by its OVRN (common.resource-summary@1). Every authority serves these for OpenVibe.Services to fan out and merge; Codes' own resources are its validated app and mod manifests (kind codes.manifest, id mfs_<ULID>) and its releases (kind codes.release, id rel_<ULID>), each carrying the Network project it was created in as its tenancy boundary. Trust tiers are per-app metadata and playground run logs are audit records, neither a resource; Codes hosts no repositories, so the catalog carries no codes.repo kind. Planned until Codes ships the index.",-- "tags": [-- "codes.resource"-- ],-- "x-openvibe-capabilities": [-- "codes.resource.read"-- ],-- "x-openvibe-visibility": [-- "first-party"-- ],-- "x-openvibe-quota-class": "standard",-- "security": [-- {-- "openvibeToken": [-- "codes.resource.read"-- ]-- }-- ],-- "parameters": [-- {-- "name": "ovrn",-- "in": "path",-- "required": true,-- "schema": {-- "type": "string"-- }-- }-- ],-- "responses": {-- "2XX": {-- "description": "Success",-- "content": {-- "application/json": {-- "schema": {-- "$ref": "#/components/schemas/common.resource-list-result.v1"-- }-- }-- }-- },-- "default": {-- "description": "An error (RFC 9457 problem details)",-- "content": {-- "application/problem+json": {-- "schema": {-- "$ref": "#/components/schemas/errors.problem.v1"-- }-- }-- }-- }-- }-- }-- }-- },-- "components": {-- "schemas": {-- "codes.app-manifest.v1": {-- "title": "AppManifest",-- "description": "PROPOSAL (OpenVibe.Codes, roadmap Wave 20): an app release as the platform knows it. The app is a Network developer app (ADR-014): its id is the Network app id, its capabilities are only a request (the grants in Network are the authority), and trust tiers are metadata that never change a grant check. OpenVibe.Codes validates with this schema, loaded into openvibe-contracts' validator, until Contracts publishes it as codes.app-manifest@1.",-- "type": "object",-- "required": [-- "id",-- "name",-- "version",-- "publisher",-- "project_id",-- "capabilities",-- "compatibility"-- ],-- "additionalProperties": false,-- "properties": {-- "id": {-- "type": "string",-- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$",-- "description": "The Network app id (its client_id). Its principal subject is app:<id>."-- },-- "name": {-- "type": "string",-- "minLength": 1,-- "maxLength": 80-- },-- "version": {-- "type": "string",-- "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",-- "description": "Semantic version of this release."-- },-- "description": {-- "type": "string",-- "maxLength": 1000-- },-- "publisher": {-- "$ref": "#/components/schemas/identity.subject-ref.v1",-- "description": "Who publishes the release: the app itself or a member of its project."-- },-- "project_id": {-- "type": "string",-- "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$",-- "description": "The Network project that owns the app. Tenancy in other services is keyed by it (ADR-014)."-- },-- "environment": {-- "enum": [-- "sandbox",-- "production"-- ],-- "description": "The app's environment. Apps never change environment."-- },-- "capabilities": {-- "description": "Capability ids the app asks for (3+ segments). Only active public (or partner, by staff allowance) capabilities can ever be granted to apps.",-- "type": "array",-- "maxItems": 64,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"-- }-- },-- "events": {-- "type": "object",-- "additionalProperties": false,-- "properties": {-- "consumes": {-- "description": "Event types (or a trailing .* family) the app subscribes to.",-- "type": "array",-- "maxItems": 64,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"-- }-- }-- }-- },-- "redirect_uris": {-- "description": "Informational copy of the redirect URIs registered in Network (Network's list is the authority).",-- "type": "array",-- "maxItems": 10,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "maxLength": 500-- }-- },-- "homepage": {-- "type": "string",-- "pattern": "^https://[^\\s]{1,2000}$"-- },-- "repository": {-- "type": "string",-- "pattern": "^https://[^\\s]{1,2000}$"-- },-- "license": {-- "type": "string",-- "minLength": 1,-- "maxLength": 100,-- "description": "SPDX license expression."-- },-- "compatibility": {-- "type": "object",-- "required": [-- "contracts"-- ],-- "additionalProperties": false,-- "properties": {-- "contracts": {-- "type": "string",-- "minLength": 1,-- "maxLength": 100,-- "description": "Semver range of openvibe-contracts releases it was built against."-- },-- "sdk": {-- "type": "string",-- "minLength": 1,-- "maxLength": 100,-- "description": "Semver range of openvibe-sdk releases it uses."-- }-- }-- }-- }-- },-- "codes.release-manage-request.v1": {-- "title": "CodesReleaseManageRequest",-- "description": "codes.release-manage-request@1: bodies of codes.release.manage on OpenVibe.Codes (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as codes.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.",-- "anyOf": [-- {-- "type": "object",-- "required": [-- "manifest"-- ],-- "properties": {-- "kind": {-- "type": "string",-- "description": "mod, or app (the default)."-- },-- "manifest": {-- "anyOf": [-- {-- "$ref": "#/components/schemas/codes.app-manifest.v1"-- },-- {-- "$ref": "#/components/schemas/mods.mod-manifest.v1"-- }-- ]-- },-- "notes": {-- "type": [-- "string",-- "null"-- ]-- },-- "publish": {-- "type": "boolean"-- }-- }-- },-- {-- "type": "object",-- "required": [-- "reason"-- ],-- "properties": {-- "reason": {-- "type": "string",-- "minLength": 1,-- "pattern": "\\S"-- },-- "replacement": {-- "type": [-- "string",-- "null"-- ],-- "pattern": "^(rel_[0-9A-HJKMNP-TV-Z]{26})?$"-- }-- }-- },-- {-- "$ref": "#/components/schemas/common.no-body.v1"-- }-- ]-- },-- "codes.release-manage-result.v1": {-- "title": "CodesReleaseManageResult",-- "description": "codes.release-manage-result@1: answers of codes.release.manage on OpenVibe.Codes (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.",-- "type": "object",-- "required": [-- "release"-- ],-- "properties": {-- "release": {-- "$ref": "#/components/schemas/codes.release.v1"-- },-- "warnings": {-- "type": "array",-- "items": {}-- },-- "event_id": {-- "type": [-- "string",-- "null"-- ]-- }-- }-- },-- "codes.release-read-result.v1": {-- "title": "CodesReleaseReadResult",-- "description": "codes.release-read-result@1: answers of codes.release.read on OpenVibe.Codes (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: codes.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.",-- "anyOf": [-- {-- "type": "object",-- "required": [-- "app_id",-- "trust",-- "releases"-- ],-- "properties": {-- "app_id": {-- "type": "string",-- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"-- },-- "trust": {-- "type": "object",-- "required": [-- "tier"-- ],-- "properties": {-- "tier": {-- "type": "string"-- },-- "note": {-- "type": [-- "string",-- "null"-- ]-- },-- "set_by": {-- "type": [-- "string",-- "null"-- ]-- },-- "set_at": {-- "type": [-- "string",-- "null"-- ]-- }-- }-- },-- "releases": {-- "type": "array",-- "items": {-- "$ref": "#/components/schemas/codes.release.v1"-- }-- }-- }-- },-- {-- "type": "object",-- "required": [-- "app_id",-- "tier",-- "note_on_authority"-- ],-- "properties": {-- "app_id": {-- "type": "string",-- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"-- },-- "tier": {-- "type": "string"-- },-- "note": {-- "type": [-- "string",-- "null"-- ]-- },-- "set_by": {-- "type": [-- "string",-- "null"-- ]-- },-- "set_at": {-- "type": [-- "string",-- "null"-- ]-- },-- "note_on_authority": {-- "type": "string"-- }-- }-- },-- {-- "type": "object",-- "required": [-- "release",-- "manifest"-- ],-- "properties": {-- "release": {-- "$ref": "#/components/schemas/codes.release.v1"-- },-- "manifest": {-- "anyOf": [-- {-- "$ref": "#/components/schemas/codes.app-manifest.v1"-- },-- {-- "$ref": "#/components/schemas/mods.mod-manifest.v1"-- },-- {-- "type": "null"-- }-- ]-- }-- }-- }-- ]-- },-- "codes.release.v1": {-- "title": "CodesRelease",-- "description": "codes.release@1: one release of an app or mod as OpenVibe.Codes presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (codes.app-manifest@1).",-- "type": "object",-- "required": [-- "id",-- "app_id",-- "kind",-- "name",-- "version",-- "status",-- "manifest_id",-- "created_at",-- "trust"-- ],-- "properties": {-- "id": {-- "type": "string",-- "pattern": "^rel_[0-9A-HJKMNP-TV-Z]{26}$"-- },-- "app_id": {-- "type": "string",-- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"-- },-- "project_id": {-- "type": [-- "string",-- "null"-- ]-- },-- "environment": {-- "enum": [-- "production",-- "sandbox"-- ]-- },-- "kind": {-- "enum": [-- "app",-- "mod"-- ]-- },-- "subject_id": {-- "type": [-- "string",-- "null"-- ]-- },-- "name": {-- "type": "string"-- },-- "version": {-- "type": "string"-- },-- "status": {-- "enum": [-- "draft",-- "published",-- "deprecated",-- "revoked"-- ]-- },-- "manifest_id": {-- "type": "string"-- },-- "compatibility": {-- "type": "object"-- },-- "notes": {-- "type": [-- "string",-- "null"-- ]-- },-- "created_at": {-- "type": "string"-- },-- "created_by": {-- "type": [-- "string",-- "null"-- ]-- },-- "published_at": {-- "type": [-- "string",-- "null"-- ]-- },-- "deprecated_at": {-- "type": [-- "string",-- "null"-- ]-- },-- "deprecation_reason": {-- "type": [-- "string",-- "null"-- ]-- },-- "replacement": {-- "type": [-- "string",-- "null"-- ]-- },-- "revoked_at": {-- "type": [-- "string",-- "null"-- ]-- },-- "revocation_reason": {-- "type": [-- "string",-- "null"-- ]-- },-- "trust": {-- "type": "object",-- "required": [-- "tier"-- ],-- "properties": {-- "tier": {-- "type": "string"-- },-- "note": {-- "type": [-- "string",-- "null"-- ]-- },-- "set_by": {-- "type": [-- "string",-- "null"-- ]-- },-- "set_at": {-- "type": [-- "string",-- "null"-- ]-- }-- }-- }-- }-- },-- "common.no-body.v1": {-- "title": "NoBody",-- "description": "common.no-body@1: the capability's request carries no body; its parameters are the path and query of the routes in implementedBy (an id, a page cursor). An input schema that says so explicitly, so every active capability names one (roadmap WS-C task 4).",-- "type": "object",-- "maxProperties": 0-- },-- "common.resource-list-result.v1": {-- "title": "ResourceListResult",-- "description": "A page of the resource index (roadmap WS-Z7).",-- "type": "object",-- "additionalProperties": false,-- "required": [-- "resources",-- "next_cursor"-- ],-- "properties": {-- "resources": {-- "type": "array",-- "items": {-- "$ref": "#/components/schemas/common.resource-summary.v1"-- }-- },-- "next_cursor": {-- "type": [-- "string",-- "null"-- ]-- },-- "partial": {-- "type": "array",-- "description": "Authorities a merged index (OpenVibe.Services, ADR-048) could not read for this page: a slow or failing authority is omitted, never fails the page. Each entry names the authority and the problem code it answered. Added in 1.1.0; a single authority's own index leaves it out.",-- "items": {-- "type": "object",-- "required": [-- "service",-- "code"-- ],-- "additionalProperties": false,-- "properties": {-- "service": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9-]{1,39}$"-- },-- "code": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"-- }-- }-- }-- }-- }-- },-- "common.resource-summary.v1": {-- "title": "ResourceSummary",-- "description": "One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.",-- "type": "object",-- "additionalProperties": false,-- "required": [-- "id",-- "kind",-- "service",-- "state",-- "created_at"-- ],-- "properties": {-- "id": {-- "type": "string"-- },-- "kind": {-- "type": "string",-- "description": "service.kind, e.g. watch.watch, actor.actor, media.object, events.subscription"-- },-- "service": {-- "type": "string"-- },-- "project_id": {-- "type": "string",-- "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"-- },-- "ovrn": {-- "type": "string",-- "maxLength": 200,-- "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",-- "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."-- },-- "owner": {-- "$ref": "#/components/schemas/identity.subject-ref.v1"-- },-- "name": {-- "type": "string"-- },-- "state": {-- "type": "string"-- },-- "created_at": {-- "type": "string",-- "format": "date-time"-- },-- "updated_at": {-- "type": "string",-- "format": "date-time"-- },-- "usage": {-- "type": "object",-- "additionalProperties": {-- "type": "number",-- "minimum": 0-- },-- "properties": {},-- "description": "cost units by name (WS-Z1)"-- },-- "links": {-- "type": "object",-- "additionalProperties": false,-- "properties": {-- "self": {-- "type": "string",-- "format": "uri"-- },-- "console": {-- "type": "string",-- "format": "uri"-- },-- "docs": {-- "type": "string",-- "format": "uri"-- }-- }-- }-- }-- },-- "errors.problem.v1": {-- "title": "Problem",-- "description": "RFC 9457 problem details (application/problem+json) with a stable OpenVibe error code and trace identifiers. The legacy 'error' string is allowed during migration so existing clients keep working.",-- "type": "object",-- "required": [-- "type",-- "title",-- "status",-- "code"-- ],-- "additionalProperties": true,-- "properties": {-- "type": {-- "type": "string",-- "format": "uri-reference"-- },-- "title": {-- "type": "string",-- "minLength": 1-- },-- "status": {-- "type": "integer",-- "minimum": 400,-- "maximum": 599-- },-- "detail": {-- "type": "string"-- },-- "instance": {-- "type": "string",-- "format": "uri-reference"-- },-- "code": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"-- },-- "request_id": {-- "type": "string"-- },-- "trace_id": {-- "type": "string",-- "pattern": "^[0-9a-f]{32}$"-- },-- "errors": {-- "type": "array",-- "items": {-- "type": "object",-- "required": [-- "message"-- ],-- "properties": {-- "path": {-- "type": "string"-- },-- "message": {-- "type": "string"-- }-- }-- }-- },-- "error": {-- "type": "string",-- "description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."-- }-- }-- },-- "identity.subject-ref.v1": {-- "title": "SubjectRef",-- "description": "The one cross-platform reference to an actor. Issued by OpenVibe.Network. Never a service-local integer id.",-- "oneOf": [-- {-- "type": "object",-- "required": [-- "type",-- "id"-- ],-- "additionalProperties": false,-- "properties": {-- "type": {-- "const": "user"-- },-- "id": {-- "type": "string",-- "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"-- }-- },-- "description": "UserSubject"-- },-- {-- "type": "object",-- "required": [-- "type",-- "id"-- ],-- "additionalProperties": false,-- "properties": {-- "type": {-- "const": "guest"-- },-- "id": {-- "type": "string",-- "pattern": "^gst_[0-9A-HJKMNP-TV-Z]{26}$"-- }-- },-- "description": "GuestSubject"-- },-- {-- "type": "object",-- "required": [-- "type",-- "id"-- ],-- "additionalProperties": false,-- "properties": {-- "type": {-- "const": "app"-- },-- "id": {-- "type": "string",-- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"-- }-- },-- "description": "AppSubject"-- },-- {-- "type": "object",-- "required": [-- "type",-- "id"-- ],-- "additionalProperties": false,-- "properties": {-- "type": {-- "const": "mod"-- },-- "id": {-- "type": "string",-- "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"-- }-- },-- "description": "ModSubject"-- },-- {-- "type": "object",-- "required": [-- "type",-- "id"-- ],-- "additionalProperties": false,-- "properties": {-- "type": {-- "enum": [-- "service",-- "system"-- ]-- },-- "id": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9-]{1,39}$"-- }-- },-- "description": "PrincipalSubject"-- },-- {-- "type": "object",-- "required": [-- "type",-- "id"-- ],-- "additionalProperties": false,-- "properties": {-- "type": {-- "const": "agent"-- },-- "id": {-- "type": "string",-- "pattern": "^agt_[0-9A-HJKMNP-TV-Z]{26}$"-- }-- },-- "description": "AgentSubject: an agent (OpenVibe.Actor, or a developer app's agent) acting under grants its owner delegated (roadmap WS-Z2). In an event envelope, on_behalf_of names the owner."-- }-- ]-- },-- "media.media-ref.v1": {-- "title": "MediaRef",-- "description": "Reference to a Media object. Canonical ids (med_<ULID>) arrive with the Wave 4 object model; until then legacy:<app>:<kind>:<id> addresses today's VOD/clip/file/paste/thumbnail rows.",-- "type": "object",-- "required": [-- "media_id"-- ],-- "additionalProperties": false,-- "properties": {-- "media_id": {-- "type": "string",-- "pattern": "^(med_[0-9A-HJKMNP-TV-Z]{26}|legacy:[a-z][a-z0-9-]{1,39}:(vod|clip|file|paste|thumbnail|avatar):[A-Za-z0-9._/-]{1,200})$"-- },-- "role": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]{1,39}$"-- },-- "variant": {-- "type": "string",-- "pattern": "^[a-z0-9][a-z0-9_-]{0,39}$"-- }-- }-- },-- "mods.mod-manifest.v1": {-- "title": "ModManifest",-- "description": "A mod as the platform knows it (ADR-013): who publishes it, which runtime runs it, which capabilities it asks for and the resources it may use. Requested capabilities are only a request: the install's approved subset is the grant, and trust tiers are install metadata that never change a grant check. The runtime-specific payload (a data pack, a script bundle) is not part of the manifest. 1.1.0 (openvibe-contracts v0.34.0) adds the optional permissions.readGrants and writeGrants, billingHooks and dependencies (ADR-013 amendment of 2026-09-24); every 1.0.0 manifest stays valid.",-- "type": "object",-- "required": [-- "id",-- "name",-- "version",-- "publisher",-- "target",-- "runtime",-- "permissions",-- "resources",-- "compatibility"-- ],-- "additionalProperties": false,-- "properties": {-- "id": {-- "type": "string",-- "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$",-- "description": "Stable mod id; its principal subject is mod:<id>."-- },-- "name": {-- "type": "string",-- "minLength": 1,-- "maxLength": 80-- },-- "version": {-- "type": "string",-- "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",-- "description": "Semantic version of this release."-- },-- "description": {-- "type": "string",-- "maxLength": 1000-- },-- "publisher": {-- "$ref": "#/components/schemas/identity.subject-ref.v1",-- "description": "Who publishes the mod (a user or an app subject)."-- },-- "target": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9-]{1,39}\\.[a-z][a-z0-9-]{1,39}$",-- "description": "Where the mod runs: <service>.<surface>, e.g. games.browser, games.source, live.overlay."-- },-- "runtime": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9-]{1,39}@[1-9][0-9]{0,3}$",-- "description": "Runtime adapter and its major version, e.g. games-content@1 (declarative data pack) or source-quickjs@1."-- },-- "permissions": {-- "type": "object",-- "required": [-- "capabilities"-- ],-- "additionalProperties": false,-- "properties": {-- "capabilities": {-- "description": "Capability ids the mod asks for (3+ segments). The target runtime binds only those it implements, and only once granted.",-- "type": "array",-- "maxItems": 64,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"-- }-- },-- "events": {-- "description": "Event types the mod wants delivered to it.",-- "type": "array",-- "maxItems": 64,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"-- }-- },-- "modules": {-- "description": "User-module namespaces the mod wants to read or write (a trailing .* names a family). A namespace listed here may be read and written; readGrants and writeGrants (1.1.0) say which.",-- "type": "array",-- "maxItems": 32,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"-- }-- },-- "mediaNamespaces": {-- "description": "Media namespaces the mod wants to read or write. A namespace listed here may be read and written; readGrants and writeGrants (1.1.0) say which.",-- "type": "array",-- "maxItems": 32,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"-- }-- },-- "readGrants": {-- "description": "1.1.0: namespaces the mod may only read. A namespace that is only here is read-only. The install's approved subset is still the grant.",-- "type": "object",-- "additionalProperties": false,-- "minProperties": 1,-- "properties": {-- "modules": {-- "description": "User-module namespaces (a trailing .* names a family).",-- "type": "array",-- "maxItems": 32,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"-- }-- },-- "mediaNamespaces": {-- "description": "Media namespaces.",-- "type": "array",-- "maxItems": 32,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"-- }-- }-- }-- },-- "writeGrants": {-- "description": "1.1.0: namespaces the mod may read and write. A write needs the namespace here, or in the older modules and mediaNamespaces lists, which mean read and write.",-- "type": "object",-- "additionalProperties": false,-- "minProperties": 1,-- "properties": {-- "modules": {-- "description": "User-module namespaces (a trailing .* names a family).",-- "type": "array",-- "maxItems": 32,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"-- }-- },-- "mediaNamespaces": {-- "description": "Media namespaces.",-- "type": "array",-- "maxItems": 32,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"-- }-- }-- }-- }-- }-- },-- "resources": {-- "type": "object",-- "required": [-- "cpuMs",-- "memoryMb",-- "storageMb"-- ],-- "additionalProperties": false,-- "description": "The budget the mod asks for. Runtimes meter it; the sandbox that enforces it lives in OpenVibe.Host (Stage C).",-- "properties": {-- "cpuMs": {-- "type": "number",-- "minimum": 0,-- "maximum": 1000,-- "description": "CPU milliseconds per tick (game runtimes) or per request."-- },-- "memoryMb": {-- "type": "integer",-- "minimum": 0,-- "maximum": 4096-- },-- "storageMb": {-- "type": "integer",-- "minimum": 0,-- "maximum": 102400-- },-- "outboundHosts": {-- "description": "Hosts the mod may reach over the network. Empty or absent = none.",-- "type": "array",-- "maxItems": 32,-- "uniqueItems": true,-- "items": {-- "type": "string",-- "pattern": "^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$"-- }-- }-- }-- },-- "assets": {-- "description": "Assets the mod ships, as Media object references.",-- "type": "array",-- "maxItems": 256,-- "items": {-- "$ref": "#/components/schemas/media.media-ref.v1"-- }-- },-- "compatibility": {-- "type": "object",-- "required": [-- "runtime"-- ],-- "additionalProperties": false,-- "properties": {-- "runtime": {-- "type": "string",-- "minLength": 1,-- "maxLength": 100,-- "description": "Semver range of the runtime this release works with, e.g. \">=1.0.0 <2.0.0\"."-- },-- "contracts": {-- "type": "string",-- "minLength": 1,-- "maxLength": 100,-- "description": "Semver range of openvibe-contracts releases it was built against."-- }-- }-- },-- "homepage": {-- "type": "string",-- "pattern": "^https://[^\\s]{1,2000}$"-- },-- "billingHooks": {-- "description": "1.1.0: how the mod takes part in money, only through Billing and VIP primitives (ADR-013 amendment, ADR-012). entitlement: the mod checks that the person holds this entitlement (billing.entitlement.check or vip.entitlement.check, granted like any other capability). checkout: the mod sends the person to the platform's own checkout for this plan (vip.membership.checkout or a Billing intent). A mod never takes payment, sees payment details or holds a balance. Prices live in Billing and VIP, never in the manifest.",-- "type": "array",-- "maxItems": 32,-- "items": {-- "type": "object",-- "required": [-- "kind",-- "key"-- ],-- "additionalProperties": false,-- "properties": {-- "kind": {-- "enum": [-- "entitlement",-- "checkout"-- ]-- },-- "key": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_.:-]{0,127}$",-- "description": "The entitlement or plan key as Billing and VIP name it, e.g. vip.plan:pln_01jab… (lowercase, the form search.index-document@1 acl.entitlements uses)."-- },-- "description": {-- "type": "string",-- "minLength": 1,-- "maxLength": 200,-- "description": "What it unlocks or sells, shown at install."-- }-- }-- }-- },-- "dependencies": {-- "description": "1.1.0: other mods this release needs. A runtime refuses to enable the mod while a required dependency is not installed, not enabled or outside its range. An optional one is used only when present.",-- "type": "array",-- "maxItems": 32,-- "uniqueItems": true,-- "items": {-- "type": "object",-- "required": [-- "id",-- "version"-- ],-- "additionalProperties": false,-- "properties": {-- "id": {-- "type": "string",-- "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"-- },-- "version": {-- "type": "string",-- "minLength": 1,-- "maxLength": 100,-- "description": "Semver range of the dependency's releases this release works with, e.g. \">=1.2.0 <2.0.0\"."-- },-- "optional": {-- "type": "boolean",-- "default": false-- }-- }-- }-- }-- }-- }-- },-- "securitySchemes": {-- "openvibeToken": {-- "type": "http",-- "scheme": "bearer",-- "bearerFormat": "JWT",-- "description": "An OpenVibe Network token for this service: a person's token, an app token (client credentials, audience of the service) or a first-party service token. Its `cap` claim must include the capability the operation names."-- }-- }-- }--}@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Community API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Coupons API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Deals API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Events API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Games API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Host API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -36,13 +36,6 @@"operations": 22,"capabilities": 12},-- {-- "service": "codes",-- "name": "OpenVibe.Codes",-- "origin": "https://openvibe.codes",-- "operations": 9,-- "capabilities": 3-- },{"service": "community","name": "OpenVibe.Community",@@@ -145,8 +138,8 @@"service": "services","name": "OpenVibe.Services","origin": "https://openvibe.services",-- "operations": 2,-- "capabilities": 1++ "operations": 9,++ "capabilities": 3},{"service": "sources",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Live API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Media API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Network API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.News API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenRe.Stream API",-- "version": "0.112.0",-- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Reviews API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Run API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Search API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Services API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -16,35 +16,45 @@}],"paths": {-- "/api/v1/resources": {++ "/api/v1/apps/{app}/releases": {"get": {-- "operationId": "get_api_v1_resources",-- "summary": "Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own ",-- "description": "**services.resource.read** (first-party): Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own or belong to (one project per request).",++ "operationId": "get_api_v1_apps_app_releases",++ "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",++ "description": "**services.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.","tags": [-- "services.resource"++ "services.release"],"x-openvibe-capabilities": [-- "services.resource.read"++ "services.release.read"],"x-openvibe-visibility": [-- "first-party"++ "public"],-- "x-openvibe-quota-class": "standard",++ "x-openvibe-quota-class": "services-read","security": [{"openvibeToken": [-- "services.resource.read"++ "services.release.read"]}],++ "parameters": [++ {++ "name": "app",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],"responses": {"2XX": {"description": "Success","content": {"application/json": {"schema": {-- "$ref": "#/components/schemas/common.resource-list-result.v1"++ "$ref": "#/components/schemas/services.release-read-result.v1"}}}@@@ -60,33 +70,41 @@}}}-- }-- },-- "/api/v1/resources/{ovrn}": {-- "get": {-- "operationId": "get_api_v1_resources_ovrn",-- "summary": "Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own ",-- "description": "**services.resource.read** (first-party): Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own or belong to (one project per request).",++ },++ "post": {++ "operationId": "post_api_v1_apps_app_releases",++ "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional rep",++ "description": "**services.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).","tags": [-- "services.resource"++ "services.release"],"x-openvibe-capabilities": [-- "services.resource.read"++ "services.release.manage"],"x-openvibe-visibility": [-- "first-party"++ "public"],-- "x-openvibe-quota-class": "standard",++ "x-openvibe-quota-class": "services-release-write","security": [{"openvibeToken": [-- "services.resource.read"++ "services.release.manage"]}],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-manage-request.v1"++ }++ }++ }++ },"parameters": [{-- "name": "ovrn",++ "name": "app","in": "path","required": true,"schema": {@@@ -100,7 +118,7 @@"content": {"application/json": {"schema": {-- "$ref": "#/components/schemas/common.resource-list-result.v1"++ "$ref": "#/components/schemas/services.release-manage-result.v1"}}}@@@ -117,317 +135,1522 @@}}}-- }-- },-- "components": {-- "schemas": {-- "common.resource-list-result.v1": {-- "title": "ResourceListResult",-- "description": "A page of the resource index (roadmap WS-Z7).",-- "type": "object",-- "additionalProperties": false,-- "required": [-- "resources",-- "next_cursor"++ },++ "/api/v1/apps/{app}/trust": {++ "get": {++ "operationId": "get_api_v1_apps_app_trust",++ "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",++ "description": "**services.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",++ "tags": [++ "services.release"],-- "properties": {-- "resources": {-- "type": "array",-- "items": {-- "$ref": "#/components/schemas/common.resource-summary.v1"-- }-- },-- "next_cursor": {-- "type": [-- "string",-- "null"++ "x-openvibe-capabilities": [++ "services.release.read"++ ],++ "x-openvibe-visibility": [++ "public"++ ],++ "x-openvibe-quota-class": "services-read",++ "security": [++ {++ "openvibeToken": [++ "services.release.read"]++ }++ ],++ "parameters": [++ {++ "name": "app",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-read-result.v1"++ }++ }++ }},-- "partial": {-- "type": "array",-- "description": "Authorities a merged index (OpenVibe.Services, ADR-048) could not read for this page: a slow or failing authority is omitted, never fails the page. Each entry names the authority and the problem code it answered. Added in 1.1.0; a single authority's own index leaves it out.",-- "items": {-- "type": "object",-- "required": [-- "service",-- "code"-- ],-- "additionalProperties": false,-- "properties": {-- "service": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9-]{1,39}$"-- },-- "code": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"}}}}}-- },-- "common.resource-summary.v1": {-- "title": "ResourceSummary",-- "description": "One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.",-- "type": "object",-- "additionalProperties": false,-- "required": [-- "id",-- "kind",-- "service",-- "state",-- "created_at"++ }++ },++ "/api/v1/releases/{id}": {++ "get": {++ "operationId": "get_api_v1_releases_id",++ "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",++ "description": "**services.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",++ "tags": [++ "services.release"],-- "properties": {-- "id": {-- "type": "string"-- },-- "kind": {-- "type": "string",-- "description": "service.kind, e.g. watch.watch, actor.actor, media.object, events.subscription"-- },-- "service": {-- "type": "string"-- },-- "project_id": {-- "type": "string",-- "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"-- },-- "ovrn": {-- "type": "string",-- "maxLength": 200,-- "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",-- "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."-- },-- "owner": {-- "$ref": "#/components/schemas/identity.subject-ref.v1"-- },-- "name": {-- "type": "string"-- },-- "state": {-- "type": "string"-- },-- "created_at": {-- "type": "string",-- "format": "date-time"-- },-- "updated_at": {-- "type": "string",-- "format": "date-time"-- },-- "usage": {-- "type": "object",-- "additionalProperties": {-- "type": "number",-- "minimum": 0-- },-- "properties": {},-- "description": "cost units by name (WS-Z1)"++ "x-openvibe-capabilities": [++ "services.release.read"++ ],++ "x-openvibe-visibility": [++ "public"++ ],++ "x-openvibe-quota-class": "services-read",++ "security": [++ {++ "openvibeToken": [++ "services.release.read"++ ]++ }++ ],++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-read-result.v1"++ }++ }++ }},-- "links": {-- "type": "object",-- "additionalProperties": false,-- "properties": {-- "self": {-- "type": "string",-- "format": "uri"-- },-- "console": {-- "type": "string",-- "format": "uri"-- },-- "docs": {-- "type": "string",-- "format": "uri"++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }}}}}-- },-- "errors.problem.v1": {-- "title": "Problem",-- "description": "RFC 9457 problem details (application/problem+json) with a stable OpenVibe error code and trace identifiers. The legacy 'error' string is allowed during migration so existing clients keep working.",-- "type": "object",-- "required": [-- "type",-- "title",-- "status",-- "code"++ }++ },++ "/api/v1/releases/{id}/deprecate": {++ "post": {++ "operationId": "post_api_v1_releases_id_deprecate",++ "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional rep",++ "description": "**services.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",++ "tags": [++ "services.release"],-- "additionalProperties": true,-- "properties": {-- "type": {-- "type": "string",-- "format": "uri-reference"-- },-- "title": {-- "type": "string",-- "minLength": 1-- },-- "status": {-- "type": "integer",-- "minimum": 400,-- "maximum": 599-- },-- "detail": {-- "type": "string"++ "x-openvibe-capabilities": [++ "services.release.manage"++ ],++ "x-openvibe-visibility": [++ "public"++ ],++ "x-openvibe-quota-class": "services-release-write",++ "security": [++ {++ "openvibeToken": [++ "services.release.manage"++ ]++ }++ ],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-manage-request.v1"++ }++ }++ }++ },++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-manage-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/releases/{id}/publish": {++ "post": {++ "operationId": "post_api_v1_releases_id_publish",++ "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional rep",++ "description": "**services.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",++ "tags": [++ "services.release"++ ],++ "x-openvibe-capabilities": [++ "services.release.manage"++ ],++ "x-openvibe-visibility": [++ "public"++ ],++ "x-openvibe-quota-class": "services-release-write",++ "security": [++ {++ "openvibeToken": [++ "services.release.manage"++ ]++ }++ ],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-manage-request.v1"++ }++ }++ }++ },++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-manage-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/releases/{id}/revoke": {++ "post": {++ "operationId": "post_api_v1_releases_id_revoke",++ "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional rep",++ "description": "**services.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",++ "tags": [++ "services.release"++ ],++ "x-openvibe-capabilities": [++ "services.release.manage"++ ],++ "x-openvibe-visibility": [++ "public"++ ],++ "x-openvibe-quota-class": "services-release-write",++ "security": [++ {++ "openvibeToken": [++ "services.release.manage"++ ]++ }++ ],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-manage-request.v1"++ }++ }++ }++ },++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/services.release-manage-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/resources": {++ "get": {++ "operationId": "get_api_v1_resources",++ "summary": "Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own ",++ "description": "**services.resource.read** (first-party): Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own or belong to (one project per request).",++ "tags": [++ "services.resource"++ ],++ "x-openvibe-capabilities": [++ "services.resource.read"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "standard",++ "security": [++ {++ "openvibeToken": [++ "services.resource.read"++ ]++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/common.resource-list-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/resources/{ovrn}": {++ "get": {++ "operationId": "get_api_v1_resources_ovrn",++ "summary": "Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own ",++ "description": "**services.resource.read** (first-party): Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own or belong to (one project per request).",++ "tags": [++ "services.resource"++ ],++ "x-openvibe-capabilities": [++ "services.resource.read"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "standard",++ "security": [++ {++ "openvibeToken": [++ "services.resource.read"++ ]++ }++ ],++ "parameters": [++ {++ "name": "ovrn",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/common.resource-list-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ }++ },++ "components": {++ "schemas": {++ "common.no-body.v1": {++ "title": "NoBody",++ "description": "common.no-body@1: the capability's request carries no body; its parameters are the path and query of the routes in implementedBy (an id, a page cursor). An input schema that says so explicitly, so every active capability names one (roadmap WS-C task 4).",++ "type": "object",++ "maxProperties": 0++ },++ "common.resource-list-result.v1": {++ "title": "ResourceListResult",++ "description": "A page of the resource index (roadmap WS-Z7).",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "resources",++ "next_cursor"++ ],++ "properties": {++ "resources": {++ "type": "array",++ "items": {++ "$ref": "#/components/schemas/common.resource-summary.v1"++ }++ },++ "next_cursor": {++ "type": [++ "string",++ "null"++ ]++ },++ "partial": {++ "type": "array",++ "description": "Authorities a merged index (OpenVibe.Services, ADR-048) could not read for this page: a slow or failing authority is omitted, never fails the page. Each entry names the authority and the problem code it answered. Added in 1.1.0; a single authority's own index leaves it out.",++ "items": {++ "type": "object",++ "required": [++ "service",++ "code"++ ],++ "additionalProperties": false,++ "properties": {++ "service": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9-]{1,39}$"++ },++ "code": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"++ }++ }++ }++ }++ }++ },++ "common.resource-summary.v1": {++ "title": "ResourceSummary",++ "description": "One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "kind",++ "service",++ "state",++ "created_at"++ ],++ "properties": {++ "id": {++ "type": "string"++ },++ "kind": {++ "type": "string",++ "description": "service.kind, e.g. watch.watch, actor.actor, media.object, events.subscription"++ },++ "service": {++ "type": "string"++ },++ "project_id": {++ "type": "string",++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "ovrn": {++ "type": "string",++ "maxLength": 200,++ "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."++ },++ "owner": {++ "$ref": "#/components/schemas/identity.subject-ref.v1"++ },++ "name": {++ "type": "string"++ },++ "state": {++ "type": "string"++ },++ "created_at": {++ "type": "string",++ "format": "date-time"++ },++ "updated_at": {++ "type": "string",++ "format": "date-time"++ },++ "usage": {++ "type": "object",++ "additionalProperties": {++ "type": "number",++ "minimum": 0++ },++ "properties": {},++ "description": "cost units by name (WS-Z1)"++ },++ "links": {++ "type": "object",++ "additionalProperties": false,++ "properties": {++ "self": {++ "type": "string",++ "format": "uri"++ },++ "console": {++ "type": "string",++ "format": "uri"++ },++ "docs": {++ "type": "string",++ "format": "uri"++ }++ }++ }++ }++ },++ "errors.problem.v1": {++ "title": "Problem",++ "description": "RFC 9457 problem details (application/problem+json) with a stable OpenVibe error code and trace identifiers. The legacy 'error' string is allowed during migration so existing clients keep working.",++ "type": "object",++ "required": [++ "type",++ "title",++ "status",++ "code"++ ],++ "additionalProperties": true,++ "properties": {++ "type": {++ "type": "string",++ "format": "uri-reference"++ },++ "title": {++ "type": "string",++ "minLength": 1++ },++ "status": {++ "type": "integer",++ "minimum": 400,++ "maximum": 599++ },++ "detail": {++ "type": "string"++ },++ "instance": {++ "type": "string",++ "format": "uri-reference"++ },++ "code": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"++ },++ "request_id": {++ "type": "string"++ },++ "trace_id": {++ "type": "string",++ "pattern": "^[0-9a-f]{32}$"++ },++ "errors": {++ "type": "array",++ "items": {++ "type": "object",++ "required": [++ "message"++ ],++ "properties": {++ "path": {++ "type": "string"++ },++ "message": {++ "type": "string"++ }++ }++ }++ },++ "error": {++ "type": "string",++ "description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."++ }++ }++ },++ "identity.subject-ref.v1": {++ "title": "SubjectRef",++ "description": "The one cross-platform reference to an actor. Issued by OpenVibe.Network. Never a service-local integer id.",++ "oneOf": [++ {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "const": "user"++ },++ "id": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "description": "UserSubject"++ },++ {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "const": "guest"++ },++ "id": {++ "type": "string",++ "pattern": "^gst_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "description": "GuestSubject"++ },++ {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "const": "app"++ },++ "id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "description": "AppSubject"++ },++ {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "const": "mod"++ },++ "id": {++ "type": "string",++ "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "description": "ModSubject"++ },++ {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "enum": [++ "service",++ "system"++ ]++ },++ "id": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9-]{1,39}$"++ }++ },++ "description": "PrincipalSubject"++ },++ {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "const": "agent"++ },++ "id": {++ "type": "string",++ "pattern": "^agt_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "description": "AgentSubject: an agent (OpenVibe.Actor, or a developer app's agent) acting under grants its owner delegated (roadmap WS-Z2). In an event envelope, on_behalf_of names the owner."++ }++ ]++ },++ "media.media-ref.v1": {++ "title": "MediaRef",++ "description": "Reference to a Media object. Canonical ids (med_<ULID>) arrive with the Wave 4 object model; until then legacy:<app>:<kind>:<id> addresses today's VOD/clip/file/paste/thumbnail rows.",++ "type": "object",++ "required": [++ "media_id"++ ],++ "additionalProperties": false,++ "properties": {++ "media_id": {++ "type": "string",++ "pattern": "^(med_[0-9A-HJKMNP-TV-Z]{26}|legacy:[a-z][a-z0-9-]{1,39}:(vod|clip|file|paste|thumbnail|avatar):[A-Za-z0-9._/-]{1,200})$"++ },++ "role": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]{1,39}$"++ },++ "variant": {++ "type": "string",++ "pattern": "^[a-z0-9][a-z0-9_-]{0,39}$"++ }++ }++ },++ "mods.mod-manifest.v1": {++ "title": "ModManifest",++ "description": "A mod as the platform knows it (ADR-013): who publishes it, which runtime runs it, which capabilities it asks for and the resources it may use. Requested capabilities are only a request: the install's approved subset is the grant, and trust tiers are install metadata that never change a grant check. The runtime-specific payload (a data pack, a script bundle) is not part of the manifest. 1.1.0 (openvibe-contracts v0.34.0) adds the optional permissions.readGrants and writeGrants, billingHooks and dependencies (ADR-013 amendment of 2026-09-24); every 1.0.0 manifest stays valid.",++ "type": "object",++ "required": [++ "id",++ "name",++ "version",++ "publisher",++ "target",++ "runtime",++ "permissions",++ "resources",++ "compatibility"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "Stable mod id; its principal subject is mod:<id>."++ },++ "name": {++ "type": "string",++ "minLength": 1,++ "maxLength": 80++ },++ "version": {++ "type": "string",++ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",++ "description": "Semantic version of this release."++ },++ "description": {++ "type": "string",++ "maxLength": 1000++ },++ "publisher": {++ "$ref": "#/components/schemas/identity.subject-ref.v1",++ "description": "Who publishes the mod (a user or an app subject)."++ },++ "target": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9-]{1,39}\\.[a-z][a-z0-9-]{1,39}$",++ "description": "Where the mod runs: <service>.<surface>, e.g. games.browser, games.source, live.overlay."++ },++ "runtime": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9-]{1,39}@[1-9][0-9]{0,3}$",++ "description": "Runtime adapter and its major version, e.g. games-content@1 (declarative data pack) or source-quickjs@1."++ },++ "permissions": {++ "type": "object",++ "required": [++ "capabilities"++ ],++ "additionalProperties": false,++ "properties": {++ "capabilities": {++ "description": "Capability ids the mod asks for (3+ segments). The target runtime binds only those it implements, and only once granted.",++ "type": "array",++ "maxItems": 64,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"++ }++ },++ "events": {++ "description": "Event types the mod wants delivered to it.",++ "type": "array",++ "maxItems": 64,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"++ }++ },++ "modules": {++ "description": "User-module namespaces the mod wants to read or write (a trailing .* names a family). A namespace listed here may be read and written; readGrants and writeGrants (1.1.0) say which.",++ "type": "array",++ "maxItems": 32,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"++ }++ },++ "mediaNamespaces": {++ "description": "Media namespaces the mod wants to read or write. A namespace listed here may be read and written; readGrants and writeGrants (1.1.0) say which.",++ "type": "array",++ "maxItems": 32,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"++ }++ },++ "readGrants": {++ "description": "1.1.0: namespaces the mod may only read. A namespace that is only here is read-only. The install's approved subset is still the grant.",++ "type": "object",++ "additionalProperties": false,++ "minProperties": 1,++ "properties": {++ "modules": {++ "description": "User-module namespaces (a trailing .* names a family).",++ "type": "array",++ "maxItems": 32,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"++ }++ },++ "mediaNamespaces": {++ "description": "Media namespaces.",++ "type": "array",++ "maxItems": 32,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"++ }++ }++ }++ },++ "writeGrants": {++ "description": "1.1.0: namespaces the mod may read and write. A write needs the namespace here, or in the older modules and mediaNamespaces lists, which mean read and write.",++ "type": "object",++ "additionalProperties": false,++ "minProperties": 1,++ "properties": {++ "modules": {++ "description": "User-module namespaces (a trailing .* names a family).",++ "type": "array",++ "maxItems": 32,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"++ }++ },++ "mediaNamespaces": {++ "description": "Media namespaces.",++ "type": "array",++ "maxItems": 32,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"++ }++ }++ }++ }++ }++ },++ "resources": {++ "type": "object",++ "required": [++ "cpuMs",++ "memoryMb",++ "storageMb"++ ],++ "additionalProperties": false,++ "description": "The budget the mod asks for. Runtimes meter it; the sandbox that enforces it lives in OpenVibe.Host (Stage C).",++ "properties": {++ "cpuMs": {++ "type": "number",++ "minimum": 0,++ "maximum": 1000,++ "description": "CPU milliseconds per tick (game runtimes) or per request."++ },++ "memoryMb": {++ "type": "integer",++ "minimum": 0,++ "maximum": 4096++ },++ "storageMb": {++ "type": "integer",++ "minimum": 0,++ "maximum": 102400++ },++ "outboundHosts": {++ "description": "Hosts the mod may reach over the network. Empty or absent = none.",++ "type": "array",++ "maxItems": 32,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$"++ }++ }++ }++ },++ "assets": {++ "description": "Assets the mod ships, as Media object references.",++ "type": "array",++ "maxItems": 256,++ "items": {++ "$ref": "#/components/schemas/media.media-ref.v1"++ }++ },++ "compatibility": {++ "type": "object",++ "required": [++ "runtime"++ ],++ "additionalProperties": false,++ "properties": {++ "runtime": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "Semver range of the runtime this release works with, e.g. \">=1.0.0 <2.0.0\"."++ },++ "contracts": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "Semver range of openvibe-contracts releases it was built against."++ }++ }++ },++ "homepage": {++ "type": "string",++ "pattern": "^https://[^\\s]{1,2000}$"++ },++ "billingHooks": {++ "description": "1.1.0: how the mod takes part in money, only through Billing and VIP primitives (ADR-013 amendment, ADR-012). entitlement: the mod checks that the person holds this entitlement (billing.entitlement.check or vip.entitlement.check, granted like any other capability). checkout: the mod sends the person to the platform's own checkout for this plan (vip.membership.checkout or a Billing intent). A mod never takes payment, sees payment details or holds a balance. Prices live in Billing and VIP, never in the manifest.",++ "type": "array",++ "maxItems": 32,++ "items": {++ "type": "object",++ "required": [++ "kind",++ "key"++ ],++ "additionalProperties": false,++ "properties": {++ "kind": {++ "enum": [++ "entitlement",++ "checkout"++ ]++ },++ "key": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_.:-]{0,127}$",++ "description": "The entitlement or plan key as Billing and VIP name it, e.g. vip.plan:pln_01jab… (lowercase, the form search.index-document@1 acl.entitlements uses)."++ },++ "description": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "What it unlocks or sells, shown at install."++ }++ }++ }++ },++ "dependencies": {++ "description": "1.1.0: other mods this release needs. A runtime refuses to enable the mod while a required dependency is not installed, not enabled or outside its range. An optional one is used only when present.",++ "type": "array",++ "maxItems": 32,++ "uniqueItems": true,++ "items": {++ "type": "object",++ "required": [++ "id",++ "version"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "version": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "Semver range of the dependency's releases this release works with, e.g. \">=1.2.0 <2.0.0\"."++ },++ "optional": {++ "type": "boolean",++ "default": false++ }++ }++ }++ }++ }++ },++ "services.app-manifest.v1": {++ "title": "AppManifest",++ "description": "PROPOSAL (OpenVibe.Services, roadmap Wave 20): an app release as the platform knows it. The app is a Network developer app (ADR-014): its id is the Network app id, its capabilities are only a request (the grants in Network are the authority), and trust tiers are metadata that never change a grant check. OpenVibe.Services validates with this schema, loaded into openvibe-contracts' validator, until Contracts publishes it as services.app-manifest@1.",++ "type": "object",++ "required": [++ "id",++ "name",++ "version",++ "publisher",++ "project_id",++ "capabilities",++ "compatibility"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network app id (its client_id). Its principal subject is app:<id>."},-- "instance": {++ "name": {"type": "string",-- "format": "uri-reference"++ "minLength": 1,++ "maxLength": 80},-- "code": {++ "version": {"type": "string",-- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"++ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",++ "description": "Semantic version of this release."},-- "request_id": {-- "type": "string"++ "description": {++ "type": "string",++ "maxLength": 1000},-- "trace_id": {++ "publisher": {++ "$ref": "#/components/schemas/identity.subject-ref.v1",++ "description": "Who publishes the release: the app itself or a member of its project."++ },++ "project_id": {"type": "string",-- "pattern": "^[0-9a-f]{32}$"++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network project that owns the app. Tenancy in other services is keyed by it (ADR-014)."},-- "errors": {++ "environment": {++ "enum": [++ "sandbox",++ "production"++ ],++ "description": "The app's environment. Apps never change environment."++ },++ "capabilities": {++ "description": "Capability ids the app asks for (3+ segments). Only active public (or partner, by staff allowance) capabilities can ever be granted to apps.","type": "array",++ "maxItems": 64,++ "uniqueItems": true,"items": {-- "type": "object",-- "required": [-- "message"-- ],-- "properties": {-- "path": {-- "type": "string"-- },-- "message": {-- "type": "string"++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"++ }++ },++ "events": {++ "type": "object",++ "additionalProperties": false,++ "properties": {++ "consumes": {++ "description": "Event types (or a trailing .* family) the app subscribes to.",++ "type": "array",++ "maxItems": 64,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"}}}},-- "error": {++ "redirect_uris": {++ "description": "Informational copy of the redirect URIs registered in Network (Network's list is the authority).",++ "type": "array",++ "maxItems": 10,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "maxLength": 500++ }++ },++ "homepage": {"type": "string",-- "description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."++ "pattern": "^https://[^\\s]{1,2000}$"++ },++ "repository": {++ "type": "string",++ "pattern": "^https://[^\\s]{1,2000}$"++ },++ "license": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "SPDX license expression."++ },++ "compatibility": {++ "type": "object",++ "required": [++ "contracts"++ ],++ "additionalProperties": false,++ "properties": {++ "contracts": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "Semver range of openvibe-contracts releases it was built against."++ },++ "sdk": {++ "type": "string",++ "minLength": 1,++ "maxLength": 100,++ "description": "Semver range of openvibe-sdk releases it uses."++ }++ }}}},-- "identity.subject-ref.v1": {-- "title": "SubjectRef",-- "description": "The one cross-platform reference to an actor. Issued by OpenVibe.Network. Never a service-local integer id.",-- "oneOf": [++ "services.release-manage-request.v1": {++ "title": "ServicesReleaseManageRequest",++ "description": "services.release-manage-request@1: bodies of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as services.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.",++ "anyOf": [{"type": "object","required": [-- "type",-- "id"++ "manifest"],-- "additionalProperties": false,"properties": {-- "type": {-- "const": "user"-- },-- "id": {++ "kind": {"type": "string",-- "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"++ "description": "mod, or app (the default)."++ },++ "manifest": {++ "anyOf": [++ {++ "$ref": "#/components/schemas/services.app-manifest.v1"++ },++ {++ "$ref": "#/components/schemas/mods.mod-manifest.v1"++ }++ ]++ },++ "notes": {++ "type": [++ "string",++ "null"++ ]++ },++ "publish": {++ "type": "boolean"}-- },-- "description": "UserSubject"++ }},{"type": "object","required": [-- "type",-- "id"++ "reason"],-- "additionalProperties": false,"properties": {-- "type": {-- "const": "guest"-- },-- "id": {++ "reason": {"type": "string",-- "pattern": "^gst_[0-9A-HJKMNP-TV-Z]{26}$"++ "minLength": 1,++ "pattern": "\\S"++ },++ "replacement": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^(rel_[0-9A-HJKMNP-TV-Z]{26})?$"}-- },-- "description": "GuestSubject"++ }++ },++ {++ "$ref": "#/components/schemas/common.no-body.v1"++ }++ ]++ },++ "services.release-manage-result.v1": {++ "title": "ServicesReleaseManageResult",++ "description": "services.release-manage-result@1: answers of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.",++ "type": "object",++ "required": [++ "release"++ ],++ "properties": {++ "release": {++ "$ref": "#/components/schemas/services.release.v1"++ },++ "warnings": {++ "type": "array",++ "items": {}},++ "event_id": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ },++ "services.release-read-result.v1": {++ "title": "ServicesReleaseReadResult",++ "description": "services.release-read-result@1: answers of services.release.read on OpenVibe.Services (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: services.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.",++ "anyOf": [{"type": "object","required": [-- "type",-- "id"++ "app_id",++ "trust",++ "releases"],-- "additionalProperties": false,"properties": {-- "type": {-- "const": "app"-- },-- "id": {++ "app_id": {"type": "string","pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "trust": {++ "type": "object",++ "required": [++ "tier"++ ],++ "properties": {++ "tier": {++ "type": "string"++ },++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ },++ "releases": {++ "type": "array",++ "items": {++ "$ref": "#/components/schemas/services.release.v1"++ }}-- },-- "description": "AppSubject"++ }},{"type": "object","required": [-- "type",-- "id"++ "app_id",++ "tier",++ "note_on_authority"],-- "additionalProperties": false,"properties": {-- "type": {-- "const": "mod"-- },-- "id": {++ "app_id": {"type": "string",-- "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "tier": {++ "type": "string"++ },++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "note_on_authority": {++ "type": "string"}-- },-- "description": "ModSubject"++ }},{"type": "object","required": [-- "type",-- "id"++ "release",++ "manifest"],-- "additionalProperties": false,"properties": {-- "type": {-- "enum": [-- "service",-- "system"-- ]++ "release": {++ "$ref": "#/components/schemas/services.release.v1"},-- "id": {-- "type": "string",-- "pattern": "^[a-z][a-z0-9-]{1,39}$"++ "manifest": {++ "anyOf": [++ {++ "$ref": "#/components/schemas/services.app-manifest.v1"++ },++ {++ "$ref": "#/components/schemas/mods.mod-manifest.v1"++ },++ {++ "type": "null"++ }++ ]}-- },-- "description": "PrincipalSubject"++ }++ }++ ]++ },++ "services.release.v1": {++ "title": "ServicesRelease",++ "description": "services.release@1: one release of an app or mod as OpenVibe.Services presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (services.app-manifest@1).",++ "type": "object",++ "required": [++ "id",++ "app_id",++ "kind",++ "name",++ "version",++ "status",++ "manifest_id",++ "created_at",++ "trust"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^rel_[0-9A-HJKMNP-TV-Z]{26}$"},-- {++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "project_id": {++ "type": [++ "string",++ "null"++ ]++ },++ "environment": {++ "enum": [++ "production",++ "sandbox"++ ]++ },++ "kind": {++ "enum": [++ "app",++ "mod"++ ]++ },++ "subject_id": {++ "type": [++ "string",++ "null"++ ]++ },++ "name": {++ "type": "string"++ },++ "version": {++ "type": "string"++ },++ "status": {++ "enum": [++ "draft",++ "published",++ "deprecated",++ "revoked"++ ]++ },++ "manifest_id": {++ "type": "string"++ },++ "compatibility": {++ "type": "object"++ },++ "notes": {++ "type": [++ "string",++ "null"++ ]++ },++ "created_at": {++ "type": "string"++ },++ "created_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "published_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "deprecated_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "deprecation_reason": {++ "type": [++ "string",++ "null"++ ]++ },++ "replacement": {++ "type": [++ "string",++ "null"++ ]++ },++ "revoked_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "revocation_reason": {++ "type": [++ "string",++ "null"++ ]++ },++ "trust": {"type": "object","required": [-- "type",-- "id"++ "tier"],-- "additionalProperties": false,"properties": {-- "type": {-- "const": "agent"++ "tier": {++ "type": "string"},-- "id": {-- "type": "string",-- "pattern": "^agt_[0-9A-HJKMNP-TV-Z]{26}$"++ "note": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_by": {++ "type": [++ "string",++ "null"++ ]++ },++ "set_at": {++ "type": [++ "string",++ "null"++ ]}-- },-- "description": "AgentSubject: an agent (OpenVibe.Actor, or a developer app's agent) acting under grants its owner delegated (roadmap WS-Z2). In an event envelope, on_behalf_of names the owner."++ }}-- ]++ }}},"securitySchemes": {@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Sources API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Space API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tips API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tools API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Trade API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.VIP API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Watch API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Wiki API",-- "version": "0.112.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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"@@@ -10933,6 +10933,130 @@ export interface CodesModerationActionPayload {details?: {};}++/** [email protected] (owner: services) */++++/** [email protected] (owner: services) */++/**++ * services.release-manage-result@1: answers of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.++ */++export interface ServicesReleaseManageResult {++ release: ServicesRelease;++ warnings?: unknown[];++ event_id?: string | null;++}++++/** [email protected] (owner: services) */++/**++ * services.release@1: one release of an app or mod as OpenVibe.Services presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (services.app-manifest@1).++ */++export interface ServicesRelease {++ id: string;++ app_id: string;++ project_id?: string | null;++ environment?: "production" | "sandbox";++ kind: "app" | "mod";++ subject_id?: string | null;++ name: string;++ version: string;++ status: "draft" | "published" | "deprecated" | "revoked";++ manifest_id: string;++ compatibility?: {};++ notes?: string | null;++ created_at: string;++ created_by?: string | null;++ published_at?: string | null;++ deprecated_at?: string | null;++ deprecation_reason?: string | null;++ replacement?: string | null;++ revoked_at?: string | null;++ revocation_reason?: string | null;++ trust: {++ tier: string;++ note?: string | null;++ set_by?: string | null;++ set_at?: string | null;++ };++}++++/** [email protected] (owner: services) */++/**++ * services.release-read-result@1: answers of services.release.read on OpenVibe.Services (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: services.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.++ */++export type ServicesReleaseReadResult =++ | {++ app_id: string;++ trust: {++ tier: string;++ note?: string | null;++ set_by?: string | null;++ set_at?: string | null;++ };++ releases: ServicesRelease[];++ }++ | {++ app_id: string;++ tier: string;++ note?: string | null;++ set_by?: string | null;++ set_at?: string | null;++ note_on_authority: string;++ }++ | {++ release: ServicesRelease;++ manifest: AppManifest | ModManifest | null;++ };++++/** [email protected] (owner: services) */++/**++ * services.release-manage-request@1: bodies of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as services.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.++ */++export type ServicesReleaseManageRequest =++ | {++ /**++ * mod, or app (the default).++ */++ kind?: string;++ manifest: AppManifest | ModManifest;++ notes?: string | null;++ publish?: boolean;++ }++ | {++ reason: string;++ replacement?: string | null;++ }++ | NoBody;++++/** [email protected] (owner: services) */++/**++ * services.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Services, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.++ */++export interface ServicesModerationActionPayload {++ /**++ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).++ */++ action: string;++ target: {++ /**++ * What was acted on, in the service's own words (post, page, release, user, player, …).++ */++ type: string;++ id: string;++ /**++ * Whose content or account it was, when known.++ */++ owner_subject?: string | null;++ };++ /**++ * The staff member or moderator (null only for a service acting without a person).++ */++ actor_subject: string | null;++ reason?: string | null;++ /**++ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.++ */++ details?: {};++}++/** [email protected] (owner: events) *//*** payload.redacts (ADR-026): a producer takes back events it published earlier. Any event may carry it, normally the producer's own *.deleted event. It names event_ids, or subject_type + subject_ids, or both, never an empty list. event_ids names events directly; subject_type + subject_ids names every stored event of the same source (for an app, the same project and environment) about those subjects. OpenVibe.Events rewrites each target into a tombstone (events.tombstone-payload@1) in the transaction that stores the directive. Naming another source's event is 403 events.redaction_not_allowed (the whole batch is refused); a malformed directive is 422 events.invalid_redaction. An event that carries a directive is never redacted itself.@@@ -2,19 +2,23 @@"id": "codes.release.manage","version": "1.0","owner": "codes",-- "status": "active",++ "status": "retired","visibility": "public",-- "description": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",++ "description": "RETIRED at 0.113.0: the developer portal moved to OpenVibe.Services. Use services.release.manage (audience openvibe.services); openvibe.codes portal paths redirect permanently to openvibe.services.","inputSchema": "codes.release-manage-request@1",-- "permissions": ["codes:releases:write"],-- "resourceConstraints": ["owner", "project"],++ "permissions": [++ "codes:releases:write"++ ],++ "resourceConstraints": [++ "owner",++ "project"++ ],"quotaClass": "codes-release-write",-- "events": ["codes.app.published", "codes.app.deprecated", "codes.app.revoked"],-- "implementedBy": [-- "POST /api/v1/apps/:app/releases",-- "POST /api/v1/releases/:id/publish",-- "POST /api/v1/releases/:id/deprecate",-- "POST /api/v1/releases/:id/revoke"++ "events": [++ "codes.app.published",++ "codes.app.deprecated",++ "codes.app.revoked"],++ "implementedBy": [],"outputSchema": "codes.release-manage-result@1"}@@@ -2,18 +2,18 @@"id": "codes.release.read","version": "1.0","owner": "codes",-- "status": "active",++ "status": "retired","visibility": "public",-- "description": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",++ "description": "RETIRED at 0.113.0: the developer portal moved to OpenVibe.Services. Use services.release.read (audience openvibe.services); openvibe.codes portal paths redirect permanently to openvibe.services.","outputSchema": "codes.release-read-result@1",-- "permissions": ["codes:releases:read"],-- "resourceConstraints": ["none"],++ "permissions": [++ "codes:releases:read"++ ],++ "resourceConstraints": [++ "none"++ ],"quotaClass": "codes-read","events": [],-- "implementedBy": [-- "GET /api/v1/apps/:app/releases",-- "GET /api/v1/apps/:app/trust",-- "GET /api/v1/releases/:id"-- ],++ "implementedBy": [],"inputSchema": "common.no-body@1"}@@@ -2,9 +2,9 @@"id": "codes.resource.read","version": "1.0","owner": "codes",-- "status": "active",++ "status": "retired","visibility": "first-party",-- "description": "Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:ovrn reads one by its OVRN (common.resource-summary@1). Every authority serves these for OpenVibe.Services to fan out and merge; Codes' own resources are its validated app and mod manifests (kind codes.manifest, id mfs_<ULID>) and its releases (kind codes.release, id rel_<ULID>), each carrying the Network project it was created in as its tenancy boundary. Trust tiers are per-app metadata and playground run logs are audit records, neither a resource; Codes hosts no repositories, so the catalog carries no codes.repo kind. Planned until Codes ships the index.",++ "description": "RETIRED at 0.113.0: Codes owns no resources any more. App and mod manifests and releases moved to OpenVibe.Services (kinds services.manifest and services.release), whose merged index (services.resource.read) lists them.","permissions": ["resources:read"],@@@ -13,10 +13,7 @@],"quotaClass": "standard","events": [],-- "implementedBy": [-- "GET /api/v1/resources",-- "GET /api/v1/resources/:ovrn"-- ],++ "implementedBy": [],"inputSchema": "common.no-body@1","outputSchema": "common.resource-list-result@1"}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "id": "services.release.manage",++ "version": "1.0",++ "owner": "services",++ "status": "active",++ "visibility": "public",++ "description": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",++ "inputSchema": "services.release-manage-request@1",++ "permissions": [++ "services:releases:write"++ ],++ "resourceConstraints": [++ "owner",++ "project"++ ],++ "quotaClass": "services-release-write",++ "events": [++ "services.app.published",++ "services.app.deprecated",++ "services.app.revoked"++ ],++ "implementedBy": [++ "POST /api/v1/apps/:app/releases",++ "POST /api/v1/releases/:id/publish",++ "POST /api/v1/releases/:id/deprecate",++ "POST /api/v1/releases/:id/revoke"++ ],++ "outputSchema": "services.release-manage-result@1"++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "id": "services.release.read",++ "version": "1.0",++ "owner": "services",++ "status": "active",++ "visibility": "public",++ "description": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",++ "outputSchema": "services.release-read-result@1",++ "permissions": [++ "services:releases:read"++ ],++ "resourceConstraints": [++ "none"++ ],++ "quotaClass": "services-read",++ "events": [],++ "implementedBy": [++ "GET /api/v1/apps/:app/releases",++ "GET /api/v1/apps/:app/trust",++ "GET /api/v1/releases/:id"++ ],++ "inputSchema": "common.no-body@1"++}@@@ -5,36 +5,28 @@"icon": "fa-server","accent": "#38bdf8","tagline": "Build with the whole network.",-- "description": "OpenVibe.Services will be the way into everything programmable on OpenVibe. Start from what you want to build (monitor a page and summarise changes, run an AI agent, process uploads, control a robot, add support to a site) and it assembles the services, keys, permissions and working code for you. Then operate it all in one place: projects, grants, usage, quotas, runs, events, deploys and health, with each service keeping its own data.",++ "description": "OpenVibe.Services is the way into everything programmable on OpenVibe: projects, apps, keys, grants and usage over Network's developer API; generated API, contract, SDK, capability and event docs; OAuth and webhook tools; playgrounds; app and mod releases; and one resource index over every service, with each service keeping its own data. Next: start from what you want to build and it assembles the services, keys, permissions and working code for you.","pillars": [{"title": "Discover",-- "text": "A catalog of services, recipes and templates, by what they do."++ "text": "Every service, capability, contract and event, with generated API references."},{"title": "Build",-- "text": "Projects, apps, keys, capabilities, playgrounds and starter code."++ "text": "Projects, apps, keys, grants, playgrounds, OAuth and webhook tools, starter code."},{-- "title": "Operate",-- "text": "Every resource across the network: runs, events, usage, quotas, health."++ "title": "Ship",++ "text": "App and mod manifests, releases and trust tiers, with a public page per app."},{-- "title": "Learn",-- "text": "Help, Wiki and Codes docs, linked from every page."++ "title": "Operate",++ "text": "Usage, quotas, exports and one resource index over the whole network."}],"keywords": "openvibe services, developer platform, open source backend, api platform, event bus api, ai gateway, website monitoring api, developer console",-- "launch": "the catalog and console over the services that already run (AI, Events, Media, Search, Sources, Host, Tools)",++ "launch": "the developer console and docs (moved from openvibe.codes) and the merged resource index","relationships": {-- "service": "services",-- "noRepo": true,-- "meanwhile": [-- {-- "label": "OpenVibe.Codes",-- "url": "https://openvibe.codes",-- "note": "The developer portal and docs work today."-- }-- ]++ "service": "services"}}@@@ -21,22 +21,13 @@"site": {"name": "Codes","icon": "codes",-- "tagline": "Build on OpenVibe",-- "what": "The developer portal: API and SDK docs, the service and capability registry, event schemas, credentials, playgrounds and mod publishing.",++ "tagline": "Code with any agent",++ "what": "The open coding-agent harness: Claude Code, Codex, OpenCode, Command Code, the DeepSeek API and self-hosted models behind one router with hand-offs, sessions and budgets, and the way to improve OpenVibe itself.","legalProfile": "ugc",-- "position": 7++ "position": 22},-- "capabilities": [-- "codes.resource.read",-- "codes.release.read",-- "codes.release.manage"-- ],-- "eventsProduced": [-- "codes.app.published",-- "codes.app.deprecated",-- "codes.app.revoked",-- "codes.moderation.action"-- ],++ "capabilities": [],++ "eventsProduced": [],"eventsConsumed": [],"namespacesOwned": ["codes.*"@@@ -51,15 +42,14 @@"deadlineSeconds": 5,"drains": ["HTTP server closed",-- "outbox relay stopped (awaited)","store closed"]},"startupRecovery": {"resumes": [{-- "kind": "outbox",-- "what": "unsent events in the outbox table go to OpenVibe.Events once the relay starts (at least once; Events dedupes by event_id)"++ "kind": "sessions",++ "what": "signed-in visitors keep their session cookies (verified offline against Network's JWKS); nothing else is pending: the harness catalog is read from the release at boot"}]},@@@ -80,5 +70,5 @@"none": "no claims: one process owns codes.db (better-sqlite3, single writer)"}},-- "notes": "Port 4900, unit openvibe-codes.service, state /var/lib/openvibe-codes. The developer portal (ADR-014): projects, members, apps, credentials, grants and quotas are OWNED BY NETWORK and shown through Network's /api/v1/projects API with the signed-in person's own token; Codes stores none of them and never a secret. Codes owns only manifests, releases (+ append-only release_log), trust tiers (metadata) and playground run logs in its own SQLite. Consumes OpenVibe.Network (SSO with PKCE S256 as OAuth client codes, JWKS, the projects API, the registry, client-credentials) and publishes through OpenVibe.Events (events.event.publish). Playgrounds call Events and Media with the APP's own token only. Docs are generated at boot from the pinned openvibe-contracts and openvibe-sdk."++ "notes": "Port 4900, unit openvibe-codes.service. The open coding-agent harness (owner 2026-10-08): the harness catalog and router (GET /api/v1/harnesses, POST /api/v1/harnesses/route), the way to improve OpenVibe (contributing, code of conduct, the contributor ladder) and permanent redirects from the former developer-portal paths to openvibe.services, where the portal moved (manifests, releases, trust, playgrounds, docs, OAuth and webhook tools)."}@@@ -87,7 +87,6 @@"billing.staff.action","blog.moderation.action","chat.moderation.action",-- "codes.moderation.action","community.moderation.action","coupons.moderation.action","deals.moderation.action",@@@ -99,6 +98,7 @@"media.moderation.action","news.moderation.action","reviews.moderation.action",++ "services.moderation.action","space.moderation.action","tips.interaction.moderated","tools.moderation.action",@@@ -1,7 +1,7 @@{-- "version": "0.0.0",++ "version": "0.1.0","contractRanges": {-- "openvibe-contracts": ">=0.94.0 <1.0.0"++ "openvibe-contracts": ">=0.113.0 <1.0.0"},"id": "services","name": "OpenVibe.Services",@@@ -12,35 +12,74 @@],"publicOrigin": "https://openvibe.services","exposure": {-- "state": "internal",-- "publicSite": "placeholder",-- "note": "deployed on loopback :4930 (2026-10-07); openvibe.services keeps its OpenVibe.Sites placeholder until Services has a product surface"++ "state": "live",++ "publicSite": "service"},"capabilities": [-- "services.resource.read"++ "services.resource.read",++ "services.release.read",++ "services.release.manage"++ ],++ "eventsProduced": [++ "services.app.published",++ "services.app.deprecated",++ "services.app.revoked",++ "services.moderation.action"],-- "eventsProduced": [],"eventsConsumed": [],-- "namespacesOwned": [],++ "namespacesOwned": [++ "services.*"++ ],"lifecycle": {"liveness": {-- "none": "not built yet; nothing listens on a loopback address"++ "endpoint": "/api/health",++ "means": "the process is up and answers HTTP; it checks nothing else (the database and dependencies are what ready checks)"},"shutdown": {-- "none": "not built yet; nothing runs or drains"++ "signal": "SIGTERM",++ "deadlineSeconds": 5,++ "drains": [++ "HTTP server closed",++ "Network key refresher stopped",++ "outbox relay stopped (awaited)",++ "store closed"++ ]},"startupRecovery": {-- "none": "not built yet; nothing starts"++ "resumes": [++ {++ "kind": "outbox",++ "what": "unsent events in the outbox table go to OpenVibe.Events once the relay starts (at least once; Events dedupes by event_id)"++ }++ ]},"rollback": {-- "none": "not built yet; nothing is released or rolled back"++ "conditions": [++ "automatic: ovhost deploy puts the previous sha back and restarts again when the ready URL does not answer 2xx within ready.timeoutSeconds after the restart (exit 3)",++ "manual: ovhost rollback <service> --to <sha>"++ ],++ "window": "automatic only while ovhost waits for readiness after the restart (30 s in host.example.json); manual afterwards, as long as no blocker applies",++ "blockers": [++ "the console tables arrive in migration 0002 (expand only): a release from before it simply never reads them"++ ]},"contracts": {-- "range": ">=0.94.0 <1.0.0"++ "range": ">=0.113.0 <1.0.0"},"leases": {-- "none": "not built yet; nothing runs"++ "none": "no claims: the outbox relay is the only background work and Events dedupes by event_id"}},-- "notes": "The developer platform of the network (plan T13, ADR-048): where projects, apps, keys, grants, capabilities, usage, quotas, runs, events, deploys and health over every service are looked up, with each service keeping its own data. Serves its merged resource index on loopback :4930 (plan T13 step 4); services.resource.read is its first capability."++ "notes": "Port 4930, unit openvibe-services.service. The developer platform of the network (plan T13, ADR-048; the developer portal moved here from OpenVibe.Codes, ADR-014): projects, members, apps, credentials, grants and quotas are OWNED BY NETWORK and shown through Network's /api/v1/projects API with the signed-in person's own token; Services stores none of them and never a secret. Services owns manifests, releases (+ append-only release_log), trust tiers (metadata) and playground run logs, and serves the merged resource index over every authority (services.resource.read). Consumes OpenVibe.Network (SSO with PKCE S256 as OAuth client services, JWKS, the projects API, the registry, client-credentials) and publishes through OpenVibe.Events (events.event.publish). Playgrounds call Events and Media with the APP's own token only. Docs are generated at boot from the pinned openvibe-contracts and openvibe-sdk.",++ "health": "/api/health",++ "ready": "/api/ready",++ "internalOrigin": "http://127.0.0.1:4930",++ "site": {++ "name": "Services",++ "icon": "services",++ "tagline": "Build on OpenVibe",++ "what": "The developer platform: projects, apps, keys, grants and usage; API, contract, SDK and event docs; OAuth and webhook tools, playgrounds and app releases.",++ "legalProfile": "ugc",++ "position": 7++ }}@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.112.0",++ "version": "0.113.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.112.0",++ "version": "0.113.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.112.0",++ "version": "0.113.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",@@@ -805,13 +805,14 @@ await assert.rejects(failing.getToken(), /401: invalid_client/);// without an older shape are common.moderation-action@1, and Network consumes every one of them.{const moderation = contracts.catalog.filter(c => /\.moderation\.action$/.test(c.id));-- for (const svc of ['media', 'tools', 'games', 'wiki', 'blog', 'news', 'reviews', 'deals', 'coupons', 'trade', 'codes', 'space']) {++ for (const svc of ['media', 'tools', 'games', 'wiki', 'blog', 'news', 'reviews', 'deals', 'coupons', 'trade', 'services', 'space']) {const id = `${svc}.moderation.action`;const c = moderation.find(x => x.id === id);ok(c && c.owner === svc && c.adr === 'ADR-022', `${id} is owned by ${svc}`);ok(contracts.schema(id).$ref === '../../common/moderation-action.v1.json', `${id} is a common.moderation-action@1`);}-- for (const c of moderation) ok(services.get('network').eventsConsumed.includes(c.id), `network consumes ${c.id} into the moderation audit log`);++ // A retired type (codes.moderation.action, 0.113.0) stays loadable for history; nothing produces it any more.++ for (const c of moderation.filter(x => x.status !== 'retired')) ok(services.get('network').eventsConsumed.includes(c.id), `network consumes ${c.id} into the moderation audit log`);const M = (v) => contracts.validate('common.moderation-action@1', v).valid;const base = { action: 'post.hidden', target: { type: 'post', id: 'p1', owner_subject: null }, actor_subject: null };ok(M(base) && M({ ...base, reason: 'spam', details: { previous: 'published' } }), 'action, target and actor_subject are enough; reason and details are optional');@@@ -913,7 +914,7 @@ sub(path.join(__dirname, 'bot-manifest.test.js'));sub(path.join(__dirname, 'product-catalog.test.js'));// Named object zones: identity, retired names, list limits and per-zone usage (ADR-031 amendment 2026-10-02).sub(path.join(__dirname, 'zones.test.js'));--// *.usage.recorded rollups are counts: only network, codes and zone may consume one, never billing (T5 step 8).++// *.usage.recorded rollups are counts: only network, services and zone may consume one, never billing (T5 step 8).sub(path.join(__dirname, 'usage-topics.test.js'));sub(path.join(__dirname, 'billing-grace.test.js'));sub(path.join(__dirname, 'resources.test.js'));@@@ -1,5 +1,5 @@'use strict';--// T5 step 8: *.usage.recorded rollups are counts for dashboards and quotas, never money. Only network, codes and++// T5 step 8: *.usage.recorded rollups are counts for dashboards and quotas, never money. Only network, services and// zone may consume one; Billing never does (it rates platform.usage-sample readings, billing.usage.record).const assert = require('assert');const fs = require('fs');@@@ -7,7 +7,7 @@ const path = require('path');const { capabilities, services, schema } = require('..');const dir = path.join(__dirname, '..', 'manifests', 'services');--const MAY_CONSUME = new Set(['network', 'codes', 'zone']);++const MAY_CONSUME = new Set(['network', 'services', 'zone']);const isUsageTopic = (t) => /\.usage\.recorded$/.test(t);const consumers = [];@@@ -19,7 +19,7 @@ for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.json')).sort()) {}for (const c of consumers) {-- assert.ok(MAY_CONSUME.has(c.id), `${c.id} consumes ${c.topics.join(', ')}: only network, codes and zone may consume a *.usage.recorded topic`);++ assert.ok(MAY_CONSUME.has(c.id), `${c.id} consumes ${c.topics.join(', ')}: only network, services and zone may consume a *.usage.recorded topic`);}assert.ok(!consumers.some((c) => c.id === 'billing'), 'billing never consumes a *.usage.recorded topic');assert.ok(consumers.some((c) => c.id === 'network'), 'network consumes the usage rollups it adds up per project');
@@ -4,6 +4,21 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
@@ -4,6 +4,21 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
the notes were in the tag and commit messages (`git tag -n1`).
+## 0.113.0 — 2026-10-08
+
+**The developer portal moves from OpenVibe.Codes to OpenVibe.Services; Codes becomes the open coding-agent harness**
+(owner decision 2026-10-08; plan T13 and T16 notes). Codes' portal data in production is empty, so the names move at once.
+- New in Services' namespace: `services.release.read` and `services.release.manage` (audience `openvibe.services`), the
+ schemas `services.app-manifest@1`, `services.release@1`, `services.release-read-result@1`,
+ `services.release-manage-request@1`, `services.release-manage-result@1`, the event payload `services.moderation.action@1`
+ and the events `services.app.published|deprecated|revoked`. They are the `codes.*` ones under the new owner and audience.
+- Retired, kept loadable: `codes.release.read`, `codes.release.manage`, `codes.resource.read` and the six `codes.*` schemas
+ (`compatibility/deprecations.json` names each replacement). Network consumes `services.moderation.action`.
+- `manifests/services/services.json`: live with `publicSite: service`; it owns manifests, releases, trust tiers and
+ playground logs (kinds `services.manifest` `mfs_`, `services.release` `rel_`) besides the merged index; its site
+ block is the developer platform's. `manifests/products/openvibe.services.json` describes the console and docs.
+- `manifests/services/codes.json`: no capability or event; the site block describes the harness (position 22).
+
## 0.112.0 — 2026-10-07
## 0.112.0 — 2026-10-07
**Robots driven through the relay plugin.** `bot.robot-profile@1` is 1.1.0: `mapping.driver` gains `relay`, the
**Robots driven through the relay plugin.** `bot.robot-profile@1` is 1.1.0: `mapping.driver` gains `relay`, the
@@ -63,6 +63,48 @@
@@ -63,6 +63,48 @@
"since": "0.110.0",
"since": "0.110.0",
"removeAfter": "1.0.0",
"removeAfter": "1.0.0",
"reason": "Community forum producer retired after the move to OpenVibe.Space; historical payload remains loadable"
"reason": "Community forum producer retired after the move to OpenVibe.Space; historical payload remains loadable"
+ },
+ {
+ "id": "codes.app-manifest",
+ "replacement": "services.app-manifest@1",
+ "since": "0.113.0",
+ "removeAfter": "1.0.0",
+ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"
+ },
+ {
+ "id": "codes.release-manage-result",
+ "replacement": "services.release-manage-result@1",
+ "since": "0.113.0",
+ "removeAfter": "1.0.0",
+ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"
+ },
+ {
+ "id": "codes.release",
+ "replacement": "services.release@1",
+ "since": "0.113.0",
+ "removeAfter": "1.0.0",
+ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"
+ },
+ {
+ "id": "codes.release-read-result",
+ "replacement": "services.release-read-result@1",
+ "since": "0.113.0",
+ "removeAfter": "1.0.0",
+ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"
+ },
+ {
+ "id": "codes.release-manage-request",
+ "replacement": "services.release-manage-request@1",
+ "since": "0.113.0",
+ "removeAfter": "1.0.0",
+ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"
+ },
+ {
+ "id": "codes.moderation.action",
+ "replacement": "services.moderation.action@1",
+ "since": "0.113.0",
+ "removeAfter": "1.0.0",
+ "reason": "the developer portal (manifests, releases, trust, playgrounds) moves from OpenVibe.Codes to OpenVibe.Services (owner 2026-10-08; Codes becomes the open coding-agent harness); retired at once, kept loadable for historical events and compatibility"
}
}
]
]
}
}
@@ -322,7 +322,7 @@
@@ -322,7 +322,7 @@
"schema": "codes/app-manifest.v1.json",
"schema": "codes/app-manifest.v1.json",
"visibility": "public",
"visibility": "public",
"compatibility": "backward",
"compatibility": "backward",
- "status": "active",
+ "status": "retired",
"adr": "ADR-014"
"adr": "ADR-014"
},
},
{
{
@@ -332,7 +332,7 @@
@@ -332,7 +332,7 @@
"schema": "codes/release-manage-result.v1.json",
"schema": "codes/release-manage-result.v1.json",
"visibility": "first-party",
"visibility": "first-party",
"compatibility": "backward",
"compatibility": "backward",
- "status": "active"
+ "status": "retired"
},
},
{
{
"id": "codes.release",
"id": "codes.release",
@@ -341,7 +341,7 @@
@@ -341,7 +341,7 @@
"schema": "codes/release.v1.json",
"schema": "codes/release.v1.json",
"visibility": "first-party",
"visibility": "first-party",
"compatibility": "backward",
"compatibility": "backward",
- "status": "active"
+ "status": "retired"
},
},
{
{
"id": "codes.release-read-result",
"id": "codes.release-read-result",
@@ -350,7 +350,7 @@
@@ -350,7 +350,7 @@
"schema": "codes/release-read-result.v1.json",
"schema": "codes/release-read-result.v1.json",
"visibility": "first-party",
"visibility": "first-party",
"compatibility": "backward",
"compatibility": "backward",
- "status": "active"
+ "status": "retired"
},
},
{
{
"id": "codes.release-manage-request",
"id": "codes.release-manage-request",
@@ -359,7 +359,7 @@
@@ -359,7 +359,7 @@
"schema": "codes/release-manage-request.v1.json",
"schema": "codes/release-manage-request.v1.json",
"visibility": "first-party",
"visibility": "first-party",
"compatibility": "backward",
"compatibility": "backward",
- "status": "active"
+ "status": "retired"
},
},
{
{
"id": "codes.moderation.action",
"id": "codes.moderation.action",
@@ -368,6 +368,62 @@
@@ -368,6 +368,62 @@
"schema": "events/payloads/codes.moderation.action.v1.json",
"schema": "events/payloads/codes.moderation.action.v1.json",
"visibility": "first-party",
"visibility": "first-party",
"compatibility": "backward",
"compatibility": "backward",
+ "status": "retired",
+ "adr": "ADR-022"
+ },
+ {
+ "id": "services.app-manifest",
+ "version": "1.0.0",
+ "owner": "services",
+ "schema": "services/app-manifest.v1.json",
+ "visibility": "public",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-014"
+ },
+ {
+ "id": "services.release-manage-result",
+ "version": "1.0.0",
+ "owner": "services",
+ "schema": "services/release-manage-result.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "services.release",
+ "version": "1.0.0",
+ "owner": "services",
+ "schema": "services/release.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "services.release-read-result",
+ "version": "1.0.0",
+ "owner": "services",
+ "schema": "services/release-read-result.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "services.release-manage-request",
+ "version": "1.0.0",
+ "owner": "services",
+ "schema": "services/release-manage-request.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "services.moderation.action",
+ "version": "1.0.0",
+ "owner": "services",
+ "schema": "events/payloads/services.moderation.action.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
"status": "active",
"status": "active",
"adr": "ADR-022"
"adr": "ADR-022"
},
},
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/services.moderation.action.v1.json",
+ "title": "ServicesModerationActionPayload",
+ "description": "services.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Services, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,68 @@
@@ -0,0 +1,68 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/app-manifest.v1.json",
+ "title": "AppManifest",
+ "description": "PROPOSAL (OpenVibe.Services, roadmap Wave 20): an app release as the platform knows it. The app is a Network developer app (ADR-014): its id is the Network app id, its capabilities are only a request (the grants in Network are the authority), and trust tiers are metadata that never change a grant check. OpenVibe.Services validates with this schema, loaded into openvibe-contracts' validator, until Contracts publishes it as services.app-manifest@1.",
+ "type": "object",
+ "required": ["id", "name", "version", "publisher", "project_id", "capabilities", "compatibility"],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network app id (its client_id). Its principal subject is app:<id>."
+ },
+ "name": { "type": "string", "minLength": 1, "maxLength": 80 },
+ "version": {
+ "type": "string",
+ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",
+ "description": "Semantic version of this release."
+ },
+ "description": { "type": "string", "maxLength": 1000 },
+ "publisher": {
+ "$ref": "../identity/subject-ref.v1.json",
+ "description": "Who publishes the release: the app itself or a member of its project."
+ },
+ "project_id": {
+ "type": "string",
+ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network project that owns the app. Tenancy in other services is keyed by it (ADR-014)."
+ },
+ "environment": { "enum": ["sandbox", "production"], "description": "The app's environment. Apps never change environment." },
+ "capabilities": {
+ "description": "Capability ids the app asks for (3+ segments). Only active public (or partner, by staff allowance) capabilities can ever be granted to apps.",
+ "type": "array",
+ "maxItems": 64,
+ "uniqueItems": true,
+ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$" }
+ },
+ "events": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "consumes": {
+ "description": "Event types (or a trailing .* family) the app subscribes to.",
+ "type": "array", "maxItems": 64, "uniqueItems": true,
+ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$" }
+ }
+ }
+ },
+ "redirect_uris": {
+ "description": "Informational copy of the redirect URIs registered in Network (Network's list is the authority).",
+ "type": "array", "maxItems": 10, "uniqueItems": true,
+ "items": { "type": "string", "maxLength": 500 }
+ },
+ "homepage": { "type": "string", "pattern": "^https://[^\\s]{1,2000}$" },
+ "repository": { "type": "string", "pattern": "^https://[^\\s]{1,2000}$" },
+ "license": { "type": "string", "minLength": 1, "maxLength": 100, "description": "SPDX license expression." },
+ "compatibility": {
+ "type": "object",
+ "required": ["contracts"],
+ "additionalProperties": false,
+ "properties": {
+ "contracts": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Semver range of openvibe-contracts releases it was built against." },
+ "sdk": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Semver range of openvibe-sdk releases it uses." }
+ }
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/release-manage-request.v1.json",
+ "title": "ServicesReleaseManageRequest",
+ "description": "services.release-manage-request@1: bodies of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as services.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "manifest"
+ ],
+ "properties": {
+ "kind": {
+ "type": "string",
+ "description": "mod, or app (the default)."
+ },
+ "manifest": {
+ "anyOf": [
+ {
+ "$ref": "app-manifest.v1.json"
+ },
+ {
+ "$ref": "../mods/mod-manifest.v1.json"
+ }
+ ]
+ },
+ "notes": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "publish": {
+ "type": "boolean"
+ }
+ }
+ },
+ {
+ "type": "object",
+ "required": [
+ "reason"
+ ],
+ "properties": {
+ "reason": {
+ "type": "string",
+ "minLength": 1,
+ "pattern": "\\S"
+ },
+ "replacement": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^(rel_[0-9A-HJKMNP-TV-Z]{26})?$"
+ }
+ }
+ },
+ {
+ "$ref": "../common/no-body.v1.json"
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/release-manage-result.v1.json",
+ "title": "ServicesReleaseManageResult",
+ "description": "services.release-manage-result@1: answers of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.",
+ "type": "object",
+ "required": [
+ "release"
+ ],
+ "properties": {
+ "release": {
+ "$ref": "release.v1.json"
+ },
+ "warnings": {
+ "type": "array",
+ "items": {}
+ },
+ "event_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,120 @@
@@ -0,0 +1,120 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/release-read-result.v1.json",
+ "title": "ServicesReleaseReadResult",
+ "description": "services.release-read-result@1: answers of services.release.read on OpenVibe.Services (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: services.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "app_id",
+ "trust",
+ "releases"
+ ],
+ "properties": {
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "trust": {
+ "type": "object",
+ "required": [
+ "tier"
+ ],
+ "properties": {
+ "tier": {
+ "type": "string"
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ },
+ "releases": {
+ "type": "array",
+ "items": {
+ "$ref": "release.v1.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "required": [
+ "app_id",
+ "tier",
+ "note_on_authority"
+ ],
+ "properties": {
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "tier": {
+ "type": "string"
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "note_on_authority": {
+ "type": "string"
+ }
+ }
+ },
+ {
+ "type": "object",
+ "required": [
+ "release",
+ "manifest"
+ ],
+ "properties": {
+ "release": {
+ "$ref": "release.v1.json"
+ },
+ "manifest": {
+ "anyOf": [
+ {
+ "$ref": "app-manifest.v1.json"
+ },
+ {
+ "$ref": "../mods/mod-manifest.v1.json"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,152 @@
@@ -0,0 +1,152 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/release.v1.json",
+ "title": "ServicesRelease",
+ "description": "services.release@1: one release of an app or mod as OpenVibe.Services presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (services.app-manifest@1).",
+ "type": "object",
+ "required": [
+ "id",
+ "app_id",
+ "kind",
+ "name",
+ "version",
+ "status",
+ "manifest_id",
+ "created_at",
+ "trust"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^rel_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "project_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "environment": {
+ "enum": [
+ "production",
+ "sandbox"
+ ]
+ },
+ "kind": {
+ "enum": [
+ "app",
+ "mod"
+ ]
+ },
+ "subject_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "name": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "draft",
+ "published",
+ "deprecated",
+ "revoked"
+ ]
+ },
+ "manifest_id": {
+ "type": "string"
+ },
+ "compatibility": {
+ "type": "object"
+ },
+ "notes": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "created_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "published_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "deprecated_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "deprecation_reason": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "replacement": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "revoked_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "revocation_reason": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "trust": {
+ "type": "object",
+ "required": [
+ "tier"
+ ],
+ "properties": {
+ "tier": {
+ "type": "string"
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ }
+}
@@ -90,11 +90,11 @@ below is in `lib/ids.js` except `act`, `run` and `zon`, which are proposed and n
@@ -90,11 +90,11 @@ below is in `lib/ids.js` except `act`, `run` and `zon`, which are proposed and n
| Service | Kind | Id prefix |
| Service | Kind | Id prefix |
|---|---|---|
|---|---|---|
| Actor | `actor.actor` | `act` (proposed, not in `lib/ids.js`) |
| Actor | `actor.actor` | `act` (proposed, not in `lib/ids.js`) |
-| Codes | `codes.manifest` | `mfs` |
-| Codes | `codes.release` | `rel` |
| Events | `events.queue` | **future: when Events stores queues** |
| Events | `events.queue` | **future: when Events stores queues** |
| Events | `events.subscription` | `sub` |
| Events | `events.subscription` | `sub` |
| Media | `media.object` | `med` |
| Media | `media.object` | `med` |
+| Services | `services.manifest` | `mfs` (was `codes.manifest` until 0.113.0, when the developer portal moved from Codes to Services) |
+| Services | `services.release` | `rel` (was `codes.release` until 0.113.0) |
| Run | `run.sandbox` | `run` (proposed, not in `lib/ids.js`; collides with the existing `run_` AI run ids, `contracts/ai/run.v1.json`) |
| Run | `run.sandbox` | `run` (proposed, not in `lib/ids.js`; collides with the existing `run_` AI run ids, `contracts/ai/run.v1.json`) |
| Watch | `watch.watch` | `wch` |
| Watch | `watch.watch` | `wch` |
| Zone | `zone.object-zone` | `zon` (proposed, not in `lib/ids.js`; today only a usage-recorded description field `<zon_id>`) |
| Zone | `zone.object-zone` | `zon` (proposed, not in `lib/ids.js`; today only a usage-recorded description field `<zon_id>`) |
new file mode 100644
new file mode 100644
@@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
+{
+ "id": "app_lowercase",
+ "name": "My app",
+ "version": "0.1.0",
+ "publisher": {
+ "type": "app",
+ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0"
+ },
+ "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0",
+ "environment": "sandbox",
+ "capabilities": [],
+ "compatibility": {
+ "contracts": "^0.26.0",
+ "sdk": "^0.2.2"
+ }
+}
\ No newline at end of file
\ No newline at end of file
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
+{
+ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0",
+ "name": "My app",
+ "version": "0.1.0",
+ "publisher": {
+ "type": "app",
+ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0"
+ },
+ "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0",
+ "environment": "sandbox",
+ "capabilities": [],
+ "compatibility": {}
+}
\ No newline at end of file
\ No newline at end of file
new file mode 100644
new file mode 100644
@@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
+{
+ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0",
+ "name": "My app",
+ "version": "0.1.0",
+ "publisher": {
+ "type": "app",
+ "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0"
+ },
+ "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0",
+ "environment": "sandbox",
+ "capabilities": [],
+ "compatibility": {
+ "contracts": "^0.26.0",
+ "sdk": "^0.2.2"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "action": "release.revoked",
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "malware in 1.4.2"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
+{
+ "action": "release.revoked",
+ "target": {
+ "type": "release",
+ "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPT",
+ "owner_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
+ },
+ "actor_subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "reason": "malware in 1.4.2",
+ "details": {
+ "app": "app_3",
+ "version": "1.4.2"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "reason": " ", "manifest": 5 }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "kind": "app", "manifest": { "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0", "name": "My app", "version": "0.1.0", "publisher": { "type": "app", "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0" }, "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0", "environment": "sandbox", "capabilities": [], "compatibility": { "contracts": "^0.26.0", "sdk": "^0.2.2" }}, "notes": "First release.", "publish": true }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "reason": "superseded by 1.5.0", "replacement": "rel_01JAB2C3D4E5F6G7H8J9K0MNPS" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "warnings": [] }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "release": { "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }, "event_id": "evt_01JAB2C3D4E5F6G7H8J9K0MNPV" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "app_id": "not-an-app", "trust": { "tier": "unreviewed" }, "releases": [] }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "release": { "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }, "manifest": "not a manifest" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null }, "releases": [ { "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } } ] }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "release": { "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }, "manifest": { "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0", "name": "My app", "version": "0.1.0", "publisher": { "type": "app", "id": "app_01JABCDEFGHJKMNPQRSTVWXYZ0" }, "project_id": "prj_01JABCDEFGHJKMNPQRSTVWXYZ0", "environment": "sandbox", "capabilities": [], "compatibility": { "contracts": "^0.26.0", "sdk": "^0.2.2" }} }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "tier": "reviewed", "note": "checked 1.4.0", "set_by": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ", "set_at": "2026-09-25T10:00:00.000Z", "note_on_authority": "metadata only; grants in OpenVibe.Network are the authority" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "live", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "id": "rel_01JAB2C3D4E5F6G7H8J9K0MNPQ", "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPR", "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPS", "environment": "production", "kind": "app", "subject_id": null, "name": "Stream Deck Bridge", "version": "1.4.0", "status": "published", "manifest_id": "man_01JAB2C3D4E5F6G7H8J9K0MNPT", "compatibility": { "openvibe-contracts": ">=0.40.0" }, "notes": "Scene switching over the chat socket.", "created_at": "2026-09-24T10:00:00.000Z", "created_by": "app:app_01JAB2C3D4E5F6G7H8J9K0MNPR", "published_at": "2026-09-24T10:05:00.000Z", "deprecated_at": null, "deprecation_reason": null, "replacement": null, "revoked_at": null, "revocation_reason": null, "trust": { "tier": "unreviewed", "note": "", "set_by": null, "set_at": null } }
@@ -4674,7 +4674,7 @@
@@ -4674,7 +4674,7 @@
"codes.app-manifest": {
"codes.app-manifest": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"schema": {
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/codes/app-manifest.v1.json",
"$id": "https://openvibe.network/contracts/codes/app-manifest.v1.json",
@@ -4804,7 +4804,7 @@
@@ -4804,7 +4804,7 @@
"codes.release-manage-result": {
"codes.release-manage-result": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"schema": {
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/codes/release-manage-result.v1.json",
"$id": "https://openvibe.network/contracts/codes/release-manage-result.v1.json",
@@ -4834,7 +4834,7 @@
@@ -4834,7 +4834,7 @@
"codes.release": {
"codes.release": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"schema": {
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/codes/release.v1.json",
"$id": "https://openvibe.network/contracts/codes/release.v1.json",
@@ -4991,7 +4991,7 @@
@@ -4991,7 +4991,7 @@
"codes.release-read-result": {
"codes.release-read-result": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"schema": {
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/codes/release-read-result.v1.json",
"$id": "https://openvibe.network/contracts/codes/release-read-result.v1.json",
@@ -5116,7 +5116,7 @@
@@ -5116,7 +5116,7 @@
"codes.release-manage-request": {
"codes.release-manage-request": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"schema": {
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/codes/release-manage-request.v1.json",
"$id": "https://openvibe.network/contracts/codes/release-manage-request.v1.json",
@@ -5183,7 +5183,7 @@
@@ -5183,7 +5183,7 @@
"codes.moderation.action": {
"codes.moderation.action": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"schema": {
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/payloads/codes.moderation.action.v1.json",
"$id": "https://openvibe.network/contracts/events/payloads/codes.moderation.action.v1.json",
@@ -5192,6 +5192,527 @@
@@ -5192,6 +5192,527 @@
"$ref": "../../common/moderation-action.v1.json"
"$ref": "../../common/moderation-action.v1.json"
}
}
},
},
+ "services.app-manifest": {
+ "version": "1.0.0",
+ "owner": "services",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/app-manifest.v1.json",
+ "title": "AppManifest",
+ "description": "PROPOSAL (OpenVibe.Services, roadmap Wave 20): an app release as the platform knows it. The app is a Network developer app (ADR-014): its id is the Network app id, its capabilities are only a request (the grants in Network are the authority), and trust tiers are metadata that never change a grant check. OpenVibe.Services validates with this schema, loaded into openvibe-contracts' validator, until Contracts publishes it as services.app-manifest@1.",
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "publisher",
+ "project_id",
+ "capabilities",
+ "compatibility"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network app id (its client_id). Its principal subject is app:<id>."
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 80
+ },
+ "version": {
+ "type": "string",
+ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",
+ "description": "Semantic version of this release."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1000
+ },
+ "publisher": {
+ "$ref": "../identity/subject-ref.v1.json",
+ "description": "Who publishes the release: the app itself or a member of its project."
+ },
+ "project_id": {
+ "type": "string",
+ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network project that owns the app. Tenancy in other services is keyed by it (ADR-014)."
+ },
+ "environment": {
+ "enum": [
+ "sandbox",
+ "production"
+ ],
+ "description": "The app's environment. Apps never change environment."
+ },
+ "capabilities": {
+ "description": "Capability ids the app asks for (3+ segments). Only active public (or partner, by staff allowance) capabilities can ever be granted to apps.",
+ "type": "array",
+ "maxItems": 64,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"
+ }
+ },
+ "events": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "consumes": {
+ "description": "Event types (or a trailing .* family) the app subscribes to.",
+ "type": "array",
+ "maxItems": 64,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
+ }
+ }
+ }
+ },
+ "redirect_uris": {
+ "description": "Informational copy of the redirect URIs registered in Network (Network's list is the authority).",
+ "type": "array",
+ "maxItems": 10,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "maxLength": 500
+ }
+ },
+ "homepage": {
+ "type": "string",
+ "pattern": "^https://[^\\s]{1,2000}$"
+ },
+ "repository": {
+ "type": "string",
+ "pattern": "^https://[^\\s]{1,2000}$"
+ },
+ "license": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "SPDX license expression."
+ },
+ "compatibility": {
+ "type": "object",
+ "required": [
+ "contracts"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "contracts": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Semver range of openvibe-contracts releases it was built against."
+ },
+ "sdk": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Semver range of openvibe-sdk releases it uses."
+ }
+ }
+ }
+ }
+ }
+ },
+ "services.release-manage-result": {
+ "version": "1.0.0",
+ "owner": "services",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/release-manage-result.v1.json",
+ "title": "ServicesReleaseManageResult",
+ "description": "services.release-manage-result@1: answers of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.",
+ "type": "object",
+ "required": [
+ "release"
+ ],
+ "properties": {
+ "release": {
+ "$ref": "release.v1.json"
+ },
+ "warnings": {
+ "type": "array",
+ "items": {}
+ },
+ "event_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ },
+ "services.release": {
+ "version": "1.0.0",
+ "owner": "services",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/release.v1.json",
+ "title": "ServicesRelease",
+ "description": "services.release@1: one release of an app or mod as OpenVibe.Services presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (services.app-manifest@1).",
+ "type": "object",
+ "required": [
+ "id",
+ "app_id",
+ "kind",
+ "name",
+ "version",
+ "status",
+ "manifest_id",
+ "created_at",
+ "trust"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^rel_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "project_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "environment": {
+ "enum": [
+ "production",
+ "sandbox"
+ ]
+ },
+ "kind": {
+ "enum": [
+ "app",
+ "mod"
+ ]
+ },
+ "subject_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "name": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "draft",
+ "published",
+ "deprecated",
+ "revoked"
+ ]
+ },
+ "manifest_id": {
+ "type": "string"
+ },
+ "compatibility": {
+ "type": "object"
+ },
+ "notes": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "created_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "published_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "deprecated_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "deprecation_reason": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "replacement": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "revoked_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "revocation_reason": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "trust": {
+ "type": "object",
+ "required": [
+ "tier"
+ ],
+ "properties": {
+ "tier": {
+ "type": "string"
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "services.release-read-result": {
+ "version": "1.0.0",
+ "owner": "services",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/release-read-result.v1.json",
+ "title": "ServicesReleaseReadResult",
+ "description": "services.release-read-result@1: answers of services.release.read on OpenVibe.Services (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: services.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "app_id",
+ "trust",
+ "releases"
+ ],
+ "properties": {
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "trust": {
+ "type": "object",
+ "required": [
+ "tier"
+ ],
+ "properties": {
+ "tier": {
+ "type": "string"
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ },
+ "releases": {
+ "type": "array",
+ "items": {
+ "$ref": "release.v1.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "required": [
+ "app_id",
+ "tier",
+ "note_on_authority"
+ ],
+ "properties": {
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "tier": {
+ "type": "string"
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "note_on_authority": {
+ "type": "string"
+ }
+ }
+ },
+ {
+ "type": "object",
+ "required": [
+ "release",
+ "manifest"
+ ],
+ "properties": {
+ "release": {
+ "$ref": "release.v1.json"
+ },
+ "manifest": {
+ "anyOf": [
+ {
+ "$ref": "app-manifest.v1.json"
+ },
+ {
+ "$ref": "../mods/mod-manifest.v1.json"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ "services.release-manage-request": {
+ "version": "1.0.0",
+ "owner": "services",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/services/release-manage-request.v1.json",
+ "title": "ServicesReleaseManageRequest",
+ "description": "services.release-manage-request@1: bodies of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as services.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "manifest"
+ ],
+ "properties": {
+ "kind": {
+ "type": "string",
+ "description": "mod, or app (the default)."
+ },
+ "manifest": {
+ "anyOf": [
+ {
+ "$ref": "app-manifest.v1.json"
+ },
+ {
+ "$ref": "../mods/mod-manifest.v1.json"
+ }
+ ]
+ },
+ "notes": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "publish": {
+ "type": "boolean"
+ }
+ }
+ },
+ {
+ "type": "object",
+ "required": [
+ "reason"
+ ],
+ "properties": {
+ "reason": {
+ "type": "string",
+ "minLength": 1,
+ "pattern": "\\S"
+ },
+ "replacement": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^(rel_[0-9A-HJKMNP-TV-Z]{26})?$"
+ }
+ }
+ },
+ {
+ "$ref": "../common/no-body.v1.json"
+ }
+ ]
+ }
+ },
+ "services.moderation.action": {
+ "version": "1.0.0",
+ "owner": "services",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/services.moderation.action.v1.json",
+ "title": "ServicesModerationActionPayload",
+ "description": "services.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Services, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.",
+ "$ref": "../../common/moderation-action.v1.json"
+ }
+ },
"events.redaction-directive": {
"events.redaction-directive": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "events",
"owner": "events",
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.AI API",
"title": "OpenVibe.AI API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Billing API",
"title": "OpenVibe.Billing API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Blog API",
"title": "OpenVibe.Blog API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Bot API",
"title": "OpenVibe.Bot API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Chat API",
"title": "OpenVibe.Chat API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
deleted file mode 100644
deleted file mode 100644
@@ -1,1665 +0,0 @@
@@ -1,1665 +0,0 @@
-{
- "openapi": "3.1.0",
- "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
- "info": {
- "title": "OpenVibe.Codes API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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"
- }
- },
- "servers": [
- {
- "url": "https://openvibe.codes"
- }
- ],
- "paths": {
- "/api/v1/apps/{app}/releases": {
- "get": {
- "operationId": "get_api_v1_apps_app_releases",
- "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",
- "description": "**codes.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",
- "tags": [
- "codes.release"
- ],
- "x-openvibe-capabilities": [
- "codes.release.read"
- ],
- "x-openvibe-visibility": [
- "public"
- ],
- "x-openvibe-quota-class": "codes-read",
- "security": [
- {
- "openvibeToken": [
- "codes.release.read"
- ]
- }
- ],
- "parameters": [
- {
- "name": "app",
- "in": "path",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-read-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- },
- "post": {
- "operationId": "post_api_v1_apps_app_releases",
- "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replac",
- "description": "**codes.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
- "tags": [
- "codes.release"
- ],
- "x-openvibe-capabilities": [
- "codes.release.manage"
- ],
- "x-openvibe-visibility": [
- "public"
- ],
- "x-openvibe-quota-class": "codes-release-write",
- "security": [
- {
- "openvibeToken": [
- "codes.release.manage"
- ]
- }
- ],
- "requestBody": {
- "required": false,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-manage-request.v1"
- }
- }
- }
- },
- "parameters": [
- {
- "name": "app",
- "in": "path",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-manage-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/apps/{app}/trust": {
- "get": {
- "operationId": "get_api_v1_apps_app_trust",
- "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",
- "description": "**codes.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",
- "tags": [
- "codes.release"
- ],
- "x-openvibe-capabilities": [
- "codes.release.read"
- ],
- "x-openvibe-visibility": [
- "public"
- ],
- "x-openvibe-quota-class": "codes-read",
- "security": [
- {
- "openvibeToken": [
- "codes.release.read"
- ]
- }
- ],
- "parameters": [
- {
- "name": "app",
- "in": "path",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-read-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/releases/{id}": {
- "get": {
- "operationId": "get_api_v1_releases_id",
- "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",
- "description": "**codes.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",
- "tags": [
- "codes.release"
- ],
- "x-openvibe-capabilities": [
- "codes.release.read"
- ],
- "x-openvibe-visibility": [
- "public"
- ],
- "x-openvibe-quota-class": "codes-read",
- "security": [
- {
- "openvibeToken": [
- "codes.release.read"
- ]
- }
- ],
- "parameters": [
- {
- "name": "id",
- "in": "path",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-read-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/releases/{id}/deprecate": {
- "post": {
- "operationId": "post_api_v1_releases_id_deprecate",
- "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replac",
- "description": "**codes.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
- "tags": [
- "codes.release"
- ],
- "x-openvibe-capabilities": [
- "codes.release.manage"
- ],
- "x-openvibe-visibility": [
- "public"
- ],
- "x-openvibe-quota-class": "codes-release-write",
- "security": [
- {
- "openvibeToken": [
- "codes.release.manage"
- ]
- }
- ],
- "requestBody": {
- "required": false,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-manage-request.v1"
- }
- }
- }
- },
- "parameters": [
- {
- "name": "id",
- "in": "path",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-manage-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/releases/{id}/publish": {
- "post": {
- "operationId": "post_api_v1_releases_id_publish",
- "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replac",
- "description": "**codes.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
- "tags": [
- "codes.release"
- ],
- "x-openvibe-capabilities": [
- "codes.release.manage"
- ],
- "x-openvibe-visibility": [
- "public"
- ],
- "x-openvibe-quota-class": "codes-release-write",
- "security": [
- {
- "openvibeToken": [
- "codes.release.manage"
- ]
- }
- ],
- "requestBody": {
- "required": false,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-manage-request.v1"
- }
- }
- }
- },
- "parameters": [
- {
- "name": "id",
- "in": "path",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-manage-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/releases/{id}/revoke": {
- "post": {
- "operationId": "post_api_v1_releases_id_revoke",
- "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replac",
- "description": "**codes.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
- "tags": [
- "codes.release"
- ],
- "x-openvibe-capabilities": [
- "codes.release.manage"
- ],
- "x-openvibe-visibility": [
- "public"
- ],
- "x-openvibe-quota-class": "codes-release-write",
- "security": [
- {
- "openvibeToken": [
- "codes.release.manage"
- ]
- }
- ],
- "requestBody": {
- "required": false,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-manage-request.v1"
- }
- }
- }
- },
- "parameters": [
- {
- "name": "id",
- "in": "path",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/codes.release-manage-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/resources": {
- "get": {
- "operationId": "get_api_v1_resources",
- "summary": "Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:o",
- "description": "**codes.resource.read** (first-party): Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:ovrn reads one by its OVRN (common.resource-summary@1). Every authority serves these for OpenVibe.Services to fan out and merge; Codes' own resources are its validated app and mod manifests (kind codes.manifest, id mfs_<ULID>) and its releases (kind codes.release, id rel_<ULID>), each carrying the Network project it was created in as its tenancy boundary. Trust tiers are per-app metadata and playground run logs are audit records, neither a resource; Codes hosts no repositories, so the catalog carries no codes.repo kind. Planned until Codes ships the index.",
- "tags": [
- "codes.resource"
- ],
- "x-openvibe-capabilities": [
- "codes.resource.read"
- ],
- "x-openvibe-visibility": [
- "first-party"
- ],
- "x-openvibe-quota-class": "standard",
- "security": [
- {
- "openvibeToken": [
- "codes.resource.read"
- ]
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/common.resource-list-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- }
- },
- "/api/v1/resources/{ovrn}": {
- "get": {
- "operationId": "get_api_v1_resources_ovrn",
- "summary": "Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:o",
- "description": "**codes.resource.read** (first-party): Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:ovrn reads one by its OVRN (common.resource-summary@1). Every authority serves these for OpenVibe.Services to fan out and merge; Codes' own resources are its validated app and mod manifests (kind codes.manifest, id mfs_<ULID>) and its releases (kind codes.release, id rel_<ULID>), each carrying the Network project it was created in as its tenancy boundary. Trust tiers are per-app metadata and playground run logs are audit records, neither a resource; Codes hosts no repositories, so the catalog carries no codes.repo kind. Planned until Codes ships the index.",
- "tags": [
- "codes.resource"
- ],
- "x-openvibe-capabilities": [
- "codes.resource.read"
- ],
- "x-openvibe-visibility": [
- "first-party"
- ],
- "x-openvibe-quota-class": "standard",
- "security": [
- {
- "openvibeToken": [
- "codes.resource.read"
- ]
- }
- ],
- "parameters": [
- {
- "name": "ovrn",
- "in": "path",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "2XX": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/common.resource-list-result.v1"
- }
- }
- }
- },
- "default": {
- "description": "An error (RFC 9457 problem details)",
- "content": {
- "application/problem+json": {
- "schema": {
- "$ref": "#/components/schemas/errors.problem.v1"
- }
- }
- }
- }
- }
- }
- }
- },
- "components": {
- "schemas": {
- "codes.app-manifest.v1": {
- "title": "AppManifest",
- "description": "PROPOSAL (OpenVibe.Codes, roadmap Wave 20): an app release as the platform knows it. The app is a Network developer app (ADR-014): its id is the Network app id, its capabilities are only a request (the grants in Network are the authority), and trust tiers are metadata that never change a grant check. OpenVibe.Codes validates with this schema, loaded into openvibe-contracts' validator, until Contracts publishes it as codes.app-manifest@1.",
- "type": "object",
- "required": [
- "id",
- "name",
- "version",
- "publisher",
- "project_id",
- "capabilities",
- "compatibility"
- ],
- "additionalProperties": false,
- "properties": {
- "id": {
- "type": "string",
- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$",
- "description": "The Network app id (its client_id). Its principal subject is app:<id>."
- },
- "name": {
- "type": "string",
- "minLength": 1,
- "maxLength": 80
- },
- "version": {
- "type": "string",
- "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",
- "description": "Semantic version of this release."
- },
- "description": {
- "type": "string",
- "maxLength": 1000
- },
- "publisher": {
- "$ref": "#/components/schemas/identity.subject-ref.v1",
- "description": "Who publishes the release: the app itself or a member of its project."
- },
- "project_id": {
- "type": "string",
- "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$",
- "description": "The Network project that owns the app. Tenancy in other services is keyed by it (ADR-014)."
- },
- "environment": {
- "enum": [
- "sandbox",
- "production"
- ],
- "description": "The app's environment. Apps never change environment."
- },
- "capabilities": {
- "description": "Capability ids the app asks for (3+ segments). Only active public (or partner, by staff allowance) capabilities can ever be granted to apps.",
- "type": "array",
- "maxItems": 64,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"
- }
- },
- "events": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "consumes": {
- "description": "Event types (or a trailing .* family) the app subscribes to.",
- "type": "array",
- "maxItems": 64,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
- }
- }
- }
- },
- "redirect_uris": {
- "description": "Informational copy of the redirect URIs registered in Network (Network's list is the authority).",
- "type": "array",
- "maxItems": 10,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "maxLength": 500
- }
- },
- "homepage": {
- "type": "string",
- "pattern": "^https://[^\\s]{1,2000}$"
- },
- "repository": {
- "type": "string",
- "pattern": "^https://[^\\s]{1,2000}$"
- },
- "license": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "SPDX license expression."
- },
- "compatibility": {
- "type": "object",
- "required": [
- "contracts"
- ],
- "additionalProperties": false,
- "properties": {
- "contracts": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Semver range of openvibe-contracts releases it was built against."
- },
- "sdk": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Semver range of openvibe-sdk releases it uses."
- }
- }
- }
- }
- },
- "codes.release-manage-request.v1": {
- "title": "CodesReleaseManageRequest",
- "description": "codes.release-manage-request@1: bodies of codes.release.manage on OpenVibe.Codes (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as codes.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.",
- "anyOf": [
- {
- "type": "object",
- "required": [
- "manifest"
- ],
- "properties": {
- "kind": {
- "type": "string",
- "description": "mod, or app (the default)."
- },
- "manifest": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/codes.app-manifest.v1"
- },
- {
- "$ref": "#/components/schemas/mods.mod-manifest.v1"
- }
- ]
- },
- "notes": {
- "type": [
- "string",
- "null"
- ]
- },
- "publish": {
- "type": "boolean"
- }
- }
- },
- {
- "type": "object",
- "required": [
- "reason"
- ],
- "properties": {
- "reason": {
- "type": "string",
- "minLength": 1,
- "pattern": "\\S"
- },
- "replacement": {
- "type": [
- "string",
- "null"
- ],
- "pattern": "^(rel_[0-9A-HJKMNP-TV-Z]{26})?$"
- }
- }
- },
- {
- "$ref": "#/components/schemas/common.no-body.v1"
- }
- ]
- },
- "codes.release-manage-result.v1": {
- "title": "CodesReleaseManageResult",
- "description": "codes.release-manage-result@1: answers of codes.release.manage on OpenVibe.Codes (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.",
- "type": "object",
- "required": [
- "release"
- ],
- "properties": {
- "release": {
- "$ref": "#/components/schemas/codes.release.v1"
- },
- "warnings": {
- "type": "array",
- "items": {}
- },
- "event_id": {
- "type": [
- "string",
- "null"
- ]
- }
- }
- },
- "codes.release-read-result.v1": {
- "title": "CodesReleaseReadResult",
- "description": "codes.release-read-result@1: answers of codes.release.read on OpenVibe.Codes (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: codes.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.",
- "anyOf": [
- {
- "type": "object",
- "required": [
- "app_id",
- "trust",
- "releases"
- ],
- "properties": {
- "app_id": {
- "type": "string",
- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
- },
- "trust": {
- "type": "object",
- "required": [
- "tier"
- ],
- "properties": {
- "tier": {
- "type": "string"
- },
- "note": {
- "type": [
- "string",
- "null"
- ]
- },
- "set_by": {
- "type": [
- "string",
- "null"
- ]
- },
- "set_at": {
- "type": [
- "string",
- "null"
- ]
- }
- }
- },
- "releases": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/codes.release.v1"
- }
- }
- }
- },
- {
- "type": "object",
- "required": [
- "app_id",
- "tier",
- "note_on_authority"
- ],
- "properties": {
- "app_id": {
- "type": "string",
- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
- },
- "tier": {
- "type": "string"
- },
- "note": {
- "type": [
- "string",
- "null"
- ]
- },
- "set_by": {
- "type": [
- "string",
- "null"
- ]
- },
- "set_at": {
- "type": [
- "string",
- "null"
- ]
- },
- "note_on_authority": {
- "type": "string"
- }
- }
- },
- {
- "type": "object",
- "required": [
- "release",
- "manifest"
- ],
- "properties": {
- "release": {
- "$ref": "#/components/schemas/codes.release.v1"
- },
- "manifest": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/codes.app-manifest.v1"
- },
- {
- "$ref": "#/components/schemas/mods.mod-manifest.v1"
- },
- {
- "type": "null"
- }
- ]
- }
- }
- }
- ]
- },
- "codes.release.v1": {
- "title": "CodesRelease",
- "description": "codes.release@1: one release of an app or mod as OpenVibe.Codes presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (codes.app-manifest@1).",
- "type": "object",
- "required": [
- "id",
- "app_id",
- "kind",
- "name",
- "version",
- "status",
- "manifest_id",
- "created_at",
- "trust"
- ],
- "properties": {
- "id": {
- "type": "string",
- "pattern": "^rel_[0-9A-HJKMNP-TV-Z]{26}$"
- },
- "app_id": {
- "type": "string",
- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
- },
- "project_id": {
- "type": [
- "string",
- "null"
- ]
- },
- "environment": {
- "enum": [
- "production",
- "sandbox"
- ]
- },
- "kind": {
- "enum": [
- "app",
- "mod"
- ]
- },
- "subject_id": {
- "type": [
- "string",
- "null"
- ]
- },
- "name": {
- "type": "string"
- },
- "version": {
- "type": "string"
- },
- "status": {
- "enum": [
- "draft",
- "published",
- "deprecated",
- "revoked"
- ]
- },
- "manifest_id": {
- "type": "string"
- },
- "compatibility": {
- "type": "object"
- },
- "notes": {
- "type": [
- "string",
- "null"
- ]
- },
- "created_at": {
- "type": "string"
- },
- "created_by": {
- "type": [
- "string",
- "null"
- ]
- },
- "published_at": {
- "type": [
- "string",
- "null"
- ]
- },
- "deprecated_at": {
- "type": [
- "string",
- "null"
- ]
- },
- "deprecation_reason": {
- "type": [
- "string",
- "null"
- ]
- },
- "replacement": {
- "type": [
- "string",
- "null"
- ]
- },
- "revoked_at": {
- "type": [
- "string",
- "null"
- ]
- },
- "revocation_reason": {
- "type": [
- "string",
- "null"
- ]
- },
- "trust": {
- "type": "object",
- "required": [
- "tier"
- ],
- "properties": {
- "tier": {
- "type": "string"
- },
- "note": {
- "type": [
- "string",
- "null"
- ]
- },
- "set_by": {
- "type": [
- "string",
- "null"
- ]
- },
- "set_at": {
- "type": [
- "string",
- "null"
- ]
- }
- }
- }
- }
- },
- "common.no-body.v1": {
- "title": "NoBody",
- "description": "common.no-body@1: the capability's request carries no body; its parameters are the path and query of the routes in implementedBy (an id, a page cursor). An input schema that says so explicitly, so every active capability names one (roadmap WS-C task 4).",
- "type": "object",
- "maxProperties": 0
- },
- "common.resource-list-result.v1": {
- "title": "ResourceListResult",
- "description": "A page of the resource index (roadmap WS-Z7).",
- "type": "object",
- "additionalProperties": false,
- "required": [
- "resources",
- "next_cursor"
- ],
- "properties": {
- "resources": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/common.resource-summary.v1"
- }
- },
- "next_cursor": {
- "type": [
- "string",
- "null"
- ]
- },
- "partial": {
- "type": "array",
- "description": "Authorities a merged index (OpenVibe.Services, ADR-048) could not read for this page: a slow or failing authority is omitted, never fails the page. Each entry names the authority and the problem code it answered. Added in 1.1.0; a single authority's own index leaves it out.",
- "items": {
- "type": "object",
- "required": [
- "service",
- "code"
- ],
- "additionalProperties": false,
- "properties": {
- "service": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9-]{1,39}$"
- },
- "code": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"
- }
- }
- }
- }
- }
- },
- "common.resource-summary.v1": {
- "title": "ResourceSummary",
- "description": "One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.",
- "type": "object",
- "additionalProperties": false,
- "required": [
- "id",
- "kind",
- "service",
- "state",
- "created_at"
- ],
- "properties": {
- "id": {
- "type": "string"
- },
- "kind": {
- "type": "string",
- "description": "service.kind, e.g. watch.watch, actor.actor, media.object, events.subscription"
- },
- "service": {
- "type": "string"
- },
- "project_id": {
- "type": "string",
- "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
- },
- "ovrn": {
- "type": "string",
- "maxLength": 200,
- "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",
- "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."
- },
- "owner": {
- "$ref": "#/components/schemas/identity.subject-ref.v1"
- },
- "name": {
- "type": "string"
- },
- "state": {
- "type": "string"
- },
- "created_at": {
- "type": "string",
- "format": "date-time"
- },
- "updated_at": {
- "type": "string",
- "format": "date-time"
- },
- "usage": {
- "type": "object",
- "additionalProperties": {
- "type": "number",
- "minimum": 0
- },
- "properties": {},
- "description": "cost units by name (WS-Z1)"
- },
- "links": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "self": {
- "type": "string",
- "format": "uri"
- },
- "console": {
- "type": "string",
- "format": "uri"
- },
- "docs": {
- "type": "string",
- "format": "uri"
- }
- }
- }
- }
- },
- "errors.problem.v1": {
- "title": "Problem",
- "description": "RFC 9457 problem details (application/problem+json) with a stable OpenVibe error code and trace identifiers. The legacy 'error' string is allowed during migration so existing clients keep working.",
- "type": "object",
- "required": [
- "type",
- "title",
- "status",
- "code"
- ],
- "additionalProperties": true,
- "properties": {
- "type": {
- "type": "string",
- "format": "uri-reference"
- },
- "title": {
- "type": "string",
- "minLength": 1
- },
- "status": {
- "type": "integer",
- "minimum": 400,
- "maximum": 599
- },
- "detail": {
- "type": "string"
- },
- "instance": {
- "type": "string",
- "format": "uri-reference"
- },
- "code": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"
- },
- "request_id": {
- "type": "string"
- },
- "trace_id": {
- "type": "string",
- "pattern": "^[0-9a-f]{32}$"
- },
- "errors": {
- "type": "array",
- "items": {
- "type": "object",
- "required": [
- "message"
- ],
- "properties": {
- "path": {
- "type": "string"
- },
- "message": {
- "type": "string"
- }
- }
- }
- },
- "error": {
- "type": "string",
- "description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."
- }
- }
- },
- "identity.subject-ref.v1": {
- "title": "SubjectRef",
- "description": "The one cross-platform reference to an actor. Issued by OpenVibe.Network. Never a service-local integer id.",
- "oneOf": [
- {
- "type": "object",
- "required": [
- "type",
- "id"
- ],
- "additionalProperties": false,
- "properties": {
- "type": {
- "const": "user"
- },
- "id": {
- "type": "string",
- "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
- }
- },
- "description": "UserSubject"
- },
- {
- "type": "object",
- "required": [
- "type",
- "id"
- ],
- "additionalProperties": false,
- "properties": {
- "type": {
- "const": "guest"
- },
- "id": {
- "type": "string",
- "pattern": "^gst_[0-9A-HJKMNP-TV-Z]{26}$"
- }
- },
- "description": "GuestSubject"
- },
- {
- "type": "object",
- "required": [
- "type",
- "id"
- ],
- "additionalProperties": false,
- "properties": {
- "type": {
- "const": "app"
- },
- "id": {
- "type": "string",
- "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
- }
- },
- "description": "AppSubject"
- },
- {
- "type": "object",
- "required": [
- "type",
- "id"
- ],
- "additionalProperties": false,
- "properties": {
- "type": {
- "const": "mod"
- },
- "id": {
- "type": "string",
- "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"
- }
- },
- "description": "ModSubject"
- },
- {
- "type": "object",
- "required": [
- "type",
- "id"
- ],
- "additionalProperties": false,
- "properties": {
- "type": {
- "enum": [
- "service",
- "system"
- ]
- },
- "id": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9-]{1,39}$"
- }
- },
- "description": "PrincipalSubject"
- },
- {
- "type": "object",
- "required": [
- "type",
- "id"
- ],
- "additionalProperties": false,
- "properties": {
- "type": {
- "const": "agent"
- },
- "id": {
- "type": "string",
- "pattern": "^agt_[0-9A-HJKMNP-TV-Z]{26}$"
- }
- },
- "description": "AgentSubject: an agent (OpenVibe.Actor, or a developer app's agent) acting under grants its owner delegated (roadmap WS-Z2). In an event envelope, on_behalf_of names the owner."
- }
- ]
- },
- "media.media-ref.v1": {
- "title": "MediaRef",
- "description": "Reference to a Media object. Canonical ids (med_<ULID>) arrive with the Wave 4 object model; until then legacy:<app>:<kind>:<id> addresses today's VOD/clip/file/paste/thumbnail rows.",
- "type": "object",
- "required": [
- "media_id"
- ],
- "additionalProperties": false,
- "properties": {
- "media_id": {
- "type": "string",
- "pattern": "^(med_[0-9A-HJKMNP-TV-Z]{26}|legacy:[a-z][a-z0-9-]{1,39}:(vod|clip|file|paste|thumbnail|avatar):[A-Za-z0-9._/-]{1,200})$"
- },
- "role": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]{1,39}$"
- },
- "variant": {
- "type": "string",
- "pattern": "^[a-z0-9][a-z0-9_-]{0,39}$"
- }
- }
- },
- "mods.mod-manifest.v1": {
- "title": "ModManifest",
- "description": "A mod as the platform knows it (ADR-013): who publishes it, which runtime runs it, which capabilities it asks for and the resources it may use. Requested capabilities are only a request: the install's approved subset is the grant, and trust tiers are install metadata that never change a grant check. The runtime-specific payload (a data pack, a script bundle) is not part of the manifest. 1.1.0 (openvibe-contracts v0.34.0) adds the optional permissions.readGrants and writeGrants, billingHooks and dependencies (ADR-013 amendment of 2026-09-24); every 1.0.0 manifest stays valid.",
- "type": "object",
- "required": [
- "id",
- "name",
- "version",
- "publisher",
- "target",
- "runtime",
- "permissions",
- "resources",
- "compatibility"
- ],
- "additionalProperties": false,
- "properties": {
- "id": {
- "type": "string",
- "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$",
- "description": "Stable mod id; its principal subject is mod:<id>."
- },
- "name": {
- "type": "string",
- "minLength": 1,
- "maxLength": 80
- },
- "version": {
- "type": "string",
- "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",
- "description": "Semantic version of this release."
- },
- "description": {
- "type": "string",
- "maxLength": 1000
- },
- "publisher": {
- "$ref": "#/components/schemas/identity.subject-ref.v1",
- "description": "Who publishes the mod (a user or an app subject)."
- },
- "target": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9-]{1,39}\\.[a-z][a-z0-9-]{1,39}$",
- "description": "Where the mod runs: <service>.<surface>, e.g. games.browser, games.source, live.overlay."
- },
- "runtime": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9-]{1,39}@[1-9][0-9]{0,3}$",
- "description": "Runtime adapter and its major version, e.g. games-content@1 (declarative data pack) or source-quickjs@1."
- },
- "permissions": {
- "type": "object",
- "required": [
- "capabilities"
- ],
- "additionalProperties": false,
- "properties": {
- "capabilities": {
- "description": "Capability ids the mod asks for (3+ segments). The target runtime binds only those it implements, and only once granted.",
- "type": "array",
- "maxItems": 64,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"
- }
- },
- "events": {
- "description": "Event types the mod wants delivered to it.",
- "type": "array",
- "maxItems": 64,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"
- }
- },
- "modules": {
- "description": "User-module namespaces the mod wants to read or write (a trailing .* names a family). A namespace listed here may be read and written; readGrants and writeGrants (1.1.0) say which.",
- "type": "array",
- "maxItems": 32,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
- }
- },
- "mediaNamespaces": {
- "description": "Media namespaces the mod wants to read or write. A namespace listed here may be read and written; readGrants and writeGrants (1.1.0) say which.",
- "type": "array",
- "maxItems": 32,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"
- }
- },
- "readGrants": {
- "description": "1.1.0: namespaces the mod may only read. A namespace that is only here is read-only. The install's approved subset is still the grant.",
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "modules": {
- "description": "User-module namespaces (a trailing .* names a family).",
- "type": "array",
- "maxItems": 32,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
- }
- },
- "mediaNamespaces": {
- "description": "Media namespaces.",
- "type": "array",
- "maxItems": 32,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"
- }
- }
- }
- },
- "writeGrants": {
- "description": "1.1.0: namespaces the mod may read and write. A write needs the namespace here, or in the older modules and mediaNamespaces lists, which mean read and write.",
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "modules": {
- "description": "User-module namespaces (a trailing .* names a family).",
- "type": "array",
- "maxItems": 32,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
- }
- },
- "mediaNamespaces": {
- "description": "Media namespaces.",
- "type": "array",
- "maxItems": 32,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"
- }
- }
- }
- }
- }
- },
- "resources": {
- "type": "object",
- "required": [
- "cpuMs",
- "memoryMb",
- "storageMb"
- ],
- "additionalProperties": false,
- "description": "The budget the mod asks for. Runtimes meter it; the sandbox that enforces it lives in OpenVibe.Host (Stage C).",
- "properties": {
- "cpuMs": {
- "type": "number",
- "minimum": 0,
- "maximum": 1000,
- "description": "CPU milliseconds per tick (game runtimes) or per request."
- },
- "memoryMb": {
- "type": "integer",
- "minimum": 0,
- "maximum": 4096
- },
- "storageMb": {
- "type": "integer",
- "minimum": 0,
- "maximum": 102400
- },
- "outboundHosts": {
- "description": "Hosts the mod may reach over the network. Empty or absent = none.",
- "type": "array",
- "maxItems": 32,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$"
- }
- }
- }
- },
- "assets": {
- "description": "Assets the mod ships, as Media object references.",
- "type": "array",
- "maxItems": 256,
- "items": {
- "$ref": "#/components/schemas/media.media-ref.v1"
- }
- },
- "compatibility": {
- "type": "object",
- "required": [
- "runtime"
- ],
- "additionalProperties": false,
- "properties": {
- "runtime": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Semver range of the runtime this release works with, e.g. \">=1.0.0 <2.0.0\"."
- },
- "contracts": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Semver range of openvibe-contracts releases it was built against."
- }
- }
- },
- "homepage": {
- "type": "string",
- "pattern": "^https://[^\\s]{1,2000}$"
- },
- "billingHooks": {
- "description": "1.1.0: how the mod takes part in money, only through Billing and VIP primitives (ADR-013 amendment, ADR-012). entitlement: the mod checks that the person holds this entitlement (billing.entitlement.check or vip.entitlement.check, granted like any other capability). checkout: the mod sends the person to the platform's own checkout for this plan (vip.membership.checkout or a Billing intent). A mod never takes payment, sees payment details or holds a balance. Prices live in Billing and VIP, never in the manifest.",
- "type": "array",
- "maxItems": 32,
- "items": {
- "type": "object",
- "required": [
- "kind",
- "key"
- ],
- "additionalProperties": false,
- "properties": {
- "kind": {
- "enum": [
- "entitlement",
- "checkout"
- ]
- },
- "key": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_.:-]{0,127}$",
- "description": "The entitlement or plan key as Billing and VIP name it, e.g. vip.plan:pln_01jab… (lowercase, the form search.index-document@1 acl.entitlements uses)."
- },
- "description": {
- "type": "string",
- "minLength": 1,
- "maxLength": 200,
- "description": "What it unlocks or sells, shown at install."
- }
- }
- }
- },
- "dependencies": {
- "description": "1.1.0: other mods this release needs. A runtime refuses to enable the mod while a required dependency is not installed, not enabled or outside its range. An optional one is used only when present.",
- "type": "array",
- "maxItems": 32,
- "uniqueItems": true,
- "items": {
- "type": "object",
- "required": [
- "id",
- "version"
- ],
- "additionalProperties": false,
- "properties": {
- "id": {
- "type": "string",
- "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"
- },
- "version": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Semver range of the dependency's releases this release works with, e.g. \">=1.2.0 <2.0.0\"."
- },
- "optional": {
- "type": "boolean",
- "default": false
- }
- }
- }
- }
- }
- }
- },
- "securitySchemes": {
- "openvibeToken": {
- "type": "http",
- "scheme": "bearer",
- "bearerFormat": "JWT",
- "description": "An OpenVibe Network token for this service: a person's token, an app token (client credentials, audience of the service) or a first-party service token. Its `cap` claim must include the capability the operation names."
- }
- }
- }
-}
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Community API",
"title": "OpenVibe.Community API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Coupons API",
"title": "OpenVibe.Coupons API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Deals API",
"title": "OpenVibe.Deals API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Events API",
"title": "OpenVibe.Events API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Games API",
"title": "OpenVibe.Games API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Host API",
"title": "OpenVibe.Host API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -36,13 +36,6 @@
@@ -36,13 +36,6 @@
"operations": 22,
"operations": 22,
"capabilities": 12
"capabilities": 12
},
},
- {
- "service": "codes",
- "name": "OpenVibe.Codes",
- "origin": "https://openvibe.codes",
- "operations": 9,
- "capabilities": 3
- },
{
{
"service": "community",
"service": "community",
"name": "OpenVibe.Community",
"name": "OpenVibe.Community",
@@ -145,8 +138,8 @@
@@ -145,8 +138,8 @@
"service": "services",
"service": "services",
"name": "OpenVibe.Services",
"name": "OpenVibe.Services",
"origin": "https://openvibe.services",
"origin": "https://openvibe.services",
- "operations": 2,
- "capabilities": 1
+ "operations": 9,
+ "capabilities": 3
},
},
{
{
"service": "sources",
"service": "sources",
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Live API",
"title": "OpenVibe.Live API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Media API",
"title": "OpenVibe.Media API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Network API",
"title": "OpenVibe.Network API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.News API",
"title": "OpenVibe.News API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenRe.Stream API",
"title": "OpenRe.Stream API",
- "version": "0.112.0",
- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Reviews API",
"title": "OpenVibe.Reviews API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Run API",
"title": "OpenVibe.Run API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Search API",
"title": "OpenVibe.Search API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Services API",
"title": "OpenVibe.Services API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -16,35 +16,45 @@
@@ -16,35 +16,45 @@
}
}
],
],
"paths": {
"paths": {
- "/api/v1/resources": {
+ "/api/v1/apps/{app}/releases": {
"get": {
"get": {
- "operationId": "get_api_v1_resources",
- "summary": "Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own ",
- "description": "**services.resource.read** (first-party): Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own or belong to (one project per request).",
+ "operationId": "get_api_v1_apps_app_releases",
+ "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",
+ "description": "**services.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",
"tags": [
"tags": [
- "services.resource"
+ "services.release"
],
],
"x-openvibe-capabilities": [
"x-openvibe-capabilities": [
- "services.resource.read"
+ "services.release.read"
],
],
"x-openvibe-visibility": [
"x-openvibe-visibility": [
- "first-party"
+ "public"
],
],
- "x-openvibe-quota-class": "standard",
+ "x-openvibe-quota-class": "services-read",
"security": [
"security": [
{
{
"openvibeToken": [
"openvibeToken": [
- "services.resource.read"
+ "services.release.read"
]
]
}
}
],
],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
"responses": {
"responses": {
"2XX": {
"2XX": {
"description": "Success",
"description": "Success",
"content": {
"content": {
"application/json": {
"application/json": {
"schema": {
"schema": {
- "$ref": "#/components/schemas/common.resource-list-result.v1"
+ "$ref": "#/components/schemas/services.release-read-result.v1"
}
}
}
}
}
}
@@ -60,33 +70,41 @@
@@ -60,33 +70,41 @@
}
}
}
}
}
}
- }
- },
- "/api/v1/resources/{ovrn}": {
- "get": {
- "operationId": "get_api_v1_resources_ovrn",
- "summary": "Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own ",
- "description": "**services.resource.read** (first-party): Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own or belong to (one project per request).",
+ },
+ "post": {
+ "operationId": "post_api_v1_apps_app_releases",
+ "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional rep",
+ "description": "**services.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
"tags": [
"tags": [
- "services.resource"
+ "services.release"
],
],
"x-openvibe-capabilities": [
"x-openvibe-capabilities": [
- "services.resource.read"
+ "services.release.manage"
],
],
"x-openvibe-visibility": [
"x-openvibe-visibility": [
- "first-party"
+ "public"
],
],
- "x-openvibe-quota-class": "standard",
+ "x-openvibe-quota-class": "services-release-write",
"security": [
"security": [
{
{
"openvibeToken": [
"openvibeToken": [
- "services.resource.read"
+ "services.release.manage"
]
]
}
}
],
],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-manage-request.v1"
+ }
+ }
+ }
+ },
"parameters": [
"parameters": [
{
{
- "name": "ovrn",
+ "name": "app",
"in": "path",
"in": "path",
"required": true,
"required": true,
"schema": {
"schema": {
@@ -100,7 +118,7 @@
@@ -100,7 +118,7 @@
"content": {
"content": {
"application/json": {
"application/json": {
"schema": {
"schema": {
- "$ref": "#/components/schemas/common.resource-list-result.v1"
+ "$ref": "#/components/schemas/services.release-manage-result.v1"
}
}
}
}
}
}
@@ -117,317 +135,1522 @@
@@ -117,317 +135,1522 @@
}
}
}
}
}
}
- }
- },
- "components": {
- "schemas": {
- "common.resource-list-result.v1": {
- "title": "ResourceListResult",
- "description": "A page of the resource index (roadmap WS-Z7).",
- "type": "object",
- "additionalProperties": false,
- "required": [
- "resources",
- "next_cursor"
+ },
+ "/api/v1/apps/{app}/trust": {
+ "get": {
+ "operationId": "get_api_v1_apps_app_trust",
+ "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",
+ "description": "**services.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",
+ "tags": [
+ "services.release"
],
],
- "properties": {
- "resources": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/common.resource-summary.v1"
- }
- },
- "next_cursor": {
- "type": [
- "string",
- "null"
+ "x-openvibe-capabilities": [
+ "services.release.read"
+ ],
+ "x-openvibe-visibility": [
+ "public"
+ ],
+ "x-openvibe-quota-class": "services-read",
+ "security": [
+ {
+ "openvibeToken": [
+ "services.release.read"
]
]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-read-result.v1"
+ }
+ }
+ }
},
},
- "partial": {
- "type": "array",
- "description": "Authorities a merged index (OpenVibe.Services, ADR-048) could not read for this page: a slow or failing authority is omitted, never fails the page. Each entry names the authority and the problem code it answered. Added in 1.1.0; a single authority's own index leaves it out.",
- "items": {
- "type": "object",
- "required": [
- "service",
- "code"
- ],
- "additionalProperties": false,
- "properties": {
- "service": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9-]{1,39}$"
- },
- "code": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
}
}
}
}
}
}
}
}
}
}
- },
- "common.resource-summary.v1": {
- "title": "ResourceSummary",
- "description": "One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.",
- "type": "object",
- "additionalProperties": false,
- "required": [
- "id",
- "kind",
- "service",
- "state",
- "created_at"
+ }
+ },
+ "/api/v1/releases/{id}": {
+ "get": {
+ "operationId": "get_api_v1_releases_id",
+ "summary": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything).",
+ "description": "**services.release.read** (public): Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",
+ "tags": [
+ "services.release"
],
],
- "properties": {
- "id": {
- "type": "string"
- },
- "kind": {
- "type": "string",
- "description": "service.kind, e.g. watch.watch, actor.actor, media.object, events.subscription"
- },
- "service": {
- "type": "string"
- },
- "project_id": {
- "type": "string",
- "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
- },
- "ovrn": {
- "type": "string",
- "maxLength": 200,
- "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",
- "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."
- },
- "owner": {
- "$ref": "#/components/schemas/identity.subject-ref.v1"
- },
- "name": {
- "type": "string"
- },
- "state": {
- "type": "string"
- },
- "created_at": {
- "type": "string",
- "format": "date-time"
- },
- "updated_at": {
- "type": "string",
- "format": "date-time"
- },
- "usage": {
- "type": "object",
- "additionalProperties": {
- "type": "number",
- "minimum": 0
- },
- "properties": {},
- "description": "cost units by name (WS-Z1)"
+ "x-openvibe-capabilities": [
+ "services.release.read"
+ ],
+ "x-openvibe-visibility": [
+ "public"
+ ],
+ "x-openvibe-quota-class": "services-read",
+ "security": [
+ {
+ "openvibeToken": [
+ "services.release.read"
+ ]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-read-result.v1"
+ }
+ }
+ }
},
},
- "links": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "self": {
- "type": "string",
- "format": "uri"
- },
- "console": {
- "type": "string",
- "format": "uri"
- },
- "docs": {
- "type": "string",
- "format": "uri"
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
}
}
}
}
}
}
}
}
- },
- "errors.problem.v1": {
- "title": "Problem",
- "description": "RFC 9457 problem details (application/problem+json) with a stable OpenVibe error code and trace identifiers. The legacy 'error' string is allowed during migration so existing clients keep working.",
- "type": "object",
- "required": [
- "type",
- "title",
- "status",
- "code"
+ }
+ },
+ "/api/v1/releases/{id}/deprecate": {
+ "post": {
+ "operationId": "post_api_v1_releases_id_deprecate",
+ "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional rep",
+ "description": "**services.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
+ "tags": [
+ "services.release"
],
],
- "additionalProperties": true,
- "properties": {
- "type": {
- "type": "string",
- "format": "uri-reference"
- },
- "title": {
- "type": "string",
- "minLength": 1
- },
- "status": {
- "type": "integer",
- "minimum": 400,
- "maximum": 599
- },
- "detail": {
- "type": "string"
+ "x-openvibe-capabilities": [
+ "services.release.manage"
+ ],
+ "x-openvibe-visibility": [
+ "public"
+ ],
+ "x-openvibe-quota-class": "services-release-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "services.release.manage"
+ ]
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-manage-request.v1"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-manage-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/releases/{id}/publish": {
+ "post": {
+ "operationId": "post_api_v1_releases_id_publish",
+ "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional rep",
+ "description": "**services.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
+ "tags": [
+ "services.release"
+ ],
+ "x-openvibe-capabilities": [
+ "services.release.manage"
+ ],
+ "x-openvibe-visibility": [
+ "public"
+ ],
+ "x-openvibe-quota-class": "services-release-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "services.release.manage"
+ ]
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-manage-request.v1"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-manage-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/releases/{id}/revoke": {
+ "post": {
+ "operationId": "post_api_v1_releases_id_revoke",
+ "summary": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional rep",
+ "description": "**services.release.manage** (public): An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
+ "tags": [
+ "services.release"
+ ],
+ "x-openvibe-capabilities": [
+ "services.release.manage"
+ ],
+ "x-openvibe-visibility": [
+ "public"
+ ],
+ "x-openvibe-quota-class": "services-release-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "services.release.manage"
+ ]
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-manage-request.v1"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/services.release-manage-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/resources": {
+ "get": {
+ "operationId": "get_api_v1_resources",
+ "summary": "Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own ",
+ "description": "**services.resource.read** (first-party): Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own or belong to (one project per request).",
+ "tags": [
+ "services.resource"
+ ],
+ "x-openvibe-capabilities": [
+ "services.resource.read"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "standard",
+ "security": [
+ {
+ "openvibeToken": [
+ "services.resource.read"
+ ]
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/common.resource-list-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/resources/{ovrn}": {
+ "get": {
+ "operationId": "get_api_v1_resources_ovrn",
+ "summary": "Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own ",
+ "description": "**services.resource.read** (first-party): Services' merged resource index over every authority that serves one (ADR-048), readable by a first-party service token holding the capability or by a person's user token scoped to a project they own or belong to (one project per request).",
+ "tags": [
+ "services.resource"
+ ],
+ "x-openvibe-capabilities": [
+ "services.resource.read"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "standard",
+ "security": [
+ {
+ "openvibeToken": [
+ "services.resource.read"
+ ]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "ovrn",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/common.resource-list-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "common.no-body.v1": {
+ "title": "NoBody",
+ "description": "common.no-body@1: the capability's request carries no body; its parameters are the path and query of the routes in implementedBy (an id, a page cursor). An input schema that says so explicitly, so every active capability names one (roadmap WS-C task 4).",
+ "type": "object",
+ "maxProperties": 0
+ },
+ "common.resource-list-result.v1": {
+ "title": "ResourceListResult",
+ "description": "A page of the resource index (roadmap WS-Z7).",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "resources",
+ "next_cursor"
+ ],
+ "properties": {
+ "resources": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/common.resource-summary.v1"
+ }
+ },
+ "next_cursor": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "partial": {
+ "type": "array",
+ "description": "Authorities a merged index (OpenVibe.Services, ADR-048) could not read for this page: a slow or failing authority is omitted, never fails the page. Each entry names the authority and the problem code it answered. Added in 1.1.0; a single authority's own index leaves it out.",
+ "items": {
+ "type": "object",
+ "required": [
+ "service",
+ "code"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "service": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9-]{1,39}$"
+ },
+ "code": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"
+ }
+ }
+ }
+ }
+ }
+ },
+ "common.resource-summary.v1": {
+ "title": "ResourceSummary",
+ "description": "One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "kind",
+ "service",
+ "state",
+ "created_at"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "kind": {
+ "type": "string",
+ "description": "service.kind, e.g. watch.watch, actor.actor, media.object, events.subscription"
+ },
+ "service": {
+ "type": "string"
+ },
+ "project_id": {
+ "type": "string",
+ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "ovrn": {
+ "type": "string",
+ "maxLength": 200,
+ "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."
+ },
+ "owner": {
+ "$ref": "#/components/schemas/identity.subject-ref.v1"
+ },
+ "name": {
+ "type": "string"
+ },
+ "state": {
+ "type": "string"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "usage": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "number",
+ "minimum": 0
+ },
+ "properties": {},
+ "description": "cost units by name (WS-Z1)"
+ },
+ "links": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "self": {
+ "type": "string",
+ "format": "uri"
+ },
+ "console": {
+ "type": "string",
+ "format": "uri"
+ },
+ "docs": {
+ "type": "string",
+ "format": "uri"
+ }
+ }
+ }
+ }
+ },
+ "errors.problem.v1": {
+ "title": "Problem",
+ "description": "RFC 9457 problem details (application/problem+json) with a stable OpenVibe error code and trace identifiers. The legacy 'error' string is allowed during migration so existing clients keep working.",
+ "type": "object",
+ "required": [
+ "type",
+ "title",
+ "status",
+ "code"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "type": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1
+ },
+ "status": {
+ "type": "integer",
+ "minimum": 400,
+ "maximum": 599
+ },
+ "detail": {
+ "type": "string"
+ },
+ "instance": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "code": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"
+ },
+ "request_id": {
+ "type": "string"
+ },
+ "trace_id": {
+ "type": "string",
+ "pattern": "^[0-9a-f]{32}$"
+ },
+ "errors": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "error": {
+ "type": "string",
+ "description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."
+ }
+ }
+ },
+ "identity.subject-ref.v1": {
+ "title": "SubjectRef",
+ "description": "The one cross-platform reference to an actor. Issued by OpenVibe.Network. Never a service-local integer id.",
+ "oneOf": [
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "user"
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "description": "UserSubject"
+ },
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "guest"
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^gst_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "description": "GuestSubject"
+ },
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "app"
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "description": "AppSubject"
+ },
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "mod"
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "description": "ModSubject"
+ },
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "enum": [
+ "service",
+ "system"
+ ]
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9-]{1,39}$"
+ }
+ },
+ "description": "PrincipalSubject"
+ },
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "agent"
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^agt_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "description": "AgentSubject: an agent (OpenVibe.Actor, or a developer app's agent) acting under grants its owner delegated (roadmap WS-Z2). In an event envelope, on_behalf_of names the owner."
+ }
+ ]
+ },
+ "media.media-ref.v1": {
+ "title": "MediaRef",
+ "description": "Reference to a Media object. Canonical ids (med_<ULID>) arrive with the Wave 4 object model; until then legacy:<app>:<kind>:<id> addresses today's VOD/clip/file/paste/thumbnail rows.",
+ "type": "object",
+ "required": [
+ "media_id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "media_id": {
+ "type": "string",
+ "pattern": "^(med_[0-9A-HJKMNP-TV-Z]{26}|legacy:[a-z][a-z0-9-]{1,39}:(vod|clip|file|paste|thumbnail|avatar):[A-Za-z0-9._/-]{1,200})$"
+ },
+ "role": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]{1,39}$"
+ },
+ "variant": {
+ "type": "string",
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,39}$"
+ }
+ }
+ },
+ "mods.mod-manifest.v1": {
+ "title": "ModManifest",
+ "description": "A mod as the platform knows it (ADR-013): who publishes it, which runtime runs it, which capabilities it asks for and the resources it may use. Requested capabilities are only a request: the install's approved subset is the grant, and trust tiers are install metadata that never change a grant check. The runtime-specific payload (a data pack, a script bundle) is not part of the manifest. 1.1.0 (openvibe-contracts v0.34.0) adds the optional permissions.readGrants and writeGrants, billingHooks and dependencies (ADR-013 amendment of 2026-09-24); every 1.0.0 manifest stays valid.",
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "publisher",
+ "target",
+ "runtime",
+ "permissions",
+ "resources",
+ "compatibility"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "Stable mod id; its principal subject is mod:<id>."
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 80
+ },
+ "version": {
+ "type": "string",
+ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",
+ "description": "Semantic version of this release."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1000
+ },
+ "publisher": {
+ "$ref": "#/components/schemas/identity.subject-ref.v1",
+ "description": "Who publishes the mod (a user or an app subject)."
+ },
+ "target": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9-]{1,39}\\.[a-z][a-z0-9-]{1,39}$",
+ "description": "Where the mod runs: <service>.<surface>, e.g. games.browser, games.source, live.overlay."
+ },
+ "runtime": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9-]{1,39}@[1-9][0-9]{0,3}$",
+ "description": "Runtime adapter and its major version, e.g. games-content@1 (declarative data pack) or source-quickjs@1."
+ },
+ "permissions": {
+ "type": "object",
+ "required": [
+ "capabilities"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "capabilities": {
+ "description": "Capability ids the mod asks for (3+ segments). The target runtime binds only those it implements, and only once granted.",
+ "type": "array",
+ "maxItems": 64,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"
+ }
+ },
+ "events": {
+ "description": "Event types the mod wants delivered to it.",
+ "type": "array",
+ "maxItems": 64,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"
+ }
+ },
+ "modules": {
+ "description": "User-module namespaces the mod wants to read or write (a trailing .* names a family). A namespace listed here may be read and written; readGrants and writeGrants (1.1.0) say which.",
+ "type": "array",
+ "maxItems": 32,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
+ }
+ },
+ "mediaNamespaces": {
+ "description": "Media namespaces the mod wants to read or write. A namespace listed here may be read and written; readGrants and writeGrants (1.1.0) say which.",
+ "type": "array",
+ "maxItems": 32,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"
+ }
+ },
+ "readGrants": {
+ "description": "1.1.0: namespaces the mod may only read. A namespace that is only here is read-only. The install's approved subset is still the grant.",
+ "type": "object",
+ "additionalProperties": false,
+ "minProperties": 1,
+ "properties": {
+ "modules": {
+ "description": "User-module namespaces (a trailing .* names a family).",
+ "type": "array",
+ "maxItems": 32,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
+ }
+ },
+ "mediaNamespaces": {
+ "description": "Media namespaces.",
+ "type": "array",
+ "maxItems": 32,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"
+ }
+ }
+ }
+ },
+ "writeGrants": {
+ "description": "1.1.0: namespaces the mod may read and write. A write needs the namespace here, or in the older modules and mediaNamespaces lists, which mean read and write.",
+ "type": "object",
+ "additionalProperties": false,
+ "minProperties": 1,
+ "properties": {
+ "modules": {
+ "description": "User-module namespaces (a trailing .* names a family).",
+ "type": "array",
+ "maxItems": 32,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
+ }
+ },
+ "mediaNamespaces": {
+ "description": "Media namespaces.",
+ "type": "array",
+ "maxItems": 32,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_-]+)*$"
+ }
+ }
+ }
+ }
+ }
+ },
+ "resources": {
+ "type": "object",
+ "required": [
+ "cpuMs",
+ "memoryMb",
+ "storageMb"
+ ],
+ "additionalProperties": false,
+ "description": "The budget the mod asks for. Runtimes meter it; the sandbox that enforces it lives in OpenVibe.Host (Stage C).",
+ "properties": {
+ "cpuMs": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 1000,
+ "description": "CPU milliseconds per tick (game runtimes) or per request."
+ },
+ "memoryMb": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 4096
+ },
+ "storageMb": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 102400
+ },
+ "outboundHosts": {
+ "description": "Hosts the mod may reach over the network. Empty or absent = none.",
+ "type": "array",
+ "maxItems": 32,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$"
+ }
+ }
+ }
+ },
+ "assets": {
+ "description": "Assets the mod ships, as Media object references.",
+ "type": "array",
+ "maxItems": 256,
+ "items": {
+ "$ref": "#/components/schemas/media.media-ref.v1"
+ }
+ },
+ "compatibility": {
+ "type": "object",
+ "required": [
+ "runtime"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "runtime": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Semver range of the runtime this release works with, e.g. \">=1.0.0 <2.0.0\"."
+ },
+ "contracts": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Semver range of openvibe-contracts releases it was built against."
+ }
+ }
+ },
+ "homepage": {
+ "type": "string",
+ "pattern": "^https://[^\\s]{1,2000}$"
+ },
+ "billingHooks": {
+ "description": "1.1.0: how the mod takes part in money, only through Billing and VIP primitives (ADR-013 amendment, ADR-012). entitlement: the mod checks that the person holds this entitlement (billing.entitlement.check or vip.entitlement.check, granted like any other capability). checkout: the mod sends the person to the platform's own checkout for this plan (vip.membership.checkout or a Billing intent). A mod never takes payment, sees payment details or holds a balance. Prices live in Billing and VIP, never in the manifest.",
+ "type": "array",
+ "maxItems": 32,
+ "items": {
+ "type": "object",
+ "required": [
+ "kind",
+ "key"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "kind": {
+ "enum": [
+ "entitlement",
+ "checkout"
+ ]
+ },
+ "key": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_.:-]{0,127}$",
+ "description": "The entitlement or plan key as Billing and VIP name it, e.g. vip.plan:pln_01jab… (lowercase, the form search.index-document@1 acl.entitlements uses)."
+ },
+ "description": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "What it unlocks or sells, shown at install."
+ }
+ }
+ }
+ },
+ "dependencies": {
+ "description": "1.1.0: other mods this release needs. A runtime refuses to enable the mod while a required dependency is not installed, not enabled or outside its range. An optional one is used only when present.",
+ "type": "array",
+ "maxItems": 32,
+ "uniqueItems": true,
+ "items": {
+ "type": "object",
+ "required": [
+ "id",
+ "version"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "version": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Semver range of the dependency's releases this release works with, e.g. \">=1.2.0 <2.0.0\"."
+ },
+ "optional": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "services.app-manifest.v1": {
+ "title": "AppManifest",
+ "description": "PROPOSAL (OpenVibe.Services, roadmap Wave 20): an app release as the platform knows it. The app is a Network developer app (ADR-014): its id is the Network app id, its capabilities are only a request (the grants in Network are the authority), and trust tiers are metadata that never change a grant check. OpenVibe.Services validates with this schema, loaded into openvibe-contracts' validator, until Contracts publishes it as services.app-manifest@1.",
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "publisher",
+ "project_id",
+ "capabilities",
+ "compatibility"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network app id (its client_id). Its principal subject is app:<id>."
},
},
- "instance": {
+ "name": {
"type": "string",
"type": "string",
- "format": "uri-reference"
+ "minLength": 1,
+ "maxLength": 80
},
},
- "code": {
+ "version": {
"type": "string",
"type": "string",
- "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"
+ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$",
+ "description": "Semantic version of this release."
},
},
- "request_id": {
- "type": "string"
+ "description": {
+ "type": "string",
+ "maxLength": 1000
},
},
- "trace_id": {
+ "publisher": {
+ "$ref": "#/components/schemas/identity.subject-ref.v1",
+ "description": "Who publishes the release: the app itself or a member of its project."
+ },
+ "project_id": {
"type": "string",
"type": "string",
- "pattern": "^[0-9a-f]{32}$"
+ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network project that owns the app. Tenancy in other services is keyed by it (ADR-014)."
},
},
- "errors": {
+ "environment": {
+ "enum": [
+ "sandbox",
+ "production"
+ ],
+ "description": "The app's environment. Apps never change environment."
+ },
+ "capabilities": {
+ "description": "Capability ids the app asks for (3+ segments). Only active public (or partner, by staff allowance) capabilities can ever be granted to apps.",
"type": "array",
"type": "array",
+ "maxItems": 64,
+ "uniqueItems": true,
"items": {
"items": {
- "type": "object",
- "required": [
- "message"
- ],
- "properties": {
- "path": {
- "type": "string"
- },
- "message": {
- "type": "string"
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+){2,}$"
+ }
+ },
+ "events": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "consumes": {
+ "description": "Event types (or a trailing .* family) the app subscribes to.",
+ "type": "array",
+ "maxItems": 64,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*(\\.\\*)?$"
}
}
}
}
}
}
},
},
- "error": {
+ "redirect_uris": {
+ "description": "Informational copy of the redirect URIs registered in Network (Network's list is the authority).",
+ "type": "array",
+ "maxItems": 10,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "maxLength": 500
+ }
+ },
+ "homepage": {
"type": "string",
"type": "string",
- "description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."
+ "pattern": "^https://[^\\s]{1,2000}$"
+ },
+ "repository": {
+ "type": "string",
+ "pattern": "^https://[^\\s]{1,2000}$"
+ },
+ "license": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "SPDX license expression."
+ },
+ "compatibility": {
+ "type": "object",
+ "required": [
+ "contracts"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "contracts": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Semver range of openvibe-contracts releases it was built against."
+ },
+ "sdk": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100,
+ "description": "Semver range of openvibe-sdk releases it uses."
+ }
+ }
}
}
}
}
},
},
- "identity.subject-ref.v1": {
- "title": "SubjectRef",
- "description": "The one cross-platform reference to an actor. Issued by OpenVibe.Network. Never a service-local integer id.",
- "oneOf": [
+ "services.release-manage-request.v1": {
+ "title": "ServicesReleaseManageRequest",
+ "description": "services.release-manage-request@1: bodies of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as services.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.",
+ "anyOf": [
{
{
"type": "object",
"type": "object",
"required": [
"required": [
- "type",
- "id"
+ "manifest"
],
],
- "additionalProperties": false,
"properties": {
"properties": {
- "type": {
- "const": "user"
- },
- "id": {
+ "kind": {
"type": "string",
"type": "string",
- "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
+ "description": "mod, or app (the default)."
+ },
+ "manifest": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/services.app-manifest.v1"
+ },
+ {
+ "$ref": "#/components/schemas/mods.mod-manifest.v1"
+ }
+ ]
+ },
+ "notes": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "publish": {
+ "type": "boolean"
}
}
- },
- "description": "UserSubject"
+ }
},
},
{
{
"type": "object",
"type": "object",
"required": [
"required": [
- "type",
- "id"
+ "reason"
],
],
- "additionalProperties": false,
"properties": {
"properties": {
- "type": {
- "const": "guest"
- },
- "id": {
+ "reason": {
"type": "string",
"type": "string",
- "pattern": "^gst_[0-9A-HJKMNP-TV-Z]{26}$"
+ "minLength": 1,
+ "pattern": "\\S"
+ },
+ "replacement": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^(rel_[0-9A-HJKMNP-TV-Z]{26})?$"
}
}
- },
- "description": "GuestSubject"
+ }
+ },
+ {
+ "$ref": "#/components/schemas/common.no-body.v1"
+ }
+ ]
+ },
+ "services.release-manage-result.v1": {
+ "title": "ServicesReleaseManageResult",
+ "description": "services.release-manage-result@1: answers of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.",
+ "type": "object",
+ "required": [
+ "release"
+ ],
+ "properties": {
+ "release": {
+ "$ref": "#/components/schemas/services.release.v1"
+ },
+ "warnings": {
+ "type": "array",
+ "items": {}
},
},
+ "event_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ },
+ "services.release-read-result.v1": {
+ "title": "ServicesReleaseReadResult",
+ "description": "services.release-read-result@1: answers of services.release.read on OpenVibe.Services (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: services.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.",
+ "anyOf": [
{
{
"type": "object",
"type": "object",
"required": [
"required": [
- "type",
- "id"
+ "app_id",
+ "trust",
+ "releases"
],
],
- "additionalProperties": false,
"properties": {
"properties": {
- "type": {
- "const": "app"
- },
- "id": {
+ "app_id": {
"type": "string",
"type": "string",
"pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
"pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "trust": {
+ "type": "object",
+ "required": [
+ "tier"
+ ],
+ "properties": {
+ "tier": {
+ "type": "string"
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ },
+ "releases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/services.release.v1"
+ }
}
}
- },
- "description": "AppSubject"
+ }
},
},
{
{
"type": "object",
"type": "object",
"required": [
"required": [
- "type",
- "id"
+ "app_id",
+ "tier",
+ "note_on_authority"
],
],
- "additionalProperties": false,
"properties": {
"properties": {
- "type": {
- "const": "mod"
- },
- "id": {
+ "app_id": {
"type": "string",
"type": "string",
- "pattern": "^mod_[0-9A-HJKMNP-TV-Z]{26}$"
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "tier": {
+ "type": "string"
+ },
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "note_on_authority": {
+ "type": "string"
}
}
- },
- "description": "ModSubject"
+ }
},
},
{
{
"type": "object",
"type": "object",
"required": [
"required": [
- "type",
- "id"
+ "release",
+ "manifest"
],
],
- "additionalProperties": false,
"properties": {
"properties": {
- "type": {
- "enum": [
- "service",
- "system"
- ]
+ "release": {
+ "$ref": "#/components/schemas/services.release.v1"
},
},
- "id": {
- "type": "string",
- "pattern": "^[a-z][a-z0-9-]{1,39}$"
+ "manifest": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/services.app-manifest.v1"
+ },
+ {
+ "$ref": "#/components/schemas/mods.mod-manifest.v1"
+ },
+ {
+ "type": "null"
+ }
+ ]
}
}
- },
- "description": "PrincipalSubject"
+ }
+ }
+ ]
+ },
+ "services.release.v1": {
+ "title": "ServicesRelease",
+ "description": "services.release@1: one release of an app or mod as OpenVibe.Services presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (services.app-manifest@1).",
+ "type": "object",
+ "required": [
+ "id",
+ "app_id",
+ "kind",
+ "name",
+ "version",
+ "status",
+ "manifest_id",
+ "created_at",
+ "trust"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^rel_[0-9A-HJKMNP-TV-Z]{26}$"
},
},
- {
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "project_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "environment": {
+ "enum": [
+ "production",
+ "sandbox"
+ ]
+ },
+ "kind": {
+ "enum": [
+ "app",
+ "mod"
+ ]
+ },
+ "subject_id": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "name": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "draft",
+ "published",
+ "deprecated",
+ "revoked"
+ ]
+ },
+ "manifest_id": {
+ "type": "string"
+ },
+ "compatibility": {
+ "type": "object"
+ },
+ "notes": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "created_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "published_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "deprecated_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "deprecation_reason": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "replacement": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "revoked_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "revocation_reason": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "trust": {
"type": "object",
"type": "object",
"required": [
"required": [
- "type",
- "id"
+ "tier"
],
],
- "additionalProperties": false,
"properties": {
"properties": {
- "type": {
- "const": "agent"
+ "tier": {
+ "type": "string"
},
},
- "id": {
- "type": "string",
- "pattern": "^agt_[0-9A-HJKMNP-TV-Z]{26}$"
+ "note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "set_at": {
+ "type": [
+ "string",
+ "null"
+ ]
}
}
- },
- "description": "AgentSubject: an agent (OpenVibe.Actor, or a developer app's agent) acting under grants its owner delegated (roadmap WS-Z2). In an event envelope, on_behalf_of names the owner."
+ }
}
}
- ]
+ }
}
}
},
},
"securitySchemes": {
"securitySchemes": {
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Sources API",
"title": "OpenVibe.Sources API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Space API",
"title": "OpenVibe.Space API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tips API",
"title": "OpenVibe.Tips API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tools API",
"title": "OpenVibe.Tools API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Trade API",
"title": "OpenVibe.Trade API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.VIP API",
"title": "OpenVibe.VIP API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Watch API",
"title": "OpenVibe.Watch API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Wiki API",
"title": "OpenVibe.Wiki API",
- "version": "0.112.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.112.0): each operation lists the capabilities it performs; a token for 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.113.0",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.113.0): each operation lists the capabilities it performs; a token for 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": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -10933,6 +10933,130 @@ export interface CodesModerationActionPayload {
@@ -10933,6 +10933,130 @@ export interface CodesModerationActionPayload {
details?: {};
details?: {};
}
}
+/** [email protected] (owner: services) */
+
+/** [email protected] (owner: services) */
+/**
+ * services.release-manage-result@1: answers of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases → 201 { release, warnings } (a draft, or published at once with publish: true; manifest validation warnings); POST /api/v1/releases/:id/publish | deprecate | revoke → { release, event_id } (the codes.release.* event announcing it; null when a revoke announced nothing). Refusals are problem+json: 401 auth.required, 403 release.forbidden (another app's release), 409 release.not_draft, 422 with validation errors.
+ */
+export interface ServicesReleaseManageResult {
+ release: ServicesRelease;
+ warnings?: unknown[];
+ event_id?: string | null;
+}
+
+/** [email protected] (owner: services) */
+/**
+ * services.release@1: one release of an app or mod as OpenVibe.Services presents it (server/domain/releases.js view): its lifecycle (draft → published → deprecated or revoked), compatibility ranges and the app's trust tier (metadata only; grants in OpenVibe.Network are the authority). The manifest itself is served separately (services.app-manifest@1).
+ */
+export interface ServicesRelease {
+ id: string;
+ app_id: string;
+ project_id?: string | null;
+ environment?: "production" | "sandbox";
+ kind: "app" | "mod";
+ subject_id?: string | null;
+ name: string;
+ version: string;
+ status: "draft" | "published" | "deprecated" | "revoked";
+ manifest_id: string;
+ compatibility?: {};
+ notes?: string | null;
+ created_at: string;
+ created_by?: string | null;
+ published_at?: string | null;
+ deprecated_at?: string | null;
+ deprecation_reason?: string | null;
+ replacement?: string | null;
+ revoked_at?: string | null;
+ revocation_reason?: string | null;
+ trust: {
+ tier: string;
+ note?: string | null;
+ set_by?: string | null;
+ set_at?: string | null;
+ };
+}
+
+/** [email protected] (owner: services) */
+/**
+ * services.release-read-result@1: answers of services.release.read on OpenVibe.Services (public; no token needed, but a token that is presented must hold the capability; never drafts). GET /api/v1/apps/:app/releases → { app_id, trust, releases } (published, deprecated and revoked releases, newest first); GET /api/v1/apps/:app/trust → { app_id, tier, note, set_by, set_at, note_on_authority } (metadata only: grants in OpenVibe.Network are the authority); GET /api/v1/releases/:id → { release, manifest } (the manifest as published: services.app-manifest@1 for an app, mods.mod-manifest@1 for a mod). An id that is not an app or a release is 404.
+ */
+export type ServicesReleaseReadResult =
+ | {
+ app_id: string;
+ trust: {
+ tier: string;
+ note?: string | null;
+ set_by?: string | null;
+ set_at?: string | null;
+ };
+ releases: ServicesRelease[];
+ }
+ | {
+ app_id: string;
+ tier: string;
+ note?: string | null;
+ set_by?: string | null;
+ set_at?: string | null;
+ note_on_authority: string;
+ }
+ | {
+ release: ServicesRelease;
+ manifest: AppManifest | ModManifest | null;
+ };
+
+/** [email protected] (owner: services) */
+/**
+ * services.release-manage-request@1: bodies of services.release.manage on OpenVibe.Services (an app token managing its own releases). POST /api/v1/apps/:app/releases: { kind?, manifest, notes?, publish? } — kind mod or app (anything else is app); manifest must validate as services.app-manifest@1 for an app or mods.mod-manifest@1 for a mod (422 manifest.invalid with the validation otherwise; a version that already has a release is 409); notes are cut to 2000 characters; publish true publishes the draft at once. POST /api/v1/releases/:id/deprecate: { reason, replacement? } (a reason is required, cut to 500 characters; replacement must be a published release of the same app). POST /api/v1/releases/:id/revoke: { reason } (required). POST /api/v1/releases/:id/publish takes no body. Unknown fields are ignored.
+ */
+export type ServicesReleaseManageRequest =
+ | {
+ /**
+ * mod, or app (the default).
+ */
+ kind?: string;
+ manifest: AppManifest | ModManifest;
+ notes?: string | null;
+ publish?: boolean;
+ }
+ | {
+ reason: string;
+ replacement?: string | null;
+ }
+ | NoBody;
+
+/** [email protected] (owner: services) */
+/**
+ * services.moderation.action v1 (ADR-022, roadmap WS-D task 1). A staff or moderator action on someone else's content or account in OpenVibe.Services, such as revoking or deprecating someone else's release or app, and withdrawing trust in a publisher or signing key. Not a person acting on their own content. Written to the service's outbox in the transaction that performs the action; OpenVibe.Network keeps it in the moderation audit log. The payload is common.moderation-action@1. Envelope: subject { type: moderation_action, id: <target type>:<target id> }, visibility internal, actor the staff member. Never carries the content itself.
+ */
+export interface ServicesModerationActionPayload {
+ /**
+ * A short verb id, as the service names it: <thing>.<what happened> (post.hidden, user.banned, release.revoked, guard.blocked).
+ */
+ action: string;
+ target: {
+ /**
+ * What was acted on, in the service's own words (post, page, release, user, player, …).
+ */
+ type: string;
+ id: string;
+ /**
+ * Whose content or account it was, when known.
+ */
+ owner_subject?: string | null;
+ };
+ /**
+ * The staff member or moderator (null only for a service acting without a person).
+ */
+ actor_subject: string | null;
+ reason?: string | null;
+ /**
+ * Per action: the fields changed, the previous and new state, a bulk action's count, … never the content.
+ */
+ details?: {};
+}
+
/** [email protected] (owner: events) */
/** [email protected] (owner: events) */
/**
/**
* payload.redacts (ADR-026): a producer takes back events it published earlier. Any event may carry it, normally the producer's own *.deleted event. It names event_ids, or subject_type + subject_ids, or both, never an empty list. event_ids names events directly; subject_type + subject_ids names every stored event of the same source (for an app, the same project and environment) about those subjects. OpenVibe.Events rewrites each target into a tombstone (events.tombstone-payload@1) in the transaction that stores the directive. Naming another source's event is 403 events.redaction_not_allowed (the whole batch is refused); a malformed directive is 422 events.invalid_redaction. An event that carries a directive is never redacted itself.
* payload.redacts (ADR-026): a producer takes back events it published earlier. Any event may carry it, normally the producer's own *.deleted event. It names event_ids, or subject_type + subject_ids, or both, never an empty list. event_ids names events directly; subject_type + subject_ids names every stored event of the same source (for an app, the same project and environment) about those subjects. OpenVibe.Events rewrites each target into a tombstone (events.tombstone-payload@1) in the transaction that stores the directive. Naming another source's event is 403 events.redaction_not_allowed (the whole batch is refused); a malformed directive is 422 events.invalid_redaction. An event that carries a directive is never redacted itself.
@@ -2,19 +2,23 @@
@@ -2,19 +2,23 @@
"id": "codes.release.manage",
"id": "codes.release.manage",
"version": "1.0",
"version": "1.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"visibility": "public",
"visibility": "public",
- "description": "An app manages release metadata for ITSELF with its own token (audience openvibe.codes): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the portal with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
+ "description": "RETIRED at 0.113.0: the developer portal moved to OpenVibe.Services. Use services.release.manage (audience openvibe.services); openvibe.codes portal paths redirect permanently to openvibe.services.",
"inputSchema": "codes.release-manage-request@1",
"inputSchema": "codes.release-manage-request@1",
- "permissions": ["codes:releases:write"],
- "resourceConstraints": ["owner", "project"],
+ "permissions": [
+ "codes:releases:write"
+ ],
+ "resourceConstraints": [
+ "owner",
+ "project"
+ ],
"quotaClass": "codes-release-write",
"quotaClass": "codes-release-write",
- "events": ["codes.app.published", "codes.app.deprecated", "codes.app.revoked"],
- "implementedBy": [
- "POST /api/v1/apps/:app/releases",
- "POST /api/v1/releases/:id/publish",
- "POST /api/v1/releases/:id/deprecate",
- "POST /api/v1/releases/:id/revoke"
+ "events": [
+ "codes.app.published",
+ "codes.app.deprecated",
+ "codes.app.revoked"
],
],
+ "implementedBy": [],
"outputSchema": "codes.release-manage-result@1"
"outputSchema": "codes.release-manage-result@1"
}
}
@@ -2,18 +2,18 @@
@@ -2,18 +2,18 @@
"id": "codes.release.read",
"id": "codes.release.read",
"version": "1.0",
"version": "1.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"visibility": "public",
"visibility": "public",
- "description": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",
+ "description": "RETIRED at 0.113.0: the developer portal moved to OpenVibe.Services. Use services.release.read (audience openvibe.services); openvibe.codes portal paths redirect permanently to openvibe.services.",
"outputSchema": "codes.release-read-result@1",
"outputSchema": "codes.release-read-result@1",
- "permissions": ["codes:releases:read"],
- "resourceConstraints": ["none"],
+ "permissions": [
+ "codes:releases:read"
+ ],
+ "resourceConstraints": [
+ "none"
+ ],
"quotaClass": "codes-read",
"quotaClass": "codes-read",
"events": [],
"events": [],
- "implementedBy": [
- "GET /api/v1/apps/:app/releases",
- "GET /api/v1/apps/:app/trust",
- "GET /api/v1/releases/:id"
- ],
+ "implementedBy": [],
"inputSchema": "common.no-body@1"
"inputSchema": "common.no-body@1"
}
}
@@ -2,9 +2,9 @@
@@ -2,9 +2,9 @@
"id": "codes.resource.read",
"id": "codes.resource.read",
"version": "1.0",
"version": "1.0",
"owner": "codes",
"owner": "codes",
- "status": "active",
+ "status": "retired",
"visibility": "first-party",
"visibility": "first-party",
- "description": "Read OpenVibe.Codes' resource index (ADR-048): GET /api/v1/resources lists the resources Codes owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:ovrn reads one by its OVRN (common.resource-summary@1). Every authority serves these for OpenVibe.Services to fan out and merge; Codes' own resources are its validated app and mod manifests (kind codes.manifest, id mfs_<ULID>) and its releases (kind codes.release, id rel_<ULID>), each carrying the Network project it was created in as its tenancy boundary. Trust tiers are per-app metadata and playground run logs are audit records, neither a resource; Codes hosts no repositories, so the catalog carries no codes.repo kind. Planned until Codes ships the index.",
+ "description": "RETIRED at 0.113.0: Codes owns no resources any more. App and mod manifests and releases moved to OpenVibe.Services (kinds services.manifest and services.release), whose merged index (services.resource.read) lists them.",
"permissions": [
"permissions": [
"resources:read"
"resources:read"
],
],
@@ -13,10 +13,7 @@
@@ -13,10 +13,7 @@
],
],
"quotaClass": "standard",
"quotaClass": "standard",
"events": [],
"events": [],
- "implementedBy": [
- "GET /api/v1/resources",
- "GET /api/v1/resources/:ovrn"
- ],
+ "implementedBy": [],
"inputSchema": "common.no-body@1",
"inputSchema": "common.no-body@1",
"outputSchema": "common.resource-list-result@1"
"outputSchema": "common.resource-list-result@1"
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "id": "services.release.manage",
+ "version": "1.0",
+ "owner": "services",
+ "status": "active",
+ "visibility": "public",
+ "description": "An app manages release metadata for ITSELF with its own token (audience openvibe.services): create a release from a validated app or mod manifest, publish, deprecate (with a reason and an optional replacement) and revoke it. The token's sub must be app:<the app in the path>; people manage releases in the console at openvibe.services with their project role instead. Trust tiers are not part of this capability (staff metadata only).",
+ "inputSchema": "services.release-manage-request@1",
+ "permissions": [
+ "services:releases:write"
+ ],
+ "resourceConstraints": [
+ "owner",
+ "project"
+ ],
+ "quotaClass": "services-release-write",
+ "events": [
+ "services.app.published",
+ "services.app.deprecated",
+ "services.app.revoked"
+ ],
+ "implementedBy": [
+ "POST /api/v1/apps/:app/releases",
+ "POST /api/v1/releases/:id/publish",
+ "POST /api/v1/releases/:id/deprecate",
+ "POST /api/v1/releases/:id/revoke"
+ ],
+ "outputSchema": "services.release-manage-result@1"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "id": "services.release.read",
+ "version": "1.0",
+ "owner": "services",
+ "status": "active",
+ "visibility": "public",
+ "description": "Read public release metadata: an app's published, deprecated and revoked releases with their manifests, compatibility ranges and the app's trust tier (metadata only; it never grants anything). Drafts are never returned. Public; no token needed.",
+ "outputSchema": "services.release-read-result@1",
+ "permissions": [
+ "services:releases:read"
+ ],
+ "resourceConstraints": [
+ "none"
+ ],
+ "quotaClass": "services-read",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/apps/:app/releases",
+ "GET /api/v1/apps/:app/trust",
+ "GET /api/v1/releases/:id"
+ ],
+ "inputSchema": "common.no-body@1"
+}
@@ -5,36 +5,28 @@
@@ -5,36 +5,28 @@
"icon": "fa-server",
"icon": "fa-server",
"accent": "#38bdf8",
"accent": "#38bdf8",
"tagline": "Build with the whole network.",
"tagline": "Build with the whole network.",
- "description": "OpenVibe.Services will be the way into everything programmable on OpenVibe. Start from what you want to build (monitor a page and summarise changes, run an AI agent, process uploads, control a robot, add support to a site) and it assembles the services, keys, permissions and working code for you. Then operate it all in one place: projects, grants, usage, quotas, runs, events, deploys and health, with each service keeping its own data.",
+ "description": "OpenVibe.Services is the way into everything programmable on OpenVibe: projects, apps, keys, grants and usage over Network's developer API; generated API, contract, SDK, capability and event docs; OAuth and webhook tools; playgrounds; app and mod releases; and one resource index over every service, with each service keeping its own data. Next: start from what you want to build and it assembles the services, keys, permissions and working code for you.",
"pillars": [
"pillars": [
{
{
"title": "Discover",
"title": "Discover",
- "text": "A catalog of services, recipes and templates, by what they do."
+ "text": "Every service, capability, contract and event, with generated API references."
},
},
{
{
"title": "Build",
"title": "Build",
- "text": "Projects, apps, keys, capabilities, playgrounds and starter code."
+ "text": "Projects, apps, keys, grants, playgrounds, OAuth and webhook tools, starter code."
},
},
{
{
- "title": "Operate",
- "text": "Every resource across the network: runs, events, usage, quotas, health."
+ "title": "Ship",
+ "text": "App and mod manifests, releases and trust tiers, with a public page per app."
},
},
{
{
- "title": "Learn",
- "text": "Help, Wiki and Codes docs, linked from every page."
+ "title": "Operate",
+ "text": "Usage, quotas, exports and one resource index over the whole network."
}
}
],
],
"keywords": "openvibe services, developer platform, open source backend, api platform, event bus api, ai gateway, website monitoring api, developer console",
"keywords": "openvibe services, developer platform, open source backend, api platform, event bus api, ai gateway, website monitoring api, developer console",
- "launch": "the catalog and console over the services that already run (AI, Events, Media, Search, Sources, Host, Tools)",
+ "launch": "the developer console and docs (moved from openvibe.codes) and the merged resource index",
"relationships": {
"relationships": {
- "service": "services",
- "noRepo": true,
- "meanwhile": [
- {
- "label": "OpenVibe.Codes",
- "url": "https://openvibe.codes",
- "note": "The developer portal and docs work today."
- }
- ]
+ "service": "services"
}
}
}
}
@@ -21,22 +21,13 @@
@@ -21,22 +21,13 @@
"site": {
"site": {
"name": "Codes",
"name": "Codes",
"icon": "codes",
"icon": "codes",
- "tagline": "Build on OpenVibe",
- "what": "The developer portal: API and SDK docs, the service and capability registry, event schemas, credentials, playgrounds and mod publishing.",
+ "tagline": "Code with any agent",
+ "what": "The open coding-agent harness: Claude Code, Codex, OpenCode, Command Code, the DeepSeek API and self-hosted models behind one router with hand-offs, sessions and budgets, and the way to improve OpenVibe itself.",
"legalProfile": "ugc",
"legalProfile": "ugc",
- "position": 7
+ "position": 22
},
},
- "capabilities": [
- "codes.resource.read",
- "codes.release.read",
- "codes.release.manage"
- ],
- "eventsProduced": [
- "codes.app.published",
- "codes.app.deprecated",
- "codes.app.revoked",
- "codes.moderation.action"
- ],
+ "capabilities": [],
+ "eventsProduced": [],
"eventsConsumed": [],
"eventsConsumed": [],
"namespacesOwned": [
"namespacesOwned": [
"codes.*"
"codes.*"
@@ -51,15 +42,14 @@
@@ -51,15 +42,14 @@
"deadlineSeconds": 5,
"deadlineSeconds": 5,
"drains": [
"drains": [
"HTTP server closed",
"HTTP server closed",
- "outbox relay stopped (awaited)",
"store closed"
"store closed"
]
]
},
},
"startupRecovery": {
"startupRecovery": {
"resumes": [
"resumes": [
{
{
- "kind": "outbox",
- "what": "unsent events in the outbox table go to OpenVibe.Events once the relay starts (at least once; Events dedupes by event_id)"
+ "kind": "sessions",
+ "what": "signed-in visitors keep their session cookies (verified offline against Network's JWKS); nothing else is pending: the harness catalog is read from the release at boot"
}
}
]
]
},
},
@@ -80,5 +70,5 @@
@@ -80,5 +70,5 @@
"none": "no claims: one process owns codes.db (better-sqlite3, single writer)"
"none": "no claims: one process owns codes.db (better-sqlite3, single writer)"
}
}
},
},
- "notes": "Port 4900, unit openvibe-codes.service, state /var/lib/openvibe-codes. The developer portal (ADR-014): projects, members, apps, credentials, grants and quotas are OWNED BY NETWORK and shown through Network's /api/v1/projects API with the signed-in person's own token; Codes stores none of them and never a secret. Codes owns only manifests, releases (+ append-only release_log), trust tiers (metadata) and playground run logs in its own SQLite. Consumes OpenVibe.Network (SSO with PKCE S256 as OAuth client codes, JWKS, the projects API, the registry, client-credentials) and publishes through OpenVibe.Events (events.event.publish). Playgrounds call Events and Media with the APP's own token only. Docs are generated at boot from the pinned openvibe-contracts and openvibe-sdk."
+ "notes": "Port 4900, unit openvibe-codes.service. The open coding-agent harness (owner 2026-10-08): the harness catalog and router (GET /api/v1/harnesses, POST /api/v1/harnesses/route), the way to improve OpenVibe (contributing, code of conduct, the contributor ladder) and permanent redirects from the former developer-portal paths to openvibe.services, where the portal moved (manifests, releases, trust, playgrounds, docs, OAuth and webhook tools)."
}
}
@@ -87,7 +87,6 @@
@@ -87,7 +87,6 @@
"billing.staff.action",
"billing.staff.action",
"blog.moderation.action",
"blog.moderation.action",
"chat.moderation.action",
"chat.moderation.action",
- "codes.moderation.action",
"community.moderation.action",
"community.moderation.action",
"coupons.moderation.action",
"coupons.moderation.action",
"deals.moderation.action",
"deals.moderation.action",
@@ -99,6 +98,7 @@
@@ -99,6 +98,7 @@
"media.moderation.action",
"media.moderation.action",
"news.moderation.action",
"news.moderation.action",
"reviews.moderation.action",
"reviews.moderation.action",
+ "services.moderation.action",
"space.moderation.action",
"space.moderation.action",
"tips.interaction.moderated",
"tips.interaction.moderated",
"tools.moderation.action",
"tools.moderation.action",
@@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
{
{
- "version": "0.0.0",
+ "version": "0.1.0",
"contractRanges": {
"contractRanges": {
- "openvibe-contracts": ">=0.94.0 <1.0.0"
+ "openvibe-contracts": ">=0.113.0 <1.0.0"
},
},
"id": "services",
"id": "services",
"name": "OpenVibe.Services",
"name": "OpenVibe.Services",
@@ -12,35 +12,74 @@
@@ -12,35 +12,74 @@
],
],
"publicOrigin": "https://openvibe.services",
"publicOrigin": "https://openvibe.services",
"exposure": {
"exposure": {
- "state": "internal",
- "publicSite": "placeholder",
- "note": "deployed on loopback :4930 (2026-10-07); openvibe.services keeps its OpenVibe.Sites placeholder until Services has a product surface"
+ "state": "live",
+ "publicSite": "service"
},
},
"capabilities": [
"capabilities": [
- "services.resource.read"
+ "services.resource.read",
+ "services.release.read",
+ "services.release.manage"
+ ],
+ "eventsProduced": [
+ "services.app.published",
+ "services.app.deprecated",
+ "services.app.revoked",
+ "services.moderation.action"
],
],
- "eventsProduced": [],
"eventsConsumed": [],
"eventsConsumed": [],
- "namespacesOwned": [],
+ "namespacesOwned": [
+ "services.*"
+ ],
"lifecycle": {
"lifecycle": {
"liveness": {
"liveness": {
- "none": "not built yet; nothing listens on a loopback address"
+ "endpoint": "/api/health",
+ "means": "the process is up and answers HTTP; it checks nothing else (the database and dependencies are what ready checks)"
},
},
"shutdown": {
"shutdown": {
- "none": "not built yet; nothing runs or drains"
+ "signal": "SIGTERM",
+ "deadlineSeconds": 5,
+ "drains": [
+ "HTTP server closed",
+ "Network key refresher stopped",
+ "outbox relay stopped (awaited)",
+ "store closed"
+ ]
},
},
"startupRecovery": {
"startupRecovery": {
- "none": "not built yet; nothing starts"
+ "resumes": [
+ {
+ "kind": "outbox",
+ "what": "unsent events in the outbox table go to OpenVibe.Events once the relay starts (at least once; Events dedupes by event_id)"
+ }
+ ]
},
},
"rollback": {
"rollback": {
- "none": "not built yet; nothing is released or rolled back"
+ "conditions": [
+ "automatic: ovhost deploy puts the previous sha back and restarts again when the ready URL does not answer 2xx within ready.timeoutSeconds after the restart (exit 3)",
+ "manual: ovhost rollback <service> --to <sha>"
+ ],
+ "window": "automatic only while ovhost waits for readiness after the restart (30 s in host.example.json); manual afterwards, as long as no blocker applies",
+ "blockers": [
+ "the console tables arrive in migration 0002 (expand only): a release from before it simply never reads them"
+ ]
},
},
"contracts": {
"contracts": {
- "range": ">=0.94.0 <1.0.0"
+ "range": ">=0.113.0 <1.0.0"
},
},
"leases": {
"leases": {
- "none": "not built yet; nothing runs"
+ "none": "no claims: the outbox relay is the only background work and Events dedupes by event_id"
}
}
},
},
- "notes": "The developer platform of the network (plan T13, ADR-048): where projects, apps, keys, grants, capabilities, usage, quotas, runs, events, deploys and health over every service are looked up, with each service keeping its own data. Serves its merged resource index on loopback :4930 (plan T13 step 4); services.resource.read is its first capability."
+ "notes": "Port 4930, unit openvibe-services.service. The developer platform of the network (plan T13, ADR-048; the developer portal moved here from OpenVibe.Codes, ADR-014): projects, members, apps, credentials, grants and quotas are OWNED BY NETWORK and shown through Network's /api/v1/projects API with the signed-in person's own token; Services stores none of them and never a secret. Services owns manifests, releases (+ append-only release_log), trust tiers (metadata) and playground run logs, and serves the merged resource index over every authority (services.resource.read). Consumes OpenVibe.Network (SSO with PKCE S256 as OAuth client services, JWKS, the projects API, the registry, client-credentials) and publishes through OpenVibe.Events (events.event.publish). Playgrounds call Events and Media with the APP's own token only. Docs are generated at boot from the pinned openvibe-contracts and openvibe-sdk.",
+ "health": "/api/health",
+ "ready": "/api/ready",
+ "internalOrigin": "http://127.0.0.1:4930",
+ "site": {
+ "name": "Services",
+ "icon": "services",
+ "tagline": "Build on OpenVibe",
+ "what": "The developer platform: projects, apps, keys, grants and usage; API, contract, SDK and event docs; OAuth and webhook tools, playgrounds and app releases.",
+ "legalProfile": "ugc",
+ "position": 7
+ }
}
}
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.112.0",
+ "version": "0.113.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.112.0",
+ "version": "0.113.0",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
"ajv": "^8.17.1",
"ajv": "^8.17.1",
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.112.0",
+ "version": "0.113.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
"types": "generated/typescript/index.d.ts",
@@ -805,13 +805,14 @@ await assert.rejects(failing.getToken(), /401: invalid_client/);
@@ -805,13 +805,14 @@ await assert.rejects(failing.getToken(), /401: invalid_client/);
// without an older shape are common.moderation-action@1, and Network consumes every one of them.
// without an older shape are common.moderation-action@1, and Network consumes every one of them.
{
{
const moderation = contracts.catalog.filter(c => /\.moderation\.action$/.test(c.id));
const moderation = contracts.catalog.filter(c => /\.moderation\.action$/.test(c.id));
- for (const svc of ['media', 'tools', 'games', 'wiki', 'blog', 'news', 'reviews', 'deals', 'coupons', 'trade', 'codes', 'space']) {
+ for (const svc of ['media', 'tools', 'games', 'wiki', 'blog', 'news', 'reviews', 'deals', 'coupons', 'trade', 'services', 'space']) {
const id = `${svc}.moderation.action`;
const id = `${svc}.moderation.action`;
const c = moderation.find(x => x.id === id);
const c = moderation.find(x => x.id === id);
ok(c && c.owner === svc && c.adr === 'ADR-022', `${id} is owned by ${svc}`);
ok(c && c.owner === svc && c.adr === 'ADR-022', `${id} is owned by ${svc}`);
ok(contracts.schema(id).$ref === '../../common/moderation-action.v1.json', `${id} is a common.moderation-action@1`);
ok(contracts.schema(id).$ref === '../../common/moderation-action.v1.json', `${id} is a common.moderation-action@1`);
}
}
- for (const c of moderation) ok(services.get('network').eventsConsumed.includes(c.id), `network consumes ${c.id} into the moderation audit log`);
+ // A retired type (codes.moderation.action, 0.113.0) stays loadable for history; nothing produces it any more.
+ for (const c of moderation.filter(x => x.status !== 'retired')) ok(services.get('network').eventsConsumed.includes(c.id), `network consumes ${c.id} into the moderation audit log`);
const M = (v) => contracts.validate('common.moderation-action@1', v).valid;
const M = (v) => contracts.validate('common.moderation-action@1', v).valid;
const base = { action: 'post.hidden', target: { type: 'post', id: 'p1', owner_subject: null }, actor_subject: null };
const base = { action: 'post.hidden', target: { type: 'post', id: 'p1', owner_subject: null }, actor_subject: null };
ok(M(base) && M({ ...base, reason: 'spam', details: { previous: 'published' } }), 'action, target and actor_subject are enough; reason and details are optional');
ok(M(base) && M({ ...base, reason: 'spam', details: { previous: 'published' } }), 'action, target and actor_subject are enough; reason and details are optional');
@@ -913,7 +914,7 @@ sub(path.join(__dirname, 'bot-manifest.test.js'));
@@ -913,7 +914,7 @@ sub(path.join(__dirname, 'bot-manifest.test.js'));
sub(path.join(__dirname, 'product-catalog.test.js'));
sub(path.join(__dirname, 'product-catalog.test.js'));
// Named object zones: identity, retired names, list limits and per-zone usage (ADR-031 amendment 2026-10-02).
// Named object zones: identity, retired names, list limits and per-zone usage (ADR-031 amendment 2026-10-02).
sub(path.join(__dirname, 'zones.test.js'));
sub(path.join(__dirname, 'zones.test.js'));
-// *.usage.recorded rollups are counts: only network, codes and zone may consume one, never billing (T5 step 8).
+// *.usage.recorded rollups are counts: only network, services and zone may consume one, never billing (T5 step 8).
sub(path.join(__dirname, 'usage-topics.test.js'));
sub(path.join(__dirname, 'usage-topics.test.js'));
sub(path.join(__dirname, 'billing-grace.test.js'));
sub(path.join(__dirname, 'billing-grace.test.js'));
sub(path.join(__dirname, 'resources.test.js'));
sub(path.join(__dirname, 'resources.test.js'));
@@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
'use strict';
'use strict';
-// T5 step 8: *.usage.recorded rollups are counts for dashboards and quotas, never money. Only network, codes and
+// T5 step 8: *.usage.recorded rollups are counts for dashboards and quotas, never money. Only network, services and
// zone may consume one; Billing never does (it rates platform.usage-sample readings, billing.usage.record).
// zone may consume one; Billing never does (it rates platform.usage-sample readings, billing.usage.record).
const assert = require('assert');
const assert = require('assert');
const fs = require('fs');
const fs = require('fs');
@@ -7,7 +7,7 @@ const path = require('path');
@@ -7,7 +7,7 @@ const path = require('path');
const { capabilities, services, schema } = require('..');
const { capabilities, services, schema } = require('..');
const dir = path.join(__dirname, '..', 'manifests', 'services');
const dir = path.join(__dirname, '..', 'manifests', 'services');
-const MAY_CONSUME = new Set(['network', 'codes', 'zone']);
+const MAY_CONSUME = new Set(['network', 'services', 'zone']);
const isUsageTopic = (t) => /\.usage\.recorded$/.test(t);
const isUsageTopic = (t) => /\.usage\.recorded$/.test(t);
const consumers = [];
const consumers = [];
@@ -19,7 +19,7 @@ for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.json')).sort()) {
@@ -19,7 +19,7 @@ for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.json')).sort()) {
}
}
for (const c of consumers) {
for (const c of consumers) {
- assert.ok(MAY_CONSUME.has(c.id), `${c.id} consumes ${c.topics.join(', ')}: only network, codes and zone may consume a *.usage.recorded topic`);
+ assert.ok(MAY_CONSUME.has(c.id), `${c.id} consumes ${c.topics.join(', ')}: only network, services and zone may consume a *.usage.recorded topic`);
}
}
assert.ok(!consumers.some((c) => c.id === 'billing'), 'billing never consumes a *.usage.recorded topic');
assert.ok(!consumers.some((c) => c.id === 'billing'), 'billing never consumes a *.usage.recorded topic');
assert.ok(consumers.some((c) => c.id === 'network'), 'network consumes the usage rollups it adds up per project');
assert.ok(consumers.some((c) => c.id === 'network'), 'network consumes the usage rollups it adds up per project');