@progalaxyelabs/ngx-stonescriptphp-client 1.17.1 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -602,6 +602,289 @@ function provideNgxStoneScriptPhpClient(environment, plugin) {
|
|
|
602
602
|
]);
|
|
603
603
|
}
|
|
604
604
|
|
|
605
|
+
/**
|
|
606
|
+
* Auth plugin for progalaxyelabs-auth (Rust/Axum).
|
|
607
|
+
*
|
|
608
|
+
* Speaks the Rust auth server's native format:
|
|
609
|
+
* - Login: { access_token, refresh_token, identity, membership, ... }
|
|
610
|
+
* - Tenant selection: { requires_tenant_selection, selection_token, memberships }
|
|
611
|
+
* - New identity: { access_token, identity, is_new_identity, memberships:[] }
|
|
612
|
+
* - select-tenant: Bearer header + { tenant_id } body
|
|
613
|
+
* - refresh: { access_token, refresh_token } body mode
|
|
614
|
+
*/
|
|
615
|
+
class ProgalaxyElabsAuth {
|
|
616
|
+
config;
|
|
617
|
+
constructor(config) {
|
|
618
|
+
this.config = config;
|
|
619
|
+
}
|
|
620
|
+
get host() {
|
|
621
|
+
return this.config.host;
|
|
622
|
+
}
|
|
623
|
+
// -- Login ----------------------------------------------------------------
|
|
624
|
+
async login(email, password) {
|
|
625
|
+
try {
|
|
626
|
+
const response = await fetch(`${this.host}/api/auth/login`, {
|
|
627
|
+
method: 'POST',
|
|
628
|
+
headers: { 'Content-Type': 'application/json' },
|
|
629
|
+
body: JSON.stringify({ email, password, platform: this.config.platformCode })
|
|
630
|
+
});
|
|
631
|
+
const data = await response.json();
|
|
632
|
+
if (!response.ok) {
|
|
633
|
+
return { success: false, message: data.error || data.message || 'Login failed' };
|
|
634
|
+
}
|
|
635
|
+
return this.handleLoginResponse(data);
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
return { success: false, message: 'Network error. Please try again.' };
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
async register(email, password, displayName) {
|
|
642
|
+
try {
|
|
643
|
+
const response = await fetch(`${this.host}/api/auth/register`, {
|
|
644
|
+
method: 'POST',
|
|
645
|
+
headers: { 'Content-Type': 'application/json' },
|
|
646
|
+
body: JSON.stringify({
|
|
647
|
+
email,
|
|
648
|
+
password,
|
|
649
|
+
display_name: displayName,
|
|
650
|
+
platform: this.config.platformCode
|
|
651
|
+
})
|
|
652
|
+
});
|
|
653
|
+
const data = await response.json();
|
|
654
|
+
if (!response.ok) {
|
|
655
|
+
return { success: false, message: data.error || data.message || 'Registration failed' };
|
|
656
|
+
}
|
|
657
|
+
return this.handleLoginResponse(data);
|
|
658
|
+
}
|
|
659
|
+
catch {
|
|
660
|
+
return { success: false, message: 'Network error. Please try again.' };
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
// -- Logout ---------------------------------------------------------------
|
|
664
|
+
async logout(refreshToken) {
|
|
665
|
+
try {
|
|
666
|
+
await fetch(`${this.host}/api/auth/logout`, {
|
|
667
|
+
method: 'POST',
|
|
668
|
+
headers: { 'Content-Type': 'application/json' },
|
|
669
|
+
body: JSON.stringify({ refresh_token: refreshToken })
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
catch { /* ignore */ }
|
|
673
|
+
}
|
|
674
|
+
// -- Session & Refresh ----------------------------------------------------
|
|
675
|
+
async checkSession() {
|
|
676
|
+
return { success: false };
|
|
677
|
+
}
|
|
678
|
+
async refresh(accessToken, refreshToken) {
|
|
679
|
+
if (!refreshToken)
|
|
680
|
+
return null;
|
|
681
|
+
try {
|
|
682
|
+
const response = await fetch(`${this.host}/api/auth/refresh`, {
|
|
683
|
+
method: 'POST',
|
|
684
|
+
headers: { 'Content-Type': 'application/json' },
|
|
685
|
+
body: JSON.stringify({ access_token: accessToken, refresh_token: refreshToken })
|
|
686
|
+
});
|
|
687
|
+
if (!response.ok)
|
|
688
|
+
return null;
|
|
689
|
+
const data = await response.json();
|
|
690
|
+
// Refresh can also return tenant_selection if memberships changed
|
|
691
|
+
if (data.requires_tenant_selection)
|
|
692
|
+
return null;
|
|
693
|
+
return data.access_token ?? null;
|
|
694
|
+
}
|
|
695
|
+
catch {
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
// -- Tenant operations ----------------------------------------------------
|
|
700
|
+
async selectTenant(tenantId, selectionToken) {
|
|
701
|
+
try {
|
|
702
|
+
const response = await fetch(`${this.host}/api/auth/select-tenant`, {
|
|
703
|
+
method: 'POST',
|
|
704
|
+
headers: {
|
|
705
|
+
'Authorization': `Bearer ${selectionToken}`,
|
|
706
|
+
'Content-Type': 'application/json'
|
|
707
|
+
},
|
|
708
|
+
body: JSON.stringify({ tenant_id: tenantId })
|
|
709
|
+
});
|
|
710
|
+
const data = await response.json();
|
|
711
|
+
if (!response.ok) {
|
|
712
|
+
return { success: false, message: data.error || data.message || 'Tenant selection failed' };
|
|
713
|
+
}
|
|
714
|
+
return {
|
|
715
|
+
success: true,
|
|
716
|
+
accessToken: data.access_token,
|
|
717
|
+
refreshToken: data.refresh_token,
|
|
718
|
+
user: this.toUser(data.identity),
|
|
719
|
+
membership: this.toMembership(data.membership),
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
catch {
|
|
723
|
+
return { success: false, message: 'Network error. Please try again.' };
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
async getTenantMemberships(accessToken) {
|
|
727
|
+
try {
|
|
728
|
+
const platformCode = encodeURIComponent(this.config.platformCode);
|
|
729
|
+
const response = await fetch(`${this.host}/api/auth/memberships?platform_code=${platformCode}`, {
|
|
730
|
+
method: 'GET',
|
|
731
|
+
headers: { 'Authorization': `Bearer ${accessToken}` }
|
|
732
|
+
});
|
|
733
|
+
if (!response.ok)
|
|
734
|
+
return [];
|
|
735
|
+
const data = await response.json();
|
|
736
|
+
return (data.memberships || []).map((m) => this.toMembership(m));
|
|
737
|
+
}
|
|
738
|
+
catch {
|
|
739
|
+
return [];
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
async checkTenantSlugAvailable(slug) {
|
|
743
|
+
try {
|
|
744
|
+
const response = await fetch(`${this.host}/api/auth/check-tenant-slug/${slug}`);
|
|
745
|
+
const data = await response.json();
|
|
746
|
+
return { available: data.available || false, suggestion: data.suggestion };
|
|
747
|
+
}
|
|
748
|
+
catch {
|
|
749
|
+
return { available: true };
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
async checkOnboardingStatus(identityId, platformCode) {
|
|
753
|
+
const platform = platformCode ?? this.config.platformCode;
|
|
754
|
+
const response = await fetch(`${this.host}/api/auth/onboarding/status?platform_code=${platform}&identity_id=${identityId}`);
|
|
755
|
+
if (!response.ok)
|
|
756
|
+
throw new Error('Failed to check onboarding status');
|
|
757
|
+
return response.json();
|
|
758
|
+
}
|
|
759
|
+
async checkEmail(email) {
|
|
760
|
+
try {
|
|
761
|
+
const response = await fetch(`${this.host}/api/auth/check-email`, {
|
|
762
|
+
method: 'POST',
|
|
763
|
+
headers: { 'Content-Type': 'application/json' },
|
|
764
|
+
body: JSON.stringify({ email })
|
|
765
|
+
});
|
|
766
|
+
const data = await response.json();
|
|
767
|
+
return { exists: data.exists, user: data.user };
|
|
768
|
+
}
|
|
769
|
+
catch {
|
|
770
|
+
return { exists: false };
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
// -- OAuth ----------------------------------------------------------------
|
|
774
|
+
async loginWithProvider(provider) {
|
|
775
|
+
return new Promise((resolve) => {
|
|
776
|
+
const width = 500, height = 600;
|
|
777
|
+
const left = (window.screen.width - width) / 2;
|
|
778
|
+
const top = (window.screen.height - height) / 2;
|
|
779
|
+
const oauthUrl = `${this.host}/oauth/${provider}?platform=${this.config.platformCode}&mode=popup`;
|
|
780
|
+
const popup = window.open(oauthUrl, `${provider}_login`, `width=${width},height=${height},left=${left},top=${top}`);
|
|
781
|
+
if (!popup) {
|
|
782
|
+
resolve({ success: false, message: 'Popup blocked. Please allow popups for this site.' });
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const cleanup = () => {
|
|
786
|
+
window.removeEventListener('message', messageHandler);
|
|
787
|
+
clearInterval(checkClosed);
|
|
788
|
+
if (popup && !popup.closed)
|
|
789
|
+
popup.close();
|
|
790
|
+
};
|
|
791
|
+
const messageHandler = (event) => {
|
|
792
|
+
if (event.origin !== new URL(this.host).origin)
|
|
793
|
+
return;
|
|
794
|
+
cleanup();
|
|
795
|
+
if (event.data.type === 'oauth_success') {
|
|
796
|
+
resolve({
|
|
797
|
+
success: true,
|
|
798
|
+
accessToken: event.data.access_token,
|
|
799
|
+
refreshToken: event.data.refresh_token,
|
|
800
|
+
user: this.toUser(event.data.user || event.data.identity),
|
|
801
|
+
membership: event.data.membership ? this.toMembership(event.data.membership) : undefined,
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
else if (event.data.type === 'oauth_tenant_selection') {
|
|
805
|
+
resolve({
|
|
806
|
+
success: true,
|
|
807
|
+
accessToken: event.data.selection_token,
|
|
808
|
+
memberships: (event.data.memberships || []).map((m) => this.toMembership(m)),
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
else if (event.data.type === 'oauth_new_identity') {
|
|
812
|
+
resolve({
|
|
813
|
+
success: true,
|
|
814
|
+
accessToken: event.data.access_token,
|
|
815
|
+
refreshToken: event.data.refresh_token,
|
|
816
|
+
isNewIdentity: true,
|
|
817
|
+
authMethod: event.data.auth_method,
|
|
818
|
+
oauthProvider: event.data.oauth_provider,
|
|
819
|
+
identity: event.data.identity,
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
else if (event.data.type === 'oauth_error') {
|
|
823
|
+
resolve({ success: false, message: event.data.message || 'OAuth login failed' });
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
window.addEventListener('message', messageHandler);
|
|
827
|
+
const checkClosed = setInterval(() => {
|
|
828
|
+
if (popup.closed) {
|
|
829
|
+
clearInterval(checkClosed);
|
|
830
|
+
window.removeEventListener('message', messageHandler);
|
|
831
|
+
resolve({ success: false, message: 'Login cancelled' });
|
|
832
|
+
}
|
|
833
|
+
}, 500);
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
// -- Internal helpers -----------------------------------------------------
|
|
837
|
+
handleLoginResponse(data) {
|
|
838
|
+
// New identity — needs onboarding
|
|
839
|
+
if (data.is_new_identity) {
|
|
840
|
+
return {
|
|
841
|
+
success: true,
|
|
842
|
+
accessToken: data.access_token,
|
|
843
|
+
refreshToken: data.refresh_token,
|
|
844
|
+
isNewIdentity: true,
|
|
845
|
+
authMethod: data.auth_method,
|
|
846
|
+
oauthProvider: data.oauth_provider,
|
|
847
|
+
identity: data.identity,
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
// Multi-tenant selection required
|
|
851
|
+
if (data.requires_tenant_selection) {
|
|
852
|
+
return {
|
|
853
|
+
success: true,
|
|
854
|
+
accessToken: data.selection_token,
|
|
855
|
+
memberships: (data.memberships || []).map((m) => this.toMembership(m)),
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
// Standard success (single tenant auto-selected or tenant specified)
|
|
859
|
+
return {
|
|
860
|
+
success: true,
|
|
861
|
+
accessToken: data.access_token,
|
|
862
|
+
refreshToken: data.refresh_token,
|
|
863
|
+
user: this.toUser(data.identity),
|
|
864
|
+
membership: this.toMembership(data.membership),
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
toUser(raw) {
|
|
868
|
+
if (!raw)
|
|
869
|
+
return undefined;
|
|
870
|
+
return {
|
|
871
|
+
email: raw.email,
|
|
872
|
+
display_name: raw.display_name ?? raw.email?.split('@')[0] ?? '',
|
|
873
|
+
photo_url: raw.photo_url ?? raw.picture,
|
|
874
|
+
is_email_verified: raw.is_email_verified ?? false
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
toMembership(raw) {
|
|
878
|
+
return {
|
|
879
|
+
tenant_id: raw.tenant_id,
|
|
880
|
+
slug: raw.tenant_slug ?? raw.slug ?? '',
|
|
881
|
+
name: raw.tenant_name ?? raw.name ?? '',
|
|
882
|
+
role: raw.role ?? '',
|
|
883
|
+
status: raw.status ?? 'active',
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
605
888
|
class ApiResponse {
|
|
606
889
|
status;
|
|
607
890
|
data;
|
|
@@ -3925,5 +4208,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
3925
4208
|
* Generated bundle index. Do not edit.
|
|
3926
4209
|
*/
|
|
3927
4210
|
|
|
3928
|
-
export { AUTH_PLUGIN, ApiConnectionService, ApiResponse, AuthPageComponent, AuthService, CsrfService, DbService, FilesService, LoginDialogComponent, MyEnvironmentModel, ProviderRegistryService, RegisterComponent, SigninStatusService, StoneScriptPHPAuth, TenantLoginComponent, TenantLoginDialogComponent, TenantRegisterComponent, TenantRegisterDialogComponent, TokenService, VerifyStatus, provideNgxStoneScriptPhpClient };
|
|
4211
|
+
export { AUTH_PLUGIN, ApiConnectionService, ApiResponse, AuthPageComponent, AuthService, CsrfService, DbService, FilesService, LoginDialogComponent, MyEnvironmentModel, ProgalaxyElabsAuth, ProviderRegistryService, RegisterComponent, SigninStatusService, StoneScriptPHPAuth, TenantLoginComponent, TenantLoginDialogComponent, TenantRegisterComponent, TenantRegisterDialogComponent, TokenService, VerifyStatus, provideNgxStoneScriptPhpClient };
|
|
3929
4212
|
//# sourceMappingURL=progalaxyelabs-ngx-stonescriptphp-client.mjs.map
|