openvibers/openvibe.contracts Commits
Contracts 0.103.0: schemas for Chat's site-daily, first-chat and sound-by-command reads; planned network.resource.read (#48)
Changes
@@@ -4,6 +4,27 @@ 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.103.0 — 2026-10-05++++**Chat's three new internal reads and Network's resource index** (Chat PR #24; ADR-048). Additive: three new chat result++contracts and one planned capability, two capability route lists extended, no existing schema broken.++- `chat.site-daily-result@1` (new, owner `chat`, first-party): the answer of `POST /internal/chat/stats` with++ `kind: "site-daily"` — `{ days: [{ day, messages, chatters }] }`, one UTC day per entry in `[since, until)`,++ zero-filled, at most 400 — Live's home series. `chat.stats-request@1` gained `site-daily` in its kind `enum`, with++ the per-kind `allOf` rule that both `since` and `until` are required, the way its `user` and `stream` kinds already++ express their required field.++- `chat.first-chat-result@1` (`{ first }`, Live's welcome check) and `chat.sound-result@1` (`{ sound }`, reusing++ `chat.sounds-result@1`'s sound projection) are the answers of the other two reads. All three follow the other++ `chat.*` internal-read schemas: an `anyOf` of the ok shape and `chat.ingress-ack@1`'s error, with valid and++ invalid fixtures.++- Capabilities: `GET /internal/chat/first-chat` joins `chat.analysis.read`'s routes and++ `GET /internal/chat/sounds/by-command` joins `chat.sounds.read`'s.++- `network.resource.read` (new, owner `network`, first-party, **planned**): OpenVibe.Network's resource index++ (ADR-048 section 3) — `GET /api/v1/resources` answers `common.resource-list-result@1` and++ `GET /api/v1/resources/:ovrn` answers `common.resource-summary@1`; listed in `manifests/services/network.json`.++ The T2 Fabric offer registry's public routes, today sharing `/api/v1/resources`, move to `/api/v1/offers` in++ Network's own release; no Contracts manifest listed those public routes, so no route list changed here.++## 0.102.0 — 2026-10-05**The Watch contracts** (plan T18). Additive: eight new planned contracts, four planned capabilities and the Watch placeholder manifest, no existing schema changed.@@@ -9,7 +9,7 @@"plan": "OpenVibe Development Roadmap (combined), Wave 1; implementation plan rev 3 section 3.1","deployed": false,"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",-- "contracts": "openvibe-contracts v0.102.0 (this package; the newest tag)",++ "contracts": "openvibe-contracts v0.103.0 (this package; the newest tag)","features": ["589 JSON Schemas with valid and invalid fixtures","31 service manifests with lifecycle declarations",@@@ -23,7 +23,9 @@"generated estate: docs/ESTATE.md and manifests/repositories/ from the checkouts (scripts/estate.js; --check fails on drift)","chat.ticket-conversation@1 and the planned chat.ticket.write capability: a per-ticket conversation keyed by ticket id and calling service, with author_kind person|agent|staff","platform.task@1 (planned, owner network) and ADR-044: one task at OpenVibe.Actor's router with a mode, a per-task and per-day budget, result, cost and explanation, SSE progress, cancel and webhooks",-- "watch.watch@1 and the other Watch contracts (plan T18, planned), three watch events, four capabilities and the placeholder service manifest: user-defined persistent observations over pages, feeds, APIs, events and devices"++ "watch.watch@1 and the other Watch contracts (plan T18, planned), three watch events, four capabilities and the placeholder service manifest: user-defined persistent observations over pages, feeds, APIs, events and devices",++ "chat.site-daily-result@1, chat.first-chat-result@1 and chat.sound-result@1: Chat's three new internal reads (kind site-daily for Live's home series, the welcome check, and the sound a !command plays), with chat.stats-request@1 now accepting kind site-daily and the two route lists extended",++ "network.resource.read (planned, ADR-048): OpenVibe.Network's resource index, GET /api/v1/resources (common.resource-list-result@1) and GET /api/v1/resources/:ovrn (common.resource-summary@1)"],"updated": "2026-10-05"}@@@ -4728,6 +4728,15 @@"compatibility": "backward","status": "active"},++ {++ "id": "chat.site-daily-result",++ "version": "1.0.0",++ "owner": "chat",++ "schema": "chat/site-daily-result.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },{"id": "chat.messages-page","version": "1.0.0",@@@ -4746,6 +4755,15 @@"compatibility": "backward","status": "active"},++ {++ "id": "chat.first-chat-result",++ "version": "1.0.0",++ "owner": "chat",++ "schema": "chat/first-chat-result.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },{"id": "chat.moderation-queue-result","version": "1.0.0",@@@ -4764,6 +4782,15 @@"compatibility": "backward","status": "active"},++ {++ "id": "chat.sound-result",++ "version": "1.0.0",++ "owner": "chat",++ "schema": "chat/sound-result.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },{"id": "chat.sound-asset-request","version": "1.0.0",nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/first-chat-result.v1.json",++ "title": "ChatFirstChatResult",++ "description": "chat.first-chat-result@1: the answer of GET /internal/chat/first-chat?channel_id&identity on OpenVibe.Chat (capability chat.analysis.read), OpenVibe.Live's welcome check (isFirstChatInChannel): first is true when identity (user:<user_id>, anon:<anonId> or ext:<prefixed username>) has never chatted in the channel, from stream_first_chats, and false when it has. channel_id is the channel owner's Live user id (stream_first_chats.channel_user_id), not Chat's ctx_channels.id. A failure is chat.ingress-ack@1's error.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "first"++ ],++ "additionalProperties": false,++ "properties": {++ "ok": {++ "const": true++ },++ "first": {++ "type": "boolean"++ }++ }++ },++ {++ "$ref": "ingress-ack.v1.json#/$defs/error"++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,58 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/site-daily-result.v1.json",++ "title": "ChatSiteDailyResult",++ "description": "chat.site-daily-result@1: the answer of POST /internal/chat/stats with kind site-daily on OpenVibe.Chat (capability chat.stats.read), for OpenVibe.Live's home series: every non-deleted message across all channels and the distinct chatters (COALESCE(user_id, anon_id, source_platform || username)) per UTC day in [since, until), one entry per day with zero-filled gaps, at most 400 days. A failure is chat.ingress-ack@1's error.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "days"++ ],++ "additionalProperties": false,++ "properties": {++ "ok": {++ "const": true++ },++ "days": {++ "type": "array",++ "maxItems": 400,++ "items": {++ "$ref": "#/$defs/day"++ }++ }++ }++ },++ {++ "$ref": "ingress-ack.v1.json#/$defs/error"++ }++ ],++ "$defs": {++ "day": {++ "type": "object",++ "required": [++ "day",++ "messages",++ "chatters"++ ],++ "additionalProperties": false,++ "properties": {++ "day": {++ "type": "string",++ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",++ "description": "UTC calendar day, 'YYYY-MM-DD'."++ },++ "messages": {++ "type": "integer",++ "minimum": 0,++ "description": "Non-deleted messages that day, any message_type."++ },++ "chatters": {++ "type": "integer",++ "minimum": 0,++ "description": "Distinct chatters that day (registered, anonymous or relayed)."++ }++ }++ }++ }++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/sound-result.v1.json",++ "title": "ChatSoundResult",++ "description": "chat.sound-result@1: the answer of GET /internal/chat/sounds/by-command?channel_id&command on OpenVibe.Chat (capability chat.sounds.read): the approved channel sound a !command plays, one at random when several match (OpenVibe.Live's getChannelSoundByCommand), projected exactly as chat.sounds-result@1's sound. channel_id is the channel owner's Live user id (channel_sounds.channel_owner_id). An unknown command or channel is a 404, answered as chat.ingress-ack@1's error.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "sound"++ ],++ "additionalProperties": false,++ "properties": {++ "ok": {++ "const": true++ },++ "sound": {++ "$ref": "sounds-result.v1.json#/$defs/sound"++ }++ }++ },++ {++ "$ref": "ingress-ack.v1.json#/$defs/error"++ }++ ]++}@@@ -2,7 +2,7 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/chat/stats-request.v1.json","title": "ChatStatsRequest",-- "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",++ "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given; site-daily one row per UTC day in [since, until), zero-filled, a kind that takes only since and until. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.","type": "object","required": ["kind"@@@ -15,7 +15,8 @@"site","user","stream",-- "channel-top"++ "channel-top",++ "site-daily"]},"user_id": {@@@ -84,6 +85,24 @@"stream_id"]}++ },++ {++ "if": {++ "properties": {++ "kind": {++ "const": "site-daily"++ }++ },++ "required": [++ "kind"++ ]++ },++ "then": {++ "required": [++ "since",++ "until"++ ]++ }}]}@@@ -2,7 +2,7 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/chat/stats-result.v1.json","title": "ChatStatsResult",-- "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",++ "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first; the kind site-daily is answered by chat.site-daily-result@1, not here. A failure is chat.ingress-ack@1's error ({ ok: false, error }).","anyOf": [{"type": "object",nnew file mode 100644@@@ -0,0 +1,3 @@++{++ "ok": true++}nnew file mode 100644@@@ -0,0 +1,4 @@++{++ "ok": true,++ "first": true++}nnew file mode 100644@@@ -0,0 +1,9 @@++{++ "days": [++ {++ "day": "2026-10-03",++ "messages": -1,++ "chatters": 96++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,15 @@++{++ "ok": true,++ "days": [++ {++ "day": "2026-10-03",++ "messages": 1834,++ "chatters": 96++ },++ {++ "day": "2026-10-04",++ "messages": 0,++ "chatters": 0++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,13 @@++{++ "sound": {++ "id": 904,++ "channel_owner_id": 77,++ "command": "airhorn",++ "mime": "audio/mpeg",++ "duration_seconds": 2.4,++ "created_by": 512,++ "created_by_name": "pixelfox",++ "media_url": null,++ "media_asset_id": null++ }++}nnew file mode 100644@@@ -0,0 +1,15 @@++{++ "ok": true,++ "sound": {++ "id": 904,++ "channel_owner_id": 77,++ "command": "airhorn",++ "url": "/sounds/77/airhorn.mp3",++ "mime": "audio/mpeg",++ "duration_seconds": 2.4,++ "created_by": 512,++ "created_by_name": "pixelfox",++ "media_url": "https://media.openvibe.network/med_01K6R3A1B2C3D4E5F6G7H8J9KA",++ "media_asset_id": 4402++ }++}nnew file mode 100644@@@ -0,0 +1,4 @@++{++ "kind": "site-daily",++ "since": 1759449600000++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "kind": "site-daily",++ "since": 1759449600000,++ "until": 1759622400000++}@@@ -52906,7 +52906,7 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/chat/stats-request.v1.json","title": "ChatStatsRequest",-- "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",++ "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given; site-daily one row per UTC day in [since, until), zero-filled, a kind that takes only since and until. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.","type": "object","required": ["kind"@@@ -52919,7 +52919,8 @@"site","user","stream",-- "channel-top"++ "channel-top",++ "site-daily"]},"user_id": {@@@ -52988,6 +52989,24 @@"stream_id"]}++ },++ {++ "if": {++ "properties": {++ "kind": {++ "const": "site-daily"++ }++ },++ "required": [++ "kind"++ ]++ },++ "then": {++ "required": [++ "since",++ "until"++ ]++ }}]}@@@ -53000,7 +53019,7 @@"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://openvibe.network/contracts/chat/stats-result.v1.json","title": "ChatStatsResult",-- "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",++ "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first; the kind site-daily is answered by chat.site-daily-result@1, not here. A failure is chat.ingress-ack@1's error ({ ok: false, error }).","anyOf": [{"type": "object",@@@ -53085,6 +53104,69 @@}}},++ "chat.site-daily-result": {++ "version": "1.0.0",++ "owner": "chat",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/site-daily-result.v1.json",++ "title": "ChatSiteDailyResult",++ "description": "chat.site-daily-result@1: the answer of POST /internal/chat/stats with kind site-daily on OpenVibe.Chat (capability chat.stats.read), for OpenVibe.Live's home series: every non-deleted message across all channels and the distinct chatters (COALESCE(user_id, anon_id, source_platform || username)) per UTC day in [since, until), one entry per day with zero-filled gaps, at most 400 days. A failure is chat.ingress-ack@1's error.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "days"++ ],++ "additionalProperties": false,++ "properties": {++ "ok": {++ "const": true++ },++ "days": {++ "type": "array",++ "maxItems": 400,++ "items": {++ "$ref": "#/$defs/day"++ }++ }++ }++ },++ {++ "$ref": "ingress-ack.v1.json#/$defs/error"++ }++ ],++ "$defs": {++ "day": {++ "type": "object",++ "required": [++ "day",++ "messages",++ "chatters"++ ],++ "additionalProperties": false,++ "properties": {++ "day": {++ "type": "string",++ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",++ "description": "UTC calendar day, 'YYYY-MM-DD'."++ },++ "messages": {++ "type": "integer",++ "minimum": 0,++ "description": "Non-deleted messages that day, any message_type."++ },++ "chatters": {++ "type": "integer",++ "minimum": 0,++ "description": "Distinct chatters that day (registered, anonymous or relayed)."++ }++ }++ }++ }++ }++ },"chat.messages-page": {"version": "1.0.0","owner": "chat",@@@ -53289,6 +53371,37 @@]}},++ "chat.first-chat-result": {++ "version": "1.0.0",++ "owner": "chat",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/first-chat-result.v1.json",++ "title": "ChatFirstChatResult",++ "description": "chat.first-chat-result@1: the answer of GET /internal/chat/first-chat?channel_id&identity on OpenVibe.Chat (capability chat.analysis.read), OpenVibe.Live's welcome check (isFirstChatInChannel): first is true when identity (user:<user_id>, anon:<anonId> or ext:<prefixed username>) has never chatted in the channel, from stream_first_chats, and false when it has. channel_id is the channel owner's Live user id (stream_first_chats.channel_user_id), not Chat's ctx_channels.id. A failure is chat.ingress-ack@1's error.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "first"++ ],++ "additionalProperties": false,++ "properties": {++ "ok": {++ "const": true++ },++ "first": {++ "type": "boolean"++ }++ }++ },++ {++ "$ref": "ingress-ack.v1.json#/$defs/error"++ }++ ]++ }++ },"chat.moderation-queue-result": {"version": "1.0.0","owner": "chat",@@@ -53705,6 +53818,37 @@}}},++ "chat.sound-result": {++ "version": "1.0.0",++ "owner": "chat",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/chat/sound-result.v1.json",++ "title": "ChatSoundResult",++ "description": "chat.sound-result@1: the answer of GET /internal/chat/sounds/by-command?channel_id&command on OpenVibe.Chat (capability chat.sounds.read): the approved channel sound a !command plays, one at random when several match (OpenVibe.Live's getChannelSoundByCommand), projected exactly as chat.sounds-result@1's sound. channel_id is the channel owner's Live user id (channel_sounds.channel_owner_id). An unknown command or channel is a 404, answered as chat.ingress-ack@1's error.",++ "anyOf": [++ {++ "type": "object",++ "required": [++ "sound"++ ],++ "additionalProperties": false,++ "properties": {++ "ok": {++ "const": true++ },++ "sound": {++ "$ref": "sounds-result.v1.json#/$defs/sound"++ }++ }++ },++ {++ "$ref": "ingress-ack.v1.json#/$defs/error"++ }++ ]++ }++ },"chat.sound-asset-request": {"version": "1.0.0","owner": "chat",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.AI API",-- "version": "0.102.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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"@@@ -72,6 +72,52 @@}}},++ "/internal/chat/first-chat": {++ "get": {++ "operationId": "get_internal_chat_first_chat",++ "summary": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the c",++ "description": "**chat.analysis.read** (internal): Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the channel welcome check (GET /internal/chat/first-chat: whether an identity has chatted in the channel before). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",++ "tags": [++ "chat.analysis"++ ],++ "x-openvibe-capabilities": [++ "chat.analysis.read"++ ],++ "x-openvibe-visibility": [++ "internal"++ ],++ "x-openvibe-quota-class": "internal-read",++ "security": [++ {++ "openvibeToken": [++ "chat.analysis.read"++ ]++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.timeline-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },"/internal/chat/invalidate": {"post": {"operationId": "post_internal_chat_invalidate",@@@ -580,6 +626,52 @@}}},++ "/internal/chat/sounds/by-command": {++ "get": {++ "operationId": "get_internal_chat_sounds_by_command",++ "summary": "Count a channel's custom sounds, or list the sounds not yet uploaded to OpenVibe.Media, from OpenVibe.Chat's channel_sounds: for OpenVibe.Live's channel readiness and its Media asset sync (plan T3, J4",++ "description": "**chat.sounds.read** (internal): Count a channel's custom sounds, or list the sounds not yet uploaded to OpenVibe.Media, from OpenVibe.Chat's channel_sounds: for OpenVibe.Live's channel readiness and its Media asset sync (plan T3, J4b). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",++ "tags": [++ "chat.sounds"++ ],++ "x-openvibe-capabilities": [++ "chat.sounds.read"++ ],++ "x-openvibe-visibility": [++ "internal"++ ],++ "x-openvibe-quota-class": "internal-read",++ "security": [++ {++ "openvibeToken": [++ "chat.sounds.read"++ ]++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/chat.sounds-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },"/internal/chat/stats": {"post": {"operationId": "post_internal_chat_stats",@@@ -639,8 +731,8 @@"/internal/chat/timeline": {"get": {"operationId": "get_internal_chat_timeline",-- "summary": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b).",-- "description": "**chat.analysis.read** (internal): Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",++ "summary": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the c",++ "description": "**chat.analysis.read** (internal): Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the channel welcome check (GET /internal/chat/first-chat: whether an identity has chatted in the channel before). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.","tags": ["chat.analysis"],@@@ -4108,7 +4200,7 @@},"chat.stats-request.v1": {"title": "ChatStatsRequest",-- "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",++ "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given; site-daily one row per UTC day in [since, until), zero-filled, a kind that takes only since and until. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.","type": "object","required": ["kind"@@@ -4121,7 +4213,8 @@"site","user","stream",-- "channel-top"++ "channel-top",++ "site-daily"]},"user_id": {@@@ -4190,12 +4283,30 @@"stream_id"]}++ },++ {++ "if": {++ "properties": {++ "kind": {++ "const": "site-daily"++ }++ },++ "required": [++ "kind"++ ]++ },++ "then": {++ "required": [++ "since",++ "until"++ ]++ }}]},"chat.stats-result.v1": {"title": "ChatStatsResult",-- "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",++ "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first; the kind site-daily is answered by chat.site-daily-result@1, not here. A failure is chat.ingress-ack@1's error ({ ok: false, error }).","anyOf": [{"type": "object",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Codes API",-- "version": "0.102.0",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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"@@@ -33,7 +33,7 @@"service": "chat","name": "OpenVibe.Chat","origin": "https://openvibe.chat",-- "operations": 17,++ "operations": 19,"capabilities": 11},{@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Live API",-- "version": "0.102.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenRe.Stream API",-- "version": "0.102.0",-- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Space API",-- "version": "0.102.0",-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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"@@@ -51164,12 +51164,12 @@ export type ChatEmoteCountResult =/** [email protected] (owner: chat) *//**-- * chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.++ * chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given; site-daily one row per UTC day in [since, until), zero-filled, a kind that takes only since and until. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.*/export type ChatStatsRequest = {[k: string]: unknown | undefined;} & {-- kind: "site" | "user" | "stream" | "channel-top";++ kind: "site" | "user" | "stream" | "channel-top" | "site-daily";/*** Live user id; required for kind user.*/@@@ -51198,7 +51198,7 @@ export type ChatStatsRequest = {/** [email protected] (owner: chat) *//**-- * chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first. A failure is chat.ingress-ack@1's error ({ ok: false, error }).++ * chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first; the kind site-daily is answered by chat.site-daily-result@1, not here. A failure is chat.ingress-ack@1's error ({ ok: false, error }).*/export type ChatStatsResult =| {@@@ -51238,6 +51238,39 @@ export type ChatStatsResult =error: string;};++/** [email protected] (owner: chat) */++/**++ * chat.site-daily-result@1: the answer of POST /internal/chat/stats with kind site-daily on OpenVibe.Chat (capability chat.stats.read), for OpenVibe.Live's home series: every non-deleted message across all channels and the distinct chatters (COALESCE(user_id, anon_id, source_platform || username)) per UTC day in [since, until), one entry per day with zero-filled gaps, at most 400 days. A failure is chat.ingress-ack@1's error.++ */++export type ChatSiteDailyResult =++ | {++ ok?: true;++ /**++ * @maxItems 400++ */++ days: {++ /**++ * UTC calendar day, 'YYYY-MM-DD'.++ */++ day: string;++ /**++ * Non-deleted messages that day, any message_type.++ */++ messages: number;++ /**++ * Distinct chatters that day (registered, anonymous or relayed).++ */++ chatters: number;++ }[];++ }++ | {++ ok: false;++ /**++ * A human-readable reason.++ */++ error: string;++ };++/** [email protected] (owner: chat) *//*** chat.messages-page@1: the answer of GET /internal/chat/messages on OpenVibe.Chat (capability chat.messages.read), which pages non-deleted chat_messages for OpenVibe.Live's AI context, clip and viewer jobs and its moderator search and history. Query: one filter of channel_user_id, stream_id, user_id, anon_id, username or id (one message), a cursor on id (after_id ascending, before_id descending), limit, and tail=1 (no rows, only max_id). max_id is the highest id matching the filter, null when none, so a caller can resume after it. A failure is chat.ingress-ack@1's error.@@@ -51311,6 +51344,23 @@ export type ChatTimelineResult =error: string;};++/** [email protected] (owner: chat) */++/**++ * chat.first-chat-result@1: the answer of GET /internal/chat/first-chat?channel_id&identity on OpenVibe.Chat (capability chat.analysis.read), OpenVibe.Live's welcome check (isFirstChatInChannel): first is true when identity (user:<user_id>, anon:<anonId> or ext:<prefixed username>) has never chatted in the channel, from stream_first_chats, and false when it has. channel_id is the channel owner's Live user id (stream_first_chats.channel_user_id), not Chat's ctx_channels.id. A failure is chat.ingress-ack@1's error.++ */++export type ChatFirstChatResult =++ | {++ ok?: true;++ first: boolean;++ }++ | {++ ok: false;++ /**++ * A human-readable reason.++ */++ error: string;++ };++/** [email protected] (owner: chat) *//*** chat.moderation-queue-result@1: what OpenVibe.Chat's moderation queue reads answer (capability chat.moderation.queue.read), one shape per route, for OpenVibe.Live's moderator pages: GET /internal/chat/moderation/pending-ip?channel_id → { pending_ip } (a channel's messages held for IP approval, status pending, oldest first); GET /internal/chat/moderation/relay-users?channel_id → { relay_users } (relay names hidden or banned on the channel or everywhere, newest first); GET /internal/chat/moderation/relay-users/:id → { relay_user } (one, null when unknown); GET /internal/chat/moderation/tts-override?identity_key → { tts_override } (null when none). Internal: rows carry IP addresses. A failure is chat.ingress-ack@1's error.@@@ -51454,6 +51504,52 @@ export type ChatSoundsResult =error: string;};++/** [email protected] (owner: chat) */++/**++ * chat.sound-result@1: the answer of GET /internal/chat/sounds/by-command?channel_id&command on OpenVibe.Chat (capability chat.sounds.read): the approved channel sound a !command plays, one at random when several match (OpenVibe.Live's getChannelSoundByCommand), projected exactly as chat.sounds-result@1's sound. channel_id is the channel owner's Live user id (channel_sounds.channel_owner_id). An unknown command or channel is a 404, answered as chat.ingress-ack@1's error.++ */++export type ChatSoundResult =++ | {++ ok?: true;++ /**++ * One channel_sounds row.++ */++ sound: {++ id: number;++ channel_owner_id: number;++ /**++ * The trigger word (no leading '!'), lowercased: the sound's name.++ */++ command: string;++ /**++ * Where Chat keeps the audio file (its on-disk path).++ */++ url: string;++ mime?: string | null;++ duration_seconds?: number | null;++ /**++ * The uploader's Live user id.++ */++ created_by?: number | null;++ created_by_name?: string | null;++ /**++ * The file's OpenVibe.Media URL; null until Live's asset sync uploaded it.++ */++ media_url: string | null;++ /**++ * The OpenVibe.Media asset id; null until uploaded.++ */++ media_asset_id: number | null;++ };++ }++ | {++ ok: false;++ /**++ * A human-readable reason.++ */++ error: string;++ };++/** [email protected] (owner: chat) *//*** chat.sound-asset-request@1: the body of POST /internal/chat/sounds/asset on OpenVibe.Chat (capability chat.sounds.write): after OpenVibe.Live's asset sync uploaded a channel sound to OpenVibe.Media, the asset is written back onto Chat's channel_sounds row id. Writing the same asset again is a no-op; an unknown id is 404. Answers chat.ingress-ack@1.@@@ -4,7 +4,7 @@"owner": "chat","status": "active","visibility": "internal",-- "description": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",++ "description": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the channel welcome check (GET /internal/chat/first-chat: whether an identity has chatted in the channel before). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.","permissions": ["chat:read"],@@@ -14,7 +14,8 @@"quotaClass": "internal-read","events": [],"implementedBy": [-- "GET /internal/chat/timeline"++ "GET /internal/chat/timeline",++ "GET /internal/chat/first-chat"],"inputSchema": "common.no-body@1","outputSchema": "chat.timeline-result@1"@@@ -14,7 +14,8 @@"quotaClass": "internal-read","events": [],"implementedBy": [-- "GET /internal/chat/sounds"++ "GET /internal/chat/sounds",++ "GET /internal/chat/sounds/by-command"],"inputSchema": "common.no-body@1","outputSchema": "chat.sounds-result@1"nnew file mode 100644@@@ -0,0 +1,22 @@++{++ "id": "network.resource.read",++ "version": "1.0",++ "owner": "network",++ "status": "planned",++ "visibility": "first-party",++ "description": "Read OpenVibe.Network's resource index (ADR-048): GET /api/v1/resources lists the resources Network owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:ovrn reads one by its OVRN (common.resource-summary@1). Every authority serves these for OpenVibe.Services to fan out and merge; Network's own resources today are its projects, apps, keys and nodes. Planned until Network ships the index; the T2 Fabric offer registry's public routes, today sharing /api/v1/resources, move to /api/v1/offers in the same release.",++ "permissions": [++ "resources:read"++ ],++ "resourceConstraints": [++ "none"++ ],++ "quotaClass": "standard",++ "events": [],++ "implementedBy": [++ "GET /api/v1/resources",++ "GET /api/v1/resources/:ovrn"++ ],++ "inputSchema": "common.no-body@1",++ "outputSchema": "common.resource-list-result@1"++}@@@ -57,6 +57,7 @@"network.project.manage","network.project.read","network.registry.read",++ "network.resource.read","network.resource.report","network.staff.read","network.status.incident"@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.102.0",++ "version": "0.103.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.102.0",++ "version": "0.103.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.102.0",++ "version": "0.103.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,27 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
@@ -4,6 +4,27 @@ 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.103.0 — 2026-10-05
+
+**Chat's three new internal reads and Network's resource index** (Chat PR #24; ADR-048). Additive: three new chat result
+contracts and one planned capability, two capability route lists extended, no existing schema broken.
+- `chat.site-daily-result@1` (new, owner `chat`, first-party): the answer of `POST /internal/chat/stats` with
+ `kind: "site-daily"` — `{ days: [{ day, messages, chatters }] }`, one UTC day per entry in `[since, until)`,
+ zero-filled, at most 400 — Live's home series. `chat.stats-request@1` gained `site-daily` in its kind `enum`, with
+ the per-kind `allOf` rule that both `since` and `until` are required, the way its `user` and `stream` kinds already
+ express their required field.
+- `chat.first-chat-result@1` (`{ first }`, Live's welcome check) and `chat.sound-result@1` (`{ sound }`, reusing
+ `chat.sounds-result@1`'s sound projection) are the answers of the other two reads. All three follow the other
+ `chat.*` internal-read schemas: an `anyOf` of the ok shape and `chat.ingress-ack@1`'s error, with valid and
+ invalid fixtures.
+- Capabilities: `GET /internal/chat/first-chat` joins `chat.analysis.read`'s routes and
+ `GET /internal/chat/sounds/by-command` joins `chat.sounds.read`'s.
+- `network.resource.read` (new, owner `network`, first-party, **planned**): OpenVibe.Network's resource index
+ (ADR-048 section 3) — `GET /api/v1/resources` answers `common.resource-list-result@1` and
+ `GET /api/v1/resources/:ovrn` answers `common.resource-summary@1`; listed in `manifests/services/network.json`.
+ The T2 Fabric offer registry's public routes, today sharing `/api/v1/resources`, move to `/api/v1/offers` in
+ Network's own release; no Contracts manifest listed those public routes, so no route list changed here.
+
## 0.102.0 — 2026-10-05
## 0.102.0 — 2026-10-05
**The Watch contracts** (plan T18). Additive: eight new planned contracts, four planned capabilities and the Watch placeholder manifest, no existing schema changed.
**The Watch contracts** (plan T18). Additive: eight new planned contracts, four planned capabilities and the Watch placeholder manifest, no existing schema changed.
@@ -9,7 +9,7 @@
@@ -9,7 +9,7 @@
"plan": "OpenVibe Development Roadmap (combined), Wave 1; implementation plan rev 3 section 3.1",
"plan": "OpenVibe Development Roadmap (combined), Wave 1; implementation plan rev 3 section 3.1",
"deployed": false,
"deployed": false,
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
- "contracts": "openvibe-contracts v0.102.0 (this package; the newest tag)",
+ "contracts": "openvibe-contracts v0.103.0 (this package; the newest tag)",
"features": [
"features": [
"589 JSON Schemas with valid and invalid fixtures",
"589 JSON Schemas with valid and invalid fixtures",
"31 service manifests with lifecycle declarations",
"31 service manifests with lifecycle declarations",
@@ -23,7 +23,9 @@
@@ -23,7 +23,9 @@
"generated estate: docs/ESTATE.md and manifests/repositories/ from the checkouts (scripts/estate.js; --check fails on drift)",
"generated estate: docs/ESTATE.md and manifests/repositories/ from the checkouts (scripts/estate.js; --check fails on drift)",
"chat.ticket-conversation@1 and the planned chat.ticket.write capability: a per-ticket conversation keyed by ticket id and calling service, with author_kind person|agent|staff",
"chat.ticket-conversation@1 and the planned chat.ticket.write capability: a per-ticket conversation keyed by ticket id and calling service, with author_kind person|agent|staff",
"platform.task@1 (planned, owner network) and ADR-044: one task at OpenVibe.Actor's router with a mode, a per-task and per-day budget, result, cost and explanation, SSE progress, cancel and webhooks",
"platform.task@1 (planned, owner network) and ADR-044: one task at OpenVibe.Actor's router with a mode, a per-task and per-day budget, result, cost and explanation, SSE progress, cancel and webhooks",
- "watch.watch@1 and the other Watch contracts (plan T18, planned), three watch events, four capabilities and the placeholder service manifest: user-defined persistent observations over pages, feeds, APIs, events and devices"
+ "watch.watch@1 and the other Watch contracts (plan T18, planned), three watch events, four capabilities and the placeholder service manifest: user-defined persistent observations over pages, feeds, APIs, events and devices",
+ "chat.site-daily-result@1, chat.first-chat-result@1 and chat.sound-result@1: Chat's three new internal reads (kind site-daily for Live's home series, the welcome check, and the sound a !command plays), with chat.stats-request@1 now accepting kind site-daily and the two route lists extended",
+ "network.resource.read (planned, ADR-048): OpenVibe.Network's resource index, GET /api/v1/resources (common.resource-list-result@1) and GET /api/v1/resources/:ovrn (common.resource-summary@1)"
],
],
"updated": "2026-10-05"
"updated": "2026-10-05"
}
}
@@ -4728,6 +4728,15 @@
@@ -4728,6 +4728,15 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "chat.site-daily-result",
+ "version": "1.0.0",
+ "owner": "chat",
+ "schema": "chat/site-daily-result.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
{
{
"id": "chat.messages-page",
"id": "chat.messages-page",
"version": "1.0.0",
"version": "1.0.0",
@@ -4746,6 +4755,15 @@
@@ -4746,6 +4755,15 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "chat.first-chat-result",
+ "version": "1.0.0",
+ "owner": "chat",
+ "schema": "chat/first-chat-result.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
{
{
"id": "chat.moderation-queue-result",
"id": "chat.moderation-queue-result",
"version": "1.0.0",
"version": "1.0.0",
@@ -4764,6 +4782,15 @@
@@ -4764,6 +4782,15 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "chat.sound-result",
+ "version": "1.0.0",
+ "owner": "chat",
+ "schema": "chat/sound-result.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
{
{
"id": "chat.sound-asset-request",
"id": "chat.sound-asset-request",
"version": "1.0.0",
"version": "1.0.0",
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/first-chat-result.v1.json",
+ "title": "ChatFirstChatResult",
+ "description": "chat.first-chat-result@1: the answer of GET /internal/chat/first-chat?channel_id&identity on OpenVibe.Chat (capability chat.analysis.read), OpenVibe.Live's welcome check (isFirstChatInChannel): first is true when identity (user:<user_id>, anon:<anonId> or ext:<prefixed username>) has never chatted in the channel, from stream_first_chats, and false when it has. channel_id is the channel owner's Live user id (stream_first_chats.channel_user_id), not Chat's ctx_channels.id. A failure is chat.ingress-ack@1's error.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "first"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "ok": {
+ "const": true
+ },
+ "first": {
+ "type": "boolean"
+ }
+ }
+ },
+ {
+ "$ref": "ingress-ack.v1.json#/$defs/error"
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/site-daily-result.v1.json",
+ "title": "ChatSiteDailyResult",
+ "description": "chat.site-daily-result@1: the answer of POST /internal/chat/stats with kind site-daily on OpenVibe.Chat (capability chat.stats.read), for OpenVibe.Live's home series: every non-deleted message across all channels and the distinct chatters (COALESCE(user_id, anon_id, source_platform || username)) per UTC day in [since, until), one entry per day with zero-filled gaps, at most 400 days. A failure is chat.ingress-ack@1's error.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "days"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "ok": {
+ "const": true
+ },
+ "days": {
+ "type": "array",
+ "maxItems": 400,
+ "items": {
+ "$ref": "#/$defs/day"
+ }
+ }
+ }
+ },
+ {
+ "$ref": "ingress-ack.v1.json#/$defs/error"
+ }
+ ],
+ "$defs": {
+ "day": {
+ "type": "object",
+ "required": [
+ "day",
+ "messages",
+ "chatters"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "day": {
+ "type": "string",
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
+ "description": "UTC calendar day, 'YYYY-MM-DD'."
+ },
+ "messages": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Non-deleted messages that day, any message_type."
+ },
+ "chatters": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Distinct chatters that day (registered, anonymous or relayed)."
+ }
+ }
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/sound-result.v1.json",
+ "title": "ChatSoundResult",
+ "description": "chat.sound-result@1: the answer of GET /internal/chat/sounds/by-command?channel_id&command on OpenVibe.Chat (capability chat.sounds.read): the approved channel sound a !command plays, one at random when several match (OpenVibe.Live's getChannelSoundByCommand), projected exactly as chat.sounds-result@1's sound. channel_id is the channel owner's Live user id (channel_sounds.channel_owner_id). An unknown command or channel is a 404, answered as chat.ingress-ack@1's error.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "sound"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "ok": {
+ "const": true
+ },
+ "sound": {
+ "$ref": "sounds-result.v1.json#/$defs/sound"
+ }
+ }
+ },
+ {
+ "$ref": "ingress-ack.v1.json#/$defs/error"
+ }
+ ]
+}
@@ -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/chat/stats-request.v1.json",
"$id": "https://openvibe.network/contracts/chat/stats-request.v1.json",
"title": "ChatStatsRequest",
"title": "ChatStatsRequest",
- "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",
+ "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given; site-daily one row per UTC day in [since, until), zero-filled, a kind that takes only since and until. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",
"type": "object",
"type": "object",
"required": [
"required": [
"kind"
"kind"
@@ -15,7 +15,8 @@
@@ -15,7 +15,8 @@
"site",
"site",
"user",
"user",
"stream",
"stream",
- "channel-top"
+ "channel-top",
+ "site-daily"
]
]
},
},
"user_id": {
"user_id": {
@@ -84,6 +85,24 @@
@@ -84,6 +85,24 @@
"stream_id"
"stream_id"
]
]
}
}
+ },
+ {
+ "if": {
+ "properties": {
+ "kind": {
+ "const": "site-daily"
+ }
+ },
+ "required": [
+ "kind"
+ ]
+ },
+ "then": {
+ "required": [
+ "since",
+ "until"
+ ]
+ }
}
}
]
]
}
}
@@ -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/chat/stats-result.v1.json",
"$id": "https://openvibe.network/contracts/chat/stats-result.v1.json",
"title": "ChatStatsResult",
"title": "ChatStatsResult",
- "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",
+ "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first; the kind site-daily is answered by chat.site-daily-result@1, not here. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
new file mode 100644
new file mode 100644
@@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
+{
+ "ok": true
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "ok": true,
+ "first": true
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
+{
+ "days": [
+ {
+ "day": "2026-10-03",
+ "messages": -1,
+ "chatters": 96
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
+{
+ "ok": true,
+ "days": [
+ {
+ "day": "2026-10-03",
+ "messages": 1834,
+ "chatters": 96
+ },
+ {
+ "day": "2026-10-04",
+ "messages": 0,
+ "chatters": 0
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
+{
+ "sound": {
+ "id": 904,
+ "channel_owner_id": 77,
+ "command": "airhorn",
+ "mime": "audio/mpeg",
+ "duration_seconds": 2.4,
+ "created_by": 512,
+ "created_by_name": "pixelfox",
+ "media_url": null,
+ "media_asset_id": null
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
+{
+ "ok": true,
+ "sound": {
+ "id": 904,
+ "channel_owner_id": 77,
+ "command": "airhorn",
+ "url": "/sounds/77/airhorn.mp3",
+ "mime": "audio/mpeg",
+ "duration_seconds": 2.4,
+ "created_by": 512,
+ "created_by_name": "pixelfox",
+ "media_url": "https://media.openvibe.network/med_01K6R3A1B2C3D4E5F6G7H8J9KA",
+ "media_asset_id": 4402
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "kind": "site-daily",
+ "since": 1759449600000
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "kind": "site-daily",
+ "since": 1759449600000,
+ "until": 1759622400000
+}
@@ -52906,7 +52906,7 @@
@@ -52906,7 +52906,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/chat/stats-request.v1.json",
"$id": "https://openvibe.network/contracts/chat/stats-request.v1.json",
"title": "ChatStatsRequest",
"title": "ChatStatsRequest",
- "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",
+ "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given; site-daily one row per UTC day in [since, until), zero-filled, a kind that takes only since and until. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",
"type": "object",
"type": "object",
"required": [
"required": [
"kind"
"kind"
@@ -52919,7 +52919,8 @@
@@ -52919,7 +52919,8 @@
"site",
"site",
"user",
"user",
"stream",
"stream",
- "channel-top"
+ "channel-top",
+ "site-daily"
]
]
},
},
"user_id": {
"user_id": {
@@ -52988,6 +52989,24 @@
@@ -52988,6 +52989,24 @@
"stream_id"
"stream_id"
]
]
}
}
+ },
+ {
+ "if": {
+ "properties": {
+ "kind": {
+ "const": "site-daily"
+ }
+ },
+ "required": [
+ "kind"
+ ]
+ },
+ "then": {
+ "required": [
+ "since",
+ "until"
+ ]
+ }
}
}
]
]
}
}
@@ -53000,7 +53019,7 @@
@@ -53000,7 +53019,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/chat/stats-result.v1.json",
"$id": "https://openvibe.network/contracts/chat/stats-result.v1.json",
"title": "ChatStatsResult",
"title": "ChatStatsResult",
- "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",
+ "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first; the kind site-daily is answered by chat.site-daily-result@1, not here. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
@@ -53085,6 +53104,69 @@
@@ -53085,6 +53104,69 @@
}
}
}
}
},
},
+ "chat.site-daily-result": {
+ "version": "1.0.0",
+ "owner": "chat",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/site-daily-result.v1.json",
+ "title": "ChatSiteDailyResult",
+ "description": "chat.site-daily-result@1: the answer of POST /internal/chat/stats with kind site-daily on OpenVibe.Chat (capability chat.stats.read), for OpenVibe.Live's home series: every non-deleted message across all channels and the distinct chatters (COALESCE(user_id, anon_id, source_platform || username)) per UTC day in [since, until), one entry per day with zero-filled gaps, at most 400 days. A failure is chat.ingress-ack@1's error.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "days"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "ok": {
+ "const": true
+ },
+ "days": {
+ "type": "array",
+ "maxItems": 400,
+ "items": {
+ "$ref": "#/$defs/day"
+ }
+ }
+ }
+ },
+ {
+ "$ref": "ingress-ack.v1.json#/$defs/error"
+ }
+ ],
+ "$defs": {
+ "day": {
+ "type": "object",
+ "required": [
+ "day",
+ "messages",
+ "chatters"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "day": {
+ "type": "string",
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
+ "description": "UTC calendar day, 'YYYY-MM-DD'."
+ },
+ "messages": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Non-deleted messages that day, any message_type."
+ },
+ "chatters": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Distinct chatters that day (registered, anonymous or relayed)."
+ }
+ }
+ }
+ }
+ }
+ },
"chat.messages-page": {
"chat.messages-page": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "chat",
"owner": "chat",
@@ -53289,6 +53371,37 @@
@@ -53289,6 +53371,37 @@
]
]
}
}
},
},
+ "chat.first-chat-result": {
+ "version": "1.0.0",
+ "owner": "chat",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/first-chat-result.v1.json",
+ "title": "ChatFirstChatResult",
+ "description": "chat.first-chat-result@1: the answer of GET /internal/chat/first-chat?channel_id&identity on OpenVibe.Chat (capability chat.analysis.read), OpenVibe.Live's welcome check (isFirstChatInChannel): first is true when identity (user:<user_id>, anon:<anonId> or ext:<prefixed username>) has never chatted in the channel, from stream_first_chats, and false when it has. channel_id is the channel owner's Live user id (stream_first_chats.channel_user_id), not Chat's ctx_channels.id. A failure is chat.ingress-ack@1's error.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "first"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "ok": {
+ "const": true
+ },
+ "first": {
+ "type": "boolean"
+ }
+ }
+ },
+ {
+ "$ref": "ingress-ack.v1.json#/$defs/error"
+ }
+ ]
+ }
+ },
"chat.moderation-queue-result": {
"chat.moderation-queue-result": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "chat",
"owner": "chat",
@@ -53705,6 +53818,37 @@
@@ -53705,6 +53818,37 @@
}
}
}
}
},
},
+ "chat.sound-result": {
+ "version": "1.0.0",
+ "owner": "chat",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/chat/sound-result.v1.json",
+ "title": "ChatSoundResult",
+ "description": "chat.sound-result@1: the answer of GET /internal/chat/sounds/by-command?channel_id&command on OpenVibe.Chat (capability chat.sounds.read): the approved channel sound a !command plays, one at random when several match (OpenVibe.Live's getChannelSoundByCommand), projected exactly as chat.sounds-result@1's sound. channel_id is the channel owner's Live user id (channel_sounds.channel_owner_id). An unknown command or channel is a 404, answered as chat.ingress-ack@1's error.",
+ "anyOf": [
+ {
+ "type": "object",
+ "required": [
+ "sound"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "ok": {
+ "const": true
+ },
+ "sound": {
+ "$ref": "sounds-result.v1.json#/$defs/sound"
+ }
+ }
+ },
+ {
+ "$ref": "ingress-ack.v1.json#/$defs/error"
+ }
+ ]
+ }
+ },
"chat.sound-asset-request": {
"chat.sound-asset-request": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "chat",
"owner": "chat",
@@ -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.102.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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"
@@ -72,6 +72,52 @@
@@ -72,6 +72,52 @@
}
}
}
}
},
},
+ "/internal/chat/first-chat": {
+ "get": {
+ "operationId": "get_internal_chat_first_chat",
+ "summary": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the c",
+ "description": "**chat.analysis.read** (internal): Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the channel welcome check (GET /internal/chat/first-chat: whether an identity has chatted in the channel before). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",
+ "tags": [
+ "chat.analysis"
+ ],
+ "x-openvibe-capabilities": [
+ "chat.analysis.read"
+ ],
+ "x-openvibe-visibility": [
+ "internal"
+ ],
+ "x-openvibe-quota-class": "internal-read",
+ "security": [
+ {
+ "openvibeToken": [
+ "chat.analysis.read"
+ ]
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.timeline-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/internal/chat/invalidate": {
"/internal/chat/invalidate": {
"post": {
"post": {
"operationId": "post_internal_chat_invalidate",
"operationId": "post_internal_chat_invalidate",
@@ -580,6 +626,52 @@
@@ -580,6 +626,52 @@
}
}
}
}
},
},
+ "/internal/chat/sounds/by-command": {
+ "get": {
+ "operationId": "get_internal_chat_sounds_by_command",
+ "summary": "Count a channel's custom sounds, or list the sounds not yet uploaded to OpenVibe.Media, from OpenVibe.Chat's channel_sounds: for OpenVibe.Live's channel readiness and its Media asset sync (plan T3, J4",
+ "description": "**chat.sounds.read** (internal): Count a channel's custom sounds, or list the sounds not yet uploaded to OpenVibe.Media, from OpenVibe.Chat's channel_sounds: for OpenVibe.Live's channel readiness and its Media asset sync (plan T3, J4b). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",
+ "tags": [
+ "chat.sounds"
+ ],
+ "x-openvibe-capabilities": [
+ "chat.sounds.read"
+ ],
+ "x-openvibe-visibility": [
+ "internal"
+ ],
+ "x-openvibe-quota-class": "internal-read",
+ "security": [
+ {
+ "openvibeToken": [
+ "chat.sounds.read"
+ ]
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/chat.sounds-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/internal/chat/stats": {
"/internal/chat/stats": {
"post": {
"post": {
"operationId": "post_internal_chat_stats",
"operationId": "post_internal_chat_stats",
@@ -639,8 +731,8 @@
@@ -639,8 +731,8 @@
"/internal/chat/timeline": {
"/internal/chat/timeline": {
"get": {
"get": {
"operationId": "get_internal_chat_timeline",
"operationId": "get_internal_chat_timeline",
- "summary": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b).",
- "description": "**chat.analysis.read** (internal): Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",
+ "summary": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the c",
+ "description": "**chat.analysis.read** (internal): Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the channel welcome check (GET /internal/chat/first-chat: whether an identity has chatted in the channel before). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",
"tags": [
"tags": [
"chat.analysis"
"chat.analysis"
],
],
@@ -4108,7 +4200,7 @@
@@ -4108,7 +4200,7 @@
},
},
"chat.stats-request.v1": {
"chat.stats-request.v1": {
"title": "ChatStatsRequest",
"title": "ChatStatsRequest",
- "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",
+ "description": "chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given; site-daily one row per UTC day in [since, until), zero-filled, a kind that takes only since and until. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.",
"type": "object",
"type": "object",
"required": [
"required": [
"kind"
"kind"
@@ -4121,7 +4213,8 @@
@@ -4121,7 +4213,8 @@
"site",
"site",
"user",
"user",
"stream",
"stream",
- "channel-top"
+ "channel-top",
+ "site-daily"
]
]
},
},
"user_id": {
"user_id": {
@@ -4190,12 +4283,30 @@
@@ -4190,12 +4283,30 @@
"stream_id"
"stream_id"
]
]
}
}
+ },
+ {
+ "if": {
+ "properties": {
+ "kind": {
+ "const": "site-daily"
+ }
+ },
+ "required": [
+ "kind"
+ ]
+ },
+ "then": {
+ "required": [
+ "since",
+ "until"
+ ]
+ }
}
}
]
]
},
},
"chat.stats-result.v1": {
"chat.stats-result.v1": {
"title": "ChatStatsResult",
"title": "ChatStatsResult",
- "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",
+ "description": "chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first; the kind site-daily is answered by chat.site-daily-result@1, not here. A failure is chat.ingress-ack@1's error ({ ok: false, error }).",
"anyOf": [
"anyOf": [
{
{
"type": "object",
"type": "object",
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Codes API",
"title": "OpenVibe.Codes API",
- "version": "0.102.0",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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"
@@ -33,7 +33,7 @@
@@ -33,7 +33,7 @@
"service": "chat",
"service": "chat",
"name": "OpenVibe.Chat",
"name": "OpenVibe.Chat",
"origin": "https://openvibe.chat",
"origin": "https://openvibe.chat",
- "operations": 17,
+ "operations": 19,
"capabilities": 11
"capabilities": 11
},
},
{
{
@@ -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.102.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenRe.Stream API",
"title": "OpenRe.Stream API",
- "version": "0.102.0",
- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Space API",
"title": "OpenVibe.Space API",
- "version": "0.102.0",
- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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.102.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for 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.103.0",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.103.0): each operation lists the capabilities it performs; a token for 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"
@@ -51164,12 +51164,12 @@ export type ChatEmoteCountResult =
@@ -51164,12 +51164,12 @@ export type ChatEmoteCountResult =
/** [email protected] (owner: chat) */
/** [email protected] (owner: chat) */
/**
/**
- * chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.
+ * chat.stats-request@1: the body of POST /internal/chat/stats on OpenVibe.Chat (capability chat.stats.read): one count over chat_messages, for the stats OpenVibe.Live shows without reading its own copy of Chat's tables (home and SEO stats, admin dashboard, star of the day, VOD and recap cards, stream analytics, top chatters, AI slogans). kind site counts all of chat; user one person's messages (user_id); stream one stream's messages, chatters and soundboard plays (stream_id); channel-top the top chatters, of one stream (stream_id) or one channel (channel_user_id), or of all chat when neither is given; site-daily one row per UTC day in [since, until), zero-filled, a kind that takes only since and until. since and until bound chat_messages.timestamp, epoch ms, until exclusive. Deleted messages are never counted. Loopback only, service token.
*/
*/
export type ChatStatsRequest = {
export type ChatStatsRequest = {
[k: string]: unknown | undefined;
[k: string]: unknown | undefined;
} & {
} & {
- kind: "site" | "user" | "stream" | "channel-top";
+ kind: "site" | "user" | "stream" | "channel-top" | "site-daily";
/**
/**
* Live user id; required for kind user.
* Live user id; required for kind user.
*/
*/
@@ -51198,7 +51198,7 @@ export type ChatStatsRequest = {
@@ -51198,7 +51198,7 @@ export type ChatStatsRequest = {
/** [email protected] (owner: chat) */
/** [email protected] (owner: chat) */
/**
/**
- * chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first. A failure is chat.ingress-ack@1's error ({ ok: false, error }).
+ * chat.stats-result@1: the answer of POST /internal/chat/stats (chat.stats.read). site, user and stream answer messages (non-deleted chat_messages rows) and chatters (distinct COALESCE(user_id, anon_id, source_platform || username)); stream also answers sounds (soundboard plays); channel-top answers top_chatters, most messages first; the kind site-daily is answered by chat.site-daily-result@1, not here. A failure is chat.ingress-ack@1's error ({ ok: false, error }).
*/
*/
export type ChatStatsResult =
export type ChatStatsResult =
| {
| {
@@ -51238,6 +51238,39 @@ export type ChatStatsResult =
@@ -51238,6 +51238,39 @@ export type ChatStatsResult =
error: string;
error: string;
};
};
+/** [email protected] (owner: chat) */
+/**
+ * chat.site-daily-result@1: the answer of POST /internal/chat/stats with kind site-daily on OpenVibe.Chat (capability chat.stats.read), for OpenVibe.Live's home series: every non-deleted message across all channels and the distinct chatters (COALESCE(user_id, anon_id, source_platform || username)) per UTC day in [since, until), one entry per day with zero-filled gaps, at most 400 days. A failure is chat.ingress-ack@1's error.
+ */
+export type ChatSiteDailyResult =
+ | {
+ ok?: true;
+ /**
+ * @maxItems 400
+ */
+ days: {
+ /**
+ * UTC calendar day, 'YYYY-MM-DD'.
+ */
+ day: string;
+ /**
+ * Non-deleted messages that day, any message_type.
+ */
+ messages: number;
+ /**
+ * Distinct chatters that day (registered, anonymous or relayed).
+ */
+ chatters: number;
+ }[];
+ }
+ | {
+ ok: false;
+ /**
+ * A human-readable reason.
+ */
+ error: string;
+ };
+
/** [email protected] (owner: chat) */
/** [email protected] (owner: chat) */
/**
/**
* chat.messages-page@1: the answer of GET /internal/chat/messages on OpenVibe.Chat (capability chat.messages.read), which pages non-deleted chat_messages for OpenVibe.Live's AI context, clip and viewer jobs and its moderator search and history. Query: one filter of channel_user_id, stream_id, user_id, anon_id, username or id (one message), a cursor on id (after_id ascending, before_id descending), limit, and tail=1 (no rows, only max_id). max_id is the highest id matching the filter, null when none, so a caller can resume after it. A failure is chat.ingress-ack@1's error.
* chat.messages-page@1: the answer of GET /internal/chat/messages on OpenVibe.Chat (capability chat.messages.read), which pages non-deleted chat_messages for OpenVibe.Live's AI context, clip and viewer jobs and its moderator search and history. Query: one filter of channel_user_id, stream_id, user_id, anon_id, username or id (one message), a cursor on id (after_id ascending, before_id descending), limit, and tail=1 (no rows, only max_id). max_id is the highest id matching the filter, null when none, so a caller can resume after it. A failure is chat.ingress-ack@1's error.
@@ -51311,6 +51344,23 @@ export type ChatTimelineResult =
@@ -51311,6 +51344,23 @@ export type ChatTimelineResult =
error: string;
error: string;
};
};
+/** [email protected] (owner: chat) */
+/**
+ * chat.first-chat-result@1: the answer of GET /internal/chat/first-chat?channel_id&identity on OpenVibe.Chat (capability chat.analysis.read), OpenVibe.Live's welcome check (isFirstChatInChannel): first is true when identity (user:<user_id>, anon:<anonId> or ext:<prefixed username>) has never chatted in the channel, from stream_first_chats, and false when it has. channel_id is the channel owner's Live user id (stream_first_chats.channel_user_id), not Chat's ctx_channels.id. A failure is chat.ingress-ack@1's error.
+ */
+export type ChatFirstChatResult =
+ | {
+ ok?: true;
+ first: boolean;
+ }
+ | {
+ ok: false;
+ /**
+ * A human-readable reason.
+ */
+ error: string;
+ };
+
/** [email protected] (owner: chat) */
/** [email protected] (owner: chat) */
/**
/**
* chat.moderation-queue-result@1: what OpenVibe.Chat's moderation queue reads answer (capability chat.moderation.queue.read), one shape per route, for OpenVibe.Live's moderator pages: GET /internal/chat/moderation/pending-ip?channel_id → { pending_ip } (a channel's messages held for IP approval, status pending, oldest first); GET /internal/chat/moderation/relay-users?channel_id → { relay_users } (relay names hidden or banned on the channel or everywhere, newest first); GET /internal/chat/moderation/relay-users/:id → { relay_user } (one, null when unknown); GET /internal/chat/moderation/tts-override?identity_key → { tts_override } (null when none). Internal: rows carry IP addresses. A failure is chat.ingress-ack@1's error.
* chat.moderation-queue-result@1: what OpenVibe.Chat's moderation queue reads answer (capability chat.moderation.queue.read), one shape per route, for OpenVibe.Live's moderator pages: GET /internal/chat/moderation/pending-ip?channel_id → { pending_ip } (a channel's messages held for IP approval, status pending, oldest first); GET /internal/chat/moderation/relay-users?channel_id → { relay_users } (relay names hidden or banned on the channel or everywhere, newest first); GET /internal/chat/moderation/relay-users/:id → { relay_user } (one, null when unknown); GET /internal/chat/moderation/tts-override?identity_key → { tts_override } (null when none). Internal: rows carry IP addresses. A failure is chat.ingress-ack@1's error.
@@ -51454,6 +51504,52 @@ export type ChatSoundsResult =
@@ -51454,6 +51504,52 @@ export type ChatSoundsResult =
error: string;
error: string;
};
};
+/** [email protected] (owner: chat) */
+/**
+ * chat.sound-result@1: the answer of GET /internal/chat/sounds/by-command?channel_id&command on OpenVibe.Chat (capability chat.sounds.read): the approved channel sound a !command plays, one at random when several match (OpenVibe.Live's getChannelSoundByCommand), projected exactly as chat.sounds-result@1's sound. channel_id is the channel owner's Live user id (channel_sounds.channel_owner_id). An unknown command or channel is a 404, answered as chat.ingress-ack@1's error.
+ */
+export type ChatSoundResult =
+ | {
+ ok?: true;
+ /**
+ * One channel_sounds row.
+ */
+ sound: {
+ id: number;
+ channel_owner_id: number;
+ /**
+ * The trigger word (no leading '!'), lowercased: the sound's name.
+ */
+ command: string;
+ /**
+ * Where Chat keeps the audio file (its on-disk path).
+ */
+ url: string;
+ mime?: string | null;
+ duration_seconds?: number | null;
+ /**
+ * The uploader's Live user id.
+ */
+ created_by?: number | null;
+ created_by_name?: string | null;
+ /**
+ * The file's OpenVibe.Media URL; null until Live's asset sync uploaded it.
+ */
+ media_url: string | null;
+ /**
+ * The OpenVibe.Media asset id; null until uploaded.
+ */
+ media_asset_id: number | null;
+ };
+ }
+ | {
+ ok: false;
+ /**
+ * A human-readable reason.
+ */
+ error: string;
+ };
+
/** [email protected] (owner: chat) */
/** [email protected] (owner: chat) */
/**
/**
* chat.sound-asset-request@1: the body of POST /internal/chat/sounds/asset on OpenVibe.Chat (capability chat.sounds.write): after OpenVibe.Live's asset sync uploaded a channel sound to OpenVibe.Media, the asset is written back onto Chat's channel_sounds row id. Writing the same asset again is a no-op; an unknown id is 404. Answers chat.ingress-ack@1.
* chat.sound-asset-request@1: the body of POST /internal/chat/sounds/asset on OpenVibe.Chat (capability chat.sounds.write): after OpenVibe.Live's asset sync uploaded a channel sound to OpenVibe.Media, the asset is written back onto Chat's channel_sounds row id. Writing the same asset again is a no-op; an unknown id is 404. Answers chat.ingress-ack@1.
@@ -4,7 +4,7 @@
@@ -4,7 +4,7 @@
"owner": "chat",
"owner": "chat",
"status": "active",
"status": "active",
"visibility": "internal",
"visibility": "internal",
- "description": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",
+ "description": "Count a channel's or a stream's chat messages per time bucket, with the latest message id: the chat timeline behind OpenVibe.Live's AI moments, chat spikes and activity reads (plan T3, J4b), and the channel welcome check (GET /internal/chat/first-chat: whether an identity has chatted in the channel before). Loopback only, Chat service token (Live's principal today); never granted to an app or delegated to an agent.",
"permissions": [
"permissions": [
"chat:read"
"chat:read"
],
],
@@ -14,7 +14,8 @@
@@ -14,7 +14,8 @@
"quotaClass": "internal-read",
"quotaClass": "internal-read",
"events": [],
"events": [],
"implementedBy": [
"implementedBy": [
- "GET /internal/chat/timeline"
+ "GET /internal/chat/timeline",
+ "GET /internal/chat/first-chat"
],
],
"inputSchema": "common.no-body@1",
"inputSchema": "common.no-body@1",
"outputSchema": "chat.timeline-result@1"
"outputSchema": "chat.timeline-result@1"
@@ -14,7 +14,8 @@
@@ -14,7 +14,8 @@
"quotaClass": "internal-read",
"quotaClass": "internal-read",
"events": [],
"events": [],
"implementedBy": [
"implementedBy": [
- "GET /internal/chat/sounds"
+ "GET /internal/chat/sounds",
+ "GET /internal/chat/sounds/by-command"
],
],
"inputSchema": "common.no-body@1",
"inputSchema": "common.no-body@1",
"outputSchema": "chat.sounds-result@1"
"outputSchema": "chat.sounds-result@1"
new file mode 100644
new file mode 100644
@@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
+{
+ "id": "network.resource.read",
+ "version": "1.0",
+ "owner": "network",
+ "status": "planned",
+ "visibility": "first-party",
+ "description": "Read OpenVibe.Network's resource index (ADR-048): GET /api/v1/resources lists the resources Network owns as a page of common.resource-summary@1 (common.resource-list-result@1), and GET /api/v1/resources/:ovrn reads one by its OVRN (common.resource-summary@1). Every authority serves these for OpenVibe.Services to fan out and merge; Network's own resources today are its projects, apps, keys and nodes. Planned until Network ships the index; the T2 Fabric offer registry's public routes, today sharing /api/v1/resources, move to /api/v1/offers in the same release.",
+ "permissions": [
+ "resources:read"
+ ],
+ "resourceConstraints": [
+ "none"
+ ],
+ "quotaClass": "standard",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/resources",
+ "GET /api/v1/resources/:ovrn"
+ ],
+ "inputSchema": "common.no-body@1",
+ "outputSchema": "common.resource-list-result@1"
+}
@@ -57,6 +57,7 @@
@@ -57,6 +57,7 @@
"network.project.manage",
"network.project.manage",
"network.project.read",
"network.project.read",
"network.registry.read",
"network.registry.read",
+ "network.resource.read",
"network.resource.report",
"network.resource.report",
"network.staff.read",
"network.staff.read",
"network.status.incident"
"network.status.incident"
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.102.0",
+ "version": "0.103.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.102.0",
+ "version": "0.103.0",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
"ajv": "^8.17.1",
"ajv": "^8.17.1",
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.102.0",
+ "version": "0.103.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",