openvibers/openvibe.events Commits

openvibe-contracts v0.416.0 (was v0.410.0) (#317)

OP OpenVibers committed 24 h ago · 42d420e1cb · 7 files, +11 −11

* openvibe-contracts v0.416.0 (was v0.410.0)

Opened by scripts/pin-bump.js in OpenVibers/OpenVibe.Shared after the v0.416.0 release.

* events: allow the network's agents.* namespace

Changes

ddiff --git a/README.md b/README.md
iindex bd7d02b..b6993b3 100644
---- a/README.md
++++ b/README.md
@@@ -82,7 +82,7 @@ project's hourly publishing and delivery rollup, for Network; never visible to a
`POST /api/v1/events` takes one `events.event-envelope@1` envelope, or `{ "events": [ … ] }` (up to 100, stored atomically).
--- `source` must be the calling service (`svc:live` publishes `source: "live"`), and `event_type` must start with a prefix that source owns (`live.*`, `media.*`, `network.*`, `community.*`, `chat.*`, `openre.*`, `billing.*`, `tips.*`, `vip.*`, `ai.*`, `games.*`, `tools.*`, `codes.*`, `host.*`, `bot.*`, `watch.*`, `run.*`, `space.*`, and the publication products (`wiki.*`, `blog.*`, `news.*`, `reviews.*`, `deals.*`, `coupons.*`, `trade.*`, `sources.*`, `search.*`); `EVENTS_SOURCE_PREFIXES` overrides). A source's namespace is its id without hyphens, since an event type has none: `svc:media-hub` publishes `source: "media-hub"` with `mediahub.*` types, and no other source can claim `mediahub.*`. A network-wide prefix may be published by any first-party service: `provider.*` carries storage provider health/capacity telemetry (`provider.health.degraded`, `provider.capacity.warning`), so whichever service observes a provider can report it; `agent.*` is the network's agent namespace (design 2026-11-07): every mode of the one agent publishes the steps it takes into it (`agent.step.started|updated|ended`), so Chat, Codes, Run, Watch, Live and Surf can each publish the step they just ran; `EVENTS_SHARED_PREFIXES` overrides.
++- `source` must be the calling service (`svc:live` publishes `source: "live"`), and `event_type` must start with a prefix that source owns (`live.*`, `media.*`, `network.*`, `community.*`, `chat.*`, `openre.*`, `billing.*`, `tips.*`, `vip.*`, `ai.*`, `games.*`, `tools.*`, `codes.*`, `host.*`, `bot.*`, `watch.*`, `run.*`, `space.*`, and the publication products (`wiki.*`, `blog.*`, `news.*`, `reviews.*`, `deals.*`, `coupons.*`, `trade.*`, `sources.*`, `search.*`); `EVENTS_SOURCE_PREFIXES` overrides). A source's namespace is its id without hyphens, since an event type has none: `svc:media-hub` publishes `source: "media-hub"` with `mediahub.*` types, and no other source can claim `mediahub.*`. A network-wide prefix may be published by any first-party service: `provider.*` carries storage provider health/capacity telemetry (`provider.health.degraded`, `provider.capacity.warning`), so whichever service observes a provider can report it; `agent.*` is the network's agent namespace (design 2026-11-07): every mode of the one agent publishes the steps it takes into it (`agent.step.started|updated|ended`), so Chat, Codes, Run, Watch, Live and Surf can each publish the step they just ran; `agents.*` is the one agent system's run namespace (2026-11-12): the product that stores a run publishes its `agents.step.appended` and `agents.run.updated` (hyphen-free, like every event namespace), so a run's list stays current wherever it is read; `EVENTS_SHARED_PREFIXES` overrides.
- Idempotent on `event_id`: a repeat answers `200 { event_id, cursor, duplicate: true }` (`pruned: true` and no cursor when retention already removed the stored copy) and is never stored twice (even after retention, for `EVENTS_RECEIPT_RETENTION_DAYS`).
- Missing `trace_id` is taken from the request's `traceparent`; `priority` defaults to `important`, `visibility` to `internal`.
- Loop guard: an event whose trace already carries 8 hops (the cross-service chain depth, or the same source/type/subject repeating in the trace) is refused with `409 events.loop_detected`. The chain depth of a first-party publish counts first-party events only (developer-app events in the same trace never count toward it), so an app cannot poison a trace it has seen.
@@@ -452,7 +452,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.410.0
++- openvibe-contracts: v0.416.0
- openvibe-sdk: v0.150.0
- openvibe-shared: v4.223.0
<!-- versions:end -->
ddiff --git a/STATUS.json b/STATUS.json
iindex 241ff84..552d31a 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -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.410.0",
++ "contracts": "openvibe-contracts v0.416.0",
"sdk": "openvibe-sdk v0.150.0",
"shared": "openvibe-shared v4.223.0",
"capabilities": [
ddiff --git a/package-lock.json b/package-lock.json
iindex aab591c..0f61fef 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -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.410.0",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.416.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.150.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.223.0",
"pg": "^8.23.0"
@@@ -1184,9 +1184,9 @@
}
},
"node_modules/openvibe-contracts": {
-- "version": "0.410.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.410.0",
-- "integrity": "sha512-rmmq2mebXim2fv+sip2YQ0PrrZLxGUhEfe1w+1EFfGdoVvLI5tp0/eavY2sW6/VU+rzs7cQMC/A0NZD5th5wrA==",
++ "version": "0.416.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.416.0",
++ "integrity": "sha512-gFZGSXY7GM2SHdyOmqZ0699yJhF9ZsF/Rb0WHo3asI+S4LTqthqIQPOCoYczlF/dcB5p13KBjLCMdAvEqmNLoQ==",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 9c34896..9e463b9 100644
---- a/package.json
++++ b/package.json
@@@ -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.410.0",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.416.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.150.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.223.0",
"pg": "^8.23.0"
ddiff --git a/server/config.js b/server/config.js
iindex f6ace12..af273b8 100644
---- a/server/config.js
++++ b/server/config.js
@@@ -84,7 +84,7 @@ const DEFAULT_SOURCES = ['live', 'media', 'network', 'community', 'chat', 'openr
* Developer apps can never publish a shared prefix. EVENTS_SHARED_PREFIXES (comma-separated)
* replaces the default.
*/
--const DEFAULT_SHARED_PREFIXES = ['provider.', 'share.', 'agent.'];
++const DEFAULT_SHARED_PREFIXES = ['provider.', 'share.', 'agent.', 'agents.'];
function sourcePrefixes(env) {
ddiff --git a/test/pull-health.test.js b/test/pull-health.test.js
iindex 4e9748f..04dce66 100644
---- a/test/pull-health.test.js
++++ b/test/pull-health.test.js
@@@ -43,7 +43,7 @@ t('config: every source prefix must start with the source', () => {
});
t('config: network-wide prefixes are shared, source namespaces stay owned', () => {
-- assert.deepStrictEqual(load({}).sharedPrefixes, ['provider.', 'share.', 'agent.']);
++ assert.deepStrictEqual(load({}).sharedPrefixes, ['provider.', 'share.', 'agent.', 'agents.']);
const c = load({ EVENTS_SHARED_PREFIXES: 'provider.,storage.' });
assert.deepStrictEqual(c.sharedPrefixes, ['provider.', 'storage.']);
ddiff --git a/test/sources-cover-producers.test.js b/test/sources-cover-producers.test.js
iindex e427f5e..2657bbe 100644
---- a/test/sources-cover-producers.test.js
++++ b/test/sources-cover-producers.test.js
@@@ -12,7 +12,7 @@ const manifests = fs.readdirSync(dir).filter((f) => f.endsWith('.json')).map((f)
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(', ')}`);
--// A shared prefix (provider.*, share.*, agent.*) belongs to the network, not to one service, so a producer may use it.
++// A shared prefix (provider.*, share.*, agent.*, agents.*) 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');