openvibers/openvibe.search Commits

openvibe-shared v1.5.0 (Track R release manifest), openvibe-contracts v0.32.0

OP OpenVibers committed 23 Sept 2026 · 5a4b08bc16 · 6 files, +22 −13

- /release.json is mounted with release.mount(app, { registry }), which also answers POST
  /release-metrics (release_client_updates_total in /metrics; the search page loads no
  release-watch and nginx proxies no such path, so nothing reports yet). On contracts 0.32.0 the
  manifest carries the release-manifest 1.1.0 fields; no components are declared. The
  observability test validates the served manifest against the contracts.
- Contracts 0.13.0 -> 0.32.0 is additive for Search (search.document.indexed|removed payload
  contracts since 0.30.0); the tests and the contracts check pass unchanged.

Changes

ddiff --git a/README.md b/README.md
iindex 1602f84..748c9e0 100644
---- a/README.md
++++ b/README.md
@@@ -200,7 +200,7 @@ the `search.document.removed` event it records:
| `search.document.write` | `PUT/DELETE /api/v1/documents/:owner/:type/:id`, `/api/v1/owners/:owner/...` including the removal feed (own owner only) |
| `search.query.delegate` | the query and saved-search routes, acting for `X-OV-Subject` |
--Released in `openvibe-contracts` v0.12.0 with the service manifest (this repo pins v0.13.0);
++Released in `openvibe-contracts` v0.12.0 with the service manifest (this repo pins v0.32.0);
[server/auth.js](server/auth.js) decides them with the contracts grant rule, and CI runs
`openvibe-contracts-check --service search`.
ddiff --git a/STATUS.json b/STATUS.json
iindex b4a7468..2ad3a87 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -7,7 +7,7 @@
"runtime": "node 22, express, better-sqlite3 (FTS5)",
"port": 4710,
"domain": "search.openvibe.network (vhost in deploy/nginx, not installed: until it is, the name falls through to the admin.openvibe.network placeholder; README \"Public host\")",
-- "contracts": "openvibe-contracts v0.13.0",
++ "contracts": "openvibe-contracts v0.32.0",
"capabilities": ["search.document.write", "search.query.delegate"],
"capabilitiesRegistered": true,
"contractsProposed": ["search.index-document@1 (released in openvibe-contracts v0.12.0)"],
ddiff --git a/package-lock.json b/package-lock.json
iindex cc254bb..cfa9b9c 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -14,8 +14,8 @@
"better-sqlite3": "^11.10.0",
"dotenv": "^16.4.7",
"express": "^4.21.2",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.13.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.3.0"
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.32.0",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.0"
},
"engines": {
"node": ">=22.0.0"
@@@ -969,9 +969,9 @@
}
},
"node_modules/openvibe-contracts": {
-- "version": "0.13.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.13.0",
-- "integrity": "sha512-MeIGJYHQsbr6ISeEErduUw/PD52X5IBclH2ht/G/t4lSX5X4o2AwcZYLEzOZrcbaXQyplgC7r86RCGFvi1ifUA==",
++ "version": "0.32.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.32.0",
++ "integrity": "sha512-ntN58SIG03YDxbhsiIzOM5GRH19jRMHZUYWI3xU2VwovExagF5DdwApLVfezsu84UTJ+V2Jfn+LWDc+Oz8ab+g==",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
@@@ -985,9 +985,9 @@
}
},
"node_modules/openvibe-shared": {
-- "version": "1.3.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.3.0",
-- "integrity": "sha512-w8yl/5+9eend8I2O/DzAJnEAL2N3GTUY7c7pzK+MLJuLAGD8FmJJQ9gwbgyrq70Snjt3ebrg3TlpORhRAp2kgA==",
++ "version": "1.5.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.0",
++ "integrity": "sha512-cehnscuYMkJwuCYGcI6wPSswbUn0bhTyGAaD5feNCoO//2e9gyC7cgjkEcIOtM8DQF3yTuUNyXnOwckIeM4fUg==",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0"
ddiff --git a/package.json b/package.json
iindex acb622b..106c496 100644
---- a/package.json
++++ b/package.json
@@@ -20,8 +20,8 @@
"better-sqlite3": "^11.10.0",
"dotenv": "^16.4.7",
"express": "^4.21.2",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.13.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.3.0"
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.32.0",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.0"
},
"engines": {
"node": ">=22.0.0"
ddiff --git a/server/app.js b/server/app.js
iindex 9b6b503..88493eb 100644
---- a/server/app.js
++++ b/server/app.js
@@@ -42,7 +42,8 @@ function createApp({ config, db, store, engine, auth, keys, outbox, relay, purge
// fails; the Network key and index consistency are optional and degrade it (see observability.js).
const readiness = createSearchReadiness({ db, keys, config, engine, store, outbox, relay, purges, purger, saved, release: release.release });
app.get('/api/ready', readiness.handler);
-- app.get('/release.json', release.handler);
++ // GET /release.json (ADR-016) and POST /release-metrics (open tabs' update reports into /metrics).
++ release.mount(app, { registry: metrics.registry });
const searcher = createSearcher({ config, store, engine, now });
app.use(documentsRouter({ store, auth, db, relay, purges }));
ddiff --git a/test/observability.test.js b/test/observability.test.js
iindex 3c0a462..e487cff 100644
---- a/test/observability.test.js
++++ b/test/observability.test.js
@@@ -71,6 +71,14 @@ t('/metrics: 404 through a proxy; route templates and Search gauges direct', asy
assert.ok(/\nsearch_outbox_pending \d+\n/.test(text));
});
++t('/release.json: a registry.release-manifest@1 that names where tabs report updates', async () => {
++ const r = await request(svc.base, 'GET', '/release.json');
++ assert.strictEqual(r.status, 200, r.text);
++ assert.strictEqual(r.body.service, 'search');
++ assert.deepStrictEqual(require('openvibe-contracts').validate('registry.release-manifest@1', r.body).errors, []);
++ assert.strictEqual(r.body.metrics_url, '/release-metrics');
++});
++
t('a full-text index out of step with the documents degrades /api/ready (still 200)', async () => {
await svc.stop();
svc = await boot(); // fresh: the index check has no cached result