- create-channel modal: Public checkbox (default off), self excluded from member list (creator auto-added), shows member display names - Settings modal to edit your own display name - members panel shows names and marks (you) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
63 lines
1.3 KiB
TypeScript
63 lines
1.3 KiB
TypeScript
export type AuthSession = {
|
|
centerApiBase: string
|
|
accessToken: string
|
|
refreshToken: string
|
|
tokenType: string
|
|
expiresIn?: number
|
|
user: {
|
|
id: string
|
|
email: string
|
|
name: string
|
|
}
|
|
guilds: Array<{
|
|
nodeId: string
|
|
name: string
|
|
endpoint: string
|
|
status: 'active' | 'offline' | 'revoked'
|
|
}>
|
|
guildAccessTokens: Array<{
|
|
guildNodeId: string
|
|
token: string
|
|
tokenType: string
|
|
expiresIn?: number
|
|
}>
|
|
}
|
|
|
|
const KEY = 'fabric.auth.session.v1'
|
|
|
|
export function getAuthSession(): AuthSession | null {
|
|
const raw = localStorage.getItem(KEY)
|
|
if (!raw) return null
|
|
try {
|
|
return JSON.parse(raw) as AuthSession
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function setAuthSession(session: AuthSession): void {
|
|
localStorage.setItem(KEY, JSON.stringify(session))
|
|
}
|
|
|
|
export function clearAuthSession(): void {
|
|
localStorage.removeItem(KEY)
|
|
}
|
|
|
|
function parseJwtExpMs(token: string): number | null {
|
|
const payload = token.split('.')[1]
|
|
if (!payload) return null
|
|
try {
|
|
const decoded = JSON.parse(atob(payload)) as { exp?: number }
|
|
if (!decoded.exp) return null
|
|
return decoded.exp * 1000
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function isAccessTokenStale(token: string, leadMs = 60_000): boolean {
|
|
const expMs = parseJwtExpMs(token)
|
|
if (!expMs) return true
|
|
return Date.now() + leadMs >= expMs
|
|
}
|