openvibers/openvibe.contracts Commits

Add share.v1 and uniform sharing API contracts (0.291.0) (#301)

OP OpenVibers committed 7 days ago · f6f52740a1 · 131 files, +3469 −88

* Add network-wide sharing contracts and uniform API schemas

* Distinguish member and transfer preview revocations

* Add people, requests, describe and CSRF to the sharing contracts

- share@1 answers people, not bare subjects: owner, members, a pending
  transfer's recipient and pending requests carry share.person@1. Add share.you@1,
  share.access-request-view@1, share.transfer-view@1 and share.people-lookup@1.
- The body carries the service's describe() fields: title, link, roles,
  audiences and transferable.
- PUT accepts notify (default true); access requests gain the dismissed state.
- A transfer request accepts { name } or { subject }.
- Valid and invalid fixtures for every new and changed contract; docs and
  generated output follow. Version stays 0.291.0.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 035418d9..9c850dce 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,5 +1,12 @@
# Changelog
++## 0.291.0 — 2026-11-05
++
++- Add `share@1`: resource refs, audiences, members and member inputs, transfers, access requests, uniform API requests and responses. Transfers are recipient-bound, last seven days, and default to removing the former owner's membership.
++- The uniform response names people: `share.person@1` on the owner, members, a pending transfer's `to` and each pending request; plus `share.you@1`, pending `requests` (`share.access-request-view@1`), the pending transfer view, and the service's `describe()` fields (`title`, `link`, `roles`, `audiences`, `transferable`). Add `share.people-lookup@1` for the exact-name people endpoint.
++- PUT accepts `notify` (default true); access requests can be `dismissed`; a transfer request accepts `{ name }` or `{ subject }`.
++- Add the five `share.*` event payloads with strict ids-only fields; Network owns the model, adopting services produce events using their own source. Valid and invalid fixtures cover every new contract. No existing schema changes.
++
## 0.290.0 — 2026-11-05
ddiff --git a/README.md b/README.md
iindex 9dd87f42..4b320d46 100644
---- a/README.md
++++ b/README.md
@@@ -2,7 +2,7 @@
> Machine-readable contracts for the whole OpenVibe network.
--**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.290.0: 986 schemas in `contracts/catalog.json`, 60 service manifests, 452 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
++**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.291.0: 1002 schemas in `contracts/catalog.json`, 60 service manifests, 452 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).
**License:** AGPL-3.0 (same as every OpenVibe service).
@@@ -350,3 +350,5 @@ The `v0.27.0` tag (commit `742db68`) was cut on top of the `0.28.0` developer-ap
package reports version `0.28.0` and contains both changes (Codes: `codes.app-manifest@1`,
`codes.release.*`; Events: `events.app.*`). `v0.28.0` points at the same commit. Pin `v0.28.0`; `v0.27.0`
stays for consumers that already pinned it and is identical.
++
++The network-wide [sharing contracts](docs/sharing.md) define the uniform access and ownership-transfer API (`share@1`).
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex 5342c09b..ee9bf9e8 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -9112,6 +9112,195 @@
"visibility": "internal",
"compatibility": "backward",
"status": "active"
++ },
++ {
++ "id": "share.resource-ref",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/resource-ref.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.member",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/member.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.member-input",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/member-input.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.transfer",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/transfer.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.access-request",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/access-request.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/share.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.person",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/person.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.you",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/you.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.access-request-view",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/access-request-view.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.transfer-view",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/transfer-view.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.people-lookup",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/people-lookup.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.update-request",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/update-request.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.transfer-request",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/transfer-request.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.transfer-action-request",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/transfer-action-request.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.access-request-create",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/access-request-create.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.list-result",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "share/list-result.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.granted",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "events/payloads/share.granted.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.revoked",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "events/payloads/share.revoked.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.transfer.requested",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "events/payloads/share.transfer.requested.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.transfer.accepted",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "events/payloads/share.transfer.accepted.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "share.transfer.declined",
++ "version": "1.0.0",
++ "owner": "network",
++ "schema": "events/payloads/share.transfer.declined.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
}
]
--}
\\ No newline at end of file
++}
ddiff --git a/contracts/events/payloads/share.granted.v1.json b/contracts/events/payloads/share.granted.v1.json
nnew file mode 100644
iindex 00000000..7dcf1217
---- /dev/null
++++ b/contracts/events/payloads/share.granted.v1.json
@@@ -0,0 +1,67 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.granted.v1.json",
++ "title": "ShareGrantedPayload",
++ "description": "share.granted@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "reason": {
++ "enum": [
++ "member_added",
++ "member_removed",
++ "member_expired",
++ "audience_changed",
++ "transfer_cancelled",
++ "transfer_expired",
++ "ownership_changed"
++ ]
++ },
++ "transfer_id": {
++ "type": "string",
++ "format": "uuid"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at"
++ ]
++}
ddiff --git a/contracts/events/payloads/share.revoked.v1.json b/contracts/events/payloads/share.revoked.v1.json
nnew file mode 100644
iindex 00000000..06dbd580
---- /dev/null
++++ b/contracts/events/payloads/share.revoked.v1.json
@@@ -0,0 +1,67 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.revoked.v1.json",
++ "title": "ShareRevokedPayload",
++ "description": "share.revoked@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "reason": {
++ "enum": [
++ "member_added",
++ "member_removed",
++ "member_expired",
++ "audience_changed",
++ "transfer_cancelled",
++ "transfer_expired",
++ "ownership_changed"
++ ]
++ },
++ "transfer_id": {
++ "type": "string",
++ "format": "uuid"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at"
++ ]
++}
ddiff --git a/contracts/events/payloads/share.transfer.accepted.v1.json b/contracts/events/payloads/share.transfer.accepted.v1.json
nnew file mode 100644
iindex 00000000..43244f1e
---- /dev/null
++++ b/contracts/events/payloads/share.transfer.accepted.v1.json
@@@ -0,0 +1,46 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.transfer.accepted.v1.json",
++ "title": "ShareTransferAcceptedPayload",
++ "description": "share.transfer.accepted@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "transfer": {
++ "$ref": "../../share/transfer.v1.json"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at",
++ "transfer"
++ ]
++}
ddiff --git a/contracts/events/payloads/share.transfer.declined.v1.json b/contracts/events/payloads/share.transfer.declined.v1.json
nnew file mode 100644
iindex 00000000..bb993c87
---- /dev/null
++++ b/contracts/events/payloads/share.transfer.declined.v1.json
@@@ -0,0 +1,46 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.transfer.declined.v1.json",
++ "title": "ShareTransferDeclinedPayload",
++ "description": "share.transfer.declined@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "transfer": {
++ "$ref": "../../share/transfer.v1.json"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at",
++ "transfer"
++ ]
++}
ddiff --git a/contracts/events/payloads/share.transfer.requested.v1.json b/contracts/events/payloads/share.transfer.requested.v1.json
nnew file mode 100644
iindex 00000000..d6067cd5
---- /dev/null
++++ b/contracts/events/payloads/share.transfer.requested.v1.json
@@@ -0,0 +1,46 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.transfer.requested.v1.json",
++ "title": "ShareTransferRequestedPayload",
++ "description": "share.transfer.requested@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "transfer": {
++ "$ref": "../../share/transfer.v1.json"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at",
++ "transfer"
++ ]
++}
ddiff --git a/contracts/share/access-request-create.v1.json b/contracts/share/access-request-create.v1.json
nnew file mode 100644
iindex 00000000..772fa047
---- /dev/null
++++ b/contracts/share/access-request-create.v1.json
@@@ -0,0 +1,10 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/access-request-create.v1.json",
++ "title": "ShareAccessRequestCreate",
++ "description": "share.access-request-create@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {},
++ "required": []
++}
ddiff --git a/contracts/share/access-request-view.v1.json b/contracts/share/access-request-view.v1.json
nnew file mode 100644
iindex 00000000..f5477461
---- /dev/null
++++ b/contracts/share/access-request-view.v1.json
@@@ -0,0 +1,47 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/access-request-view.v1.json",
++ "title": "ShareAccessRequestView",
++ "description": "share.access-request-view@1: a pending access request in the GET body, with the person who asked. Pending only; dismissed and granted requests are not shown.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "format": "uuid"
++ },
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "username": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "display_name": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "avatar_url": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "requested_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ },
++ "required": [
++ "id",
++ "subject",
++ "username",
++ "display_name",
++ "avatar_url",
++ "requested_at"
++ ]
++}
ddiff --git a/contracts/share/access-request.v1.json b/contracts/share/access-request.v1.json
nnew file mode 100644
iindex 00000000..4366992d
---- /dev/null
++++ b/contracts/share/access-request.v1.json
@@@ -0,0 +1,34 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/access-request.v1.json",
++ "title": "ShareAccessRequest",
++ "description": "share.access-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "format": "uuid"
++ },
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "requested_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "state": {
++ "enum": [
++ "pending",
++ "granted",
++ "dismissed"
++ ]
++ }
++ },
++ "required": [
++ "id",
++ "subject",
++ "requested_at",
++ "state"
++ ]
++}
ddiff --git a/contracts/share/list-result.v1.json b/contracts/share/list-result.v1.json
nnew file mode 100644
iindex 00000000..3a0dc6a9
---- /dev/null
++++ b/contracts/share/list-result.v1.json
@@@ -0,0 +1,63 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/list-result.v1.json",
++ "title": "ShareListResult",
++ "description": "share.list-result@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "items": {
++ "type": "array",
++ "items": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "resource-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "shared_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "transfer": {
++ "$ref": "transfer.v1.json"
++ }
++ },
++ "required": [
++ "ref",
++ "owner_subject",
++ "audience",
++ "role",
++ "shared_at"
++ ]
++ }
++ },
++ "next_cursor": {
++ "type": [
++ "string",
++ "null"
++ ]
++ }
++ },
++ "required": [
++ "items",
++ "next_cursor"
++ ]
++}
ddiff --git a/contracts/share/member-input.v1.json b/contracts/share/member-input.v1.json
nnew file mode 100644
iindex 00000000..252a4e3a
---- /dev/null
++++ b/contracts/share/member-input.v1.json
@@@ -0,0 +1,52 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/member-input.v1.json",
++ "title": "ShareMemberInput",
++ "description": "share.member-input@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "name": {
++ "type": "string",
++ "pattern": "^@?[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$"
++ },
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ },
++ "required": [
++ "role"
++ ],
++ "oneOf": [
++ {
++ "required": [
++ "name"
++ ],
++ "not": {
++ "required": [
++ "subject"
++ ]
++ }
++ },
++ {
++ "required": [
++ "subject"
++ ],
++ "not": {
++ "required": [
++ "name"
++ ]
++ }
++ }
++ ]
++}
ddiff --git a/contracts/share/member.v1.json b/contracts/share/member.v1.json
nnew file mode 100644
iindex 00000000..5d9ed488
---- /dev/null
++++ b/contracts/share/member.v1.json
@@@ -0,0 +1,57 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/member.v1.json",
++ "title": "ShareMember",
++ "description": "share.member@1: a member with their Network identity fields. username, display_name and avatar_url are null when Network does not know the subject (or reports it banned or deleted).",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "username": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "display_name": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "avatar_url": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "added_by": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "added_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ },
++ "required": [
++ "subject",
++ "username",
++ "display_name",
++ "avatar_url",
++ "role",
++ "added_by",
++ "added_at"
++ ]
++}
ddiff --git a/contracts/share/people-lookup.v1.json b/contracts/share/people-lookup.v1.json
nnew file mode 100644
iindex 00000000..6a0e3f69
---- /dev/null
++++ b/contracts/share/people-lookup.v1.json
@@@ -0,0 +1,23 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/people-lookup.v1.json",
++ "title": "SharePeopleLookup",
++ "description": "share.people-lookup@1: the answer to GET /api/v1/share/people?name=exact. person is null when nobody holds that exact name, for banned or deleted accounts, and for non-user subjects.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "person": {
++ "oneOf": [
++ {
++ "$ref": "person.v1.json"
++ },
++ {
++ "type": "null"
++ }
++ ]
++ }
++ },
++ "required": [
++ "person"
++ ]
++}
ddiff --git a/contracts/share/person.v1.json b/contracts/share/person.v1.json
nnew file mode 100644
iindex 00000000..c4030348
---- /dev/null
++++ b/contracts/share/person.v1.json
@@@ -0,0 +1,37 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/person.v1.json",
++ "title": "SharePerson",
++ "description": "share.person@1: a person in a sharing answer, from Network's identity projection. username, display_name and avatar_url are null when Network does not know the subject (or reports it banned or deleted).",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "username": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "display_name": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "avatar_url": {
++ "type": [
++ "string",
++ "null"
++ ]
++ }
++ },
++ "required": [
++ "subject",
++ "username",
++ "display_name",
++ "avatar_url"
++ ]
++}
ddiff --git a/contracts/share/resource-ref.v1.json b/contracts/share/resource-ref.v1.json
nnew file mode 100644
iindex 00000000..8789efde
---- /dev/null
++++ b/contracts/share/resource-ref.v1.json
@@@ -0,0 +1,28 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/resource-ref.v1.json",
++ "title": "ShareResourceRef",
++ "description": "share.resource-ref@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "service": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{1,39}$"
++ },
++ "kind": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
++ },
++ "id": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ }
++ },
++ "required": [
++ "service",
++ "kind",
++ "id"
++ ]
++}
ddiff --git a/contracts/share/share.v1.json b/contracts/share/share.v1.json
nnew file mode 100644
iindex 00000000..527141be
---- /dev/null
++++ b/contracts/share/share.v1.json
@@@ -0,0 +1,98 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/share.v1.json",
++ "title": "Share",
++ "description": "share@1: the uniform GET/PUT body. People, not bare subjects; ids only, never a resource title or content except the service's own describe() (title and link). Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "resource-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "owner": {
++ "$ref": "person.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "members": {
++ "type": "array",
++ "maxItems": 100,
++ "items": {
++ "$ref": "member.v1.json"
++ }
++ },
++ "transfer": {
++ "$ref": "transfer-view.v1.json"
++ },
++ "you": {
++ "$ref": "you.v1.json"
++ },
++ "requests": {
++ "type": "array",
++ "items": {
++ "$ref": "access-request-view.v1.json"
++ }
++ },
++ "title": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "link": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ },
++ "roles": {
++ "type": "array",
++ "minItems": 1,
++ "items": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ }
++ },
++ "audiences": {
++ "type": "array",
++ "minItems": 1,
++ "items": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ }
++ },
++ "transferable": {
++ "type": "boolean"
++ }
++ },
++ "required": [
++ "ref",
++ "owner_subject",
++ "owner",
++ "audience",
++ "members",
++ "you",
++ "requests",
++ "title",
++ "link",
++ "roles",
++ "audiences",
++ "transferable"
++ ]
++}
ddiff --git a/contracts/share/transfer-action-request.v1.json b/contracts/share/transfer-action-request.v1.json
nnew file mode 100644
iindex 00000000..75cf6858
---- /dev/null
++++ b/contracts/share/transfer-action-request.v1.json
@@@ -0,0 +1,17 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/transfer-action-request.v1.json",
++ "title": "ShareTransferActionRequest",
++ "description": "share.transfer-action-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "transfer_id": {
++ "type": "string",
++ "format": "uuid"
++ }
++ },
++ "required": [
++ "transfer_id"
++ ]
++}
ddiff --git a/contracts/share/transfer-request.v1.json b/contracts/share/transfer-request.v1.json
nnew file mode 100644
iindex 00000000..c29d192d
---- /dev/null
++++ b/contracts/share/transfer-request.v1.json
@@@ -0,0 +1,53 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/transfer-request.v1.json",
++ "title": "ShareTransferRequest",
++ "description": "share.transfer-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "to": {
++ "oneOf": [
++ {
++ "type": "string",
++ "pattern": "^@?[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$"
++ },
++ {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "name": {
++ "type": "string",
++ "pattern": "^@?[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$"
++ }
++ },
++ "required": [
++ "name"
++ ]
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ }
++ },
++ "required": [
++ "subject"
++ ]
++ }
++ ]
++ },
++ "keep_access": {
++ "type": "boolean",
++ "default": false
++ }
++ },
++ "required": [
++ "to"
++ ]
++}
ddiff --git a/contracts/share/transfer-view.v1.json b/contracts/share/transfer-view.v1.json
nnew file mode 100644
iindex 00000000..21bfed2f
---- /dev/null
++++ b/contracts/share/transfer-view.v1.json
@@@ -0,0 +1,50 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/transfer-view.v1.json",
++ "title": "ShareTransferView",
++ "description": "share.transfer-view@1: the pending transfer in the GET body, with its recipient as a person. The transfer id is what the sheet sends back.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "format": "uuid"
++ },
++ "from": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "to": {
++ "$ref": "person.v1.json"
++ },
++ "keep_access": {
++ "type": "boolean",
++ "default": false
++ },
++ "requested_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "state": {
++ "enum": [
++ "pending",
++ "accepted",
++ "declined",
++ "cancelled",
++ "expired"
++ ]
++ }
++ },
++ "required": [
++ "id",
++ "from",
++ "to",
++ "keep_access",
++ "requested_at",
++ "expires_at",
++ "state"
++ ]
++}
ddiff --git a/contracts/share/transfer.v1.json b/contracts/share/transfer.v1.json
nnew file mode 100644
iindex 00000000..813b2fac
---- /dev/null
++++ b/contracts/share/transfer.v1.json
@@@ -0,0 +1,50 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/transfer.v1.json",
++ "title": "ShareTransfer",
++ "description": "share.transfer@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "format": "uuid"
++ },
++ "from": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "to": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "keep_access": {
++ "type": "boolean",
++ "default": false
++ },
++ "requested_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "state": {
++ "enum": [
++ "pending",
++ "accepted",
++ "declined",
++ "cancelled",
++ "expired"
++ ]
++ }
++ },
++ "required": [
++ "id",
++ "from",
++ "to",
++ "keep_access",
++ "requested_at",
++ "expires_at",
++ "state"
++ ]
++}
ddiff --git a/contracts/share/update-request.v1.json b/contracts/share/update-request.v1.json
nnew file mode 100644
iindex 00000000..a29729f4
---- /dev/null
++++ b/contracts/share/update-request.v1.json
@@@ -0,0 +1,31 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/update-request.v1.json",
++ "title": "ShareUpdateRequest",
++ "description": "share.update-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "members": {
++ "type": "array",
++ "maxItems": 100,
++ "items": {
++ "$ref": "member-input.v1.json"
++ }
++ },
++ "notify": {
++ "type": "boolean",
++ "default": true
++ }
++ },
++ "required": [],
++ "minProperties": 1
++}
ddiff --git a/contracts/share/you.v1.json b/contracts/share/you.v1.json
nnew file mode 100644
iindex 00000000..c44d862b
---- /dev/null
++++ b/contracts/share/you.v1.json
@@@ -0,0 +1,23 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/you.v1.json",
++ "title": "ShareYou",
++ "description": "share.you@1: who the caller is on this resource, as the sheet needs it. Owner or trusted staff; never a client-supplied value.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "role": {
++ "enum": [
++ "owner",
++ "staff"
++ ]
++ }
++ },
++ "required": [
++ "subject",
++ "role"
++ ]
++}
ddiff --git a/docs/sharing.md b/docs/sharing.md
nnew file mode 100644
iindex 00000000..d0ef0bc9
---- /dev/null
++++ b/docs/sharing.md
@@@ -0,0 +1,28 @@
++# Sharing on OpenVibe: core contracts
++
++`share@1` (`contracts/share/share.v1.json`) is the uniform GET/PUT response. Resource refs are `{ service, kind, id }`; every subject is `identity.subject-ref@1`, never a local id or bare string.
++
++| API | Request contract | Response contract |
++| --- | --- | --- |
++| GET /api/v1/{kind}/{id}/share | none | share@1 |
++| PUT /api/v1/{kind}/{id}/share | share.update-request@1 | share@1 |
++| POST .../share/requests | share.access-request-create@1 | share.access-request@1 |
++| POST .../share/requests/{id}/dismiss | none (empty JSON) | share@1 |
++| POST .../share/transfer | share.transfer-request@1 | share@1 |
++| POST .../share/transfer/{accept,decline,cancel} | share.transfer-action-request@1 | share@1, or share.transfer@1 for a recipient's accept/decline |
++| GET /api/v1/share/people?name=exact | query `name` | share.people-lookup@1 |
++| GET /api/v1/shared-with-me | limit (1–100), cursor (opaque) | share.list-result@1 |
++
++The GET/PUT body names people, not bare subjects. `owner`, every member, the pending transfer's `to` and every pending request carry `share.person@1` (`{ subject, username, display_name, avatar_url }`, from Network's identity projection; a subject Network does not know, or reports banned or deleted, has a null username). It also carries `you` (`share.you@1`: `owner` or `staff`), `requests` (pending only, `share.access-request-view@1`) and the service's own `describe(ref)`: `title`, `link`, `roles` (default `['viewer']`), `audiences` (default all four) and `transferable` (default `true`). `owner_subject` stays for ids-only consumers. PUT, POST transfer, cancel, dismiss, and a recipient's accept or decline answer with the same body and a fresh ETag so the Share sheet redraws from one shape; a recipient's accept or decline answers the plain `share.transfer@1` its banner expects.
++
++PUT replaces members when `members` is present; omitted fields are unchanged. `name` and `subject` are mutually exclusive. Members and transfer recipients must be active **user** subjects: non-user subjects are refused, and a user subject is verified against Network's batch resolver, so unknown, banned and deleted accounts cannot be added. Names are exact, resolved by Network with per-caller rate limiting; there is no global suggestion endpoint. `GET /api/v1/share/people?name=` is signed in only, answers `{ person }` or `{ person: null }` for an unknown, banned or deleted account, and shares the name-check budget (`429 share.rate_limited`). `notify: false` on a PUT suppresses `share.added` for that save; events still flow. The agent SDK `.add()` preserves existing members.
++
++Public is listed and viewable by anyone; link is viewable by link but excluded from listings/indexes. People admits active members; private admits the owner. Editors may edit only with people audience. An unexpired pending transfer permits its recipient to preview in any audience. Staff moderation is an authenticated server assertion and every override is audited. A staff member who is not the owner may narrow access only — set the audience to private and remove members — and nothing else; widening, adding a member or raising a role is a generic 404 like any other non-owner. A denied resource returns generic 404 with no title or content. A non-GET request without an Authorization header needs `X-Requested-With` or `Sec-Fetch-Site: same-origin|same-site`, otherwise `403 { code: 'share.csrf' }`.
++
++Transfer actions must include `transfer_id`, preventing a stale notification from accepting a newer offer. A transfer request accepts `to` as an exact `@name`, a subject ref, `{ subject }` or `{ name }`. Only the exact recipient subject can accept/decline; only the owner can cancel. Seven-day expiry is enforced at access and action time. Accept removes the old owner's membership unless `keep_access` is true (viewer); public/link viewing remains inherent to that audience. Private becomes people when keeping the old owner as viewer, so the chosen retained access works. These operations are atomic and log outgoing/incoming ownership separately. A pending access request is `pending`, `granted` when its person is added, or `dismissed` when the owner dismisses it.
++
++The events are `share.granted`, `share.revoked`, `share.transfer.requested`, `share.transfer.accepted`, `share.transfer.declined`. Payloads never carry titles or content in **any** audience. Network owns these shared contracts and adopting services use their own event source and declare produced types in their manifests. Audience changes, cancellation and expiry emit appropriate grant/revoke effects; notification kinds are `share.added`, `share.access_requested`, `share.transfer.requested`, `share.transfer.answered`. Only a newly added member hears `share.added` (not on a role or expiry change, and never on removal or expiry); the owner hears an answer, accept/decline/expiry, and the recipient hears a cancellation. Nobody is told about their own action, and the owner is never told about their own audience change.
++
++Service integration must enforce `canView` on pages, raw/download/API, embeds, media proxies, comments and previews. Only public resources may be indexed, exported to search, listed in sitemaps or have content previews/events; even an owner viewing a private item must not export its content. Store media private and serve it through a checked service proxy. The SDK core does not retrofit adopting service routes.
++
++Grant/revoke payloads may carry `reason` (member_added, member_removed, member_expired, audience_changed, transfer_cancelled, transfer_expired, ownership_changed) and `transfer_id`. A consumer removes only the indicated grant: losing a pending preview does not remove an independent membership. Audience changes update the resource-wide audience. These are access metadata, never titles or content.
ddiff --git a/fixtures/share.access-request-create/invalid/unknown-field.json b/fixtures/share.access-request-create/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..9b77e975
---- /dev/null
++++ b/fixtures/share.access-request-create/invalid/unknown-field.json
@@@ -0,0 +1,3 @@
++{
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.access-request-create/valid/example.json b/fixtures/share.access-request-create/valid/example.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/share.access-request-create/valid/example.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/share.access-request-view/invalid/missing-username.json b/fixtures/share.access-request-view/invalid/missing-username.json
nnew file mode 100644
iindex 00000000..826284f5
---- /dev/null
++++ b/fixtures/share.access-request-view/invalid/missing-username.json
@@@ -0,0 +1,7 @@
++{
++ "id": "00000000-0000-4000-8000-000000000001",
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS" },
++ "display_name": "Xenia",
++ "avatar_url": null,
++ "requested_at": "2026-11-06T00:05:00Z"
++}
ddiff --git a/fixtures/share.access-request-view/valid/example.json b/fixtures/share.access-request-view/valid/example.json
nnew file mode 100644
iindex 00000000..681902ad
---- /dev/null
++++ b/fixtures/share.access-request-view/valid/example.json
@@@ -0,0 +1,8 @@
++{
++ "id": "00000000-0000-4000-8000-000000000001",
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS" },
++ "username": "xenia",
++ "display_name": "Xenia",
++ "avatar_url": null,
++ "requested_at": "2026-11-06T00:05:00Z"
++}
ddiff --git a/fixtures/share.access-request/invalid/unknown-field.json b/fixtures/share.access-request/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..4df0b10e
---- /dev/null
++++ b/fixtures/share.access-request/invalid/unknown-field.json
@@@ -0,0 +1,10 @@
++{
++ "id": "00000000-0000-4000-8000-000000000001",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "requested_at": "2026-11-06T00:00:00Z",
++ "state": "pending",
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.access-request/valid/dismissed.json b/fixtures/share.access-request/valid/dismissed.json
nnew file mode 100644
iindex 00000000..b71f7ca4
---- /dev/null
++++ b/fixtures/share.access-request/valid/dismissed.json
@@@ -0,0 +1,6 @@
++{
++ "id": "00000000-0000-4000-8000-000000000001",
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "requested_at": "2026-11-06T00:00:00Z",
++ "state": "dismissed"
++}
ddiff --git a/fixtures/share.access-request/valid/example.json b/fixtures/share.access-request/valid/example.json
nnew file mode 100644
iindex 00000000..1ed1302b
---- /dev/null
++++ b/fixtures/share.access-request/valid/example.json
@@@ -0,0 +1,9 @@
++{
++ "id": "00000000-0000-4000-8000-000000000001",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "requested_at": "2026-11-06T00:00:00Z",
++ "state": "pending"
++}
ddiff --git a/fixtures/share.granted/invalid/content-leak.json b/fixtures/share.granted/invalid/content-leak.json
nnew file mode 100644
iindex 00000000..572a9082
---- /dev/null
++++ b/fixtures/share.granted/invalid/content-leak.json
@@@ -0,0 +1,23 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "role": "viewer",
++ "content": "forbidden"
++}
ddiff --git a/fixtures/share.granted/valid/example.json b/fixtures/share.granted/valid/example.json
nnew file mode 100644
iindex 00000000..30d97a82
---- /dev/null
++++ b/fixtures/share.granted/valid/example.json
@@@ -0,0 +1,22 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "role": "viewer"
++}
ddiff --git a/fixtures/share.list-result/invalid/unknown-field.json b/fixtures/share.list-result/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..0d55052e
---- /dev/null
++++ b/fixtures/share.list-result/invalid/unknown-field.json
@@@ -0,0 +1,5 @@
++{
++ "items": [],
++ "next_cursor": null,
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.list-result/valid/example.json b/fixtures/share.list-result/valid/example.json
nnew file mode 100644
iindex 00000000..ceef6f81
---- /dev/null
++++ b/fixtures/share.list-result/valid/example.json
@@@ -0,0 +1,4 @@
++{
++ "items": [],
++ "next_cursor": null
++}
ddiff --git a/fixtures/share.member-input/invalid/both.json b/fixtures/share.member-input/invalid/both.json
nnew file mode 100644
iindex 00000000..8c2adb29
---- /dev/null
++++ b/fixtures/share.member-input/invalid/both.json
@@@ -0,0 +1,8 @@
++{
++ "name": "@a",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "role": "viewer"
++}
ddiff --git a/fixtures/share.member-input/invalid/prefix.json b/fixtures/share.member-input/invalid/prefix.json
nnew file mode 100644
iindex 00000000..56e1eea5
---- /dev/null
++++ b/fixtures/share.member-input/invalid/prefix.json
@@@ -0,0 +1,4 @@
++{
++ "name": "@a*",
++ "role": "viewer"
++}
ddiff --git a/fixtures/share.member-input/invalid/unknown-field.json b/fixtures/share.member-input/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..2d2d7971
---- /dev/null
++++ b/fixtures/share.member-input/invalid/unknown-field.json
@@@ -0,0 +1,5 @@
++{
++ "name": "@maticus",
++ "role": "viewer",
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.member-input/valid/example.json b/fixtures/share.member-input/valid/example.json
nnew file mode 100644
iindex 00000000..dc24e621
---- /dev/null
++++ b/fixtures/share.member-input/valid/example.json
@@@ -0,0 +1,4 @@
++{
++ "name": "@maticus",
++ "role": "viewer"
++}
ddiff --git a/fixtures/share.member/invalid/bare-subject.json b/fixtures/share.member/invalid/bare-subject.json
nnew file mode 100644
iindex 00000000..5eb37028
---- /dev/null
++++ b/fixtures/share.member/invalid/bare-subject.json
@@@ -0,0 +1,9 @@
++{
++ "subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
++ "role": "viewer",
++ "added_by": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "added_at": "2026-11-06T00:00:00Z"
++}
ddiff --git a/fixtures/share.member/invalid/expiry.json b/fixtures/share.member/invalid/expiry.json
nnew file mode 100644
iindex 00000000..cd446e32
---- /dev/null
++++ b/fixtures/share.member/invalid/expiry.json
@@@ -0,0 +1,13 @@
++{
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "role": "viewer",
++ "added_by": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "added_at": "2026-11-06T00:00:00Z",
++ "expires_at": "tomorrow"
++}
ddiff --git a/fixtures/share.member/invalid/role.json b/fixtures/share.member/invalid/role.json
nnew file mode 100644
iindex 00000000..b31d7012
---- /dev/null
++++ b/fixtures/share.member/invalid/role.json
@@@ -0,0 +1,12 @@
++{
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "role": "owner",
++ "added_by": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "added_at": "2026-11-06T00:00:00Z"
++}
ddiff --git a/fixtures/share.member/invalid/unknown-field.json b/fixtures/share.member/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..9e213395
---- /dev/null
++++ b/fixtures/share.member/invalid/unknown-field.json
@@@ -0,0 +1,13 @@
++{
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "role": "viewer",
++ "added_by": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "added_at": "2026-11-06T00:00:00Z",
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.member/valid/example.json b/fixtures/share.member/valid/example.json
nnew file mode 100644
iindex 00000000..4f1f27ab
---- /dev/null
++++ b/fixtures/share.member/valid/example.json
@@@ -0,0 +1,15 @@
++{
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": "https://cdn.openvibe.network/avatars/maticus.png",
++ "role": "viewer",
++ "added_by": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "added_at": "2026-11-06T00:00:00Z"
++}
ddiff --git a/fixtures/share.people-lookup/invalid/unknown-field.json b/fixtures/share.people-lookup/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..be08a91d
---- /dev/null
++++ b/fixtures/share.people-lookup/invalid/unknown-field.json
@@@ -0,0 +1,9 @@
++{
++ "person": {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": null
++ },
++ "names": ["maticus"]
++}
ddiff --git a/fixtures/share.people-lookup/valid/none.json b/fixtures/share.people-lookup/valid/none.json
nnew file mode 100644
iindex 00000000..b8e51736
---- /dev/null
++++ b/fixtures/share.people-lookup/valid/none.json
@@@ -0,0 +1,3 @@
++{
++ "person": null
++}
ddiff --git a/fixtures/share.people-lookup/valid/person.json b/fixtures/share.people-lookup/valid/person.json
nnew file mode 100644
iindex 00000000..d478fad5
---- /dev/null
++++ b/fixtures/share.people-lookup/valid/person.json
@@@ -0,0 +1,8 @@
++{
++ "person": {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": "https://cdn.openvibe.network/avatars/maticus.png"
++ }
++}
ddiff --git a/fixtures/share.person/invalid/missing-username.json b/fixtures/share.person/invalid/missing-username.json
nnew file mode 100644
iindex 00000000..2d1f3ac2
---- /dev/null
++++ b/fixtures/share.person/invalid/missing-username.json
@@@ -0,0 +1,5 @@
++{
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "display_name": "Maticus",
++ "avatar_url": null
++}
ddiff --git a/fixtures/share.person/valid/example.json b/fixtures/share.person/valid/example.json
nnew file mode 100644
iindex 00000000..63d2b680
---- /dev/null
++++ b/fixtures/share.person/valid/example.json
@@@ -0,0 +1,6 @@
++{
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": "https://cdn.openvibe.network/avatars/maticus.png"
++}
ddiff --git a/fixtures/share.person/valid/unknown.json b/fixtures/share.person/valid/unknown.json
nnew file mode 100644
iindex 00000000..4dcd91a5
---- /dev/null
++++ b/fixtures/share.person/valid/unknown.json
@@@ -0,0 +1,6 @@
++{
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "username": null,
++ "display_name": null,
++ "avatar_url": null
++}
ddiff --git a/fixtures/share.resource-ref/invalid/unknown-field.json b/fixtures/share.resource-ref/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..c27523e3
---- /dev/null
++++ b/fixtures/share.resource-ref/invalid/unknown-field.json
@@@ -0,0 +1,6 @@
++{
++ "service": "community",
++ "kind": "paste",
++ "id": "abc",
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.resource-ref/valid/example.json b/fixtures/share.resource-ref/valid/example.json
nnew file mode 100644
iindex 00000000..c7b9063a
---- /dev/null
++++ b/fixtures/share.resource-ref/valid/example.json
@@@ -0,0 +1,5 @@
++{
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++}
ddiff --git a/fixtures/share.revoked/invalid/content-leak.json b/fixtures/share.revoked/invalid/content-leak.json
nnew file mode 100644
iindex 00000000..572a9082
---- /dev/null
++++ b/fixtures/share.revoked/invalid/content-leak.json
@@@ -0,0 +1,23 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "role": "viewer",
++ "content": "forbidden"
++}
ddiff --git a/fixtures/share.revoked/invalid/unknown-reason.json b/fixtures/share.revoked/invalid/unknown-reason.json
nnew file mode 100644
iindex 00000000..35a9b596
---- /dev/null
++++ b/fixtures/share.revoked/invalid/unknown-reason.json
@@@ -0,0 +1,24 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "role": "viewer",
++ "reason": "resource title",
++ "transfer_id": "00000000-0000-4000-8000-000000000001"
++}
ddiff --git a/fixtures/share.revoked/valid/example.json b/fixtures/share.revoked/valid/example.json
nnew file mode 100644
iindex 00000000..30d97a82
---- /dev/null
++++ b/fixtures/share.revoked/valid/example.json
@@@ -0,0 +1,22 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "role": "viewer"
++}
ddiff --git a/fixtures/share.revoked/valid/transfer-expired.json b/fixtures/share.revoked/valid/transfer-expired.json
nnew file mode 100644
iindex 00000000..fd843b58
---- /dev/null
++++ b/fixtures/share.revoked/valid/transfer-expired.json
@@@ -0,0 +1,24 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "role": "viewer",
++ "reason": "transfer_expired",
++ "transfer_id": "00000000-0000-4000-8000-000000000001"
++}
ddiff --git a/fixtures/share.transfer-action-request/invalid/missing-id.json b/fixtures/share.transfer-action-request/invalid/missing-id.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/share.transfer-action-request/invalid/missing-id.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/share.transfer-action-request/invalid/unknown-field.json b/fixtures/share.transfer-action-request/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..bcd71a2a
---- /dev/null
++++ b/fixtures/share.transfer-action-request/invalid/unknown-field.json
@@@ -0,0 +1,4 @@
++{
++ "transfer_id": "00000000-0000-4000-8000-000000000001",
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.transfer-action-request/valid/example.json b/fixtures/share.transfer-action-request/valid/example.json
nnew file mode 100644
iindex 00000000..12c605a9
---- /dev/null
++++ b/fixtures/share.transfer-action-request/valid/example.json
@@@ -0,0 +1,3 @@
++{
++ "transfer_id": "00000000-0000-4000-8000-000000000001"
++}
ddiff --git a/fixtures/share.transfer-request/invalid/keep-access.json b/fixtures/share.transfer-request/invalid/keep-access.json
nnew file mode 100644
iindex 00000000..0ec7a674
---- /dev/null
++++ b/fixtures/share.transfer-request/invalid/keep-access.json
@@@ -0,0 +1,7 @@
++{
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": "true"
++}
ddiff --git a/fixtures/share.transfer-request/invalid/unknown-field.json b/fixtures/share.transfer-request/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..385a1caf
---- /dev/null
++++ b/fixtures/share.transfer-request/invalid/unknown-field.json
@@@ -0,0 +1,4 @@
++{
++ "to": "@maticus",
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.transfer-request/valid/example.json b/fixtures/share.transfer-request/valid/example.json
nnew file mode 100644
iindex 00000000..24a48bfb
---- /dev/null
++++ b/fixtures/share.transfer-request/valid/example.json
@@@ -0,0 +1,3 @@
++{
++ "to": "@maticus"
++}
ddiff --git a/fixtures/share.transfer-request/valid/subject.json b/fixtures/share.transfer-request/valid/subject.json
nnew file mode 100644
iindex 00000000..4faeaca0
---- /dev/null
++++ b/fixtures/share.transfer-request/valid/subject.json
@@@ -0,0 +1,9 @@
++{
++ "to": {
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ }
++ },
++ "keep_access": true
++}
ddiff --git a/fixtures/share.transfer-view/invalid/bare-to.json b/fixtures/share.transfer-view/invalid/bare-to.json
nnew file mode 100644
iindex 00000000..1a517f85
---- /dev/null
++++ b/fixtures/share.transfer-view/invalid/bare-to.json
@@@ -0,0 +1,9 @@
++{
++ "id": "00000000-0000-4000-8000-000000000002",
++ "from": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "to": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:10:00Z",
++ "expires_at": "2026-11-13T00:10:00Z",
++ "state": "pending"
++}
ddiff --git a/fixtures/share.transfer-view/valid/example.json b/fixtures/share.transfer-view/valid/example.json
nnew file mode 100644
iindex 00000000..4c565a07
---- /dev/null
++++ b/fixtures/share.transfer-view/valid/example.json
@@@ -0,0 +1,14 @@
++{
++ "id": "00000000-0000-4000-8000-000000000002",
++ "from": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "to": {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": null
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:10:00Z",
++ "expires_at": "2026-11-13T00:10:00Z",
++ "state": "pending"
++}
ddiff --git a/fixtures/share.transfer.accepted/invalid/content-leak.json b/fixtures/share.transfer.accepted/invalid/content-leak.json
nnew file mode 100644
iindex 00000000..869277d4
---- /dev/null
++++ b/fixtures/share.transfer.accepted/invalid/content-leak.json
@@@ -0,0 +1,37 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "transfer": {
++ "id": "00000000-0000-4000-8000-000000000001",
++ "from": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:00:00Z",
++ "expires_at": "2026-11-13T00:00:00Z",
++ "state": "accepted"
++ },
++ "content": "forbidden"
++}
ddiff --git a/fixtures/share.transfer.accepted/valid/example.json b/fixtures/share.transfer.accepted/valid/example.json
nnew file mode 100644
iindex 00000000..7f67b652
---- /dev/null
++++ b/fixtures/share.transfer.accepted/valid/example.json
@@@ -0,0 +1,36 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "transfer": {
++ "id": "00000000-0000-4000-8000-000000000001",
++ "from": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:00:00Z",
++ "expires_at": "2026-11-13T00:00:00Z",
++ "state": "accepted"
++ }
++}
ddiff --git a/fixtures/share.transfer.declined/invalid/content-leak.json b/fixtures/share.transfer.declined/invalid/content-leak.json
nnew file mode 100644
iindex 00000000..2b1cf285
---- /dev/null
++++ b/fixtures/share.transfer.declined/invalid/content-leak.json
@@@ -0,0 +1,37 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "transfer": {
++ "id": "00000000-0000-4000-8000-000000000001",
++ "from": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:00:00Z",
++ "expires_at": "2026-11-13T00:00:00Z",
++ "state": "declined"
++ },
++ "content": "forbidden"
++}
ddiff --git a/fixtures/share.transfer.declined/valid/example.json b/fixtures/share.transfer.declined/valid/example.json
nnew file mode 100644
iindex 00000000..eb2d90d3
---- /dev/null
++++ b/fixtures/share.transfer.declined/valid/example.json
@@@ -0,0 +1,36 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "transfer": {
++ "id": "00000000-0000-4000-8000-000000000001",
++ "from": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:00:00Z",
++ "expires_at": "2026-11-13T00:00:00Z",
++ "state": "declined"
++ }
++}
ddiff --git a/fixtures/share.transfer.requested/invalid/content-leak.json b/fixtures/share.transfer.requested/invalid/content-leak.json
nnew file mode 100644
iindex 00000000..bfd6c822
---- /dev/null
++++ b/fixtures/share.transfer.requested/invalid/content-leak.json
@@@ -0,0 +1,37 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "transfer": {
++ "id": "00000000-0000-4000-8000-000000000001",
++ "from": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:00:00Z",
++ "expires_at": "2026-11-13T00:00:00Z",
++ "state": "pending"
++ },
++ "content": "forbidden"
++}
ddiff --git a/fixtures/share.transfer.requested/valid/example.json b/fixtures/share.transfer.requested/valid/example.json
nnew file mode 100644
iindex 00000000..0ef4e08d
---- /dev/null
++++ b/fixtures/share.transfer.requested/valid/example.json
@@@ -0,0 +1,36 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "actor": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "audience": "people",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "occurred_at": "2026-11-06T00:00:00Z",
++ "transfer": {
++ "id": "00000000-0000-4000-8000-000000000001",
++ "from": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:00:00Z",
++ "expires_at": "2026-11-13T00:00:00Z",
++ "state": "pending"
++ }
++}
ddiff --git a/fixtures/share.transfer/invalid/unknown-field.json b/fixtures/share.transfer/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..2ce59d57
---- /dev/null
++++ b/fixtures/share.transfer/invalid/unknown-field.json
@@@ -0,0 +1,16 @@
++{
++ "id": "00000000-0000-4000-8000-000000000001",
++ "from": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:00:00Z",
++ "expires_at": "2026-11-13T00:00:00Z",
++ "state": "pending",
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.transfer/valid/example.json b/fixtures/share.transfer/valid/example.json
nnew file mode 100644
iindex 00000000..6992343b
---- /dev/null
++++ b/fixtures/share.transfer/valid/example.json
@@@ -0,0 +1,15 @@
++{
++ "id": "00000000-0000-4000-8000-000000000001",
++ "from": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "to": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "keep_access": false,
++ "requested_at": "2026-11-06T00:00:00Z",
++ "expires_at": "2026-11-13T00:00:00Z",
++ "state": "pending"
++}
ddiff --git a/fixtures/share.update-request/invalid/empty.json b/fixtures/share.update-request/invalid/empty.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/share.update-request/invalid/empty.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/share.update-request/invalid/unknown-field.json b/fixtures/share.update-request/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..a38655a3
---- /dev/null
++++ b/fixtures/share.update-request/invalid/unknown-field.json
@@@ -0,0 +1,13 @@
++{
++ "audience": "people",
++ "members": [
++ {
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "role": "editor"
++ }
++ ],
++ "title": "must never appear"
++}
ddiff --git a/fixtures/share.update-request/valid/example.json b/fixtures/share.update-request/valid/example.json
nnew file mode 100644
iindex 00000000..ab199f66
---- /dev/null
++++ b/fixtures/share.update-request/valid/example.json
@@@ -0,0 +1,13 @@
++{
++ "audience": "people",
++ "members": [
++ {
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "role": "editor"
++ }
++ ],
++ "notify": false
++}
ddiff --git a/fixtures/share.you/invalid/role.json b/fixtures/share.you/invalid/role.json
nnew file mode 100644
iindex 00000000..1b67b00d
---- /dev/null
++++ b/fixtures/share.you/invalid/role.json
@@@ -0,0 +1,4 @@
++{
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "role": "admin"
++}
ddiff --git a/fixtures/share.you/valid/owner.json b/fixtures/share.you/valid/owner.json
nnew file mode 100644
iindex 00000000..ae93b0af
---- /dev/null
++++ b/fixtures/share.you/valid/owner.json
@@@ -0,0 +1,4 @@
++{
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "role": "owner"
++}
ddiff --git a/fixtures/share/invalid/audience.json b/fixtures/share/invalid/audience.json
nnew file mode 100644
iindex 00000000..0e8673b9
---- /dev/null
++++ b/fixtures/share/invalid/audience.json
@@@ -0,0 +1,19 @@
++{
++ "ref": { "service": "community", "kind": "paste", "id": "abc" },
++ "owner_subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "owner": {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "username": "ursula",
++ "display_name": "Ursula",
++ "avatar_url": null
++ },
++ "audience": "unlisted",
++ "members": [],
++ "you": { "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" }, "role": "owner" },
++ "requests": [],
++ "title": "LOOI bridge notes",
++ "link": "https://community.openvibe.network/p/abc",
++ "roles": ["viewer"],
++ "audiences": ["public", "link", "people", "private"],
++ "transferable": true
++}
ddiff --git a/fixtures/share/invalid/unknown-field.json b/fixtures/share/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..983d71df
---- /dev/null
++++ b/fixtures/share/invalid/unknown-field.json
@@@ -0,0 +1,20 @@
++{
++ "ref": { "service": "community", "kind": "paste", "id": "abc" },
++ "owner_subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "owner": {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "username": "ursula",
++ "display_name": "Ursula",
++ "avatar_url": null
++ },
++ "audience": "people",
++ "members": [],
++ "you": { "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" }, "role": "owner" },
++ "requests": [],
++ "title": "LOOI bridge notes",
++ "link": "https://community.openvibe.network/p/abc",
++ "roles": ["viewer"],
++ "audiences": ["public", "link", "people", "private"],
++ "transferable": true,
++ "content": "must never appear"
++}
ddiff --git a/fixtures/share/valid/example.json b/fixtures/share/valid/example.json
nnew file mode 100644
iindex 00000000..771b7e0c
---- /dev/null
++++ b/fixtures/share/valid/example.json
@@@ -0,0 +1,71 @@
++{
++ "ref": {
++ "service": "community",
++ "kind": "paste",
++ "id": "abc"
++ },
++ "owner_subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "owner": {
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "username": "ursula",
++ "display_name": "Ursula",
++ "avatar_url": null
++ },
++ "audience": "people",
++ "members": [
++ {
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
++ },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": "https://cdn.openvibe.network/avatars/maticus.png",
++ "role": "viewer",
++ "added_by": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "added_at": "2026-11-06T00:00:00Z"
++ }
++ ],
++ "you": {
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
++ },
++ "role": "owner"
++ },
++ "requests": [
++ {
++ "id": "00000000-0000-4000-8000-000000000001",
++ "subject": {
++ "type": "user",
++ "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS"
++ },
++ "username": "xenia",
++ "display_name": "Xenia",
++ "avatar_url": null,
++ "requested_at": "2026-11-06T00:05:00Z"
++ }
++ ],
++ "title": "LOOI bridge notes",
++ "link": "https://community.openvibe.network/p/abc",
++ "roles": [
++ "viewer",
++ "editor"
++ ],
++ "audiences": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ],
++ "transferable": true
++}
ddiff --git a/fixtures/share/valid/link.json b/fixtures/share/valid/link.json
nnew file mode 100644
iindex 00000000..8931681f
---- /dev/null
++++ b/fixtures/share/valid/link.json
@@@ -0,0 +1,29 @@
++{
++ "ref": { "service": "community", "kind": "paste", "id": "abc" },
++ "owner_subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "owner": {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "username": "ursula",
++ "display_name": "Ursula",
++ "avatar_url": null
++ },
++ "audience": "link",
++ "members": [
++ {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": "https://cdn.openvibe.network/avatars/maticus.png",
++ "role": "viewer",
++ "added_by": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "added_at": "2026-11-06T00:00:00Z"
++ }
++ ],
++ "you": { "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" }, "role": "owner" },
++ "requests": [],
++ "title": "LOOI bridge notes",
++ "link": "https://community.openvibe.network/p/abc",
++ "roles": ["viewer"],
++ "audiences": ["public", "link", "people", "private"],
++ "transferable": true
++}
ddiff --git a/fixtures/share/valid/private.json b/fixtures/share/valid/private.json
nnew file mode 100644
iindex 00000000..e448046e
---- /dev/null
++++ b/fixtures/share/valid/private.json
@@@ -0,0 +1,29 @@
++{
++ "ref": { "service": "community", "kind": "paste", "id": "abc" },
++ "owner_subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "owner": {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "username": "ursula",
++ "display_name": "Ursula",
++ "avatar_url": null
++ },
++ "audience": "private",
++ "members": [
++ {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": "https://cdn.openvibe.network/avatars/maticus.png",
++ "role": "viewer",
++ "added_by": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "added_at": "2026-11-06T00:00:00Z"
++ }
++ ],
++ "you": { "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" }, "role": "owner" },
++ "requests": [],
++ "title": "LOOI bridge notes",
++ "link": "https://community.openvibe.network/p/abc",
++ "roles": ["viewer"],
++ "audiences": ["public", "link", "people", "private"],
++ "transferable": true
++}
ddiff --git a/fixtures/share/valid/public.json b/fixtures/share/valid/public.json
nnew file mode 100644
iindex 00000000..7a2bf187
---- /dev/null
++++ b/fixtures/share/valid/public.json
@@@ -0,0 +1,29 @@
++{
++ "ref": { "service": "community", "kind": "paste", "id": "abc" },
++ "owner_subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "owner": {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "username": "ursula",
++ "display_name": "Ursula",
++ "avatar_url": null
++ },
++ "audience": "public",
++ "members": [
++ {
++ "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR" },
++ "username": "maticus",
++ "display_name": "Maticus",
++ "avatar_url": "https://cdn.openvibe.network/avatars/maticus.png",
++ "role": "viewer",
++ "added_by": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
++ "added_at": "2026-11-06T00:00:00Z"
++ }
++ ],
++ "you": { "subject": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" }, "role": "owner" },
++ "requests": [],
++ "title": "LOOI bridge notes",
++ "link": "https://community.openvibe.network/p/abc",
++ "roles": ["viewer"],
++ "audiences": ["public", "link", "people", "private"],
++ "transferable": true
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex 866705b0..a5b2c7c5 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -101584,6 +101584,1056 @@
}
}
}
++ },
++ "share.resource-ref": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/resource-ref.v1.json",
++ "title": "ShareResourceRef",
++ "description": "share.resource-ref@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "service": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{1,39}$"
++ },
++ "kind": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
++ },
++ "id": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ }
++ },
++ "required": [
++ "service",
++ "kind",
++ "id"
++ ]
++ }
++ },
++ "share.member": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/member.v1.json",
++ "title": "ShareMember",
++ "description": "share.member@1: a member with their Network identity fields. username, display_name and avatar_url are null when Network does not know the subject (or reports it banned or deleted).",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "username": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "display_name": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "avatar_url": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "added_by": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "added_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ },
++ "required": [
++ "subject",
++ "username",
++ "display_name",
++ "avatar_url",
++ "role",
++ "added_by",
++ "added_at"
++ ]
++ }
++ },
++ "share.member-input": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/member-input.v1.json",
++ "title": "ShareMemberInput",
++ "description": "share.member-input@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "name": {
++ "type": "string",
++ "pattern": "^@?[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$"
++ },
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ },
++ "required": [
++ "role"
++ ],
++ "oneOf": [
++ {
++ "required": [
++ "name"
++ ],
++ "not": {
++ "required": [
++ "subject"
++ ]
++ }
++ },
++ {
++ "required": [
++ "subject"
++ ],
++ "not": {
++ "required": [
++ "name"
++ ]
++ }
++ }
++ ]
++ }
++ },
++ "share.transfer": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/transfer.v1.json",
++ "title": "ShareTransfer",
++ "description": "share.transfer@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "format": "uuid"
++ },
++ "from": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "to": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "keep_access": {
++ "type": "boolean",
++ "default": false
++ },
++ "requested_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "state": {
++ "enum": [
++ "pending",
++ "accepted",
++ "declined",
++ "cancelled",
++ "expired"
++ ]
++ }
++ },
++ "required": [
++ "id",
++ "from",
++ "to",
++ "keep_access",
++ "requested_at",
++ "expires_at",
++ "state"
++ ]
++ }
++ },
++ "share.access-request": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/access-request.v1.json",
++ "title": "ShareAccessRequest",
++ "description": "share.access-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "format": "uuid"
++ },
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "requested_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "state": {
++ "enum": [
++ "pending",
++ "granted",
++ "dismissed"
++ ]
++ }
++ },
++ "required": [
++ "id",
++ "subject",
++ "requested_at",
++ "state"
++ ]
++ }
++ },
++ "share": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/share.v1.json",
++ "title": "Share",
++ "description": "share@1: the uniform GET/PUT body. People, not bare subjects; ids only, never a resource title or content except the service's own describe() (title and link). Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "resource-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "owner": {
++ "$ref": "person.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "members": {
++ "type": "array",
++ "maxItems": 100,
++ "items": {
++ "$ref": "member.v1.json"
++ }
++ },
++ "transfer": {
++ "$ref": "transfer-view.v1.json"
++ },
++ "you": {
++ "$ref": "you.v1.json"
++ },
++ "requests": {
++ "type": "array",
++ "items": {
++ "$ref": "access-request-view.v1.json"
++ }
++ },
++ "title": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "link": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ },
++ "roles": {
++ "type": "array",
++ "minItems": 1,
++ "items": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ }
++ },
++ "audiences": {
++ "type": "array",
++ "minItems": 1,
++ "items": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ }
++ },
++ "transferable": {
++ "type": "boolean"
++ }
++ },
++ "required": [
++ "ref",
++ "owner_subject",
++ "owner",
++ "audience",
++ "members",
++ "you",
++ "requests",
++ "title",
++ "link",
++ "roles",
++ "audiences",
++ "transferable"
++ ]
++ }
++ },
++ "share.person": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/person.v1.json",
++ "title": "SharePerson",
++ "description": "share.person@1: a person in a sharing answer, from Network's identity projection. username, display_name and avatar_url are null when Network does not know the subject (or reports it banned or deleted).",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "username": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "display_name": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "avatar_url": {
++ "type": [
++ "string",
++ "null"
++ ]
++ }
++ },
++ "required": [
++ "subject",
++ "username",
++ "display_name",
++ "avatar_url"
++ ]
++ }
++ },
++ "share.you": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/you.v1.json",
++ "title": "ShareYou",
++ "description": "share.you@1: who the caller is on this resource, as the sheet needs it. Owner or trusted staff; never a client-supplied value.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "role": {
++ "enum": [
++ "owner",
++ "staff"
++ ]
++ }
++ },
++ "required": [
++ "subject",
++ "role"
++ ]
++ }
++ },
++ "share.access-request-view": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/access-request-view.v1.json",
++ "title": "ShareAccessRequestView",
++ "description": "share.access-request-view@1: a pending access request in the GET body, with the person who asked. Pending only; dismissed and granted requests are not shown.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "format": "uuid"
++ },
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "username": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "display_name": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "avatar_url": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "requested_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ },
++ "required": [
++ "id",
++ "subject",
++ "username",
++ "display_name",
++ "avatar_url",
++ "requested_at"
++ ]
++ }
++ },
++ "share.transfer-view": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/transfer-view.v1.json",
++ "title": "ShareTransferView",
++ "description": "share.transfer-view@1: the pending transfer in the GET body, with its recipient as a person. The transfer id is what the sheet sends back.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "format": "uuid"
++ },
++ "from": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "to": {
++ "$ref": "person.v1.json"
++ },
++ "keep_access": {
++ "type": "boolean",
++ "default": false
++ },
++ "requested_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "state": {
++ "enum": [
++ "pending",
++ "accepted",
++ "declined",
++ "cancelled",
++ "expired"
++ ]
++ }
++ },
++ "required": [
++ "id",
++ "from",
++ "to",
++ "keep_access",
++ "requested_at",
++ "expires_at",
++ "state"
++ ]
++ }
++ },
++ "share.people-lookup": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/people-lookup.v1.json",
++ "title": "SharePeopleLookup",
++ "description": "share.people-lookup@1: the answer to GET /api/v1/share/people?name=exact. person is null when nobody holds that exact name, for banned or deleted accounts, and for non-user subjects.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "person": {
++ "oneOf": [
++ {
++ "$ref": "person.v1.json"
++ },
++ {
++ "type": "null"
++ }
++ ]
++ }
++ },
++ "required": [
++ "person"
++ ]
++ }
++ },
++ "share.update-request": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/update-request.v1.json",
++ "title": "ShareUpdateRequest",
++ "description": "share.update-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "members": {
++ "type": "array",
++ "maxItems": 100,
++ "items": {
++ "$ref": "member-input.v1.json"
++ }
++ },
++ "notify": {
++ "type": "boolean",
++ "default": true
++ }
++ },
++ "required": [],
++ "minProperties": 1
++ }
++ },
++ "share.transfer-request": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/transfer-request.v1.json",
++ "title": "ShareTransferRequest",
++ "description": "share.transfer-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "to": {
++ "oneOf": [
++ {
++ "type": "string",
++ "pattern": "^@?[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$"
++ },
++ {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "name": {
++ "type": "string",
++ "pattern": "^@?[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$"
++ }
++ },
++ "required": [
++ "name"
++ ]
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ }
++ },
++ "required": [
++ "subject"
++ ]
++ }
++ ]
++ },
++ "keep_access": {
++ "type": "boolean",
++ "default": false
++ }
++ },
++ "required": [
++ "to"
++ ]
++ }
++ },
++ "share.transfer-action-request": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/transfer-action-request.v1.json",
++ "title": "ShareTransferActionRequest",
++ "description": "share.transfer-action-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "transfer_id": {
++ "type": "string",
++ "format": "uuid"
++ }
++ },
++ "required": [
++ "transfer_id"
++ ]
++ }
++ },
++ "share.access-request-create": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/access-request-create.v1.json",
++ "title": "ShareAccessRequestCreate",
++ "description": "share.access-request-create@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {},
++ "required": []
++ }
++ },
++ "share.list-result": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/share/list-result.v1.json",
++ "title": "ShareListResult",
++ "description": "share.list-result@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "items": {
++ "type": "array",
++ "items": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "resource-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "shared_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "transfer": {
++ "$ref": "transfer.v1.json"
++ }
++ },
++ "required": [
++ "ref",
++ "owner_subject",
++ "audience",
++ "role",
++ "shared_at"
++ ]
++ }
++ },
++ "next_cursor": {
++ "type": [
++ "string",
++ "null"
++ ]
++ }
++ },
++ "required": [
++ "items",
++ "next_cursor"
++ ]
++ }
++ },
++ "share.granted": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.granted.v1.json",
++ "title": "ShareGrantedPayload",
++ "description": "share.granted@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "reason": {
++ "enum": [
++ "member_added",
++ "member_removed",
++ "member_expired",
++ "audience_changed",
++ "transfer_cancelled",
++ "transfer_expired",
++ "ownership_changed"
++ ]
++ },
++ "transfer_id": {
++ "type": "string",
++ "format": "uuid"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at"
++ ]
++ }
++ },
++ "share.revoked": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.revoked.v1.json",
++ "title": "ShareRevokedPayload",
++ "description": "share.revoked@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "role": {
++ "enum": [
++ "viewer",
++ "editor"
++ ]
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "reason": {
++ "enum": [
++ "member_added",
++ "member_removed",
++ "member_expired",
++ "audience_changed",
++ "transfer_cancelled",
++ "transfer_expired",
++ "ownership_changed"
++ ]
++ },
++ "transfer_id": {
++ "type": "string",
++ "format": "uuid"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at"
++ ]
++ }
++ },
++ "share.transfer.requested": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.transfer.requested.v1.json",
++ "title": "ShareTransferRequestedPayload",
++ "description": "share.transfer.requested@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "transfer": {
++ "$ref": "../../share/transfer.v1.json"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at",
++ "transfer"
++ ]
++ }
++ },
++ "share.transfer.accepted": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.transfer.accepted.v1.json",
++ "title": "ShareTransferAcceptedPayload",
++ "description": "share.transfer.accepted@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "transfer": {
++ "$ref": "../../share/transfer.v1.json"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at",
++ "transfer"
++ ]
++ }
++ },
++ "share.transfer.declined": {
++ "version": "1.0.0",
++ "owner": "network",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/share.transfer.declined.v1.json",
++ "title": "ShareTransferDeclinedPayload",
++ "description": "share.transfer.declined@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "ref": {
++ "$ref": "../../share/resource-ref.v1.json"
++ },
++ "actor": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "owner_subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "audience": {
++ "enum": [
++ "public",
++ "link",
++ "people",
++ "private"
++ ]
++ },
++ "subject": {
++ "$ref": "../../identity/subject-ref.v1.json"
++ },
++ "occurred_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "transfer": {
++ "$ref": "../../share/transfer.v1.json"
++ }
++ },
++ "required": [
++ "ref",
++ "actor",
++ "owner_subject",
++ "audience",
++ "subject",
++ "occurred_at",
++ "transfer"
++ ]
++ }
}
}
}
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex ca643177..5ab21728 100644
---- a/generated/openapi/actor.json
++++ b/generated/openapi/actor.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Actor API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex 25118108..93acbd22 100644
---- a/generated/openapi/ai.json
++++ b/generated/openapi/ai.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.AI API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bench.json b/generated/openapi/bench.json
iindex 1463d2d6..d6c8765f 100644
---- a/generated/openapi/bench.json
++++ b/generated/openapi/bench.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bench API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/billing.json b/generated/openapi/billing.json
iindex 65d275e3..8c8c9b7a 100644
---- a/generated/openapi/billing.json
++++ b/generated/openapi/billing.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Billing API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex 150b48ce..1a751a6e 100644
---- a/generated/openapi/blog.json
++++ b/generated/openapi/blog.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Blog API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bot.json b/generated/openapi/bot.json
iindex 0e29eb3a..2e1e418a 100644
---- a/generated/openapi/bot.json
++++ b/generated/openapi/bot.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bot API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/chat.json b/generated/openapi/chat.json
iindex 17b84958..9eebd521 100644
---- a/generated/openapi/chat.json
++++ b/generated/openapi/chat.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Chat API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/codes.json b/generated/openapi/codes.json
iindex 8741cec1..e6d0f300 100644
---- a/generated/openapi/codes.json
++++ b/generated/openapi/codes.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Codes API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/community.json b/generated/openapi/community.json
iindex 122becb2..e5ae3568 100644
---- a/generated/openapi/community.json
++++ b/generated/openapi/community.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Community API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/coupons.json b/generated/openapi/coupons.json
iindex 837fc45f..72dc69c6 100644
---- a/generated/openapi/coupons.json
++++ b/generated/openapi/coupons.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Coupons API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/deals.json b/generated/openapi/deals.json
iindex 27412e3f..978908d9 100644
---- a/generated/openapi/deals.json
++++ b/generated/openapi/deals.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Deals API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/domains.json b/generated/openapi/domains.json
iindex acb985c2..e2914a95 100644
---- a/generated/openapi/domains.json
++++ b/generated/openapi/domains.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Domains API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/events.json b/generated/openapi/events.json
iindex 2a90e70e..6f32ee7d 100644
---- a/generated/openapi/events.json
++++ b/generated/openapi/events.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Events API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/food.json b/generated/openapi/food.json
iindex e531eb50..1b0abb00 100644
---- a/generated/openapi/food.json
++++ b/generated/openapi/food.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Food API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/games.json b/generated/openapi/games.json
iindex 5b49ce4b..fa04faaf 100644
---- a/generated/openapi/games.json
++++ b/generated/openapi/games.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Games API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/host.json b/generated/openapi/host.json
iindex 21a8d7dc..d785c6b7 100644
---- a/generated/openapi/host.json
++++ b/generated/openapi/host.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Host API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex 71f817f8..3dcb78d6 100644
---- a/generated/openapi/inventory.json
++++ b/generated/openapi/inventory.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Inventory API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/live.json b/generated/openapi/live.json
iindex 62ac85dd..9abe27a0 100644
---- a/generated/openapi/live.json
++++ b/generated/openapi/live.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Live API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media-hub.json b/generated/openapi/media-hub.json
iindex 498856c3..bbb11626 100644
---- a/generated/openapi/media-hub.json
++++ b/generated/openapi/media-hub.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.MediaHub API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media.json b/generated/openapi/media.json
iindex 0132abb7..cdee7c82 100644
---- a/generated/openapi/media.json
++++ b/generated/openapi/media.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Media API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex 1f869a3f..01fd373f 100644
---- a/generated/openapi/network.json
++++ b/generated/openapi/network.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Network API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/news.json b/generated/openapi/news.json
iindex 5acbfc56..323910de 100644
---- a/generated/openapi/news.json
++++ b/generated/openapi/news.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.News API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/openre.json b/generated/openapi/openre.json
iindex d5c5567e..7f256f37 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRestream API",
-- "version": "0.290.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/play.json b/generated/openapi/play.json
iindex 1bb8e391..a845a5b2 100644
---- a/generated/openapi/play.json
++++ b/generated/openapi/play.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Play API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/quest.json b/generated/openapi/quest.json
iindex cb99b901..afc44be5 100644
---- a/generated/openapi/quest.json
++++ b/generated/openapi/quest.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Quest API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/report.json b/generated/openapi/report.json
iindex 446a93a0..61b4d96d 100644
---- a/generated/openapi/report.json
++++ b/generated/openapi/report.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Report API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/reviews.json b/generated/openapi/reviews.json
iindex bd69029a..26c15490 100644
---- a/generated/openapi/reviews.json
++++ b/generated/openapi/reviews.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Reviews API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/run.json b/generated/openapi/run.json
iindex 4ae416bf..16b76b0a 100644
---- a/generated/openapi/run.json
++++ b/generated/openapi/run.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Run API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/search.json b/generated/openapi/search.json
iindex 08cfc936..40dae0d1 100644
---- a/generated/openapi/search.json
++++ b/generated/openapi/search.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Search API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/services.json b/generated/openapi/services.json
iindex 3d0b5ec1..90232d05 100644
---- a/generated/openapi/services.json
++++ b/generated/openapi/services.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Services API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/sources.json b/generated/openapi/sources.json
iindex 26a595d8..521d2133 100644
---- a/generated/openapi/sources.json
++++ b/generated/openapi/sources.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Sources API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/space.json b/generated/openapi/space.json
iindex 7b409591..ebf8baac 100644
---- a/generated/openapi/space.json
++++ b/generated/openapi/space.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Space API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tips.json b/generated/openapi/tips.json
iindex 7d6b0b51..9900aa06 100644
---- a/generated/openapi/tips.json
++++ b/generated/openapi/tips.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tips API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/today.json b/generated/openapi/today.json
iindex aae5d6c7..1c49a8c5 100644
---- a/generated/openapi/today.json
++++ b/generated/openapi/today.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Today API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tools.json b/generated/openapi/tools.json
iindex bf9d3174..8664e725 100644
---- a/generated/openapi/tools.json
++++ b/generated/openapi/tools.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tools API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/trade.json b/generated/openapi/trade.json
iindex af9b98c1..217d91a0 100644
---- a/generated/openapi/trade.json
++++ b/generated/openapi/trade.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Trade API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vip.json b/generated/openapi/vip.json
iindex ccd0c012..b052478d 100644
---- a/generated/openapi/vip.json
++++ b/generated/openapi/vip.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.VIP API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vision.json b/generated/openapi/vision.json
iindex 7c0e21b5..b2ad7fdb 100644
---- a/generated/openapi/vision.json
++++ b/generated/openapi/vision.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Vision API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/watch.json b/generated/openapi/watch.json
iindex 9a424e71..f327c94c 100644
---- a/generated/openapi/watch.json
++++ b/generated/openapi/watch.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Watch API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/wiki.json b/generated/openapi/wiki.json
iindex 7b76b754..cf2d212f 100644
---- a/generated/openapi/wiki.json
++++ b/generated/openapi/wiki.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Wiki API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/work.json b/generated/openapi/work.json
iindex c754fc6d..e9f39d0c 100644
---- a/generated/openapi/work.json
++++ b/generated/openapi/work.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Work API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/zone.json b/generated/openapi/zone.json
iindex 2c7316f5..0d7c0c1d 100644
---- a/generated/openapi/zone.json
++++ b/generated/openapi/zone.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Zone API",
-- "version": "0.290.0",
-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.290.0): each operation lists the capabilities it performs; a token for 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.291.0",
++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.291.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex 053eaacd..059c026f 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -291650,3 +291650,300 @@ export interface BillingCreditSandboxGrantResult {
*/
balance_nano_usd: string;
}
++
++/** [email protected] (owner: network) */
++/**
++ * share.resource-ref@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface ShareResourceRef {
++ service: string;
++ kind: string;
++ id: string;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.member@1: a member with their Network identity fields. username, display_name and avatar_url are null when Network does not know the subject (or reports it banned or deleted).
++ */
++export interface ShareMember {
++ subject: SubjectRef;
++ username: string | null;
++ display_name: string | null;
++ avatar_url: string | null;
++ role: "viewer" | "editor";
++ expires_at?: string;
++ added_by: SubjectRef;
++ added_at: string;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.member-input@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export type ShareMemberInput = {
++ name?: string;
++ subject?: SubjectRef;
++ role: "viewer" | "editor";
++ expires_at?: string;
++} & {
++ [k: string]: unknown | undefined;
++};
++
++/** [email protected] (owner: network) */
++/**
++ * share.transfer@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface ShareTransfer {
++ id: string;
++ from: SubjectRef;
++ to: SubjectRef;
++ keep_access: boolean;
++ requested_at: string;
++ expires_at: string;
++ state: "pending" | "accepted" | "declined" | "cancelled" | "expired";
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.access-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface ShareAccessRequest {
++ id: string;
++ subject: SubjectRef;
++ requested_at: string;
++ state: "pending" | "granted" | "dismissed";
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share@1: the uniform GET/PUT body. People, not bare subjects; ids only, never a resource title or content except the service's own describe() (title and link). Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface Share {
++ ref: ShareResourceRef;
++ owner_subject: SubjectRef;
++ owner: SharePerson;
++ audience: "public" | "link" | "people" | "private";
++ /**
++ * @maxItems 100
++ */
++ members: ShareMember[];
++ transfer?: ShareTransferView;
++ you: ShareYou;
++ requests: ShareAccessRequestView[];
++ title: string | null;
++ link: string | null;
++ /**
++ * @minItems 1
++ */
++ roles: ["viewer" | "editor", ...("viewer" | "editor")[]];
++ /**
++ * @minItems 1
++ */
++ audiences: ["public" | "link" | "people" | "private", ...("public" | "link" | "people" | "private")[]];
++ transferable: boolean;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.person@1: a person in a sharing answer, from Network's identity projection. username, display_name and avatar_url are null when Network does not know the subject (or reports it banned or deleted).
++ */
++export interface SharePerson {
++ subject: SubjectRef;
++ username: string | null;
++ display_name: string | null;
++ avatar_url: string | null;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.you@1: who the caller is on this resource, as the sheet needs it. Owner or trusted staff; never a client-supplied value.
++ */
++export interface ShareYou {
++ subject: SubjectRef;
++ role: "owner" | "staff";
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.access-request-view@1: a pending access request in the GET body, with the person who asked. Pending only; dismissed and granted requests are not shown.
++ */
++export interface ShareAccessRequestView {
++ id: string;
++ subject: SubjectRef;
++ username: string | null;
++ display_name: string | null;
++ avatar_url: string | null;
++ requested_at: string;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.transfer-view@1: the pending transfer in the GET body, with its recipient as a person. The transfer id is what the sheet sends back.
++ */
++export interface ShareTransferView {
++ id: string;
++ from: SubjectRef;
++ to: SharePerson;
++ keep_access: boolean;
++ requested_at: string;
++ expires_at: string;
++ state: "pending" | "accepted" | "declined" | "cancelled" | "expired";
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.people-lookup@1: the answer to GET /api/v1/share/people?name=exact. person is null when nobody holds that exact name, for banned or deleted accounts, and for non-user subjects.
++ */
++export interface SharePeopleLookup {
++ person: SharePerson | null;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.update-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface ShareUpdateRequest {
++ audience?: "public" | "link" | "people" | "private";
++ /**
++ * @maxItems 100
++ */
++ members?: ShareMemberInput[];
++ notify?: boolean;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.transfer-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface ShareTransferRequest {
++ to:
++ | string
++ | SubjectRef
++ | {
++ name: string;
++ }
++ | {
++ subject: SubjectRef;
++ };
++ keep_access?: boolean;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.transfer-action-request@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface ShareTransferActionRequest {
++ transfer_id: string;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.access-request-create@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface ShareAccessRequestCreate {}
++
++/** [email protected] (owner: network) */
++/**
++ * share.list-result@1: network-wide sharing. Ids only; no resource title or content. Members apply to people audience; pending recipients may preview for seven days.
++ */
++export interface ShareListResult {
++ items: {
++ ref: ShareResourceRef;
++ owner_subject: SubjectRef;
++ audience: "public" | "link" | "people" | "private";
++ role: "viewer" | "editor";
++ shared_at: string;
++ transfer?: ShareTransfer;
++ }[];
++ next_cursor: string | null;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.granted@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.
++ */
++export interface ShareGrantedPayload {
++ ref: ShareResourceRef;
++ actor: SubjectRef;
++ owner_subject: SubjectRef;
++ audience: "public" | "link" | "people" | "private";
++ subject: SubjectRef;
++ occurred_at: string;
++ role?: "viewer" | "editor";
++ expires_at?: string;
++ reason?:
++ | "member_added"
++ | "member_removed"
++ | "member_expired"
++ | "audience_changed"
++ | "transfer_cancelled"
++ | "transfer_expired"
++ | "ownership_changed";
++ transfer_id?: string;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.revoked@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.
++ */
++export interface ShareRevokedPayload {
++ ref: ShareResourceRef;
++ actor: SubjectRef;
++ owner_subject: SubjectRef;
++ audience: "public" | "link" | "people" | "private";
++ subject: SubjectRef;
++ occurred_at: string;
++ role?: "viewer" | "editor";
++ expires_at?: string;
++ reason?:
++ | "member_added"
++ | "member_removed"
++ | "member_expired"
++ | "audience_changed"
++ | "transfer_cancelled"
++ | "transfer_expired"
++ | "ownership_changed";
++ transfer_id?: string;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.transfer.requested@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.
++ */
++export interface ShareTransferRequestedPayload {
++ ref: ShareResourceRef;
++ actor: SubjectRef;
++ owner_subject: SubjectRef;
++ audience: "public" | "link" | "people" | "private";
++ subject: SubjectRef;
++ occurred_at: string;
++ transfer: ShareTransfer;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.transfer.accepted@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.
++ */
++export interface ShareTransferAcceptedPayload {
++ ref: ShareResourceRef;
++ actor: SubjectRef;
++ owner_subject: SubjectRef;
++ audience: "public" | "link" | "people" | "private";
++ subject: SubjectRef;
++ occurred_at: string;
++ transfer: ShareTransfer;
++}
++
++/** [email protected] (owner: network) */
++/**
++ * share.transfer.declined@1: ids and access metadata only, for every audience. Produced by adopting services; Network owns the shared model.
++ */
++export interface ShareTransferDeclinedPayload {
++ ref: ShareResourceRef;
++ actor: SubjectRef;
++ owner_subject: SubjectRef;
++ audience: "public" | "link" | "people" | "private";
++ subject: SubjectRef;
++ occurred_at: string;
++ transfer: ShareTransfer;
++}
ddiff --git a/manifests/services/network.json b/manifests/services/network.json
iindex b6c8d20a..9d452f21 100644
---- a/manifests/services/network.json
++++ b/manifests/services/network.json
@@@ -110,7 +110,12 @@
"network.machine.offline",
"network.machine.paired",
"network.machine.roles_changed",
-- "network.machine.revoked"
++ "network.machine.revoked",
++ "share.granted",
++ "share.revoked",
++ "share.transfer.requested",
++ "share.transfer.accepted",
++ "share.transfer.declined"
],
"eventsConsumed": [
"billing.staff.action",
ddiff --git a/package.json b/package.json
iindex bc1e8c68..93183e8e 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.290.0",
++ "version": "0.291.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",