feat: roles SPA foundations

This commit is contained in:
Florian Sylvain committed 2026-10-27 22:21:12 +01:00
1 parent 80f7037d3a
commit 907949aa12
180 files changed
+4308 -835

No files matched your search

+70
View File
@@ -0,0 +1,70 @@
export type Scope = 'none' | 'own' | 'all'
export interface Grant {
key: string
scope: Scope
}
export interface RoleRef {
id: number
name: string
built_in: boolean
locked: boolean
}
export interface Access {
role: RoleRef
permissions: Grant[]
}
export interface CanOptions {
ownerId?: number
typeKey?: string
scope?: 'own' | 'all'
}
export interface ScopeOptions {
typeKey?: string
}
const TYPE_SEPARATOR = ':'
function scopeOfGrant(grants: readonly Grant[], key: string): Scope | undefined {
return grants.find((grant) => grant.key === key)?.scope
}
export function effectiveScope(
grants: readonly Grant[],
key: string,
options: ScopeOptions = {},
): Scope {
if (options.typeKey) {
const typed = scopeOfGrant(grants, `${key}${TYPE_SEPARATOR}${options.typeKey}`)
if (typed !== undefined) {
return typed
}
}
return scopeOfGrant(grants, key) ?? 'none'
}
export function allows(
grants: readonly Grant[],
userId: number | undefined,
key: string,
options: CanOptions = {},
): boolean {
const scope = effectiveScope(grants, key, options)
if (scope === 'none') {
return false
}
if (scope === 'all') {
return true
}
if (options.scope === 'all') {
return false
}
if (options.ownerId === undefined) {
return true
}
return userId !== undefined && options.ownerId !== 0 && options.ownerId === userId
}