@drmhse/sso-sdk 0.2.4 → 0.2.7
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/README.md +215 -310
- package/dist/index.d.mts +1751 -145
- package/dist/index.d.ts +1751 -145
- package/dist/index.js +1570 -266
- package/dist/index.mjs +1569 -266
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
InvitationsModule: () => InvitationsModule,
|
|
25
25
|
OrganizationsModule: () => OrganizationsModule,
|
|
26
26
|
PlatformModule: () => PlatformModule,
|
|
27
|
+
ServiceApiModule: () => ServiceApiModule,
|
|
27
28
|
ServicesModule: () => ServicesModule,
|
|
28
29
|
SsoApiError: () => SsoApiError,
|
|
29
30
|
SsoClient: () => SsoClient,
|
|
@@ -471,7 +472,8 @@ var AuthModule = class {
|
|
|
471
472
|
* ```typescript
|
|
472
473
|
* await sso.auth.logout();
|
|
473
474
|
* sso.setAuthToken(null);
|
|
474
|
-
* localStorage.removeItem('
|
|
475
|
+
* localStorage.removeItem('sso_access_token');
|
|
476
|
+
* localStorage.removeItem('sso_refresh_token');
|
|
475
477
|
* ```
|
|
476
478
|
*/
|
|
477
479
|
async logout() {
|
|
@@ -494,8 +496,8 @@ var AuthModule = class {
|
|
|
494
496
|
* try {
|
|
495
497
|
* const tokens = await sso.auth.refreshToken(storedRefreshToken);
|
|
496
498
|
* sso.setAuthToken(tokens.access_token);
|
|
497
|
-
* localStorage.setItem('
|
|
498
|
-
* localStorage.setItem('
|
|
499
|
+
* localStorage.setItem('sso_access_token', tokens.access_token);
|
|
500
|
+
* localStorage.setItem('sso_refresh_token', tokens.refresh_token);
|
|
499
501
|
* } catch (error) {
|
|
500
502
|
* // Refresh failed - redirect to login
|
|
501
503
|
* window.location.href = '/login';
|
|
@@ -525,6 +527,129 @@ var AuthModule = class {
|
|
|
525
527
|
const response = await this.http.get(`/api/provider-token/${provider}`);
|
|
526
528
|
return response.data;
|
|
527
529
|
}
|
|
530
|
+
// ============================================================================
|
|
531
|
+
// PASSWORD AUTHENTICATION
|
|
532
|
+
// ============================================================================
|
|
533
|
+
/**
|
|
534
|
+
* Register a new user with email and password.
|
|
535
|
+
* After registration, the user will receive a verification email.
|
|
536
|
+
*
|
|
537
|
+
* @param payload Registration details (email and password)
|
|
538
|
+
* @returns Registration confirmation message
|
|
539
|
+
*
|
|
540
|
+
* @example
|
|
541
|
+
* ```typescript
|
|
542
|
+
* const response = await sso.auth.register({
|
|
543
|
+
* email: 'user@example.com',
|
|
544
|
+
* password: 'SecurePassword123!'
|
|
545
|
+
* });
|
|
546
|
+
* console.log(response.message);
|
|
547
|
+
* ```
|
|
548
|
+
*/
|
|
549
|
+
async register(payload) {
|
|
550
|
+
const response = await this.http.post("/api/auth/register", payload);
|
|
551
|
+
return response.data;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Login with email and password.
|
|
555
|
+
* Returns access token and refresh token on successful authentication.
|
|
556
|
+
* The user's email must be verified before login.
|
|
557
|
+
*
|
|
558
|
+
* @param payload Login credentials (email and password)
|
|
559
|
+
* @returns Access token, refresh token, and expiration info
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```typescript
|
|
563
|
+
* const tokens = await sso.auth.login({
|
|
564
|
+
* email: 'user@example.com',
|
|
565
|
+
* password: 'SecurePassword123!'
|
|
566
|
+
* });
|
|
567
|
+
* sso.setAuthToken(tokens.access_token);
|
|
568
|
+
* localStorage.setItem('sso_access_token', tokens.access_token);
|
|
569
|
+
* localStorage.setItem('sso_refresh_token', tokens.refresh_token);
|
|
570
|
+
* ```
|
|
571
|
+
*/
|
|
572
|
+
async login(payload) {
|
|
573
|
+
const response = await this.http.post("/api/auth/login", payload);
|
|
574
|
+
return response.data;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Verify MFA code and complete authentication.
|
|
578
|
+
* This method should be called after login when the user has MFA enabled.
|
|
579
|
+
* The login will return a pre-auth token with a short expiration (5 minutes).
|
|
580
|
+
* Exchange the pre-auth token and TOTP code for a full session.
|
|
581
|
+
*
|
|
582
|
+
* @param preauthToken The pre-authentication token received from login
|
|
583
|
+
* @param code The TOTP code from the user's authenticator app or a backup code
|
|
584
|
+
* @returns Full session tokens (access_token and refresh_token)
|
|
585
|
+
*
|
|
586
|
+
* @example
|
|
587
|
+
* ```typescript
|
|
588
|
+
* // After login, if MFA is enabled:
|
|
589
|
+
* const loginResponse = await sso.auth.login({
|
|
590
|
+
* email: 'user@example.com',
|
|
591
|
+
* password: 'password'
|
|
592
|
+
* });
|
|
593
|
+
*
|
|
594
|
+
* // Check if this is a pre-auth token (expires_in will be 300 seconds = 5 minutes)
|
|
595
|
+
* if (loginResponse.expires_in === 300) {
|
|
596
|
+
* // User needs to provide MFA code
|
|
597
|
+
* const mfaCode = prompt('Enter your 6-digit code from authenticator app');
|
|
598
|
+
* const tokens = await sso.auth.verifyMfa(loginResponse.access_token, mfaCode);
|
|
599
|
+
* sso.setAuthToken(tokens.access_token);
|
|
600
|
+
* localStorage.setItem('sso_access_token', tokens.access_token);
|
|
601
|
+
* localStorage.setItem('sso_refresh_token', tokens.refresh_token);
|
|
602
|
+
* }
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
605
|
+
async verifyMfa(preauthToken, code, deviceCodeId) {
|
|
606
|
+
const response = await this.http.post("/api/auth/mfa/verify", {
|
|
607
|
+
preauth_token: preauthToken,
|
|
608
|
+
code,
|
|
609
|
+
...deviceCodeId && { device_code_id: deviceCodeId }
|
|
610
|
+
});
|
|
611
|
+
return response.data;
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Request a password reset for a user account.
|
|
615
|
+
* If the email exists, a reset link will be sent to the user.
|
|
616
|
+
* Returns success regardless of whether the email exists (to prevent email enumeration).
|
|
617
|
+
*
|
|
618
|
+
* @param payload Forgot password request (email address)
|
|
619
|
+
* @returns Confirmation message
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```typescript
|
|
623
|
+
* const response = await sso.auth.requestPasswordReset({
|
|
624
|
+
* email: 'user@example.com'
|
|
625
|
+
* });
|
|
626
|
+
* console.log(response.message);
|
|
627
|
+
* ```
|
|
628
|
+
*/
|
|
629
|
+
async requestPasswordReset(payload) {
|
|
630
|
+
const response = await this.http.post("/api/auth/forgot-password", payload);
|
|
631
|
+
return response.data;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Reset a user's password using a reset token from email.
|
|
635
|
+
* The token is obtained from the password reset email link.
|
|
636
|
+
*
|
|
637
|
+
* @param payload Reset password request (token and new password)
|
|
638
|
+
* @returns Confirmation message
|
|
639
|
+
*
|
|
640
|
+
* @example
|
|
641
|
+
* ```typescript
|
|
642
|
+
* const response = await sso.auth.resetPassword({
|
|
643
|
+
* token: 'reset-token-from-email',
|
|
644
|
+
* new_password: 'NewSecurePassword123!'
|
|
645
|
+
* });
|
|
646
|
+
* console.log(response.message);
|
|
647
|
+
* ```
|
|
648
|
+
*/
|
|
649
|
+
async resetPassword(payload) {
|
|
650
|
+
const response = await this.http.post("/api/auth/reset-password", payload);
|
|
651
|
+
return response.data;
|
|
652
|
+
}
|
|
528
653
|
};
|
|
529
654
|
|
|
530
655
|
// src/modules/user.ts
|
|
@@ -533,454 +658,1433 @@ var IdentitiesModule = class {
|
|
|
533
658
|
this.http = http;
|
|
534
659
|
}
|
|
535
660
|
/**
|
|
536
|
-
* List all social accounts linked to the authenticated user.
|
|
661
|
+
* List all social accounts linked to the authenticated user.
|
|
662
|
+
*
|
|
663
|
+
* @returns Array of linked identities
|
|
664
|
+
*
|
|
665
|
+
* @example
|
|
666
|
+
* ```typescript
|
|
667
|
+
* const identities = await sso.user.identities.list();
|
|
668
|
+
* console.log(identities); // [{ provider: 'github' }, { provider: 'google' }]
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
async list() {
|
|
672
|
+
const response = await this.http.get("/api/user/identities");
|
|
673
|
+
return response.data;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Start linking a new social account to the authenticated user.
|
|
677
|
+
* Returns an authorization URL that the user should be redirected to.
|
|
678
|
+
*
|
|
679
|
+
* @param provider The OAuth provider to link (e.g., 'github', 'google', 'microsoft')
|
|
680
|
+
* @returns Object containing the authorization URL
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* ```typescript
|
|
684
|
+
* const { authorization_url } = await sso.user.identities.startLink('github');
|
|
685
|
+
* window.location.href = authorization_url; // Redirect user to complete OAuth
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
async startLink(provider) {
|
|
689
|
+
const response = await this.http.post(`/api/user/identities/${provider}/link`, {});
|
|
690
|
+
return response.data;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Unlink a social account from the authenticated user.
|
|
694
|
+
* Note: Cannot unlink the last remaining identity to prevent account lockout.
|
|
695
|
+
*
|
|
696
|
+
* @param provider The OAuth provider to unlink (e.g., 'github', 'google', 'microsoft')
|
|
697
|
+
*
|
|
698
|
+
* @example
|
|
699
|
+
* ```typescript
|
|
700
|
+
* await sso.user.identities.unlink('google');
|
|
701
|
+
* ```
|
|
702
|
+
*/
|
|
703
|
+
async unlink(provider) {
|
|
704
|
+
await this.http.delete(`/api/user/identities/${provider}`);
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
var MfaModule = class {
|
|
708
|
+
constructor(http) {
|
|
709
|
+
this.http = http;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Get the current MFA status for the authenticated user.
|
|
713
|
+
*
|
|
714
|
+
* @returns MFA status
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```typescript
|
|
718
|
+
* const status = await sso.user.mfa.getStatus();
|
|
719
|
+
* console.log(status.enabled); // false
|
|
720
|
+
* ```
|
|
721
|
+
*/
|
|
722
|
+
async getStatus() {
|
|
723
|
+
const response = await this.http.get("/api/user/mfa/status");
|
|
724
|
+
return response.data;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Initiate MFA setup. Generates a TOTP secret and QR code.
|
|
728
|
+
* The user must complete setup by calling verify() with a code from their authenticator app.
|
|
729
|
+
*
|
|
730
|
+
* @returns MFA setup details including QR code
|
|
731
|
+
*
|
|
732
|
+
* @example
|
|
733
|
+
* ```typescript
|
|
734
|
+
* const setup = await sso.user.mfa.setup();
|
|
735
|
+
* console.log(setup.qr_code_svg); // Display this QR code to the user
|
|
736
|
+
* // User scans QR code with authenticator app and enters code to verify
|
|
737
|
+
* ```
|
|
738
|
+
*/
|
|
739
|
+
async setup() {
|
|
740
|
+
const response = await this.http.post("/api/user/mfa/setup", {});
|
|
741
|
+
return response.data;
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Verify TOTP code and enable MFA.
|
|
745
|
+
* Returns backup codes that must be stored securely by the user.
|
|
746
|
+
*
|
|
747
|
+
* @param code TOTP code from authenticator app
|
|
748
|
+
* @returns Verification response with backup codes
|
|
749
|
+
*
|
|
750
|
+
* @example
|
|
751
|
+
* ```typescript
|
|
752
|
+
* const result = await sso.user.mfa.verify('123456');
|
|
753
|
+
* console.log(result.backup_codes); // Store these securely!
|
|
754
|
+
* ```
|
|
755
|
+
*/
|
|
756
|
+
async verify(code) {
|
|
757
|
+
const response = await this.http.post("/api/user/mfa/verify", { code });
|
|
758
|
+
return response.data;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Disable MFA for the authenticated user.
|
|
762
|
+
*
|
|
763
|
+
* @example
|
|
764
|
+
* ```typescript
|
|
765
|
+
* await sso.user.mfa.disable();
|
|
766
|
+
* ```
|
|
767
|
+
*/
|
|
768
|
+
async disable() {
|
|
769
|
+
const response = await this.http.delete("/api/user/mfa");
|
|
770
|
+
return response.data;
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Regenerate backup codes.
|
|
774
|
+
* Invalidates all previous backup codes and returns new ones.
|
|
775
|
+
*
|
|
776
|
+
* @returns New backup codes
|
|
777
|
+
*
|
|
778
|
+
* @example
|
|
779
|
+
* ```typescript
|
|
780
|
+
* const { backup_codes } = await sso.user.mfa.regenerateBackupCodes();
|
|
781
|
+
* console.log(backup_codes); // Store these securely!
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
async regenerateBackupCodes() {
|
|
785
|
+
const response = await this.http.post("/api/user/mfa/backup-codes/regenerate", {});
|
|
786
|
+
return response.data;
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
var UserModule = class {
|
|
790
|
+
constructor(http) {
|
|
791
|
+
this.http = http;
|
|
792
|
+
this.identities = new IdentitiesModule(http);
|
|
793
|
+
this.mfa = new MfaModule(http);
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Get the profile of the currently authenticated user.
|
|
797
|
+
* The response includes context from the JWT (org, service).
|
|
798
|
+
*
|
|
799
|
+
* @returns User profile
|
|
800
|
+
*
|
|
801
|
+
* @example
|
|
802
|
+
* ```typescript
|
|
803
|
+
* const profile = await sso.user.getProfile();
|
|
804
|
+
* console.log(profile.email, profile.org, profile.service);
|
|
805
|
+
* ```
|
|
806
|
+
*/
|
|
807
|
+
async getProfile() {
|
|
808
|
+
const response = await this.http.get("/api/user");
|
|
809
|
+
return response.data;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Update the authenticated user's profile.
|
|
813
|
+
*
|
|
814
|
+
* @param payload Update payload
|
|
815
|
+
* @returns Updated user profile
|
|
816
|
+
*
|
|
817
|
+
* @example
|
|
818
|
+
* ```typescript
|
|
819
|
+
* const updated = await sso.user.updateProfile({
|
|
820
|
+
* email: 'newemail@example.com'
|
|
821
|
+
* });
|
|
822
|
+
* ```
|
|
823
|
+
*/
|
|
824
|
+
async updateProfile(payload) {
|
|
825
|
+
const response = await this.http.patch("/api/user", payload);
|
|
826
|
+
return response.data;
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Get the current user's subscription details for the service in their JWT.
|
|
830
|
+
*
|
|
831
|
+
* @returns Subscription details
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* ```typescript
|
|
835
|
+
* const subscription = await sso.user.getSubscription();
|
|
836
|
+
* console.log(subscription.plan, subscription.features);
|
|
837
|
+
* ```
|
|
838
|
+
*/
|
|
839
|
+
async getSubscription() {
|
|
840
|
+
const response = await this.http.get("/api/subscription");
|
|
841
|
+
return response.data;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Change the authenticated user's password.
|
|
845
|
+
* Requires the current password for verification.
|
|
846
|
+
*
|
|
847
|
+
* @param payload Change password request (current and new password)
|
|
848
|
+
* @returns Confirmation message
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* ```typescript
|
|
852
|
+
* const response = await sso.user.changePassword({
|
|
853
|
+
* current_password: 'OldPassword123!',
|
|
854
|
+
* new_password: 'NewSecurePassword456!'
|
|
855
|
+
* });
|
|
856
|
+
* console.log(response.message);
|
|
857
|
+
* ```
|
|
858
|
+
*/
|
|
859
|
+
async changePassword(payload) {
|
|
860
|
+
const response = await this.http.post("/api/user/change-password", payload);
|
|
861
|
+
return response.data;
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Set a password for the authenticated user (OAuth users only).
|
|
865
|
+
* This endpoint is for OAuth users who don't have a password yet.
|
|
866
|
+
* If a password is already set, this will return an error.
|
|
867
|
+
*
|
|
868
|
+
* @param payload Set password request (new password only)
|
|
869
|
+
* @returns Confirmation message
|
|
870
|
+
*
|
|
871
|
+
* @example
|
|
872
|
+
* ```typescript
|
|
873
|
+
* const response = await sso.user.setPassword({
|
|
874
|
+
* new_password: 'MyNewSecurePassword123!'
|
|
875
|
+
* });
|
|
876
|
+
* console.log(response.message); // "Password set successfully"
|
|
877
|
+
* ```
|
|
878
|
+
*/
|
|
879
|
+
async setPassword(payload) {
|
|
880
|
+
const response = await this.http.post("/api/user/set-password", payload);
|
|
881
|
+
return response.data;
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
// src/modules/organizations/audit.ts
|
|
886
|
+
var AuditLogsModule = class {
|
|
887
|
+
constructor(http) {
|
|
888
|
+
this.http = http;
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Get audit logs for an organization.
|
|
892
|
+
* Requires 'owner' or 'admin' role.
|
|
893
|
+
*
|
|
894
|
+
* @param orgSlug Organization slug
|
|
895
|
+
* @param params Optional query parameters for filtering and pagination
|
|
896
|
+
* @returns Paginated audit log response
|
|
897
|
+
*
|
|
898
|
+
* @example
|
|
899
|
+
* ```typescript
|
|
900
|
+
* // Get all audit logs
|
|
901
|
+
* const logs = await sso.organizations.auditLogs.get('acme-corp');
|
|
902
|
+
*
|
|
903
|
+
* // Filter by specific action
|
|
904
|
+
* const userLogs = await sso.organizations.auditLogs.get('acme-corp', {
|
|
905
|
+
* action: 'user.role_updated',
|
|
906
|
+
* page: 1,
|
|
907
|
+
* limit: 20
|
|
908
|
+
* });
|
|
909
|
+
*
|
|
910
|
+
* // Filter by target
|
|
911
|
+
* const serviceLogs = await sso.organizations.auditLogs.get('acme-corp', {
|
|
912
|
+
* target_type: 'service',
|
|
913
|
+
* target_id: 'service-123'
|
|
914
|
+
* });
|
|
915
|
+
* ```
|
|
916
|
+
*/
|
|
917
|
+
async get(orgSlug, params) {
|
|
918
|
+
const response = await this.http.get(
|
|
919
|
+
`/api/organizations/${orgSlug}/audit-log`,
|
|
920
|
+
{ params }
|
|
921
|
+
);
|
|
922
|
+
return response.data;
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Get available audit event types for filtering.
|
|
926
|
+
* Requires 'owner' or 'admin' role.
|
|
927
|
+
*
|
|
928
|
+
* @param orgSlug Organization slug
|
|
929
|
+
* @returns Array of event type information
|
|
930
|
+
*
|
|
931
|
+
* @example
|
|
932
|
+
* ```typescript
|
|
933
|
+
* const eventTypes = await sso.organizations.auditLogs.getEventTypes('acme-corp');
|
|
934
|
+
*
|
|
935
|
+
* // Group by category for UI display
|
|
936
|
+
* const byCategory = eventTypes.reduce((acc, event) => {
|
|
937
|
+
* if (!acc[event.category]) {
|
|
938
|
+
* acc[event.category] = [];
|
|
939
|
+
* }
|
|
940
|
+
* acc[event.category].push(event);
|
|
941
|
+
* return acc;
|
|
942
|
+
* }, {});
|
|
943
|
+
* ```
|
|
944
|
+
*/
|
|
945
|
+
async getEventTypes(orgSlug) {
|
|
946
|
+
const response = await this.http.get(
|
|
947
|
+
`/api/organizations/${orgSlug}/audit-log/event-types`
|
|
948
|
+
);
|
|
949
|
+
return response.data;
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
// src/modules/organizations/webhooks.ts
|
|
954
|
+
var WebhooksModule = class {
|
|
955
|
+
constructor(http) {
|
|
956
|
+
this.http = http;
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Create a new webhook for an organization.
|
|
960
|
+
* Requires 'owner' or 'admin' role.
|
|
961
|
+
*
|
|
962
|
+
* @param orgSlug Organization slug
|
|
963
|
+
* @param webhook Webhook creation payload
|
|
964
|
+
* @returns Created webhook details
|
|
965
|
+
*
|
|
966
|
+
* @example
|
|
967
|
+
* ```typescript
|
|
968
|
+
* const webhook = await sso.organizations.webhooks.create('acme-corp', {
|
|
969
|
+
* name: 'User Activity',
|
|
970
|
+
* url: 'https://api.example.com/webhooks',
|
|
971
|
+
* events: ['user.invited', 'user.joined', 'user.removed']
|
|
972
|
+
* });
|
|
973
|
+
* console.log('Created webhook:', webhook.id);
|
|
974
|
+
* ```
|
|
975
|
+
*/
|
|
976
|
+
async create(orgSlug, webhook) {
|
|
977
|
+
const response = await this.http.post(
|
|
978
|
+
`/api/organizations/${orgSlug}/webhooks`,
|
|
979
|
+
webhook
|
|
980
|
+
);
|
|
981
|
+
return response.data;
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* List all webhooks for an organization.
|
|
985
|
+
* Requires 'owner' or 'admin' role.
|
|
986
|
+
*
|
|
987
|
+
* @param orgSlug Organization slug
|
|
988
|
+
* @returns List of webhooks with total count
|
|
989
|
+
*
|
|
990
|
+
* @example
|
|
991
|
+
* ```typescript
|
|
992
|
+
* const { webhooks, total } = await sso.organizations.webhooks.list('acme-corp');
|
|
993
|
+
* console.log(`Found ${total} webhooks`);
|
|
994
|
+
* webhooks.forEach(w => console.log(w.name, w.is_active));
|
|
995
|
+
* ```
|
|
996
|
+
*/
|
|
997
|
+
async list(orgSlug) {
|
|
998
|
+
const response = await this.http.get(
|
|
999
|
+
`/api/organizations/${orgSlug}/webhooks`
|
|
1000
|
+
);
|
|
1001
|
+
return response.data;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Get a specific webhook by ID.
|
|
1005
|
+
* Requires 'owner' or 'admin' role.
|
|
1006
|
+
*
|
|
1007
|
+
* @param orgSlug Organization slug
|
|
1008
|
+
* @param webhookId Webhook ID
|
|
1009
|
+
* @returns Webhook details
|
|
1010
|
+
*
|
|
1011
|
+
* @example
|
|
1012
|
+
* ```typescript
|
|
1013
|
+
* const webhook = await sso.organizations.webhooks.get('acme-corp', 'webhook-123');
|
|
1014
|
+
* console.log('Webhook URL:', webhook.url);
|
|
1015
|
+
* console.log('Subscribed events:', webhook.events);
|
|
1016
|
+
* ```
|
|
1017
|
+
*/
|
|
1018
|
+
async get(orgSlug, webhookId) {
|
|
1019
|
+
const response = await this.http.get(
|
|
1020
|
+
`/api/organizations/${orgSlug}/webhooks/${webhookId}`
|
|
1021
|
+
);
|
|
1022
|
+
return response.data;
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Update an existing webhook.
|
|
1026
|
+
* Requires 'owner' or 'admin' role.
|
|
1027
|
+
*
|
|
1028
|
+
* @param orgSlug Organization slug
|
|
1029
|
+
* @param webhookId Webhook ID
|
|
1030
|
+
* @param updates Partial webhook update payload
|
|
1031
|
+
* @returns Updated webhook details
|
|
1032
|
+
*
|
|
1033
|
+
* @example
|
|
1034
|
+
* ```typescript
|
|
1035
|
+
* // Update webhook URL and add new events
|
|
1036
|
+
* const updated = await sso.organizations.webhooks.update('acme-corp', 'webhook-123', {
|
|
1037
|
+
* url: 'https://api.example.com/webhooks/v2',
|
|
1038
|
+
* events: ['user.invited', 'user.joined', 'user.removed', 'user.role_updated']
|
|
1039
|
+
* });
|
|
1040
|
+
*
|
|
1041
|
+
* // Deactivate webhook temporarily
|
|
1042
|
+
* await sso.organizations.webhooks.update('acme-corp', 'webhook-123', {
|
|
1043
|
+
* is_active: false
|
|
1044
|
+
* });
|
|
1045
|
+
* ```
|
|
1046
|
+
*/
|
|
1047
|
+
async update(orgSlug, webhookId, updates) {
|
|
1048
|
+
const response = await this.http.patch(
|
|
1049
|
+
`/api/organizations/${orgSlug}/webhooks/${webhookId}`,
|
|
1050
|
+
updates
|
|
1051
|
+
);
|
|
1052
|
+
return response.data;
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Delete a webhook.
|
|
1056
|
+
* Requires 'owner' or 'admin' role.
|
|
1057
|
+
* This will also delete all delivery history for this webhook.
|
|
1058
|
+
*
|
|
1059
|
+
* @param orgSlug Organization slug
|
|
1060
|
+
* @param webhookId Webhook ID
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* ```typescript
|
|
1064
|
+
* await sso.organizations.webhooks.delete('acme-corp', 'webhook-123');
|
|
1065
|
+
* console.log('Webhook deleted successfully');
|
|
1066
|
+
* ```
|
|
1067
|
+
*/
|
|
1068
|
+
async delete(orgSlug, webhookId) {
|
|
1069
|
+
await this.http.delete(
|
|
1070
|
+
`/api/organizations/${orgSlug}/webhooks/${webhookId}`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Get delivery history for a specific webhook.
|
|
1075
|
+
* Requires 'owner' or 'admin' role.
|
|
1076
|
+
*
|
|
1077
|
+
* @param orgSlug Organization slug
|
|
1078
|
+
* @param webhookId Webhook ID
|
|
1079
|
+
* @param params Optional query parameters for filtering and pagination
|
|
1080
|
+
* @returns Paginated webhook delivery response
|
|
1081
|
+
*
|
|
1082
|
+
* @example
|
|
1083
|
+
* ```typescript
|
|
1084
|
+
* // Get all delivery attempts
|
|
1085
|
+
* const deliveries = await sso.organizations.webhooks.getDeliveries('acme-corp', 'webhook-123');
|
|
1086
|
+
*
|
|
1087
|
+
* // Get only failed deliveries
|
|
1088
|
+
* const failed = await sso.organizations.webhooks.getDeliveries('acme-corp', 'webhook-123', {
|
|
1089
|
+
* delivered: false,
|
|
1090
|
+
* page: 1,
|
|
1091
|
+
* limit: 20
|
|
1092
|
+
* });
|
|
1093
|
+
*
|
|
1094
|
+
* // Get deliveries for specific event type
|
|
1095
|
+
* const userEvents = await sso.organizations.webhooks.getDeliveries('acme-corp', 'webhook-123', {
|
|
1096
|
+
* event_type: 'user.invited'
|
|
1097
|
+
* });
|
|
1098
|
+
* ```
|
|
1099
|
+
*/
|
|
1100
|
+
async getDeliveries(orgSlug, webhookId, params) {
|
|
1101
|
+
const response = await this.http.get(
|
|
1102
|
+
`/api/organizations/${orgSlug}/webhooks/${webhookId}/deliveries`,
|
|
1103
|
+
{ params }
|
|
1104
|
+
);
|
|
1105
|
+
return response.data;
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Get available webhook event types that can be subscribed to.
|
|
1109
|
+
* Requires 'owner' or 'admin' role.
|
|
1110
|
+
*
|
|
1111
|
+
* @param orgSlug Organization slug
|
|
1112
|
+
* @returns Array of available event types with categories
|
|
1113
|
+
*
|
|
1114
|
+
* @example
|
|
1115
|
+
* ```typescript
|
|
1116
|
+
* const eventTypes = await sso.organizations.webhooks.getEventTypes('acme-corp');
|
|
1117
|
+
*
|
|
1118
|
+
* // Group events by category for UI display
|
|
1119
|
+
* const byCategory = eventTypes.reduce((acc, event) => {
|
|
1120
|
+
* if (!acc[event.category]) {
|
|
1121
|
+
* acc[event.category] = [];
|
|
1122
|
+
* }
|
|
1123
|
+
* acc[event.category].push(event);
|
|
1124
|
+
* return acc;
|
|
1125
|
+
* }, {});
|
|
1126
|
+
*
|
|
1127
|
+
* // Display available events
|
|
1128
|
+
* Object.entries(byCategory).forEach(([category, events]) => {
|
|
1129
|
+
* console.log(`\n${category}:`);
|
|
1130
|
+
* events.forEach(e => console.log(` - ${e.label} (${e.value})`));
|
|
1131
|
+
* });
|
|
1132
|
+
* ```
|
|
1133
|
+
*/
|
|
1134
|
+
async getEventTypes(orgSlug) {
|
|
1135
|
+
const response = await this.http.get(
|
|
1136
|
+
`/api/organizations/${orgSlug}/webhooks/event-types`
|
|
1137
|
+
);
|
|
1138
|
+
return response.data;
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
// src/modules/organizations.ts
|
|
1143
|
+
var OrganizationsModule = class {
|
|
1144
|
+
constructor(http) {
|
|
1145
|
+
this.http = http;
|
|
1146
|
+
/**
|
|
1147
|
+
* Member management methods
|
|
1148
|
+
*/
|
|
1149
|
+
this.members = {
|
|
1150
|
+
/**
|
|
1151
|
+
* List all members of an organization.
|
|
1152
|
+
*
|
|
1153
|
+
* @param orgSlug Organization slug
|
|
1154
|
+
* @returns Member list response with pagination metadata
|
|
1155
|
+
*
|
|
1156
|
+
* @example
|
|
1157
|
+
* ```typescript
|
|
1158
|
+
* const result = await sso.organizations.members.list('acme-corp');
|
|
1159
|
+
* console.log(`Total members: ${result.total}`);
|
|
1160
|
+
* result.members.forEach(m => console.log(m.email, m.role));
|
|
1161
|
+
* ```
|
|
1162
|
+
*/
|
|
1163
|
+
list: async (orgSlug) => {
|
|
1164
|
+
const response = await this.http.get(
|
|
1165
|
+
`/api/organizations/${orgSlug}/members`
|
|
1166
|
+
);
|
|
1167
|
+
return response.data;
|
|
1168
|
+
},
|
|
1169
|
+
/**
|
|
1170
|
+
* Update a member's role.
|
|
1171
|
+
* Requires 'owner' role.
|
|
1172
|
+
*
|
|
1173
|
+
* @param orgSlug Organization slug
|
|
1174
|
+
* @param userId User ID to update
|
|
1175
|
+
* @param payload Role update payload
|
|
1176
|
+
* @returns Updated member details
|
|
1177
|
+
*
|
|
1178
|
+
* @example
|
|
1179
|
+
* ```typescript
|
|
1180
|
+
* await sso.organizations.members.updateRole('acme-corp', 'user-id', {
|
|
1181
|
+
* role: 'admin'
|
|
1182
|
+
* });
|
|
1183
|
+
* ```
|
|
1184
|
+
*/
|
|
1185
|
+
updateRole: async (orgSlug, userId, payload) => {
|
|
1186
|
+
const response = await this.http.patch(
|
|
1187
|
+
`/api/organizations/${orgSlug}/members/${userId}`,
|
|
1188
|
+
payload
|
|
1189
|
+
);
|
|
1190
|
+
return response.data;
|
|
1191
|
+
},
|
|
1192
|
+
/**
|
|
1193
|
+
* Remove a member from the organization.
|
|
1194
|
+
* Requires 'owner' or 'admin' role.
|
|
1195
|
+
*
|
|
1196
|
+
* @param orgSlug Organization slug
|
|
1197
|
+
* @param userId User ID to remove
|
|
1198
|
+
*
|
|
1199
|
+
* @example
|
|
1200
|
+
* ```typescript
|
|
1201
|
+
* await sso.organizations.members.remove('acme-corp', 'user-id');
|
|
1202
|
+
* ```
|
|
1203
|
+
*/
|
|
1204
|
+
remove: async (orgSlug, userId) => {
|
|
1205
|
+
await this.http.post(`/api/organizations/${orgSlug}/members/${userId}`);
|
|
1206
|
+
},
|
|
1207
|
+
/**
|
|
1208
|
+
* Transfer organization ownership to another member.
|
|
1209
|
+
* Requires 'owner' role.
|
|
1210
|
+
*
|
|
1211
|
+
* @param orgSlug Organization slug
|
|
1212
|
+
* @param payload Transfer payload with new owner ID
|
|
1213
|
+
*
|
|
1214
|
+
* @example
|
|
1215
|
+
* ```typescript
|
|
1216
|
+
* await sso.organizations.members.transferOwnership('acme-corp', {
|
|
1217
|
+
* new_owner_user_id: 'new-owner-id'
|
|
1218
|
+
* });
|
|
1219
|
+
* ```
|
|
1220
|
+
*/
|
|
1221
|
+
transferOwnership: async (orgSlug, payload) => {
|
|
1222
|
+
await this.http.post(`/api/organizations/${orgSlug}/members/transfer-ownership`, payload);
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
/**
|
|
1226
|
+
* End-user management methods
|
|
1227
|
+
* Manage organization's customers (end-users with subscriptions)
|
|
1228
|
+
*/
|
|
1229
|
+
this.endUsers = {
|
|
1230
|
+
/**
|
|
1231
|
+
* List all end-users for an organization.
|
|
1232
|
+
* Returns users who have identities (logged in) or subscriptions for the organization's services.
|
|
1233
|
+
*
|
|
1234
|
+
* @param orgSlug Organization slug
|
|
1235
|
+
* @param params Optional query parameters for pagination and filtering
|
|
1236
|
+
* @param params.service_slug Optional service slug to filter users by a specific service
|
|
1237
|
+
* @returns Paginated list of end-users with their subscriptions and identities
|
|
1238
|
+
*
|
|
1239
|
+
* @example
|
|
1240
|
+
* ```typescript
|
|
1241
|
+
* // List all end-users across all services
|
|
1242
|
+
* const allUsers = await sso.organizations.endUsers.list('acme-corp', {
|
|
1243
|
+
* page: 1,
|
|
1244
|
+
* limit: 20
|
|
1245
|
+
* });
|
|
1246
|
+
*
|
|
1247
|
+
* // Filter by specific service
|
|
1248
|
+
* const serviceUsers = await sso.organizations.endUsers.list('acme-corp', {
|
|
1249
|
+
* service_slug: 'my-app',
|
|
1250
|
+
* page: 1,
|
|
1251
|
+
* limit: 20
|
|
1252
|
+
* });
|
|
1253
|
+
* console.log(`Total end-users: ${allUsers.total}`);
|
|
1254
|
+
* ```
|
|
1255
|
+
*/
|
|
1256
|
+
list: async (orgSlug, params) => {
|
|
1257
|
+
const response = await this.http.get(
|
|
1258
|
+
`/api/organizations/${orgSlug}/users`,
|
|
1259
|
+
{ params }
|
|
1260
|
+
);
|
|
1261
|
+
return response.data;
|
|
1262
|
+
},
|
|
1263
|
+
/**
|
|
1264
|
+
* Get detailed information about a specific end-user.
|
|
1265
|
+
*
|
|
1266
|
+
* @param orgSlug Organization slug
|
|
1267
|
+
* @param userId User ID
|
|
1268
|
+
* @returns End-user details with subscriptions, identities, and session count
|
|
1269
|
+
*
|
|
1270
|
+
* @example
|
|
1271
|
+
* ```typescript
|
|
1272
|
+
* const endUser = await sso.organizations.endUsers.get('acme-corp', 'user-id');
|
|
1273
|
+
* console.log(`Active sessions: ${endUser.session_count}`);
|
|
1274
|
+
* ```
|
|
1275
|
+
*/
|
|
1276
|
+
get: async (orgSlug, userId) => {
|
|
1277
|
+
const response = await this.http.get(
|
|
1278
|
+
`/api/organizations/${orgSlug}/users/${userId}`
|
|
1279
|
+
);
|
|
1280
|
+
return response.data;
|
|
1281
|
+
},
|
|
1282
|
+
/**
|
|
1283
|
+
* Revoke all active sessions for an end-user.
|
|
1284
|
+
* Requires admin or owner role.
|
|
1285
|
+
* This will force the user to re-authenticate.
|
|
1286
|
+
*
|
|
1287
|
+
* @param orgSlug Organization slug
|
|
1288
|
+
* @param userId User ID
|
|
1289
|
+
* @returns Response with number of revoked sessions
|
|
1290
|
+
*
|
|
1291
|
+
* @example
|
|
1292
|
+
* ```typescript
|
|
1293
|
+
* const result = await sso.organizations.endUsers.revokeSessions('acme-corp', 'user-id');
|
|
1294
|
+
* console.log(`Revoked ${result.revoked_count} sessions`);
|
|
1295
|
+
* ```
|
|
1296
|
+
*/
|
|
1297
|
+
revokeSessions: async (orgSlug, userId) => {
|
|
1298
|
+
const response = await this.http.delete(
|
|
1299
|
+
`/api/organizations/${orgSlug}/users/${userId}/sessions`
|
|
1300
|
+
);
|
|
1301
|
+
return response.data;
|
|
1302
|
+
}
|
|
1303
|
+
};
|
|
1304
|
+
/**
|
|
1305
|
+
* BYOO (Bring Your Own OAuth) credential management
|
|
1306
|
+
*/
|
|
1307
|
+
this.oauthCredentials = {
|
|
1308
|
+
/**
|
|
1309
|
+
* Set or update custom OAuth credentials for a provider.
|
|
1310
|
+
* This enables white-labeled authentication using the organization's
|
|
1311
|
+
* own OAuth application.
|
|
1312
|
+
* Requires 'owner' or 'admin' role.
|
|
1313
|
+
*
|
|
1314
|
+
* @param orgSlug Organization slug
|
|
1315
|
+
* @param provider OAuth provider
|
|
1316
|
+
* @param payload OAuth credentials
|
|
1317
|
+
* @returns Created/updated credentials (without secret)
|
|
1318
|
+
*
|
|
1319
|
+
* @example
|
|
1320
|
+
* ```typescript
|
|
1321
|
+
* await sso.organizations.oauthCredentials.set('acme-corp', 'github', {
|
|
1322
|
+
* client_id: 'Iv1.abc123',
|
|
1323
|
+
* client_secret: 'secret-value'
|
|
1324
|
+
* });
|
|
1325
|
+
* ```
|
|
1326
|
+
*/
|
|
1327
|
+
set: async (orgSlug, provider, payload) => {
|
|
1328
|
+
const response = await this.http.post(
|
|
1329
|
+
`/api/organizations/${orgSlug}/oauth-credentials/${provider}`,
|
|
1330
|
+
payload
|
|
1331
|
+
);
|
|
1332
|
+
return response.data;
|
|
1333
|
+
},
|
|
1334
|
+
/**
|
|
1335
|
+
* Get the configured OAuth credentials for a provider.
|
|
1336
|
+
* The secret is never returned.
|
|
1337
|
+
*
|
|
1338
|
+
* @param orgSlug Organization slug
|
|
1339
|
+
* @param provider OAuth provider
|
|
1340
|
+
* @returns OAuth credentials (without secret)
|
|
1341
|
+
*
|
|
1342
|
+
* @example
|
|
1343
|
+
* ```typescript
|
|
1344
|
+
* const creds = await sso.organizations.oauthCredentials.get('acme-corp', 'github');
|
|
1345
|
+
* console.log(creds.client_id);
|
|
1346
|
+
* ```
|
|
1347
|
+
*/
|
|
1348
|
+
get: async (orgSlug, provider) => {
|
|
1349
|
+
const response = await this.http.get(
|
|
1350
|
+
`/api/organizations/${orgSlug}/oauth-credentials/${provider}`
|
|
1351
|
+
);
|
|
1352
|
+
return response.data;
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
this.auditLogs = new AuditLogsModule(http);
|
|
1356
|
+
this.webhooks = new WebhooksModule(http);
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Create a new organization (public endpoint).
|
|
1360
|
+
* The organization will be created with 'pending' status and requires
|
|
1361
|
+
* platform owner approval before becoming active.
|
|
1362
|
+
*
|
|
1363
|
+
* @param payload Organization creation payload
|
|
1364
|
+
* @returns Created organization with owner and membership details
|
|
1365
|
+
*
|
|
1366
|
+
* @example
|
|
1367
|
+
* ```typescript
|
|
1368
|
+
* const result = await sso.organizations.createPublic({
|
|
1369
|
+
* slug: 'acme-corp',
|
|
1370
|
+
* name: 'Acme Corporation',
|
|
1371
|
+
* owner_email: 'founder@acme.com'
|
|
1372
|
+
* });
|
|
1373
|
+
* ```
|
|
1374
|
+
*/
|
|
1375
|
+
async createPublic(payload) {
|
|
1376
|
+
const response = await this.http.post("/api/organizations", payload);
|
|
1377
|
+
return response.data;
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* List all organizations the authenticated user is a member of.
|
|
1381
|
+
*
|
|
1382
|
+
* @param params Optional query parameters for filtering and pagination
|
|
1383
|
+
* @returns Array of organization responses
|
|
1384
|
+
*
|
|
1385
|
+
* @example
|
|
1386
|
+
* ```typescript
|
|
1387
|
+
* const orgs = await sso.organizations.list({
|
|
1388
|
+
* status: 'active',
|
|
1389
|
+
* page: 1,
|
|
1390
|
+
* limit: 20
|
|
1391
|
+
* });
|
|
1392
|
+
* ```
|
|
1393
|
+
*/
|
|
1394
|
+
async list(params) {
|
|
1395
|
+
const response = await this.http.get("/api/organizations", { params });
|
|
1396
|
+
return response.data;
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Get detailed information for a specific organization.
|
|
1400
|
+
*
|
|
1401
|
+
* @param orgSlug Organization slug
|
|
1402
|
+
* @returns Organization details
|
|
1403
|
+
*
|
|
1404
|
+
* @example
|
|
1405
|
+
* ```typescript
|
|
1406
|
+
* const org = await sso.organizations.get('acme-corp');
|
|
1407
|
+
* console.log(org.organization.name, org.membership_count);
|
|
1408
|
+
* ```
|
|
1409
|
+
*/
|
|
1410
|
+
async get(orgSlug) {
|
|
1411
|
+
const response = await this.http.get(`/api/organizations/${orgSlug}`);
|
|
1412
|
+
return response.data;
|
|
1413
|
+
}
|
|
1414
|
+
/**
|
|
1415
|
+
* Update organization details.
|
|
1416
|
+
* Requires 'owner' or 'admin' role.
|
|
1417
|
+
*
|
|
1418
|
+
* @param orgSlug Organization slug
|
|
1419
|
+
* @param payload Update payload
|
|
1420
|
+
* @returns Updated organization details
|
|
1421
|
+
*
|
|
1422
|
+
* @example
|
|
1423
|
+
* ```typescript
|
|
1424
|
+
* const updated = await sso.organizations.update('acme-corp', {
|
|
1425
|
+
* name: 'Acme Corporation Inc.',
|
|
1426
|
+
* max_services: 20
|
|
1427
|
+
* });
|
|
1428
|
+
* ```
|
|
1429
|
+
*/
|
|
1430
|
+
async update(orgSlug, payload) {
|
|
1431
|
+
const response = await this.http.patch(
|
|
1432
|
+
`/api/organizations/${orgSlug}`,
|
|
1433
|
+
payload
|
|
1434
|
+
);
|
|
1435
|
+
return response.data;
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Delete an organization and all its associated data.
|
|
1439
|
+
* This is a destructive operation that cannot be undone.
|
|
1440
|
+
* Requires 'owner' role.
|
|
1441
|
+
*
|
|
1442
|
+
* All related data will be cascaded deleted including:
|
|
1443
|
+
* - Members and invitations
|
|
1444
|
+
* - Services and plans
|
|
1445
|
+
* - Subscriptions
|
|
1446
|
+
* - OAuth credentials
|
|
1447
|
+
* - Audit logs
|
|
1448
|
+
*
|
|
1449
|
+
* @param orgSlug Organization slug
|
|
1450
|
+
*
|
|
1451
|
+
* @example
|
|
1452
|
+
* ```typescript
|
|
1453
|
+
* await sso.organizations.delete('acme-corp');
|
|
1454
|
+
* ```
|
|
1455
|
+
*/
|
|
1456
|
+
async delete(orgSlug) {
|
|
1457
|
+
await this.http.delete(`/api/organizations/${orgSlug}`);
|
|
1458
|
+
}
|
|
1459
|
+
// ============================================================================
|
|
1460
|
+
// SMTP MANAGEMENT
|
|
1461
|
+
// ============================================================================
|
|
1462
|
+
/**
|
|
1463
|
+
* Configure SMTP settings for an organization.
|
|
1464
|
+
* Only owners and admins can configure SMTP.
|
|
1465
|
+
* The organization will use these settings for sending transactional emails
|
|
1466
|
+
* (registration, password reset, etc.).
|
|
1467
|
+
*
|
|
1468
|
+
* @param orgSlug Organization slug
|
|
1469
|
+
* @param config SMTP configuration
|
|
1470
|
+
* @returns Success message
|
|
1471
|
+
*
|
|
1472
|
+
* @example
|
|
1473
|
+
* ```typescript
|
|
1474
|
+
* await sso.organizations.setSmtp('acme-corp', {
|
|
1475
|
+
* host: 'smtp.gmail.com',
|
|
1476
|
+
* port: 587,
|
|
1477
|
+
* username: 'notifications@acme.com',
|
|
1478
|
+
* password: 'your-app-password',
|
|
1479
|
+
* from_email: 'notifications@acme.com',
|
|
1480
|
+
* from_name: 'Acme Corp'
|
|
1481
|
+
* });
|
|
1482
|
+
* ```
|
|
1483
|
+
*/
|
|
1484
|
+
async setSmtp(orgSlug, config) {
|
|
1485
|
+
const response = await this.http.post(
|
|
1486
|
+
`/api/organizations/${orgSlug}/smtp`,
|
|
1487
|
+
config
|
|
1488
|
+
);
|
|
1489
|
+
return response.data;
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Get SMTP configuration for an organization.
|
|
1493
|
+
* Only owners and admins can view SMTP settings.
|
|
1494
|
+
* Password is never returned for security reasons.
|
|
1495
|
+
*
|
|
1496
|
+
* @param orgSlug Organization slug
|
|
1497
|
+
* @returns SMTP configuration (without password)
|
|
1498
|
+
*
|
|
1499
|
+
* @example
|
|
1500
|
+
* ```typescript
|
|
1501
|
+
* const config = await sso.organizations.getSmtp('acme-corp');
|
|
1502
|
+
* if (config.configured) {
|
|
1503
|
+
* console.log('SMTP host:', config.host);
|
|
1504
|
+
* }
|
|
1505
|
+
* ```
|
|
1506
|
+
*/
|
|
1507
|
+
async getSmtp(orgSlug) {
|
|
1508
|
+
const response = await this.http.get(
|
|
1509
|
+
`/api/organizations/${orgSlug}/smtp`
|
|
1510
|
+
);
|
|
1511
|
+
return response.data;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Delete SMTP configuration for an organization.
|
|
1515
|
+
* The organization will revert to using platform-level SMTP.
|
|
1516
|
+
* Only owners and admins can delete SMTP settings.
|
|
537
1517
|
*
|
|
538
|
-
* @
|
|
1518
|
+
* @param orgSlug Organization slug
|
|
1519
|
+
* @returns Success message
|
|
539
1520
|
*
|
|
540
1521
|
* @example
|
|
541
1522
|
* ```typescript
|
|
542
|
-
*
|
|
543
|
-
*
|
|
1523
|
+
* await sso.organizations.deleteSmtp('acme-corp');
|
|
1524
|
+
* // Organization now uses platform SMTP
|
|
544
1525
|
* ```
|
|
545
1526
|
*/
|
|
546
|
-
async
|
|
547
|
-
const response = await this.http.
|
|
1527
|
+
async deleteSmtp(orgSlug) {
|
|
1528
|
+
const response = await this.http.delete(
|
|
1529
|
+
`/api/organizations/${orgSlug}/smtp`
|
|
1530
|
+
);
|
|
548
1531
|
return response.data;
|
|
549
1532
|
}
|
|
1533
|
+
// ============================================================================
|
|
1534
|
+
// CUSTOM DOMAINS & BRANDING
|
|
1535
|
+
// ============================================================================
|
|
550
1536
|
/**
|
|
551
|
-
*
|
|
552
|
-
*
|
|
1537
|
+
* Set a custom domain for an organization.
|
|
1538
|
+
* This enables white-labeling by allowing the organization to use their own domain
|
|
1539
|
+
* (e.g., auth.acme.com) instead of the platform's domain.
|
|
1540
|
+
* Requires 'owner' or 'admin' role.
|
|
553
1541
|
*
|
|
554
|
-
* @param
|
|
555
|
-
* @
|
|
1542
|
+
* @param orgSlug Organization slug
|
|
1543
|
+
* @param request Custom domain request
|
|
1544
|
+
* @returns Domain verification instructions
|
|
556
1545
|
*
|
|
557
1546
|
* @example
|
|
558
1547
|
* ```typescript
|
|
559
|
-
* const
|
|
560
|
-
*
|
|
1548
|
+
* const verification = await sso.organizations.setCustomDomain('acme-corp', {
|
|
1549
|
+
* domain: 'auth.acme.com'
|
|
1550
|
+
* });
|
|
1551
|
+
* console.log('Verification token:', verification.verification_token);
|
|
1552
|
+
* verification.verification_methods.forEach(method => {
|
|
1553
|
+
* console.log(method.method, method.instructions);
|
|
1554
|
+
* });
|
|
561
1555
|
* ```
|
|
562
1556
|
*/
|
|
563
|
-
async
|
|
564
|
-
const response = await this.http.post(
|
|
1557
|
+
async setCustomDomain(orgSlug, request) {
|
|
1558
|
+
const response = await this.http.post(
|
|
1559
|
+
`/api/organizations/${orgSlug}/domain`,
|
|
1560
|
+
request
|
|
1561
|
+
);
|
|
565
1562
|
return response.data;
|
|
566
1563
|
}
|
|
567
1564
|
/**
|
|
568
|
-
*
|
|
569
|
-
*
|
|
1565
|
+
* Verify a custom domain by checking DNS TXT record or HTTP file.
|
|
1566
|
+
* Requires 'owner' or 'admin' role.
|
|
570
1567
|
*
|
|
571
|
-
* @param
|
|
1568
|
+
* @param orgSlug Organization slug
|
|
1569
|
+
* @returns Verification result
|
|
572
1570
|
*
|
|
573
1571
|
* @example
|
|
574
1572
|
* ```typescript
|
|
575
|
-
* await sso.
|
|
1573
|
+
* const result = await sso.organizations.verifyCustomDomain('acme-corp');
|
|
1574
|
+
* if (result.verified) {
|
|
1575
|
+
* console.log('Domain verified successfully!');
|
|
1576
|
+
* } else {
|
|
1577
|
+
* console.log('Verification failed:', result.message);
|
|
1578
|
+
* }
|
|
576
1579
|
* ```
|
|
577
1580
|
*/
|
|
578
|
-
async
|
|
579
|
-
await this.http.
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
constructor(http) {
|
|
584
|
-
this.http = http;
|
|
585
|
-
this.identities = new IdentitiesModule(http);
|
|
1581
|
+
async verifyCustomDomain(orgSlug) {
|
|
1582
|
+
const response = await this.http.post(
|
|
1583
|
+
`/api/organizations/${orgSlug}/domain/verify`
|
|
1584
|
+
);
|
|
1585
|
+
return response.data;
|
|
586
1586
|
}
|
|
587
1587
|
/**
|
|
588
|
-
* Get
|
|
589
|
-
* The response includes context from the JWT (org, service).
|
|
1588
|
+
* Get custom domain configuration for an organization.
|
|
590
1589
|
*
|
|
591
|
-
* @
|
|
1590
|
+
* @param orgSlug Organization slug
|
|
1591
|
+
* @returns Domain configuration
|
|
592
1592
|
*
|
|
593
1593
|
* @example
|
|
594
1594
|
* ```typescript
|
|
595
|
-
* const
|
|
596
|
-
*
|
|
1595
|
+
* const config = await sso.organizations.getDomainConfiguration('acme-corp');
|
|
1596
|
+
* if (config.custom_domain && config.domain_verified) {
|
|
1597
|
+
* console.log('Custom domain active:', config.custom_domain);
|
|
1598
|
+
* }
|
|
597
1599
|
* ```
|
|
598
1600
|
*/
|
|
599
|
-
async
|
|
600
|
-
const response = await this.http.get(
|
|
1601
|
+
async getDomainConfiguration(orgSlug) {
|
|
1602
|
+
const response = await this.http.get(
|
|
1603
|
+
`/api/organizations/${orgSlug}/domain`
|
|
1604
|
+
);
|
|
601
1605
|
return response.data;
|
|
602
1606
|
}
|
|
603
1607
|
/**
|
|
604
|
-
*
|
|
1608
|
+
* Delete custom domain configuration.
|
|
1609
|
+
* Requires 'owner' or 'admin' role.
|
|
605
1610
|
*
|
|
606
|
-
* @param
|
|
607
|
-
* @returns Updated user profile
|
|
1611
|
+
* @param orgSlug Organization slug
|
|
608
1612
|
*
|
|
609
1613
|
* @example
|
|
610
1614
|
* ```typescript
|
|
611
|
-
*
|
|
612
|
-
*
|
|
1615
|
+
* await sso.organizations.deleteCustomDomain('acme-corp');
|
|
1616
|
+
* // Organization reverts to using platform domain
|
|
1617
|
+
* ```
|
|
1618
|
+
*/
|
|
1619
|
+
async deleteCustomDomain(orgSlug) {
|
|
1620
|
+
await this.http.delete(`/api/organizations/${orgSlug}/domain`);
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* Update branding configuration (logo and primary color).
|
|
1624
|
+
* This controls the visual appearance of authentication pages.
|
|
1625
|
+
* Requires 'owner' or 'admin' role.
|
|
1626
|
+
*
|
|
1627
|
+
* @param orgSlug Organization slug
|
|
1628
|
+
* @param request Branding configuration
|
|
1629
|
+
* @returns Updated branding configuration
|
|
1630
|
+
*
|
|
1631
|
+
* @example
|
|
1632
|
+
* ```typescript
|
|
1633
|
+
* await sso.organizations.updateBranding('acme-corp', {
|
|
1634
|
+
* logo_url: 'https://cdn.acme.com/logo.png',
|
|
1635
|
+
* primary_color: '#FF5733'
|
|
613
1636
|
* });
|
|
614
1637
|
* ```
|
|
615
1638
|
*/
|
|
616
|
-
async
|
|
617
|
-
const response = await this.http.patch(
|
|
1639
|
+
async updateBranding(orgSlug, request) {
|
|
1640
|
+
const response = await this.http.patch(
|
|
1641
|
+
`/api/organizations/${orgSlug}/branding`,
|
|
1642
|
+
request
|
|
1643
|
+
);
|
|
618
1644
|
return response.data;
|
|
619
1645
|
}
|
|
620
1646
|
/**
|
|
621
|
-
* Get
|
|
1647
|
+
* Get branding configuration for an organization.
|
|
622
1648
|
*
|
|
623
|
-
* @
|
|
1649
|
+
* @param orgSlug Organization slug
|
|
1650
|
+
* @returns Branding configuration
|
|
624
1651
|
*
|
|
625
1652
|
* @example
|
|
626
1653
|
* ```typescript
|
|
627
|
-
* const
|
|
628
|
-
*
|
|
1654
|
+
* const branding = await sso.organizations.getBranding('acme-corp');
|
|
1655
|
+
* if (branding.logo_url) {
|
|
1656
|
+
* console.log('Logo URL:', branding.logo_url);
|
|
1657
|
+
* }
|
|
629
1658
|
* ```
|
|
630
1659
|
*/
|
|
631
|
-
async
|
|
632
|
-
const response = await this.http.get(
|
|
1660
|
+
async getBranding(orgSlug) {
|
|
1661
|
+
const response = await this.http.get(
|
|
1662
|
+
`/api/organizations/${orgSlug}/branding`
|
|
1663
|
+
);
|
|
1664
|
+
return response.data;
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Get public branding configuration (no authentication required).
|
|
1668
|
+
* This endpoint is used by login pages to display organization branding.
|
|
1669
|
+
*
|
|
1670
|
+
* @param orgSlug Organization slug
|
|
1671
|
+
* @returns Branding configuration
|
|
1672
|
+
*
|
|
1673
|
+
* @example
|
|
1674
|
+
* ```typescript
|
|
1675
|
+
* // Can be called without authentication
|
|
1676
|
+
* const branding = await sso.organizations.getPublicBranding('acme-corp');
|
|
1677
|
+
* ```
|
|
1678
|
+
*/
|
|
1679
|
+
async getPublicBranding(orgSlug) {
|
|
1680
|
+
const response = await this.http.get(
|
|
1681
|
+
`/api/organizations/${orgSlug}/branding/public`
|
|
1682
|
+
);
|
|
633
1683
|
return response.data;
|
|
634
1684
|
}
|
|
635
1685
|
};
|
|
636
1686
|
|
|
637
|
-
// src/modules/
|
|
638
|
-
var
|
|
1687
|
+
// src/modules/services.ts
|
|
1688
|
+
var ServicesModule = class {
|
|
639
1689
|
constructor(http) {
|
|
640
1690
|
this.http = http;
|
|
641
1691
|
/**
|
|
642
|
-
*
|
|
1692
|
+
* Plan management methods
|
|
643
1693
|
*/
|
|
644
|
-
this.
|
|
1694
|
+
this.plans = {
|
|
645
1695
|
/**
|
|
646
|
-
*
|
|
1696
|
+
* Create a new subscription plan for a service.
|
|
1697
|
+
* Requires 'owner' or 'admin' role.
|
|
647
1698
|
*
|
|
648
1699
|
* @param orgSlug Organization slug
|
|
649
|
-
* @
|
|
1700
|
+
* @param serviceSlug Service slug
|
|
1701
|
+
* @param payload Plan creation payload
|
|
1702
|
+
* @returns Created plan with subscription count
|
|
650
1703
|
*
|
|
651
1704
|
* @example
|
|
652
1705
|
* ```typescript
|
|
653
|
-
* const result = await sso.
|
|
654
|
-
*
|
|
655
|
-
*
|
|
1706
|
+
* const result = await sso.services.plans.create('acme-corp', 'main-app', {
|
|
1707
|
+
* name: 'pro',
|
|
1708
|
+
* price_cents: 2999,
|
|
1709
|
+
* currency: 'usd',
|
|
1710
|
+
* features: ['api-access', 'advanced-analytics', 'priority-support']
|
|
1711
|
+
* });
|
|
1712
|
+
* console.log(result.plan.name, result.subscription_count);
|
|
656
1713
|
* ```
|
|
657
1714
|
*/
|
|
658
|
-
|
|
1715
|
+
create: async (orgSlug, serviceSlug, payload) => {
|
|
1716
|
+
const response = await this.http.post(
|
|
1717
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans`,
|
|
1718
|
+
payload
|
|
1719
|
+
);
|
|
1720
|
+
return response.data;
|
|
1721
|
+
},
|
|
1722
|
+
/**
|
|
1723
|
+
* List all plans for a service.
|
|
1724
|
+
*
|
|
1725
|
+
* @param orgSlug Organization slug
|
|
1726
|
+
* @param serviceSlug Service slug
|
|
1727
|
+
* @returns Array of plans with subscription counts
|
|
1728
|
+
*
|
|
1729
|
+
* @example
|
|
1730
|
+
* ```typescript
|
|
1731
|
+
* const plans = await sso.services.plans.list('acme-corp', 'main-app');
|
|
1732
|
+
* plans.forEach(p => console.log(p.plan.name, p.subscription_count));
|
|
1733
|
+
* ```
|
|
1734
|
+
*/
|
|
1735
|
+
list: async (orgSlug, serviceSlug) => {
|
|
659
1736
|
const response = await this.http.get(
|
|
660
|
-
`/api/organizations/${orgSlug}/
|
|
1737
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans`
|
|
661
1738
|
);
|
|
662
1739
|
return response.data;
|
|
663
1740
|
},
|
|
664
1741
|
/**
|
|
665
|
-
* Update a
|
|
666
|
-
* Requires 'owner' role.
|
|
1742
|
+
* Update a subscription plan.
|
|
1743
|
+
* Requires 'owner' or 'admin' role.
|
|
667
1744
|
*
|
|
668
1745
|
* @param orgSlug Organization slug
|
|
669
|
-
* @param
|
|
670
|
-
* @param
|
|
671
|
-
* @
|
|
1746
|
+
* @param serviceSlug Service slug
|
|
1747
|
+
* @param planId Plan ID
|
|
1748
|
+
* @param payload Plan update payload
|
|
1749
|
+
* @returns Updated plan with subscription count
|
|
672
1750
|
*
|
|
673
1751
|
* @example
|
|
674
1752
|
* ```typescript
|
|
675
|
-
* await sso.
|
|
676
|
-
*
|
|
1753
|
+
* const result = await sso.services.plans.update('acme-corp', 'main-app', 'plan_123', {
|
|
1754
|
+
* name: 'Pro Plus',
|
|
1755
|
+
* price_cents: 3999,
|
|
1756
|
+
* currency: 'usd',
|
|
1757
|
+
* features: ['api-access', 'advanced-analytics', 'priority-support', 'custom-integrations']
|
|
677
1758
|
* });
|
|
1759
|
+
* console.log('Updated plan:', result.plan.name);
|
|
678
1760
|
* ```
|
|
679
1761
|
*/
|
|
680
|
-
|
|
1762
|
+
update: async (orgSlug, serviceSlug, planId, payload) => {
|
|
681
1763
|
const response = await this.http.patch(
|
|
682
|
-
`/api/organizations/${orgSlug}/
|
|
1764
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans/${planId}`,
|
|
683
1765
|
payload
|
|
684
1766
|
);
|
|
685
1767
|
return response.data;
|
|
686
1768
|
},
|
|
687
1769
|
/**
|
|
688
|
-
*
|
|
1770
|
+
* Delete a subscription plan.
|
|
689
1771
|
* Requires 'owner' or 'admin' role.
|
|
690
1772
|
*
|
|
1773
|
+
* WARNING: This will fail if the plan has active subscriptions.
|
|
1774
|
+
* You must migrate or cancel all subscriptions before deleting a plan.
|
|
1775
|
+
*
|
|
691
1776
|
* @param orgSlug Organization slug
|
|
692
|
-
* @param
|
|
1777
|
+
* @param serviceSlug Service slug
|
|
1778
|
+
* @param planId Plan ID
|
|
693
1779
|
*
|
|
694
1780
|
* @example
|
|
695
1781
|
* ```typescript
|
|
696
|
-
*
|
|
1782
|
+
* try {
|
|
1783
|
+
* await sso.services.plans.delete('acme-corp', 'main-app', 'plan_123');
|
|
1784
|
+
* console.log('Plan deleted successfully');
|
|
1785
|
+
* } catch (error) {
|
|
1786
|
+
* console.error('Cannot delete plan with active subscriptions');
|
|
1787
|
+
* }
|
|
697
1788
|
* ```
|
|
698
1789
|
*/
|
|
699
|
-
|
|
700
|
-
await this.http.
|
|
1790
|
+
delete: async (orgSlug, serviceSlug, planId) => {
|
|
1791
|
+
await this.http.delete(
|
|
1792
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans/${planId}`
|
|
1793
|
+
);
|
|
1794
|
+
}
|
|
1795
|
+
};
|
|
1796
|
+
/**
|
|
1797
|
+
* API Key management methods for service-to-service authentication
|
|
1798
|
+
*/
|
|
1799
|
+
this.apiKeys = {
|
|
1800
|
+
/**
|
|
1801
|
+
* Create a new API key for a service.
|
|
1802
|
+
* Requires 'owner' or 'admin' role.
|
|
1803
|
+
*
|
|
1804
|
+
* IMPORTANT: The full API key is only returned once upon creation.
|
|
1805
|
+
* Store it securely as it cannot be retrieved again.
|
|
1806
|
+
*
|
|
1807
|
+
* @param orgSlug Organization slug
|
|
1808
|
+
* @param serviceSlug Service slug
|
|
1809
|
+
* @param payload API key creation payload
|
|
1810
|
+
* @returns Created API key with the full key value
|
|
1811
|
+
*
|
|
1812
|
+
* @example
|
|
1813
|
+
* ```typescript
|
|
1814
|
+
* const apiKey = await sso.services.apiKeys.create('acme-corp', 'main-app', {
|
|
1815
|
+
* name: 'Production Backend',
|
|
1816
|
+
* permissions: ['read:users', 'write:subscriptions'],
|
|
1817
|
+
* expires_in_days: 90
|
|
1818
|
+
* });
|
|
1819
|
+
*
|
|
1820
|
+
* // IMPORTANT: Store this key securely - it won't be shown again
|
|
1821
|
+
* console.log('API Key:', apiKey.key);
|
|
1822
|
+
* console.log('Prefix:', apiKey.prefix);
|
|
1823
|
+
* ```
|
|
1824
|
+
*/
|
|
1825
|
+
create: async (orgSlug, serviceSlug, payload) => {
|
|
1826
|
+
const response = await this.http.post(
|
|
1827
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/api-keys`,
|
|
1828
|
+
payload
|
|
1829
|
+
);
|
|
1830
|
+
return response.data;
|
|
701
1831
|
},
|
|
702
1832
|
/**
|
|
703
|
-
*
|
|
704
|
-
*
|
|
1833
|
+
* List all API keys for a service.
|
|
1834
|
+
* Note: The full key values are not included in this response.
|
|
705
1835
|
*
|
|
706
1836
|
* @param orgSlug Organization slug
|
|
707
|
-
* @param
|
|
1837
|
+
* @param serviceSlug Service slug
|
|
1838
|
+
* @param options Optional query parameters for pagination
|
|
1839
|
+
* @returns List of API keys with metadata
|
|
708
1840
|
*
|
|
709
1841
|
* @example
|
|
710
1842
|
* ```typescript
|
|
711
|
-
* await sso.
|
|
712
|
-
*
|
|
1843
|
+
* const result = await sso.services.apiKeys.list('acme-corp', 'main-app', {
|
|
1844
|
+
* limit: 50,
|
|
1845
|
+
* offset: 0
|
|
1846
|
+
* });
|
|
1847
|
+
*
|
|
1848
|
+
* console.log(`Total API keys: ${result.total}`);
|
|
1849
|
+
* result.api_keys.forEach(key => {
|
|
1850
|
+
* console.log(`${key.name} (${key.prefix})`);
|
|
1851
|
+
* console.log(`Permissions: ${key.permissions.join(', ')}`);
|
|
1852
|
+
* console.log(`Last used: ${key.last_used_at || 'Never'}`);
|
|
713
1853
|
* });
|
|
714
1854
|
* ```
|
|
715
1855
|
*/
|
|
716
|
-
|
|
717
|
-
|
|
1856
|
+
list: async (orgSlug, serviceSlug, options) => {
|
|
1857
|
+
const queryParams = new URLSearchParams();
|
|
1858
|
+
if (options?.limit) queryParams.set("limit", options.limit.toString());
|
|
1859
|
+
if (options?.offset) queryParams.set("offset", options.offset.toString());
|
|
1860
|
+
const query = queryParams.toString() ? `?${queryParams.toString()}` : "";
|
|
1861
|
+
const response = await this.http.get(
|
|
1862
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/api-keys${query}`
|
|
1863
|
+
);
|
|
1864
|
+
return response.data;
|
|
1865
|
+
},
|
|
1866
|
+
/**
|
|
1867
|
+
* Get details for a specific API key.
|
|
1868
|
+
* Note: The full key value is not included in this response.
|
|
1869
|
+
*
|
|
1870
|
+
* @param orgSlug Organization slug
|
|
1871
|
+
* @param serviceSlug Service slug
|
|
1872
|
+
* @param apiKeyId API key ID
|
|
1873
|
+
* @returns API key details
|
|
1874
|
+
*
|
|
1875
|
+
* @example
|
|
1876
|
+
* ```typescript
|
|
1877
|
+
* const apiKey = await sso.services.apiKeys.get('acme-corp', 'main-app', 'key_abc123');
|
|
1878
|
+
* console.log(`Name: ${apiKey.name}`);
|
|
1879
|
+
* console.log(`Permissions: ${apiKey.permissions.join(', ')}`);
|
|
1880
|
+
* console.log(`Expires: ${apiKey.expires_at || 'Never'}`);
|
|
1881
|
+
* ```
|
|
1882
|
+
*/
|
|
1883
|
+
get: async (orgSlug, serviceSlug, apiKeyId) => {
|
|
1884
|
+
const response = await this.http.get(
|
|
1885
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/api-keys/${apiKeyId}`
|
|
1886
|
+
);
|
|
1887
|
+
return response.data;
|
|
1888
|
+
},
|
|
1889
|
+
/**
|
|
1890
|
+
* Delete an API key.
|
|
1891
|
+
* Requires 'owner' or 'admin' role.
|
|
1892
|
+
*
|
|
1893
|
+
* WARNING: This action is immediate and cannot be undone.
|
|
1894
|
+
* Any services using this key will lose access immediately.
|
|
1895
|
+
*
|
|
1896
|
+
* @param orgSlug Organization slug
|
|
1897
|
+
* @param serviceSlug Service slug
|
|
1898
|
+
* @param apiKeyId API key ID
|
|
1899
|
+
*
|
|
1900
|
+
* @example
|
|
1901
|
+
* ```typescript
|
|
1902
|
+
* await sso.services.apiKeys.delete('acme-corp', 'main-app', 'key_abc123');
|
|
1903
|
+
* console.log('API key deleted successfully');
|
|
1904
|
+
* ```
|
|
1905
|
+
*/
|
|
1906
|
+
delete: async (orgSlug, serviceSlug, apiKeyId) => {
|
|
1907
|
+
await this.http.delete(
|
|
1908
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/api-keys/${apiKeyId}`
|
|
1909
|
+
);
|
|
718
1910
|
}
|
|
719
1911
|
};
|
|
720
1912
|
/**
|
|
721
|
-
*
|
|
722
|
-
*
|
|
1913
|
+
* SAML 2.0 Identity Provider (IdP) management methods
|
|
1914
|
+
*
|
|
1915
|
+
* Configure your service as a SAML IdP to enable SSO into third-party applications
|
|
1916
|
+
* (Salesforce, AWS, Google Workspace, etc.)
|
|
723
1917
|
*/
|
|
724
|
-
this.
|
|
1918
|
+
this.saml = {
|
|
725
1919
|
/**
|
|
726
|
-
*
|
|
727
|
-
*
|
|
1920
|
+
* Configure SAML IdP settings for a service.
|
|
1921
|
+
* Requires 'owner' or 'admin' role.
|
|
728
1922
|
*
|
|
729
1923
|
* @param orgSlug Organization slug
|
|
730
|
-
* @param
|
|
731
|
-
* @param
|
|
732
|
-
* @returns
|
|
1924
|
+
* @param serviceSlug Service slug
|
|
1925
|
+
* @param payload SAML configuration payload
|
|
1926
|
+
* @returns Configuration success response
|
|
733
1927
|
*
|
|
734
1928
|
* @example
|
|
735
1929
|
* ```typescript
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
* limit: 20
|
|
1930
|
+
* const result = await sso.services.saml.configure('acme-corp', 'main-app', {
|
|
1931
|
+
* enabled: true,
|
|
1932
|
+
* entity_id: 'https://salesforce.example.com',
|
|
1933
|
+
* acs_url: 'https://salesforce.example.com/saml/acs',
|
|
1934
|
+
* name_id_format: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
|
|
1935
|
+
* attribute_mapping: {
|
|
1936
|
+
* email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'
|
|
1937
|
+
* },
|
|
1938
|
+
* sign_assertions: true,
|
|
1939
|
+
* sign_response: true
|
|
747
1940
|
* });
|
|
748
|
-
* console.log(`Total end-users: ${allUsers.total}`);
|
|
749
1941
|
* ```
|
|
750
1942
|
*/
|
|
751
|
-
|
|
752
|
-
const response = await this.http.
|
|
753
|
-
`/api/organizations/${orgSlug}/
|
|
754
|
-
|
|
1943
|
+
configure: async (orgSlug, serviceSlug, payload) => {
|
|
1944
|
+
const response = await this.http.post(
|
|
1945
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`,
|
|
1946
|
+
payload
|
|
755
1947
|
);
|
|
756
1948
|
return response.data;
|
|
757
1949
|
},
|
|
758
1950
|
/**
|
|
759
|
-
* Get
|
|
1951
|
+
* Get current SAML IdP configuration for a service.
|
|
760
1952
|
*
|
|
761
|
-
* @param orgSlug Organization slug
|
|
762
|
-
* @param
|
|
763
|
-
* @returns
|
|
1953
|
+
* @param orgSlug Organization slug
|
|
1954
|
+
* @param serviceSlug Service slug
|
|
1955
|
+
* @returns Current SAML configuration
|
|
764
1956
|
*
|
|
765
1957
|
* @example
|
|
766
1958
|
* ```typescript
|
|
767
|
-
* const
|
|
768
|
-
*
|
|
1959
|
+
* const config = await sso.services.saml.getConfig('acme-corp', 'main-app');
|
|
1960
|
+
* if (config.enabled && config.has_certificate) {
|
|
1961
|
+
* console.log('SAML IdP is ready');
|
|
1962
|
+
* console.log('Entity ID:', config.entity_id);
|
|
1963
|
+
* console.log('ACS URL:', config.acs_url);
|
|
1964
|
+
* }
|
|
769
1965
|
* ```
|
|
770
1966
|
*/
|
|
771
|
-
|
|
1967
|
+
getConfig: async (orgSlug, serviceSlug) => {
|
|
772
1968
|
const response = await this.http.get(
|
|
773
|
-
`/api/organizations/${orgSlug}/
|
|
1969
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`
|
|
774
1970
|
);
|
|
775
1971
|
return response.data;
|
|
776
1972
|
},
|
|
777
1973
|
/**
|
|
778
|
-
*
|
|
779
|
-
* Requires
|
|
780
|
-
*
|
|
1974
|
+
* Delete SAML IdP configuration and deactivate all certificates.
|
|
1975
|
+
* Requires 'owner' or 'admin' role.
|
|
1976
|
+
*
|
|
1977
|
+
* WARNING: This will break SSO for all third-party applications using this IdP.
|
|
781
1978
|
*
|
|
782
1979
|
* @param orgSlug Organization slug
|
|
783
|
-
* @param
|
|
784
|
-
* @returns Response with number of revoked sessions
|
|
1980
|
+
* @param serviceSlug Service slug
|
|
785
1981
|
*
|
|
786
1982
|
* @example
|
|
787
1983
|
* ```typescript
|
|
788
|
-
*
|
|
789
|
-
* console.log(
|
|
1984
|
+
* await sso.services.saml.deleteConfig('acme-corp', 'main-app');
|
|
1985
|
+
* console.log('SAML IdP configuration deleted');
|
|
790
1986
|
* ```
|
|
791
1987
|
*/
|
|
792
|
-
|
|
1988
|
+
deleteConfig: async (orgSlug, serviceSlug) => {
|
|
793
1989
|
const response = await this.http.delete(
|
|
794
|
-
`/api/organizations/${orgSlug}/
|
|
1990
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`
|
|
795
1991
|
);
|
|
796
1992
|
return response.data;
|
|
797
|
-
}
|
|
798
|
-
};
|
|
799
|
-
/**
|
|
800
|
-
* BYOO (Bring Your Own OAuth) credential management
|
|
801
|
-
*/
|
|
802
|
-
this.oauthCredentials = {
|
|
1993
|
+
},
|
|
803
1994
|
/**
|
|
804
|
-
*
|
|
805
|
-
* This enables white-labeled authentication using the organization's
|
|
806
|
-
* own OAuth application.
|
|
1995
|
+
* Generate a new SAML signing certificate for the IdP.
|
|
807
1996
|
* Requires 'owner' or 'admin' role.
|
|
808
1997
|
*
|
|
1998
|
+
* IMPORTANT: This automatically deactivates any existing active certificates.
|
|
1999
|
+
* Provide the returned certificate to your Service Provider during SAML setup.
|
|
2000
|
+
*
|
|
809
2001
|
* @param orgSlug Organization slug
|
|
810
|
-
* @param
|
|
811
|
-
* @
|
|
812
|
-
* @returns Created/updated credentials (without secret)
|
|
2002
|
+
* @param serviceSlug Service slug
|
|
2003
|
+
* @returns Certificate information including public key
|
|
813
2004
|
*
|
|
814
2005
|
* @example
|
|
815
2006
|
* ```typescript
|
|
816
|
-
* await sso.
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
2007
|
+
* const cert = await sso.services.saml.generateCertificate('acme-corp', 'main-app');
|
|
2008
|
+
* console.log('Certificate generated, valid until:', cert.valid_until);
|
|
2009
|
+
* console.log('Public certificate:\n', cert.public_key);
|
|
2010
|
+
* // Provide cert.public_key to your Service Provider
|
|
820
2011
|
* ```
|
|
821
2012
|
*/
|
|
822
|
-
|
|
2013
|
+
generateCertificate: async (orgSlug, serviceSlug) => {
|
|
823
2014
|
const response = await this.http.post(
|
|
824
|
-
`/api/organizations/${orgSlug}/
|
|
825
|
-
|
|
2015
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml/certificate`,
|
|
2016
|
+
{}
|
|
826
2017
|
);
|
|
827
2018
|
return response.data;
|
|
828
2019
|
},
|
|
829
2020
|
/**
|
|
830
|
-
* Get the
|
|
831
|
-
* The secret is never returned.
|
|
2021
|
+
* Get the active SAML signing certificate.
|
|
832
2022
|
*
|
|
833
2023
|
* @param orgSlug Organization slug
|
|
834
|
-
* @param
|
|
835
|
-
* @returns
|
|
2024
|
+
* @param serviceSlug Service slug
|
|
2025
|
+
* @returns Active certificate information
|
|
836
2026
|
*
|
|
837
2027
|
* @example
|
|
838
2028
|
* ```typescript
|
|
839
|
-
*
|
|
840
|
-
*
|
|
2029
|
+
* try {
|
|
2030
|
+
* const cert = await sso.services.saml.getCertificate('acme-corp', 'main-app');
|
|
2031
|
+
* console.log('Certificate expires:', cert.valid_until);
|
|
2032
|
+
* } catch (error) {
|
|
2033
|
+
* console.log('No active certificate - generate one first');
|
|
2034
|
+
* }
|
|
841
2035
|
* ```
|
|
842
2036
|
*/
|
|
843
|
-
|
|
2037
|
+
getCertificate: async (orgSlug, serviceSlug) => {
|
|
844
2038
|
const response = await this.http.get(
|
|
845
|
-
`/api/organizations/${orgSlug}/
|
|
2039
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml/certificate`
|
|
846
2040
|
);
|
|
847
2041
|
return response.data;
|
|
848
|
-
}
|
|
849
|
-
};
|
|
850
|
-
}
|
|
851
|
-
/**
|
|
852
|
-
* Create a new organization (public endpoint).
|
|
853
|
-
* The organization will be created with 'pending' status and requires
|
|
854
|
-
* platform owner approval before becoming active.
|
|
855
|
-
*
|
|
856
|
-
* @param payload Organization creation payload
|
|
857
|
-
* @returns Created organization with owner and membership details
|
|
858
|
-
*
|
|
859
|
-
* @example
|
|
860
|
-
* ```typescript
|
|
861
|
-
* const result = await sso.organizations.createPublic({
|
|
862
|
-
* slug: 'acme-corp',
|
|
863
|
-
* name: 'Acme Corporation',
|
|
864
|
-
* owner_email: 'founder@acme.com'
|
|
865
|
-
* });
|
|
866
|
-
* ```
|
|
867
|
-
*/
|
|
868
|
-
async createPublic(payload) {
|
|
869
|
-
const response = await this.http.post("/api/organizations", payload);
|
|
870
|
-
return response.data;
|
|
871
|
-
}
|
|
872
|
-
/**
|
|
873
|
-
* List all organizations the authenticated user is a member of.
|
|
874
|
-
*
|
|
875
|
-
* @param params Optional query parameters for filtering and pagination
|
|
876
|
-
* @returns Array of organization responses
|
|
877
|
-
*
|
|
878
|
-
* @example
|
|
879
|
-
* ```typescript
|
|
880
|
-
* const orgs = await sso.organizations.list({
|
|
881
|
-
* status: 'active',
|
|
882
|
-
* page: 1,
|
|
883
|
-
* limit: 20
|
|
884
|
-
* });
|
|
885
|
-
* ```
|
|
886
|
-
*/
|
|
887
|
-
async list(params) {
|
|
888
|
-
const response = await this.http.get("/api/organizations", { params });
|
|
889
|
-
return response.data;
|
|
890
|
-
}
|
|
891
|
-
/**
|
|
892
|
-
* Get detailed information for a specific organization.
|
|
893
|
-
*
|
|
894
|
-
* @param orgSlug Organization slug
|
|
895
|
-
* @returns Organization details
|
|
896
|
-
*
|
|
897
|
-
* @example
|
|
898
|
-
* ```typescript
|
|
899
|
-
* const org = await sso.organizations.get('acme-corp');
|
|
900
|
-
* console.log(org.organization.name, org.membership_count);
|
|
901
|
-
* ```
|
|
902
|
-
*/
|
|
903
|
-
async get(orgSlug) {
|
|
904
|
-
const response = await this.http.get(`/api/organizations/${orgSlug}`);
|
|
905
|
-
return response.data;
|
|
906
|
-
}
|
|
907
|
-
/**
|
|
908
|
-
* Update organization details.
|
|
909
|
-
* Requires 'owner' or 'admin' role.
|
|
910
|
-
*
|
|
911
|
-
* @param orgSlug Organization slug
|
|
912
|
-
* @param payload Update payload
|
|
913
|
-
* @returns Updated organization details
|
|
914
|
-
*
|
|
915
|
-
* @example
|
|
916
|
-
* ```typescript
|
|
917
|
-
* const updated = await sso.organizations.update('acme-corp', {
|
|
918
|
-
* name: 'Acme Corporation Inc.',
|
|
919
|
-
* max_services: 20
|
|
920
|
-
* });
|
|
921
|
-
* ```
|
|
922
|
-
*/
|
|
923
|
-
async update(orgSlug, payload) {
|
|
924
|
-
const response = await this.http.patch(
|
|
925
|
-
`/api/organizations/${orgSlug}`,
|
|
926
|
-
payload
|
|
927
|
-
);
|
|
928
|
-
return response.data;
|
|
929
|
-
}
|
|
930
|
-
};
|
|
931
|
-
|
|
932
|
-
// src/modules/services.ts
|
|
933
|
-
var ServicesModule = class {
|
|
934
|
-
constructor(http) {
|
|
935
|
-
this.http = http;
|
|
936
|
-
/**
|
|
937
|
-
* Plan management methods
|
|
938
|
-
*/
|
|
939
|
-
this.plans = {
|
|
2042
|
+
},
|
|
940
2043
|
/**
|
|
941
|
-
*
|
|
942
|
-
*
|
|
2044
|
+
* Get the SAML IdP metadata URL for this service.
|
|
2045
|
+
* This URL can be provided to Service Providers for automatic configuration.
|
|
943
2046
|
*
|
|
2047
|
+
* @param baseURL SSO platform base URL
|
|
944
2048
|
* @param orgSlug Organization slug
|
|
945
2049
|
* @param serviceSlug Service slug
|
|
946
|
-
* @
|
|
947
|
-
* @returns Created plan
|
|
2050
|
+
* @returns Metadata URL
|
|
948
2051
|
*
|
|
949
2052
|
* @example
|
|
950
2053
|
* ```typescript
|
|
951
|
-
* const
|
|
952
|
-
*
|
|
953
|
-
*
|
|
954
|
-
*
|
|
955
|
-
*
|
|
956
|
-
*
|
|
2054
|
+
* const metadataUrl = sso.services.saml.getMetadataUrl(
|
|
2055
|
+
* 'https://sso.example.com',
|
|
2056
|
+
* 'acme-corp',
|
|
2057
|
+
* 'main-app'
|
|
2058
|
+
* );
|
|
2059
|
+
* console.log('Provide this URL to your SP:', metadataUrl);
|
|
2060
|
+
* // https://sso.example.com/saml/acme-corp/main-app/metadata
|
|
957
2061
|
* ```
|
|
958
2062
|
*/
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans`,
|
|
962
|
-
payload
|
|
963
|
-
);
|
|
964
|
-
return response.data;
|
|
2063
|
+
getMetadataUrl: (baseURL, orgSlug, serviceSlug) => {
|
|
2064
|
+
return `${baseURL}/saml/${orgSlug}/${serviceSlug}/metadata`;
|
|
965
2065
|
},
|
|
966
2066
|
/**
|
|
967
|
-
*
|
|
2067
|
+
* Get the SAML SSO endpoint URL for this service.
|
|
2068
|
+
* This is where Service Providers should redirect users to initiate SSO.
|
|
968
2069
|
*
|
|
2070
|
+
* @param baseURL SSO platform base URL
|
|
969
2071
|
* @param orgSlug Organization slug
|
|
970
2072
|
* @param serviceSlug Service slug
|
|
971
|
-
* @returns
|
|
2073
|
+
* @returns SSO endpoint URL
|
|
972
2074
|
*
|
|
973
2075
|
* @example
|
|
974
2076
|
* ```typescript
|
|
975
|
-
* const
|
|
976
|
-
*
|
|
2077
|
+
* const ssoUrl = sso.services.saml.getSsoUrl(
|
|
2078
|
+
* 'https://sso.example.com',
|
|
2079
|
+
* 'acme-corp',
|
|
2080
|
+
* 'main-app'
|
|
2081
|
+
* );
|
|
2082
|
+
* console.log('SSO endpoint:', ssoUrl);
|
|
2083
|
+
* // https://sso.example.com/saml/acme-corp/main-app/sso
|
|
977
2084
|
* ```
|
|
978
2085
|
*/
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans`
|
|
982
|
-
);
|
|
983
|
-
return response.data;
|
|
2086
|
+
getSsoUrl: (baseURL, orgSlug, serviceSlug) => {
|
|
2087
|
+
return `${baseURL}/saml/${orgSlug}/${serviceSlug}/sso`;
|
|
984
2088
|
}
|
|
985
2089
|
};
|
|
986
2090
|
}
|
|
@@ -1327,6 +2431,97 @@ var PlatformModule = class {
|
|
|
1327
2431
|
payload
|
|
1328
2432
|
);
|
|
1329
2433
|
return response.data;
|
|
2434
|
+
},
|
|
2435
|
+
/**
|
|
2436
|
+
* Delete an organization and all its associated data.
|
|
2437
|
+
* This is a destructive operation that cannot be undone.
|
|
2438
|
+
* Only platform owners can delete organizations.
|
|
2439
|
+
*
|
|
2440
|
+
* All related data will be cascaded deleted including:
|
|
2441
|
+
* - Members and invitations
|
|
2442
|
+
* - Services and plans
|
|
2443
|
+
* - Subscriptions
|
|
2444
|
+
* - OAuth credentials
|
|
2445
|
+
* - Audit logs
|
|
2446
|
+
*
|
|
2447
|
+
* @param orgId Organization ID
|
|
2448
|
+
* @returns Success confirmation
|
|
2449
|
+
*
|
|
2450
|
+
* @example
|
|
2451
|
+
* ```typescript
|
|
2452
|
+
* const result = await sso.platform.organizations.delete('org-id');
|
|
2453
|
+
* console.log(result.message); // 'Organization deleted successfully'
|
|
2454
|
+
* ```
|
|
2455
|
+
*/
|
|
2456
|
+
delete: async (orgId) => {
|
|
2457
|
+
const response = await this.http.delete(
|
|
2458
|
+
`/api/platform/organizations/${orgId}`
|
|
2459
|
+
);
|
|
2460
|
+
return response.data;
|
|
2461
|
+
}
|
|
2462
|
+
};
|
|
2463
|
+
/**
|
|
2464
|
+
* User MFA management methods for platform administrators
|
|
2465
|
+
*/
|
|
2466
|
+
this.users = {
|
|
2467
|
+
/**
|
|
2468
|
+
* Get MFA status for a specific user.
|
|
2469
|
+
*
|
|
2470
|
+
* @param userId The ID of the user
|
|
2471
|
+
* @returns MFA status information
|
|
2472
|
+
*
|
|
2473
|
+
* @example
|
|
2474
|
+
* ```typescript
|
|
2475
|
+
* const mfaStatus = await sso.platform.users.getMfaStatus('user-uuid-here');
|
|
2476
|
+
* console.log(mfaStatus.enabled, mfaStatus.has_backup_codes);
|
|
2477
|
+
* ```
|
|
2478
|
+
*/
|
|
2479
|
+
getMfaStatus: async (userId) => {
|
|
2480
|
+
const response = await this.http.get(`/api/platform/users/${userId}/mfa/status`);
|
|
2481
|
+
return response.data;
|
|
2482
|
+
},
|
|
2483
|
+
/**
|
|
2484
|
+
* Search users by email address or user ID.
|
|
2485
|
+
*
|
|
2486
|
+
* @param query The search query (email or user ID)
|
|
2487
|
+
* @param limit Optional maximum number of results (default: 10, max: 50)
|
|
2488
|
+
* @returns Array of matching users
|
|
2489
|
+
*
|
|
2490
|
+
* @example
|
|
2491
|
+
* ```typescript
|
|
2492
|
+
* const users = await sso.platform.users.search('john@example.com');
|
|
2493
|
+
* console.log(users); // [{ id: 'user-uuid', email: 'john@example.com', ... }]
|
|
2494
|
+
*
|
|
2495
|
+
* // Search by user ID
|
|
2496
|
+
* const users = await sso.platform.users.search('user-uuid-here');
|
|
2497
|
+
*
|
|
2498
|
+
* // Limit results
|
|
2499
|
+
* const users = await sso.platform.users.search('john@', { limit: 5 });
|
|
2500
|
+
* ```
|
|
2501
|
+
*/
|
|
2502
|
+
search: async (query, options) => {
|
|
2503
|
+
const params = {
|
|
2504
|
+
q: query.trim(),
|
|
2505
|
+
limit: options?.limit ? Math.min(options.limit, 50) : void 0
|
|
2506
|
+
};
|
|
2507
|
+
const response = await this.http.get("/api/platform/users/search", { params });
|
|
2508
|
+
return response.data;
|
|
2509
|
+
},
|
|
2510
|
+
/**
|
|
2511
|
+
* Force disable MFA for a user (emergency access).
|
|
2512
|
+
*
|
|
2513
|
+
* @param userId The ID of the user
|
|
2514
|
+
* @returns Success confirmation
|
|
2515
|
+
*
|
|
2516
|
+
* @example
|
|
2517
|
+
* ```typescript
|
|
2518
|
+
* await sso.platform.users.forceDisableMfa('user-uuid-here');
|
|
2519
|
+
* console.log('MFA disabled for user');
|
|
2520
|
+
* ```
|
|
2521
|
+
*/
|
|
2522
|
+
forceDisableMfa: async (userId) => {
|
|
2523
|
+
const response = await this.http.delete(`/api/platform/users/${userId}/mfa`);
|
|
2524
|
+
return response.data;
|
|
1330
2525
|
}
|
|
1331
2526
|
};
|
|
1332
2527
|
/**
|
|
@@ -1510,6 +2705,88 @@ var PlatformModule = class {
|
|
|
1510
2705
|
}
|
|
1511
2706
|
};
|
|
1512
2707
|
|
|
2708
|
+
// src/modules/serviceApi.ts
|
|
2709
|
+
var ServiceApiModule = class {
|
|
2710
|
+
constructor(http) {
|
|
2711
|
+
this.http = http;
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Create a new user
|
|
2715
|
+
* Requires 'write:users' permission on the API key
|
|
2716
|
+
*
|
|
2717
|
+
* @param request User creation request
|
|
2718
|
+
* @returns Created user
|
|
2719
|
+
*/
|
|
2720
|
+
async createUser(request) {
|
|
2721
|
+
const response = await this.http.post("/api/service/users", request);
|
|
2722
|
+
return response.data;
|
|
2723
|
+
}
|
|
2724
|
+
/**
|
|
2725
|
+
* Update user details
|
|
2726
|
+
* Requires 'write:users' permission on the API key
|
|
2727
|
+
*
|
|
2728
|
+
* @param userId User ID to update
|
|
2729
|
+
* @param request User update request
|
|
2730
|
+
* @returns Updated user
|
|
2731
|
+
*/
|
|
2732
|
+
async updateUser(userId, request) {
|
|
2733
|
+
const response = await this.http.patch(`/api/service/users/${userId}`, request);
|
|
2734
|
+
return response.data;
|
|
2735
|
+
}
|
|
2736
|
+
/**
|
|
2737
|
+
* Create a new subscription for a user
|
|
2738
|
+
* Requires 'write:subscriptions' permission on the API key
|
|
2739
|
+
*
|
|
2740
|
+
* @param request Subscription creation request
|
|
2741
|
+
* @returns Created subscription
|
|
2742
|
+
*/
|
|
2743
|
+
async createSubscription(request) {
|
|
2744
|
+
const response = await this.http.post("/api/service/subscriptions", request);
|
|
2745
|
+
return response.data;
|
|
2746
|
+
}
|
|
2747
|
+
/**
|
|
2748
|
+
* Update a subscription for a user
|
|
2749
|
+
* Requires 'write:subscriptions' permission on the API key
|
|
2750
|
+
*
|
|
2751
|
+
* @param userId User ID whose subscription to update
|
|
2752
|
+
* @param request Subscription update request
|
|
2753
|
+
* @returns Updated subscription
|
|
2754
|
+
*/
|
|
2755
|
+
async updateSubscription(userId, request) {
|
|
2756
|
+
const response = await this.http.patch(`/api/service/subscriptions/${userId}`, request);
|
|
2757
|
+
return response.data;
|
|
2758
|
+
}
|
|
2759
|
+
/**
|
|
2760
|
+
* Update service configuration
|
|
2761
|
+
* Requires 'write:service' permission on the API key
|
|
2762
|
+
*
|
|
2763
|
+
* @param request Service update request
|
|
2764
|
+
* @returns Updated service info
|
|
2765
|
+
*/
|
|
2766
|
+
async updateServiceInfo(request) {
|
|
2767
|
+
const response = await this.http.patch("/api/service/info", request);
|
|
2768
|
+
return response.data;
|
|
2769
|
+
}
|
|
2770
|
+
/**
|
|
2771
|
+
* Delete a user
|
|
2772
|
+
* Requires 'delete:users' permission on the API key
|
|
2773
|
+
*
|
|
2774
|
+
* @param userId User ID to delete
|
|
2775
|
+
*/
|
|
2776
|
+
async deleteUser(userId) {
|
|
2777
|
+
await this.http.delete(`/api/service/users/${userId}`);
|
|
2778
|
+
}
|
|
2779
|
+
/**
|
|
2780
|
+
* Delete a subscription for a user
|
|
2781
|
+
* Requires 'delete:subscriptions' permission on the API key
|
|
2782
|
+
*
|
|
2783
|
+
* @param userId User ID whose subscription to delete
|
|
2784
|
+
*/
|
|
2785
|
+
async deleteSubscription(userId) {
|
|
2786
|
+
await this.http.delete(`/api/service/subscriptions/${userId}`);
|
|
2787
|
+
}
|
|
2788
|
+
};
|
|
2789
|
+
|
|
1513
2790
|
// src/client.ts
|
|
1514
2791
|
var SsoClient = class {
|
|
1515
2792
|
constructor(options) {
|
|
@@ -1517,6 +2794,9 @@ var SsoClient = class {
|
|
|
1517
2794
|
if (options.token) {
|
|
1518
2795
|
this.setAuthToken(options.token);
|
|
1519
2796
|
}
|
|
2797
|
+
if (options.apiKey) {
|
|
2798
|
+
this.setApiKey(options.apiKey);
|
|
2799
|
+
}
|
|
1520
2800
|
this.analytics = new AnalyticsModule(this.http);
|
|
1521
2801
|
this.auth = new AuthModule(this.http);
|
|
1522
2802
|
this.user = new UserModule(this.http);
|
|
@@ -1524,6 +2804,7 @@ var SsoClient = class {
|
|
|
1524
2804
|
this.services = new ServicesModule(this.http);
|
|
1525
2805
|
this.invitations = new InvitationsModule(this.http);
|
|
1526
2806
|
this.platform = new PlatformModule(this.http);
|
|
2807
|
+
this.serviceApi = new ServiceApiModule(this.http);
|
|
1527
2808
|
}
|
|
1528
2809
|
/**
|
|
1529
2810
|
* Sets the JWT for all subsequent authenticated requests.
|
|
@@ -1547,6 +2828,28 @@ var SsoClient = class {
|
|
|
1547
2828
|
delete this.http.defaults.headers.common["Authorization"];
|
|
1548
2829
|
}
|
|
1549
2830
|
}
|
|
2831
|
+
/**
|
|
2832
|
+
* Sets the API key for service-to-service authentication.
|
|
2833
|
+
* Pass null to clear the API key.
|
|
2834
|
+
*
|
|
2835
|
+
* @param apiKey The API key string, or null to clear
|
|
2836
|
+
*
|
|
2837
|
+
* @example
|
|
2838
|
+
* ```typescript
|
|
2839
|
+
* // Set API key
|
|
2840
|
+
* sso.setApiKey('sk_live_abcd1234...');
|
|
2841
|
+
*
|
|
2842
|
+
* // Clear API key
|
|
2843
|
+
* sso.setApiKey(null);
|
|
2844
|
+
* ```
|
|
2845
|
+
*/
|
|
2846
|
+
setApiKey(apiKey) {
|
|
2847
|
+
if (apiKey) {
|
|
2848
|
+
this.http.defaults.headers.common["X-Api-Key"] = apiKey;
|
|
2849
|
+
} else {
|
|
2850
|
+
delete this.http.defaults.headers.common["X-Api-Key"];
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
1550
2853
|
/**
|
|
1551
2854
|
* Gets the current base URL
|
|
1552
2855
|
*/
|
|
@@ -1560,6 +2863,7 @@ var SsoClient = class {
|
|
|
1560
2863
|
InvitationsModule,
|
|
1561
2864
|
OrganizationsModule,
|
|
1562
2865
|
PlatformModule,
|
|
2866
|
+
ServiceApiModule,
|
|
1563
2867
|
ServicesModule,
|
|
1564
2868
|
SsoApiError,
|
|
1565
2869
|
SsoClient,
|