@drmhse/sso-sdk 0.2.3 → 0.2.6
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 +216 -300
- package/dist/index.d.mts +1767 -148
- package/dist/index.d.ts +1767 -148
- package/dist/index.js +1569 -256
- package/dist/index.mjs +1568 -256
- 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,445 +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.
|
|
537
1495
|
*
|
|
538
|
-
* @
|
|
1496
|
+
* @param orgSlug Organization slug
|
|
1497
|
+
* @returns SMTP configuration (without password)
|
|
539
1498
|
*
|
|
540
1499
|
* @example
|
|
541
1500
|
* ```typescript
|
|
542
|
-
* const
|
|
543
|
-
*
|
|
1501
|
+
* const config = await sso.organizations.getSmtp('acme-corp');
|
|
1502
|
+
* if (config.configured) {
|
|
1503
|
+
* console.log('SMTP host:', config.host);
|
|
1504
|
+
* }
|
|
544
1505
|
* ```
|
|
545
1506
|
*/
|
|
546
|
-
async
|
|
547
|
-
const response = await this.http.get(
|
|
1507
|
+
async getSmtp(orgSlug) {
|
|
1508
|
+
const response = await this.http.get(
|
|
1509
|
+
`/api/organizations/${orgSlug}/smtp`
|
|
1510
|
+
);
|
|
548
1511
|
return response.data;
|
|
549
1512
|
}
|
|
550
1513
|
/**
|
|
551
|
-
*
|
|
552
|
-
*
|
|
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.
|
|
553
1517
|
*
|
|
554
|
-
* @param
|
|
555
|
-
* @returns
|
|
1518
|
+
* @param orgSlug Organization slug
|
|
1519
|
+
* @returns Success message
|
|
556
1520
|
*
|
|
557
1521
|
* @example
|
|
558
1522
|
* ```typescript
|
|
559
|
-
*
|
|
560
|
-
*
|
|
1523
|
+
* await sso.organizations.deleteSmtp('acme-corp');
|
|
1524
|
+
* // Organization now uses platform SMTP
|
|
561
1525
|
* ```
|
|
562
1526
|
*/
|
|
563
|
-
async
|
|
564
|
-
const response = await this.http.
|
|
1527
|
+
async deleteSmtp(orgSlug) {
|
|
1528
|
+
const response = await this.http.delete(
|
|
1529
|
+
`/api/organizations/${orgSlug}/smtp`
|
|
1530
|
+
);
|
|
565
1531
|
return response.data;
|
|
566
1532
|
}
|
|
1533
|
+
// ============================================================================
|
|
1534
|
+
// CUSTOM DOMAINS & BRANDING
|
|
1535
|
+
// ============================================================================
|
|
567
1536
|
/**
|
|
568
|
-
*
|
|
569
|
-
*
|
|
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.
|
|
570
1541
|
*
|
|
571
|
-
* @param
|
|
1542
|
+
* @param orgSlug Organization slug
|
|
1543
|
+
* @param request Custom domain request
|
|
1544
|
+
* @returns Domain verification instructions
|
|
572
1545
|
*
|
|
573
1546
|
* @example
|
|
574
1547
|
* ```typescript
|
|
575
|
-
* await sso.
|
|
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
|
+
* });
|
|
576
1555
|
* ```
|
|
577
1556
|
*/
|
|
578
|
-
async
|
|
579
|
-
await this.http.
|
|
1557
|
+
async setCustomDomain(orgSlug, request) {
|
|
1558
|
+
const response = await this.http.post(
|
|
1559
|
+
`/api/organizations/${orgSlug}/domain`,
|
|
1560
|
+
request
|
|
1561
|
+
);
|
|
1562
|
+
return response.data;
|
|
580
1563
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
1564
|
+
/**
|
|
1565
|
+
* Verify a custom domain by checking DNS TXT record or HTTP file.
|
|
1566
|
+
* Requires 'owner' or 'admin' role.
|
|
1567
|
+
*
|
|
1568
|
+
* @param orgSlug Organization slug
|
|
1569
|
+
* @returns Verification result
|
|
1570
|
+
*
|
|
1571
|
+
* @example
|
|
1572
|
+
* ```typescript
|
|
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
|
+
* }
|
|
1579
|
+
* ```
|
|
1580
|
+
*/
|
|
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
|
-
* @
|
|
1924
|
+
* @param serviceSlug Service slug
|
|
1925
|
+
* @param payload SAML configuration payload
|
|
1926
|
+
* @returns Configuration success response
|
|
732
1927
|
*
|
|
733
1928
|
* @example
|
|
734
1929
|
* ```typescript
|
|
735
|
-
* const
|
|
736
|
-
*
|
|
737
|
-
*
|
|
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
|
|
738
1940
|
* });
|
|
739
|
-
* console.log(`Total end-users: ${endUsers.total}`);
|
|
740
1941
|
* ```
|
|
741
1942
|
*/
|
|
742
|
-
|
|
743
|
-
const response = await this.http.
|
|
744
|
-
`/api/organizations/${orgSlug}/
|
|
745
|
-
|
|
1943
|
+
configure: async (orgSlug, serviceSlug, payload) => {
|
|
1944
|
+
const response = await this.http.post(
|
|
1945
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`,
|
|
1946
|
+
payload
|
|
746
1947
|
);
|
|
747
1948
|
return response.data;
|
|
748
1949
|
},
|
|
749
1950
|
/**
|
|
750
|
-
* Get
|
|
1951
|
+
* Get current SAML IdP configuration for a service.
|
|
751
1952
|
*
|
|
752
|
-
* @param orgSlug Organization slug
|
|
753
|
-
* @param
|
|
754
|
-
* @returns
|
|
1953
|
+
* @param orgSlug Organization slug
|
|
1954
|
+
* @param serviceSlug Service slug
|
|
1955
|
+
* @returns Current SAML configuration
|
|
755
1956
|
*
|
|
756
1957
|
* @example
|
|
757
1958
|
* ```typescript
|
|
758
|
-
* const
|
|
759
|
-
*
|
|
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
|
+
* }
|
|
760
1965
|
* ```
|
|
761
1966
|
*/
|
|
762
|
-
|
|
1967
|
+
getConfig: async (orgSlug, serviceSlug) => {
|
|
763
1968
|
const response = await this.http.get(
|
|
764
|
-
`/api/organizations/${orgSlug}/
|
|
1969
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`
|
|
765
1970
|
);
|
|
766
1971
|
return response.data;
|
|
767
1972
|
},
|
|
768
1973
|
/**
|
|
769
|
-
*
|
|
770
|
-
* Requires
|
|
771
|
-
*
|
|
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.
|
|
772
1978
|
*
|
|
773
1979
|
* @param orgSlug Organization slug
|
|
774
|
-
* @param
|
|
775
|
-
* @returns Response with number of revoked sessions
|
|
1980
|
+
* @param serviceSlug Service slug
|
|
776
1981
|
*
|
|
777
1982
|
* @example
|
|
778
1983
|
* ```typescript
|
|
779
|
-
*
|
|
780
|
-
* console.log(
|
|
1984
|
+
* await sso.services.saml.deleteConfig('acme-corp', 'main-app');
|
|
1985
|
+
* console.log('SAML IdP configuration deleted');
|
|
781
1986
|
* ```
|
|
782
1987
|
*/
|
|
783
|
-
|
|
1988
|
+
deleteConfig: async (orgSlug, serviceSlug) => {
|
|
784
1989
|
const response = await this.http.delete(
|
|
785
|
-
`/api/organizations/${orgSlug}/
|
|
1990
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`
|
|
786
1991
|
);
|
|
787
1992
|
return response.data;
|
|
788
|
-
}
|
|
789
|
-
};
|
|
790
|
-
/**
|
|
791
|
-
* BYOO (Bring Your Own OAuth) credential management
|
|
792
|
-
*/
|
|
793
|
-
this.oauthCredentials = {
|
|
1993
|
+
},
|
|
794
1994
|
/**
|
|
795
|
-
*
|
|
796
|
-
* This enables white-labeled authentication using the organization's
|
|
797
|
-
* own OAuth application.
|
|
1995
|
+
* Generate a new SAML signing certificate for the IdP.
|
|
798
1996
|
* Requires 'owner' or 'admin' role.
|
|
799
1997
|
*
|
|
1998
|
+
* IMPORTANT: This automatically deactivates any existing active certificates.
|
|
1999
|
+
* Provide the returned certificate to your Service Provider during SAML setup.
|
|
2000
|
+
*
|
|
800
2001
|
* @param orgSlug Organization slug
|
|
801
|
-
* @param
|
|
802
|
-
* @
|
|
803
|
-
* @returns Created/updated credentials (without secret)
|
|
2002
|
+
* @param serviceSlug Service slug
|
|
2003
|
+
* @returns Certificate information including public key
|
|
804
2004
|
*
|
|
805
2005
|
* @example
|
|
806
2006
|
* ```typescript
|
|
807
|
-
* await sso.
|
|
808
|
-
*
|
|
809
|
-
*
|
|
810
|
-
*
|
|
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
|
|
811
2011
|
* ```
|
|
812
2012
|
*/
|
|
813
|
-
|
|
2013
|
+
generateCertificate: async (orgSlug, serviceSlug) => {
|
|
814
2014
|
const response = await this.http.post(
|
|
815
|
-
`/api/organizations/${orgSlug}/
|
|
816
|
-
|
|
2015
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml/certificate`,
|
|
2016
|
+
{}
|
|
817
2017
|
);
|
|
818
2018
|
return response.data;
|
|
819
2019
|
},
|
|
820
2020
|
/**
|
|
821
|
-
* Get the
|
|
822
|
-
* The secret is never returned.
|
|
2021
|
+
* Get the active SAML signing certificate.
|
|
823
2022
|
*
|
|
824
2023
|
* @param orgSlug Organization slug
|
|
825
|
-
* @param
|
|
826
|
-
* @returns
|
|
2024
|
+
* @param serviceSlug Service slug
|
|
2025
|
+
* @returns Active certificate information
|
|
827
2026
|
*
|
|
828
2027
|
* @example
|
|
829
2028
|
* ```typescript
|
|
830
|
-
*
|
|
831
|
-
*
|
|
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
|
+
* }
|
|
832
2035
|
* ```
|
|
833
2036
|
*/
|
|
834
|
-
|
|
2037
|
+
getCertificate: async (orgSlug, serviceSlug) => {
|
|
835
2038
|
const response = await this.http.get(
|
|
836
|
-
`/api/organizations/${orgSlug}/
|
|
2039
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml/certificate`
|
|
837
2040
|
);
|
|
838
2041
|
return response.data;
|
|
839
|
-
}
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
/**
|
|
843
|
-
* Create a new organization (public endpoint).
|
|
844
|
-
* The organization will be created with 'pending' status and requires
|
|
845
|
-
* platform owner approval before becoming active.
|
|
846
|
-
*
|
|
847
|
-
* @param payload Organization creation payload
|
|
848
|
-
* @returns Created organization with owner and membership details
|
|
849
|
-
*
|
|
850
|
-
* @example
|
|
851
|
-
* ```typescript
|
|
852
|
-
* const result = await sso.organizations.createPublic({
|
|
853
|
-
* slug: 'acme-corp',
|
|
854
|
-
* name: 'Acme Corporation',
|
|
855
|
-
* owner_email: 'founder@acme.com'
|
|
856
|
-
* });
|
|
857
|
-
* ```
|
|
858
|
-
*/
|
|
859
|
-
async createPublic(payload) {
|
|
860
|
-
const response = await this.http.post("/api/organizations", payload);
|
|
861
|
-
return response.data;
|
|
862
|
-
}
|
|
863
|
-
/**
|
|
864
|
-
* List all organizations the authenticated user is a member of.
|
|
865
|
-
*
|
|
866
|
-
* @param params Optional query parameters for filtering and pagination
|
|
867
|
-
* @returns Array of organization responses
|
|
868
|
-
*
|
|
869
|
-
* @example
|
|
870
|
-
* ```typescript
|
|
871
|
-
* const orgs = await sso.organizations.list({
|
|
872
|
-
* status: 'active',
|
|
873
|
-
* page: 1,
|
|
874
|
-
* limit: 20
|
|
875
|
-
* });
|
|
876
|
-
* ```
|
|
877
|
-
*/
|
|
878
|
-
async list(params) {
|
|
879
|
-
const response = await this.http.get("/api/organizations", { params });
|
|
880
|
-
return response.data;
|
|
881
|
-
}
|
|
882
|
-
/**
|
|
883
|
-
* Get detailed information for a specific organization.
|
|
884
|
-
*
|
|
885
|
-
* @param orgSlug Organization slug
|
|
886
|
-
* @returns Organization details
|
|
887
|
-
*
|
|
888
|
-
* @example
|
|
889
|
-
* ```typescript
|
|
890
|
-
* const org = await sso.organizations.get('acme-corp');
|
|
891
|
-
* console.log(org.organization.name, org.membership_count);
|
|
892
|
-
* ```
|
|
893
|
-
*/
|
|
894
|
-
async get(orgSlug) {
|
|
895
|
-
const response = await this.http.get(`/api/organizations/${orgSlug}`);
|
|
896
|
-
return response.data;
|
|
897
|
-
}
|
|
898
|
-
/**
|
|
899
|
-
* Update organization details.
|
|
900
|
-
* Requires 'owner' or 'admin' role.
|
|
901
|
-
*
|
|
902
|
-
* @param orgSlug Organization slug
|
|
903
|
-
* @param payload Update payload
|
|
904
|
-
* @returns Updated organization details
|
|
905
|
-
*
|
|
906
|
-
* @example
|
|
907
|
-
* ```typescript
|
|
908
|
-
* const updated = await sso.organizations.update('acme-corp', {
|
|
909
|
-
* name: 'Acme Corporation Inc.',
|
|
910
|
-
* max_services: 20
|
|
911
|
-
* });
|
|
912
|
-
* ```
|
|
913
|
-
*/
|
|
914
|
-
async update(orgSlug, payload) {
|
|
915
|
-
const response = await this.http.patch(
|
|
916
|
-
`/api/organizations/${orgSlug}`,
|
|
917
|
-
payload
|
|
918
|
-
);
|
|
919
|
-
return response.data;
|
|
920
|
-
}
|
|
921
|
-
};
|
|
922
|
-
|
|
923
|
-
// src/modules/services.ts
|
|
924
|
-
var ServicesModule = class {
|
|
925
|
-
constructor(http) {
|
|
926
|
-
this.http = http;
|
|
927
|
-
/**
|
|
928
|
-
* Plan management methods
|
|
929
|
-
*/
|
|
930
|
-
this.plans = {
|
|
2042
|
+
},
|
|
931
2043
|
/**
|
|
932
|
-
*
|
|
933
|
-
*
|
|
2044
|
+
* Get the SAML IdP metadata URL for this service.
|
|
2045
|
+
* This URL can be provided to Service Providers for automatic configuration.
|
|
934
2046
|
*
|
|
2047
|
+
* @param baseURL SSO platform base URL
|
|
935
2048
|
* @param orgSlug Organization slug
|
|
936
2049
|
* @param serviceSlug Service slug
|
|
937
|
-
* @
|
|
938
|
-
* @returns Created plan
|
|
2050
|
+
* @returns Metadata URL
|
|
939
2051
|
*
|
|
940
2052
|
* @example
|
|
941
2053
|
* ```typescript
|
|
942
|
-
* const
|
|
943
|
-
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
*
|
|
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
|
|
948
2061
|
* ```
|
|
949
2062
|
*/
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans`,
|
|
953
|
-
payload
|
|
954
|
-
);
|
|
955
|
-
return response.data;
|
|
2063
|
+
getMetadataUrl: (baseURL, orgSlug, serviceSlug) => {
|
|
2064
|
+
return `${baseURL}/saml/${orgSlug}/${serviceSlug}/metadata`;
|
|
956
2065
|
},
|
|
957
2066
|
/**
|
|
958
|
-
*
|
|
2067
|
+
* Get the SAML SSO endpoint URL for this service.
|
|
2068
|
+
* This is where Service Providers should redirect users to initiate SSO.
|
|
959
2069
|
*
|
|
2070
|
+
* @param baseURL SSO platform base URL
|
|
960
2071
|
* @param orgSlug Organization slug
|
|
961
2072
|
* @param serviceSlug Service slug
|
|
962
|
-
* @returns
|
|
2073
|
+
* @returns SSO endpoint URL
|
|
963
2074
|
*
|
|
964
2075
|
* @example
|
|
965
2076
|
* ```typescript
|
|
966
|
-
* const
|
|
967
|
-
*
|
|
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
|
|
968
2084
|
* ```
|
|
969
2085
|
*/
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans`
|
|
973
|
-
);
|
|
974
|
-
return response.data;
|
|
2086
|
+
getSsoUrl: (baseURL, orgSlug, serviceSlug) => {
|
|
2087
|
+
return `${baseURL}/saml/${orgSlug}/${serviceSlug}/sso`;
|
|
975
2088
|
}
|
|
976
2089
|
};
|
|
977
2090
|
}
|
|
@@ -1318,6 +2431,97 @@ var PlatformModule = class {
|
|
|
1318
2431
|
payload
|
|
1319
2432
|
);
|
|
1320
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;
|
|
1321
2525
|
}
|
|
1322
2526
|
};
|
|
1323
2527
|
/**
|
|
@@ -1501,6 +2705,88 @@ var PlatformModule = class {
|
|
|
1501
2705
|
}
|
|
1502
2706
|
};
|
|
1503
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
|
+
|
|
1504
2790
|
// src/client.ts
|
|
1505
2791
|
var SsoClient = class {
|
|
1506
2792
|
constructor(options) {
|
|
@@ -1508,6 +2794,9 @@ var SsoClient = class {
|
|
|
1508
2794
|
if (options.token) {
|
|
1509
2795
|
this.setAuthToken(options.token);
|
|
1510
2796
|
}
|
|
2797
|
+
if (options.apiKey) {
|
|
2798
|
+
this.setApiKey(options.apiKey);
|
|
2799
|
+
}
|
|
1511
2800
|
this.analytics = new AnalyticsModule(this.http);
|
|
1512
2801
|
this.auth = new AuthModule(this.http);
|
|
1513
2802
|
this.user = new UserModule(this.http);
|
|
@@ -1515,6 +2804,7 @@ var SsoClient = class {
|
|
|
1515
2804
|
this.services = new ServicesModule(this.http);
|
|
1516
2805
|
this.invitations = new InvitationsModule(this.http);
|
|
1517
2806
|
this.platform = new PlatformModule(this.http);
|
|
2807
|
+
this.serviceApi = new ServiceApiModule(this.http);
|
|
1518
2808
|
}
|
|
1519
2809
|
/**
|
|
1520
2810
|
* Sets the JWT for all subsequent authenticated requests.
|
|
@@ -1538,6 +2828,28 @@ var SsoClient = class {
|
|
|
1538
2828
|
delete this.http.defaults.headers.common["Authorization"];
|
|
1539
2829
|
}
|
|
1540
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
|
+
}
|
|
1541
2853
|
/**
|
|
1542
2854
|
* Gets the current base URL
|
|
1543
2855
|
*/
|
|
@@ -1551,6 +2863,7 @@ var SsoClient = class {
|
|
|
1551
2863
|
InvitationsModule,
|
|
1552
2864
|
OrganizationsModule,
|
|
1553
2865
|
PlatformModule,
|
|
2866
|
+
ServiceApiModule,
|
|
1554
2867
|
ServicesModule,
|
|
1555
2868
|
SsoApiError,
|
|
1556
2869
|
SsoClient,
|