@rbacbee-lib/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/index.cjs +629 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +300 -0
- package/dist/index.d.ts +300 -0
- package/dist/index.js +579 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/domain/errors/rbac-error.ts","../src/domain/value-objects/identifiers.ts","../src/domain/policies/policy-registry.ts","../src/infrastructure/clock/system-clock.ts","../src/domain/services/permission-evaluator.ts","../src/application/use-cases/check-permission.ts","../src/application/use-cases/check-role.ts","../src/application/rbac-engine.ts","../src/domain/entities/assignment.ts","../src/domain/entities/permission.ts","../src/domain/entities/role.ts","../src/infrastructure/cache/memory-cache.ts"],"sourcesContent":["export * from './application/rbac-engine';\nexport * from './application/use-cases/check-permission';\nexport * from './application/use-cases/check-role';\nexport * from './domain/entities/assignment';\nexport * from './domain/entities/permission';\nexport * from './domain/entities/role';\nexport * from './domain/errors/rbac-error';\nexport * from './domain/policies/policy-registry';\nexport * from './domain/rbac-types';\nexport * from './domain/services/permission-evaluator';\nexport * from './domain/value-objects/identifiers';\nexport * from './infrastructure/cache/memory-cache';\nexport * from './infrastructure/clock/system-clock';\nexport * from './ports/access-repository';\nexport * from './ports/audit-port';\nexport * from './ports/cache-port';\nexport * from './ports/clock-port';\n","export class RbacError extends Error {\n public readonly code: string;\n\n public constructor(code: string, message: string) {\n super(message);\n this.name = new.target.name;\n this.code = code;\n }\n}\n\nexport class RbacValidationError extends RbacError {\n public constructor(message: string) {\n super('RBAC_VALIDATION_ERROR', message);\n }\n}\n\nexport class RbacAuthorizationError extends RbacError {\n public constructor(message = 'Authorization denied') {\n super('RBAC_AUTHORIZATION_DENIED', message);\n }\n}\n\nexport class RbacConfigurationError extends RbacError {\n public constructor(message: string) {\n super('RBAC_CONFIGURATION_ERROR', message);\n }\n}\n","import { RbacValidationError } from '../errors/rbac-error';\n\nconst ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_:@./-]{0,255}$/;\nconst PERMISSION_PATTERN = /^[A-Za-z0-9*][A-Za-z0-9:_.*-]{0,127}$/;\n\nabstract class StringValueObject {\n public readonly value: string;\n\n protected constructor(value: string, name: string, pattern: RegExp, maxLength: number) {\n const normalized = value.trim();\n\n if (normalized.length === 0) {\n throw new RbacValidationError(`${name} cannot be empty`);\n }\n\n if (normalized.length > maxLength) {\n throw new RbacValidationError(`${name} cannot exceed ${maxLength} characters`);\n }\n\n if (!pattern.test(normalized)) {\n throw new RbacValidationError(`${name} contains invalid characters`);\n }\n\n this.value = normalized;\n Object.freeze(this);\n }\n\n public equals(other: StringValueObject): boolean {\n return this.value === other.value;\n }\n\n public toString(): string {\n return this.value;\n }\n}\n\nexport class UserId extends StringValueObject {\n private constructor(value: string) {\n super(value, 'UserId', ID_PATTERN, 256);\n }\n\n public static create(value: string): UserId {\n return new UserId(value);\n }\n}\n\nexport class RoleId extends StringValueObject {\n private constructor(value: string) {\n super(value, 'RoleId', ID_PATTERN, 256);\n }\n\n public static create(value: string): RoleId {\n return new RoleId(value);\n }\n}\n\nexport class TenantId extends StringValueObject {\n private constructor(value: string) {\n super(value, 'TenantId', ID_PATTERN, 256);\n }\n\n public static create(value: string): TenantId {\n return new TenantId(value);\n }\n}\n\nexport class ResourceId extends StringValueObject {\n private constructor(value: string) {\n super(value, 'ResourceId', ID_PATTERN, 256);\n }\n\n public static create(value: string): ResourceId {\n return new ResourceId(value);\n }\n}\n\nexport class PermissionKey extends StringValueObject {\n private constructor(value: string) {\n super(value, 'PermissionKey', PERMISSION_PATTERN, 128);\n }\n\n public static create(value: string): PermissionKey {\n return new PermissionKey(value);\n }\n}\n\nexport class PolicyKey extends StringValueObject {\n private constructor(value: string) {\n super(value, 'PolicyKey', PERMISSION_PATTERN, 128);\n }\n\n public static create(value: string): PolicyKey {\n return new PolicyKey(value);\n }\n}\n","import { PolicyKey } from '../value-objects/identifiers';\nimport type { AuthorizationResult, RbacAuthorizationContext, RbacPrincipal } from '../rbac-types';\n\nexport interface RbacPolicyInput {\n readonly principal: RbacPrincipal;\n readonly context: RbacAuthorizationContext;\n}\n\nexport type RbacPolicyHandler = (\n input: RbacPolicyInput\n) => boolean | AuthorizationResult | Promise<boolean | AuthorizationResult>;\n\nexport class PolicyRegistry {\n private readonly handlers = new Map<string, RbacPolicyHandler>();\n\n public register(policy: string, handler: RbacPolicyHandler): void {\n const key = PolicyKey.create(policy).value;\n this.handlers.set(key, handler);\n }\n\n public has(policy: string): boolean {\n return this.handlers.has(PolicyKey.create(policy).value);\n }\n\n public async evaluate(\n policy: string,\n principal: RbacPrincipal,\n context: RbacAuthorizationContext\n ): Promise<AuthorizationResult> {\n const key = PolicyKey.create(policy).value;\n const handler = this.handlers.get(key);\n\n if (handler === undefined) {\n return {\n decision: 'deny',\n reason: 'policy not registered',\n principal,\n context,\n policy: key\n };\n }\n\n const result = await handler({ principal, context });\n\n if (typeof result === 'boolean') {\n return {\n decision: result ? 'allow' : 'deny',\n reason: result ? 'policy allowed' : 'policy denied',\n principal,\n context,\n policy: key\n };\n }\n\n return result;\n }\n}\n","import type { ClockPort } from '../../ports/clock-port';\n\nexport class SystemClock implements ClockPort {\n public now(): Date {\n return new Date();\n }\n}\n","import type {\n AccessPermission,\n AccessProfile,\n AccessRole,\n AuthorizationResult,\n RbacAuthorizationContext,\n RbacPrincipal\n} from '../rbac-types';\n\nexport class PermissionEvaluator {\n public evaluatePermission(\n profile: AccessProfile,\n principal: RbacPrincipal,\n requiredPermission: string,\n context: RbacAuthorizationContext\n ): AuthorizationResult {\n const now = context.now ?? new Date();\n const matched = profile.permissions\n .filter((permission) => permissionApplies(permission, requiredPermission, context, now))\n .map((permission) => permission.key);\n\n if (matched.length > 0) {\n return {\n decision: 'allow',\n reason: 'permission matched',\n principal,\n context,\n permission: requiredPermission,\n matched\n };\n }\n\n return {\n decision: 'deny',\n reason: 'permission not found',\n principal,\n context,\n permission: requiredPermission\n };\n }\n\n public evaluateRole(\n profile: AccessProfile,\n principal: RbacPrincipal,\n requiredRole: string,\n context: RbacAuthorizationContext\n ): AuthorizationResult {\n const now = context.now ?? new Date();\n const matched = profile.roles\n .filter((role) => roleApplies(role, requiredRole, context, now))\n .map((role) => role.id);\n\n if (matched.length > 0) {\n return {\n decision: 'allow',\n reason: 'role matched',\n principal,\n context,\n role: requiredRole,\n matched\n };\n }\n\n return {\n decision: 'deny',\n reason: 'role not found',\n principal,\n context,\n role: requiredRole\n };\n }\n}\n\nexport function matchesPermission(granted: string, required: string): boolean {\n if (granted === '*' || granted === required) {\n return true;\n }\n\n const grantedParts = granted.split(':');\n const requiredParts = required.split(':');\n\n for (let index = 0; index < grantedParts.length; index += 1) {\n const grantedPart = grantedParts[index];\n const requiredPart = requiredParts[index];\n\n if (grantedPart === undefined) {\n return false;\n }\n\n if (grantedPart === '*') {\n return index === grantedParts.length - 1 || requiredPart !== undefined;\n }\n\n if (requiredPart === undefined || grantedPart !== requiredPart) {\n return false;\n }\n }\n\n return grantedParts.length === requiredParts.length;\n}\n\nfunction permissionApplies(\n granted: AccessPermission,\n requiredPermission: string,\n context: RbacAuthorizationContext,\n now: Date\n): boolean {\n if (granted.expiresAt !== undefined && granted.expiresAt <= now) {\n return false;\n }\n\n if (!scopeApplies(granted, context)) {\n return false;\n }\n\n return matchesPermission(granted.key, requiredPermission);\n}\n\nfunction roleApplies(\n granted: AccessRole,\n requiredRole: string,\n context: RbacAuthorizationContext,\n now: Date\n): boolean {\n if (granted.expiresAt !== undefined && granted.expiresAt <= now) {\n return false;\n }\n\n if (!scopeApplies(granted, context)) {\n return false;\n }\n\n return granted.id === requiredRole || granted.name === requiredRole;\n}\n\nfunction scopeApplies(\n granted: Pick<AccessPermission | AccessRole, 'tenantId' | 'resourceType' | 'resourceId'>,\n context: RbacAuthorizationContext\n): boolean {\n if (granted.tenantId !== undefined && granted.tenantId !== context.tenantId) {\n return false;\n }\n\n if (granted.resourceType !== undefined && granted.resourceType !== context.resourceType) {\n return false;\n }\n\n if (granted.resourceId !== undefined && granted.resourceId !== context.resourceId) {\n return false;\n }\n\n return true;\n}\n","import { PermissionKey, TenantId, UserId } from '../../domain/value-objects/identifiers';\nimport { PermissionEvaluator } from '../../domain/services/permission-evaluator';\nimport type {\n AccessProfile,\n AuthorizationResult,\n RbacAuthorizationContext,\n RbacPrincipal\n} from '../../domain/rbac-types';\nimport type { AccessProfileQuery, AccessRepository } from '../../ports/access-repository';\nimport type { AuditPort } from '../../ports/audit-port';\nimport type { CachePort } from '../../ports/cache-port';\nimport type { ClockPort } from '../../ports/clock-port';\nimport { SystemClock } from '../../infrastructure/clock/system-clock';\n\nexport interface CheckPermissionDependencies {\n readonly accessRepository: AccessRepository;\n readonly evaluator?: PermissionEvaluator;\n readonly cache?: CachePort;\n readonly audit?: AuditPort;\n readonly clock?: ClockPort;\n readonly cacheTtlMs?: number;\n}\n\nexport class CheckPermissionUseCase {\n private readonly accessRepository: AccessRepository;\n private readonly evaluator: PermissionEvaluator;\n private readonly cache?: CachePort;\n private readonly audit?: AuditPort;\n private readonly clock: ClockPort;\n private readonly cacheTtlMs?: number;\n\n public constructor(dependencies: CheckPermissionDependencies) {\n this.accessRepository = dependencies.accessRepository;\n this.evaluator = dependencies.evaluator ?? new PermissionEvaluator();\n this.cache = dependencies.cache;\n this.audit = dependencies.audit;\n this.clock = dependencies.clock ?? new SystemClock();\n this.cacheTtlMs = dependencies.cacheTtlMs;\n }\n\n public async execute(\n principal: RbacPrincipal,\n requiredPermission: string,\n context: RbacAuthorizationContext = {}\n ): Promise<AuthorizationResult> {\n UserId.create(principal.userId);\n PermissionKey.create(requiredPermission);\n\n const normalizedContext = normalizeContext(principal, context, this.clock.now());\n const profile = await this.loadProfile(principal, normalizedContext);\n\n const result =\n profile === null\n ? deny(principal, normalizedContext, requiredPermission, 'access profile not found')\n : this.evaluator.evaluatePermission(\n profile,\n principal,\n requiredPermission,\n normalizedContext\n );\n\n await this.audit?.record({\n type: 'authorization.checked',\n occurredAt: this.clock.now(),\n decision: result.decision,\n principal,\n permission: requiredPermission,\n context: normalizedContext,\n reason: result.reason\n });\n\n return result;\n }\n\n private async loadProfile(\n principal: RbacPrincipal,\n context: RbacAuthorizationContext\n ): Promise<AccessProfile | null> {\n const cacheKey = accessProfileCacheKey(principal.userId, context.tenantId);\n const cachedProfile = await this.cache?.get<AccessProfile>(cacheKey);\n\n if (cachedProfile !== undefined) {\n return cachedProfile;\n }\n\n const query: AccessProfileQuery = { userId: principal.userId };\n\n if (context.tenantId !== undefined) {\n TenantId.create(context.tenantId);\n Object.assign(query, { tenantId: context.tenantId });\n }\n\n const profile = await this.accessRepository.getAccessProfile(query);\n\n if (profile !== null) {\n await this.cache?.set(cacheKey, profile, this.cacheTtlMs);\n }\n\n return profile;\n }\n}\n\nexport function normalizeContext(\n principal: RbacPrincipal,\n context: RbacAuthorizationContext,\n now: Date\n): RbacAuthorizationContext {\n return {\n ...context,\n tenantId: context.tenantId ?? principal.tenantId,\n now: context.now ?? now\n };\n}\n\nexport function accessProfileCacheKey(userId: string, tenantId?: string): string {\n return `rbac:access-profile:${userId}:${tenantId ?? 'global'}`;\n}\n\nfunction deny(\n principal: RbacPrincipal,\n context: RbacAuthorizationContext,\n permission: string,\n reason: string\n): AuthorizationResult {\n return {\n decision: 'deny',\n reason,\n principal,\n context,\n permission\n };\n}\n","import { RoleId, TenantId, UserId } from '../../domain/value-objects/identifiers';\nimport { PermissionEvaluator } from '../../domain/services/permission-evaluator';\nimport type {\n AccessProfile,\n AuthorizationResult,\n RbacAuthorizationContext,\n RbacPrincipal\n} from '../../domain/rbac-types';\nimport type { AccessProfileQuery, AccessRepository } from '../../ports/access-repository';\nimport type { AuditPort } from '../../ports/audit-port';\nimport type { CachePort } from '../../ports/cache-port';\nimport type { ClockPort } from '../../ports/clock-port';\nimport { SystemClock } from '../../infrastructure/clock/system-clock';\nimport { accessProfileCacheKey, normalizeContext } from './check-permission';\n\nexport interface CheckRoleDependencies {\n readonly accessRepository: AccessRepository;\n readonly evaluator?: PermissionEvaluator;\n readonly cache?: CachePort;\n readonly audit?: AuditPort;\n readonly clock?: ClockPort;\n readonly cacheTtlMs?: number;\n}\n\nexport class CheckRoleUseCase {\n private readonly accessRepository: AccessRepository;\n private readonly evaluator: PermissionEvaluator;\n private readonly cache?: CachePort;\n private readonly audit?: AuditPort;\n private readonly clock: ClockPort;\n private readonly cacheTtlMs?: number;\n\n public constructor(dependencies: CheckRoleDependencies) {\n this.accessRepository = dependencies.accessRepository;\n this.evaluator = dependencies.evaluator ?? new PermissionEvaluator();\n this.cache = dependencies.cache;\n this.audit = dependencies.audit;\n this.clock = dependencies.clock ?? new SystemClock();\n this.cacheTtlMs = dependencies.cacheTtlMs;\n }\n\n public async execute(\n principal: RbacPrincipal,\n requiredRole: string,\n context: RbacAuthorizationContext = {}\n ): Promise<AuthorizationResult> {\n UserId.create(principal.userId);\n RoleId.create(requiredRole);\n\n const normalizedContext = normalizeContext(principal, context, this.clock.now());\n const profile = await this.loadProfile(principal, normalizedContext);\n\n const result =\n profile === null\n ? deny(principal, normalizedContext, requiredRole, 'access profile not found')\n : this.evaluator.evaluateRole(profile, principal, requiredRole, normalizedContext);\n\n await this.audit?.record({\n type: 'role.checked',\n occurredAt: this.clock.now(),\n decision: result.decision,\n principal,\n role: requiredRole,\n context: normalizedContext,\n reason: result.reason\n });\n\n return result;\n }\n\n private async loadProfile(\n principal: RbacPrincipal,\n context: RbacAuthorizationContext\n ): Promise<AccessProfile | null> {\n const cacheKey = accessProfileCacheKey(principal.userId, context.tenantId);\n const cachedProfile = await this.cache?.get<AccessProfile>(cacheKey);\n\n if (cachedProfile !== undefined) {\n return cachedProfile;\n }\n\n const query: AccessProfileQuery = { userId: principal.userId };\n\n if (context.tenantId !== undefined) {\n TenantId.create(context.tenantId);\n Object.assign(query, { tenantId: context.tenantId });\n }\n\n const profile = await this.accessRepository.getAccessProfile(query);\n\n if (profile !== null) {\n await this.cache?.set(cacheKey, profile, this.cacheTtlMs);\n }\n\n return profile;\n }\n}\n\nfunction deny(\n principal: RbacPrincipal,\n context: RbacAuthorizationContext,\n role: string,\n reason: string\n): AuthorizationResult {\n return {\n decision: 'deny',\n reason,\n principal,\n context,\n role\n };\n}\n","import { RbacAuthorizationError } from '../domain/errors/rbac-error';\nimport { PolicyRegistry } from '../domain/policies/policy-registry';\nimport type {\n AuthorizationResult,\n RbacAuthorizationContext,\n RbacPrincipal\n} from '../domain/rbac-types';\nimport { PolicyKey } from '../domain/value-objects/identifiers';\nimport type { AccessRepository } from '../ports/access-repository';\nimport type { AuditPort } from '../ports/audit-port';\nimport type { CachePort } from '../ports/cache-port';\nimport type { ClockPort } from '../ports/clock-port';\nimport { SystemClock } from '../infrastructure/clock/system-clock';\nimport { CheckPermissionUseCase } from './use-cases/check-permission';\nimport { CheckRoleUseCase } from './use-cases/check-role';\n\nexport interface RbacEngine {\n can(\n principal: RbacPrincipal,\n permission: string,\n context?: RbacAuthorizationContext\n ): Promise<AuthorizationResult>;\n assertCan(\n principal: RbacPrincipal,\n permission: string,\n context?: RbacAuthorizationContext\n ): Promise<void>;\n hasRole(\n principal: RbacPrincipal,\n role: string,\n context?: RbacAuthorizationContext\n ): Promise<AuthorizationResult>;\n evaluatePolicy(\n policy: string,\n principal: RbacPrincipal,\n context?: RbacAuthorizationContext\n ): Promise<AuthorizationResult>;\n}\n\nexport interface RbacEngineDependencies {\n readonly accessRepository: AccessRepository;\n readonly cache?: CachePort;\n readonly audit?: AuditPort;\n readonly clock?: ClockPort;\n readonly policies?: PolicyRegistry;\n readonly cacheTtlMs?: number;\n}\n\nexport class DefaultRbacEngine implements RbacEngine {\n private readonly checkPermission: CheckPermissionUseCase;\n private readonly checkRole: CheckRoleUseCase;\n private readonly policies: PolicyRegistry;\n private readonly audit?: AuditPort;\n private readonly clock: ClockPort;\n\n public constructor(dependencies: RbacEngineDependencies) {\n this.clock = dependencies.clock ?? new SystemClock();\n this.audit = dependencies.audit;\n this.policies = dependencies.policies ?? new PolicyRegistry();\n this.checkPermission = new CheckPermissionUseCase(dependencies);\n this.checkRole = new CheckRoleUseCase(dependencies);\n }\n\n public can(\n principal: RbacPrincipal,\n permission: string,\n context: RbacAuthorizationContext = {}\n ): Promise<AuthorizationResult> {\n return this.checkPermission.execute(principal, permission, context);\n }\n\n public async assertCan(\n principal: RbacPrincipal,\n permission: string,\n context: RbacAuthorizationContext = {}\n ): Promise<void> {\n const result = await this.can(principal, permission, context);\n\n if (result.decision === 'deny') {\n throw new RbacAuthorizationError(result.reason);\n }\n }\n\n public hasRole(\n principal: RbacPrincipal,\n role: string,\n context: RbacAuthorizationContext = {}\n ): Promise<AuthorizationResult> {\n return this.checkRole.execute(principal, role, context);\n }\n\n public async evaluatePolicy(\n policy: string,\n principal: RbacPrincipal,\n context: RbacAuthorizationContext = {}\n ): Promise<AuthorizationResult> {\n const key = PolicyKey.create(policy).value;\n const result = await this.policies.evaluate(key, principal, {\n ...context,\n tenantId: context.tenantId ?? principal.tenantId,\n now: context.now ?? this.clock.now()\n });\n\n await this.audit?.record({\n type: 'policy.checked',\n occurredAt: this.clock.now(),\n decision: result.decision,\n principal,\n policy: key,\n context: result.context,\n reason: result.reason\n });\n\n return result;\n }\n}\n\nexport function createRbacEngine(dependencies: RbacEngineDependencies): RbacEngine {\n return new DefaultRbacEngine(dependencies);\n}\n","import type { RoleAssignment } from '../rbac-types';\nimport { ResourceId, RoleId, TenantId, UserId } from '../value-objects/identifiers';\n\nexport class Assignment {\n public readonly userId: UserId;\n public readonly roleId: RoleId;\n public readonly tenantId?: TenantId;\n public readonly resourceType?: string;\n public readonly resourceId?: ResourceId;\n public readonly expiresAt?: Date;\n\n private constructor(input: RoleAssignment) {\n this.userId = UserId.create(input.userId);\n this.roleId = RoleId.create(input.roleId);\n this.tenantId = input.tenantId === undefined ? undefined : TenantId.create(input.tenantId);\n this.resourceType = input.resourceType;\n this.resourceId =\n input.resourceId === undefined ? undefined : ResourceId.create(input.resourceId);\n this.expiresAt = input.expiresAt;\n Object.freeze(this);\n }\n\n public static create(input: RoleAssignment): Assignment {\n return new Assignment(input);\n }\n\n public toPrimitives(): RoleAssignment {\n const output: RoleAssignment = {\n userId: this.userId.value,\n roleId: this.roleId.value\n };\n\n return {\n ...output,\n ...(this.tenantId === undefined ? {} : { tenantId: this.tenantId.value }),\n ...(this.resourceType === undefined ? {} : { resourceType: this.resourceType }),\n ...(this.resourceId === undefined ? {} : { resourceId: this.resourceId.value }),\n ...(this.expiresAt === undefined ? {} : { expiresAt: this.expiresAt })\n };\n }\n}\n","import type { PermissionDefinition } from '../rbac-types';\nimport { PermissionKey } from '../value-objects/identifiers';\n\nexport class Permission {\n public readonly key: PermissionKey;\n public readonly description?: string;\n\n private constructor(key: PermissionKey, description?: string) {\n this.key = key;\n this.description = description;\n Object.freeze(this);\n }\n\n public static create(input: PermissionDefinition): Permission {\n return new Permission(PermissionKey.create(input.key), input.description);\n }\n\n public toPrimitives(): PermissionDefinition {\n const output: PermissionDefinition = { key: this.key.value };\n\n if (this.description !== undefined) {\n return { ...output, description: this.description };\n }\n\n return output;\n }\n}\n","import type { RoleDefinition } from '../rbac-types';\nimport { PermissionKey, RoleId, TenantId } from '../value-objects/identifiers';\n\nexport class Role {\n public readonly id: RoleId;\n public readonly name: string;\n public readonly tenantId?: TenantId;\n public readonly permissions: readonly PermissionKey[];\n\n private constructor(\n id: RoleId,\n name: string,\n permissions: readonly PermissionKey[],\n tenantId?: TenantId\n ) {\n const normalizedName = name.trim();\n\n if (normalizedName.length === 0) {\n throw new Error('Role name cannot be empty');\n }\n\n this.id = id;\n this.name = normalizedName;\n this.permissions = Object.freeze([...permissions]);\n this.tenantId = tenantId;\n Object.freeze(this);\n }\n\n public static create(input: RoleDefinition): Role {\n return new Role(\n RoleId.create(input.id),\n input.name,\n (input.permissions ?? []).map((permission) => PermissionKey.create(permission)),\n input.tenantId === undefined ? undefined : TenantId.create(input.tenantId)\n );\n }\n\n public toPrimitives(): RoleDefinition {\n const output: RoleDefinition = {\n id: this.id.value,\n name: this.name,\n permissions: this.permissions.map((permission) => permission.value)\n };\n\n if (this.tenantId !== undefined) {\n return { ...output, tenantId: this.tenantId.value };\n }\n\n return output;\n }\n}\n","import type { CachePort } from '../../ports/cache-port';\n\ninterface MemoryCacheEntry {\n readonly value: unknown;\n readonly expiresAt?: number;\n}\n\nexport class MemoryCache implements CachePort {\n private readonly entries = new Map<string, MemoryCacheEntry>();\n\n public async get<TValue>(key: string): Promise<TValue | undefined> {\n const entry = this.entries.get(key);\n\n if (entry === undefined) {\n return undefined;\n }\n\n if (entry.expiresAt !== undefined && entry.expiresAt <= Date.now()) {\n this.entries.delete(key);\n return undefined;\n }\n\n return entry.value as TValue;\n }\n\n public async set<TValue>(key: string, value: TValue, ttlMs?: number): Promise<void> {\n const entry: MemoryCacheEntry =\n ttlMs === undefined ? { value } : { value, expiresAt: Date.now() + ttlMs };\n\n this.entries.set(key, entry);\n }\n\n public async delete(key: string): Promise<void> {\n this.entries.delete(key);\n }\n\n public async deleteByPrefix(prefix: string): Promise<void> {\n for (const key of this.entries.keys()) {\n if (key.startsWith(prefix)) {\n this.entries.delete(key);\n }\n }\n }\n\n public clear(): void {\n this.entries.clear();\n }\n}\n"],"mappings":"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","names":["deny"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
type RbacDecision = 'allow' | 'deny';
|
|
2
|
+
type RbacRequirementMode = 'all' | 'any';
|
|
3
|
+
interface RbacPrincipal {
|
|
4
|
+
readonly userId: string;
|
|
5
|
+
readonly tenantId?: string;
|
|
6
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
7
|
+
}
|
|
8
|
+
interface RbacAuthorizationContext {
|
|
9
|
+
readonly tenantId?: string;
|
|
10
|
+
readonly resourceType?: string;
|
|
11
|
+
readonly resourceId?: string;
|
|
12
|
+
readonly attributes?: Readonly<Record<string, unknown>>;
|
|
13
|
+
readonly now?: Date;
|
|
14
|
+
}
|
|
15
|
+
interface AccessPermission {
|
|
16
|
+
readonly key: string;
|
|
17
|
+
readonly tenantId?: string;
|
|
18
|
+
readonly resourceType?: string;
|
|
19
|
+
readonly resourceId?: string;
|
|
20
|
+
readonly expiresAt?: Date;
|
|
21
|
+
readonly sourceRoleId?: string;
|
|
22
|
+
}
|
|
23
|
+
interface AccessRole {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly name?: string;
|
|
26
|
+
readonly tenantId?: string;
|
|
27
|
+
readonly resourceType?: string;
|
|
28
|
+
readonly resourceId?: string;
|
|
29
|
+
readonly expiresAt?: Date;
|
|
30
|
+
}
|
|
31
|
+
interface AccessProfile {
|
|
32
|
+
readonly userId: string;
|
|
33
|
+
readonly tenantId?: string;
|
|
34
|
+
readonly permissions: readonly AccessPermission[];
|
|
35
|
+
readonly roles: readonly AccessRole[];
|
|
36
|
+
readonly loadedAt: Date;
|
|
37
|
+
}
|
|
38
|
+
interface AuthorizationResult {
|
|
39
|
+
readonly decision: RbacDecision;
|
|
40
|
+
readonly reason: string;
|
|
41
|
+
readonly principal: RbacPrincipal;
|
|
42
|
+
readonly context: RbacAuthorizationContext;
|
|
43
|
+
readonly permission?: string;
|
|
44
|
+
readonly role?: string;
|
|
45
|
+
readonly policy?: string;
|
|
46
|
+
readonly matched?: readonly string[];
|
|
47
|
+
}
|
|
48
|
+
interface PermissionDefinition {
|
|
49
|
+
readonly key: string;
|
|
50
|
+
readonly description?: string;
|
|
51
|
+
}
|
|
52
|
+
interface RoleDefinition {
|
|
53
|
+
readonly id: string;
|
|
54
|
+
readonly name: string;
|
|
55
|
+
readonly tenantId?: string;
|
|
56
|
+
readonly permissions?: readonly string[];
|
|
57
|
+
}
|
|
58
|
+
interface RoleAssignment {
|
|
59
|
+
readonly userId: string;
|
|
60
|
+
readonly roleId: string;
|
|
61
|
+
readonly tenantId?: string;
|
|
62
|
+
readonly resourceType?: string;
|
|
63
|
+
readonly resourceId?: string;
|
|
64
|
+
readonly expiresAt?: Date;
|
|
65
|
+
}
|
|
66
|
+
interface RoleAssignmentRevocation {
|
|
67
|
+
readonly userId: string;
|
|
68
|
+
readonly roleId: string;
|
|
69
|
+
readonly tenantId?: string;
|
|
70
|
+
readonly resourceType?: string;
|
|
71
|
+
readonly resourceId?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface RbacPolicyInput {
|
|
75
|
+
readonly principal: RbacPrincipal;
|
|
76
|
+
readonly context: RbacAuthorizationContext;
|
|
77
|
+
}
|
|
78
|
+
type RbacPolicyHandler = (input: RbacPolicyInput) => boolean | AuthorizationResult | Promise<boolean | AuthorizationResult>;
|
|
79
|
+
declare class PolicyRegistry {
|
|
80
|
+
private readonly handlers;
|
|
81
|
+
register(policy: string, handler: RbacPolicyHandler): void;
|
|
82
|
+
has(policy: string): boolean;
|
|
83
|
+
evaluate(policy: string, principal: RbacPrincipal, context: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
interface AccessProfileQuery {
|
|
87
|
+
readonly userId: string;
|
|
88
|
+
readonly tenantId?: string;
|
|
89
|
+
}
|
|
90
|
+
interface AccessRepository {
|
|
91
|
+
getAccessProfile(query: AccessProfileQuery): Promise<AccessProfile | null>;
|
|
92
|
+
}
|
|
93
|
+
interface PermissionRepository {
|
|
94
|
+
upsertPermission(permission: PermissionDefinition): Promise<void>;
|
|
95
|
+
deletePermission(permissionKey: string): Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
interface RoleRepository {
|
|
98
|
+
createRole(role: RoleDefinition): Promise<void>;
|
|
99
|
+
deleteRole(roleId: string): Promise<void>;
|
|
100
|
+
grantPermissionToRole(roleId: string, permissionKey: string): Promise<void>;
|
|
101
|
+
revokePermissionFromRole(roleId: string, permissionKey: string): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
interface AssignmentRepository {
|
|
104
|
+
assignRole(assignment: RoleAssignment): Promise<void>;
|
|
105
|
+
revokeRole(revocation: RoleAssignmentRevocation): Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
type RbacAuditEventType = 'authorization.checked' | 'policy.checked' | 'role.checked' | 'role.assigned' | 'role.revoked';
|
|
109
|
+
interface RbacAuditEvent {
|
|
110
|
+
readonly type: RbacAuditEventType;
|
|
111
|
+
readonly occurredAt: Date;
|
|
112
|
+
readonly decision?: RbacDecision;
|
|
113
|
+
readonly principal?: RbacPrincipal;
|
|
114
|
+
readonly permission?: string;
|
|
115
|
+
readonly role?: string;
|
|
116
|
+
readonly policy?: string;
|
|
117
|
+
readonly context?: RbacAuthorizationContext;
|
|
118
|
+
readonly reason?: string;
|
|
119
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
120
|
+
}
|
|
121
|
+
interface AuditPort {
|
|
122
|
+
record(event: RbacAuditEvent): Promise<void> | void;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface CachePort {
|
|
126
|
+
get<TValue>(key: string): Promise<TValue | undefined>;
|
|
127
|
+
set<TValue>(key: string, value: TValue, ttlMs?: number): Promise<void>;
|
|
128
|
+
delete(key: string): Promise<void>;
|
|
129
|
+
deleteByPrefix?(prefix: string): Promise<void>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface ClockPort {
|
|
133
|
+
now(): Date;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
interface RbacEngine {
|
|
137
|
+
can(principal: RbacPrincipal, permission: string, context?: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
138
|
+
assertCan(principal: RbacPrincipal, permission: string, context?: RbacAuthorizationContext): Promise<void>;
|
|
139
|
+
hasRole(principal: RbacPrincipal, role: string, context?: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
140
|
+
evaluatePolicy(policy: string, principal: RbacPrincipal, context?: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
141
|
+
}
|
|
142
|
+
interface RbacEngineDependencies {
|
|
143
|
+
readonly accessRepository: AccessRepository;
|
|
144
|
+
readonly cache?: CachePort;
|
|
145
|
+
readonly audit?: AuditPort;
|
|
146
|
+
readonly clock?: ClockPort;
|
|
147
|
+
readonly policies?: PolicyRegistry;
|
|
148
|
+
readonly cacheTtlMs?: number;
|
|
149
|
+
}
|
|
150
|
+
declare class DefaultRbacEngine implements RbacEngine {
|
|
151
|
+
private readonly checkPermission;
|
|
152
|
+
private readonly checkRole;
|
|
153
|
+
private readonly policies;
|
|
154
|
+
private readonly audit?;
|
|
155
|
+
private readonly clock;
|
|
156
|
+
constructor(dependencies: RbacEngineDependencies);
|
|
157
|
+
can(principal: RbacPrincipal, permission: string, context?: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
158
|
+
assertCan(principal: RbacPrincipal, permission: string, context?: RbacAuthorizationContext): Promise<void>;
|
|
159
|
+
hasRole(principal: RbacPrincipal, role: string, context?: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
160
|
+
evaluatePolicy(policy: string, principal: RbacPrincipal, context?: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
161
|
+
}
|
|
162
|
+
declare function createRbacEngine(dependencies: RbacEngineDependencies): RbacEngine;
|
|
163
|
+
|
|
164
|
+
declare class PermissionEvaluator {
|
|
165
|
+
evaluatePermission(profile: AccessProfile, principal: RbacPrincipal, requiredPermission: string, context: RbacAuthorizationContext): AuthorizationResult;
|
|
166
|
+
evaluateRole(profile: AccessProfile, principal: RbacPrincipal, requiredRole: string, context: RbacAuthorizationContext): AuthorizationResult;
|
|
167
|
+
}
|
|
168
|
+
declare function matchesPermission(granted: string, required: string): boolean;
|
|
169
|
+
|
|
170
|
+
interface CheckPermissionDependencies {
|
|
171
|
+
readonly accessRepository: AccessRepository;
|
|
172
|
+
readonly evaluator?: PermissionEvaluator;
|
|
173
|
+
readonly cache?: CachePort;
|
|
174
|
+
readonly audit?: AuditPort;
|
|
175
|
+
readonly clock?: ClockPort;
|
|
176
|
+
readonly cacheTtlMs?: number;
|
|
177
|
+
}
|
|
178
|
+
declare class CheckPermissionUseCase {
|
|
179
|
+
private readonly accessRepository;
|
|
180
|
+
private readonly evaluator;
|
|
181
|
+
private readonly cache?;
|
|
182
|
+
private readonly audit?;
|
|
183
|
+
private readonly clock;
|
|
184
|
+
private readonly cacheTtlMs?;
|
|
185
|
+
constructor(dependencies: CheckPermissionDependencies);
|
|
186
|
+
execute(principal: RbacPrincipal, requiredPermission: string, context?: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
187
|
+
private loadProfile;
|
|
188
|
+
}
|
|
189
|
+
declare function normalizeContext(principal: RbacPrincipal, context: RbacAuthorizationContext, now: Date): RbacAuthorizationContext;
|
|
190
|
+
declare function accessProfileCacheKey(userId: string, tenantId?: string): string;
|
|
191
|
+
|
|
192
|
+
interface CheckRoleDependencies {
|
|
193
|
+
readonly accessRepository: AccessRepository;
|
|
194
|
+
readonly evaluator?: PermissionEvaluator;
|
|
195
|
+
readonly cache?: CachePort;
|
|
196
|
+
readonly audit?: AuditPort;
|
|
197
|
+
readonly clock?: ClockPort;
|
|
198
|
+
readonly cacheTtlMs?: number;
|
|
199
|
+
}
|
|
200
|
+
declare class CheckRoleUseCase {
|
|
201
|
+
private readonly accessRepository;
|
|
202
|
+
private readonly evaluator;
|
|
203
|
+
private readonly cache?;
|
|
204
|
+
private readonly audit?;
|
|
205
|
+
private readonly clock;
|
|
206
|
+
private readonly cacheTtlMs?;
|
|
207
|
+
constructor(dependencies: CheckRoleDependencies);
|
|
208
|
+
execute(principal: RbacPrincipal, requiredRole: string, context?: RbacAuthorizationContext): Promise<AuthorizationResult>;
|
|
209
|
+
private loadProfile;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
declare abstract class StringValueObject {
|
|
213
|
+
readonly value: string;
|
|
214
|
+
protected constructor(value: string, name: string, pattern: RegExp, maxLength: number);
|
|
215
|
+
equals(other: StringValueObject): boolean;
|
|
216
|
+
toString(): string;
|
|
217
|
+
}
|
|
218
|
+
declare class UserId extends StringValueObject {
|
|
219
|
+
private constructor();
|
|
220
|
+
static create(value: string): UserId;
|
|
221
|
+
}
|
|
222
|
+
declare class RoleId extends StringValueObject {
|
|
223
|
+
private constructor();
|
|
224
|
+
static create(value: string): RoleId;
|
|
225
|
+
}
|
|
226
|
+
declare class TenantId extends StringValueObject {
|
|
227
|
+
private constructor();
|
|
228
|
+
static create(value: string): TenantId;
|
|
229
|
+
}
|
|
230
|
+
declare class ResourceId extends StringValueObject {
|
|
231
|
+
private constructor();
|
|
232
|
+
static create(value: string): ResourceId;
|
|
233
|
+
}
|
|
234
|
+
declare class PermissionKey extends StringValueObject {
|
|
235
|
+
private constructor();
|
|
236
|
+
static create(value: string): PermissionKey;
|
|
237
|
+
}
|
|
238
|
+
declare class PolicyKey extends StringValueObject {
|
|
239
|
+
private constructor();
|
|
240
|
+
static create(value: string): PolicyKey;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
declare class Assignment {
|
|
244
|
+
readonly userId: UserId;
|
|
245
|
+
readonly roleId: RoleId;
|
|
246
|
+
readonly tenantId?: TenantId;
|
|
247
|
+
readonly resourceType?: string;
|
|
248
|
+
readonly resourceId?: ResourceId;
|
|
249
|
+
readonly expiresAt?: Date;
|
|
250
|
+
private constructor();
|
|
251
|
+
static create(input: RoleAssignment): Assignment;
|
|
252
|
+
toPrimitives(): RoleAssignment;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
declare class Permission {
|
|
256
|
+
readonly key: PermissionKey;
|
|
257
|
+
readonly description?: string;
|
|
258
|
+
private constructor();
|
|
259
|
+
static create(input: PermissionDefinition): Permission;
|
|
260
|
+
toPrimitives(): PermissionDefinition;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
declare class Role {
|
|
264
|
+
readonly id: RoleId;
|
|
265
|
+
readonly name: string;
|
|
266
|
+
readonly tenantId?: TenantId;
|
|
267
|
+
readonly permissions: readonly PermissionKey[];
|
|
268
|
+
private constructor();
|
|
269
|
+
static create(input: RoleDefinition): Role;
|
|
270
|
+
toPrimitives(): RoleDefinition;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
declare class RbacError extends Error {
|
|
274
|
+
readonly code: string;
|
|
275
|
+
constructor(code: string, message: string);
|
|
276
|
+
}
|
|
277
|
+
declare class RbacValidationError extends RbacError {
|
|
278
|
+
constructor(message: string);
|
|
279
|
+
}
|
|
280
|
+
declare class RbacAuthorizationError extends RbacError {
|
|
281
|
+
constructor(message?: string);
|
|
282
|
+
}
|
|
283
|
+
declare class RbacConfigurationError extends RbacError {
|
|
284
|
+
constructor(message: string);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
declare class MemoryCache implements CachePort {
|
|
288
|
+
private readonly entries;
|
|
289
|
+
get<TValue>(key: string): Promise<TValue | undefined>;
|
|
290
|
+
set<TValue>(key: string, value: TValue, ttlMs?: number): Promise<void>;
|
|
291
|
+
delete(key: string): Promise<void>;
|
|
292
|
+
deleteByPrefix(prefix: string): Promise<void>;
|
|
293
|
+
clear(): void;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
declare class SystemClock implements ClockPort {
|
|
297
|
+
now(): Date;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export { type AccessPermission, type AccessProfile, type AccessProfileQuery, type AccessRepository, type AccessRole, Assignment, type AssignmentRepository, type AuditPort, type AuthorizationResult, type CachePort, type CheckPermissionDependencies, CheckPermissionUseCase, type CheckRoleDependencies, CheckRoleUseCase, type ClockPort, DefaultRbacEngine, MemoryCache, Permission, type PermissionDefinition, PermissionEvaluator, PermissionKey, type PermissionRepository, PolicyKey, PolicyRegistry, type RbacAuditEvent, type RbacAuditEventType, type RbacAuthorizationContext, RbacAuthorizationError, RbacConfigurationError, type RbacDecision, type RbacEngine, type RbacEngineDependencies, RbacError, type RbacPolicyHandler, type RbacPolicyInput, type RbacPrincipal, type RbacRequirementMode, RbacValidationError, ResourceId, Role, type RoleAssignment, type RoleAssignmentRevocation, type RoleDefinition, RoleId, type RoleRepository, SystemClock, TenantId, UserId, accessProfileCacheKey, createRbacEngine, matchesPermission, normalizeContext };
|