@dereekb/dbx-firebase 13.5.0 → 13.5.1
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/fesm2022/dereekb-dbx-firebase-oidc.mjs +1 -1
- package/fesm2022/dereekb-dbx-firebase-oidc.mjs.map +1 -1
- package/fesm2022/dereekb-dbx-firebase.mjs +159 -138
- package/fesm2022/dereekb-dbx-firebase.mjs.map +1 -1
- package/lib/auth/login/_login.scss +0 -4
- package/package.json +10 -10
- package/types/dereekb-dbx-firebase.d.ts +36 -39
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { inject, Injectable, provideAppInitializer, makeEnvironmentProviders, InjectionToken, Component, model, computed, ChangeDetectionStrategy, signal, Directive, EventEmitter, input, output, Injector, viewChild, HostListener, NgModule, ElementRef, forwardRef, effect, DestroyRef, Inject, Optional, Pipe } from '@angular/core';
|
|
3
3
|
import { DbxAnalyticsService } from '@dereekb/dbx-analytics';
|
|
4
4
|
import { asObservable, timeoutStartWith, filterMaybe, isNot, SubscriptionObject, lazyFrom, switchMapWhileTrue, loadingStateFromObs, distinctUntilKeysChange, cleanupDestroyable, iterationHasNextAndCanLoadMore, pageItemAccumulatorCurrentPage, accumulatorFlattenPageListLoadingState, useFirst, itemAccumulatorNextPageUntilResultsCount, iteratorNextPageUntilPage, iteratorNextPageUntilMaxPageLoadLimit, pageLoadingStateFromObs, useAsObservable, filterMaybeArray, mapEachAsync, invertObservableDecision, filterItemsWithObservableDecision, switchMapMaybe, beginLoading, mapLoadingStateValueWithOperator, valueFromFinishedLoadingState, skipInitialMaybe, distinctUntilModelKeyChange, successResult, errorResult, isLoadingStateLoading, cleanup, mapLoadingState, throwErrorFromLoadingStateError, maybeValueFromObservableOrValue, distinctUntilHasDifferentValues, MultiSubscriptionObject, startWithBeginLoading, skipAllInitialMaybe } from '@dereekb/rxjs';
|
|
5
|
-
import { switchMap, of, shareReplay, map, distinctUntilChanged, EMPTY, catchError, firstValueFrom, BehaviorSubject, combineLatest, first, from,
|
|
5
|
+
import { switchMap, of, shareReplay, map, Subject, merge, distinctUntilChanged, EMPTY, catchError, firstValueFrom, tap, BehaviorSubject, combineLatest, first, from, interval, exhaustMap, filter, take, startWith, throttleTime, NEVER, defaultIfEmpty, combineLatestWith, mergeMap, Observable } from 'rxjs';
|
|
6
6
|
import * as i2 from '@dereekb/dbx-core';
|
|
7
7
|
import { loggedInObsFromIsLoggedIn, loggedOutObsFromIsLoggedIn, authUserIdentifier, DbxInjectionContext, DBX_INJECTION_COMPONENT_DATA, DbxInjectionComponent, AbstractForwardDbxInjectionContextDirective, DbxInjectionContextDirective, DbxAuthService, DbxActionButtonDirective, completeOnDestroy, cleanSubscription, DbxActionDirective, DbxActionEnforceModifiedDirective, DbxActionHandlerDirective, DbxActionAutoTriggerDirective, clean, cleanLoadingContext, provideDbxRouteModelIdDirectiveDelegate, provideDbxRouteModelKeyDirectiveDelegate, AbstractIfDirective, LockSetComponentStore, newWithInjector, CutTextPipe, DbxActionContextStoreSourceInstance, DbxActionHandlerInstance, cleanSubscriptionWithLockSet, SimpleStorageAccessorFactory, dbxRouteParamReaderInstance, DbxRouteParamDefaultRedirectInstance } from '@dereekb/dbx-core';
|
|
8
8
|
import { Auth, authState, idToken, signInWithPopup, linkWithPopup, linkWithCredential, unlink, createUserWithEmailAndPassword, signInWithEmailAndPassword, signInAnonymously, reauthenticateWithPopup, OAuthProvider, FacebookAuthProvider, GithubAuthProvider, GoogleAuthProvider, TwitterAuthProvider, provideAuth, getAuth, connectAuthEmulator } from '@angular/fire/auth';
|
|
@@ -141,7 +141,14 @@ class DbxFirebaseAuthService {
|
|
|
141
141
|
firebaseAuth = inject(Auth);
|
|
142
142
|
delegate = inject(DbxFirebaseAuthServiceDelegate, { optional: true }) ?? DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE;
|
|
143
143
|
_authState$ = authState(this.firebaseAuth);
|
|
144
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Subject that triggers a re-emission of the current auth user.
|
|
146
|
+
*
|
|
147
|
+
* Useful after operations that mutate the {@link User} object in place (e.g., linking/unlinking providers)
|
|
148
|
+
* without triggering a new {@link authState} emission.
|
|
149
|
+
*/
|
|
150
|
+
_authUpdate$ = new Subject();
|
|
151
|
+
currentAuthUser$ = merge(this._authState$, this._authUpdate$.pipe(map(() => this.firebaseAuth.currentUser))).pipe(timeoutStartWith(null, 1000), shareReplay(1));
|
|
145
152
|
currentAuthUserInfo$ = this.currentAuthUser$.pipe(map((x) => (x ? authUserInfoFromAuthUser(x) : undefined)));
|
|
146
153
|
authUser$ = this.currentAuthUser$.pipe(filterMaybe());
|
|
147
154
|
authUserInfo$ = this.authUser$.pipe(map(authUserInfoFromAuthUser));
|
|
@@ -250,7 +257,7 @@ class DbxFirebaseAuthService {
|
|
|
250
257
|
else {
|
|
251
258
|
throw new Error('User is not logged in currently.');
|
|
252
259
|
}
|
|
253
|
-
})));
|
|
260
|
+
}), tap(() => this._authUpdate$.next())));
|
|
254
261
|
}
|
|
255
262
|
/**
|
|
256
263
|
* Links a credential to the current user. Useful for merging accounts
|
|
@@ -272,7 +279,7 @@ class DbxFirebaseAuthService {
|
|
|
272
279
|
else {
|
|
273
280
|
throw new Error('User is not logged in currently.');
|
|
274
281
|
}
|
|
275
|
-
})));
|
|
282
|
+
}), tap(() => this._authUpdate$.next())));
|
|
276
283
|
}
|
|
277
284
|
/**
|
|
278
285
|
* Unlinks an authentication provider from the current user.
|
|
@@ -293,7 +300,7 @@ class DbxFirebaseAuthService {
|
|
|
293
300
|
else {
|
|
294
301
|
throw new Error('User is not logged in currently.');
|
|
295
302
|
}
|
|
296
|
-
})));
|
|
303
|
+
}), tap(() => this._authUpdate$.next())));
|
|
297
304
|
}
|
|
298
305
|
registerWithEmailAndPassword(email, password) {
|
|
299
306
|
return createUserWithEmailAndPassword(this.firebaseAuth, email, password);
|
|
@@ -726,6 +733,73 @@ const OAUTH_FIREBASE_LOGIN_METHOD_CATEGORY = 'oauth';
|
|
|
726
733
|
class DbxFirebaseLoginContext extends DbxInjectionContext {
|
|
727
734
|
}
|
|
728
735
|
|
|
736
|
+
/**
|
|
737
|
+
* Map of Firebase provider IDs to known login method types.
|
|
738
|
+
*
|
|
739
|
+
* @example
|
|
740
|
+
* ```ts
|
|
741
|
+
* FIREBASE_PROVIDER_ID_TO_LOGIN_METHOD_TYPE_MAP['google.com']; // 'google'
|
|
742
|
+
* ```
|
|
743
|
+
*/
|
|
744
|
+
const FIREBASE_PROVIDER_ID_TO_LOGIN_METHOD_TYPE_MAP = {
|
|
745
|
+
'google.com': 'google',
|
|
746
|
+
'facebook.com': 'facebook',
|
|
747
|
+
'github.com': 'github',
|
|
748
|
+
'twitter.com': 'twitter',
|
|
749
|
+
'apple.com': 'apple',
|
|
750
|
+
'microsoft.com': 'microsoft',
|
|
751
|
+
phone: 'phone',
|
|
752
|
+
password: 'email'
|
|
753
|
+
};
|
|
754
|
+
/**
|
|
755
|
+
* Map of known login method types to Firebase provider IDs.
|
|
756
|
+
*
|
|
757
|
+
* @example
|
|
758
|
+
* ```ts
|
|
759
|
+
* LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP['google']; // 'google.com'
|
|
760
|
+
* ```
|
|
761
|
+
*/
|
|
762
|
+
const LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP = {
|
|
763
|
+
google: 'google.com',
|
|
764
|
+
facebook: 'facebook.com',
|
|
765
|
+
github: 'github.com',
|
|
766
|
+
twitter: 'twitter.com',
|
|
767
|
+
apple: 'apple.com',
|
|
768
|
+
microsoft: 'microsoft.com',
|
|
769
|
+
phone: 'phone',
|
|
770
|
+
email: 'password'
|
|
771
|
+
};
|
|
772
|
+
/**
|
|
773
|
+
* Converts a Firebase provider ID (e.g., 'google.com') to its corresponding login method type (e.g., 'google').
|
|
774
|
+
*
|
|
775
|
+
* @param providerId - The Firebase provider ID.
|
|
776
|
+
* @returns The matching login method type, or undefined if unknown.
|
|
777
|
+
*
|
|
778
|
+
* @example
|
|
779
|
+
* ```ts
|
|
780
|
+
* firebaseProviderIdToLoginMethodType('google.com'); // 'google'
|
|
781
|
+
* firebaseProviderIdToLoginMethodType('unknown.com'); // undefined
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
function firebaseProviderIdToLoginMethodType(providerId) {
|
|
785
|
+
return FIREBASE_PROVIDER_ID_TO_LOGIN_METHOD_TYPE_MAP[providerId];
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Converts a login method type (e.g., 'google') to its corresponding Firebase provider ID (e.g., 'google.com').
|
|
789
|
+
*
|
|
790
|
+
* @param type - The login method type.
|
|
791
|
+
* @returns The matching Firebase provider ID, or undefined if unknown.
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* ```ts
|
|
795
|
+
* loginMethodTypeToFirebaseProviderId('google'); // 'google.com'
|
|
796
|
+
* loginMethodTypeToFirebaseProviderId('unknown'); // undefined
|
|
797
|
+
* ```
|
|
798
|
+
*/
|
|
799
|
+
function loginMethodTypeToFirebaseProviderId(type) {
|
|
800
|
+
return LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP[type];
|
|
801
|
+
}
|
|
802
|
+
|
|
729
803
|
/**
|
|
730
804
|
* Renders a styled login button that triggers a login action handler on click.
|
|
731
805
|
*
|
|
@@ -737,8 +811,10 @@ class DbxFirebaseLoginButtonComponent {
|
|
|
737
811
|
iconSignal = computed(() => this.config()?.icon, ...(ngDevMode ? [{ debugName: "iconSignal" }] : /* istanbul ignore next */ []));
|
|
738
812
|
iconFilterSignal = computed(() => this.config()?.iconFilter, ...(ngDevMode ? [{ debugName: "iconFilterSignal" }] : /* istanbul ignore next */ []));
|
|
739
813
|
textSignal = computed(() => this.config()?.text ?? '', ...(ngDevMode ? [{ debugName: "textSignal" }] : /* istanbul ignore next */ []));
|
|
740
|
-
buttonColorSignal = computed(() => this.config()?.buttonColor ?? 'transparent', ...(ngDevMode ? [{ debugName: "buttonColorSignal" }] : /* istanbul ignore next */ []));
|
|
814
|
+
buttonColorSignal = computed(() => this.config()?.buttonColor ?? (this.config()?.color ? undefined : 'transparent'), ...(ngDevMode ? [{ debugName: "buttonColorSignal" }] : /* istanbul ignore next */ []));
|
|
741
815
|
buttonTextColorSignal = computed(() => this.config()?.buttonTextColor, ...(ngDevMode ? [{ debugName: "buttonTextColorSignal" }] : /* istanbul ignore next */ []));
|
|
816
|
+
colorSignal = computed(() => this.config()?.color, ...(ngDevMode ? [{ debugName: "colorSignal" }] : /* istanbul ignore next */ []));
|
|
817
|
+
confirmConfigSignal = computed(() => this.config()?.confirmConfig, ...(ngDevMode ? [{ debugName: "confirmConfigSignal" }] : /* istanbul ignore next */ []));
|
|
742
818
|
setConfig(config) {
|
|
743
819
|
this.config.set(config);
|
|
744
820
|
}
|
|
@@ -757,8 +833,8 @@ class DbxFirebaseLoginButtonComponent {
|
|
|
757
833
|
};
|
|
758
834
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: DbxFirebaseLoginButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
759
835
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: DbxFirebaseLoginButtonComponent, isStandalone: true, selector: "dbx-firebase-login-button", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { config: "configChange" }, host: { classAttribute: "dbx-firebase-login-button" }, ngImport: i0, template: `
|
|
760
|
-
<ng-container dbxAction [dbxActionHandler]="handleAction"
|
|
761
|
-
<dbx-button dbxActionButton [customTextColor]="buttonTextColorSignal()" [customButtonColor]="buttonColorSignal()" [raised]="true">
|
|
836
|
+
<ng-container dbxAction [dbxActionHandler]="handleAction" [dbxActionSuccessHandler]="onActionSuccess" [dbxActionConfirm]="confirmConfigSignal()" [dbxActionConfirmSkip]="!confirmConfigSignal()">
|
|
837
|
+
<dbx-button dbxActionButton [customTextColor]="buttonTextColorSignal()" [customButtonColor]="buttonColorSignal()" [raised]="true" [color]="colorSignal()">
|
|
762
838
|
<div class="dbx-firebase-login-button-content">
|
|
763
839
|
<span class="dbx-firebase-login-button-icon dbx-icon-spacer">
|
|
764
840
|
@if (iconUrlSignal()) {
|
|
@@ -772,15 +848,15 @@ class DbxFirebaseLoginButtonComponent {
|
|
|
772
848
|
</div>
|
|
773
849
|
</dbx-button>
|
|
774
850
|
</ng-container>
|
|
775
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: DbxActionModule }, { kind: "directive", type: i2.DbxActionDirective, selector: "dbx-action,[dbxAction]", exportAs: ["action", "dbxAction"] }, { kind: "directive", type: i2.DbxActionHandlerDirective, selector: "[dbxActionHandler]", inputs: ["dbxActionHandler"] }, { kind: "directive", type: i2.
|
|
851
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: DbxActionModule }, { kind: "directive", type: i2.DbxActionDirective, selector: "dbx-action,[dbxAction]", exportAs: ["action", "dbxAction"] }, { kind: "directive", type: i2.DbxActionHandlerDirective, selector: "[dbxActionHandler]", inputs: ["dbxActionHandler"] }, { kind: "directive", type: i2.DbxActionSuccessHandlerDirective, selector: "[dbxActionSuccessHandler]", inputs: ["dbxActionSuccessHandler"] }, { kind: "directive", type: i2.DbxActionButtonDirective, selector: "[dbxActionButton]" }, { kind: "directive", type: i1$1.DbxActionConfirmDirective, selector: "[dbxActionConfirm]", inputs: ["dbxActionConfirm", "dbxActionConfirmSkip"] }, { kind: "ngmodule", type: DbxButtonModule }, { kind: "component", type: i1$1.DbxButtonComponent, selector: "dbx-button", inputs: ["bar", "type", "buttonStyle", "color", "spinnerColor", "customButtonColor", "customTextColor", "customSpinnerColor", "basic", "tonal", "raised", "stroked", "flat", "iconOnly", "fab", "allowClickPropagation", "mode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
776
852
|
}
|
|
777
853
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: DbxFirebaseLoginButtonComponent, decorators: [{
|
|
778
854
|
type: Component,
|
|
779
855
|
args: [{
|
|
780
856
|
selector: 'dbx-firebase-login-button',
|
|
781
857
|
template: `
|
|
782
|
-
<ng-container dbxAction [dbxActionHandler]="handleAction"
|
|
783
|
-
<dbx-button dbxActionButton [customTextColor]="buttonTextColorSignal()" [customButtonColor]="buttonColorSignal()" [raised]="true">
|
|
858
|
+
<ng-container dbxAction [dbxActionHandler]="handleAction" [dbxActionSuccessHandler]="onActionSuccess" [dbxActionConfirm]="confirmConfigSignal()" [dbxActionConfirmSkip]="!confirmConfigSignal()">
|
|
859
|
+
<dbx-button dbxActionButton [customTextColor]="buttonTextColorSignal()" [customButtonColor]="buttonColorSignal()" [raised]="true" [color]="colorSignal()">
|
|
784
860
|
<div class="dbx-firebase-login-button-content">
|
|
785
861
|
<span class="dbx-firebase-login-button-icon dbx-icon-spacer">
|
|
786
862
|
@if (iconUrlSignal()) {
|
|
@@ -876,13 +952,16 @@ class AbstractConfiguredDbxFirebaseLoginButtonDirective {
|
|
|
876
952
|
ngOnInit() {
|
|
877
953
|
const assets = this.assetConfig;
|
|
878
954
|
const text = this._textForMode(assets);
|
|
955
|
+
const isUnlink = this.effectiveLoginMode === 'unlink';
|
|
879
956
|
this._config.set({
|
|
880
957
|
text,
|
|
881
|
-
icon: assets.loginIcon,
|
|
882
|
-
iconUrl: assets.logoUrl,
|
|
883
|
-
iconFilter: assets.logoFilter,
|
|
884
|
-
buttonColor: assets.backgroundColor,
|
|
885
|
-
buttonTextColor: assets.textColor,
|
|
958
|
+
icon: isUnlink ? 'link_off' : assets.loginIcon,
|
|
959
|
+
iconUrl: isUnlink ? undefined : assets.logoUrl,
|
|
960
|
+
iconFilter: isUnlink ? undefined : assets.logoFilter,
|
|
961
|
+
buttonColor: isUnlink ? undefined : assets.backgroundColor,
|
|
962
|
+
buttonTextColor: isUnlink ? undefined : assets.textColor,
|
|
963
|
+
color: isUnlink ? 'warn' : undefined,
|
|
964
|
+
confirmConfig: isUnlink ? { title: `Disconnect ${assets.providerName ?? 'Provider'}`, prompt: `Are you sure you want to disconnect ${assets.providerName ?? 'this provider'}?` } : undefined,
|
|
886
965
|
handleLogin: () => this._handleAction()
|
|
887
966
|
});
|
|
888
967
|
}
|
|
@@ -895,6 +974,19 @@ class AbstractConfiguredDbxFirebaseLoginButtonDirective {
|
|
|
895
974
|
handleLink() {
|
|
896
975
|
throw new Error(`Linking is not supported for the "${this.loginProvider}" provider.`);
|
|
897
976
|
}
|
|
977
|
+
/**
|
|
978
|
+
* Handles the unlink action by removing the provider from the current user.
|
|
979
|
+
* Uses the {@link LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP} to resolve the Firebase provider ID.
|
|
980
|
+
*
|
|
981
|
+
* @returns A promise that resolves when the unlink action completes.
|
|
982
|
+
*/
|
|
983
|
+
handleUnlink() {
|
|
984
|
+
const providerId = loginMethodTypeToFirebaseProviderId(this.loginProvider);
|
|
985
|
+
if (!providerId) {
|
|
986
|
+
throw new Error(`Unknown provider ID for login method type "${this.loginProvider}".`);
|
|
987
|
+
}
|
|
988
|
+
return this.dbxFirebaseAuthService.unlinkProvider(providerId);
|
|
989
|
+
}
|
|
898
990
|
get providerConfig() {
|
|
899
991
|
return this.dbxFirebaseAuthLoginService.getLoginProvider(this.loginProvider);
|
|
900
992
|
}
|
|
@@ -906,21 +998,31 @@ class AbstractConfiguredDbxFirebaseLoginButtonDirective {
|
|
|
906
998
|
}
|
|
907
999
|
_textForMode(assets) {
|
|
908
1000
|
let text;
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1001
|
+
switch (this.effectiveLoginMode) {
|
|
1002
|
+
case 'link':
|
|
1003
|
+
text = assets.linkText ?? (assets.providerName ? `Connect ${assets.providerName}` : '<linkText not configured>');
|
|
1004
|
+
break;
|
|
1005
|
+
case 'unlink':
|
|
1006
|
+
text = assets.unlinkText ?? (assets.providerName ? `Disconnect ${assets.providerName}` : '<unlinkText not configured>');
|
|
1007
|
+
break;
|
|
1008
|
+
default:
|
|
1009
|
+
text = assets.loginText ?? '<loginText not configured>';
|
|
1010
|
+
break;
|
|
914
1011
|
}
|
|
915
1012
|
return text;
|
|
916
1013
|
}
|
|
917
1014
|
_handleAction() {
|
|
918
1015
|
let promise;
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1016
|
+
switch (this.effectiveLoginMode) {
|
|
1017
|
+
case 'link':
|
|
1018
|
+
promise = this.handleLink();
|
|
1019
|
+
break;
|
|
1020
|
+
case 'unlink':
|
|
1021
|
+
promise = this.handleUnlink();
|
|
1022
|
+
break;
|
|
1023
|
+
default:
|
|
1024
|
+
promise = this.handleLogin();
|
|
1025
|
+
break;
|
|
924
1026
|
}
|
|
925
1027
|
return promise.catch((error) => {
|
|
926
1028
|
throw firebaseAuthErrorToReadableError(error);
|
|
@@ -1432,6 +1534,14 @@ function provideDbxFirebaseLogin(config) {
|
|
|
1432
1534
|
*/
|
|
1433
1535
|
class DbxFirebaseLoginListComponent {
|
|
1434
1536
|
dbxFirebaseAuthLoginService = inject(DbxFirebaseAuthLoginService);
|
|
1537
|
+
dbxFirebaseAuthService = inject(DbxFirebaseAuthService);
|
|
1538
|
+
_linkedProviderIds = toSignal(this.dbxFirebaseAuthService.currentLinkedProviderIds$, { initialValue: [] });
|
|
1539
|
+
/**
|
|
1540
|
+
* The login method types currently linked to the authenticated user.
|
|
1541
|
+
*/
|
|
1542
|
+
linkedMethodTypesSignal = computed(() => {
|
|
1543
|
+
return filterMaybeArrayValues(this._linkedProviderIds().map(firebaseProviderIdToLoginMethodType));
|
|
1544
|
+
}, ...(ngDevMode ? [{ debugName: "linkedMethodTypesSignal" }] : /* istanbul ignore next */ []));
|
|
1435
1545
|
loginMode = input('login', ...(ngDevMode ? [{ debugName: "loginMode" }] : /* istanbul ignore next */ []));
|
|
1436
1546
|
providerTypes = input(...(ngDevMode ? [undefined, { debugName: "providerTypes" }] : /* istanbul ignore next */ []));
|
|
1437
1547
|
omitProviderTypes = input(...(ngDevMode ? [undefined, { debugName: "omitProviderTypes" }] : /* istanbul ignore next */ []));
|
|
@@ -1439,7 +1549,15 @@ class DbxFirebaseLoginListComponent {
|
|
|
1439
1549
|
providerTypesSignal = computed(() => {
|
|
1440
1550
|
const providerTypes = this.providerTypes();
|
|
1441
1551
|
const omitProviderTypes = this.omitProviderTypes();
|
|
1442
|
-
const
|
|
1552
|
+
const loginMode = this.loginMode();
|
|
1553
|
+
let baseTypes;
|
|
1554
|
+
if (loginMode === 'unlink') {
|
|
1555
|
+
// In unlink mode, show only currently linked providers
|
|
1556
|
+
baseTypes = this.linkedMethodTypesSignal();
|
|
1557
|
+
}
|
|
1558
|
+
else {
|
|
1559
|
+
baseTypes = providerTypes ? asArray(providerTypes) : this.dbxFirebaseAuthLoginService.getEnabledTypes();
|
|
1560
|
+
}
|
|
1443
1561
|
return omitProviderTypes ? excludeValuesFromArray(baseTypes, asArray(omitProviderTypes)) : baseTypes;
|
|
1444
1562
|
}, ...(ngDevMode ? [{ debugName: "providerTypesSignal" }] : /* istanbul ignore next */ []));
|
|
1445
1563
|
providersSignal = computed(() => {
|
|
@@ -1464,6 +1582,10 @@ class DbxFirebaseLoginListComponent {
|
|
|
1464
1582
|
providers = providers.filter((x) => x.allowLinking !== false);
|
|
1465
1583
|
mapFn = (x) => ({ componentClass: x.componentClass, loginMethodType: x.loginMethodType, data: { loginMode } });
|
|
1466
1584
|
break;
|
|
1585
|
+
case 'unlink':
|
|
1586
|
+
providers = providers.filter((x) => x.allowLinking !== false);
|
|
1587
|
+
mapFn = (x) => ({ componentClass: x.componentClass, loginMethodType: x.loginMethodType, data: { loginMode } });
|
|
1588
|
+
break;
|
|
1467
1589
|
default:
|
|
1468
1590
|
mapFn = (x) => ({ componentClass: x.componentClass, loginMethodType: x.loginMethodType, data: { loginMode } });
|
|
1469
1591
|
break;
|
|
@@ -1471,7 +1593,7 @@ class DbxFirebaseLoginListComponent {
|
|
|
1471
1593
|
return providers.map(mapFn);
|
|
1472
1594
|
}, ...(ngDevMode ? [{ debugName: "providersInjectionConfigsSignal" }] : /* istanbul ignore next */ []));
|
|
1473
1595
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: DbxFirebaseLoginListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1474
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: DbxFirebaseLoginListComponent, isStandalone: true, selector: "dbx-firebase-login-list", inputs: { loginMode: { classPropertyName: "loginMode", publicName: "loginMode", isSignal: true, isRequired: false, transformFunction: null }, providerTypes: { classPropertyName: "providerTypes", publicName: "providerTypes", isSignal: true, isRequired: false, transformFunction: null }, omitProviderTypes: { classPropertyName: "omitProviderTypes", publicName: "omitProviderTypes", isSignal: true, isRequired: false, transformFunction: null }, providerCategories: { classPropertyName: "providerCategories", publicName: "providerCategories", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "dbx-firebase-login-list" }, ngImport: i0, template: `
|
|
1596
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: DbxFirebaseLoginListComponent, isStandalone: true, selector: "dbx-firebase-login-list", inputs: { loginMode: { classPropertyName: "loginMode", publicName: "loginMode", isSignal: true, isRequired: false, transformFunction: null }, providerTypes: { classPropertyName: "providerTypes", publicName: "providerTypes", isSignal: true, isRequired: false, transformFunction: null }, omitProviderTypes: { classPropertyName: "omitProviderTypes", publicName: "omitProviderTypes", isSignal: true, isRequired: false, transformFunction: null }, providerCategories: { classPropertyName: "providerCategories", publicName: "providerCategories", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "dbx-firebase-login-list dbx-button-column" }, ngImport: i0, template: `
|
|
1475
1597
|
@for (config of providersInjectionConfigsSignal(); track config.loginMethodType) {
|
|
1476
1598
|
<div class="dbx-firebase-login-item">
|
|
1477
1599
|
<dbx-injection [config]="config"></dbx-injection>
|
|
@@ -1491,7 +1613,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImpor
|
|
|
1491
1613
|
}
|
|
1492
1614
|
`,
|
|
1493
1615
|
host: {
|
|
1494
|
-
class: 'dbx-firebase-login-list'
|
|
1616
|
+
class: 'dbx-firebase-login-list dbx-button-column'
|
|
1495
1617
|
},
|
|
1496
1618
|
standalone: true,
|
|
1497
1619
|
imports: [DbxInjectionComponent]
|
|
@@ -1638,73 +1760,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImpor
|
|
|
1638
1760
|
}]
|
|
1639
1761
|
}] });
|
|
1640
1762
|
|
|
1641
|
-
/**
|
|
1642
|
-
* Map of Firebase provider IDs to known login method types.
|
|
1643
|
-
*
|
|
1644
|
-
* @example
|
|
1645
|
-
* ```ts
|
|
1646
|
-
* FIREBASE_PROVIDER_ID_TO_LOGIN_METHOD_TYPE_MAP['google.com']; // 'google'
|
|
1647
|
-
* ```
|
|
1648
|
-
*/
|
|
1649
|
-
const FIREBASE_PROVIDER_ID_TO_LOGIN_METHOD_TYPE_MAP = {
|
|
1650
|
-
'google.com': 'google',
|
|
1651
|
-
'facebook.com': 'facebook',
|
|
1652
|
-
'github.com': 'github',
|
|
1653
|
-
'twitter.com': 'twitter',
|
|
1654
|
-
'apple.com': 'apple',
|
|
1655
|
-
'microsoft.com': 'microsoft',
|
|
1656
|
-
phone: 'phone',
|
|
1657
|
-
password: 'email'
|
|
1658
|
-
};
|
|
1659
|
-
/**
|
|
1660
|
-
* Map of known login method types to Firebase provider IDs.
|
|
1661
|
-
*
|
|
1662
|
-
* @example
|
|
1663
|
-
* ```ts
|
|
1664
|
-
* LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP['google']; // 'google.com'
|
|
1665
|
-
* ```
|
|
1666
|
-
*/
|
|
1667
|
-
const LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP = {
|
|
1668
|
-
google: 'google.com',
|
|
1669
|
-
facebook: 'facebook.com',
|
|
1670
|
-
github: 'github.com',
|
|
1671
|
-
twitter: 'twitter.com',
|
|
1672
|
-
apple: 'apple.com',
|
|
1673
|
-
microsoft: 'microsoft.com',
|
|
1674
|
-
phone: 'phone',
|
|
1675
|
-
email: 'password'
|
|
1676
|
-
};
|
|
1677
|
-
/**
|
|
1678
|
-
* Converts a Firebase provider ID (e.g., 'google.com') to its corresponding login method type (e.g., 'google').
|
|
1679
|
-
*
|
|
1680
|
-
* @param providerId - The Firebase provider ID.
|
|
1681
|
-
* @returns The matching login method type, or undefined if unknown.
|
|
1682
|
-
*
|
|
1683
|
-
* @example
|
|
1684
|
-
* ```ts
|
|
1685
|
-
* firebaseProviderIdToLoginMethodType('google.com'); // 'google'
|
|
1686
|
-
* firebaseProviderIdToLoginMethodType('unknown.com'); // undefined
|
|
1687
|
-
* ```
|
|
1688
|
-
*/
|
|
1689
|
-
function firebaseProviderIdToLoginMethodType(providerId) {
|
|
1690
|
-
return FIREBASE_PROVIDER_ID_TO_LOGIN_METHOD_TYPE_MAP[providerId];
|
|
1691
|
-
}
|
|
1692
|
-
/**
|
|
1693
|
-
* Converts a login method type (e.g., 'google') to its corresponding Firebase provider ID (e.g., 'google.com').
|
|
1694
|
-
*
|
|
1695
|
-
* @param type - The login method type.
|
|
1696
|
-
* @returns The matching Firebase provider ID, or undefined if unknown.
|
|
1697
|
-
*
|
|
1698
|
-
* @example
|
|
1699
|
-
* ```ts
|
|
1700
|
-
* loginMethodTypeToFirebaseProviderId('google'); // 'google.com'
|
|
1701
|
-
* loginMethodTypeToFirebaseProviderId('unknown'); // undefined
|
|
1702
|
-
* ```
|
|
1703
|
-
*/
|
|
1704
|
-
function loginMethodTypeToFirebaseProviderId(type) {
|
|
1705
|
-
return LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP[type];
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
1763
|
/**
|
|
1709
1764
|
* Component for managing linked authentication providers on a user account.
|
|
1710
1765
|
*
|
|
@@ -1721,47 +1776,19 @@ class DbxFirebaseManageAuthProvidersComponent {
|
|
|
1721
1776
|
dbxFirebaseAuthService = inject(DbxFirebaseAuthService);
|
|
1722
1777
|
dbxFirebaseAuthLoginService = inject(DbxFirebaseAuthLoginService);
|
|
1723
1778
|
_linkedProviderIds = toSignal(this.dbxFirebaseAuthService.currentLinkedProviderIds$, { initialValue: [] });
|
|
1724
|
-
linkedProvidersSignal = computed(() => {
|
|
1725
|
-
const providerIds = this._linkedProviderIds();
|
|
1726
|
-
return providerIds.map((providerId) => {
|
|
1727
|
-
const loginMethodType = firebaseProviderIdToLoginMethodType(providerId);
|
|
1728
|
-
const assets = loginMethodType ? this.dbxFirebaseAuthLoginService.getProviderAssets(loginMethodType) : undefined;
|
|
1729
|
-
const providerName = assets?.providerName ?? providerId;
|
|
1730
|
-
const unlinkText = assets?.unlinkText ?? `Disconnect ${providerName}`;
|
|
1731
|
-
return { providerId, loginMethodType, providerName, unlinkText, assets };
|
|
1732
|
-
});
|
|
1733
|
-
}, ...(ngDevMode ? [{ debugName: "linkedProvidersSignal" }] : /* istanbul ignore next */ []));
|
|
1734
1779
|
linkedMethodTypesSignal = computed(() => {
|
|
1735
|
-
return filterMaybeArrayValues(this.
|
|
1780
|
+
return filterMaybeArrayValues(this._linkedProviderIds().map(firebaseProviderIdToLoginMethodType));
|
|
1736
1781
|
}, ...(ngDevMode ? [{ debugName: "linkedMethodTypesSignal" }] : /* istanbul ignore next */ []));
|
|
1737
1782
|
showLinkSectionSignal = computed(() => {
|
|
1738
1783
|
const linkedTypes = new Set(this.linkedMethodTypesSignal());
|
|
1739
1784
|
const oauthProviders = this.dbxFirebaseAuthLoginService.getLinkProviders(this.dbxFirebaseAuthLoginService.getEnabledTypes());
|
|
1740
1785
|
return oauthProviders.some((p) => p.category === OAUTH_FIREBASE_LOGIN_METHOD_CATEGORY && !linkedTypes.has(p.loginMethodType));
|
|
1741
1786
|
}, ...(ngDevMode ? [{ debugName: "showLinkSectionSignal" }] : /* istanbul ignore next */ []));
|
|
1742
|
-
/**
|
|
1743
|
-
* Creates a work handler for unlinking a specific provider.
|
|
1744
|
-
*
|
|
1745
|
-
* @param providerId - The Firebase provider ID to unlink (e.g., 'google.com').
|
|
1746
|
-
* @returns A {@link WorkUsingContext} handler that unlinking the provider on execution.
|
|
1747
|
-
*/
|
|
1748
|
-
makeUnlinkHandler(providerId) {
|
|
1749
|
-
return (_, context) => {
|
|
1750
|
-
const promise = this.dbxFirebaseAuthService.unlinkProvider(providerId);
|
|
1751
|
-
context.startWorkingWithPromise(promise);
|
|
1752
|
-
};
|
|
1753
|
-
}
|
|
1754
1787
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: DbxFirebaseManageAuthProvidersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1755
1788
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: DbxFirebaseManageAuthProvidersComponent, isStandalone: true, selector: "dbx-firebase-manage-auth-providers", host: { classAttribute: "d-block dbx-firebase-manage-auth-providers" }, ngImport: i0, template: `
|
|
1756
|
-
@if (
|
|
1789
|
+
@if (linkedMethodTypesSignal().length) {
|
|
1757
1790
|
<dbx-section header="Connected Providers">
|
|
1758
|
-
|
|
1759
|
-
<div class="dbx-firebase-manage-provider-item">
|
|
1760
|
-
<ng-container dbxAction [dbxActionHandler]="makeUnlinkHandler(provider.providerId)" dbxActionValue>
|
|
1761
|
-
<dbx-button dbxActionButton [text]="provider.unlinkText" icon="link_off" color="warn"></dbx-button>
|
|
1762
|
-
</ng-container>
|
|
1763
|
-
</div>
|
|
1764
|
-
}
|
|
1791
|
+
<dbx-firebase-login loginMode="unlink" providerCategories="oauth"></dbx-firebase-login>
|
|
1765
1792
|
</dbx-section>
|
|
1766
1793
|
}
|
|
1767
1794
|
@if (showLinkSectionSignal()) {
|
|
@@ -1769,24 +1796,18 @@ class DbxFirebaseManageAuthProvidersComponent {
|
|
|
1769
1796
|
<dbx-firebase-login loginMode="link" [omitProviderTypes]="linkedMethodTypesSignal()" providerCategories="oauth"></dbx-firebase-login>
|
|
1770
1797
|
</dbx-section>
|
|
1771
1798
|
}
|
|
1772
|
-
`, isInline: true, dependencies: [{ kind: "component", type: DbxFirebaseLoginComponent, selector: "dbx-firebase-login", inputs: ["loginMode", "providerTypes", "omitProviderTypes", "providerCategories"] }, { kind: "component", type: DbxSectionComponent, selector: "dbx-section", inputs: ["elevate"] }
|
|
1799
|
+
`, isInline: true, dependencies: [{ kind: "component", type: DbxFirebaseLoginComponent, selector: "dbx-firebase-login", inputs: ["loginMode", "providerTypes", "omitProviderTypes", "providerCategories"] }, { kind: "component", type: DbxSectionComponent, selector: "dbx-section", inputs: ["elevate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1773
1800
|
}
|
|
1774
1801
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: DbxFirebaseManageAuthProvidersComponent, decorators: [{
|
|
1775
1802
|
type: Component,
|
|
1776
1803
|
args: [{
|
|
1777
1804
|
selector: 'dbx-firebase-manage-auth-providers',
|
|
1778
1805
|
standalone: true,
|
|
1779
|
-
imports: [DbxFirebaseLoginComponent, DbxSectionComponent
|
|
1806
|
+
imports: [DbxFirebaseLoginComponent, DbxSectionComponent],
|
|
1780
1807
|
template: `
|
|
1781
|
-
@if (
|
|
1808
|
+
@if (linkedMethodTypesSignal().length) {
|
|
1782
1809
|
<dbx-section header="Connected Providers">
|
|
1783
|
-
|
|
1784
|
-
<div class="dbx-firebase-manage-provider-item">
|
|
1785
|
-
<ng-container dbxAction [dbxActionHandler]="makeUnlinkHandler(provider.providerId)" dbxActionValue>
|
|
1786
|
-
<dbx-button dbxActionButton [text]="provider.unlinkText" icon="link_off" color="warn"></dbx-button>
|
|
1787
|
-
</ng-container>
|
|
1788
|
-
</div>
|
|
1789
|
-
}
|
|
1810
|
+
<dbx-firebase-login loginMode="unlink" providerCategories="oauth"></dbx-firebase-login>
|
|
1790
1811
|
</dbx-section>
|
|
1791
1812
|
}
|
|
1792
1813
|
@if (showLinkSectionSignal()) {
|
|
@@ -4196,7 +4217,7 @@ class DbxFirebaseDocumentStoreContextStore extends ComponentStore {
|
|
|
4196
4217
|
lastStoresChangeAt$ = this.select((state) => state.lastStoresChangeAt).pipe(distinctUntilChanged(isSameDate), shareReplay(1));
|
|
4197
4218
|
entriesGroupedByIdentity$ = this.stores$.pipe(switchMap((stores) => {
|
|
4198
4219
|
let entriesObs;
|
|
4199
|
-
const allEntries =
|
|
4220
|
+
const allEntries = Array.from(stores.values());
|
|
4200
4221
|
const { included: hasIdentity, excluded: noIdentity } = separateValues(allEntries, (x) => x.modelIdentity != null);
|
|
4201
4222
|
if (noIdentity.length > 0) {
|
|
4202
4223
|
entriesObs = combineLatest(noIdentity.map((entryWithoutCachedIdentity) => entryWithoutCachedIdentity.store.modelIdentity$.pipe(first(), map((z) => {
|