@omnibase/core-js 0.7.6 → 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,447 @@
1
+ // src/permissions/handler.ts
2
+ import { RelationshipApi, PermissionApi } from "@ory/client";
3
+
4
+ // src/permissions/roles.ts
5
+ var RolesHandler = class {
6
+ constructor(client) {
7
+ this.client = client;
8
+ }
9
+ /**
10
+ * Get available namespace definitions for UI
11
+ *
12
+ * Returns all namespaces and their available relations/permissions.
13
+ * Useful for building role configuration UIs.
14
+ *
15
+ * @returns List of namespace definitions
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const definitions = await omnibase.permissions.roles.getDefinitions();
20
+ *
21
+ * // Output: [{ namespace: 'Tenant', relations: ['invite_user', 'delete_tenant', ...] }]
22
+ * definitions.forEach(def => {
23
+ * console.log(`${def.namespace} supports: ${def.relations.join(', ')}`);
24
+ * });
25
+ * ```
26
+ */
27
+ async getDefinitions() {
28
+ const response = await this.client.fetch(
29
+ "/api/v1/permissions/definitions",
30
+ {
31
+ method: "GET"
32
+ }
33
+ );
34
+ const data = await response.json();
35
+ if (!response.ok || data.error) {
36
+ throw new Error(data.error || "Failed to fetch definitions");
37
+ }
38
+ return data.data.definitions;
39
+ }
40
+ /**
41
+ * List all roles for the current tenant
42
+ *
43
+ * Returns both system roles (defined in roles.config.json) and
44
+ * custom roles created via the API. System roles have `tenant_id = null`.
45
+ *
46
+ * @returns List of roles
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const roles = await omnibase.permissions.roles.list();
51
+ *
52
+ * const systemRoles = roles.filter(r => r.tenant_id === null);
53
+ * const customRoles = roles.filter(r => r.tenant_id !== null);
54
+ *
55
+ * console.log(`System roles: ${systemRoles.map(r => r.role_name).join(', ')}`);
56
+ * console.log(`Custom roles: ${customRoles.map(r => r.role_name).join(', ')}`);
57
+ * ```
58
+ */
59
+ async list() {
60
+ const response = await this.client.fetch("/api/v1/permissions/roles", {
61
+ method: "GET"
62
+ });
63
+ const data = await response.json();
64
+ if (!response.ok || data.error) {
65
+ throw new Error(data.error || "Failed to list roles");
66
+ }
67
+ return data.data.roles;
68
+ }
69
+ /**
70
+ * Create a new custom role
71
+ *
72
+ * Creates a tenant-specific role with the specified permissions.
73
+ * Permissions use the format `namespace#relation` or `namespace:id#relation`.
74
+ *
75
+ * @param request - Role creation request
76
+ * @returns Created role
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const role = await omnibase.permissions.roles.create({
81
+ * role_name: 'billing_manager',
82
+ * permissions: [
83
+ * 'tenant#manage_billing',
84
+ * 'tenant#view_invoices',
85
+ * 'tenant#update_payment_methods'
86
+ * ]
87
+ * });
88
+ *
89
+ * console.log(`Created role: ${role.id}`);
90
+ * ```
91
+ *
92
+ * @example
93
+ * Resource-specific permissions:
94
+ * ```typescript
95
+ * const devRole = await omnibase.permissions.roles.create({
96
+ * role_name: 'project_developer',
97
+ * permissions: [
98
+ * 'project:proj_abc123#deploy',
99
+ * 'project:proj_abc123#view_logs',
100
+ * 'tenant#invite_user'
101
+ * ]
102
+ * });
103
+ * ```
104
+ */
105
+ async create(request) {
106
+ const response = await this.client.fetch("/api/v1/permissions/roles", {
107
+ method: "POST",
108
+ headers: { "Content-Type": "application/json" },
109
+ body: JSON.stringify(request)
110
+ });
111
+ const data = await response.json();
112
+ if (!response.ok || data.error) {
113
+ throw new Error(data.error || "Failed to create role");
114
+ }
115
+ return data.data;
116
+ }
117
+ /**
118
+ * Update an existing role's permissions
119
+ *
120
+ * Updates the permissions for a role and automatically updates all
121
+ * Keto relationships for users assigned to this role. Old permissions
122
+ * are removed and new ones are created.
123
+ *
124
+ * @param roleId - ID of role to update
125
+ * @param request - Update request with new permissions
126
+ * @returns Updated role
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * const updatedRole = await omnibase.permissions.roles.update('role_123', {
131
+ * permissions: [
132
+ * 'tenant#manage_billing',
133
+ * 'tenant#view_invoices',
134
+ * 'tenant#manage_users' // Added new permission
135
+ * ]
136
+ * });
137
+ *
138
+ * console.log(`Updated role with ${updatedRole.permissions.length} permissions`);
139
+ * ```
140
+ */
141
+ async update(roleId, request) {
142
+ const response = await this.client.fetch(
143
+ `/api/v1/permissions/roles/${roleId}`,
144
+ {
145
+ method: "PUT",
146
+ headers: { "Content-Type": "application/json" },
147
+ body: JSON.stringify(request)
148
+ }
149
+ );
150
+ const data = await response.json();
151
+ if (!response.ok || data.error) {
152
+ throw new Error(data.error || "Failed to update role");
153
+ }
154
+ return data.data;
155
+ }
156
+ /**
157
+ * Delete a role
158
+ *
159
+ * Deletes the role and automatically removes all Keto relationships
160
+ * for users assigned to this role. Cannot delete system roles.
161
+ *
162
+ * @param roleId - ID of role to delete
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * await omnibase.permissions.roles.delete('role_123');
167
+ * console.log('Role deleted successfully');
168
+ * ```
169
+ */
170
+ async delete(roleId) {
171
+ const response = await this.client.fetch(
172
+ `/api/v1/permissions/roles/${roleId}`,
173
+ {
174
+ method: "DELETE"
175
+ }
176
+ );
177
+ const data = await response.json();
178
+ if (!response.ok || data.error) {
179
+ throw new Error(data.error || "Failed to delete role");
180
+ }
181
+ }
182
+ /**
183
+ * Assign a role to a user
184
+ *
185
+ * Assigns a role to a user and automatically creates all necessary
186
+ * Keto relationship tuples based on the role's permissions. The user
187
+ * immediately gains all permissions defined in the role.
188
+ *
189
+ * Supports assignment by either role ID or role name for flexibility.
190
+ *
191
+ * @param userId - ID of user to assign role to
192
+ * @param request - Assignment request with either role_id or role_name
193
+ *
194
+ * @example
195
+ * Assign by role ID:
196
+ * ```typescript
197
+ * await omnibase.permissions.roles.assign('user_123', {
198
+ * role_id: 'role_456'
199
+ * });
200
+ * ```
201
+ *
202
+ * @example
203
+ * Assign by role name (system or custom role):
204
+ * ```typescript
205
+ * // Assign system role
206
+ * await omnibase.permissions.roles.assign('user_123', {
207
+ * role_name: 'owner'
208
+ * });
209
+ *
210
+ * // Assign custom role
211
+ * await omnibase.permissions.roles.assign('user_456', {
212
+ * role_name: 'billing_manager'
213
+ * });
214
+ * ```
215
+ *
216
+ * @example
217
+ * Verify permissions after assignment:
218
+ * ```typescript
219
+ * await omnibase.permissions.roles.assign('user_123', {
220
+ * role_name: 'admin'
221
+ * });
222
+ *
223
+ * // User now has all permissions from the admin role
224
+ * const canManage = await omnibase.permissions.permissions.checkPermission(
225
+ * undefined,
226
+ * {
227
+ * namespace: 'Tenant',
228
+ * object: 'tenant_789',
229
+ * relation: 'manage_billing',
230
+ * subjectId: 'user_123'
231
+ * }
232
+ * );
233
+ * // canManage.data.allowed === true
234
+ * ```
235
+ */
236
+ async assign(userId, request) {
237
+ const response = await this.client.fetch(
238
+ `/api/v1/permissions/users/${userId}/roles`,
239
+ {
240
+ method: "POST",
241
+ headers: { "Content-Type": "application/json" },
242
+ body: JSON.stringify(request)
243
+ }
244
+ );
245
+ const data = await response.json();
246
+ if (!response.ok || data.error) {
247
+ throw new Error(data.error || "Failed to assign role");
248
+ }
249
+ }
250
+ };
251
+
252
+ // src/permissions/handler.ts
253
+ var PermissionsClient = class {
254
+ /**
255
+ * Ory Keto RelationshipApi for managing subject-object relationships
256
+ *
257
+ * Provides methods for creating, updating, and deleting relationships between
258
+ * subjects (users, groups) and objects (tenants, resources). This API handles
259
+ * write operations and is used to establish permission structures.
260
+ *
261
+ * Key methods:
262
+ * - `createRelationship()` - Creates a new relationship tuple
263
+ * - `deleteRelationships()` - Removes existing relationship tuples
264
+ * - `getRelationships()` - Queries existing relationships
265
+ * - `patchRelationships()` - Updates multiple relationships atomically
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * // Create a relationship
270
+ * await client.relationships.createRelationship(
271
+ * undefined,
272
+ * {
273
+ * namespace: 'Tenant',
274
+ * object: 'tenant_123',
275
+ * relation: 'members',
276
+ * subjectId: 'user_456'
277
+ * }
278
+ * );
279
+ * ```
280
+ *
281
+ * @since 1.0.0
282
+ * @group Relationships
283
+ */
284
+ relationships;
285
+ /**
286
+ * Ory Keto PermissionApi for checking permissions
287
+ *
288
+ * Provides methods for querying whether a subject has a specific permission
289
+ * on an object. This API handles read operations and is optimized for fast
290
+ * permission checks in your application logic.
291
+ *
292
+ * All operations are proxied through Omnibase's API at `/api/v1/permissions/read`.
293
+ *
294
+ * Key methods:
295
+ * - `checkPermission(params)` - Checks if a subject has permission on an object
296
+ * - `checkPermissionOrError(params)` - Same as above but throws error if denied
297
+ * - `expandPermissions(namespace, object, relation, maxDepth?)` - Expands relationships to show all granted permissions
298
+ * - `postCheckPermission(maxDepth?, body)` - POST variant of permission check
299
+ *
300
+ * @example
301
+ * Check a single permission:
302
+ * ```typescript
303
+ * const result = await omnibase.permissions.permissions.checkPermission({
304
+ * namespace: 'Tenant',
305
+ * object: 'tenant_123',
306
+ * relation: 'view',
307
+ * subjectId: 'user_456'
308
+ * });
309
+ *
310
+ * if (result.data.allowed) {
311
+ * console.log('User has permission');
312
+ * }
313
+ * ```
314
+ *
315
+ * @example
316
+ * Expand permission tree:
317
+ * ```typescript
318
+ * const tree = await omnibase.permissions.permissions.expandPermissions(
319
+ * 'Tenant',
320
+ * 'tenant_123',
321
+ * 'view'
322
+ * );
323
+ *
324
+ * console.log('Permission tree:', tree.data);
325
+ * ```
326
+ *
327
+ * @example
328
+ * Check permission or throw error:
329
+ * ```typescript
330
+ * try {
331
+ * await omnibase.permissions.permissions.checkPermissionOrError({
332
+ * namespace: 'Tenant',
333
+ * object: 'tenant_123',
334
+ * relation: 'edit',
335
+ * subjectId: 'user_456'
336
+ * });
337
+ * // Permission granted
338
+ * } catch (error) {
339
+ * // Permission denied
340
+ * console.error('Access denied');
341
+ * }
342
+ * ```
343
+ *
344
+ * @since 1.0.0
345
+ * @group Permissions
346
+ */
347
+ permissions;
348
+ /**
349
+ * Handler for managing roles and role-based permissions
350
+ *
351
+ * Provides methods for creating custom roles, assigning permissions,
352
+ * and managing role assignments. Works alongside the Keto-based
353
+ * permissions system to provide dynamic RBAC capabilities.
354
+ *
355
+ * Roles are stored in the database and automatically synchronized with
356
+ * Ory Keto relationships, providing a higher-level abstraction over
357
+ * raw relationship tuples.
358
+ *
359
+ * @example
360
+ * Create a custom role:
361
+ * ```typescript
362
+ * const role = await omnibase.permissions.roles.create({
363
+ * role_name: 'billing_manager',
364
+ * permissions: ['tenant#manage_billing', 'tenant#view_invoices']
365
+ * });
366
+ * ```
367
+ *
368
+ * @example
369
+ * Assign role to a user:
370
+ * ```typescript
371
+ * await omnibase.permissions.roles.assign('user_123', {
372
+ * role_id: role.id
373
+ * });
374
+ * ```
375
+ *
376
+ * @example
377
+ * List all roles:
378
+ * ```typescript
379
+ * const roles = await omnibase.permissions.roles.list();
380
+ * console.log('Available roles:', roles);
381
+ * ```
382
+ *
383
+ * @since 0.7.0
384
+ * @group Roles
385
+ */
386
+ roles;
387
+ /**
388
+ * Creates a new PermissionsClient instance
389
+ *
390
+ * Initializes the client with separate endpoints for read and write operations.
391
+ * The client automatically configures the Ory Keto client libraries to use
392
+ * Omnibase's permission proxy endpoints:
393
+ * - Write endpoint: `${apiBaseUrl}/api/v1/permissions/write`
394
+ * - Read endpoint: `${apiBaseUrl}/api/v1/permissions/read`
395
+ *
396
+ * This separation follows Ory Keto's recommended architecture for optimal
397
+ * performance and security.
398
+ *
399
+ * @param apiBaseUrl - The base URL for your Omnibase API instance (e.g., 'https://api.example.com')
400
+ * @param client - The main OmnibaseClient instance (required for roles handler)
401
+ *
402
+ * @throws {Error} When the base URL is invalid or cannot be reached
403
+ *
404
+ * @example
405
+ * Direct instantiation (not recommended - use OmnibaseClient instead):
406
+ * ```typescript
407
+ * const client = new PermissionsClient('https://api.example.com', omnibaseClient);
408
+ * ```
409
+ *
410
+ * @example
411
+ * Recommended usage via OmnibaseClient:
412
+ * ```typescript
413
+ * import { OmnibaseClient } from '@omnibase/core-js';
414
+ *
415
+ * const omnibase = new OmnibaseClient({
416
+ * apiUrl: 'https://api.example.com'
417
+ * });
418
+ *
419
+ * // Use the permissions client
420
+ * await omnibase.permissions.permissions.checkPermission({
421
+ * namespace: 'Tenant',
422
+ * object: 'tenant_123',
423
+ * relation: 'view',
424
+ * subjectId: 'user_456'
425
+ * });
426
+ * ```
427
+ *
428
+ * @since 1.0.0
429
+ * @group Client
430
+ */
431
+ constructor(apiBaseUrl, client) {
432
+ this.relationships = new RelationshipApi(
433
+ void 0,
434
+ `${apiBaseUrl}/api/v1/permissions/write`
435
+ );
436
+ this.permissions = new PermissionApi(
437
+ void 0,
438
+ `${apiBaseUrl}/api/v1/permissions/read`
439
+ );
440
+ this.roles = new RolesHandler(client);
441
+ }
442
+ };
443
+
444
+ export {
445
+ RolesHandler,
446
+ PermissionsClient
447
+ };
package/dist/index.cjs CHANGED
@@ -801,25 +801,56 @@ var PermissionsClient = class {
801
801
  * on an object. This API handles read operations and is optimized for fast
802
802
  * permission checks in your application logic.
803
803
  *
804
+ * All operations are proxied through Omnibase's API at `/api/v1/permissions/read`.
805
+ *
804
806
  * Key methods:
805
- * - `checkPermission()` - Checks if a subject has permission on an object
806
- * - `checkPermissionOrError()` - Same as above but throws error if denied
807
- * - `expandPermissions()` - Expands relationships to show all granted permissions
807
+ * - `checkPermission(params)` - Checks if a subject has permission on an object
808
+ * - `checkPermissionOrError(params)` - Same as above but throws error if denied
809
+ * - `expandPermissions(namespace, object, relation, maxDepth?)` - Expands relationships to show all granted permissions
810
+ * - `postCheckPermission(maxDepth?, body)` - POST variant of permission check
808
811
  *
809
812
  * @example
813
+ * Check a single permission:
810
814
  * ```typescript
811
- * // Check permission
812
- * const result = await client.permissions.checkPermission(
813
- * undefined,
814
- * {
815
+ * const result = await omnibase.permissions.permissions.checkPermission({
816
+ * namespace: 'Tenant',
817
+ * object: 'tenant_123',
818
+ * relation: 'view',
819
+ * subjectId: 'user_456'
820
+ * });
821
+ *
822
+ * if (result.data.allowed) {
823
+ * console.log('User has permission');
824
+ * }
825
+ * ```
826
+ *
827
+ * @example
828
+ * Expand permission tree:
829
+ * ```typescript
830
+ * const tree = await omnibase.permissions.permissions.expandPermissions(
831
+ * 'Tenant',
832
+ * 'tenant_123',
833
+ * 'view'
834
+ * );
835
+ *
836
+ * console.log('Permission tree:', tree.data);
837
+ * ```
838
+ *
839
+ * @example
840
+ * Check permission or throw error:
841
+ * ```typescript
842
+ * try {
843
+ * await omnibase.permissions.permissions.checkPermissionOrError({
815
844
  * namespace: 'Tenant',
816
845
  * object: 'tenant_123',
817
- * relation: 'view',
846
+ * relation: 'edit',
818
847
  * subjectId: 'user_456'
819
- * }
820
- * );
821
- *
822
- * console.log('Has permission:', result.data.allowed);
848
+ * });
849
+ * // Permission granted
850
+ * } catch (error) {
851
+ * // Permission denied
852
+ * console.error('Access denied');
853
+ * }
823
854
  * ```
824
855
  *
825
856
  * @since 1.0.0
@@ -833,20 +864,34 @@ var PermissionsClient = class {
833
864
  * and managing role assignments. Works alongside the Keto-based
834
865
  * permissions system to provide dynamic RBAC capabilities.
835
866
  *
867
+ * Roles are stored in the database and automatically synchronized with
868
+ * Ory Keto relationships, providing a higher-level abstraction over
869
+ * raw relationship tuples.
870
+ *
836
871
  * @example
872
+ * Create a custom role:
837
873
  * ```typescript
838
- * // Create a custom role
839
874
  * const role = await omnibase.permissions.roles.create({
840
875
  * role_name: 'billing_manager',
841
876
  * permissions: ['tenant#manage_billing', 'tenant#view_invoices']
842
877
  * });
878
+ * ```
843
879
  *
844
- * // Assign role to user
880
+ * @example
881
+ * Assign role to a user:
882
+ * ```typescript
845
883
  * await omnibase.permissions.roles.assign('user_123', {
846
884
  * role_id: role.id
847
885
  * });
848
886
  * ```
849
887
  *
888
+ * @example
889
+ * List all roles:
890
+ * ```typescript
891
+ * const roles = await omnibase.permissions.roles.list();
892
+ * console.log('Available roles:', roles);
893
+ * ```
894
+ *
850
895
  * @since 0.7.0
851
896
  * @group Roles
852
897
  */
@@ -855,19 +900,43 @@ var PermissionsClient = class {
855
900
  * Creates a new PermissionsClient instance
856
901
  *
857
902
  * Initializes the client with separate endpoints for read and write operations.
858
- * The client automatically appends the appropriate Keto API paths to the base URL
859
- * for optimal performance and security separation.
903
+ * The client automatically configures the Ory Keto client libraries to use
904
+ * Omnibase's permission proxy endpoints:
905
+ * - Write endpoint: `${apiBaseUrl}/api/v1/permissions/write`
906
+ * - Read endpoint: `${apiBaseUrl}/api/v1/permissions/read`
907
+ *
908
+ * This separation follows Ory Keto's recommended architecture for optimal
909
+ * performance and security.
860
910
  *
861
- * @param apiBaseUrl - The base URL for your Omnibase API instance
862
- * @param client - The main OmnibaseClient instance (for roles handler)
911
+ * @param apiBaseUrl - The base URL for your Omnibase API instance (e.g., 'https://api.example.com')
912
+ * @param client - The main OmnibaseClient instance (required for roles handler)
863
913
  *
864
914
  * @throws {Error} When the base URL is invalid or cannot be reached
865
915
  *
866
916
  * @example
917
+ * Direct instantiation (not recommended - use OmnibaseClient instead):
867
918
  * ```typescript
868
919
  * const client = new PermissionsClient('https://api.example.com', omnibaseClient);
869
920
  * ```
870
921
  *
922
+ * @example
923
+ * Recommended usage via OmnibaseClient:
924
+ * ```typescript
925
+ * import { OmnibaseClient } from '@omnibase/core-js';
926
+ *
927
+ * const omnibase = new OmnibaseClient({
928
+ * apiUrl: 'https://api.example.com'
929
+ * });
930
+ *
931
+ * // Use the permissions client
932
+ * await omnibase.permissions.permissions.checkPermission({
933
+ * namespace: 'Tenant',
934
+ * object: 'tenant_123',
935
+ * relation: 'view',
936
+ * subjectId: 'user_456'
937
+ * });
938
+ * ```
939
+ *
871
940
  * @since 1.0.0
872
941
  * @group Client
873
942
  */
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  PermissionsClient,
3
3
  RolesHandler
4
- } from "./chunk-V4FWENQQ.js";
4
+ } from "./chunk-5B37CXXH.js";
5
5
  import {
6
6
  PaymentHandler
7
7
  } from "./chunk-QPW6G4PA.js";