openvibers/openvibe.contracts Commits

v0.45.0: live.index_document also carries Live's public VOD and clip pages (types vod and clip; Live owns their canonical pages); media.index_document is only for VODs and clips whose canonical page is on openvibe.media

OP OpenVibers committed 25 Sept 2026 · 494301b531 · 13 files, +42 −16


Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 5001a1df..61c60660 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
++## 0.45.0 — 2026-09-25
++
++**`live.index_document.upserted|deleted`** also carry Live's public VOD and clip pages (types `vod` and `clip`, id = the Media id, canonical `openvibe.live/vod/<id>` and `/clip/<id>`), alongside channels. Live owns those canonical pages (title, channel, AI overview, transcript), so Live sends their Search documents. `media.index_document.*` is only for VODs and clips whose canonical page is on openvibe.media (apps other than Live), the same rule as Media's sitemap. Fixtures for a VOD, an AI clip (noindex) and a VOD tombstone. Additive.
++
## 0.44.0 — 2026-09-25
Search documents from three more owners (roadmap WS-O task 10): **`live.index_document.upserted|deleted`** (a streamer's channel page, type `channel`), **`media.index_document.upserted|deleted`** (public, playable VODs and clips, types `vod` and `clip`) and **`community.index_document.upserted|deleted`** (public forum threads and public pastes, types `thread` and `paste`). They use the same shape as the Wiki, Blog, News and other owners' index events: the `search.index-document@1` document, or a tombstone `{ type, id, revision }`. OpenVibe.Search consumes them through `*.index_document.*`. The live, media and community manifests list them. Fixtures cover the Live payloads. Additive.
ddiff --git a/contracts/events/payloads/live.index_document.deleted.v1.json b/contracts/events/payloads/live.index_document.deleted.v1.json
iindex ada5b7af..1eb0993a 100644
---- a/contracts/events/payloads/live.index_document.deleted.v1.json
++++ b/contracts/events/payloads/live.index_document.deleted.v1.json
@@@ -12,7 +12,11 @@
"additionalProperties": false,
"properties": {
"type": {
-- "const": "channel"
++ "enum": [
++ "channel",
++ "vod",
++ "clip"
++ ]
},
"id": {
"type": "string",
ddiff --git a/contracts/events/payloads/live.index_document.upserted.v1.json b/contracts/events/payloads/live.index_document.upserted.v1.json
iindex 6befb2a0..bcaa24f9 100644
---- a/contracts/events/payloads/live.index_document.upserted.v1.json
++++ b/contracts/events/payloads/live.index_document.upserted.v1.json
@@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/payloads/live.index_document.upserted.v1.json",
"title": "LiveIndexDocumentUpsertedPayload",
-- "description": "live.index_document.upserted v1 (OpenVibe.Live server/events/search-documents.js; roadmap WS-O task 10). The OpenVibe.Search document of A streamer's channel page (openvibe.live/@username): its name, bio, what it streams and whether it is live. Sent whenever what Search should hold changed; a banned channel, or one that stopped streaming for good, gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:live.",
++ "description": "live.index_document.upserted v1 (OpenVibe.Live server/events/search-documents.js; roadmap WS-O task 10). The OpenVibe.Search document of one of Live's canonical pages: a streamer's channel (type channel, openvibe.live/@username: its name, bio, what it streams and whether it is live), or a public VOD or clip of a Live stream (types vod and clip, openvibe.live/vod/<id> and /clip/<id>: title, channel, AI overview and transcript; the id is the Media id; AI clips are noindex). Sent whenever what Search should hold changed; a banned channel, or a VOD or clip that is deleted, made private or failed, gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:live.",
"allOf": [
{
"$ref": "../../search/index-document.v1.json"
@@@ -19,7 +19,11 @@
"const": "live"
},
"type": {
-- "const": "channel"
++ "enum": [
++ "channel",
++ "vod",
++ "clip"
++ ]
},
"id": {
"type": "string",
ddiff --git a/contracts/events/payloads/media.index_document.upserted.v1.json b/contracts/events/payloads/media.index_document.upserted.v1.json
iindex a07b4d4f..6472290b 100644
---- a/contracts/events/payloads/media.index_document.upserted.v1.json
++++ b/contracts/events/payloads/media.index_document.upserted.v1.json
@@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/payloads/media.index_document.upserted.v1.json",
"title": "MediaIndexDocumentUpsertedPayload",
-- "description": "media.index_document.upserted v1 (OpenVibe.Media; roadmap WS-O task 10). The OpenVibe.Search document of A public, playable VOD or clip page on openvibe.media (readiness playable, visibility public). Sent whenever what Search should hold changed; a VOD or clip that is deleted, made private or stops being playable gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:media.",
++ "description": "media.index_document.upserted v1 (OpenVibe.Media; roadmap WS-O task 10). The OpenVibe.Search document of a public, playable VOD or clip whose canonical page is on openvibe.media (openvibe.media/v/<id>, /c/<id>): readiness playable, visibility public, made by a person, and owned by an app other than Live (Live's own VODs and clips are live.index_document, type vod or clip, on Live's pages). Sent whenever what Search should hold changed; a VOD or clip that is deleted, made private or stops being playable gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:media.",
"allOf": [
{
"$ref": "../../search/index-document.v1.json"
ddiff --git a/fixtures/live.index_document.deleted/valid/vod.json b/fixtures/live.index_document.deleted/valid/vod.json
nnew file mode 100644
iindex 00000000..f6dc5308
---- /dev/null
++++ b/fixtures/live.index_document.deleted/valid/vod.json
@@@ -0,0 +1 @@
++{ "type": "vod", "id": "912", "revision": 3 }
ddiff --git a/fixtures/live.index_document.upserted/invalid/paste-type.json b/fixtures/live.index_document.upserted/invalid/paste-type.json
nnew file mode 100644
iindex 00000000..fb997c2c
---- /dev/null
++++ b/fixtures/live.index_document.upserted/invalid/paste-type.json
@@@ -0,0 +1 @@
++{ "owner": "live", "type": "paste", "id": "12", "revision": 1, "deleted": false, "visibility": "public", "canonical_url": "https://openvibe.live/p/x", "title": "x", "publication_state": "published" }
ddiff --git a/fixtures/live.index_document.upserted/invalid/wrong-type.json b/fixtures/live.index_document.upserted/invalid/wrong-type.json
ddeleted file mode 100644
iindex 138b78ec..00000000
---- a/fixtures/live.index_document.upserted/invalid/wrong-type.json
++++ /dev/null
@@@ -1 +0,0 @@
--{ "owner": "live", "type": "vod", "id": "42", "revision": 3, "deleted": false, "visibility": "public", "title": "x", "publication_state": "published", "indexability": { "decision": "index" } }
ddiff --git a/fixtures/live.index_document.upserted/valid/ai-clip.json b/fixtures/live.index_document.upserted/valid/ai-clip.json
nnew file mode 100644
iindex 00000000..aa0b1a64
---- /dev/null
++++ b/fixtures/live.index_document.upserted/valid/ai-clip.json
@@@ -0,0 +1 @@
++{ "owner": "live", "type": "clip", "id": "3107", "revision": 1, "deleted": false, "visibility": "public", "canonical_url": "https://openvibe.live/clip/3107", "title": "Chat erupts at the boss fight", "summary": "AI clip from Alex's stream.", "facets": { "channel": "alex", "ai_clip": true, "vod_id": "912", "duration_seconds": 30 }, "authorship": "ai_generated", "publication_state": "published", "published_at": "2026-09-24T21:00:00.000Z", "updated_at": "2026-09-25T19:00:00.000Z", "indexability": { "decision": "noindex", "reasons": ["ai_unreviewed"] } }
ddiff --git a/fixtures/live.index_document.upserted/valid/vod.json b/fixtures/live.index_document.upserted/valid/vod.json
nnew file mode 100644
iindex 00000000..e8368f42
---- /dev/null
++++ b/fixtures/live.index_document.upserted/valid/vod.json
@@@ -0,0 +1 @@
++{ "owner": "live", "type": "vod", "id": "912", "revision": 2, "deleted": false, "visibility": "public", "canonical_url": "https://openvibe.live/vod/912", "title": "Building a forum", "summary": "Alex builds the forum's rating menu and fixes it on phones.", "body": "Transcript: okay so today we are building the forum", "facets": { "channel": "alex", "category": "tech", "duration_seconds": 5400 }, "language": "en", "authorship": "human", "publication_state": "published", "published_at": "2026-09-24T19:00:00.000Z", "updated_at": "2026-09-25T19:00:00.000Z", "indexability": { "decision": "index" } }
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex cca82969..b7a35d32 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -4195,7 +4195,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/payloads/live.index_document.upserted.v1.json",
"title": "LiveIndexDocumentUpsertedPayload",
-- "description": "live.index_document.upserted v1 (OpenVibe.Live server/events/search-documents.js; roadmap WS-O task 10). The OpenVibe.Search document of A streamer's channel page (openvibe.live/@username): its name, bio, what it streams and whether it is live. Sent whenever what Search should hold changed; a banned channel, or one that stopped streaming for good, gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:live.",
++ "description": "live.index_document.upserted v1 (OpenVibe.Live server/events/search-documents.js; roadmap WS-O task 10). The OpenVibe.Search document of one of Live's canonical pages: a streamer's channel (type channel, openvibe.live/@username: its name, bio, what it streams and whether it is live), or a public VOD or clip of a Live stream (types vod and clip, openvibe.live/vod/<id> and /clip/<id>: title, channel, AI overview and transcript; the id is the Media id; AI clips are noindex). Sent whenever what Search should hold changed; a banned channel, or a VOD or clip that is deleted, made private or failed, gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:live.",
"allOf": [
{
"$ref": "../../search/index-document.v1.json"
@@@ -4212,7 +4212,11 @@
"const": "live"
},
"type": {
-- "const": "channel"
++ "enum": [
++ "channel",
++ "vod",
++ "clip"
++ ]
},
"id": {
"type": "string",
@@@ -4244,7 +4248,11 @@
"additionalProperties": false,
"properties": {
"type": {
-- "const": "channel"
++ "enum": [
++ "channel",
++ "vod",
++ "clip"
++ ]
},
"id": {
"type": "string",
@@@ -4267,7 +4275,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/events/payloads/media.index_document.upserted.v1.json",
"title": "MediaIndexDocumentUpsertedPayload",
-- "description": "media.index_document.upserted v1 (OpenVibe.Media; roadmap WS-O task 10). The OpenVibe.Search document of A public, playable VOD or clip page on openvibe.media (readiness playable, visibility public). Sent whenever what Search should hold changed; a VOD or clip that is deleted, made private or stops being playable gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:media.",
++ "description": "media.index_document.upserted v1 (OpenVibe.Media; roadmap WS-O task 10). The OpenVibe.Search document of a public, playable VOD or clip whose canonical page is on openvibe.media (openvibe.media/v/<id>, /c/<id>): readiness playable, visibility public, made by a person, and owned by an app other than Live (Live's own VODs and clips are live.index_document, type vod or clip, on Live's pages). Sent whenever what Search should hold changed; a VOD or clip that is deleted, made private or stops being playable gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:media.",
"allOf": [
{
"$ref": "../../search/index-document.v1.json"
ddiff --git a/generated/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex 51c224e1..b51df302 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -6701,11 +6701,11 @@ export interface WikiIndexDocumentDeletedPayload {
/** [email protected] (owner: live) */
/**
-- * live.index_document.upserted v1 (OpenVibe.Live server/events/search-documents.js; roadmap WS-O task 10). The OpenVibe.Search document of A streamer's channel page (openvibe.live/@username): its name, bio, what it streams and whether it is live. Sent whenever what Search should hold changed; a banned channel, or one that stopped streaming for good, gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:live.
++ * live.index_document.upserted v1 (OpenVibe.Live server/events/search-documents.js; roadmap WS-O task 10). The OpenVibe.Search document of one of Live's canonical pages: a streamer's channel (type channel, openvibe.live/@username: its name, bio, what it streams and whether it is live), or a public VOD or clip of a Live stream (types vod and clip, openvibe.live/vod/<id> and /clip/<id>: title, channel, AI overview and transcript; the id is the Media id; AI clips are noindex). Sent whenever what Search should hold changed; a banned channel, or a VOD or clip that is deleted, made private or failed, gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:live.
*/
export type LiveIndexDocumentUpsertedPayload = IndexDocument & {
owner: "live";
-- type: "channel";
++ type: "channel" | "vod" | "clip";
id?: string;
deleted: false;
};
@@@ -6715,7 +6715,7 @@ export type LiveIndexDocumentUpsertedPayload = IndexDocument & {
* live.index_document.deleted v1 (OpenVibe.Live server/events/search-documents.js; roadmap WS-O task 10). A Search tombstone: Search drops the document at this revision or older. Only sent for a document Search was sent before. Envelope: subject { type, id, revision }, visibility internal, actor service:live.
*/
export interface LiveIndexDocumentDeletedPayload {
-- type: "channel";
++ type: "channel" | "vod" | "clip";
id: string;
/**
* Index revision of the tombstone; wins over any document at the same or an older revision.
@@@ -6725,7 +6725,7 @@ export interface LiveIndexDocumentDeletedPayload {
/** [email protected] (owner: media) */
/**
-- * media.index_document.upserted v1 (OpenVibe.Media; roadmap WS-O task 10). The OpenVibe.Search document of A public, playable VOD or clip page on openvibe.media (readiness playable, visibility public). Sent whenever what Search should hold changed; a VOD or clip that is deleted, made private or stops being playable gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:media.
++ * media.index_document.upserted v1 (OpenVibe.Media; roadmap WS-O task 10). The OpenVibe.Search document of a public, playable VOD or clip whose canonical page is on openvibe.media (openvibe.media/v/<id>, /c/<id>): readiness playable, visibility public, made by a person, and owned by an app other than Live (Live's own VODs and clips are live.index_document, type vod or clip, on Live's pages). Sent whenever what Search should hold changed; a VOD or clip that is deleted, made private or stops being playable gets a tombstone. The revision grows with every change. Consumed by OpenVibe.Search ('*.index_document.*'). Envelope: subject { type, id, revision: <document revision> }, visibility internal, actor service:media.
*/
export type MediaIndexDocumentUpsertedPayload = IndexDocument & {
owner: "media";
ddiff --git a/package-lock.json b/package-lock.json
iindex 30f0876b..d67fbe48 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,17 +1,20 @@
{
"name": "openvibe-contracts",
-- "version": "0.44.0",
++ "version": "0.45.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.44.0",
++ "version": "0.45.0",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1"
},
++ "bin": {
++ "openvibe-contracts-check": "bin/check-service.js"
++ },
"devDependencies": {
"json-schema-to-typescript": "^15.0.4"
},
ddiff --git a/package.json b/package.json
iindex 03ec5f37..6c820a78 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.44.0",
++ "version": "0.45.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",