import { s, type ParseOptions, parse, InvalidSchemaError, HttpStatus } from "bknd/utils"; export const permissionOptionsSchema = s .strictObject({ description: s.string(), filterable: s.boolean(), }) .partial(); export type TPermission = { name: string; description?: string; filterable?: boolean; context?: any; }; export type PermissionOptions = s.Static; export type PermissionContext

> = P extends Permission< any, any, infer Context, any > ? Context extends s.ObjectSchema ? s.Static : never : never; export class InvalidPermissionContextError extends InvalidSchemaError { override name = "InvalidPermissionContextError"; // changing to internal server error because it's an unexpected behavior override code = HttpStatus.INTERNAL_SERVER_ERROR; static from(e: InvalidSchemaError) { return new InvalidPermissionContextError(e.schema, e.value, e.errors); } } export class Permission< Name extends string = string, Options extends PermissionOptions = {}, Context extends s.ObjectSchema | undefined = undefined, ContextValue = Context extends s.ObjectSchema ? s.Static : undefined, > { constructor( public name: Name, public options: Options = {} as Options, public context: Context = undefined as Context, ) {} isFilterable() { return this.options.filterable === true; } parseContext(ctx: ContextValue, opts?: ParseOptions) { // @todo: allow additional properties if (!this.context) return ctx; try { return this.context ? parse(this.context!, ctx, opts) : undefined; } catch (e) { if (e instanceof InvalidSchemaError) { throw InvalidPermissionContextError.from(e); } throw e; } } toJSON() { return { name: this.name, ...this.options, context: this.context, }; } }