71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
import {
|
|
getUserApps,
|
|
getUserById,
|
|
getUserDataGeneration,
|
|
getUserPermissions,
|
|
type AppDb,
|
|
type UserRow,
|
|
} from '@authportal/db'
|
|
import { allPermissionKeys, normalizePermissionKeys } from '@authportal/shared'
|
|
import { TtlCache } from './cache.js'
|
|
|
|
export type UserProfile = {
|
|
row: UserRow
|
|
/** Сырые app_id из БД. */
|
|
apps: string[]
|
|
/** Нормализованные права; у админа — полный каталог. */
|
|
permissions: string[]
|
|
}
|
|
|
|
type Entry = { profile: UserProfile; generation: number }
|
|
|
|
/** Страховочный TTL: основная инвалидация — по счётчику поколения из @authportal/db. */
|
|
const PROFILE_TTL_MS = 10_000
|
|
const PROFILE_MAX = 500
|
|
|
|
const caches = new WeakMap<AppDb, TtlCache<string, Entry>>()
|
|
|
|
function cacheFor(db: AppDb): TtlCache<string, Entry> {
|
|
let c = caches.get(db)
|
|
if (!c) {
|
|
c = new TtlCache({ max: PROFILE_MAX, ttlMs: PROFILE_TTL_MS })
|
|
caches.set(db, c)
|
|
}
|
|
return c
|
|
}
|
|
|
|
export function loadUserProfile(db: AppDb, id: string): UserProfile | undefined {
|
|
const row = getUserById(db, id)
|
|
if (!row) return undefined
|
|
return profileFromRow(db, row)
|
|
}
|
|
|
|
function profileFromRow(db: AppDb, row: UserRow): UserProfile {
|
|
const apps = getUserApps(db, row.id)
|
|
const permissions = row.isAdmin
|
|
? allPermissionKeys()
|
|
: normalizePermissionKeys(getUserPermissions(db, row.id))
|
|
return { row, apps, permissions }
|
|
}
|
|
|
|
/**
|
|
* Профиль пользователя (строка + приложения + права) с кэшем: 3 SELECT на
|
|
* запрос → 0 пока данные пользователей не менялись.
|
|
*/
|
|
export function getUserProfile(
|
|
db: AppDb,
|
|
id: string,
|
|
): UserProfile | undefined {
|
|
const cache = cacheFor(db)
|
|
const generation = getUserDataGeneration()
|
|
const hit = cache.get(id)
|
|
if (hit && hit.generation === generation) return hit.profile
|
|
const profile = loadUserProfile(db, id)
|
|
if (!profile) {
|
|
cache.delete(id)
|
|
return undefined
|
|
}
|
|
cache.set(id, { profile, generation })
|
|
return profile
|
|
}
|