Files
supabase/apps/studio/components/interfaces/Auth/Overview/OverviewUsage.constants.ts
2026-04-01 10:22:37 +02:00

108 lines
3.4 KiB
TypeScript

import {
RawAuthMetricsResponseSchema,
type RawAuthMetricsResponse,
type RawAuthMetricsRow,
} from './OverviewUsage.schema'
import { get } from '@/data/fetchers'
export type AuthMetricsResponse = RawAuthMetricsResponse
export type MetricName =
| 'activeUsers'
| 'signUpCount'
| 'apiTotalRequests'
| 'apiErrorRequests'
| 'authTotalRequests'
| 'authTotalErrors'
| 'passwordResetRequests'
type NumericMetricKey = keyof Omit<RawAuthMetricsRow, 'period'>
const metricKeyMap: Record<MetricName, NumericMetricKey> = {
activeUsers: 'active_users',
signUpCount: 'sign_up_count',
apiTotalRequests: 'api_total_requests',
apiErrorRequests: 'api_error_requests',
authTotalRequests: 'auth_total_requests',
authTotalErrors: 'auth_total_errors',
passwordResetRequests: 'password_reset_requests',
}
export const fetchAllAuthMetrics = async (projectRef: string): Promise<RawAuthMetricsResponse> => {
const { data, error } = await get(
`/platform/projects/{ref}/analytics/endpoints/auth.metrics` as any,
{
params: {
path: { ref: projectRef },
query: {
interval: '1day',
},
},
}
)
if (error) throw error
const parsed = RawAuthMetricsResponseSchema.safeParse(data)
if (!parsed.success) {
const first = parsed.error.issues[0]
throw new Error(`Invalid auth metrics response: ${first?.message ?? 'Invalid shape'}`)
}
return parsed.data
}
export const getMetricValues = (
metrics: AuthMetricsResponse | undefined,
metricName: MetricName
) => {
const key = metricKeyMap[metricName]
const currentRow = metrics?.result.find((r) => r.period === 'current')
const previousRow = metrics?.result.find((r) => r.period === 'previous')
return {
current: currentRow ? currentRow[key] : 0,
previous: previousRow ? previousRow[key] : 0,
}
}
export const getApiSuccessRates = (metrics: AuthMetricsResponse | undefined) => {
const { current: apiTotalCurrent, previous: apiTotalPrevious } = getMetricValues(
metrics,
'apiTotalRequests'
)
const { current: apiErrorCurrent, previous: apiErrorPrevious } = getMetricValues(
metrics,
'apiErrorRequests'
)
const current =
apiTotalCurrent > 0 ? Math.max(0, 100 - (apiErrorCurrent / apiTotalCurrent) * 100) : 0
const previous =
apiTotalPrevious > 0 ? Math.max(0, 100 - (apiErrorPrevious / apiTotalPrevious) * 100) : 0
return { current, previous }
}
export const getAuthSuccessRates = (metrics: AuthMetricsResponse | undefined) => {
const { current: authTotalRequestsCurrent, previous: authTotalRequestsPrevious } =
getMetricValues(metrics, 'authTotalRequests')
const { current: authTotalErrorsCurrent, previous: authTotalErrorsPrevious } = getMetricValues(
metrics,
'authTotalErrors'
)
const current =
authTotalRequestsCurrent > 0
? Math.max(0, 100 - (authTotalErrorsCurrent / authTotalRequestsCurrent) * 100)
: 0
const previous =
authTotalRequestsPrevious > 0
? Math.max(0, 100 - (authTotalErrorsPrevious / authTotalRequestsPrevious) * 100)
: 0
return { current, previous }
}
export const calculatePercentageChange = (current: number, previous: number): number => {
if (previous === 0) return current > 0 ? 100 : 0
return ((current - previous) / previous) * 100
}
export const getChangeColor = (percentageChange: number): string => {
return percentageChange >= 0 ? 'text-brand' : 'text-destructive'
}