@auth-gate/rbac 0.8.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.
@@ -0,0 +1,315 @@
1
+ /** A resource definition: declares available actions and optional scopes. */
2
+ interface ResourceConfig {
3
+ actions: readonly string[];
4
+ scopes?: readonly string[];
5
+ }
6
+ /** Context provided to condition functions for attribute-based decisions. */
7
+ interface ConditionContext {
8
+ user: {
9
+ id: string;
10
+ metadata?: Record<string, unknown>;
11
+ };
12
+ resource?: {
13
+ id?: string;
14
+ ownerId?: string;
15
+ metadata?: Record<string, unknown>;
16
+ };
17
+ env: {
18
+ timestamp: number;
19
+ hour: number;
20
+ dayOfWeek: number;
21
+ };
22
+ }
23
+ /** A named condition function evaluated at check time (client/edge only). */
24
+ type ConditionFn = (ctx: ConditionContext) => boolean;
25
+ /**
26
+ * Grant value for a resource action.
27
+ *
28
+ * - `true` — boolean access (Phase 1)
29
+ * - `string` — scope key, e.g. "own", "department", "all" (Phase 2)
30
+ * - `{ when: string; scope?: string }` — conditional grant (Phase 2)
31
+ */
32
+ type GrantValue = true | string | {
33
+ when: string;
34
+ scope?: string;
35
+ };
36
+ /** A role definition with grants matrix and optional inheritance. */
37
+ interface RoleConfig {
38
+ name: string;
39
+ description?: string;
40
+ inherits?: readonly string[];
41
+ grants: Record<string, Record<string, GrantValue>>;
42
+ /** Previous config key if this role was renamed. */
43
+ renamedFrom?: string;
44
+ }
45
+ /** Root RBAC config object passed to `defineRbac()`. */
46
+ interface RbacConfig {
47
+ resources: Record<string, ResourceConfig>;
48
+ conditions?: Record<string, ConditionFn>;
49
+ roles: Record<string, RoleConfig>;
50
+ }
51
+ /** Extract literal resource keys from an RBAC config type. */
52
+ type InferResourceKeys<T> = T extends {
53
+ resources: infer R;
54
+ } ? keyof R & string : never;
55
+ /** Extract literal role keys from an RBAC config type. */
56
+ type InferRoleKeys<T> = T extends {
57
+ roles: infer R;
58
+ } ? keyof R & string : never;
59
+ /** Extract action literals for a specific resource from an RBAC config type. */
60
+ type InferActions<T, Resource extends string> = T extends {
61
+ resources: infer R;
62
+ } ? Resource extends keyof R ? R[Resource] extends {
63
+ actions: infer A;
64
+ } ? A extends readonly (infer U)[] ? U & string : never : never : never : never;
65
+ /** Produce `"resource:action"` union from all resources in an RBAC config type. */
66
+ type InferPermissions<T> = T extends {
67
+ resources: infer R;
68
+ } ? {
69
+ [K in keyof R & string]: R[K] extends {
70
+ actions: infer A;
71
+ } ? A extends readonly (infer U)[] ? `${K}:${U & string}` : never : never;
72
+ }[keyof R & string] : never;
73
+ /** Extract scope literals for a specific resource from an RBAC config type. */
74
+ type InferScopes<T, Resource extends string> = T extends {
75
+ resources: infer R;
76
+ } ? Resource extends keyof R ? R[Resource] extends {
77
+ scopes: infer S;
78
+ } ? S extends readonly (infer U)[] ? U & string : never : never : never : never;
79
+ /** Extract literal condition keys from an RBAC config type. */
80
+ type InferConditionKeys<T> = T extends {
81
+ conditions: infer C;
82
+ } ? keyof C & string : never;
83
+ /** A structured resource with a `key` constant and an `actions` map of `"resource:action"` strings. */
84
+ type StructuredResource<T, K extends string> = {
85
+ readonly key: K;
86
+ readonly actions: {
87
+ readonly [A in InferActions<T, K>]: `${K}:${A}`;
88
+ };
89
+ };
90
+ /** Map of all resources as structured objects: `resources.documents.actions.read` -> `"documents:read"`. */
91
+ type StructuredResources<T> = {
92
+ readonly [K in InferResourceKeys<T>]: StructuredResource<T, K>;
93
+ };
94
+ /** A structured role with `key`, `name`, and `grants` from the config. */
95
+ type StructuredRole<T, K extends string> = {
96
+ readonly key: K;
97
+ readonly name: T extends {
98
+ roles: infer R;
99
+ } ? K extends keyof R ? R[K] extends {
100
+ name: infer N;
101
+ } ? N : string : string : string;
102
+ readonly grants: T extends {
103
+ roles: infer R;
104
+ } ? K extends keyof R ? R[K] extends {
105
+ grants: infer G;
106
+ } ? Readonly<G> : {} : {} : {};
107
+ };
108
+ /** Map of all roles as structured objects: `roles.admin.key` -> `"admin"`. */
109
+ type StructuredRoles<T> = {
110
+ readonly [K in InferRoleKeys<T>]: StructuredRole<T, K>;
111
+ };
112
+ /** Permissions grouped by resource then action: `permissions.documents.read` -> `"documents:read"`. */
113
+ type StructuredPermissions<T> = {
114
+ readonly [K in InferResourceKeys<T>]: {
115
+ readonly [A in InferActions<T, K>]: `${K}:${A}`;
116
+ };
117
+ };
118
+ /**
119
+ * Typed RBAC definition returned by `defineRbac()`.
120
+ *
121
+ * Carries phantom types that downstream factories use to constrain
122
+ * permission/role string parameters -- enabling full IDE autocomplete.
123
+ */
124
+ interface TypedRbac<T extends RbacConfig> {
125
+ /** The raw RBAC config. Access resources, roles, etc. via `rbac._config`. */
126
+ readonly _config: T;
127
+ /**
128
+ * Phantom type carrier -- never read at runtime.
129
+ * Use `A["_types"]["permission"]` to extract the permission union from a `TypedRbac`.
130
+ */
131
+ readonly _types: {
132
+ readonly resourceKey: InferResourceKeys<T>;
133
+ readonly roleKey: InferRoleKeys<T>;
134
+ readonly permission: InferPermissions<T>;
135
+ readonly conditionKey: InferConditionKeys<T>;
136
+ };
137
+ /** Structured resource objects: `rbac.resources.documents.actions.read` -> `"documents:read"`. */
138
+ readonly resources: StructuredResources<T>;
139
+ /** Structured role objects: `rbac.roles.admin.key` -> `"admin"`, `.name`, `.grants`. */
140
+ readonly roles: StructuredRoles<T>;
141
+ /** Permissions grouped by resource: `rbac.permissions.documents.read` -> `"documents:read"`. */
142
+ readonly permissions: StructuredPermissions<T>;
143
+ }
144
+ /** Extract the permission union from a `TypedRbac` instance type. Falls back to `string`. */
145
+ type Permission<A> = A extends TypedRbac<infer T> ? InferPermissions<T> : string;
146
+ /** Extract the role key union from a `TypedRbac` instance type. Falls back to `string`. */
147
+ type RoleKey<A> = A extends TypedRbac<infer T> ? InferRoleKeys<T> : string;
148
+ /** Extract the resource key union from a `TypedRbac` instance type. Falls back to `string`. */
149
+ type ResourceKey<A> = A extends TypedRbac<infer T> ? InferResourceKeys<T> : string;
150
+
151
+ /**
152
+ * Validate an RbacConfig object, throwing a descriptive error on the first
153
+ * problem found. Returns the validated config on success.
154
+ */
155
+ declare function validateRbacConfig(config: unknown): RbacConfig;
156
+
157
+ declare function loadRbacConfig(cwd: string): Promise<RbacConfig>;
158
+
159
+ interface ServerResource {
160
+ id: string;
161
+ key: string;
162
+ actions: string[];
163
+ scopes: string[];
164
+ isActive: boolean;
165
+ managedBy: string;
166
+ }
167
+ interface ServerRole {
168
+ id: string;
169
+ configKey: string;
170
+ name: string;
171
+ description: string | null;
172
+ grants: Record<string, Record<string, GrantValue>> | null;
173
+ inherits: string[];
174
+ resolvedPermissions: string[];
175
+ isActive: boolean;
176
+ managedBy: string;
177
+ version: number;
178
+ previousConfigKeys: string[];
179
+ }
180
+ interface ServerCondition {
181
+ id: string;
182
+ key: string;
183
+ description: string | null;
184
+ sourceHash: string | null;
185
+ isActive: boolean;
186
+ }
187
+ interface ServerState {
188
+ resources: ServerResource[];
189
+ roles: ServerRole[];
190
+ conditions: ServerCondition[];
191
+ }
192
+ type ResourceOp = {
193
+ type: "create";
194
+ key: string;
195
+ resource: RbacConfig["resources"][string];
196
+ } | {
197
+ type: "update";
198
+ key: string;
199
+ resource: RbacConfig["resources"][string];
200
+ existing: ServerResource;
201
+ changes: string[];
202
+ } | {
203
+ type: "archive";
204
+ key: string;
205
+ existing: ServerResource;
206
+ };
207
+ type RoleOp = {
208
+ type: "create";
209
+ key: string;
210
+ role: RoleConfig;
211
+ } | {
212
+ type: "update";
213
+ key: string;
214
+ role: RoleConfig;
215
+ existing: ServerRole;
216
+ changes: string[];
217
+ } | {
218
+ type: "archive";
219
+ key: string;
220
+ existing: ServerRole;
221
+ assignedMembers: number;
222
+ } | {
223
+ type: "rename";
224
+ key: string;
225
+ oldKey: string;
226
+ role: RoleConfig;
227
+ existing: ServerRole;
228
+ assignedMembers: number;
229
+ };
230
+ type ConditionOp = {
231
+ type: "create";
232
+ key: string;
233
+ } | {
234
+ type: "update";
235
+ key: string;
236
+ changes: string[];
237
+ } | {
238
+ type: "archive";
239
+ key: string;
240
+ existing: ServerCondition;
241
+ };
242
+ interface DiffResult {
243
+ resourceOps: ResourceOp[];
244
+ roleOps: RoleOp[];
245
+ conditionOps: ConditionOp[];
246
+ hasDestructive: boolean;
247
+ }
248
+ /** Simple hash of a condition function's source code for change detection. */
249
+ declare function hashConditionSource(fn: Function): string;
250
+ declare function computeRbacDiff(config: RbacConfig, server: ServerState, memberCounts: Record<string, number>): DiffResult;
251
+
252
+ interface RbacSyncClientConfig {
253
+ baseUrl: string;
254
+ apiKey: string;
255
+ }
256
+ interface ApplyResult {
257
+ created: string[];
258
+ updated: string[];
259
+ archived: string[];
260
+ renamed: string[];
261
+ warnings: string[];
262
+ }
263
+ declare class RbacSyncClient {
264
+ private baseUrl;
265
+ private apiKey;
266
+ constructor(config: RbacSyncClientConfig);
267
+ private request;
268
+ getState(): Promise<ServerState>;
269
+ getMemberCounts(): Promise<Record<string, number>>;
270
+ apply(config: RbacConfig, force: boolean): Promise<ApplyResult>;
271
+ }
272
+
273
+ declare function formatRbacDiff(diff: DiffResult, dryRun: boolean): string;
274
+
275
+ /**
276
+ * Define your RBAC config. Use this in your `authgate.rbac.ts` config file.
277
+ *
278
+ * Returns a `TypedRbac<T>` object with structured resource, role, and permission
279
+ * objects -- enabling full IDE autocomplete via dot-notation across hooks, helpers,
280
+ * and server-side checks.
281
+ *
282
+ * @example
283
+ * ```ts
284
+ * export const rbac = defineRbac({
285
+ * resources: {
286
+ * documents: { actions: ["read", "write", "delete"] },
287
+ * billing: { actions: ["read", "manage"] },
288
+ * },
289
+ * roles: {
290
+ * admin: {
291
+ * name: "Admin",
292
+ * grants: {
293
+ * documents: { read: true, write: true, delete: true },
294
+ * billing: { read: true, manage: true },
295
+ * },
296
+ * },
297
+ * viewer: {
298
+ * name: "Viewer",
299
+ * grants: {
300
+ * documents: { read: true },
301
+ * },
302
+ * },
303
+ * },
304
+ * });
305
+ *
306
+ * rbac.resources.documents.key // "documents"
307
+ * rbac.resources.documents.actions.read // "documents:read"
308
+ * rbac.roles.admin.key // "admin"
309
+ * rbac.roles.admin.name // "Admin"
310
+ * rbac.permissions.documents.write // "documents:write"
311
+ * ```
312
+ */
313
+ declare function defineRbac<const T extends RbacConfig>(config: T): TypedRbac<T>;
314
+
315
+ export { type ApplyResult, type ConditionContext, type ConditionFn, type ConditionOp, type DiffResult, type GrantValue, type InferActions, type InferConditionKeys, type InferPermissions, type InferResourceKeys, type InferRoleKeys, type InferScopes, type Permission, type RbacConfig, RbacSyncClient, type RbacSyncClientConfig, type ResourceConfig, type ResourceKey, type ResourceOp, type RoleConfig, type RoleKey, type RoleOp, type ServerCondition, type ServerResource, type ServerRole, type ServerState, type TypedRbac, computeRbacDiff, defineRbac, formatRbacDiff, hashConditionSource, loadRbacConfig, validateRbacConfig };
@@ -0,0 +1,315 @@
1
+ /** A resource definition: declares available actions and optional scopes. */
2
+ interface ResourceConfig {
3
+ actions: readonly string[];
4
+ scopes?: readonly string[];
5
+ }
6
+ /** Context provided to condition functions for attribute-based decisions. */
7
+ interface ConditionContext {
8
+ user: {
9
+ id: string;
10
+ metadata?: Record<string, unknown>;
11
+ };
12
+ resource?: {
13
+ id?: string;
14
+ ownerId?: string;
15
+ metadata?: Record<string, unknown>;
16
+ };
17
+ env: {
18
+ timestamp: number;
19
+ hour: number;
20
+ dayOfWeek: number;
21
+ };
22
+ }
23
+ /** A named condition function evaluated at check time (client/edge only). */
24
+ type ConditionFn = (ctx: ConditionContext) => boolean;
25
+ /**
26
+ * Grant value for a resource action.
27
+ *
28
+ * - `true` — boolean access (Phase 1)
29
+ * - `string` — scope key, e.g. "own", "department", "all" (Phase 2)
30
+ * - `{ when: string; scope?: string }` — conditional grant (Phase 2)
31
+ */
32
+ type GrantValue = true | string | {
33
+ when: string;
34
+ scope?: string;
35
+ };
36
+ /** A role definition with grants matrix and optional inheritance. */
37
+ interface RoleConfig {
38
+ name: string;
39
+ description?: string;
40
+ inherits?: readonly string[];
41
+ grants: Record<string, Record<string, GrantValue>>;
42
+ /** Previous config key if this role was renamed. */
43
+ renamedFrom?: string;
44
+ }
45
+ /** Root RBAC config object passed to `defineRbac()`. */
46
+ interface RbacConfig {
47
+ resources: Record<string, ResourceConfig>;
48
+ conditions?: Record<string, ConditionFn>;
49
+ roles: Record<string, RoleConfig>;
50
+ }
51
+ /** Extract literal resource keys from an RBAC config type. */
52
+ type InferResourceKeys<T> = T extends {
53
+ resources: infer R;
54
+ } ? keyof R & string : never;
55
+ /** Extract literal role keys from an RBAC config type. */
56
+ type InferRoleKeys<T> = T extends {
57
+ roles: infer R;
58
+ } ? keyof R & string : never;
59
+ /** Extract action literals for a specific resource from an RBAC config type. */
60
+ type InferActions<T, Resource extends string> = T extends {
61
+ resources: infer R;
62
+ } ? Resource extends keyof R ? R[Resource] extends {
63
+ actions: infer A;
64
+ } ? A extends readonly (infer U)[] ? U & string : never : never : never : never;
65
+ /** Produce `"resource:action"` union from all resources in an RBAC config type. */
66
+ type InferPermissions<T> = T extends {
67
+ resources: infer R;
68
+ } ? {
69
+ [K in keyof R & string]: R[K] extends {
70
+ actions: infer A;
71
+ } ? A extends readonly (infer U)[] ? `${K}:${U & string}` : never : never;
72
+ }[keyof R & string] : never;
73
+ /** Extract scope literals for a specific resource from an RBAC config type. */
74
+ type InferScopes<T, Resource extends string> = T extends {
75
+ resources: infer R;
76
+ } ? Resource extends keyof R ? R[Resource] extends {
77
+ scopes: infer S;
78
+ } ? S extends readonly (infer U)[] ? U & string : never : never : never : never;
79
+ /** Extract literal condition keys from an RBAC config type. */
80
+ type InferConditionKeys<T> = T extends {
81
+ conditions: infer C;
82
+ } ? keyof C & string : never;
83
+ /** A structured resource with a `key` constant and an `actions` map of `"resource:action"` strings. */
84
+ type StructuredResource<T, K extends string> = {
85
+ readonly key: K;
86
+ readonly actions: {
87
+ readonly [A in InferActions<T, K>]: `${K}:${A}`;
88
+ };
89
+ };
90
+ /** Map of all resources as structured objects: `resources.documents.actions.read` -> `"documents:read"`. */
91
+ type StructuredResources<T> = {
92
+ readonly [K in InferResourceKeys<T>]: StructuredResource<T, K>;
93
+ };
94
+ /** A structured role with `key`, `name`, and `grants` from the config. */
95
+ type StructuredRole<T, K extends string> = {
96
+ readonly key: K;
97
+ readonly name: T extends {
98
+ roles: infer R;
99
+ } ? K extends keyof R ? R[K] extends {
100
+ name: infer N;
101
+ } ? N : string : string : string;
102
+ readonly grants: T extends {
103
+ roles: infer R;
104
+ } ? K extends keyof R ? R[K] extends {
105
+ grants: infer G;
106
+ } ? Readonly<G> : {} : {} : {};
107
+ };
108
+ /** Map of all roles as structured objects: `roles.admin.key` -> `"admin"`. */
109
+ type StructuredRoles<T> = {
110
+ readonly [K in InferRoleKeys<T>]: StructuredRole<T, K>;
111
+ };
112
+ /** Permissions grouped by resource then action: `permissions.documents.read` -> `"documents:read"`. */
113
+ type StructuredPermissions<T> = {
114
+ readonly [K in InferResourceKeys<T>]: {
115
+ readonly [A in InferActions<T, K>]: `${K}:${A}`;
116
+ };
117
+ };
118
+ /**
119
+ * Typed RBAC definition returned by `defineRbac()`.
120
+ *
121
+ * Carries phantom types that downstream factories use to constrain
122
+ * permission/role string parameters -- enabling full IDE autocomplete.
123
+ */
124
+ interface TypedRbac<T extends RbacConfig> {
125
+ /** The raw RBAC config. Access resources, roles, etc. via `rbac._config`. */
126
+ readonly _config: T;
127
+ /**
128
+ * Phantom type carrier -- never read at runtime.
129
+ * Use `A["_types"]["permission"]` to extract the permission union from a `TypedRbac`.
130
+ */
131
+ readonly _types: {
132
+ readonly resourceKey: InferResourceKeys<T>;
133
+ readonly roleKey: InferRoleKeys<T>;
134
+ readonly permission: InferPermissions<T>;
135
+ readonly conditionKey: InferConditionKeys<T>;
136
+ };
137
+ /** Structured resource objects: `rbac.resources.documents.actions.read` -> `"documents:read"`. */
138
+ readonly resources: StructuredResources<T>;
139
+ /** Structured role objects: `rbac.roles.admin.key` -> `"admin"`, `.name`, `.grants`. */
140
+ readonly roles: StructuredRoles<T>;
141
+ /** Permissions grouped by resource: `rbac.permissions.documents.read` -> `"documents:read"`. */
142
+ readonly permissions: StructuredPermissions<T>;
143
+ }
144
+ /** Extract the permission union from a `TypedRbac` instance type. Falls back to `string`. */
145
+ type Permission<A> = A extends TypedRbac<infer T> ? InferPermissions<T> : string;
146
+ /** Extract the role key union from a `TypedRbac` instance type. Falls back to `string`. */
147
+ type RoleKey<A> = A extends TypedRbac<infer T> ? InferRoleKeys<T> : string;
148
+ /** Extract the resource key union from a `TypedRbac` instance type. Falls back to `string`. */
149
+ type ResourceKey<A> = A extends TypedRbac<infer T> ? InferResourceKeys<T> : string;
150
+
151
+ /**
152
+ * Validate an RbacConfig object, throwing a descriptive error on the first
153
+ * problem found. Returns the validated config on success.
154
+ */
155
+ declare function validateRbacConfig(config: unknown): RbacConfig;
156
+
157
+ declare function loadRbacConfig(cwd: string): Promise<RbacConfig>;
158
+
159
+ interface ServerResource {
160
+ id: string;
161
+ key: string;
162
+ actions: string[];
163
+ scopes: string[];
164
+ isActive: boolean;
165
+ managedBy: string;
166
+ }
167
+ interface ServerRole {
168
+ id: string;
169
+ configKey: string;
170
+ name: string;
171
+ description: string | null;
172
+ grants: Record<string, Record<string, GrantValue>> | null;
173
+ inherits: string[];
174
+ resolvedPermissions: string[];
175
+ isActive: boolean;
176
+ managedBy: string;
177
+ version: number;
178
+ previousConfigKeys: string[];
179
+ }
180
+ interface ServerCondition {
181
+ id: string;
182
+ key: string;
183
+ description: string | null;
184
+ sourceHash: string | null;
185
+ isActive: boolean;
186
+ }
187
+ interface ServerState {
188
+ resources: ServerResource[];
189
+ roles: ServerRole[];
190
+ conditions: ServerCondition[];
191
+ }
192
+ type ResourceOp = {
193
+ type: "create";
194
+ key: string;
195
+ resource: RbacConfig["resources"][string];
196
+ } | {
197
+ type: "update";
198
+ key: string;
199
+ resource: RbacConfig["resources"][string];
200
+ existing: ServerResource;
201
+ changes: string[];
202
+ } | {
203
+ type: "archive";
204
+ key: string;
205
+ existing: ServerResource;
206
+ };
207
+ type RoleOp = {
208
+ type: "create";
209
+ key: string;
210
+ role: RoleConfig;
211
+ } | {
212
+ type: "update";
213
+ key: string;
214
+ role: RoleConfig;
215
+ existing: ServerRole;
216
+ changes: string[];
217
+ } | {
218
+ type: "archive";
219
+ key: string;
220
+ existing: ServerRole;
221
+ assignedMembers: number;
222
+ } | {
223
+ type: "rename";
224
+ key: string;
225
+ oldKey: string;
226
+ role: RoleConfig;
227
+ existing: ServerRole;
228
+ assignedMembers: number;
229
+ };
230
+ type ConditionOp = {
231
+ type: "create";
232
+ key: string;
233
+ } | {
234
+ type: "update";
235
+ key: string;
236
+ changes: string[];
237
+ } | {
238
+ type: "archive";
239
+ key: string;
240
+ existing: ServerCondition;
241
+ };
242
+ interface DiffResult {
243
+ resourceOps: ResourceOp[];
244
+ roleOps: RoleOp[];
245
+ conditionOps: ConditionOp[];
246
+ hasDestructive: boolean;
247
+ }
248
+ /** Simple hash of a condition function's source code for change detection. */
249
+ declare function hashConditionSource(fn: Function): string;
250
+ declare function computeRbacDiff(config: RbacConfig, server: ServerState, memberCounts: Record<string, number>): DiffResult;
251
+
252
+ interface RbacSyncClientConfig {
253
+ baseUrl: string;
254
+ apiKey: string;
255
+ }
256
+ interface ApplyResult {
257
+ created: string[];
258
+ updated: string[];
259
+ archived: string[];
260
+ renamed: string[];
261
+ warnings: string[];
262
+ }
263
+ declare class RbacSyncClient {
264
+ private baseUrl;
265
+ private apiKey;
266
+ constructor(config: RbacSyncClientConfig);
267
+ private request;
268
+ getState(): Promise<ServerState>;
269
+ getMemberCounts(): Promise<Record<string, number>>;
270
+ apply(config: RbacConfig, force: boolean): Promise<ApplyResult>;
271
+ }
272
+
273
+ declare function formatRbacDiff(diff: DiffResult, dryRun: boolean): string;
274
+
275
+ /**
276
+ * Define your RBAC config. Use this in your `authgate.rbac.ts` config file.
277
+ *
278
+ * Returns a `TypedRbac<T>` object with structured resource, role, and permission
279
+ * objects -- enabling full IDE autocomplete via dot-notation across hooks, helpers,
280
+ * and server-side checks.
281
+ *
282
+ * @example
283
+ * ```ts
284
+ * export const rbac = defineRbac({
285
+ * resources: {
286
+ * documents: { actions: ["read", "write", "delete"] },
287
+ * billing: { actions: ["read", "manage"] },
288
+ * },
289
+ * roles: {
290
+ * admin: {
291
+ * name: "Admin",
292
+ * grants: {
293
+ * documents: { read: true, write: true, delete: true },
294
+ * billing: { read: true, manage: true },
295
+ * },
296
+ * },
297
+ * viewer: {
298
+ * name: "Viewer",
299
+ * grants: {
300
+ * documents: { read: true },
301
+ * },
302
+ * },
303
+ * },
304
+ * });
305
+ *
306
+ * rbac.resources.documents.key // "documents"
307
+ * rbac.resources.documents.actions.read // "documents:read"
308
+ * rbac.roles.admin.key // "admin"
309
+ * rbac.roles.admin.name // "Admin"
310
+ * rbac.permissions.documents.write // "documents:write"
311
+ * ```
312
+ */
313
+ declare function defineRbac<const T extends RbacConfig>(config: T): TypedRbac<T>;
314
+
315
+ export { type ApplyResult, type ConditionContext, type ConditionFn, type ConditionOp, type DiffResult, type GrantValue, type InferActions, type InferConditionKeys, type InferPermissions, type InferResourceKeys, type InferRoleKeys, type InferScopes, type Permission, type RbacConfig, RbacSyncClient, type RbacSyncClientConfig, type ResourceConfig, type ResourceKey, type ResourceOp, type RoleConfig, type RoleKey, type RoleOp, type ServerCondition, type ServerResource, type ServerRole, type ServerState, type TypedRbac, computeRbacDiff, defineRbac, formatRbacDiff, hashConditionSource, loadRbacConfig, validateRbacConfig };
package/dist/index.mjs ADDED
@@ -0,0 +1,49 @@
1
+ import {
2
+ RbacSyncClient,
3
+ computeRbacDiff,
4
+ formatRbacDiff,
5
+ hashConditionSource,
6
+ loadRbacConfig,
7
+ validateRbacConfig
8
+ } from "./chunk-HE57TIQI.mjs";
9
+
10
+ // src/index.ts
11
+ function defineRbac(config) {
12
+ const resources = {};
13
+ for (const [key, resource] of Object.entries(config.resources)) {
14
+ const actions = {};
15
+ for (const action of resource.actions) {
16
+ actions[action] = `${key}:${action}`;
17
+ }
18
+ resources[key] = { key, actions };
19
+ }
20
+ const roles = {};
21
+ for (const [key, role] of Object.entries(config.roles)) {
22
+ roles[key] = { key, name: role.name, grants: role.grants };
23
+ }
24
+ const permissions = {};
25
+ for (const [key, resource] of Object.entries(config.resources)) {
26
+ const perms = {};
27
+ for (const action of resource.actions) {
28
+ perms[action] = `${key}:${action}`;
29
+ }
30
+ permissions[key] = perms;
31
+ }
32
+ return {
33
+ _config: config,
34
+ _types: void 0,
35
+ // phantom -- never read at runtime
36
+ resources,
37
+ roles,
38
+ permissions
39
+ };
40
+ }
41
+ export {
42
+ RbacSyncClient,
43
+ computeRbacDiff,
44
+ defineRbac,
45
+ formatRbacDiff,
46
+ hashConditionSource,
47
+ loadRbacConfig,
48
+ validateRbacConfig
49
+ };