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