openvibers/openvibe.vip Commits

Health and readiness show the outbox's real counts: status() awaits pending()/rejected() (queries on PostgreSQL), so /api/health and /api/ready no longer serialize two Promises as {}. The API test asserts a number. npm test 11/11.

OP OpenVibers committed 29 Sept 2026 · 78dfe5e119 · 4 files, +5 −3


Changes

ddiff --git a/server/app.js b/server/app.js
iindex 9bdbe58..8d3cdd8 100644
---- a/server/app.js
++++ b/server/app.js
@@@ -87,7 +87,7 @@ async function createApp(opts = {}) {
app.use('/embed', createEmbedRoutes({ domain, config }));
app.use(cookieParser());
-- app.get('/api/health', (req, res) => res.json({ ok: true, service: 'vip', version: VERSION, release: release.release, events: outbox.status() }));
++ app.get('/api/health', async (req, res) => res.json({ ok: true, service: 'vip', version: VERSION, release: release.release, events: await outbox.status() }));
// Valkey (ADR-035): shared, never-authoritative state (per-actor limit counters). Optional.
const valkey = opts.valkey !== undefined ? opts.valkey : (config.valkey.url ? require('openvibe-sdk/valkey').createValkey({ url: config.valkey.url, prefix: config.valkey.prefix, log }) : null);
const readiness = createVipReadiness({ db, keys, config, outbox, now, release: release.release, fetchImpl, valkey });
ddiff --git a/server/events/outbox.js b/server/events/outbox.js
iindex 3bfdd6a..987c109 100644
---- a/server/events/outbox.js
++++ b/server/events/outbox.js
@@@ -63,7 +63,8 @@ function createVipOutbox({ db, config, fetchImpl, now = () => Date.now(), log =
start() { if (enabled) outbox.start(); },
stop: () => outbox.stop(),
kick() { if (enabled) outbox.kick(); },
-- status: () => ({ enabled, pending: outbox.pending(), rejected: outbox.rejected(), last_error: lastError }),
++ // pending()/rejected() are queries on PostgreSQL: awaited, or the health output serialized two Promises as {}.
++ status: async () => ({ enabled, pending: await outbox.pending(), rejected: await outbox.rejected(), last_error: lastError }),
};
}
ddiff --git a/server/observability.js b/server/observability.js
iindex f161a92..0891d76 100644
---- a/server/observability.js
++++ b/server/observability.js
@@@ -49,7 +49,7 @@ function createVipReadiness({ db, keys, config, outbox, now, release = null, fet
const t = now();
const p = await db.prepare('SELECT COUNT(*) AS n, SUM(CASE WHEN valid_until < ? THEN 1 ELSE 0 END) AS stale FROM vip_entitlement_projection').get(t);
return {
-- events: outbox.status(),
++ events: await outbox.status(),
billing_events_accepted: config.events.webhookSecrets.length > 0,
projection: { rows: p.n || 0, past_valid_until: p.stale || 0, max_age_ms: config.projection.maxAgeMs, grace_ms: config.projection.graceMs },
};
ddiff --git a/test/api.test.js b/test/api.test.js
iindex 44ed812..9249324 100644
---- a/test/api.test.js
++++ b/test/api.test.js
@@@ -18,6 +18,7 @@ const { test, run } = harness('api');
test('health, release and truthful readiness', async () => {
const h = await t.call('GET', '/api/health', { token: null });
assert.strictEqual(h.json.service, 'vip');
++ assert.strictEqual(typeof h.json.events.pending, 'number', 'outbox counts are numbers (an unawaited query serialized as {})');
const rel = await t.call('GET', '/release.json', { token: null });
assert.strictEqual(rel.json.service, 'vip');
assert.deepStrictEqual(require('openvibe-contracts').validate('registry.release-manifest@1', rel.json).errors, []);