openvibers/openvibe.contracts Commits
v0.57.2: ADR-029 account merge, ADR-030 follow graph, ADR-031 S3-compatible surface (WS-B 5, WS-E 4, WS-N 8 decisions)
Changes
@@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) thfrom `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,the notes were in the tag and commit messages (`git tag -n1`).++## 0.57.2 — 2026-09-26++++**Three decisions** (documentation only): ADR-029 account merge (WS-B task 5), ADR-030 follow graph (WS-E task 4), ADR-031 S3-compatible surface for Media (WS-N task 8). Each is accepted with its acceptance tests; the implementations follow in Network, Live and Media.++## 0.57.1 — 2026-09-26**ADR-024 amendment 1** (roadmap WS-E task 2): the theme preference stays Network's own data (not a user module); community themes are reviewed before they are public; theme names and values are allow-listed (shared tokens; colours, numbers, lengths and shadows only); themes import and export as `openvibe-theme@1` files. Documentation only.nnew file mode 100644@@@ -0,0 +1,53 @@++# ADR-029: Merging two accounts into one++++**Status:** Accepted 2026-09-26 (roadmap WS-B task 5). Implementation follows in OpenVibe.Network.++++## Context and current evidence++++- People end up with two accounts: one from Google, another from Discord or an old Live sign-up. Today they can link a provider to an account, but they cannot fold a second account into the first.++- Subjects (`usr_…`) are the network-wide identity (ADR-001). Services key their own rows by subject, some still alongside integer ids.++- ADR-001 forbids repointing `identity_legacy_map`: a mapping, once written, stays.++- Network's user-module events already carry `reason: subject_merged` with `merged_into` and `merged_from` (`server/identity/module-events.js`), so consumers have a place for a merge, but nothing performs one.++- Balances are loyalty, never money (ADR-012). The OpenCoins transfer grant is revoked (rule 5): services cannot move coins between people.++++## Decision++++- **Only the person merges, and only two accounts they both control.** Both must be signed in within 10 minutes: the survivor, plus a fresh proof for the account being folded in. Staff can start a merge for account recovery only with `staff.identity.merge`, a written reason and an audit row. They never do it silently.++- **The survivor keeps its subject, username, profile and settings.** The folded-in subject becomes an **alias**: a new `subject_aliases (alias_id → subject_id, merged_at, merged_by)` row. `identity_legacy_map` is not repointed: resolving an old legacy id returns the folded-in subject, and alias resolution then returns the survivor. `/internal/identity/resolve` answers the survivor with `merged_from`.++- **Network moves what it owns, in one transaction:**++ - linked providers, sessions and devices (both sets stay valid until they expire);++ - OAuth grants and developer projects (still owned, now by the survivor);++ - OpenCoins: one ledger entry per side, `reason: account_merge`, idempotent by merge id. This is a Network-internal operation, not the revoked transfer grant.++ - user modules: per namespace, the survivor's record wins field by field. The folded-in values survive only where the survivor has none, and each changed record emits `network.module.updated` with `reason: subject_merged`.++- **Everything else follows one event.** Network emits `network.subject.merged { from, into, merged_at }` (visibility internal). Each owning service repoints its own rows from `from` to `into` in its own transaction and keeps no copy under `from`:++ - Live: follows, channel points and streams;++ - Chat: messages, DMs and room members;++ - Community: posts;++ - Media: owner_subject;++ - Games: players;++ - Billing: accounts.++ A service that cannot merge a row (a unique conflict such as two follows of the same channel) keeps the survivor's row and drops the other, as a counted, logged outcome.++- **A merge is not undone automatically.** The merge record keeps the folded-in account's pre-merge state for 30 days so staff can split it by hand if a merge was a mistake. After that the record is reduced to the alias.++++## Alternatives considered++++- **Delete the second account and let the person re-link:** rejected, because it loses history, follows, balances and content.++- **Rewrite every subject reference network-wide in one distributed transaction:** rejected, because no service owns another's rows (principle 4).++- **Repoint `identity_legacy_map`:** rejected by ADR-001; aliases give the same answer without rewriting history.++++## Migration consequences++++New table `subject_aliases` and a merge record in Network. Contracts gain `network.subject.merged@1` and the capability `staff.identity.merge`. Every service that stores subjects consumes the event; until one does, its rows stay under the old subject, which still resolves (alias), so nothing breaks while consumers land.++++## Rollback++++Stop offering merges. Aliases already written keep resolving. A mistaken merge is split by hand from the 30-day record.++++## Acceptance tests++++- A merge needs both sign-ins and refuses otherwise.++- Resolving either subject, or any old legacy id, answers the survivor.++- Balances sum, with one ledger entry per side, and a retried merge applies once.++- Module conflicts keep the survivor's fields.++- Each consuming service's test repoints its rows on `network.subject.merged` and counts conflicts.++- A staff merge without a reason is refused.nnew file mode 100644@@@ -0,0 +1,43 @@++# ADR-030: Who owns the follow graph++++**Status:** Accepted 2026-09-26 (roadmap WS-E task 4). Migration follows.++++## Context and current evidence++++- Follows live in OpenVibe.Live's `follows (follower_id, streamer_id, email_notify, push_notify, created_at)`, keyed by Live's integer user ids. On 2026-09-26 it held 62 follows: 12 channels, 46 followers.++- OpenVibe.Network sends the go-live notifications and asks Live for a stream's followers each time (`server/notifications/live-followers.js`).++- Other products will want follows too: Community spaces, Games creators, Blog authors. Today each would have to ask Live.++++## Decision++++- **Network owns follows, keyed by subjects:** `follows (follower_subject, target_type, target_id, notify_email, notify_push, created_at)`. `target_type` is `channel` (a Live channel owner's subject) for now, and other kinds as products need them, such as `creator` or `space`.++- **Public API** on Network: follow, unfollow, is-following, and paged followers and following. Counts are public; lists are visible to the account itself and to the target's owner. A service token with `network.follows.read` reads them.++- **Events:** `network.follow.created` and `network.follow.deleted` (visibility subject for the follower; counts go out as `public` summaries). Live, and anyone else, keeps a **projection** it can rebuild.++- **Live keeps its table as that projection** for its own reads (channel pages, sort orders), fed by the events. Its follow and unfollow buttons call Network.++- **Notifications stop asking Live**: Network already holds the followers.++++## Alternatives considered++++- Leave follows in Live and add an API: rejected. It keeps Live as the identity-adjacent authority for a network-wide feature.++- A separate social service: rejected. There is no measured need; Network already owns people and notifications.++++## Migration consequences++++Expand, migrate, contract (ADR-028):++1. Network adds the table and API.++2. A backfill maps Live follows through the identity resolver (subjects for both sides); a follow whose side has no subject is held and reported, never dropped. Take a backup first.++3. A reconciliation compares counts per channel and the pair sets; it must match before Live's writes move.++4. Live's buttons call Network, and the projection follows the events.++5. Live's table stops being written directly after one release with no drift.++++## Rollback++++Until step 5 Live's table is complete: switch the buttons back. After it, rebuild Live's table from Network (the projection is derived).++++## Acceptance tests++++- The backfill preserves all 62 current follows, or reports each one held.++- Counts per channel match after the reconciliation.++- Following and unfollowing are idempotent.++- The events are validated by their contracts.++- Go-live notifications reach the same people as before the move.nnew file mode 100644@@@ -0,0 +1,46 @@++# ADR-031: An S3-compatible surface for OpenVibe.Media++++**Status:** Accepted 2026-09-26 (roadmap WS-N task 8). Implementation follows in OpenVibe.Media.++++## Context and current evidence++++- Developers store files through Media's object API: `med_` ids, per-project tenants with byte quotas, uploads verified at `complete`, and signed URLs for sandbox reads (ADR-006, ADR-014).++- Many tools already speak S3: the AWS SDKs, rclone, static-site deployers and backup scripts. Asking developers to learn a second storage API is friction.++++## Decision++++- **A subset of S3, not all of it**, served at `https://s3.openvibe.media` (path style: `/<bucket>/<key>`).++- **A bucket is a project namespace.** The developer's tenant (`app.<project>`) has one bucket per environment: `<project_key>-sandbox` and `<project_key>` (production). Keys are the object's path under that namespace.++- **Supported operations:**++ - objects: `PutObject`, `GetObject` (with ranges), `HeadObject`, `DeleteObject`;++ - listing: `ListObjectsV2` (prefix, delimiter, continuation) and `ListBuckets` (the project's own);++ - presigned `GET` and `PUT` (SigV4 query), valid for at most 7 days.++ - Everything else answers `NotImplemented`, including ACLs, policies, versioning and multipart uploads. Multipart is a candidate for a second phase: Media's own chunked uploads cover large files today.++- **Credentials are per project and scoped:**++ - Codes issues access keys (`ovk_…` id plus secret) bound to one project and environment, with read and/or write.++ - The secret is shown once and stored encrypted, because SigV4 needs it to verify.++ - Every request is authorised as that project's app would be, so the same quota, capability checks (`media.object.*`) and sandbox rules apply.++- **Same objects, two doors:** an object written over S3 is an ordinary Media object (`med_` id, owner app, lifecycle, derivatives), and the reverse. `PutObject` completes the object in the same request (hash and quota checked); a quota overrun answers `QuotaExceeded` (403).++- **Conformance** is proven with the AWS SDK for JavaScript v3 against a local Media, for every supported operation, including a presigned round trip and the `NotImplemented` answers.++++## Alternatives considered++++- **Full S3** (MinIO in front of Media): rejected. It gives two sources of truth for objects, and no quota or capability integration.++- **No S3 at all:** rejected. It is the most requested integration for storage.++- **Buckets as free-form names:** rejected. Namespaces already are the unit of ownership, quota and grants.++++## Migration consequences++++A new vhost, a signature verifier and access-key issuance in Codes (contract `media.access-key@1`, capability `media.object.s3`). No change to existing objects.++++## Rollback++++Turn the vhost off and revoke the keys. Objects written through it stay ordinary Media objects.++++## Acceptance tests++++- The AWS SDK v3 conformance suite passes against a local Media.++- A key cannot touch another project, and sandbox keys cannot touch production.++- A quota overrun is refused.++- A presigned URL expires on time.++- An object written over S3 reads through the object API with the same bytes and hash.@@@ -32,3 +32,6 @@ Platform-wide decisions from the OpenVibe development roadmap (section 10). Each| [ADR-026](ADR-026-event-redaction.md) | Producer redaction of its own events (`payload.redacts`) and event payload contracts | Accepted and implemented 2026-09-23 (OpenVibe.Events, Chat) || [ADR-027](ADR-027-tools-platform-api.md) | Tools platform API: descriptors, one run API, caller tiers, probes, abuse log, legacy sunset | Accepted 2026-09-23; contracts v0.33.0, routes planned || [ADR-028](ADR-028-expand-migrate-contract.md) | Expand, migrate, contract: schema changes that survive a rollback (7-day window); destructive-statement check and rollback-with-newer-writes test | Accepted 2026-09-25; enforced in Live |++| [ADR-029](ADR-029-account-merge.md) | Merging two accounts: survivor keeps the subject, the other becomes an alias, services follow `network.subject.merged` | Accepted 2026-09-26; implementation pending |++| [ADR-030](ADR-030-follow-graph.md) | Follow graph: Network owns follows by subject, Live keeps a projection; expand/migrate/contract with reconciliation | Accepted 2026-09-26; migration pending |++| [ADR-031](ADR-031-s3-compatible-surface.md) | S3-compatible subset for Media: bucket = project namespace, object CRUD + ListObjectsV2 + presign, per-project keys | Accepted 2026-09-26; implementation pending |@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.AI API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Billing API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Blog API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Chat API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Codes API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Community API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Coupons API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Deals API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Events API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Games API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Host API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Live API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Media API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Network API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.News API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenRe.Stream API",-- "version": "0.57.1",-- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Reviews API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Search API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Sources API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tips API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tools API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Trade API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.VIP API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Wiki API",-- "version": "0.57.1",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for 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"@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.57.1",++ "version": "0.57.2","description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.","main": "index.js","types": "generated/typescript/index.d.ts",
@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
the notes were in the tag and commit messages (`git tag -n1`).
+## 0.57.2 — 2026-09-26
+
+**Three decisions** (documentation only): ADR-029 account merge (WS-B task 5), ADR-030 follow graph (WS-E task 4), ADR-031 S3-compatible surface for Media (WS-N task 8). Each is accepted with its acceptance tests; the implementations follow in Network, Live and Media.
+
## 0.57.1 — 2026-09-26
## 0.57.1 — 2026-09-26
**ADR-024 amendment 1** (roadmap WS-E task 2): the theme preference stays Network's own data (not a user module); community themes are reviewed before they are public; theme names and values are allow-listed (shared tokens; colours, numbers, lengths and shadows only); themes import and export as `openvibe-theme@1` files. Documentation only.
**ADR-024 amendment 1** (roadmap WS-E task 2): the theme preference stays Network's own data (not a user module); community themes are reviewed before they are public; theme names and values are allow-listed (shared tokens; colours, numbers, lengths and shadows only); themes import and export as `openvibe-theme@1` files. Documentation only.
new file mode 100644
new file mode 100644
@@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
+# ADR-029: Merging two accounts into one
+
+**Status:** Accepted 2026-09-26 (roadmap WS-B task 5). Implementation follows in OpenVibe.Network.
+
+## Context and current evidence
+
+- People end up with two accounts: one from Google, another from Discord or an old Live sign-up. Today they can link a provider to an account, but they cannot fold a second account into the first.
+- Subjects (`usr_…`) are the network-wide identity (ADR-001). Services key their own rows by subject, some still alongside integer ids.
+- ADR-001 forbids repointing `identity_legacy_map`: a mapping, once written, stays.
+- Network's user-module events already carry `reason: subject_merged` with `merged_into` and `merged_from` (`server/identity/module-events.js`), so consumers have a place for a merge, but nothing performs one.
+- Balances are loyalty, never money (ADR-012). The OpenCoins transfer grant is revoked (rule 5): services cannot move coins between people.
+
+## Decision
+
+- **Only the person merges, and only two accounts they both control.** Both must be signed in within 10 minutes: the survivor, plus a fresh proof for the account being folded in. Staff can start a merge for account recovery only with `staff.identity.merge`, a written reason and an audit row. They never do it silently.
+- **The survivor keeps its subject, username, profile and settings.** The folded-in subject becomes an **alias**: a new `subject_aliases (alias_id → subject_id, merged_at, merged_by)` row. `identity_legacy_map` is not repointed: resolving an old legacy id returns the folded-in subject, and alias resolution then returns the survivor. `/internal/identity/resolve` answers the survivor with `merged_from`.
+- **Network moves what it owns, in one transaction:**
+ - linked providers, sessions and devices (both sets stay valid until they expire);
+ - OAuth grants and developer projects (still owned, now by the survivor);
+ - OpenCoins: one ledger entry per side, `reason: account_merge`, idempotent by merge id. This is a Network-internal operation, not the revoked transfer grant.
+ - user modules: per namespace, the survivor's record wins field by field. The folded-in values survive only where the survivor has none, and each changed record emits `network.module.updated` with `reason: subject_merged`.
+- **Everything else follows one event.** Network emits `network.subject.merged { from, into, merged_at }` (visibility internal). Each owning service repoints its own rows from `from` to `into` in its own transaction and keeps no copy under `from`:
+ - Live: follows, channel points and streams;
+ - Chat: messages, DMs and room members;
+ - Community: posts;
+ - Media: owner_subject;
+ - Games: players;
+ - Billing: accounts.
+ A service that cannot merge a row (a unique conflict such as two follows of the same channel) keeps the survivor's row and drops the other, as a counted, logged outcome.
+- **A merge is not undone automatically.** The merge record keeps the folded-in account's pre-merge state for 30 days so staff can split it by hand if a merge was a mistake. After that the record is reduced to the alias.
+
+## Alternatives considered
+
+- **Delete the second account and let the person re-link:** rejected, because it loses history, follows, balances and content.
+- **Rewrite every subject reference network-wide in one distributed transaction:** rejected, because no service owns another's rows (principle 4).
+- **Repoint `identity_legacy_map`:** rejected by ADR-001; aliases give the same answer without rewriting history.
+
+## Migration consequences
+
+New table `subject_aliases` and a merge record in Network. Contracts gain `network.subject.merged@1` and the capability `staff.identity.merge`. Every service that stores subjects consumes the event; until one does, its rows stay under the old subject, which still resolves (alias), so nothing breaks while consumers land.
+
+## Rollback
+
+Stop offering merges. Aliases already written keep resolving. A mistaken merge is split by hand from the 30-day record.
+
+## Acceptance tests
+
+- A merge needs both sign-ins and refuses otherwise.
+- Resolving either subject, or any old legacy id, answers the survivor.
+- Balances sum, with one ledger entry per side, and a retried merge applies once.
+- Module conflicts keep the survivor's fields.
+- Each consuming service's test repoints its rows on `network.subject.merged` and counts conflicts.
+- A staff merge without a reason is refused.
new file mode 100644
new file mode 100644
@@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
+# ADR-030: Who owns the follow graph
+
+**Status:** Accepted 2026-09-26 (roadmap WS-E task 4). Migration follows.
+
+## Context and current evidence
+
+- Follows live in OpenVibe.Live's `follows (follower_id, streamer_id, email_notify, push_notify, created_at)`, keyed by Live's integer user ids. On 2026-09-26 it held 62 follows: 12 channels, 46 followers.
+- OpenVibe.Network sends the go-live notifications and asks Live for a stream's followers each time (`server/notifications/live-followers.js`).
+- Other products will want follows too: Community spaces, Games creators, Blog authors. Today each would have to ask Live.
+
+## Decision
+
+- **Network owns follows, keyed by subjects:** `follows (follower_subject, target_type, target_id, notify_email, notify_push, created_at)`. `target_type` is `channel` (a Live channel owner's subject) for now, and other kinds as products need them, such as `creator` or `space`.
+- **Public API** on Network: follow, unfollow, is-following, and paged followers and following. Counts are public; lists are visible to the account itself and to the target's owner. A service token with `network.follows.read` reads them.
+- **Events:** `network.follow.created` and `network.follow.deleted` (visibility subject for the follower; counts go out as `public` summaries). Live, and anyone else, keeps a **projection** it can rebuild.
+- **Live keeps its table as that projection** for its own reads (channel pages, sort orders), fed by the events. Its follow and unfollow buttons call Network.
+- **Notifications stop asking Live**: Network already holds the followers.
+
+## Alternatives considered
+
+- Leave follows in Live and add an API: rejected. It keeps Live as the identity-adjacent authority for a network-wide feature.
+- A separate social service: rejected. There is no measured need; Network already owns people and notifications.
+
+## Migration consequences
+
+Expand, migrate, contract (ADR-028):
+1. Network adds the table and API.
+2. A backfill maps Live follows through the identity resolver (subjects for both sides); a follow whose side has no subject is held and reported, never dropped. Take a backup first.
+3. A reconciliation compares counts per channel and the pair sets; it must match before Live's writes move.
+4. Live's buttons call Network, and the projection follows the events.
+5. Live's table stops being written directly after one release with no drift.
+
+## Rollback
+
+Until step 5 Live's table is complete: switch the buttons back. After it, rebuild Live's table from Network (the projection is derived).
+
+## Acceptance tests
+
+- The backfill preserves all 62 current follows, or reports each one held.
+- Counts per channel match after the reconciliation.
+- Following and unfollowing are idempotent.
+- The events are validated by their contracts.
+- Go-live notifications reach the same people as before the move.
new file mode 100644
new file mode 100644
@@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
+# ADR-031: An S3-compatible surface for OpenVibe.Media
+
+**Status:** Accepted 2026-09-26 (roadmap WS-N task 8). Implementation follows in OpenVibe.Media.
+
+## Context and current evidence
+
+- Developers store files through Media's object API: `med_` ids, per-project tenants with byte quotas, uploads verified at `complete`, and signed URLs for sandbox reads (ADR-006, ADR-014).
+- Many tools already speak S3: the AWS SDKs, rclone, static-site deployers and backup scripts. Asking developers to learn a second storage API is friction.
+
+## Decision
+
+- **A subset of S3, not all of it**, served at `https://s3.openvibe.media` (path style: `/<bucket>/<key>`).
+- **A bucket is a project namespace.** The developer's tenant (`app.<project>`) has one bucket per environment: `<project_key>-sandbox` and `<project_key>` (production). Keys are the object's path under that namespace.
+- **Supported operations:**
+ - objects: `PutObject`, `GetObject` (with ranges), `HeadObject`, `DeleteObject`;
+ - listing: `ListObjectsV2` (prefix, delimiter, continuation) and `ListBuckets` (the project's own);
+ - presigned `GET` and `PUT` (SigV4 query), valid for at most 7 days.
+ - Everything else answers `NotImplemented`, including ACLs, policies, versioning and multipart uploads. Multipart is a candidate for a second phase: Media's own chunked uploads cover large files today.
+- **Credentials are per project and scoped:**
+ - Codes issues access keys (`ovk_…` id plus secret) bound to one project and environment, with read and/or write.
+ - The secret is shown once and stored encrypted, because SigV4 needs it to verify.
+ - Every request is authorised as that project's app would be, so the same quota, capability checks (`media.object.*`) and sandbox rules apply.
+- **Same objects, two doors:** an object written over S3 is an ordinary Media object (`med_` id, owner app, lifecycle, derivatives), and the reverse. `PutObject` completes the object in the same request (hash and quota checked); a quota overrun answers `QuotaExceeded` (403).
+- **Conformance** is proven with the AWS SDK for JavaScript v3 against a local Media, for every supported operation, including a presigned round trip and the `NotImplemented` answers.
+
+## Alternatives considered
+
+- **Full S3** (MinIO in front of Media): rejected. It gives two sources of truth for objects, and no quota or capability integration.
+- **No S3 at all:** rejected. It is the most requested integration for storage.
+- **Buckets as free-form names:** rejected. Namespaces already are the unit of ownership, quota and grants.
+
+## Migration consequences
+
+A new vhost, a signature verifier and access-key issuance in Codes (contract `media.access-key@1`, capability `media.object.s3`). No change to existing objects.
+
+## Rollback
+
+Turn the vhost off and revoke the keys. Objects written through it stay ordinary Media objects.
+
+## Acceptance tests
+
+- The AWS SDK v3 conformance suite passes against a local Media.
+- A key cannot touch another project, and sandbox keys cannot touch production.
+- A quota overrun is refused.
+- A presigned URL expires on time.
+- An object written over S3 reads through the object API with the same bytes and hash.
@@ -32,3 +32,6 @@ Platform-wide decisions from the OpenVibe development roadmap (section 10). Each
@@ -32,3 +32,6 @@ Platform-wide decisions from the OpenVibe development roadmap (section 10). Each
| [ADR-026](ADR-026-event-redaction.md) | Producer redaction of its own events (`payload.redacts`) and event payload contracts | Accepted and implemented 2026-09-23 (OpenVibe.Events, Chat) |
| [ADR-026](ADR-026-event-redaction.md) | Producer redaction of its own events (`payload.redacts`) and event payload contracts | Accepted and implemented 2026-09-23 (OpenVibe.Events, Chat) |
| [ADR-027](ADR-027-tools-platform-api.md) | Tools platform API: descriptors, one run API, caller tiers, probes, abuse log, legacy sunset | Accepted 2026-09-23; contracts v0.33.0, routes planned |
| [ADR-027](ADR-027-tools-platform-api.md) | Tools platform API: descriptors, one run API, caller tiers, probes, abuse log, legacy sunset | Accepted 2026-09-23; contracts v0.33.0, routes planned |
| [ADR-028](ADR-028-expand-migrate-contract.md) | Expand, migrate, contract: schema changes that survive a rollback (7-day window); destructive-statement check and rollback-with-newer-writes test | Accepted 2026-09-25; enforced in Live |
| [ADR-028](ADR-028-expand-migrate-contract.md) | Expand, migrate, contract: schema changes that survive a rollback (7-day window); destructive-statement check and rollback-with-newer-writes test | Accepted 2026-09-25; enforced in Live |
+| [ADR-029](ADR-029-account-merge.md) | Merging two accounts: survivor keeps the subject, the other becomes an alias, services follow `network.subject.merged` | Accepted 2026-09-26; implementation pending |
+| [ADR-030](ADR-030-follow-graph.md) | Follow graph: Network owns follows by subject, Live keeps a projection; expand/migrate/contract with reconciliation | Accepted 2026-09-26; migration pending |
+| [ADR-031](ADR-031-s3-compatible-surface.md) | S3-compatible subset for Media: bucket = project namespace, object CRUD + ListObjectsV2 + presign, per-project keys | Accepted 2026-09-26; implementation pending |
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.AI API",
"title": "OpenVibe.AI API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Billing API",
"title": "OpenVibe.Billing API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Blog API",
"title": "OpenVibe.Blog API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Chat API",
"title": "OpenVibe.Chat API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Codes API",
"title": "OpenVibe.Codes API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Community API",
"title": "OpenVibe.Community API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Coupons API",
"title": "OpenVibe.Coupons API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Deals API",
"title": "OpenVibe.Deals API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Events API",
"title": "OpenVibe.Events API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Games API",
"title": "OpenVibe.Games API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Host API",
"title": "OpenVibe.Host API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Live API",
"title": "OpenVibe.Live API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Media API",
"title": "OpenVibe.Media API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Network API",
"title": "OpenVibe.Network API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.News API",
"title": "OpenVibe.News API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenRe.Stream API",
"title": "OpenRe.Stream API",
- "version": "0.57.1",
- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Reviews API",
"title": "OpenVibe.Reviews API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Search API",
"title": "OpenVibe.Search API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Sources API",
"title": "OpenVibe.Sources API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tips API",
"title": "OpenVibe.Tips API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tools API",
"title": "OpenVibe.Tools API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Trade API",
"title": "OpenVibe.Trade API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.VIP API",
"title": "OpenVibe.VIP API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Wiki API",
"title": "OpenVibe.Wiki API",
- "version": "0.57.1",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.57.1): each operation lists the capabilities it performs; a token for 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.57.2",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.57.2): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.57.1",
+ "version": "0.57.2",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
"types": "generated/typescript/index.d.ts",