openvibers/openvibe.contracts Commits
Contracts 0.132.0: an Events position is an opaque cursor only (#85)
Changes
@@@ -4,6 +4,26 @@ 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.132.0 — 2026-10-10++++**An Events position is an opaque cursor and nothing else** (ADR-042 decision 7, plan T7). `events.read-result@1` and++`events.read-request@1` drop the numeric positions their own descriptions kept "only until every consumer reads by++cursor". Every consumer does now, checked across the estate: Community's relay (Community #56), the SDK's pull,++iterate, checkpoints and realtime (openvibe-sdk 0.42.0), Shared's bell and release watcher (3.0.1), Examples (#14)++and Chat's e2e test (#64). Services' project archive already read by cursor.++++- **Pages:** `GET /api/v1/events` answers `{ events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? }`.++ `next_after_seq` and `latest_seq` are gone, and `next_cursor`, `latest_cursor` and each item's `cursor` are required++ (Events always sent them). Without `after=`, a page starts at the oldest retained event; `after_seq` is refused.++- **Single event:** `GET /api/v1/events/:event_id` requires `cursor` beside `seq`.++- **Checkpoints:** `PUT` takes `{ topic, cursor, carrier? }` with `cursor` an opaque cursor string; a number is refused.++ `GET`/`PUT` answer `{ consumer, topic, cursor, carrier, updated_at }` with the cursor as stored (null when none is).++- **Realtime:** the SSE id is the cursor, and `Last-Event-ID` resumes only from a cursor.++- **Per-event `seq`:** stays, documented as informational (not a position). Deleting it, with `X-OpenVibe-Seq` and the++ global-order promise, is ADR-042's last step; clients already dedupe by `event_id`.++- **Fixtures:** pages and checkpoints with cursors only, plus three invalid ones (a numeric page, a numeric checkpoint++ answer, a numeric checkpoint request). ADR-042 records what decision 7 became.++## 0.131.0 — 2026-10-10- `openre.resource.read` (owner `openre`, first-party, **active**): OpenRestream's resource index, its stream@@@ -2,7 +2,7 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/events/read-request.v1.json","title": "EventsReadRequest",-- "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor } stores the calling consumer's cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after_seq=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body.",++ "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor, carrier? } stores the calling consumer's opaque cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body. A position is only ever an opaque cursor (ADR-042 decision 7): after_seq is refused (400) and a numeric checkpoint cursor is refused.","anyOf": [{"type": "object",@@@ -18,9 +18,16 @@"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."},"cursor": {-- "type": "integer",-- "minimum": 0,-- "description": "A seq (next_after_seq of the last page handled)."++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "An opaque cursor: a page's next_cursor (or latest_cursor). Never a number, never parsed."++ },++ "carrier": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "description": "The carrier the position is on (ADR-042), recorded with it."}}},@@@ -2,14 +2,14 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/events/read-result.v1.json","title": "EventsReadResult",-- "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor?, event }], next_after_seq, next_cursor?, latest_seq, latest_cursor?, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; the numeric after_seq, next_after_seq and latest_seq remain only until every consumer reads by cursor (plan T7); gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, updated_at } (cursor 0 and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } (id: the cursor once Events sends one, else the seq; a gap message when the cursor is older than retention). An app sees only its project's events in its token's environment plus public first-party events.",++ "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; without after= a page starts at the oldest retained event; gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, cursor, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, carrier, updated_at } (cursor, carrier and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } with the cursor as the SSE id; it resumes from Last-Event-ID (or last_event_id=) when that is a cursor, and a gap message comes first when the cursor is older than retention. A position is only ever an opaque cursor (ADR-042 decision 7): the per-event seq is informational, and nothing accepts it as a position. An app sees only its project's events in its token's environment plus public first-party events.","anyOf": [{"type": "object","required": ["events",-- "next_after_seq",-- "latest_seq"++ "next_cursor",++ "latest_cursor"],"properties": {"events": {@@@ -19,12 +19,14 @@"type": "object","required": ["seq",++ "cursor","event"],"properties": {"seq": {"type": "integer",-- "minimum": 1++ "minimum": 1,++ "description": "Informational: the event's number in the hot store. Not a position."},"event": {"$ref": "event-envelope.v1.json"@@@ -33,19 +35,11 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."++ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."}}}},-- "next_after_seq": {-- "type": "integer",-- "minimum": 0-- },-- "latest_seq": {-- "type": "integer",-- "minimum": 0-- },"gap": {"type": "object","required": [@@@ -65,13 +59,13 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page. Returned beside next_after_seq for one release."++ "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page."},"latest_cursor": {"type": "string","minLength": 1,"maxLength": 200,-- "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=, never needing latest_seq."++ "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=."}}},@@@ -79,12 +73,14 @@"type": "object","required": ["seq",++ "cursor","event"],"properties": {"seq": {"type": "integer",-- "minimum": 1++ "minimum": 1,++ "description": "Informational: the event's number in the hot store. Not a position."},"event": {"$ref": "event-envelope.v1.json"@@@ -93,7 +89,7 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."++ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."}}},@@@ -113,8 +109,13 @@"type": "string"},"cursor": {-- "type": "integer",-- "minimum": 0++ "type": [++ "string",++ "null"++ ],++ "minLength": 1,++ "maxLength": 200,++ "description": "The stored opaque cursor, as it was stored; null when none is."},"updated_at": {"type": [@@@ -122,6 +123,13 @@"null"],"format": "date-time"++ },++ "carrier": {++ "type": [++ "string",++ "null"++ ],++ "description": "The carrier the stored position is on (ADR-042), or null."}}}@@@ -53,6 +53,11 @@ cell-local carrier). Amends ADR-004: its "Kafka/NATS now: rejected" is supersede`next_cursor` (opaque: a hot-store position plus a retention epoch); the SSE `id` becomes the cursor. Consumers'positions live in `consumer_checkpoints` with `epoch` and `carrier` columns. `seq` is still returned for exactly onerelease after the cursor ships; it and `X-OpenVibe-Seq` are then deleted, with the "global order" promise.++ *Positions done 2026-10-10 (Contracts 0.132.0, openvibe-sdk 0.42.0, Shared 3.0.1, Events):* every consumer reads by++ cursor, and nothing accepts a number as a position any more: `after_seq` is a 400, pages carry no `next_after_seq` or++ `latest_seq`, checkpoints store and return the opaque cursor, and a bare-number `Last-Event-ID` is not a position.++ The per-event `seq` (pull items, publish results, SSE data, the delivery body and `X-OpenVibe-Seq`) remains as an++ informational number; deleting it is the last step, and clients already dedupe by `event_id`.8. **Three tiers.** hot = `events` (pruned at `retention.hot`); replay = `events_archive` in the same database (nodelivery rows, compressed payloads, pruned at `retention.replay`); archive = monthly NDJSON objects in objectstorage, restored only by an operator job into `events_archive`. Pulls and scans span hot and replay with onennew file mode 100644@@@ -0,0 +1,4 @@++{++ "topic": "media.vod.*",++ "cursor": 88213++}@@@ -1 +1,5 @@--{ "topic": "media.vod.*", "cursor": 88213 }++{++ "topic": "media.vod.*",++ "cursor": "c1.0.ODgyMTM",++ "carrier": "pg-v1"++}@@@ -1 +1,13 @@--{ "events": [ { "seq": 1, "event": { "event_type": "x" } } ], "next_after_seq": 1, "latest_seq": 1 }++{++ "events": [++ {++ "seq": 1,++ "cursor": "c1.0.MQ",++ "event": {++ "event_type": "x"++ }++ }++ ],++ "next_cursor": "c1.0.MQ",++ "latest_cursor": "c1.0.MQ"++}@@@ -24,8 +24,6 @@"cursor": "c1.e0.1"}],-- "next_after_seq": 88240,-- "latest_seq": 88240,"next_cursor": "c1.e0.next","latest_cursor": ""}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "consumer": "live",++ "topic": "media.vod.*",++ "cursor": 88213,++ "updated_at": "2026-10-10T12:00:00Z"++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "events": [],++ "next_after_seq": 5,++ "latest_seq": 5++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "consumer": "live",++ "topic": "media.vod.*",++ "cursor": "c1.0.ODgyMTM",++ "carrier": "pg-v1",++ "updated_at": "2026-10-10T12:00:00Z"++}@@@ -1 +1,7 @@--{ "consumer": "live", "topic": "media.vod.*", "cursor": 0, "updated_at": null }++{++ "consumer": "live",++ "topic": "media.vod.*",++ "cursor": null,++ "carrier": null,++ "updated_at": null++}@@@ -24,7 +24,6 @@"cursor": "c1.e0.1"}],-- "next_after_seq": 88240,-- "latest_seq": 88240,-- "next_cursor": "c1.e0.next"++ "next_cursor": "c1.e0.next",++ "latest_cursor": "c1.0.ODgyNDA"}@@@ -24,8 +24,6 @@"cursor": "c1.e0.1"}],-- "next_after_seq": 88240,-- "latest_seq": 88240,"next_cursor": "c1.e0.next","latest_cursor": "c1.0.Nw"}@@@ -1 +1,29 @@--{ "events": [ { "seq": 88213, "event": { "event_id": "evt_01JAB2C3D4E5F6G7H8J9K0MNPR", "event_type": "app.p01jab2c3d4e5f6g7h8j9k0mnpq.order.created", "version": 1, "source": "app-01jab2c3d4e5f6g7h8j9k0mnps", "actor": { "type": "app", "id": "app_01JAB2C3D4E5F6G7H8J9K0MNPS" }, "timestamp": "2026-09-23T12:00:00Z", "visibility": "internal", "subject": { "type": "order", "id": "42" }, "payload": { "total": 3 }} } ], "next_after_seq": 88240, "latest_seq": 88240 }++{++ "events": [++ {++ "seq": 88213,++ "event": {++ "event_id": "evt_01JAB2C3D4E5F6G7H8J9K0MNPR",++ "event_type": "app.p01jab2c3d4e5f6g7h8j9k0mnpq.order.created",++ "version": 1,++ "source": "app-01jab2c3d4e5f6g7h8j9k0mnps",++ "actor": {++ "type": "app",++ "id": "app_01JAB2C3D4E5F6G7H8J9K0MNPS"++ },++ "timestamp": "2026-09-23T12:00:00Z",++ "visibility": "internal",++ "subject": {++ "type": "order",++ "id": "42"++ },++ "payload": {++ "total": 3++ }++ },++ "cursor": "c1.0.ODgyMTM"++ }++ ],++ "next_cursor": "c1.0.ODgyNDA",++ "latest_cursor": "c1.0.ODgyNDA"++}@@@ -6059,7 +6059,7 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/events/read-request.v1.json","title": "EventsReadRequest",-- "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor } stores the calling consumer's cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after_seq=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body.",++ "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor, carrier? } stores the calling consumer's opaque cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body. A position is only ever an opaque cursor (ADR-042 decision 7): after_seq is refused (400) and a numeric checkpoint cursor is refused.","anyOf": [{"type": "object",@@@ -6075,9 +6075,16 @@"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."},"cursor": {-- "type": "integer",-- "minimum": 0,-- "description": "A seq (next_after_seq of the last page handled)."++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "An opaque cursor: a page's next_cursor (or latest_cursor). Never a number, never parsed."++ },++ "carrier": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "description": "The carrier the position is on (ADR-042), recorded with it."}}},@@@ -6095,14 +6102,14 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/events/read-result.v1.json","title": "EventsReadResult",-- "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor?, event }], next_after_seq, next_cursor?, latest_seq, latest_cursor?, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; the numeric after_seq, next_after_seq and latest_seq remain only until every consumer reads by cursor (plan T7); gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, updated_at } (cursor 0 and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } (id: the cursor once Events sends one, else the seq; a gap message when the cursor is older than retention). An app sees only its project's events in its token's environment plus public first-party events.",++ "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; without after= a page starts at the oldest retained event; gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, cursor, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, carrier, updated_at } (cursor, carrier and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } with the cursor as the SSE id; it resumes from Last-Event-ID (or last_event_id=) when that is a cursor, and a gap message comes first when the cursor is older than retention. A position is only ever an opaque cursor (ADR-042 decision 7): the per-event seq is informational, and nothing accepts it as a position. An app sees only its project's events in its token's environment plus public first-party events.","anyOf": [{"type": "object","required": ["events",-- "next_after_seq",-- "latest_seq"++ "next_cursor",++ "latest_cursor"],"properties": {"events": {@@@ -6112,12 +6119,14 @@"type": "object","required": ["seq",++ "cursor","event"],"properties": {"seq": {"type": "integer",-- "minimum": 1++ "minimum": 1,++ "description": "Informational: the event's number in the hot store. Not a position."},"event": {"$ref": "event-envelope.v1.json"@@@ -6126,19 +6135,11 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."++ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."}}}},-- "next_after_seq": {-- "type": "integer",-- "minimum": 0-- },-- "latest_seq": {-- "type": "integer",-- "minimum": 0-- },"gap": {"type": "object","required": [@@@ -6158,13 +6159,13 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page. Returned beside next_after_seq for one release."++ "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page."},"latest_cursor": {"type": "string","minLength": 1,"maxLength": 200,-- "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=, never needing latest_seq."++ "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=."}}},@@@ -6172,12 +6173,14 @@"type": "object","required": ["seq",++ "cursor","event"],"properties": {"seq": {"type": "integer",-- "minimum": 1++ "minimum": 1,++ "description": "Informational: the event's number in the hot store. Not a position."},"event": {"$ref": "event-envelope.v1.json"@@@ -6186,7 +6189,7 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."++ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."}}},@@@ -6206,8 +6209,13 @@"type": "string"},"cursor": {-- "type": "integer",-- "minimum": 0++ "type": [++ "string",++ "null"++ ],++ "minLength": 1,++ "maxLength": 200,++ "description": "The stored opaque cursor, as it was stored; null when none is."},"updated_at": {"type": [@@@ -6215,6 +6223,13 @@"null"],"format": "date-time"++ },++ "carrier": {++ "type": [++ "string",++ "null"++ ],++ "description": "The carrier the stored position is on (ADR-042), or null."}}}@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Actor API",-- "version": "0.131.0",-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.AI API",-- "version": "0.131.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Bot API",-- "version": "0.131.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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"@@@ -1464,7 +1464,7 @@},"events.read-request.v1": {"title": "EventsReadRequest",-- "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor } stores the calling consumer's cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after_seq=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body.",++ "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor, carrier? } stores the calling consumer's opaque cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body. A position is only ever an opaque cursor (ADR-042 decision 7): after_seq is refused (400) and a numeric checkpoint cursor is refused.","anyOf": [{"type": "object",@@@ -1480,9 +1480,16 @@"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."},"cursor": {-- "type": "integer",-- "minimum": 0,-- "description": "A seq (next_after_seq of the last page handled)."++ "type": "string",++ "minLength": 1,++ "maxLength": 200,++ "description": "An opaque cursor: a page's next_cursor (or latest_cursor). Never a number, never parsed."++ },++ "carrier": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "description": "The carrier the position is on (ADR-042), recorded with it."}}},@@@ -1493,14 +1500,14 @@},"events.read-result.v1": {"title": "EventsReadResult",-- "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor?, event }], next_after_seq, next_cursor?, latest_seq, latest_cursor?, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; the numeric after_seq, next_after_seq and latest_seq remain only until every consumer reads by cursor (plan T7); gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, updated_at } (cursor 0 and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } (id: the cursor once Events sends one, else the seq; a gap message when the cursor is older than retention). An app sees only its project's events in its token's environment plus public first-party events.",++ "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; without after= a page starts at the oldest retained event; gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, cursor, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, carrier, updated_at } (cursor, carrier and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } with the cursor as the SSE id; it resumes from Last-Event-ID (or last_event_id=) when that is a cursor, and a gap message comes first when the cursor is older than retention. A position is only ever an opaque cursor (ADR-042 decision 7): the per-event seq is informational, and nothing accepts it as a position. An app sees only its project's events in its token's environment plus public first-party events.","anyOf": [{"type": "object","required": ["events",-- "next_after_seq",-- "latest_seq"++ "next_cursor",++ "latest_cursor"],"properties": {"events": {@@@ -1510,12 +1517,14 @@"type": "object","required": ["seq",++ "cursor","event"],"properties": {"seq": {"type": "integer",-- "minimum": 1++ "minimum": 1,++ "description": "Informational: the event's number in the hot store. Not a position."},"event": {"$ref": "#/components/schemas/events.event-envelope.v1"@@@ -1524,19 +1533,11 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."++ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."}}}},-- "next_after_seq": {-- "type": "integer",-- "minimum": 0-- },-- "latest_seq": {-- "type": "integer",-- "minimum": 0-- },"gap": {"type": "object","required": [@@@ -1556,13 +1557,13 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page. Returned beside next_after_seq for one release."++ "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page."},"latest_cursor": {"type": "string","minLength": 1,"maxLength": 200,-- "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=, never needing latest_seq."++ "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=."}}},@@@ -1570,12 +1571,14 @@"type": "object","required": ["seq",++ "cursor","event"],"properties": {"seq": {"type": "integer",-- "minimum": 1++ "minimum": 1,++ "description": "Informational: the event's number in the hot store. Not a position."},"event": {"$ref": "#/components/schemas/events.event-envelope.v1"@@@ -1584,7 +1587,7 @@"type": "string","minLength": 1,"maxLength": 200,-- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."++ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."}}},@@@ -1604,8 +1607,13 @@"type": "string"},"cursor": {-- "type": "integer",-- "minimum": 0++ "type": [++ "string",++ "null"++ ],++ "minLength": 1,++ "maxLength": 200,++ "description": "The stored opaque cursor, as it was stored; null when none is."},"updated_at": {"type": [@@@ -1613,6 +1621,13 @@"null"],"format": "date-time"++ },++ "carrier": {++ "type": [++ "string",++ "null"++ ],++ "description": "The carrier the stored position is on (ADR-042), or null."}}}@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Food API",-- "version": "0.131.0",-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.Inventory API",-- "version": "0.131.0",-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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": "OpenRestream API",-- "version": "0.131.0",-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Run API",-- "version": "0.131.0",-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Services API",-- "version": "0.131.0",-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Watch API",-- "version": "0.131.0",-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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"@@@ -11186,7 +11186,7 @@ export type EventsPublishResult =/** [email protected] (owner: events) *//**-- * events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor } stores the calling consumer's cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after_seq=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body.++ * events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor, carrier? } stores the calling consumer's opaque cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body. A position is only ever an opaque cursor (ADR-042 decision 7): after_seq is refused (400) and a numeric checkpoint cursor is refused.*/export type EventsReadRequest =| {@@@ -11195,15 +11195,19 @@ export type EventsReadRequest =*/topic: string;/**-- * A seq (next_after_seq of the last page handled).++ * An opaque cursor: a page's next_cursor (or latest_cursor). Never a number, never parsed.*/-- cursor: number;++ cursor: string;++ /**++ * The carrier the position is on (ADR-042), recorded with it.++ */++ carrier?: string;}| NoBody;/** [email protected] (owner: events) *//**-- * events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor?, event }], next_after_seq, next_cursor?, latest_seq, latest_cursor?, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; the numeric after_seq, next_after_seq and latest_seq remain only until every consumer reads by cursor (plan T7); gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, updated_at } (cursor 0 and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } (id: the cursor once Events sends one, else the seq; a gap message when the cursor is older than retention). An app sees only its project's events in its token's environment plus public first-party events.++ * events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; without after= a page starts at the oldest retained event; gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, cursor, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, carrier, updated_at } (cursor, carrier and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } with the cursor as the SSE id; it resumes from Last-Event-ID (or last_event_id=) when that is a cursor, and a gap message comes first when the cursor is older than retention. A position is only ever an opaque cursor (ADR-042 decision 7): the per-event seq is informational, and nothing accepts it as a position. An app sees only its project's events in its token's environment plus public first-party events.*/export type EventsReadResult =| {@@@ -11211,41 +11215,52 @@ export type EventsReadResult =* @maxItems 1000*/events: {++ /**++ * Informational: the event's number in the hot store. Not a position.++ */seq: number;event: EventEnvelope;/**-- * Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes.++ * Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it.*/-- cursor?: string;++ cursor: string;}[];-- next_after_seq: number;-- latest_seq: number;gap?: {from_seq: number;to_seq: number;};/**-- * Opaque position after this page (ADR-042): pass it back as after= for the next page. Returned beside next_after_seq for one release.++ * Opaque position after this page (ADR-042): pass it back as after= for the next page.*/-- next_cursor?: string;++ next_cursor: string;/**-- * The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=, never needing latest_seq.++ * The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=.*/-- latest_cursor?: string;++ latest_cursor: string;}| {++ /**++ * Informational: the event's number in the hot store. Not a position.++ */seq: number;event: EventEnvelope;/**-- * Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes.++ * Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it.*/-- cursor?: string;++ cursor: string;}| {consumer: string;topic: string;-- cursor: number;++ /**++ * The stored opaque cursor, as it was stored; null when none is.++ */++ cursor: string | null;updated_at: string | null;++ /**++ * The carrier the stored position is on (ADR-042), or null.++ */++ carrier?: string | null;};/** [email protected] (owner: events) */@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.131.0",++ "version": "0.132.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",
@@ -4,6 +4,26 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
@@ -4,6 +4,26 @@ 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.132.0 — 2026-10-10
+
+**An Events position is an opaque cursor and nothing else** (ADR-042 decision 7, plan T7). `events.read-result@1` and
+`events.read-request@1` drop the numeric positions their own descriptions kept "only until every consumer reads by
+cursor". Every consumer does now, checked across the estate: Community's relay (Community #56), the SDK's pull,
+iterate, checkpoints and realtime (openvibe-sdk 0.42.0), Shared's bell and release watcher (3.0.1), Examples (#14)
+and Chat's e2e test (#64). Services' project archive already read by cursor.
+
+- **Pages:** `GET /api/v1/events` answers `{ events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? }`.
+ `next_after_seq` and `latest_seq` are gone, and `next_cursor`, `latest_cursor` and each item's `cursor` are required
+ (Events always sent them). Without `after=`, a page starts at the oldest retained event; `after_seq` is refused.
+- **Single event:** `GET /api/v1/events/:event_id` requires `cursor` beside `seq`.
+- **Checkpoints:** `PUT` takes `{ topic, cursor, carrier? }` with `cursor` an opaque cursor string; a number is refused.
+ `GET`/`PUT` answer `{ consumer, topic, cursor, carrier, updated_at }` with the cursor as stored (null when none is).
+- **Realtime:** the SSE id is the cursor, and `Last-Event-ID` resumes only from a cursor.
+- **Per-event `seq`:** stays, documented as informational (not a position). Deleting it, with `X-OpenVibe-Seq` and the
+ global-order promise, is ADR-042's last step; clients already dedupe by `event_id`.
+- **Fixtures:** pages and checkpoints with cursors only, plus three invalid ones (a numeric page, a numeric checkpoint
+ answer, a numeric checkpoint request). ADR-042 records what decision 7 became.
+
## 0.131.0 — 2026-10-10
## 0.131.0 — 2026-10-10
- `openre.resource.read` (owner `openre`, first-party, **active**): OpenRestream's resource index, its stream
- `openre.resource.read` (owner `openre`, first-party, **active**): OpenRestream's resource index, its stream
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/read-request.v1.json",
"$id": "https://openvibe.network/contracts/events/read-request.v1.json",
"title": "EventsReadRequest",
"title": "EventsReadRequest",
- "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor } stores the calling consumer's cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after_seq=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body.",
+ "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor, carrier? } stores the calling consumer's opaque cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body. A position is only ever an opaque cursor (ADR-042 decision 7): after_seq is refused (400) and a numeric checkpoint cursor is refused.",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
@@ -18,9 +18,16 @@
@@ -18,9 +18,16 @@
"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."
"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."
},
},
"cursor": {
"cursor": {
- "type": "integer",
- "minimum": 0,
- "description": "A seq (next_after_seq of the last page handled)."
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "An opaque cursor: a page's next_cursor (or latest_cursor). Never a number, never parsed."
+ },
+ "carrier": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "description": "The carrier the position is on (ADR-042), recorded with it."
}
}
}
}
},
},
@@ -2,14 +2,14 @@
@@ -2,14 +2,14 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/read-result.v1.json",
"$id": "https://openvibe.network/contracts/events/read-result.v1.json",
"title": "EventsReadResult",
"title": "EventsReadResult",
- "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor?, event }], next_after_seq, next_cursor?, latest_seq, latest_cursor?, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; the numeric after_seq, next_after_seq and latest_seq remain only until every consumer reads by cursor (plan T7); gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, updated_at } (cursor 0 and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } (id: the cursor once Events sends one, else the seq; a gap message when the cursor is older than retention). An app sees only its project's events in its token's environment plus public first-party events.",
+ "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; without after= a page starts at the oldest retained event; gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, cursor, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, carrier, updated_at } (cursor, carrier and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } with the cursor as the SSE id; it resumes from Last-Event-ID (or last_event_id=) when that is a cursor, and a gap message comes first when the cursor is older than retention. A position is only ever an opaque cursor (ADR-042 decision 7): the per-event seq is informational, and nothing accepts it as a position. An app sees only its project's events in its token's environment plus public first-party events.",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
"required": [
"required": [
"events",
"events",
- "next_after_seq",
- "latest_seq"
+ "next_cursor",
+ "latest_cursor"
],
],
"properties": {
"properties": {
"events": {
"events": {
@@ -19,12 +19,14 @@
@@ -19,12 +19,14 @@
"type": "object",
"type": "object",
"required": [
"required": [
"seq",
"seq",
+ "cursor",
"event"
"event"
],
],
"properties": {
"properties": {
"seq": {
"seq": {
"type": "integer",
"type": "integer",
- "minimum": 1
+ "minimum": 1,
+ "description": "Informational: the event's number in the hot store. Not a position."
},
},
"event": {
"event": {
"$ref": "event-envelope.v1.json"
"$ref": "event-envelope.v1.json"
@@ -33,19 +35,11 @@
@@ -33,19 +35,11 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."
+ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."
}
}
}
}
}
}
},
},
- "next_after_seq": {
- "type": "integer",
- "minimum": 0
- },
- "latest_seq": {
- "type": "integer",
- "minimum": 0
- },
"gap": {
"gap": {
"type": "object",
"type": "object",
"required": [
"required": [
@@ -65,13 +59,13 @@
@@ -65,13 +59,13 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page. Returned beside next_after_seq for one release."
+ "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page."
},
},
"latest_cursor": {
"latest_cursor": {
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=, never needing latest_seq."
+ "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=."
}
}
}
}
},
},
@@ -79,12 +73,14 @@
@@ -79,12 +73,14 @@
"type": "object",
"type": "object",
"required": [
"required": [
"seq",
"seq",
+ "cursor",
"event"
"event"
],
],
"properties": {
"properties": {
"seq": {
"seq": {
"type": "integer",
"type": "integer",
- "minimum": 1
+ "minimum": 1,
+ "description": "Informational: the event's number in the hot store. Not a position."
},
},
"event": {
"event": {
"$ref": "event-envelope.v1.json"
"$ref": "event-envelope.v1.json"
@@ -93,7 +89,7 @@
@@ -93,7 +89,7 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."
+ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."
}
}
}
}
},
},
@@ -113,8 +109,13 @@
@@ -113,8 +109,13 @@
"type": "string"
"type": "string"
},
},
"cursor": {
"cursor": {
- "type": "integer",
- "minimum": 0
+ "type": [
+ "string",
+ "null"
+ ],
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The stored opaque cursor, as it was stored; null when none is."
},
},
"updated_at": {
"updated_at": {
"type": [
"type": [
@@ -122,6 +123,13 @@
@@ -122,6 +123,13 @@
"null"
"null"
],
],
"format": "date-time"
"format": "date-time"
+ },
+ "carrier": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The carrier the stored position is on (ADR-042), or null."
}
}
}
}
}
}
@@ -53,6 +53,11 @@ cell-local carrier). Amends ADR-004: its "Kafka/NATS now: rejected" is supersede
@@ -53,6 +53,11 @@ cell-local carrier). Amends ADR-004: its "Kafka/NATS now: rejected" is supersede
`next_cursor` (opaque: a hot-store position plus a retention epoch); the SSE `id` becomes the cursor. Consumers'
`next_cursor` (opaque: a hot-store position plus a retention epoch); the SSE `id` becomes the cursor. Consumers'
positions live in `consumer_checkpoints` with `epoch` and `carrier` columns. `seq` is still returned for exactly one
positions live in `consumer_checkpoints` with `epoch` and `carrier` columns. `seq` is still returned for exactly one
release after the cursor ships; it and `X-OpenVibe-Seq` are then deleted, with the "global order" promise.
release after the cursor ships; it and `X-OpenVibe-Seq` are then deleted, with the "global order" promise.
+ *Positions done 2026-10-10 (Contracts 0.132.0, openvibe-sdk 0.42.0, Shared 3.0.1, Events):* every consumer reads by
+ cursor, and nothing accepts a number as a position any more: `after_seq` is a 400, pages carry no `next_after_seq` or
+ `latest_seq`, checkpoints store and return the opaque cursor, and a bare-number `Last-Event-ID` is not a position.
+ The per-event `seq` (pull items, publish results, SSE data, the delivery body and `X-OpenVibe-Seq`) remains as an
+ informational number; deleting it is the last step, and clients already dedupe by `event_id`.
8. **Three tiers.** hot = `events` (pruned at `retention.hot`); replay = `events_archive` in the same database (no
8. **Three tiers.** hot = `events` (pruned at `retention.hot`); replay = `events_archive` in the same database (no
delivery rows, compressed payloads, pruned at `retention.replay`); archive = monthly NDJSON objects in object
delivery rows, compressed payloads, pruned at `retention.replay`); archive = monthly NDJSON objects in object
storage, restored only by an operator job into `events_archive`. Pulls and scans span hot and replay with one
storage, restored only by an operator job into `events_archive`. Pulls and scans span hot and replay with one
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "topic": "media.vod.*",
+ "cursor": 88213
+}
@@ -1 +1,5 @@
@@ -1 +1,5 @@
-{ "topic": "media.vod.*", "cursor": 88213 }
+{
+ "topic": "media.vod.*",
+ "cursor": "c1.0.ODgyMTM",
+ "carrier": "pg-v1"
+}
@@ -1 +1,13 @@
@@ -1 +1,13 @@
-{ "events": [ { "seq": 1, "event": { "event_type": "x" } } ], "next_after_seq": 1, "latest_seq": 1 }
+{
+ "events": [
+ {
+ "seq": 1,
+ "cursor": "c1.0.MQ",
+ "event": {
+ "event_type": "x"
+ }
+ }
+ ],
+ "next_cursor": "c1.0.MQ",
+ "latest_cursor": "c1.0.MQ"
+}
@@ -24,8 +24,6 @@
@@ -24,8 +24,6 @@
"cursor": "c1.e0.1"
"cursor": "c1.e0.1"
}
}
],
],
- "next_after_seq": 88240,
- "latest_seq": 88240,
"next_cursor": "c1.e0.next",
"next_cursor": "c1.e0.next",
"latest_cursor": ""
"latest_cursor": ""
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "consumer": "live",
+ "topic": "media.vod.*",
+ "cursor": 88213,
+ "updated_at": "2026-10-10T12:00:00Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "events": [],
+ "next_after_seq": 5,
+ "latest_seq": 5
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "consumer": "live",
+ "topic": "media.vod.*",
+ "cursor": "c1.0.ODgyMTM",
+ "carrier": "pg-v1",
+ "updated_at": "2026-10-10T12:00:00Z"
+}
@@ -1 +1,7 @@
@@ -1 +1,7 @@
-{ "consumer": "live", "topic": "media.vod.*", "cursor": 0, "updated_at": null }
+{
+ "consumer": "live",
+ "topic": "media.vod.*",
+ "cursor": null,
+ "carrier": null,
+ "updated_at": null
+}
@@ -24,7 +24,6 @@
@@ -24,7 +24,6 @@
"cursor": "c1.e0.1"
"cursor": "c1.e0.1"
}
}
],
],
- "next_after_seq": 88240,
- "latest_seq": 88240,
- "next_cursor": "c1.e0.next"
+ "next_cursor": "c1.e0.next",
+ "latest_cursor": "c1.0.ODgyNDA"
}
}
@@ -24,8 +24,6 @@
@@ -24,8 +24,6 @@
"cursor": "c1.e0.1"
"cursor": "c1.e0.1"
}
}
],
],
- "next_after_seq": 88240,
- "latest_seq": 88240,
"next_cursor": "c1.e0.next",
"next_cursor": "c1.e0.next",
"latest_cursor": "c1.0.Nw"
"latest_cursor": "c1.0.Nw"
}
}
@@ -1 +1,29 @@
@@ -1 +1,29 @@
-{ "events": [ { "seq": 88213, "event": { "event_id": "evt_01JAB2C3D4E5F6G7H8J9K0MNPR", "event_type": "app.p01jab2c3d4e5f6g7h8j9k0mnpq.order.created", "version": 1, "source": "app-01jab2c3d4e5f6g7h8j9k0mnps", "actor": { "type": "app", "id": "app_01JAB2C3D4E5F6G7H8J9K0MNPS" }, "timestamp": "2026-09-23T12:00:00Z", "visibility": "internal", "subject": { "type": "order", "id": "42" }, "payload": { "total": 3 }} } ], "next_after_seq": 88240, "latest_seq": 88240 }
+{
+ "events": [
+ {
+ "seq": 88213,
+ "event": {
+ "event_id": "evt_01JAB2C3D4E5F6G7H8J9K0MNPR",
+ "event_type": "app.p01jab2c3d4e5f6g7h8j9k0mnpq.order.created",
+ "version": 1,
+ "source": "app-01jab2c3d4e5f6g7h8j9k0mnps",
+ "actor": {
+ "type": "app",
+ "id": "app_01JAB2C3D4E5F6G7H8J9K0MNPS"
+ },
+ "timestamp": "2026-09-23T12:00:00Z",
+ "visibility": "internal",
+ "subject": {
+ "type": "order",
+ "id": "42"
+ },
+ "payload": {
+ "total": 3
+ }
+ },
+ "cursor": "c1.0.ODgyMTM"
+ }
+ ],
+ "next_cursor": "c1.0.ODgyNDA",
+ "latest_cursor": "c1.0.ODgyNDA"
+}
@@ -6059,7 +6059,7 @@
@@ -6059,7 +6059,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/read-request.v1.json",
"$id": "https://openvibe.network/contracts/events/read-request.v1.json",
"title": "EventsReadRequest",
"title": "EventsReadRequest",
- "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor } stores the calling consumer's cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after_seq=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body.",
+ "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor, carrier? } stores the calling consumer's opaque cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body. A position is only ever an opaque cursor (ADR-042 decision 7): after_seq is refused (400) and a numeric checkpoint cursor is refused.",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
@@ -6075,9 +6075,16 @@
@@ -6075,9 +6075,16 @@
"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."
"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."
},
},
"cursor": {
"cursor": {
- "type": "integer",
- "minimum": 0,
- "description": "A seq (next_after_seq of the last page handled)."
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "An opaque cursor: a page's next_cursor (or latest_cursor). Never a number, never parsed."
+ },
+ "carrier": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "description": "The carrier the position is on (ADR-042), recorded with it."
}
}
}
}
},
},
@@ -6095,14 +6102,14 @@
@@ -6095,14 +6102,14 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/read-result.v1.json",
"$id": "https://openvibe.network/contracts/events/read-result.v1.json",
"title": "EventsReadResult",
"title": "EventsReadResult",
- "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor?, event }], next_after_seq, next_cursor?, latest_seq, latest_cursor?, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; the numeric after_seq, next_after_seq and latest_seq remain only until every consumer reads by cursor (plan T7); gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, updated_at } (cursor 0 and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } (id: the cursor once Events sends one, else the seq; a gap message when the cursor is older than retention). An app sees only its project's events in its token's environment plus public first-party events.",
+ "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; without after= a page starts at the oldest retained event; gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, cursor, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, carrier, updated_at } (cursor, carrier and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } with the cursor as the SSE id; it resumes from Last-Event-ID (or last_event_id=) when that is a cursor, and a gap message comes first when the cursor is older than retention. A position is only ever an opaque cursor (ADR-042 decision 7): the per-event seq is informational, and nothing accepts it as a position. An app sees only its project's events in its token's environment plus public first-party events.",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
"required": [
"required": [
"events",
"events",
- "next_after_seq",
- "latest_seq"
+ "next_cursor",
+ "latest_cursor"
],
],
"properties": {
"properties": {
"events": {
"events": {
@@ -6112,12 +6119,14 @@
@@ -6112,12 +6119,14 @@
"type": "object",
"type": "object",
"required": [
"required": [
"seq",
"seq",
+ "cursor",
"event"
"event"
],
],
"properties": {
"properties": {
"seq": {
"seq": {
"type": "integer",
"type": "integer",
- "minimum": 1
+ "minimum": 1,
+ "description": "Informational: the event's number in the hot store. Not a position."
},
},
"event": {
"event": {
"$ref": "event-envelope.v1.json"
"$ref": "event-envelope.v1.json"
@@ -6126,19 +6135,11 @@
@@ -6126,19 +6135,11 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."
+ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."
}
}
}
}
}
}
},
},
- "next_after_seq": {
- "type": "integer",
- "minimum": 0
- },
- "latest_seq": {
- "type": "integer",
- "minimum": 0
- },
"gap": {
"gap": {
"type": "object",
"type": "object",
"required": [
"required": [
@@ -6158,13 +6159,13 @@
@@ -6158,13 +6159,13 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page. Returned beside next_after_seq for one release."
+ "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page."
},
},
"latest_cursor": {
"latest_cursor": {
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=, never needing latest_seq."
+ "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=."
}
}
}
}
},
},
@@ -6172,12 +6173,14 @@
@@ -6172,12 +6173,14 @@
"type": "object",
"type": "object",
"required": [
"required": [
"seq",
"seq",
+ "cursor",
"event"
"event"
],
],
"properties": {
"properties": {
"seq": {
"seq": {
"type": "integer",
"type": "integer",
- "minimum": 1
+ "minimum": 1,
+ "description": "Informational: the event's number in the hot store. Not a position."
},
},
"event": {
"event": {
"$ref": "event-envelope.v1.json"
"$ref": "event-envelope.v1.json"
@@ -6186,7 +6189,7 @@
@@ -6186,7 +6189,7 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."
+ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."
}
}
}
}
},
},
@@ -6206,8 +6209,13 @@
@@ -6206,8 +6209,13 @@
"type": "string"
"type": "string"
},
},
"cursor": {
"cursor": {
- "type": "integer",
- "minimum": 0
+ "type": [
+ "string",
+ "null"
+ ],
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The stored opaque cursor, as it was stored; null when none is."
},
},
"updated_at": {
"updated_at": {
"type": [
"type": [
@@ -6215,6 +6223,13 @@
@@ -6215,6 +6223,13 @@
"null"
"null"
],
],
"format": "date-time"
"format": "date-time"
+ },
+ "carrier": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The carrier the stored position is on (ADR-042), or null."
}
}
}
}
}
}
@@ -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.Actor API",
"title": "OpenVibe.Actor API",
- "version": "0.131.0",
- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.AI API",
"title": "OpenVibe.AI API",
- "version": "0.131.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Bot API",
"title": "OpenVibe.Bot API",
- "version": "0.131.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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"
@@ -1464,7 +1464,7 @@
@@ -1464,7 +1464,7 @@
},
},
"events.read-request.v1": {
"events.read-request.v1": {
"title": "EventsReadRequest",
"title": "EventsReadRequest",
- "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor } stores the calling consumer's cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after_seq=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body.",
+ "description": "events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor, carrier? } stores the calling consumer's opaque cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body. A position is only ever an opaque cursor (ADR-042 decision 7): after_seq is refused (400) and a numeric checkpoint cursor is refused.",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
@@ -1480,9 +1480,16 @@
@@ -1480,9 +1480,16 @@
"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."
"description": "Dot-separated segments of [a-z0-9_] or *, where * stands for one or more whole segments (*.* is refused)."
},
},
"cursor": {
"cursor": {
- "type": "integer",
- "minimum": 0,
- "description": "A seq (next_after_seq of the last page handled)."
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "An opaque cursor: a page's next_cursor (or latest_cursor). Never a number, never parsed."
+ },
+ "carrier": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "description": "The carrier the position is on (ADR-042), recorded with it."
}
}
}
}
},
},
@@ -1493,14 +1500,14 @@
@@ -1493,14 +1500,14 @@
},
},
"events.read-result.v1": {
"events.read-result.v1": {
"title": "EventsReadResult",
"title": "EventsReadResult",
- "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor?, event }], next_after_seq, next_cursor?, latest_seq, latest_cursor?, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; the numeric after_seq, next_after_seq and latest_seq remain only until every consumer reads by cursor (plan T7); gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, updated_at } (cursor 0 and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } (id: the cursor once Events sends one, else the seq; a gap message when the cursor is older than retention). An app sees only its project's events in its token's environment plus public first-party events.",
+ "description": "events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; without after= a page starts at the oldest retained event; gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, cursor, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, carrier, updated_at } (cursor, carrier and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } with the cursor as the SSE id; it resumes from Last-Event-ID (or last_event_id=) when that is a cursor, and a gap message comes first when the cursor is older than retention. A position is only ever an opaque cursor (ADR-042 decision 7): the per-event seq is informational, and nothing accepts it as a position. An app sees only its project's events in its token's environment plus public first-party events.",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
"required": [
"required": [
"events",
"events",
- "next_after_seq",
- "latest_seq"
+ "next_cursor",
+ "latest_cursor"
],
],
"properties": {
"properties": {
"events": {
"events": {
@@ -1510,12 +1517,14 @@
@@ -1510,12 +1517,14 @@
"type": "object",
"type": "object",
"required": [
"required": [
"seq",
"seq",
+ "cursor",
"event"
"event"
],
],
"properties": {
"properties": {
"seq": {
"seq": {
"type": "integer",
"type": "integer",
- "minimum": 1
+ "minimum": 1,
+ "description": "Informational: the event's number in the hot store. Not a position."
},
},
"event": {
"event": {
"$ref": "#/components/schemas/events.event-envelope.v1"
"$ref": "#/components/schemas/events.event-envelope.v1"
@@ -1524,19 +1533,11 @@
@@ -1524,19 +1533,11 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."
+ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."
}
}
}
}
}
}
},
},
- "next_after_seq": {
- "type": "integer",
- "minimum": 0
- },
- "latest_seq": {
- "type": "integer",
- "minimum": 0
- },
"gap": {
"gap": {
"type": "object",
"type": "object",
"required": [
"required": [
@@ -1556,13 +1557,13 @@
@@ -1556,13 +1557,13 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page. Returned beside next_after_seq for one release."
+ "description": "Opaque position after this page (ADR-042): pass it back as after= for the next page."
},
},
"latest_cursor": {
"latest_cursor": {
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=, never needing latest_seq."
+ "description": "The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=."
}
}
}
}
},
},
@@ -1570,12 +1571,14 @@
@@ -1570,12 +1571,14 @@
"type": "object",
"type": "object",
"required": [
"required": [
"seq",
"seq",
+ "cursor",
"event"
"event"
],
],
"properties": {
"properties": {
"seq": {
"seq": {
"type": "integer",
"type": "integer",
- "minimum": 1
+ "minimum": 1,
+ "description": "Informational: the event's number in the hot store. Not a position."
},
},
"event": {
"event": {
"$ref": "#/components/schemas/events.event-envelope.v1"
"$ref": "#/components/schemas/events.event-envelope.v1"
@@ -1584,7 +1587,7 @@
@@ -1584,7 +1587,7 @@
"type": "string",
"type": "string",
"minLength": 1,
"minLength": 1,
"maxLength": 200,
"maxLength": 200,
- "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes."
+ "description": "Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it."
}
}
}
}
},
},
@@ -1604,8 +1607,13 @@
@@ -1604,8 +1607,13 @@
"type": "string"
"type": "string"
},
},
"cursor": {
"cursor": {
- "type": "integer",
- "minimum": 0
+ "type": [
+ "string",
+ "null"
+ ],
+ "minLength": 1,
+ "maxLength": 200,
+ "description": "The stored opaque cursor, as it was stored; null when none is."
},
},
"updated_at": {
"updated_at": {
"type": [
"type": [
@@ -1613,6 +1621,13 @@
@@ -1613,6 +1621,13 @@
"null"
"null"
],
],
"format": "date-time"
"format": "date-time"
+ },
+ "carrier": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The carrier the stored position is on (ADR-042), or null."
}
}
}
}
}
}
@@ -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.Food API",
"title": "OpenVibe.Food API",
- "version": "0.131.0",
- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.Inventory API",
"title": "OpenVibe.Inventory API",
- "version": "0.131.0",
- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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": "OpenRestream API",
"title": "OpenRestream API",
- "version": "0.131.0",
- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Run API",
"title": "OpenVibe.Run API",
- "version": "0.131.0",
- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Services API",
"title": "OpenVibe.Services API",
- "version": "0.131.0",
- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Watch API",
"title": "OpenVibe.Watch API",
- "version": "0.131.0",
- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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.131.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.131.0): each operation lists the capabilities it performs; a token for 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.132.0",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.132.0): each operation lists the capabilities it performs; a token for 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"
@@ -11186,7 +11186,7 @@ export type EventsPublishResult =
@@ -11186,7 +11186,7 @@ export type EventsPublishResult =
/** [email protected] (owner: events) */
/** [email protected] (owner: events) */
/**
/**
- * events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor } stores the calling consumer's cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after_seq=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body.
+ * events.read-request@1: request bodies of the pull API on OpenVibe.Events (events.event.read, events.app.read). PUT /api/v1/checkpoints: { topic, cursor, carrier? } stores the calling consumer's opaque cursor for a topic pattern (an app's patterns must start with a literal segment and app.* must name its own project_key). GET /api/v1/events?topic=&after=&limit=, GET /api/v1/events/:event_id, GET /api/v1/checkpoints?topic= and GET /realtime/stream?topics= take no body. A position is only ever an opaque cursor (ADR-042 decision 7): after_seq is refused (400) and a numeric checkpoint cursor is refused.
*/
*/
export type EventsReadRequest =
export type EventsReadRequest =
| {
| {
@@ -11195,15 +11195,19 @@ export type EventsReadRequest =
@@ -11195,15 +11195,19 @@ export type EventsReadRequest =
*/
*/
topic: string;
topic: string;
/**
/**
- * A seq (next_after_seq of the last page handled).
+ * An opaque cursor: a page's next_cursor (or latest_cursor). Never a number, never parsed.
*/
*/
- cursor: number;
+ cursor: string;
+ /**
+ * The carrier the position is on (ADR-042), recorded with it.
+ */
+ carrier?: string;
}
}
| NoBody;
| NoBody;
/** [email protected] (owner: events) */
/** [email protected] (owner: events) */
/**
/**
- * events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor?, event }], next_after_seq, next_cursor?, latest_seq, latest_cursor?, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; the numeric after_seq, next_after_seq and latest_seq remain only until every consumer reads by cursor (plan T7); gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, updated_at } (cursor 0 and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } (id: the cursor once Events sends one, else the seq; a gap message when the cursor is older than retention). An app sees only its project's events in its token's environment plus public first-party events.
+ * events.read-result@1: answers of the pull API on OpenVibe.Events. GET /api/v1/events → { events: [{ seq, cursor, event }], next_cursor, latest_cursor, gap? } (keep next_cursor as the position and read on with after=: it moves past events that did not match; latest_cursor is the head, for a consumer that starts at now; without after= a page starts at the oldest retained event; gap { from_seq, to_seq } says events after the position were already pruned by retention); GET /api/v1/events/:event_id → { seq, cursor, event }; GET|PUT /api/v1/checkpoints → { consumer, topic, cursor, carrier, updated_at } (cursor, carrier and updated_at null when none is stored). GET /realtime/stream?topics= (events.event.read) is a Server-Sent Events feed whose messages carry the same { seq, event } with the cursor as the SSE id; it resumes from Last-Event-ID (or last_event_id=) when that is a cursor, and a gap message comes first when the cursor is older than retention. A position is only ever an opaque cursor (ADR-042 decision 7): the per-event seq is informational, and nothing accepts it as a position. An app sees only its project's events in its token's environment plus public first-party events.
*/
*/
export type EventsReadResult =
export type EventsReadResult =
| {
| {
@@ -11211,41 +11215,52 @@ export type EventsReadResult =
@@ -11211,41 +11215,52 @@ export type EventsReadResult =
* @maxItems 1000
* @maxItems 1000
*/
*/
events: {
events: {
+ /**
+ * Informational: the event's number in the hot store. Not a position.
+ */
seq: number;
seq: number;
event: EventEnvelope;
event: EventEnvelope;
/**
/**
- * Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes.
+ * Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it.
*/
*/
- cursor?: string;
+ cursor: string;
}[];
}[];
- next_after_seq: number;
- latest_seq: number;
gap?: {
gap?: {
from_seq: number;
from_seq: number;
to_seq: number;
to_seq: number;
};
};
/**
/**
- * Opaque position after this page (ADR-042): pass it back as after= for the next page. Returned beside next_after_seq for one release.
+ * Opaque position after this page (ADR-042): pass it back as after= for the next page.
*/
*/
- next_cursor?: string;
+ next_cursor: string;
/**
/**
- * The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=, never needing latest_seq.
+ * The head as an opaque cursor (ADR-042): a consumer that starts at now stores it and reads on with after=.
*/
*/
- latest_cursor?: string;
+ latest_cursor: string;
}
}
| {
| {
+ /**
+ * Informational: the event's number in the hot store. Not a position.
+ */
seq: number;
seq: number;
event: EventEnvelope;
event: EventEnvelope;
/**
/**
- * Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it. Returned beside seq for one release; seq then goes.
+ * Opaque position (ADR-042): hand it back as after= to read on from here, or as Last-Event-ID; never parse it.
*/
*/
- cursor?: string;
+ cursor: string;
}
}
| {
| {
consumer: string;
consumer: string;
topic: string;
topic: string;
- cursor: number;
+ /**
+ * The stored opaque cursor, as it was stored; null when none is.
+ */
+ cursor: string | null;
updated_at: string | null;
updated_at: string | null;
+ /**
+ * The carrier the stored position is on (ADR-042), or null.
+ */
+ carrier?: string | null;
};
};
/** [email protected] (owner: events) */
/** [email protected] (owner: events) */
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.131.0",
+ "version": "0.132.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
"types": "generated/typescript/index.d.ts",