@unkey/rbac
Version:
99 lines (92 loc) • 4.44 kB
TypeScript
import { z } from 'zod';
import { Result, SchemaError } from '@unkey/error';
/**
* Here, the Result type is still a generic type that takes in a type T that extends the Actions
* type. It uses a mapped type to iterate over the keys of the T object and create a string literal
* union of all the possible combinations of resourceId:action strings. The [keyof T] at the end of
* the type definition means that the resulting type is a union of all the possible string literal
* unions created by the mapped type.
*
* In the example, we define a new MyActions type that matches the Actions type from the original
* question, and then use the Result type to transform it into the desired MyResult type. The
* resulting type is:
* "team.read" | "team.write" | "domain.dns.read_record" | "domain.dns.create_record"
*
*
*
* @example
* type Resources = {
* team: 'read' | 'write';
* domain: {
* dns: "read_record" | "create_record"
* }
* };
*
* type MyResult = Flatten<Resources>; // type MyResult = "team.read" | "team.write" | "domain.dns.read_record" | "domain.dns.create_record"
*
* You can also choose a custom delimiter:
* @example
* Flatten<Resources, "::">
*/
type Flatten<T extends Record<string, unknown>, Delimiter extends string = "."> = {
[K in keyof T]: T[K] extends Record<string, unknown> ? `${string & K}${Delimiter}${T[K] extends infer U ? U extends Record<string, unknown> ? Flatten<U, Delimiter> : string & U : never}` : `${string & K}${Delimiter}${string & T[K]}`;
}[keyof T];
/**
* The database takes care of isolating roles between workspaces.
* That's why we can assume the highest scope of a role is an `api` or later `gateway`
*
* role identifiers can look like this:
* - `api_id.xxx`
* - `gateway_id.xxx`
*
*/
declare function buildIdSchema(prefix: string): z.ZodEffects<z.ZodString, string, string>;
declare const apiId: z.ZodEffects<z.ZodString, string, string>;
declare const ratelimitNamespaceId: z.ZodEffects<z.ZodString, string, string>;
declare const apiActions: z.ZodEnum<["read_api", "create_api", "delete_api", "update_api", "create_key", "update_key", "delete_key", "encrypt_key", "decrypt_key", "read_key"]>;
declare const ratelimitActions: z.ZodEnum<["limit", "create_namespace", "read_namespace", "update_namespace", "delete_namespace"]>;
type Resources = {
[resourceId in `api.${z.infer<typeof apiId>}`]: z.infer<typeof apiActions>;
} & {
[resourceId in `ratelimit.${z.infer<typeof ratelimitNamespaceId>}`]: z.infer<typeof ratelimitActions>;
};
type UnkeyPermission = Flatten<Resources> | "*";
/**
* Validation for roles used for our root keys
*/
declare const unkeyPermissionValidation: z.ZodEffects<z.ZodType<UnkeyPermission, z.ZodTypeDef, UnkeyPermission>, UnkeyPermission, UnkeyPermission>;
type PermissionQuery<R extends string = string> = R | {
and: Array<PermissionQuery<R> | undefined>;
or?: never;
} | {
and?: never;
or: Array<PermissionQuery<R> | undefined>;
};
declare const permissionQuerySchema: z.ZodType<PermissionQuery>;
declare function or<R extends string = string>(...args: Array<PermissionQuery<R> | undefined>): PermissionQuery<R>;
declare function and<R extends string = string>(...args: Array<PermissionQuery<R> | undefined>): PermissionQuery<R>;
declare function buildQuery<R extends string = string>(fn: (ops: {
or: typeof or<R>;
and: typeof and<R>;
}) => PermissionQuery<R>): PermissionQuery;
/**
* buildUnkeyQuery is preloaded with out available roles and ensures typesafety for root key validation
*/
declare const buildUnkeyQuery: (fn: (ops: {
or: (...args: (PermissionQuery<UnkeyPermission> | undefined)[]) => PermissionQuery<UnkeyPermission>;
and: (...args: (PermissionQuery<UnkeyPermission> | undefined)[]) => PermissionQuery<UnkeyPermission>;
}) => PermissionQuery<UnkeyPermission>) => PermissionQuery;
declare class RBAC {
evaluatePermissions(q: PermissionQuery, roles: string[]): Result<{
valid: true;
message?: never;
} | {
valid: false;
message: string;
}, SchemaError>;
validateQuery(q: PermissionQuery): Result<{
query: PermissionQuery;
}>;
private evaluateQueryV1;
}
export { type Flatten, type PermissionQuery, RBAC, type Resources, type UnkeyPermission, and, apiActions, buildIdSchema, buildQuery, buildUnkeyQuery, or, permissionQuerySchema, ratelimitActions, unkeyPermissionValidation };