@krutai/rbac 0.1.1
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/AI_REFERENCE.md +140 -0
- package/README.md +216 -0
- package/dist/index.d.mts +390 -0
- package/dist/index.d.ts +390 -0
- package/dist/index.js +440 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +400 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +62 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
export { ApiKeyValidationError, createApiKeyChecker, validateApiKeyFormat, validateApiKeyWithService } from 'krutai';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Core type definitions for @krutai/rbac
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* A permission string in the format "resource:action"
|
|
8
|
+
* Examples: "posts:read", "users:delete", "admin:manage"
|
|
9
|
+
*/
|
|
10
|
+
type Permission = string;
|
|
11
|
+
/**
|
|
12
|
+
* A role definition with its associated permissions and optional inheritance
|
|
13
|
+
*/
|
|
14
|
+
interface Role {
|
|
15
|
+
/** Unique name for this role */
|
|
16
|
+
name: string;
|
|
17
|
+
/** List of permissions granted to this role */
|
|
18
|
+
permissions: Permission[];
|
|
19
|
+
/** Names of roles whose permissions this role inherits */
|
|
20
|
+
inherits?: string[];
|
|
21
|
+
/** Human-readable description of this role */
|
|
22
|
+
description?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for the RBACManager
|
|
26
|
+
*/
|
|
27
|
+
interface RBACConfig {
|
|
28
|
+
/** Initial set of roles to register */
|
|
29
|
+
roles: Role[];
|
|
30
|
+
/** Name of the role assigned to users with no explicit role */
|
|
31
|
+
defaultRole?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Options for permission checks
|
|
35
|
+
*/
|
|
36
|
+
interface CheckOptions {
|
|
37
|
+
/**
|
|
38
|
+
* When checking multiple permissions:
|
|
39
|
+
* - true → user must have ALL permissions (AND)
|
|
40
|
+
* - false → user must have AT LEAST ONE permission (OR)
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
requireAll?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The context object representing the current user/request being checked
|
|
47
|
+
*/
|
|
48
|
+
interface RBACContext {
|
|
49
|
+
/** Optional identifier for the user */
|
|
50
|
+
userId?: string;
|
|
51
|
+
/** List of role names assigned to this user */
|
|
52
|
+
roles: string[];
|
|
53
|
+
/** Optional arbitrary metadata for custom logic */
|
|
54
|
+
metadata?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Result of a permission check with additional details
|
|
58
|
+
*/
|
|
59
|
+
interface PermissionCheckResult {
|
|
60
|
+
/** Whether the check passed */
|
|
61
|
+
granted: boolean;
|
|
62
|
+
/** The permission(s) that were checked */
|
|
63
|
+
permissions: Permission[];
|
|
64
|
+
/** The roles that were evaluated */
|
|
65
|
+
roles: string[];
|
|
66
|
+
/** Which permissions were missing (if denied) */
|
|
67
|
+
missing?: Permission[];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A guard function that takes a context and returns whether access is granted
|
|
71
|
+
*/
|
|
72
|
+
type GuardFn = (context: RBACContext) => boolean;
|
|
73
|
+
/**
|
|
74
|
+
* A middleware-style handler function
|
|
75
|
+
*/
|
|
76
|
+
type HandlerFn<TContext = unknown, TResult = unknown> = (context: TContext) => TResult | Promise<TResult>;
|
|
77
|
+
/**
|
|
78
|
+
* A middleware-style deny handler
|
|
79
|
+
*/
|
|
80
|
+
type DenyHandlerFn<TContext = unknown, TResult = unknown> = (context: TContext, permission: Permission) => TResult | Promise<TResult>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* RBACManager — core class for role-based access control
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The main RBAC engine. Manages roles, resolves inheritance chains,
|
|
88
|
+
* and evaluates permission checks against a user context.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* const rbac = new RBACManager({
|
|
92
|
+
* roles: [
|
|
93
|
+
* { name: 'user', permissions: ['posts:read'] },
|
|
94
|
+
* { name: 'admin', permissions: ['posts:delete'], inherits: ['user'] },
|
|
95
|
+
* ],
|
|
96
|
+
* });
|
|
97
|
+
*
|
|
98
|
+
* const ctx = { roles: ['admin'] };
|
|
99
|
+
* rbac.can(ctx, 'posts:read'); // true (inherited from user)
|
|
100
|
+
* rbac.can(ctx, 'posts:delete'); // true
|
|
101
|
+
* rbac.can(ctx, 'users:manage'); // false
|
|
102
|
+
*/
|
|
103
|
+
declare class RBACManager {
|
|
104
|
+
private readonly roles;
|
|
105
|
+
private readonly defaultRole?;
|
|
106
|
+
/** Cache of resolved permissions per role to avoid repeated traversal */
|
|
107
|
+
private readonly permissionCache;
|
|
108
|
+
constructor(config: RBACConfig);
|
|
109
|
+
/**
|
|
110
|
+
* Register a new role. Clears the permission cache.
|
|
111
|
+
*/
|
|
112
|
+
addRole(role: Role): void;
|
|
113
|
+
/**
|
|
114
|
+
* Remove a role by name. Clears the permission cache.
|
|
115
|
+
* @throws {RoleNotFoundError} if the role does not exist
|
|
116
|
+
*/
|
|
117
|
+
removeRole(name: string): void;
|
|
118
|
+
/**
|
|
119
|
+
* Retrieve a role definition by name.
|
|
120
|
+
*/
|
|
121
|
+
getRole(name: string): Role | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Returns all registered roles as an array.
|
|
124
|
+
*/
|
|
125
|
+
getAllRoles(): Role[];
|
|
126
|
+
/**
|
|
127
|
+
* Resolves the full set of permissions for a single role,
|
|
128
|
+
* including all inherited permissions (with cycle detection).
|
|
129
|
+
*
|
|
130
|
+
* @throws {RoleNotFoundError} if the role does not exist
|
|
131
|
+
* @throws {CircularInheritanceError} if a circular inheritance chain is detected
|
|
132
|
+
*/
|
|
133
|
+
getPermissionsForRole(roleName: string): Set<Permission>;
|
|
134
|
+
/**
|
|
135
|
+
* Resolves the union of all permissions across multiple roles.
|
|
136
|
+
*/
|
|
137
|
+
getPermissionsForRoles(roleNames: string[]): Set<Permission>;
|
|
138
|
+
/**
|
|
139
|
+
* Check whether the context has a specific permission.
|
|
140
|
+
* Supports wildcard permissions (e.g. "*:*" or "posts:*").
|
|
141
|
+
*/
|
|
142
|
+
hasPermission(context: RBACContext, permission: Permission, _opts?: CheckOptions): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Check whether the context has AT LEAST ONE of the given permissions.
|
|
145
|
+
*/
|
|
146
|
+
hasAnyPermission(context: RBACContext, permissions: Permission[]): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Check whether the context has ALL of the given permissions.
|
|
149
|
+
*/
|
|
150
|
+
hasAllPermissions(context: RBACContext, permissions: Permission[]): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Check whether the context has a specific role assigned.
|
|
153
|
+
*/
|
|
154
|
+
hasRole(context: RBACContext, roleName: string): boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Check whether the context has AT LEAST ONE of the given roles.
|
|
157
|
+
*/
|
|
158
|
+
hasAnyRole(context: RBACContext, roleNames: string[]): boolean;
|
|
159
|
+
/**
|
|
160
|
+
* Alias for `hasPermission`. Reads naturally in conditional expressions.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* if (rbac.can(ctx, 'posts:delete')) { ... }
|
|
164
|
+
*/
|
|
165
|
+
can(context: RBACContext, permission: Permission): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Inverse of `can`. Reads naturally in guard expressions.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* if (rbac.cannot(ctx, 'posts:delete')) throw new PermissionDeniedError(...);
|
|
171
|
+
*/
|
|
172
|
+
cannot(context: RBACContext, permission: Permission): boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Detailed permission check that returns a result object with context.
|
|
175
|
+
*/
|
|
176
|
+
check(context: RBACContext, permissions: Permission[], opts?: CheckOptions): PermissionCheckResult;
|
|
177
|
+
private resolveContextRoles;
|
|
178
|
+
private resolvePermissions;
|
|
179
|
+
/**
|
|
180
|
+
* Matches a required permission against the user's permission set,
|
|
181
|
+
* supporting wildcard segments ("*").
|
|
182
|
+
*
|
|
183
|
+
* Wildcard rules:
|
|
184
|
+
* - "*:*" matches everything
|
|
185
|
+
* - "posts:*" matches any action on "posts"
|
|
186
|
+
* - "*:read" matches "read" on any resource
|
|
187
|
+
*/
|
|
188
|
+
private matchPermission;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Role and permission definition helpers for @krutai/rbac
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Type-safe helper to define a role.
|
|
197
|
+
* Useful for getting autocomplete and validation when building role configs.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* const editorRole = defineRole({
|
|
201
|
+
* name: 'editor',
|
|
202
|
+
* permissions: ['posts:read', 'posts:write'],
|
|
203
|
+
* inherits: ['user'],
|
|
204
|
+
* });
|
|
205
|
+
*/
|
|
206
|
+
declare function defineRole(config: Role): Role;
|
|
207
|
+
/**
|
|
208
|
+
* Creates a typed permission string in the format "resource:action".
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* const canReadPosts = definePermission('posts', 'read'); // "posts:read"
|
|
212
|
+
* const canDeleteUsers = definePermission('users', 'delete'); // "users:delete"
|
|
213
|
+
*/
|
|
214
|
+
declare function definePermission(resource: string, action: string): Permission;
|
|
215
|
+
/**
|
|
216
|
+
* Creates a set of CRUD permissions for a given resource.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* const postPermissions = crudPermissions('posts');
|
|
220
|
+
* // ["posts:create", "posts:read", "posts:update", "posts:delete"]
|
|
221
|
+
*/
|
|
222
|
+
declare function crudPermissions(resource: string): Permission[];
|
|
223
|
+
/**
|
|
224
|
+
* Creates a wildcard permission for a resource (grants all actions).
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* wildcardPermission('posts') // "posts:*"
|
|
228
|
+
*/
|
|
229
|
+
declare function wildcardPermission(resource: string): Permission;
|
|
230
|
+
/**
|
|
231
|
+
* Guest role — read-only access to public resources
|
|
232
|
+
*/
|
|
233
|
+
declare const GUEST_ROLE: Role;
|
|
234
|
+
/**
|
|
235
|
+
* User role — standard authenticated user
|
|
236
|
+
*/
|
|
237
|
+
declare const USER_ROLE: Role;
|
|
238
|
+
/**
|
|
239
|
+
* Moderator role — can manage user-generated content
|
|
240
|
+
*/
|
|
241
|
+
declare const MODERATOR_ROLE: Role;
|
|
242
|
+
/**
|
|
243
|
+
* Admin role — full control over application resources
|
|
244
|
+
*/
|
|
245
|
+
declare const ADMIN_ROLE: Role;
|
|
246
|
+
/**
|
|
247
|
+
* Super Admin role — unrestricted access to everything
|
|
248
|
+
*/
|
|
249
|
+
declare const SUPER_ADMIN_ROLE: Role;
|
|
250
|
+
/**
|
|
251
|
+
* All pre-built roles in hierarchy order (least → most privileged)
|
|
252
|
+
*/
|
|
253
|
+
declare const DEFAULT_ROLES: Role[];
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Guard and middleware helpers for @krutai/rbac
|
|
257
|
+
*
|
|
258
|
+
* These utilities make it easy to integrate RBAC checks into
|
|
259
|
+
* request handlers, middleware chains, and framework-agnostic guards.
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Creates a guard function that checks a single permission.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* const canDeletePosts = createPermissionGuard(rbac, 'posts:delete');
|
|
267
|
+
* if (!canDeletePosts(ctx)) throw new PermissionDeniedError('posts:delete', ctx.roles);
|
|
268
|
+
*/
|
|
269
|
+
declare function createPermissionGuard(rbac: RBACManager, permission: Permission): GuardFn;
|
|
270
|
+
/**
|
|
271
|
+
* Creates a guard function that checks whether the context has a specific role.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* const isAdmin = createRoleGuard(rbac, 'admin');
|
|
275
|
+
* if (!isAdmin(ctx)) throw new PermissionDeniedError('admin role', ctx.roles);
|
|
276
|
+
*/
|
|
277
|
+
declare function createRoleGuard(rbac: RBACManager, roleName: string): GuardFn;
|
|
278
|
+
/**
|
|
279
|
+
* Creates a guard that requires ALL of the given permissions.
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* const canManagePosts = createAllPermissionsGuard(rbac, ['posts:read', 'posts:delete']);
|
|
283
|
+
*/
|
|
284
|
+
declare function createAllPermissionsGuard(rbac: RBACManager, permissions: Permission[]): GuardFn;
|
|
285
|
+
/**
|
|
286
|
+
* Creates a guard that requires AT LEAST ONE of the given permissions.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* const canViewContent = createAnyPermissionGuard(rbac, ['posts:read', 'drafts:read']);
|
|
290
|
+
*/
|
|
291
|
+
declare function createAnyPermissionGuard(rbac: RBACManager, permissions: Permission[]): GuardFn;
|
|
292
|
+
/**
|
|
293
|
+
* Wraps a handler function with a permission check.
|
|
294
|
+
* Calls `onDenied` (or throws `PermissionDeniedError`) if the check fails.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* const deletePost = withPermission(
|
|
298
|
+
* rbac,
|
|
299
|
+
* 'posts:delete',
|
|
300
|
+
* async (ctx) => { await db.posts.delete(ctx.postId); },
|
|
301
|
+
* (ctx, perm) => { throw new Error(`Forbidden: ${perm}`); }
|
|
302
|
+
* );
|
|
303
|
+
*/
|
|
304
|
+
declare function withPermission<TContext extends {
|
|
305
|
+
rbac: RBACContext;
|
|
306
|
+
}, TResult>(rbac: RBACManager, permission: Permission, handler: HandlerFn<TContext, TResult>, onDenied?: DenyHandlerFn<TContext, TResult>): HandlerFn<TContext, TResult>;
|
|
307
|
+
/**
|
|
308
|
+
* Represents a minimal Express/Next.js-style request with an `rbacContext` property.
|
|
309
|
+
* Attach an `RBACContext` to your request object before using this middleware.
|
|
310
|
+
*/
|
|
311
|
+
interface RBACRequest {
|
|
312
|
+
rbacContext?: RBACContext;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Express/Next.js-compatible middleware factory.
|
|
316
|
+
* Expects `req.rbacContext` to be populated by a preceding auth middleware.
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* // Express
|
|
320
|
+
* app.delete('/posts/:id', requirePermission(rbac, 'posts:delete'), deletePostHandler);
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* // Next.js API route (pages router)
|
|
324
|
+
* export default requirePermission(rbac, 'posts:delete')(handler);
|
|
325
|
+
*/
|
|
326
|
+
declare function requirePermission(rbac: RBACManager, permission: Permission): (req: RBACRequest, res: {
|
|
327
|
+
status: (code: number) => {
|
|
328
|
+
json: (body: unknown) => void;
|
|
329
|
+
};
|
|
330
|
+
}, next: () => void) => void;
|
|
331
|
+
/**
|
|
332
|
+
* Express/Next.js-compatible middleware factory for role checks.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* app.get('/admin', requireRole(rbac, 'admin'), adminHandler);
|
|
336
|
+
*/
|
|
337
|
+
declare function requireRole(rbac: RBACManager, roleName: string): (req: RBACRequest, res: {
|
|
338
|
+
status: (code: number) => {
|
|
339
|
+
json: (body: unknown) => void;
|
|
340
|
+
};
|
|
341
|
+
}, next: () => void) => void;
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Custom error classes for @krutai/rbac
|
|
345
|
+
*/
|
|
346
|
+
/**
|
|
347
|
+
* Base error class for all RBAC-related errors
|
|
348
|
+
*/
|
|
349
|
+
declare class RBACError extends Error {
|
|
350
|
+
constructor(message: string);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Thrown when a user lacks the required permission to perform an action
|
|
354
|
+
*/
|
|
355
|
+
declare class PermissionDeniedError extends RBACError {
|
|
356
|
+
/** The permission that was required but not held */
|
|
357
|
+
readonly permission: string;
|
|
358
|
+
/** The roles that were evaluated */
|
|
359
|
+
readonly roles: string[];
|
|
360
|
+
constructor(permission: string, roles: string[]);
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Thrown when a referenced role does not exist in the registry
|
|
364
|
+
*/
|
|
365
|
+
declare class RoleNotFoundError extends RBACError {
|
|
366
|
+
/** The name of the role that was not found */
|
|
367
|
+
readonly roleName: string;
|
|
368
|
+
constructor(roleName: string);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Thrown when a circular inheritance chain is detected in role definitions
|
|
372
|
+
*/
|
|
373
|
+
declare class CircularInheritanceError extends RBACError {
|
|
374
|
+
/** The chain of roles that form the cycle */
|
|
375
|
+
readonly chain: string[];
|
|
376
|
+
constructor(chain: string[]);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @krutai/rbac — Role-Based Access Control for KrutAI
|
|
381
|
+
*
|
|
382
|
+
* A flexible, type-safe RBAC library with role inheritance,
|
|
383
|
+
* wildcard permissions, and framework-agnostic guard helpers.
|
|
384
|
+
*
|
|
385
|
+
* @packageDocumentation
|
|
386
|
+
*/
|
|
387
|
+
|
|
388
|
+
declare const VERSION = "0.1.0";
|
|
389
|
+
|
|
390
|
+
export { ADMIN_ROLE, type CheckOptions, CircularInheritanceError, DEFAULT_ROLES, type DenyHandlerFn, GUEST_ROLE, type GuardFn, type HandlerFn, MODERATOR_ROLE, type Permission, type PermissionCheckResult, PermissionDeniedError, type RBACConfig, type RBACContext, RBACError, RBACManager, type RBACRequest, type Role, RoleNotFoundError, SUPER_ADMIN_ROLE, USER_ROLE, VERSION, createAllPermissionsGuard, createAnyPermissionGuard, createPermissionGuard, createRoleGuard, crudPermissions, definePermission, defineRole, requirePermission, requireRole, wildcardPermission, withPermission };
|