@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.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,445 +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.
|
|
504
1461
|
*
|
|
505
|
-
* @
|
|
1462
|
+
* @param orgSlug Organization slug
|
|
1463
|
+
* @returns SMTP configuration (without password)
|
|
506
1464
|
*
|
|
507
1465
|
* @example
|
|
508
1466
|
* ```typescript
|
|
509
|
-
* const
|
|
510
|
-
*
|
|
1467
|
+
* const config = await sso.organizations.getSmtp('acme-corp');
|
|
1468
|
+
* if (config.configured) {
|
|
1469
|
+
* console.log('SMTP host:', config.host);
|
|
1470
|
+
* }
|
|
511
1471
|
* ```
|
|
512
1472
|
*/
|
|
513
|
-
async
|
|
514
|
-
const response = await this.http.get(
|
|
1473
|
+
async getSmtp(orgSlug) {
|
|
1474
|
+
const response = await this.http.get(
|
|
1475
|
+
`/api/organizations/${orgSlug}/smtp`
|
|
1476
|
+
);
|
|
515
1477
|
return response.data;
|
|
516
1478
|
}
|
|
517
1479
|
/**
|
|
518
|
-
*
|
|
519
|
-
*
|
|
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.
|
|
520
1483
|
*
|
|
521
|
-
* @param
|
|
522
|
-
* @returns
|
|
1484
|
+
* @param orgSlug Organization slug
|
|
1485
|
+
* @returns Success message
|
|
523
1486
|
*
|
|
524
1487
|
* @example
|
|
525
1488
|
* ```typescript
|
|
526
|
-
*
|
|
527
|
-
*
|
|
1489
|
+
* await sso.organizations.deleteSmtp('acme-corp');
|
|
1490
|
+
* // Organization now uses platform SMTP
|
|
528
1491
|
* ```
|
|
529
1492
|
*/
|
|
530
|
-
async
|
|
531
|
-
const response = await this.http.
|
|
1493
|
+
async deleteSmtp(orgSlug) {
|
|
1494
|
+
const response = await this.http.delete(
|
|
1495
|
+
`/api/organizations/${orgSlug}/smtp`
|
|
1496
|
+
);
|
|
532
1497
|
return response.data;
|
|
533
1498
|
}
|
|
1499
|
+
// ============================================================================
|
|
1500
|
+
// CUSTOM DOMAINS & BRANDING
|
|
1501
|
+
// ============================================================================
|
|
534
1502
|
/**
|
|
535
|
-
*
|
|
536
|
-
*
|
|
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.
|
|
537
1507
|
*
|
|
538
|
-
* @param
|
|
1508
|
+
* @param orgSlug Organization slug
|
|
1509
|
+
* @param request Custom domain request
|
|
1510
|
+
* @returns Domain verification instructions
|
|
539
1511
|
*
|
|
540
1512
|
* @example
|
|
541
1513
|
* ```typescript
|
|
542
|
-
* await sso.
|
|
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
|
+
* });
|
|
543
1521
|
* ```
|
|
544
1522
|
*/
|
|
545
|
-
async
|
|
546
|
-
await this.http.
|
|
1523
|
+
async setCustomDomain(orgSlug, request) {
|
|
1524
|
+
const response = await this.http.post(
|
|
1525
|
+
`/api/organizations/${orgSlug}/domain`,
|
|
1526
|
+
request
|
|
1527
|
+
);
|
|
1528
|
+
return response.data;
|
|
547
1529
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
1530
|
+
/**
|
|
1531
|
+
* Verify a custom domain by checking DNS TXT record or HTTP file.
|
|
1532
|
+
* Requires 'owner' or 'admin' role.
|
|
1533
|
+
*
|
|
1534
|
+
* @param orgSlug Organization slug
|
|
1535
|
+
* @returns Verification result
|
|
1536
|
+
*
|
|
1537
|
+
* @example
|
|
1538
|
+
* ```typescript
|
|
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
|
+
* }
|
|
1545
|
+
* ```
|
|
1546
|
+
*/
|
|
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
|
-
* @
|
|
1890
|
+
* @param serviceSlug Service slug
|
|
1891
|
+
* @param payload SAML configuration payload
|
|
1892
|
+
* @returns Configuration success response
|
|
699
1893
|
*
|
|
700
1894
|
* @example
|
|
701
1895
|
* ```typescript
|
|
702
|
-
* const
|
|
703
|
-
*
|
|
704
|
-
*
|
|
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
|
|
705
1906
|
* });
|
|
706
|
-
* console.log(`Total end-users: ${endUsers.total}`);
|
|
707
1907
|
* ```
|
|
708
1908
|
*/
|
|
709
|
-
|
|
710
|
-
const response = await this.http.
|
|
711
|
-
`/api/organizations/${orgSlug}/
|
|
712
|
-
|
|
1909
|
+
configure: async (orgSlug, serviceSlug, payload) => {
|
|
1910
|
+
const response = await this.http.post(
|
|
1911
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`,
|
|
1912
|
+
payload
|
|
713
1913
|
);
|
|
714
1914
|
return response.data;
|
|
715
1915
|
},
|
|
716
1916
|
/**
|
|
717
|
-
* Get
|
|
1917
|
+
* Get current SAML IdP configuration for a service.
|
|
718
1918
|
*
|
|
719
|
-
* @param orgSlug Organization slug
|
|
720
|
-
* @param
|
|
721
|
-
* @returns
|
|
1919
|
+
* @param orgSlug Organization slug
|
|
1920
|
+
* @param serviceSlug Service slug
|
|
1921
|
+
* @returns Current SAML configuration
|
|
722
1922
|
*
|
|
723
1923
|
* @example
|
|
724
1924
|
* ```typescript
|
|
725
|
-
* const
|
|
726
|
-
*
|
|
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
|
+
* }
|
|
727
1931
|
* ```
|
|
728
1932
|
*/
|
|
729
|
-
|
|
1933
|
+
getConfig: async (orgSlug, serviceSlug) => {
|
|
730
1934
|
const response = await this.http.get(
|
|
731
|
-
`/api/organizations/${orgSlug}/
|
|
1935
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`
|
|
732
1936
|
);
|
|
733
1937
|
return response.data;
|
|
734
1938
|
},
|
|
735
1939
|
/**
|
|
736
|
-
*
|
|
737
|
-
* Requires
|
|
738
|
-
*
|
|
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.
|
|
739
1944
|
*
|
|
740
1945
|
* @param orgSlug Organization slug
|
|
741
|
-
* @param
|
|
742
|
-
* @returns Response with number of revoked sessions
|
|
1946
|
+
* @param serviceSlug Service slug
|
|
743
1947
|
*
|
|
744
1948
|
* @example
|
|
745
1949
|
* ```typescript
|
|
746
|
-
*
|
|
747
|
-
* console.log(
|
|
1950
|
+
* await sso.services.saml.deleteConfig('acme-corp', 'main-app');
|
|
1951
|
+
* console.log('SAML IdP configuration deleted');
|
|
748
1952
|
* ```
|
|
749
1953
|
*/
|
|
750
|
-
|
|
1954
|
+
deleteConfig: async (orgSlug, serviceSlug) => {
|
|
751
1955
|
const response = await this.http.delete(
|
|
752
|
-
`/api/organizations/${orgSlug}/
|
|
1956
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml`
|
|
753
1957
|
);
|
|
754
1958
|
return response.data;
|
|
755
|
-
}
|
|
756
|
-
};
|
|
757
|
-
/**
|
|
758
|
-
* BYOO (Bring Your Own OAuth) credential management
|
|
759
|
-
*/
|
|
760
|
-
this.oauthCredentials = {
|
|
1959
|
+
},
|
|
761
1960
|
/**
|
|
762
|
-
*
|
|
763
|
-
* This enables white-labeled authentication using the organization's
|
|
764
|
-
* own OAuth application.
|
|
1961
|
+
* Generate a new SAML signing certificate for the IdP.
|
|
765
1962
|
* Requires 'owner' or 'admin' role.
|
|
766
1963
|
*
|
|
1964
|
+
* IMPORTANT: This automatically deactivates any existing active certificates.
|
|
1965
|
+
* Provide the returned certificate to your Service Provider during SAML setup.
|
|
1966
|
+
*
|
|
767
1967
|
* @param orgSlug Organization slug
|
|
768
|
-
* @param
|
|
769
|
-
* @
|
|
770
|
-
* @returns Created/updated credentials (without secret)
|
|
1968
|
+
* @param serviceSlug Service slug
|
|
1969
|
+
* @returns Certificate information including public key
|
|
771
1970
|
*
|
|
772
1971
|
* @example
|
|
773
1972
|
* ```typescript
|
|
774
|
-
* await sso.
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
*
|
|
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
|
|
778
1977
|
* ```
|
|
779
1978
|
*/
|
|
780
|
-
|
|
1979
|
+
generateCertificate: async (orgSlug, serviceSlug) => {
|
|
781
1980
|
const response = await this.http.post(
|
|
782
|
-
`/api/organizations/${orgSlug}/
|
|
783
|
-
|
|
1981
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml/certificate`,
|
|
1982
|
+
{}
|
|
784
1983
|
);
|
|
785
1984
|
return response.data;
|
|
786
1985
|
},
|
|
787
1986
|
/**
|
|
788
|
-
* Get the
|
|
789
|
-
* The secret is never returned.
|
|
1987
|
+
* Get the active SAML signing certificate.
|
|
790
1988
|
*
|
|
791
1989
|
* @param orgSlug Organization slug
|
|
792
|
-
* @param
|
|
793
|
-
* @returns
|
|
1990
|
+
* @param serviceSlug Service slug
|
|
1991
|
+
* @returns Active certificate information
|
|
794
1992
|
*
|
|
795
1993
|
* @example
|
|
796
1994
|
* ```typescript
|
|
797
|
-
*
|
|
798
|
-
*
|
|
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
|
+
* }
|
|
799
2001
|
* ```
|
|
800
2002
|
*/
|
|
801
|
-
|
|
2003
|
+
getCertificate: async (orgSlug, serviceSlug) => {
|
|
802
2004
|
const response = await this.http.get(
|
|
803
|
-
`/api/organizations/${orgSlug}/
|
|
2005
|
+
`/api/organizations/${orgSlug}/services/${serviceSlug}/saml/certificate`
|
|
804
2006
|
);
|
|
805
2007
|
return response.data;
|
|
806
|
-
}
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
/**
|
|
810
|
-
* Create a new organization (public endpoint).
|
|
811
|
-
* The organization will be created with 'pending' status and requires
|
|
812
|
-
* platform owner approval before becoming active.
|
|
813
|
-
*
|
|
814
|
-
* @param payload Organization creation payload
|
|
815
|
-
* @returns Created organization with owner and membership details
|
|
816
|
-
*
|
|
817
|
-
* @example
|
|
818
|
-
* ```typescript
|
|
819
|
-
* const result = await sso.organizations.createPublic({
|
|
820
|
-
* slug: 'acme-corp',
|
|
821
|
-
* name: 'Acme Corporation',
|
|
822
|
-
* owner_email: 'founder@acme.com'
|
|
823
|
-
* });
|
|
824
|
-
* ```
|
|
825
|
-
*/
|
|
826
|
-
async createPublic(payload) {
|
|
827
|
-
const response = await this.http.post("/api/organizations", payload);
|
|
828
|
-
return response.data;
|
|
829
|
-
}
|
|
830
|
-
/**
|
|
831
|
-
* List all organizations the authenticated user is a member of.
|
|
832
|
-
*
|
|
833
|
-
* @param params Optional query parameters for filtering and pagination
|
|
834
|
-
* @returns Array of organization responses
|
|
835
|
-
*
|
|
836
|
-
* @example
|
|
837
|
-
* ```typescript
|
|
838
|
-
* const orgs = await sso.organizations.list({
|
|
839
|
-
* status: 'active',
|
|
840
|
-
* page: 1,
|
|
841
|
-
* limit: 20
|
|
842
|
-
* });
|
|
843
|
-
* ```
|
|
844
|
-
*/
|
|
845
|
-
async list(params) {
|
|
846
|
-
const response = await this.http.get("/api/organizations", { params });
|
|
847
|
-
return response.data;
|
|
848
|
-
}
|
|
849
|
-
/**
|
|
850
|
-
* Get detailed information for a specific organization.
|
|
851
|
-
*
|
|
852
|
-
* @param orgSlug Organization slug
|
|
853
|
-
* @returns Organization details
|
|
854
|
-
*
|
|
855
|
-
* @example
|
|
856
|
-
* ```typescript
|
|
857
|
-
* const org = await sso.organizations.get('acme-corp');
|
|
858
|
-
* console.log(org.organization.name, org.membership_count);
|
|
859
|
-
* ```
|
|
860
|
-
*/
|
|
861
|
-
async get(orgSlug) {
|
|
862
|
-
const response = await this.http.get(`/api/organizations/${orgSlug}`);
|
|
863
|
-
return response.data;
|
|
864
|
-
}
|
|
865
|
-
/**
|
|
866
|
-
* Update organization details.
|
|
867
|
-
* Requires 'owner' or 'admin' role.
|
|
868
|
-
*
|
|
869
|
-
* @param orgSlug Organization slug
|
|
870
|
-
* @param payload Update payload
|
|
871
|
-
* @returns Updated organization details
|
|
872
|
-
*
|
|
873
|
-
* @example
|
|
874
|
-
* ```typescript
|
|
875
|
-
* const updated = await sso.organizations.update('acme-corp', {
|
|
876
|
-
* name: 'Acme Corporation Inc.',
|
|
877
|
-
* max_services: 20
|
|
878
|
-
* });
|
|
879
|
-
* ```
|
|
880
|
-
*/
|
|
881
|
-
async update(orgSlug, payload) {
|
|
882
|
-
const response = await this.http.patch(
|
|
883
|
-
`/api/organizations/${orgSlug}`,
|
|
884
|
-
payload
|
|
885
|
-
);
|
|
886
|
-
return response.data;
|
|
887
|
-
}
|
|
888
|
-
};
|
|
889
|
-
|
|
890
|
-
// src/modules/services.ts
|
|
891
|
-
var ServicesModule = class {
|
|
892
|
-
constructor(http) {
|
|
893
|
-
this.http = http;
|
|
894
|
-
/**
|
|
895
|
-
* Plan management methods
|
|
896
|
-
*/
|
|
897
|
-
this.plans = {
|
|
2008
|
+
},
|
|
898
2009
|
/**
|
|
899
|
-
*
|
|
900
|
-
*
|
|
2010
|
+
* Get the SAML IdP metadata URL for this service.
|
|
2011
|
+
* This URL can be provided to Service Providers for automatic configuration.
|
|
901
2012
|
*
|
|
2013
|
+
* @param baseURL SSO platform base URL
|
|
902
2014
|
* @param orgSlug Organization slug
|
|
903
2015
|
* @param serviceSlug Service slug
|
|
904
|
-
* @
|
|
905
|
-
* @returns Created plan
|
|
2016
|
+
* @returns Metadata URL
|
|
906
2017
|
*
|
|
907
2018
|
* @example
|
|
908
2019
|
* ```typescript
|
|
909
|
-
* const
|
|
910
|
-
*
|
|
911
|
-
*
|
|
912
|
-
*
|
|
913
|
-
*
|
|
914
|
-
*
|
|
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
|
|
915
2027
|
* ```
|
|
916
2028
|
*/
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans`,
|
|
920
|
-
payload
|
|
921
|
-
);
|
|
922
|
-
return response.data;
|
|
2029
|
+
getMetadataUrl: (baseURL, orgSlug, serviceSlug) => {
|
|
2030
|
+
return `${baseURL}/saml/${orgSlug}/${serviceSlug}/metadata`;
|
|
923
2031
|
},
|
|
924
2032
|
/**
|
|
925
|
-
*
|
|
2033
|
+
* Get the SAML SSO endpoint URL for this service.
|
|
2034
|
+
* This is where Service Providers should redirect users to initiate SSO.
|
|
926
2035
|
*
|
|
2036
|
+
* @param baseURL SSO platform base URL
|
|
927
2037
|
* @param orgSlug Organization slug
|
|
928
2038
|
* @param serviceSlug Service slug
|
|
929
|
-
* @returns
|
|
2039
|
+
* @returns SSO endpoint URL
|
|
930
2040
|
*
|
|
931
2041
|
* @example
|
|
932
2042
|
* ```typescript
|
|
933
|
-
* const
|
|
934
|
-
*
|
|
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
|
|
935
2050
|
* ```
|
|
936
2051
|
*/
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
`/api/organizations/${orgSlug}/services/${serviceSlug}/plans`
|
|
940
|
-
);
|
|
941
|
-
return response.data;
|
|
2052
|
+
getSsoUrl: (baseURL, orgSlug, serviceSlug) => {
|
|
2053
|
+
return `${baseURL}/saml/${orgSlug}/${serviceSlug}/sso`;
|
|
942
2054
|
}
|
|
943
2055
|
};
|
|
944
2056
|
}
|
|
@@ -1285,6 +2397,97 @@ var PlatformModule = class {
|
|
|
1285
2397
|
payload
|
|
1286
2398
|
);
|
|
1287
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;
|
|
1288
2491
|
}
|
|
1289
2492
|
};
|
|
1290
2493
|
/**
|
|
@@ -1468,6 +2671,88 @@ var PlatformModule = class {
|
|
|
1468
2671
|
}
|
|
1469
2672
|
};
|
|
1470
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
|
+
|
|
1471
2756
|
// src/client.ts
|
|
1472
2757
|
var SsoClient = class {
|
|
1473
2758
|
constructor(options) {
|
|
@@ -1475,6 +2760,9 @@ var SsoClient = class {
|
|
|
1475
2760
|
if (options.token) {
|
|
1476
2761
|
this.setAuthToken(options.token);
|
|
1477
2762
|
}
|
|
2763
|
+
if (options.apiKey) {
|
|
2764
|
+
this.setApiKey(options.apiKey);
|
|
2765
|
+
}
|
|
1478
2766
|
this.analytics = new AnalyticsModule(this.http);
|
|
1479
2767
|
this.auth = new AuthModule(this.http);
|
|
1480
2768
|
this.user = new UserModule(this.http);
|
|
@@ -1482,6 +2770,7 @@ var SsoClient = class {
|
|
|
1482
2770
|
this.services = new ServicesModule(this.http);
|
|
1483
2771
|
this.invitations = new InvitationsModule(this.http);
|
|
1484
2772
|
this.platform = new PlatformModule(this.http);
|
|
2773
|
+
this.serviceApi = new ServiceApiModule(this.http);
|
|
1485
2774
|
}
|
|
1486
2775
|
/**
|
|
1487
2776
|
* Sets the JWT for all subsequent authenticated requests.
|
|
@@ -1505,6 +2794,28 @@ var SsoClient = class {
|
|
|
1505
2794
|
delete this.http.defaults.headers.common["Authorization"];
|
|
1506
2795
|
}
|
|
1507
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
|
+
}
|
|
1508
2819
|
/**
|
|
1509
2820
|
* Gets the current base URL
|
|
1510
2821
|
*/
|
|
@@ -1517,6 +2828,7 @@ export {
|
|
|
1517
2828
|
InvitationsModule,
|
|
1518
2829
|
OrganizationsModule,
|
|
1519
2830
|
PlatformModule,
|
|
2831
|
+
ServiceApiModule,
|
|
1520
2832
|
ServicesModule,
|
|
1521
2833
|
SsoApiError,
|
|
1522
2834
|
SsoClient,
|