openvibers/openvibe.events Commits
openvibe-contracts v0.338.0 (was v0.312.0) (#259)
Changes
@@@ -406,7 +406,7 @@ implemented service.Part of the [OpenVibe network](https://openvibe.network). Built in the open by [OpenVibers](https://github.com/OpenVibers).<!-- versions:start -->--- openvibe-contracts: v0.312.0++- openvibe-contracts: v0.338.0- openvibe-sdk: v0.94.0- openvibe-shared: v4.142.0<!-- versions:end -->@@@ -7,7 +7,7 @@"runtime": "node 22, express, PostgreSQL 18 (openvibe-sdk/db, async) + Valkey 9","port": 4300,"domain": "openvibe.events",-- "contracts": "openvibe-contracts v0.312.0",++ "contracts": "openvibe-contracts v0.338.0","sdk": "openvibe-sdk v0.94.0","shared": "openvibe-shared v4.142.0","capabilities": [@@@ -37,5 +37,5 @@"carrier fabric (ADR-042): the pg-v1 poll beside a valkey-v1 push carrier for QUEUE (streams) and TOPIC (SSE fan-out) an optional nats-v1 NATS Core TOPIC carrier (NATS_URL) and an optional nats-js-v1 JetStream STREAM carrier (NATS_URL, NATS_JETSTREAM; deploy/nats) and an optional cloud-v1 SQS-compatible QUEUE carrier (CLOUD_QUEUE_URL; SigV4, no dependency), with a placement planner, per-key pinning, delivery_placements history and a GET /api/v1/placement explain API; EVENTS_CARRIERS[_DISABLED] switches it","at_most_once delivery semantics (a failed attempt is final)"],-- "updated": "2026-11-07"++ "updated": "2026-11-08"}@@@ -12,7 +12,7 @@"dotenv": "^16.4.7","express": "^4.21.2","iovalkey": "^0.4.0",-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.312.0",++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.94.0","openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.142.0","pg": "^8.23.0"@@@ -1103,9 +1103,9 @@}},"node_modules/openvibe-contracts": {-- "version": "0.312.0",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.312.0",-- "integrity": "sha512-2GsD53zuIedL3eW2LBlYQ68ODTHzoZJHrAmVnZCpiL7ZWnAXGwPW9dpQagLI9Zdkh3LQuuU5ae1YJI0K+acXbA==",++ "version": "0.338.0",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0",++ "integrity": "sha512-75FD6IxMsXoud3NFXKDs0/D0rhJtF2D+WL8M92ArIyabkUnM/sZvw6E6L97EqwQ3O7M/kB+uwsNSxGudbil+ng==","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -24,7 +24,7 @@"dotenv": "^16.4.7","express": "^4.21.2","iovalkey": "^0.4.0",-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.312.0",++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.94.0","openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.142.0","pg": "^8.23.0"@@@ -58,7 +58,11 @@ const DEFAULT_SOURCES = ['live', 'media', 'network', 'community', 'chat', 'openr'design',// Vision (openvibe.vision, VIS-5): vision.result.ready, vision.alert. Its manifest declared them, but it was missing// here, so its events were refused as events.unknown_source (found 11-02 when the contracts pin moved to 0.280.0).-- 'vision'];++ 'vision',++ // Agent (OpenVibe.Actor): agent.step.started|updated|ended. The Actor manifest declares them (contracts 0.298.0),++ // so the source has to be known here or its events are refused as events.unknown_source (found 2026-11-08 when++ // the contracts pin moved to v0.338.0). They live in the network's shared agent.* namespace, not in actor.*.++ 'actor'];/*** Namespaces that belong to the network rather than to one service. `provider.*` carries storage@@@ -285,4 +289,4 @@ function load(env = process.env) {};}--module.exports = { load, DEFAULT_SOURCES, namespaceOf };++module.exports = { load, DEFAULT_SOURCES, DEFAULT_SHARED_PREFIXES, namespaceOf };@@@ -5,13 +5,15 @@const assert = require('assert');const fs = require('fs');const path = require('path');--const { DEFAULT_SOURCES, namespaceOf } = require('../server/config');++const { DEFAULT_SOURCES, DEFAULT_SHARED_PREFIXES, namespaceOf } = require('../server/config');const dir = path.join(path.dirname(require.resolve('openvibe-contracts/package.json')), 'manifests', 'services');const manifests = fs.readdirSync(dir).filter((f) => f.endsWith('.json')).map((f) => JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8')));const producers = manifests.filter((m) => (m.eventsProduced || []).length).map((m) => m.id || m.service).filter((id) => id !== 'events');const missing = producers.filter((id) => !DEFAULT_SOURCES.includes(id));assert.deepStrictEqual(missing, [], `producers that may not publish: ${missing.join(', ')}`);--const outside = manifests.flatMap((m) => (m.eventsProduced || []).filter((t) => (m.id || m.service) !== 'events' && t.split('.')[0] !== namespaceOf(m.id || m.service) && !t.startsWith('provider.') && !t.startsWith('share.')).map((t) => `${m.id || m.service}: ${t}`));++// A shared prefix (provider.*, share.*, agent.*) belongs to the network, not to one service, so a producer may use it.++const shared = DEFAULT_SHARED_PREFIXES.map((p) => p.slice(0, -1));++const outside = manifests.flatMap((m) => (m.eventsProduced || []).filter((t) => (m.id || m.service) !== 'events' && t.split('.')[0] !== namespaceOf(m.id || m.service) && !shared.includes(t.split('.')[0])).map((t) => `${m.id || m.service}: ${t}`));assert.deepStrictEqual(outside, [], 'every produced event type is in its producer\'s own namespace');console.log(`sources cover producers: ${producers.length} producers, all allowed`);
@@ -406,7 +406,7 @@ implemented service.
@@ -406,7 +406,7 @@ implemented service.
Part of the [OpenVibe network](https://openvibe.network). Built in the open by [OpenVibers](https://github.com/OpenVibers).
Part of the [OpenVibe network](https://openvibe.network). Built in the open by [OpenVibers](https://github.com/OpenVibers).
<!-- versions:start -->
<!-- versions:start -->
-- openvibe-contracts: v0.312.0
+- openvibe-contracts: v0.338.0
- openvibe-sdk: v0.94.0
- openvibe-sdk: v0.94.0
- openvibe-shared: v4.142.0
- openvibe-shared: v4.142.0
<!-- versions:end -->
<!-- versions:end -->
@@ -7,7 +7,7 @@
@@ -7,7 +7,7 @@
"runtime": "node 22, express, PostgreSQL 18 (openvibe-sdk/db, async) + Valkey 9",
"runtime": "node 22, express, PostgreSQL 18 (openvibe-sdk/db, async) + Valkey 9",
"port": 4300,
"port": 4300,
"domain": "openvibe.events",
"domain": "openvibe.events",
- "contracts": "openvibe-contracts v0.312.0",
+ "contracts": "openvibe-contracts v0.338.0",
"sdk": "openvibe-sdk v0.94.0",
"sdk": "openvibe-sdk v0.94.0",
"shared": "openvibe-shared v4.142.0",
"shared": "openvibe-shared v4.142.0",
"capabilities": [
"capabilities": [
@@ -37,5 +37,5 @@
@@ -37,5 +37,5 @@
"carrier fabric (ADR-042): the pg-v1 poll beside a valkey-v1 push carrier for QUEUE (streams) and TOPIC (SSE fan-out) an optional nats-v1 NATS Core TOPIC carrier (NATS_URL) and an optional nats-js-v1 JetStream STREAM carrier (NATS_URL, NATS_JETSTREAM; deploy/nats) and an optional cloud-v1 SQS-compatible QUEUE carrier (CLOUD_QUEUE_URL; SigV4, no dependency), with a placement planner, per-key pinning, delivery_placements history and a GET /api/v1/placement explain API; EVENTS_CARRIERS[_DISABLED] switches it",
"carrier fabric (ADR-042): the pg-v1 poll beside a valkey-v1 push carrier for QUEUE (streams) and TOPIC (SSE fan-out) an optional nats-v1 NATS Core TOPIC carrier (NATS_URL) and an optional nats-js-v1 JetStream STREAM carrier (NATS_URL, NATS_JETSTREAM; deploy/nats) and an optional cloud-v1 SQS-compatible QUEUE carrier (CLOUD_QUEUE_URL; SigV4, no dependency), with a placement planner, per-key pinning, delivery_placements history and a GET /api/v1/placement explain API; EVENTS_CARRIERS[_DISABLED] switches it",
"at_most_once delivery semantics (a failed attempt is final)"
"at_most_once delivery semantics (a failed attempt is final)"
],
],
- "updated": "2026-11-07"
+ "updated": "2026-11-08"
}
}
@@ -12,7 +12,7 @@
@@ -12,7 +12,7 @@
"dotenv": "^16.4.7",
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express": "^4.21.2",
"iovalkey": "^0.4.0",
"iovalkey": "^0.4.0",
- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.312.0",
+ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.94.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.94.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.142.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.142.0",
"pg": "^8.23.0"
"pg": "^8.23.0"
@@ -1103,9 +1103,9 @@
@@ -1103,9 +1103,9 @@
}
}
},
},
"node_modules/openvibe-contracts": {
"node_modules/openvibe-contracts": {
- "version": "0.312.0",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.312.0",
- "integrity": "sha512-2GsD53zuIedL3eW2LBlYQ68ODTHzoZJHrAmVnZCpiL7ZWnAXGwPW9dpQagLI9Zdkh3LQuuU5ae1YJI0K+acXbA==",
+ "version": "0.338.0",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0",
+ "integrity": "sha512-75FD6IxMsXoud3NFXKDs0/D0rhJtF2D+WL8M92ArIyabkUnM/sZvw6E6L97EqwQ3O7M/kB+uwsNSxGudbil+ng==",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
"ajv": "^8.17.1",
"ajv": "^8.17.1",
@@ -24,7 +24,7 @@
@@ -24,7 +24,7 @@
"dotenv": "^16.4.7",
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express": "^4.21.2",
"iovalkey": "^0.4.0",
"iovalkey": "^0.4.0",
- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.312.0",
+ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.94.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.94.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.142.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.142.0",
"pg": "^8.23.0"
"pg": "^8.23.0"
@@ -58,7 +58,11 @@ const DEFAULT_SOURCES = ['live', 'media', 'network', 'community', 'chat', 'openr
@@ -58,7 +58,11 @@ const DEFAULT_SOURCES = ['live', 'media', 'network', 'community', 'chat', 'openr
'design',
'design',
// Vision (openvibe.vision, VIS-5): vision.result.ready, vision.alert. Its manifest declared them, but it was missing
// Vision (openvibe.vision, VIS-5): vision.result.ready, vision.alert. Its manifest declared them, but it was missing
// here, so its events were refused as events.unknown_source (found 11-02 when the contracts pin moved to 0.280.0).
// here, so its events were refused as events.unknown_source (found 11-02 when the contracts pin moved to 0.280.0).
- 'vision'];
+ 'vision',
+ // Agent (OpenVibe.Actor): agent.step.started|updated|ended. The Actor manifest declares them (contracts 0.298.0),
+ // so the source has to be known here or its events are refused as events.unknown_source (found 2026-11-08 when
+ // the contracts pin moved to v0.338.0). They live in the network's shared agent.* namespace, not in actor.*.
+ 'actor'];
/**
/**
* Namespaces that belong to the network rather than to one service. `provider.*` carries storage
* Namespaces that belong to the network rather than to one service. `provider.*` carries storage
@@ -285,4 +289,4 @@ function load(env = process.env) {
@@ -285,4 +289,4 @@ function load(env = process.env) {
};
};
}
}
-module.exports = { load, DEFAULT_SOURCES, namespaceOf };
+module.exports = { load, DEFAULT_SOURCES, DEFAULT_SHARED_PREFIXES, namespaceOf };
@@ -5,13 +5,15 @@
@@ -5,13 +5,15 @@
const assert = require('assert');
const assert = require('assert');
const fs = require('fs');
const fs = require('fs');
const path = require('path');
const path = require('path');
-const { DEFAULT_SOURCES, namespaceOf } = require('../server/config');
+const { DEFAULT_SOURCES, DEFAULT_SHARED_PREFIXES, namespaceOf } = require('../server/config');
const dir = path.join(path.dirname(require.resolve('openvibe-contracts/package.json')), 'manifests', 'services');
const dir = path.join(path.dirname(require.resolve('openvibe-contracts/package.json')), 'manifests', 'services');
const manifests = fs.readdirSync(dir).filter((f) => f.endsWith('.json')).map((f) => JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8')));
const manifests = fs.readdirSync(dir).filter((f) => f.endsWith('.json')).map((f) => JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8')));
const producers = manifests.filter((m) => (m.eventsProduced || []).length).map((m) => m.id || m.service).filter((id) => id !== 'events');
const producers = manifests.filter((m) => (m.eventsProduced || []).length).map((m) => m.id || m.service).filter((id) => id !== 'events');
const missing = producers.filter((id) => !DEFAULT_SOURCES.includes(id));
const missing = producers.filter((id) => !DEFAULT_SOURCES.includes(id));
assert.deepStrictEqual(missing, [], `producers that may not publish: ${missing.join(', ')}`);
assert.deepStrictEqual(missing, [], `producers that may not publish: ${missing.join(', ')}`);
-const outside = manifests.flatMap((m) => (m.eventsProduced || []).filter((t) => (m.id || m.service) !== 'events' && t.split('.')[0] !== namespaceOf(m.id || m.service) && !t.startsWith('provider.') && !t.startsWith('share.')).map((t) => `${m.id || m.service}: ${t}`));
+// A shared prefix (provider.*, share.*, agent.*) belongs to the network, not to one service, so a producer may use it.
+const shared = DEFAULT_SHARED_PREFIXES.map((p) => p.slice(0, -1));
+const outside = manifests.flatMap((m) => (m.eventsProduced || []).filter((t) => (m.id || m.service) !== 'events' && t.split('.')[0] !== namespaceOf(m.id || m.service) && !shared.includes(t.split('.')[0])).map((t) => `${m.id || m.service}: ${t}`));
assert.deepStrictEqual(outside, [], 'every produced event type is in its producer\'s own namespace');
assert.deepStrictEqual(outside, [], 'every produced event type is in its producer\'s own namespace');
console.log(`sources cover producers: ${producers.length} producers, all allowed`);
console.log(`sources cover producers: ${producers.length} producers, all allowed`);