openvibers/openvibe.contracts Commits
v0.39.0: network.user.token_valid_after (revocation propagation, WS-B task 4) — a person's tokens issued before valid_after are refused everywhere (iat * 1000 < valid_after, Network's rule) and their sockets closed; Network produces it on password change or reset, sign out everywhere, ban, deletion and staff revocation; Chat, Community, Live, Media, Tools and Games consume it; fixtures
Changes
@@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) thfrom `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,the notes were in the tag and commit messages (`git tag -n1`).++## 0.39.0 — 2026-09-24++++**`network.user.token_valid_after`** (revocation propagation, roadmap WS-B task 4): when a person's tokens stop being good (a password change or reset, sign out everywhere, a ban, an account deletion or staff ending their sessions), Network moves their cutoff and emits this event in the same transaction. Every service that accepts Network user tokens refuses one whose `iat * 1000 < Date.parse(valid_after)` (Network's own rule), drops what it cached for those tokens and closes the sockets they opened. Consumers keep the latest cutoff per subject. Network produces it; Chat, Community, Live, Media, Tools and Games consume it. Fixtures cover valid and invalid payloads. Additive.++## 0.38.0 — 2026-09-24Staff map 1.1.0 (ADR-022), so the content products and Games can check staff capabilities instead of comparing role names:@@@ -873,6 +873,15 @@"compatibility": "backward","status": "active"},++ {++ "id": "network.user.token_valid_after",++ "version": "1.0.0",++ "owner": "network",++ "schema": "events/payloads/network.user.token_valid_after.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },{"id": "tools.tool","version": "1.1.0",nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/network.user.token_valid_after.v1.json",++ "title": "NetworkUserTokenValidAfterPayload",++ "description": "network.user.token_valid_after v1 (OpenVibe.Network server/auth/revocation.js). A person's tokens issued before valid_after are no longer good: every service that accepts Network user tokens refuses one whose iat (seconds) * 1000 is less than valid_after (milliseconds), exactly as Network does, drops what it cached for that person's older tokens and closes the sockets they opened. Emitted in the transaction that moves the cutoff: a password change or reset, sign out everywhere, a ban, an account deletion, or staff ending someone's sessions. Consumers keep the latest valid_after per subject and ignore an older one (events can arrive out of order). Envelope: subject { type: user, id }, visibility internal, actor the person (their own change) or the staff member / system:network.",++ "type": "object",++ "required": ["subject", "valid_after", "reason"],++ "additionalProperties": false,++ "properties": {++ "subject": {++ "type": "object", "required": ["type", "id"], "additionalProperties": false,++ "properties": { "type": { "const": "user" }, "id": { "type": "string", "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$" } },++ "description": "The person (identity.subject-ref@1, a user)."++ },++ "valid_after": { "type": "string", "format": "date-time", "description": "Tokens issued before this instant are refused (compare iat * 1000 < Date.parse(valid_after))." },++ "reason": {++ "enum": ["password_changed", "password_reset", "signed_out_everywhere", "banned", "account_deleted", "staff_revoked"],++ "description": "Why the cutoff moved. Consumers treat every reason the same; it is for logs and support."++ }++ }++}nnew file mode 100644@@@ -0,0 +1 @@++{ "subject": { "type": "guest", "id": "gst_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3" }, "valid_after": "2026-09-24T20:15:00Z", "reason": "signed_out_everywhere" }nnew file mode 100644@@@ -0,0 +1 @@++{ "subject": { "type": "user", "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3" }, "valid_after": "2026-09-24T20:15:00Z", "reason": "felt_like_it" }nnew file mode 100644@@@ -0,0 +1 @@++{ "subject": { "type": "user", "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3" }, "valid_after": "2026-09-24T20:15:07Z", "reason": "password_changed" }nnew file mode 100644@@@ -0,0 +1 @@++{ "subject": { "type": "user", "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3" }, "valid_after": "2026-09-24T20:15:00.000Z", "reason": "signed_out_everywhere" }@@@ -9947,6 +9947,60 @@}}},++ "network.user.token_valid_after": {++ "version": "1.0.0",++ "owner": "network",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/network.user.token_valid_after.v1.json",++ "title": "NetworkUserTokenValidAfterPayload",++ "description": "network.user.token_valid_after v1 (OpenVibe.Network server/auth/revocation.js). A person's tokens issued before valid_after are no longer good: every service that accepts Network user tokens refuses one whose iat (seconds) * 1000 is less than valid_after (milliseconds), exactly as Network does, drops what it cached for that person's older tokens and closes the sockets they opened. Emitted in the transaction that moves the cutoff: a password change or reset, sign out everywhere, a ban, an account deletion, or staff ending someone's sessions. Consumers keep the latest valid_after per subject and ignore an older one (events can arrive out of order). Envelope: subject { type: user, id }, visibility internal, actor the person (their own change) or the staff member / system:network.",++ "type": "object",++ "required": [++ "subject",++ "valid_after",++ "reason"++ ],++ "additionalProperties": false,++ "properties": {++ "subject": {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "const": "user"++ },++ "id": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "description": "The person (identity.subject-ref@1, a user)."++ },++ "valid_after": {++ "type": "string",++ "format": "date-time",++ "description": "Tokens issued before this instant are refused (compare iat * 1000 < Date.parse(valid_after))."++ },++ "reason": {++ "enum": [++ "password_changed",++ "password_reset",++ "signed_out_everywhere",++ "banned",++ "account_deleted",++ "staff_revoked"++ ],++ "description": "Why the cutoff moved. Consumers treat every reason the same; it is for logs and support."++ }++ }++ }++ },"tools.tool": {"version": "1.1.0","owner": "tools",@@@ -9330,6 +9330,29 @@ export interface NetworkModuleUpdatedPayload {};}++/** [email protected] (owner: network) */++/**++ * network.user.token_valid_after v1 (OpenVibe.Network server/auth/revocation.js). A person's tokens issued before valid_after are no longer good: every service that accepts Network user tokens refuses one whose iat (seconds) * 1000 is less than valid_after (milliseconds), exactly as Network does, drops what it cached for that person's older tokens and closes the sockets they opened. Emitted in the transaction that moves the cutoff: a password change or reset, sign out everywhere, a ban, an account deletion, or staff ending someone's sessions. Consumers keep the latest valid_after per subject and ignore an older one (events can arrive out of order). Envelope: subject { type: user, id }, visibility internal, actor the person (their own change) or the staff member / system:network.++ */++export interface NetworkUserTokenValidAfterPayload {++ /**++ * The person (identity.subject-ref@1, a user).++ */++ subject: {++ type: "user";++ id: string;++ };++ /**++ * Tokens issued before this instant are refused (compare iat * 1000 < Date.parse(valid_after)).++ */++ valid_after: string;++ /**++ * Why the cutoff moved. Consumers treat every reason the same; it is for logs and support.++ */++ reason:++ "password_changed" | "password_reset" | "signed_out_everywhere" | "banned" | "account_deleted" | "staff_revoked";++}++/** [email protected] (owner: tools) *//*** One tool on openvibe.tools as its registry describes it (GET /api/v1/tools/:id, and each item of GET /api/v1/tools; capability tools.tool.read; ADR-027). There is one descriptor per catalogue tool (GET /api/catalog.json tools[].id), built from the tool's own code, so its page, the run API, openvibe-sdk/tools, the OpenAPI document and the docs all read the same facts. EXECUTION is where the tool's engine runs for its page: client (in the browser; nothing leaves it), sync (a server request answered inline) or job (an asynchronous job on a satellite, tools.job@1). API says whether POST /api/v1/tools/{id}/run exposes the tool. A client tool has api true only when it also has a server engine (a pure transform that runs in Node), and its page stays browser-only. A page-only tool (yt) has api false and run null. A job tool's run creates a job of run.job.type whose input is { ...input, ...run.job.preset, tool: run.job.operation } (the preset and the operation always win). INPUT is the JSON Schema (2020-12) that a run request's input must match, embedded or as { $ref: https://openvibe.tools/api/v1/tools/{id}/schema#/$defs/input }. GET /api/v1/tools/:id/schema answers { $schema, $id, $defs: { input, output } }, and the list uses the $ref form. When api is false, $defs.input is false (the schema that accepts nothing), since there is no run to take an input. OUTPUT.SCHEMA describes result.data for every execution: inline and job tools alike. KEYWORDS (the catalogue's search terms) and EXAMPLES (sample runs for the docs and the OpenAPI document) are optional. NOT A TOOL: there is no planned status. A planned catalogue entry has no descriptor and is not listed, and neither is a mirror (a second build of another tool). GET /api/v1/tools/:id and /schema answer 404 tools.tool.not_found for either, with a detail that says the id is planned or names the tool it mirrors, as for an id that does not exist. RULES this schema enforces: api false has no run and no examples, and api true has a run and an input; an API job tool names its job, and only job tools name one; an API tool whose output is a file runs as a job (its results are served as job files); a tools.net.probe tool fetches (egress) and is never anonymous; an anonymous egress tool has a per-target throttle (limits.perTargetPerMinute); a client tool never fetches; an unavailable tool says why (statusReason); JSON output has a schema. contracts.tools.checkDescriptor(d) also checks what depends on the id (run.path, $ref targets), files.min <= files.max, and each example: its input against an embedded input schema and limits.maxInputBytes, and its files against files (count and accept).@@@ -19,7 +19,9 @@"chat.dm.created","chat.moderation.action"],-- "eventsConsumed": [],++ "eventsConsumed": [++ "network.user.token_valid_after"++ ],"namespacesOwned": ["chat.preferences"],@@@ -35,7 +35,9 @@"community.post.created","community.thread.created"],-- "eventsConsumed": [],++ "eventsConsumed": [++ "network.user.token_valid_after"++ ],"namespacesOwned": ["community.*"],@@@ -28,7 +28,7 @@"games.mod.grants_changed","games.mod.revoked"],-- "eventsConsumed": [],++ "eventsConsumed": ["network.user.token_valid_after"],"namespacesOwned": ["games.*"],"notes": "Scraplandia (browser runtime). Players are keyed by canonical Network subjects (ADR-0006 in the repo). Calls Events (events.event.publish), Media (media.object.upload, namespace games: map-editor assets) and Network identity (identity.subject.resolve, batch legacy adoption) with the games client-credentials principal. Mods: games-content@1 declarative packs only; executable mods wait for OpenVibe.Host Stage C. No achievement system exists, so there are no games.achievement.* events."}@@@ -35,7 +35,8 @@"openre.session.*","media.vod.*","media.clip.*",-- "media.storage.*"++ "media.storage.*",++ "network.user.token_valid_after"],"namespacesOwned": ["live.*"@@@ -39,7 +39,9 @@"media.vod.failed","media.vod.ready"],-- "eventsConsumed": [],++ "eventsConsumed": [++ "network.user.token_valid_after"++ ],"namespacesOwned": ["media.*"]@@@ -33,10 +33,11 @@"eventsProduced": ["network.app.created","network.app.revoked",-- "network.credential.rotated","network.credential.revoked",++ "network.credential.rotated","network.grant.changed",-- "network.module.updated"++ "network.module.updated",++ "network.user.token_valid_after"],"eventsConsumed": ["billing.staff.action",@@@ -27,7 +27,9 @@"tools.job.succeeded","tools.job.failed"],-- "eventsConsumed": [],++ "eventsConsumed": [++ "network.user.token_valid_after"++ ],"namespacesOwned": ["tools.*"],@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.38.0",++ "version": "0.39.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.38.0",++ "version": "0.39.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.38.0",++ "version": "0.39.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,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
the notes were in the tag and commit messages (`git tag -n1`).
+## 0.39.0 — 2026-09-24
+
+**`network.user.token_valid_after`** (revocation propagation, roadmap WS-B task 4): when a person's tokens stop being good (a password change or reset, sign out everywhere, a ban, an account deletion or staff ending their sessions), Network moves their cutoff and emits this event in the same transaction. Every service that accepts Network user tokens refuses one whose `iat * 1000 < Date.parse(valid_after)` (Network's own rule), drops what it cached for those tokens and closes the sockets they opened. Consumers keep the latest cutoff per subject. Network produces it; Chat, Community, Live, Media, Tools and Games consume it. Fixtures cover valid and invalid payloads. Additive.
+
## 0.38.0 — 2026-09-24
## 0.38.0 — 2026-09-24
Staff map 1.1.0 (ADR-022), so the content products and Games can check staff capabilities instead of comparing role names:
Staff map 1.1.0 (ADR-022), so the content products and Games can check staff capabilities instead of comparing role names:
@@ -873,6 +873,15 @@
@@ -873,6 +873,15 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
},
},
+ {
+ "id": "network.user.token_valid_after",
+ "version": "1.0.0",
+ "owner": "network",
+ "schema": "events/payloads/network.user.token_valid_after.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
{
{
"id": "tools.tool",
"id": "tools.tool",
"version": "1.1.0",
"version": "1.1.0",
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/network.user.token_valid_after.v1.json",
+ "title": "NetworkUserTokenValidAfterPayload",
+ "description": "network.user.token_valid_after v1 (OpenVibe.Network server/auth/revocation.js). A person's tokens issued before valid_after are no longer good: every service that accepts Network user tokens refuses one whose iat (seconds) * 1000 is less than valid_after (milliseconds), exactly as Network does, drops what it cached for that person's older tokens and closes the sockets they opened. Emitted in the transaction that moves the cutoff: a password change or reset, sign out everywhere, a ban, an account deletion, or staff ending someone's sessions. Consumers keep the latest valid_after per subject and ignore an older one (events can arrive out of order). Envelope: subject { type: user, id }, visibility internal, actor the person (their own change) or the staff member / system:network.",
+ "type": "object",
+ "required": ["subject", "valid_after", "reason"],
+ "additionalProperties": false,
+ "properties": {
+ "subject": {
+ "type": "object", "required": ["type", "id"], "additionalProperties": false,
+ "properties": { "type": { "const": "user" }, "id": { "type": "string", "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$" } },
+ "description": "The person (identity.subject-ref@1, a user)."
+ },
+ "valid_after": { "type": "string", "format": "date-time", "description": "Tokens issued before this instant are refused (compare iat * 1000 < Date.parse(valid_after))." },
+ "reason": {
+ "enum": ["password_changed", "password_reset", "signed_out_everywhere", "banned", "account_deleted", "staff_revoked"],
+ "description": "Why the cutoff moved. Consumers treat every reason the same; it is for logs and support."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "subject": { "type": "guest", "id": "gst_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3" }, "valid_after": "2026-09-24T20:15:00Z", "reason": "signed_out_everywhere" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "subject": { "type": "user", "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3" }, "valid_after": "2026-09-24T20:15:00Z", "reason": "felt_like_it" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "subject": { "type": "user", "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3" }, "valid_after": "2026-09-24T20:15:07Z", "reason": "password_changed" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "subject": { "type": "user", "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3" }, "valid_after": "2026-09-24T20:15:00.000Z", "reason": "signed_out_everywhere" }
@@ -9947,6 +9947,60 @@
@@ -9947,6 +9947,60 @@
}
}
}
}
},
},
+ "network.user.token_valid_after": {
+ "version": "1.0.0",
+ "owner": "network",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/network.user.token_valid_after.v1.json",
+ "title": "NetworkUserTokenValidAfterPayload",
+ "description": "network.user.token_valid_after v1 (OpenVibe.Network server/auth/revocation.js). A person's tokens issued before valid_after are no longer good: every service that accepts Network user tokens refuses one whose iat (seconds) * 1000 is less than valid_after (milliseconds), exactly as Network does, drops what it cached for that person's older tokens and closes the sockets they opened. Emitted in the transaction that moves the cutoff: a password change or reset, sign out everywhere, a ban, an account deletion, or staff ending someone's sessions. Consumers keep the latest valid_after per subject and ignore an older one (events can arrive out of order). Envelope: subject { type: user, id }, visibility internal, actor the person (their own change) or the staff member / system:network.",
+ "type": "object",
+ "required": [
+ "subject",
+ "valid_after",
+ "reason"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "subject": {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "user"
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "description": "The person (identity.subject-ref@1, a user)."
+ },
+ "valid_after": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Tokens issued before this instant are refused (compare iat * 1000 < Date.parse(valid_after))."
+ },
+ "reason": {
+ "enum": [
+ "password_changed",
+ "password_reset",
+ "signed_out_everywhere",
+ "banned",
+ "account_deleted",
+ "staff_revoked"
+ ],
+ "description": "Why the cutoff moved. Consumers treat every reason the same; it is for logs and support."
+ }
+ }
+ }
+ },
"tools.tool": {
"tools.tool": {
"version": "1.1.0",
"version": "1.1.0",
"owner": "tools",
"owner": "tools",
@@ -9330,6 +9330,29 @@ export interface NetworkModuleUpdatedPayload {
@@ -9330,6 +9330,29 @@ export interface NetworkModuleUpdatedPayload {
};
};
}
}
+/** [email protected] (owner: network) */
+/**
+ * network.user.token_valid_after v1 (OpenVibe.Network server/auth/revocation.js). A person's tokens issued before valid_after are no longer good: every service that accepts Network user tokens refuses one whose iat (seconds) * 1000 is less than valid_after (milliseconds), exactly as Network does, drops what it cached for that person's older tokens and closes the sockets they opened. Emitted in the transaction that moves the cutoff: a password change or reset, sign out everywhere, a ban, an account deletion, or staff ending someone's sessions. Consumers keep the latest valid_after per subject and ignore an older one (events can arrive out of order). Envelope: subject { type: user, id }, visibility internal, actor the person (their own change) or the staff member / system:network.
+ */
+export interface NetworkUserTokenValidAfterPayload {
+ /**
+ * The person (identity.subject-ref@1, a user).
+ */
+ subject: {
+ type: "user";
+ id: string;
+ };
+ /**
+ * Tokens issued before this instant are refused (compare iat * 1000 < Date.parse(valid_after)).
+ */
+ valid_after: string;
+ /**
+ * Why the cutoff moved. Consumers treat every reason the same; it is for logs and support.
+ */
+ reason:
+ "password_changed" | "password_reset" | "signed_out_everywhere" | "banned" | "account_deleted" | "staff_revoked";
+}
+
/** [email protected] (owner: tools) */
/** [email protected] (owner: tools) */
/**
/**
* One tool on openvibe.tools as its registry describes it (GET /api/v1/tools/:id, and each item of GET /api/v1/tools; capability tools.tool.read; ADR-027). There is one descriptor per catalogue tool (GET /api/catalog.json tools[].id), built from the tool's own code, so its page, the run API, openvibe-sdk/tools, the OpenAPI document and the docs all read the same facts. EXECUTION is where the tool's engine runs for its page: client (in the browser; nothing leaves it), sync (a server request answered inline) or job (an asynchronous job on a satellite, tools.job@1). API says whether POST /api/v1/tools/{id}/run exposes the tool. A client tool has api true only when it also has a server engine (a pure transform that runs in Node), and its page stays browser-only. A page-only tool (yt) has api false and run null. A job tool's run creates a job of run.job.type whose input is { ...input, ...run.job.preset, tool: run.job.operation } (the preset and the operation always win). INPUT is the JSON Schema (2020-12) that a run request's input must match, embedded or as { $ref: https://openvibe.tools/api/v1/tools/{id}/schema#/$defs/input }. GET /api/v1/tools/:id/schema answers { $schema, $id, $defs: { input, output } }, and the list uses the $ref form. When api is false, $defs.input is false (the schema that accepts nothing), since there is no run to take an input. OUTPUT.SCHEMA describes result.data for every execution: inline and job tools alike. KEYWORDS (the catalogue's search terms) and EXAMPLES (sample runs for the docs and the OpenAPI document) are optional. NOT A TOOL: there is no planned status. A planned catalogue entry has no descriptor and is not listed, and neither is a mirror (a second build of another tool). GET /api/v1/tools/:id and /schema answer 404 tools.tool.not_found for either, with a detail that says the id is planned or names the tool it mirrors, as for an id that does not exist. RULES this schema enforces: api false has no run and no examples, and api true has a run and an input; an API job tool names its job, and only job tools name one; an API tool whose output is a file runs as a job (its results are served as job files); a tools.net.probe tool fetches (egress) and is never anonymous; an anonymous egress tool has a per-target throttle (limits.perTargetPerMinute); a client tool never fetches; an unavailable tool says why (statusReason); JSON output has a schema. contracts.tools.checkDescriptor(d) also checks what depends on the id (run.path, $ref targets), files.min <= files.max, and each example: its input against an embedded input schema and limits.maxInputBytes, and its files against files (count and accept).
* One tool on openvibe.tools as its registry describes it (GET /api/v1/tools/:id, and each item of GET /api/v1/tools; capability tools.tool.read; ADR-027). There is one descriptor per catalogue tool (GET /api/catalog.json tools[].id), built from the tool's own code, so its page, the run API, openvibe-sdk/tools, the OpenAPI document and the docs all read the same facts. EXECUTION is where the tool's engine runs for its page: client (in the browser; nothing leaves it), sync (a server request answered inline) or job (an asynchronous job on a satellite, tools.job@1). API says whether POST /api/v1/tools/{id}/run exposes the tool. A client tool has api true only when it also has a server engine (a pure transform that runs in Node), and its page stays browser-only. A page-only tool (yt) has api false and run null. A job tool's run creates a job of run.job.type whose input is { ...input, ...run.job.preset, tool: run.job.operation } (the preset and the operation always win). INPUT is the JSON Schema (2020-12) that a run request's input must match, embedded or as { $ref: https://openvibe.tools/api/v1/tools/{id}/schema#/$defs/input }. GET /api/v1/tools/:id/schema answers { $schema, $id, $defs: { input, output } }, and the list uses the $ref form. When api is false, $defs.input is false (the schema that accepts nothing), since there is no run to take an input. OUTPUT.SCHEMA describes result.data for every execution: inline and job tools alike. KEYWORDS (the catalogue's search terms) and EXAMPLES (sample runs for the docs and the OpenAPI document) are optional. NOT A TOOL: there is no planned status. A planned catalogue entry has no descriptor and is not listed, and neither is a mirror (a second build of another tool). GET /api/v1/tools/:id and /schema answer 404 tools.tool.not_found for either, with a detail that says the id is planned or names the tool it mirrors, as for an id that does not exist. RULES this schema enforces: api false has no run and no examples, and api true has a run and an input; an API job tool names its job, and only job tools name one; an API tool whose output is a file runs as a job (its results are served as job files); a tools.net.probe tool fetches (egress) and is never anonymous; an anonymous egress tool has a per-target throttle (limits.perTargetPerMinute); a client tool never fetches; an unavailable tool says why (statusReason); JSON output has a schema. contracts.tools.checkDescriptor(d) also checks what depends on the id (run.path, $ref targets), files.min <= files.max, and each example: its input against an embedded input schema and limits.maxInputBytes, and its files against files (count and accept).
@@ -19,7 +19,9 @@
@@ -19,7 +19,9 @@
"chat.dm.created",
"chat.dm.created",
"chat.moderation.action"
"chat.moderation.action"
],
],
- "eventsConsumed": [],
+ "eventsConsumed": [
+ "network.user.token_valid_after"
+ ],
"namespacesOwned": [
"namespacesOwned": [
"chat.preferences"
"chat.preferences"
],
],
@@ -35,7 +35,9 @@
@@ -35,7 +35,9 @@
"community.post.created",
"community.post.created",
"community.thread.created"
"community.thread.created"
],
],
- "eventsConsumed": [],
+ "eventsConsumed": [
+ "network.user.token_valid_after"
+ ],
"namespacesOwned": [
"namespacesOwned": [
"community.*"
"community.*"
],
],
@@ -28,7 +28,7 @@
@@ -28,7 +28,7 @@
"games.mod.grants_changed",
"games.mod.grants_changed",
"games.mod.revoked"
"games.mod.revoked"
],
],
- "eventsConsumed": [],
+ "eventsConsumed": ["network.user.token_valid_after"],
"namespacesOwned": ["games.*"],
"namespacesOwned": ["games.*"],
"notes": "Scraplandia (browser runtime). Players are keyed by canonical Network subjects (ADR-0006 in the repo). Calls Events (events.event.publish), Media (media.object.upload, namespace games: map-editor assets) and Network identity (identity.subject.resolve, batch legacy adoption) with the games client-credentials principal. Mods: games-content@1 declarative packs only; executable mods wait for OpenVibe.Host Stage C. No achievement system exists, so there are no games.achievement.* events."
"notes": "Scraplandia (browser runtime). Players are keyed by canonical Network subjects (ADR-0006 in the repo). Calls Events (events.event.publish), Media (media.object.upload, namespace games: map-editor assets) and Network identity (identity.subject.resolve, batch legacy adoption) with the games client-credentials principal. Mods: games-content@1 declarative packs only; executable mods wait for OpenVibe.Host Stage C. No achievement system exists, so there are no games.achievement.* events."
}
}
@@ -35,7 +35,8 @@
@@ -35,7 +35,8 @@
"openre.session.*",
"openre.session.*",
"media.vod.*",
"media.vod.*",
"media.clip.*",
"media.clip.*",
- "media.storage.*"
+ "media.storage.*",
+ "network.user.token_valid_after"
],
],
"namespacesOwned": [
"namespacesOwned": [
"live.*"
"live.*"
@@ -39,7 +39,9 @@
@@ -39,7 +39,9 @@
"media.vod.failed",
"media.vod.failed",
"media.vod.ready"
"media.vod.ready"
],
],
- "eventsConsumed": [],
+ "eventsConsumed": [
+ "network.user.token_valid_after"
+ ],
"namespacesOwned": [
"namespacesOwned": [
"media.*"
"media.*"
]
]
@@ -33,10 +33,11 @@
@@ -33,10 +33,11 @@
"eventsProduced": [
"eventsProduced": [
"network.app.created",
"network.app.created",
"network.app.revoked",
"network.app.revoked",
- "network.credential.rotated",
"network.credential.revoked",
"network.credential.revoked",
+ "network.credential.rotated",
"network.grant.changed",
"network.grant.changed",
- "network.module.updated"
+ "network.module.updated",
+ "network.user.token_valid_after"
],
],
"eventsConsumed": [
"eventsConsumed": [
"billing.staff.action",
"billing.staff.action",
@@ -27,7 +27,9 @@
@@ -27,7 +27,9 @@
"tools.job.succeeded",
"tools.job.succeeded",
"tools.job.failed"
"tools.job.failed"
],
],
- "eventsConsumed": [],
+ "eventsConsumed": [
+ "network.user.token_valid_after"
+ ],
"namespacesOwned": [
"namespacesOwned": [
"tools.*"
"tools.*"
],
],
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.38.0",
+ "version": "0.39.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.38.0",
+ "version": "0.39.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.38.0",
+ "version": "0.39.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",