@omnibase/core-js 0.5.10 → 0.7.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.
package/dist/index.cjs CHANGED
@@ -20,7 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- OmnibaseClient: () => OmnibaseClient
23
+ OmnibaseClient: () => OmnibaseClient,
24
+ StorageClient: () => StorageClient
24
25
  });
25
26
  module.exports = __toCommonJS(index_exports);
26
27
 
@@ -56,31 +57,20 @@ var CheckoutManager = class {
56
57
  * @throws {ValidationError} When required parameters are missing or invalid
57
58
  *
58
59
  * @example
59
- * Creating a checkout session (mode is auto-detected):
60
60
  * ```typescript
61
61
  * const session = await checkoutManager.createSession({
62
- * price_id: 'price_one_time_product',
62
+ * price_id: 'price_monthly_pro',
63
63
  * success_url: 'https://app.com/success',
64
64
  * cancel_url: 'https://app.com/cancel'
65
65
  * });
66
66
  *
67
67
  * // Redirect to Stripe checkout
68
- * window.location.href = session.data.url;
69
- * ```
70
- *
71
- * @example
72
- * Checkout with session tracking:
73
- * ```typescript
74
- * const session = await checkoutManager.createSession({
75
- * price_id: 'price_monthly_plan',
76
- * success_url: 'https://app.com/dashboard?session_id={CHECKOUT_SESSION_ID}',
77
- * cancel_url: 'https://app.com/pricing',
78
- * });
79
- *
80
- * console.log(`Session created: ${session.data.sessionId}`);
68
+ * if (session.data?.url) {
69
+ * window.location.href = session.data.url;
70
+ * }
81
71
  * ```
82
72
  *
83
- * @since 1.0.0
73
+ * @since 0.6.0
84
74
  * @group Checkout
85
75
  */
86
76
  async createSession(options) {
@@ -301,7 +291,7 @@ var PortalManager = class {
301
291
  /**
302
292
  * Initialize the portal manager
303
293
  *
304
- * @param paymentHandler - Payment handler instance for API communication
294
+ * @param omnibaseClient - OmnibaseClient instance for API communication
305
295
  *
306
296
  * @group Portal
307
297
  */
@@ -328,32 +318,18 @@ var PortalManager = class {
328
318
  * @throws {ValidationError} When required parameters are missing or invalid
329
319
  *
330
320
  * @example
331
- * Basic portal creation:
332
321
  * ```typescript
333
322
  * const portal = await portalManager.create({
334
323
  * return_url: 'https://myapp.com/account/billing'
335
324
  * });
336
325
  *
337
326
  * // Redirect user to portal
338
- * window.location.href = portal.data.url;
339
- * ```
340
- *
341
- * @example
342
- * With error handling:
343
- * ```typescript
344
- * try {
345
- * const portal = await portalManager.create({
346
- * return_url: window.location.origin + '/billing'
347
- * });
348
- *
327
+ * if (portal.data?.url) {
349
328
  * window.location.href = portal.data.url;
350
- * } catch (error) {
351
- * console.error('Failed to create portal session:', error);
352
- * showErrorMessage('Unable to access billing portal. Please try again.');
353
329
  * }
354
330
  * ```
355
331
  *
356
- * @since 1.0.0
332
+ * @since 0.6.0
357
333
  * @group Portal
358
334
  */
359
335
  async create(options) {
@@ -383,7 +359,7 @@ var UsageManager = class {
383
359
  /**
384
360
  * Initialize the usage manager
385
361
  *
386
- * @param paymentHandler - Payment handler instance for API communication
362
+ * @param omnibaseClient - OmnibaseClient instance for API communication
387
363
  *
388
364
  * @group Usage
389
365
  */
@@ -412,7 +388,6 @@ var UsageManager = class {
412
388
  * @throws {ValidationError} When required parameters are missing or invalid
413
389
  *
414
390
  * @example
415
- * API call tracking:
416
391
  * ```typescript
417
392
  * // Record each API call
418
393
  * await usageManager.recordUsage({
@@ -421,37 +396,7 @@ var UsageManager = class {
421
396
  * });
422
397
  * ```
423
398
  *
424
- * @example
425
- * Batch usage recording:
426
- * ```typescript
427
- * // Record multiple operations at once
428
- * const usageEvents = [
429
- * { meter_event_name: 'compute_hours', value: '0.5' },
430
- * { meter_event_name: 'storage_gb', value: '10' },
431
- * { meter_event_name: 'api_calls', value: '50' }
432
- * ];
433
- *
434
- * for (const event of usageEvents) {
435
- * await usageManager.recordUsage(event);
436
- * }
437
- * ```
438
- *
439
- * @example
440
- * With error handling:
441
- * ```typescript
442
- * try {
443
- * await usageManager.recordUsage({
444
- * meter_event_name: 'file_uploads',
445
- * value: String(uploadedFiles.length)
446
- * });
447
- * } catch (error) {
448
- * console.error('Failed to record usage:', error);
449
- * // Usage recording failure shouldn't block user operations
450
- * // but should be logged for billing accuracy
451
- * }
452
- * ```
453
- *
454
- * @since 1.0.0
399
+ * @since 0.6.0
455
400
  * @group Usage
456
401
  */
457
402
  async recordUsage(options) {
@@ -476,20 +421,20 @@ var UsageManager = class {
476
421
  // src/payments/handler.ts
477
422
  var PaymentHandler = class {
478
423
  /**
479
- * Initialize the payment handler with API configuration
424
+ * Initialize the payment handler with OmnibaseClient
480
425
  *
481
- * Creates a new payment handler instance that will communicate with
482
- * the specified API endpoint. The handler automatically handles
483
- * request formatting and authentication headers.
426
+ * Creates a new payment handler instance with access to all payment
427
+ * operations including checkout, configuration, portal, and usage tracking.
428
+ * The handler uses the provided OmnibaseClient for API communication.
484
429
  *
485
- * @param apiUrl - Base URL for the payment API endpoint
430
+ * @param omnibaseClient - OmnibaseClient instance for API communication
486
431
  *
487
432
  * @example
488
433
  * ```typescript
489
- * const paymentHandler = new PaymentHandler('https://api.myapp.com');
434
+ * const paymentHandler = new PaymentHandler(omnibaseClient);
490
435
  * ```
491
436
  *
492
- * @since 1.0.0
437
+ * @since 0.6.0
493
438
  * @group Client
494
439
  */
495
440
  constructor(omnibaseClient) {
@@ -508,10 +453,14 @@ var PaymentHandler = class {
508
453
  * @example
509
454
  * ```typescript
510
455
  * const session = await paymentHandler.checkout.createSession({
511
- * price_id: 'price_monthly',
456
+ * price_id: 'price_monthly_pro',
512
457
  * success_url: window.location.origin + '/success',
513
458
  * cancel_url: window.location.origin + '/pricing'
514
459
  * });
460
+ *
461
+ * if (session.data?.url) {
462
+ * window.location.href = session.data.url;
463
+ * }
515
464
  * ```
516
465
  */
517
466
  checkout;
@@ -662,6 +611,132 @@ var PermissionsClient = class {
662
611
  }
663
612
  };
664
613
 
614
+ // src/storage/index.ts
615
+ var StorageClient = class {
616
+ constructor(client) {
617
+ this.client = client;
618
+ }
619
+ /**
620
+ * Upload a file to storage
621
+ *
622
+ * @param path - Full path for the file (e.g., "public/images/avatar.png", "users/123/private/doc.pdf")
623
+ * @param file - File or Blob to upload
624
+ * @param options - Upload options including custom metadata
625
+ *
626
+ * @example
627
+ * ```typescript
628
+ * const result = await storage.upload(
629
+ * 'public/avatars/user-123.png',
630
+ * file,
631
+ * {
632
+ * metadata: {
633
+ * userId: '123',
634
+ * uploadedBy: 'john@example.com',
635
+ * tags: ['profile', 'avatar']
636
+ * }
637
+ * }
638
+ * );
639
+ *
640
+ * // File is automatically uploaded to S3 via the presigned URL
641
+ * console.log('File uploaded to:', result.path);
642
+ * ```
643
+ */
644
+ async upload(path, file, options) {
645
+ const metadata = {
646
+ // File metadata
647
+ filename: file instanceof File ? file.name : "blob",
648
+ size: file.size,
649
+ mime_type: file.type,
650
+ uploaded_at: (/* @__PURE__ */ new Date()).toISOString(),
651
+ // Merge custom metadata
652
+ ...options?.metadata || {}
653
+ };
654
+ const response = await this.client.fetch("/api/v1/storage/upload", {
655
+ method: "POST",
656
+ headers: {
657
+ "Content-Type": "application/json"
658
+ },
659
+ body: JSON.stringify({
660
+ path,
661
+ metadata
662
+ })
663
+ });
664
+ if (!response.ok) {
665
+ const error = await response.json().catch(() => ({ error: "Upload failed" }));
666
+ throw new Error(error.error || "Failed to get upload URL");
667
+ }
668
+ const responseData = await response.json();
669
+ const result = responseData.data;
670
+ const uploadResponse = await fetch(result.upload_url, {
671
+ method: "PUT",
672
+ body: file,
673
+ headers: {
674
+ "Content-Type": file.type
675
+ }
676
+ });
677
+ if (!uploadResponse.ok) {
678
+ throw new Error("Failed to upload file to storage");
679
+ }
680
+ return result;
681
+ }
682
+ /**
683
+ * Download a file from storage
684
+ *
685
+ * @param path - Full path to the file
686
+ *
687
+ * @example
688
+ * ```typescript
689
+ * const { download_url } = await storage.download('public/images/logo.png');
690
+ *
691
+ * // Download the file
692
+ * const response = await fetch(download_url);
693
+ * const blob = await response.blob();
694
+ * ```
695
+ */
696
+ async download(path) {
697
+ const response = await this.client.fetch("/api/v1/storage/download", {
698
+ method: "POST",
699
+ headers: {
700
+ "Content-Type": "application/json"
701
+ },
702
+ body: JSON.stringify({
703
+ path
704
+ })
705
+ });
706
+ if (!response.ok) {
707
+ const error = await response.json().catch(() => ({ error: "Download failed" }));
708
+ throw new Error(error.error || "Failed to get download URL");
709
+ }
710
+ const responseData = await response.json();
711
+ return responseData.data;
712
+ }
713
+ /**
714
+ * Delete a file from storage
715
+ *
716
+ * @param path - Full path to the file
717
+ *
718
+ * @example
719
+ * ```typescript
720
+ * await storage.delete('users/123/documents/old-report.pdf');
721
+ * ```
722
+ */
723
+ async delete(path) {
724
+ const response = await this.client.fetch("/api/v1/storage/object", {
725
+ method: "DELETE",
726
+ headers: {
727
+ "Content-Type": "application/json"
728
+ },
729
+ body: JSON.stringify({
730
+ path
731
+ })
732
+ });
733
+ if (!response.ok) {
734
+ const error = await response.json().catch(() => ({ error: "Delete failed" }));
735
+ throw new Error(error.error || "Failed to delete file");
736
+ }
737
+ }
738
+ };
739
+
665
740
  // src/tenants/invites.ts
666
741
  var TenantInviteManager = class {
667
742
  /**
@@ -706,17 +781,6 @@ var TenantInviteManager = class {
706
781
  * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
707
782
  *
708
783
  * @example
709
- * Basic invitation acceptance:
710
- * ```typescript
711
- * const result = await acceptTenantInvite('inv_secure_token_abc123');
712
- *
713
- * console.log(`Successfully joined tenant: ${result.data.tenant_id}`);
714
- * // User can now access tenant resources
715
- * await switchActiveTenant(result.data.tenant_id);
716
- * ```
717
- *
718
- * @example
719
- * Handling the invitation flow:
720
784
  * ```typescript
721
785
  * // Typically called from an invitation link like:
722
786
  * // https://app.com/accept-invite?token=inv_secure_token_abc123
@@ -726,21 +790,20 @@ var TenantInviteManager = class {
726
790
  *
727
791
  * if (inviteToken) {
728
792
  * try {
729
- * const result = await acceptTenantInvite(inviteToken);
793
+ * const result = await inviteManager.accept(inviteToken);
730
794
  *
731
795
  * // Success - redirect to tenant dashboard
796
+ * console.log(`Successfully joined tenant: ${result.data.tenant_id}`);
732
797
  * window.location.href = `/dashboard?tenant=${result.data.tenant_id}`;
733
798
  * } catch (error) {
734
799
  * console.error('Failed to accept invitation:', error.message);
735
- * // Show error to user
736
800
  * }
737
801
  * }
738
802
  * ```
739
803
  *
740
- *
741
- * @since 1.0.0
804
+ * @since 0.6.0
742
805
  * @public
743
- * @group User Management
806
+ * @group Tenant Invitations
744
807
  */
745
808
  async accept(token) {
746
809
  if (!token) {
@@ -775,73 +838,58 @@ var TenantInviteManager = class {
775
838
  }
776
839
  }
777
840
  /**
778
- * Creates a new user invitation for a specific tenant
841
+ * Creates a new user invitation for the active tenant
779
842
  *
780
- * Generates a secure invitation that allows a user to join the specified
781
- * tenant with the defined role. The invitation is sent to the provided
782
- * email address and includes a time-limited token for security.
843
+ * Generates a secure invitation that allows a user to join the currently active
844
+ * tenant with the defined role. The invitation is sent to the provided email address
845
+ * and includes a time-limited token for security. The invite URL will be automatically
846
+ * appended with ?token=XYZ when sent to the user.
783
847
  *
784
- * The function creates the invitation record in the database and can
785
- * trigger email notifications (depending on server configuration).
786
- * The invitation expires after a predefined time period and can only
848
+ * The function creates the invitation record in the database and triggers an email
849
+ * notification to the invited user. The invitation expires after 7 days and can only
787
850
  * be used once.
788
851
  *
789
- * Only existing tenant members with appropriate permissions can create
790
- * invitations. The inviter's authentication is validated via HTTP-only
791
- * cookies sent with the request.
852
+ * Only existing tenant members with appropriate permissions (invite_user permission)
853
+ * can create invitations. The inviter's authentication and tenant context are validated
854
+ * via HTTP-only cookies sent with the request.
792
855
  *
793
- * @param tenantId - Unique identifier of the tenant to invite the user to
794
856
  * @param inviteData - Configuration object for the invitation
795
857
  * @param inviteData.email - Email address of the user to invite
796
858
  * @param inviteData.role - Role the user will have after joining (e.g., 'member', 'admin')
859
+ * @param inviteData.invite_url - Base URL for the invitation link (will be appended with ?token=XYZ)
797
860
  *
798
861
  * @returns Promise resolving to the created invitation with secure token
799
862
  *
800
- * @throws {Error} When tenantId parameter is missing or empty
801
- * @throws {Error} When required fields (email, role) are missing or empty
863
+ * @throws {Error} When required fields (email, role, invite_url) are missing or empty
864
+ * @throws {Error} When the user doesn't have permission to invite users to the tenant
802
865
  * @throws {Error} When the API request fails due to network issues
803
866
  * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
804
867
  *
805
868
  * @example
806
- * Basic invitation creation:
807
869
  * ```typescript
808
- * const invite = await createTenantUserInvite('tenant_123', {
870
+ * const invite = await inviteManager.create({
809
871
  * email: 'colleague@company.com',
810
- * role: 'member'
872
+ * role: 'member',
873
+ * invite_url: 'https://yourapp.com/accept-invite'
811
874
  * });
812
875
  *
813
876
  * console.log(`Invite sent to: ${invite.data.invite.email}`);
814
- * // The invite token can be used to generate invitation links
815
- * const inviteLink = `https://app.com/accept-invite?token=${invite.data.invite.token}`;
816
- * ```
817
- *
818
- * @example
819
- * Creating admin invitation:
820
- * ```typescript
821
- * const adminInvite = await createTenantUserInvite('tenant_456', {
822
- * email: 'admin@company.com',
823
- * role: 'admin'
824
- * });
825
- *
826
- * // Admin users get elevated permissions
827
- * console.log(`Admin invite created with ID: ${adminInvite.data.invite.id}`);
877
+ * console.log(`Invite token: ${invite.data.invite.token}`);
828
878
  * ```
829
879
  *
830
- *
831
- * @since 1.0.0
880
+ * @since 0.6.0
832
881
  * @public
833
- * @group User Management
882
+ * @group Tenant Invitations
834
883
  */
835
- async create(tenantId, inviteData) {
836
- if (!tenantId) {
837
- throw new Error("Tenant ID is required");
838
- }
839
- if (!inviteData.email || !inviteData.role) {
840
- throw new Error("Email and role are required");
884
+ async create(inviteData) {
885
+ if (!inviteData.email || !inviteData.role || !inviteData.invite_url) {
886
+ throw new Error(
887
+ "Missing data in `create` - email, role, and invite_url are required"
888
+ );
841
889
  }
842
890
  try {
843
891
  const response = await this.omnibaseClient.fetch(
844
- `/api/v1/tenants/${tenantId}/invites`,
892
+ `/api/v1/tenants/invites`,
845
893
  {
846
894
  method: "POST",
847
895
  headers: {
@@ -905,21 +953,17 @@ var TenantManger = class {
905
953
  * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
906
954
  *
907
955
  * @example
908
- * Basic tenant creation:
909
956
  * ```typescript
910
- * const newTenant = await createTenant({
957
+ * const newTenant = await tenantManager.createTenant({
911
958
  * name: 'Acme Corporation',
912
959
  * billing_email: 'billing@acme.com',
913
960
  * user_id: 'user_123'
914
961
  * });
915
962
  *
916
- * console.log(`Created tenant: ${newTenant.data.tenant.name}`);
917
- * // Store the token for authenticated requests
918
- * localStorage.setItem('tenant_token', newTenant.data.token);
963
+ * console.log(`Tenant created: ${newTenant.data.tenant.id}`);
919
964
  * ```
920
965
  *
921
- *
922
- * @since 1.0.0
966
+ * @since 0.6.0
923
967
  * @public
924
968
  * @group Tenant Management
925
969
  */
@@ -984,7 +1028,6 @@ var TenantManger = class {
984
1028
  * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
985
1029
  *
986
1030
  * @example
987
- * Basic tenant deletion with confirmation:
988
1031
  * ```typescript
989
1032
  * const tenantToDelete = 'tenant_abc123';
990
1033
  *
@@ -995,8 +1038,8 @@ var TenantManger = class {
995
1038
  *
996
1039
  * if (userConfirmed) {
997
1040
  * try {
998
- * const result = await deleteTenant(tenantToDelete);
999
- * console.log(result.data.message); // "Tenant deleted successfully"
1041
+ * const result = await tenantManager.deleteTenant(tenantToDelete);
1042
+ * console.log(result.data.message);
1000
1043
  *
1001
1044
  * // Redirect user away from deleted tenant
1002
1045
  * window.location.href = '/dashboard';
@@ -1006,7 +1049,7 @@ var TenantManger = class {
1006
1049
  * }
1007
1050
  * ```
1008
1051
  *
1009
- * @since 1.0.0
1052
+ * @since 0.6.0
1010
1053
  * @public
1011
1054
  * @group Tenant Management
1012
1055
  */
@@ -1069,46 +1112,17 @@ var TenantManger = class {
1069
1112
  * @throws {Error} When the server returns an error response (4xx, 5xx status codes)
1070
1113
  *
1071
1114
  * @example
1072
- * Basic tenant switching:
1073
1115
  * ```typescript
1074
- * const result = await switchActiveTenant('tenant_xyz789');
1116
+ * const result = await tenantManager.switchActiveTenant('tenant_xyz789');
1117
+ *
1118
+ * // Store the new token for future requests
1119
+ * console.log(`Switched to tenant. New token: ${result.data.token}`);
1075
1120
  *
1076
1121
  * // Now all API calls will be in the context of tenant_xyz789
1077
1122
  * const tenantData = await getCurrentTenantData();
1078
1123
  * ```
1079
1124
  *
1080
- * @example
1081
- * Using with tenant-aware data fetching:
1082
- * ```typescript
1083
- * // Switch tenant and immediately fetch tenant-specific data
1084
- * const switchAndLoadTenant = async (tenantId: string) => {
1085
- * try {
1086
- * // Switch to new tenant context
1087
- * const switchResult = await switchActiveTenant(tenantId);
1088
- *
1089
- * // Update authentication token
1090
- * setAuthToken(switchResult.data.token);
1091
- *
1092
- * // Fetch data in new tenant context
1093
- * const [tenantInfo, userPermissions, tenantSettings] = await Promise.all([
1094
- * getTenantInfo(),
1095
- * getUserPermissions(),
1096
- * getTenantSettings()
1097
- * ]);
1098
- *
1099
- * return {
1100
- * tenant: tenantInfo,
1101
- * permissions: userPermissions,
1102
- * settings: tenantSettings
1103
- * };
1104
- * } catch (error) {
1105
- * console.error('Failed to switch tenant and load data:', error);
1106
- * throw error;
1107
- * }
1108
- * };
1109
- * ```
1110
- *
1111
- * @since 1.0.0
1125
+ * @since 0.6.0
1112
1126
  * @public
1113
1127
  * @group Tenant Management
1114
1128
  */
@@ -1146,6 +1160,140 @@ var TenantManger = class {
1146
1160
  }
1147
1161
  };
1148
1162
 
1163
+ // src/tenants/user.ts
1164
+ var TenantUserManager = class {
1165
+ /**
1166
+ * Creates a new tenant user manager
1167
+ *
1168
+ * @param omnibaseClient - Configured OmnibaseClient instance for API communication
1169
+ *
1170
+ * @group Tenant User Management
1171
+ */
1172
+ constructor(omnibaseClient) {
1173
+ this.omnibaseClient = omnibaseClient;
1174
+ }
1175
+ /**
1176
+ * Removes a user from the active tenant
1177
+ *
1178
+ * This method removes a specified user from the current active tenant. The operation
1179
+ * requires the requesting user to have appropriate permissions (admin or owner role).
1180
+ * The user being removed will lose access to the tenant and all its resources.
1181
+ *
1182
+ * Note: You cannot remove yourself from a tenant using this method. To leave a tenant,
1183
+ * use the appropriate leave or delete tenant operations instead.
1184
+ *
1185
+ * @param data - Request data containing the user ID to remove
1186
+ * @param data.user_id - ID of the user to remove from the tenant
1187
+ *
1188
+ * @returns Promise resolving to an API response confirming the removal
1189
+ *
1190
+ * @throws {Error} When user_id is not provided
1191
+ * @throws {Error} When the API request fails (includes status code and error details)
1192
+ * @throws {Error} When the user doesn't have permission to remove users
1193
+ * @throws {Error} When the specified user is not a member of the tenant
1194
+ *
1195
+ * @example
1196
+ * ```typescript
1197
+ * // Remove a user from the active tenant
1198
+ * try {
1199
+ * await userManager.remove({ user_id: 'user_abc123' });
1200
+ * console.log('User removed successfully');
1201
+ * } catch (error) {
1202
+ * if (error.message.includes('403')) {
1203
+ * console.error('Insufficient permissions to remove user');
1204
+ * } else if (error.message.includes('404')) {
1205
+ * console.error('User not found in tenant');
1206
+ * } else {
1207
+ * console.error('Failed to remove user:', error);
1208
+ * }
1209
+ * }
1210
+ * ```
1211
+ *
1212
+ * @since 0.6.0
1213
+ * @public
1214
+ * @group Tenant User Management
1215
+ */
1216
+ async remove(data) {
1217
+ if (!data.user_id) {
1218
+ throw new Error("user_id is required");
1219
+ }
1220
+ const response = await this.omnibaseClient.fetch("/api/v1/tenants/users", {
1221
+ method: "DELETE",
1222
+ body: JSON.stringify(data)
1223
+ });
1224
+ if (!response.ok) {
1225
+ const errorData = await response.text();
1226
+ throw new Error(
1227
+ `Failed to delete user from tenant: ${response.status} - ${errorData}`
1228
+ );
1229
+ }
1230
+ return await response.json();
1231
+ }
1232
+ /**
1233
+ * Updates a user's role within the active tenant
1234
+ *
1235
+ * This method changes the role of a specified user in the current active tenant. The operation
1236
+ * requires the requesting user to have appropriate permissions (typically admin or owner role).
1237
+ * Role updates take effect immediately and affect the user's permissions and access rights
1238
+ * within the tenant.
1239
+ *
1240
+ * Common roles include 'admin', 'member', and 'viewer', but the exact roles available depend
1241
+ * on your tenant's configuration. Changing a user's role will modify their ability to perform
1242
+ * various operations within the tenant.
1243
+ *
1244
+ * @param data - Request data containing the user ID and new role
1245
+ * @param data.user_id - ID of the user whose role is being updated
1246
+ * @param data.role - New role to assign to the user
1247
+ *
1248
+ * @returns Promise resolving to an API response confirming the role update
1249
+ *
1250
+ * @throws {Error} When user_id or role is not provided
1251
+ * @throws {Error} When the API request fails (includes status code and error details)
1252
+ * @throws {Error} When the user doesn't have permission to update roles
1253
+ * @throws {Error} When the specified user is not a member of the tenant
1254
+ * @throws {Error} When the specified role is invalid or not allowed
1255
+ *
1256
+ * @example
1257
+ * ```typescript
1258
+ * // Update a user's role to admin
1259
+ * try {
1260
+ * const result = await userManager.updateRole({
1261
+ * user_id: 'user_abc123',
1262
+ * role: 'admin'
1263
+ * });
1264
+ * console.log('Role updated successfully:', result.data.message);
1265
+ * } catch (error) {
1266
+ * if (error.message.includes('403')) {
1267
+ * console.error('Insufficient permissions to update roles');
1268
+ * } else if (error.message.includes('404')) {
1269
+ * console.error('User not found in tenant');
1270
+ * } else {
1271
+ * console.error('Failed to update role:', error);
1272
+ * }
1273
+ * }
1274
+ * ```
1275
+ *
1276
+ * @since 0.6.0
1277
+ * @public
1278
+ * @group Tenant User Management
1279
+ */
1280
+ async updateRole(data) {
1281
+ if (!data.role || !data.user_id)
1282
+ throw new Error("user_id and role is required");
1283
+ const response = await this.omnibaseClient.fetch("/api/v1/tenants/users", {
1284
+ method: "PUT",
1285
+ body: JSON.stringify(data)
1286
+ });
1287
+ if (!response.ok) {
1288
+ const errorData = await response.text();
1289
+ throw new Error(
1290
+ `Failed to update users role: ${response.status} - ${errorData}`
1291
+ );
1292
+ }
1293
+ return await response.json();
1294
+ }
1295
+ };
1296
+
1149
1297
  // src/tenants/handler.ts
1150
1298
  var TenantHandler = class {
1151
1299
  /**
@@ -1169,10 +1317,27 @@ var TenantHandler = class {
1169
1317
  * @group Tenant Management
1170
1318
  */
1171
1319
  constructor(omnibaseClient) {
1172
- this.omnibaseClient = omnibaseClient;
1173
- this.invites = new TenantInviteManager(this.omnibaseClient);
1174
- this.manage = new TenantManger(this.omnibaseClient);
1320
+ this.invites = new TenantInviteManager(omnibaseClient);
1321
+ this.manage = new TenantManger(omnibaseClient);
1322
+ this.user = new TenantUserManager(omnibaseClient);
1175
1323
  }
1324
+ /**
1325
+ * Tenant user management operations
1326
+ *
1327
+ * Provides access to operations for managing users within tenants, including
1328
+ * removing users from the active tenant. All operations respect user permissions
1329
+ * and tenant ownership rules.
1330
+ *
1331
+ * @example
1332
+ * ```typescript
1333
+ * // Remove a user from the active tenant
1334
+ * await tenantHandler.user.remove({ user_id: 'user_123' });
1335
+ * ```
1336
+ *
1337
+ * @since 0.6.0
1338
+ * @group Tenant Management
1339
+ */
1340
+ user;
1176
1341
  /**
1177
1342
  * Core tenant management operations
1178
1343
  *
@@ -1183,17 +1348,17 @@ var TenantHandler = class {
1183
1348
  * @example
1184
1349
  * ```typescript
1185
1350
  * // Create a new tenant
1186
- * const tenant = await tenantHandler.tenants.createTenant({
1351
+ * const tenant = await tenantHandler.manage.createTenant({
1187
1352
  * name: 'New Company',
1188
1353
  * billing_email: 'billing@newcompany.com',
1189
1354
  * user_id: 'user_456'
1190
1355
  * });
1191
1356
  *
1192
1357
  * // Switch to the tenant
1193
- * await tenantHandler.tenants.switchActiveTenant(tenant.data.tenant.id);
1358
+ * await tenantHandler.manage.switchActiveTenant(tenant.data.tenant.id);
1194
1359
  *
1195
1360
  * // Delete the tenant (owner only)
1196
- * await tenantHandler.tenants.deleteTenant(tenant.data.tenant.id);
1361
+ * await tenantHandler.manage.deleteTenant(tenant.data.tenant.id);
1197
1362
  * ```
1198
1363
  */
1199
1364
  manage;
@@ -1207,9 +1372,10 @@ var TenantHandler = class {
1207
1372
  * @example
1208
1373
  * ```typescript
1209
1374
  * // Create an invitation
1210
- * const invite = await tenantHandler.invites.create('tenant_123', {
1375
+ * const invite = await tenantHandler.invites.create({
1211
1376
  * email: 'newuser@company.com',
1212
- * role: 'admin'
1377
+ * role: 'admin',
1378
+ * invite_url: 'https://yourapp.com/accept-invite'
1213
1379
  * });
1214
1380
  *
1215
1381
  * // Accept an invitation (from the invited user's session)
@@ -1250,8 +1416,105 @@ var OmnibaseClient = class {
1250
1416
  * ```
1251
1417
  */
1252
1418
  payments = new PaymentHandler(this);
1419
+ /**
1420
+ * Main tenant management handler
1421
+ *
1422
+ * This is the primary entry point for all tenant-related operations in the
1423
+ * Omnibase SDK. It provides a unified interface to tenant management,
1424
+ * user management, and invitation functionality through dedicated manager instances.
1425
+ *
1426
+ * The handler follows the composition pattern, combining specialized managers
1427
+ * for different aspects of tenant functionality:
1428
+ * - `manage`: Core tenant operations (create, delete, switch)
1429
+ * - `invites`: User invitation management (create, accept)
1430
+ * - `user`: Tenant user operations (remove, update role)
1431
+ *
1432
+ * All operations are performed within the context of the authenticated user
1433
+ * and respect tenant-level permissions and row-level security policies.
1434
+ *
1435
+ * @example
1436
+ * ```typescript
1437
+ * // Create a new tenant
1438
+ * const tenant = await omnibase.tenants.manage.createTenant({
1439
+ * name: 'My Company',
1440
+ * billing_email: 'billing@company.com',
1441
+ * user_id: 'user_123'
1442
+ * });
1443
+ *
1444
+ * // Invite users to the tenant
1445
+ * const invite = await omnibase.tenants.invites.create({
1446
+ * email: 'colleague@company.com',
1447
+ * role: 'member',
1448
+ * invite_url: 'https://yourapp.com/accept-invite'
1449
+ * });
1450
+ *
1451
+ * // Switch to the new tenant
1452
+ * await omnibase.tenants.manage.switchActiveTenant(tenant.data.tenant.id);
1453
+ * ```
1454
+ *
1455
+ * @since 0.6.0
1456
+ * @public
1457
+ * @group Tenant Management
1458
+ */
1253
1459
  tenants = new TenantHandler(this);
1460
+ /**
1461
+ * Client for managing permissions and relationships using Ory Keto
1462
+ *
1463
+ * This client provides access to Ory Keto's permission system, allowing you to
1464
+ * create, manage, and check relationships between subjects and objects. It handles
1465
+ * both read operations (permission checks) and write operations (relationship management).
1466
+ *
1467
+ * The client automatically configures separate endpoints for read and write operations
1468
+ * to optimize performance and security by following Ory Keto's recommended architecture.
1469
+ *
1470
+ * @example
1471
+ * ```typescript
1472
+ * // Check if a user can view a tenant
1473
+ * const canView = await omnibase.permissions.permissions.checkPermission(
1474
+ * undefined,
1475
+ * {
1476
+ * namespace: 'Tenant',
1477
+ * object: 'tenant_123',
1478
+ * relation: 'view',
1479
+ * subjectId: 'user_456'
1480
+ * }
1481
+ * );
1482
+ *
1483
+ * if (canView.data.allowed) {
1484
+ * console.log('User can view the tenant');
1485
+ * }
1486
+ *
1487
+ * // Create a relationship making a user an owner of a tenant
1488
+ * await omnibase.permissions.relationships.createRelationship(
1489
+ * undefined,
1490
+ * {
1491
+ * namespace: 'Tenant',
1492
+ * object: 'tenant_123',
1493
+ * relation: 'owners',
1494
+ * subjectId: 'user_456'
1495
+ * }
1496
+ * );
1497
+ * ```
1498
+ *
1499
+ * @since 0.6.0
1500
+ * @public
1501
+ * @group Permissions
1502
+ */
1254
1503
  permissions;
1504
+ /**
1505
+ * Storage client for file upload/download operations
1506
+ *
1507
+ * @example
1508
+ * ```typescript
1509
+ * // Upload with metadata
1510
+ * await omnibase.storage.bucket('documents').upload(
1511
+ * 'report.pdf',
1512
+ * file,
1513
+ * { metadata: { department: 'engineering' } }
1514
+ * );
1515
+ * ```
1516
+ */
1517
+ storage = new StorageClient(this);
1255
1518
  async fetch(endpoint, options = {}) {
1256
1519
  if (this.config.fetch)
1257
1520
  return this.config.fetch(this.config.api_url + endpoint, options);
@@ -1263,5 +1526,6 @@ var OmnibaseClient = class {
1263
1526
  };
1264
1527
  // Annotate the CommonJS export names for ESM import in node:
1265
1528
  0 && (module.exports = {
1266
- OmnibaseClient
1529
+ OmnibaseClient,
1530
+ StorageClient
1267
1531
  });