openvibers/openvibe.chat Commits

GET /metrics: chat_auth_resolutions{via=local|live|rejected}, where sign-ins were decided since start

OP OpenVibers committed 24 Sept 2026 · 6b68f57a79 · 2 files, +8 −0


Changes

ddiff --git a/server/app.js b/server/app.js
iindex d0acf02..27137ce 100644
---- a/server/app.js
++++ b/server/app.js
@@@ -76,6 +76,9 @@ function createApp({ chatServer, bridge, mirror, relay, events = null }) {
const metrics = require('openvibe-shared/metrics').instrument(app, { service: 'chat', release: release.release });
release.mount(app, { registry: metrics.registry });
app.locals.metrics = metrics.registry;
++ // How sign-ins resolve (auth/network-session.js): here, through Live, or refused.
++ metrics.registry.gauge({ name: 'chat_auth_resolutions', help: 'Token resolutions since start, by where they were decided', labelNames: ['via'],
++ collect: () => Object.entries(require('./auth/network-session').stats()).map(([via, n]) => ({ labels: { via }, value: n })) });
/** Exact allow-list only (no subdomain wildcard). */
function isAllowedOrigin(origin) {
ddiff --git a/test/network-session.test.js b/test/network-session.test.js
iindex 92b26f6..e60f626 100644
---- a/test/network-session.test.js
++++ b/test/network-session.test.js
@@@ -95,4 +95,9 @@ t('REST and the WebSocket keep working for a Network token while Live is down',
} finally { h.live.down = false; }
});
++t('/metrics counts where sign-ins were decided', async () => {
++ const m = (await h.http('GET', '/metrics')).text;
++ for (const via of ['local', 'live', 'rejected']) assert.match(m, new RegExp(`chat_auth_resolutions\\{[^}]*via="${via}"[^}]*\\} [1-9]`), via);
++});
++
t.run(async () => { if (h && h.close) await h.close(); });