81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
import { useMemo, useState } from 'react'
|
|
import type { PropsWithChildren } from 'react'
|
|
import { clearAuthSession, getAuthSession, isAccessTokenStale, setAuthSession } from '../lib/auth-storage'
|
|
import type { AuthSession } from '../lib/auth-storage'
|
|
import { loginCenter, logoutCenter, meGuildsCenter, refreshCenter } from '../lib/center-auth-client'
|
|
import { AuthContext } from './auth-context'
|
|
import type { AuthContextValue } from './auth-context'
|
|
|
|
export function AuthProvider({ children }: PropsWithChildren) {
|
|
const [session, setSession] = useState<AuthSession | null>(getAuthSession())
|
|
|
|
const value = useMemo<AuthContextValue>(
|
|
() => ({
|
|
session,
|
|
isAuthed: !!session,
|
|
login: async (centerApiBase: string, email: string, password: string) => {
|
|
const next = await loginCenter(centerApiBase, { email, password })
|
|
setAuthSession(next)
|
|
setSession(next)
|
|
},
|
|
logout: async () => {
|
|
if (session?.refreshToken) {
|
|
try {
|
|
await logoutCenter(session.centerApiBase, session.refreshToken)
|
|
} catch {
|
|
// noop
|
|
}
|
|
}
|
|
clearAuthSession()
|
|
setSession(null)
|
|
},
|
|
ensureFreshToken: async () => {
|
|
if (!session) return null
|
|
if (!isAccessTokenStale(session.accessToken)) return session.accessToken
|
|
|
|
const refreshed = await refreshCenter(session.centerApiBase, session.refreshToken)
|
|
const next: AuthSession = {
|
|
...session,
|
|
accessToken: refreshed.accessToken,
|
|
refreshToken: refreshed.refreshToken,
|
|
tokenType: refreshed.tokenType,
|
|
expiresIn: refreshed.expiresIn,
|
|
}
|
|
setAuthSession(next)
|
|
setSession(next)
|
|
return next.accessToken
|
|
},
|
|
refreshGuilds: async () => {
|
|
if (!session) return
|
|
let accessToken = session.accessToken
|
|
let refreshToken = session.refreshToken
|
|
let tokenType = session.tokenType
|
|
let expiresIn = session.expiresIn
|
|
if (isAccessTokenStale(session.accessToken)) {
|
|
const refreshed = await refreshCenter(session.centerApiBase, session.refreshToken)
|
|
accessToken = refreshed.accessToken
|
|
refreshToken = refreshed.refreshToken
|
|
tokenType = refreshed.tokenType
|
|
expiresIn = refreshed.expiresIn
|
|
}
|
|
|
|
const guildData = await meGuildsCenter(session.centerApiBase, accessToken)
|
|
const next: AuthSession = {
|
|
...session,
|
|
accessToken,
|
|
refreshToken,
|
|
tokenType,
|
|
expiresIn,
|
|
guilds: guildData.guilds,
|
|
guildAccessTokens: guildData.guildAccessTokens,
|
|
}
|
|
setAuthSession(next)
|
|
setSession(next)
|
|
},
|
|
}),
|
|
[session],
|
|
)
|
|
|
|
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
|
|
}
|