11import type { HealthCheckSnapshot } from './state/HealthCheckState' ;
22
3- export type OverallStatus = 'healthy' | 'unhealthy' | 'unknown' ;
3+ export type OverallStatus = 'healthy' | 'partial' | 'unhealthy' | 'unknown' ;
4+
5+ // Provider checks registered as 'OAuth2: <provider>' form one login group:
6+ // users need only one working provider, so a broken provider alongside a
7+ // healthy one degrades the system to 'partial' rather than 'unhealthy'.
8+ const OAUTH2_GROUP_PREFIX = 'OAuth2: ' ;
49
510export interface ServiceHealthView extends HealthCheckSnapshot {
611 /** True when the last result is too old to say anything about the present. */
@@ -30,6 +35,9 @@ const DEFAULT_STALE_AFTER_MS = 3 * 60_000;
3035 * - A result older than two check intervals proves nothing about the present;
3136 * it is flagged stale and counted as 'unknown'.
3237 * - 'healthy' requires every service to have a fresh, healthy result.
38+ * - OAuth2 provider checks are one group: as long as one provider is healthy,
39+ * failed providers yield 'partial' instead of 'unhealthy'. With no healthy
40+ * provider left (or a non-OAuth service down), the status is 'unhealthy'.
3341 */
3442export function summarizeHealth (
3543 snapshots : Record < string , HealthCheckSnapshot > ,
@@ -49,11 +57,20 @@ export function summarizeHealth(
4957 const unhealthy = list . filter ( ( s ) => effectiveStatus ( s ) === 'unhealthy' ) . length ;
5058 const unknown = list . filter ( ( s ) => effectiveStatus ( s ) === 'unknown' ) . length ;
5159
60+ const entries = Object . entries ( services ) ;
61+ const isOAuth2 = ( [ name ] : [ string , ServiceHealthView ] ) => name . startsWith ( OAUTH2_GROUP_PREFIX ) ;
62+ const coreStatuses = entries . filter ( ( e ) => ! isOAuth2 ( e ) ) . map ( ( [ , s ] ) => effectiveStatus ( s ) ) ;
63+ const oauthStatuses = entries . filter ( isOAuth2 ) . map ( ( [ , s ] ) => effectiveStatus ( s ) ) ;
64+ const oauthHealthy = oauthStatuses . filter ( ( s ) => s === 'healthy' ) . length ;
65+ const oauthUnhealthy = oauthStatuses . filter ( ( s ) => s === 'unhealthy' ) . length ;
66+
5267 let overallStatus : OverallStatus ;
5368 if ( list . length === 0 ) {
5469 overallStatus = 'unknown' ;
55- } else if ( unhealthy > 0 ) {
70+ } else if ( coreStatuses . includes ( ' unhealthy' ) || ( oauthUnhealthy > 0 && oauthHealthy === 0 ) ) {
5671 overallStatus = 'unhealthy' ;
72+ } else if ( oauthUnhealthy > 0 ) {
73+ overallStatus = 'partial' ;
5774 } else if ( unknown > 0 ) {
5875 overallStatus = 'unknown' ;
5976 } else {
0 commit comments