Files
Fabric.Frontend/src/lib/auth-storage.ts
hzhang 6b35d92aef feat(frontend): public channels, self-excluded member picker, editable display name
- 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>
2026-05-15 09:09:49 +01:00

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
}