OverviewUsage.constants.ts107 lines · main
1import {
2 RawAuthMetricsResponseSchema,
3 type RawAuthMetricsResponse,
4 type RawAuthMetricsRow,
5} from './OverviewUsage.schema'
6import { get } from '@/data/fetchers'
7
8export type AuthMetricsResponse = RawAuthMetricsResponse
9
10export type MetricName =
11 | 'activeUsers'
12 | 'signUpCount'
13 | 'apiTotalRequests'
14 | 'apiErrorRequests'
15 | 'authTotalRequests'
16 | 'authTotalErrors'
17 | 'passwordResetRequests'
18
19type NumericMetricKey = keyof Omit<RawAuthMetricsRow, 'period'>
20
21const metricKeyMap: Record<MetricName, NumericMetricKey> = {
22 activeUsers: 'active_users',
23 signUpCount: 'sign_up_count',
24 apiTotalRequests: 'api_total_requests',
25 apiErrorRequests: 'api_error_requests',
26 authTotalRequests: 'auth_total_requests',
27 authTotalErrors: 'auth_total_errors',
28 passwordResetRequests: 'password_reset_requests',
29}
30
31export const fetchAllAuthMetrics = async (projectRef: string): Promise<RawAuthMetricsResponse> => {
32 const { data, error } = await get(
33 `/platform/projects/{ref}/analytics/endpoints/auth.metrics` as any,
34 {
35 params: {
36 path: { ref: projectRef },
37 query: {
38 interval: '1day',
39 },
40 },
41 }
42 )
43 if (error) throw error
44
45 const parsed = RawAuthMetricsResponseSchema.safeParse(data)
46 if (!parsed.success) {
47 const first = parsed.error.issues[0]
48 throw new Error(`Invalid auth metrics response: ${first?.message ?? 'Invalid shape'}`)
49 }
50 return parsed.data
51}
52
53export const getMetricValues = (
54 metrics: AuthMetricsResponse | undefined,
55 metricName: MetricName
56) => {
57 const key = metricKeyMap[metricName]
58 const currentRow = metrics?.result.find((r) => r.period === 'current')
59 const previousRow = metrics?.result.find((r) => r.period === 'previous')
60 return {
61 current: currentRow ? currentRow[key] : 0,
62 previous: previousRow ? previousRow[key] : 0,
63 }
64}
65
66export const getApiSuccessRates = (metrics: AuthMetricsResponse | undefined) => {
67 const { current: apiTotalCurrent, previous: apiTotalPrevious } = getMetricValues(
68 metrics,
69 'apiTotalRequests'
70 )
71 const { current: apiErrorCurrent, previous: apiErrorPrevious } = getMetricValues(
72 metrics,
73 'apiErrorRequests'
74 )
75 const current =
76 apiTotalCurrent > 0 ? Math.max(0, 100 - (apiErrorCurrent / apiTotalCurrent) * 100) : 0
77 const previous =
78 apiTotalPrevious > 0 ? Math.max(0, 100 - (apiErrorPrevious / apiTotalPrevious) * 100) : 0
79 return { current, previous }
80}
81
82export const getAuthSuccessRates = (metrics: AuthMetricsResponse | undefined) => {
83 const { current: authTotalRequestsCurrent, previous: authTotalRequestsPrevious } =
84 getMetricValues(metrics, 'authTotalRequests')
85 const { current: authTotalErrorsCurrent, previous: authTotalErrorsPrevious } = getMetricValues(
86 metrics,
87 'authTotalErrors'
88 )
89 const current =
90 authTotalRequestsCurrent > 0
91 ? Math.max(0, 100 - (authTotalErrorsCurrent / authTotalRequestsCurrent) * 100)
92 : 0
93 const previous =
94 authTotalRequestsPrevious > 0
95 ? Math.max(0, 100 - (authTotalErrorsPrevious / authTotalRequestsPrevious) * 100)
96 : 0
97 return { current, previous }
98}
99
100export const calculatePercentageChange = (current: number, previous: number): number => {
101 if (previous === 0) return current > 0 ? 100 : 0
102 return ((current - previous) / previous) * 100
103}
104
105export const getChangeColor = (percentageChange: number): string => {
106 return percentageChange >= 0 ? 'text-brand' : 'text-destructive'
107}