@sneat/auth-core 0.27.36 → 0.27.38
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/esm2022/lib/user/init-user-record-request.js +51 -0
- package/esm2022/lib/user/init-user-record-request.js.map +1 -0
- package/esm2022/lib/user/sneat-user.service.js +3 -9
- package/esm2022/lib/user/sneat-user.service.js.map +1 -1
- package/lib/user/init-user-record-request.d.ts +15 -0
- package/package.json +1 -1
- package/tsconfig.lib.prod.tsbuildinfo +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The auth provider IDs that `POST /v0/users/init_user_record` accepts: the server's `knownAuthProviderIDs`
|
|
3
|
+
* (strongoapp `strongoauth`). Any other value, including Firebase's own `"firebase"`, answers 400
|
|
4
|
+
* `authProvider: supported auth providers=...`.
|
|
5
|
+
*/
|
|
6
|
+
export const INIT_USER_RECORD_AUTH_PROVIDERS = [
|
|
7
|
+
'password',
|
|
8
|
+
'emailLink',
|
|
9
|
+
'phone',
|
|
10
|
+
'google.com',
|
|
11
|
+
'facebook.com',
|
|
12
|
+
'twitter.com',
|
|
13
|
+
'github.com',
|
|
14
|
+
'microsoft.com',
|
|
15
|
+
'apple.com',
|
|
16
|
+
'yahoo.com',
|
|
17
|
+
'telegram',
|
|
18
|
+
'custom',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* The provider to report for a signed-in Firebase user. `user.providerId` is `"firebase"` for an account that has
|
|
22
|
+
* more than one linked provider (Google plus GitHub, say), which the server rejects with 400, so the first linked
|
|
23
|
+
* provider the server knows is reported instead. `undefined` when none is known: the field is then left out.
|
|
24
|
+
*/
|
|
25
|
+
export function initUserRecordAuthProvider(user) {
|
|
26
|
+
const candidates = [
|
|
27
|
+
user.providerId,
|
|
28
|
+
...(user.providerData ?? []).map((info) => info.providerId),
|
|
29
|
+
];
|
|
30
|
+
return candidates.find((id) => INIT_USER_RECORD_AUTH_PROVIDERS.includes(id));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The email to report: the account's own, else the first one a linked provider holds (GitHub with a private primary
|
|
34
|
+
* address leaves `user.email` empty while the provider record has it).
|
|
35
|
+
*/
|
|
36
|
+
function initUserRecordEmail(user) {
|
|
37
|
+
return (user.email ||
|
|
38
|
+
(user.providerData ?? []).find((info) => !!info.email)?.email ||
|
|
39
|
+
undefined);
|
|
40
|
+
}
|
|
41
|
+
export function initUserRecordRequestFromAuthUser(user) {
|
|
42
|
+
const request = {
|
|
43
|
+
email: initUserRecordEmail(user),
|
|
44
|
+
emailIsVerified: user.emailVerified,
|
|
45
|
+
authProvider: initUserRecordAuthProvider(user),
|
|
46
|
+
};
|
|
47
|
+
return user.displayName
|
|
48
|
+
? { ...request, names: { fullName: user.displayName } }
|
|
49
|
+
: request;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=init-user-record-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-user-record-request.js","sourceRoot":"","sources":["../../../../../../../libs/auth/core/src/lib/user/init-user-record-request.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAsB;IAChE,UAAU;IACV,WAAW;IACX,OAAO;IACP,YAAY;IACZ,cAAc;IACd,aAAa;IACb,YAAY;IACZ,eAAe;IACf,WAAW;IACX,WAAW;IACX,UAAU;IACV,QAAQ;CACT,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,IAAyD;IAEzD,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,UAAU;QACf,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC;KAC5D,CAAC;IACF,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,+BAA+B,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAC1B,IAAoD;IAEpD,OAAO,CACL,IAAI,CAAC,KAAK;QACV,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK;QAC7D,SAAS,CACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,IAAoB;IAEpB,MAAM,OAAO,GAA2B;QACtC,KAAK,EAAE,mBAAmB,CAAC,IAAI,CAAC;QAChC,eAAe,EAAE,IAAI,CAAC,aAAa;QACnC,YAAY,EAAE,0BAA0B,CAAC,IAAI,CAAC;KAC/C,CAAC;IACF,OAAO,IAAI,CAAC,WAAW;QACrB,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE;QACvD,CAAC,CAAC,OAAO,CAAC;AACd,CAAC","sourcesContent":["import type { ISneatAuthUser } from '../sneat-auth-state-service';\nimport type { IInitUserRecordRequest } from './user-record.service';\n\n/**\n * The auth provider IDs that `POST /v0/users/init_user_record` accepts: the server's `knownAuthProviderIDs`\n * (strongoapp `strongoauth`). Any other value, including Firebase's own `\"firebase\"`, answers 400\n * `authProvider: supported auth providers=...`.\n */\nexport const INIT_USER_RECORD_AUTH_PROVIDERS: readonly string[] = [\n 'password',\n 'emailLink',\n 'phone',\n 'google.com',\n 'facebook.com',\n 'twitter.com',\n 'github.com',\n 'microsoft.com',\n 'apple.com',\n 'yahoo.com',\n 'telegram',\n 'custom',\n];\n\n/**\n * The provider to report for a signed-in Firebase user. `user.providerId` is `\"firebase\"` for an account that has\n * more than one linked provider (Google plus GitHub, say), which the server rejects with 400, so the first linked\n * provider the server knows is reported instead. `undefined` when none is known: the field is then left out.\n */\nexport function initUserRecordAuthProvider(\n user: Pick<ISneatAuthUser, 'providerId' | 'providerData'>,\n): string | undefined {\n const candidates = [\n user.providerId,\n ...(user.providerData ?? []).map((info) => info.providerId),\n ];\n return candidates.find((id) => INIT_USER_RECORD_AUTH_PROVIDERS.includes(id));\n}\n\n/**\n * The email to report: the account's own, else the first one a linked provider holds (GitHub with a private primary\n * address leaves `user.email` empty while the provider record has it).\n */\nfunction initUserRecordEmail(\n user: Pick<ISneatAuthUser, 'email' | 'providerData'>,\n): string | undefined {\n return (\n user.email ||\n (user.providerData ?? []).find((info) => !!info.email)?.email ||\n undefined\n );\n}\n\nexport function initUserRecordRequestFromAuthUser(\n user: ISneatAuthUser,\n): IInitUserRecordRequest {\n const request: IInitUserRecordRequest = {\n email: initUserRecordEmail(user),\n emailIsVerified: user.emailVerified,\n authProvider: initUserRecordAuthProvider(user),\n };\n return user.displayName\n ? { ...request, names: { fullName: user.displayName } }\n : request;\n}\n"]}
|
|
@@ -6,7 +6,8 @@ import { SneatApiService } from '@sneat/api';
|
|
|
6
6
|
import { ErrorLogger, SneatUrlOperationBlocker, } from '@sneat/core';
|
|
7
7
|
import { initialSneatAuthState, AuthStatuses, SneatAuthStateService, } from '../sneat-auth-state-service';
|
|
8
8
|
import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs';
|
|
9
|
-
import {
|
|
9
|
+
import { initUserRecordRequestFromAuthUser } from './init-user-record-request';
|
|
10
|
+
import { UserRecordService } from './user-record.service';
|
|
10
11
|
import * as i0 from "@angular/core";
|
|
11
12
|
const UsersCollection = 'users';
|
|
12
13
|
export class SneatUserService {
|
|
@@ -306,14 +307,7 @@ export class SneatUserService {
|
|
|
306
307
|
}
|
|
307
308
|
const operation = { uid, accountGeneration, id: ++this.initOperationID };
|
|
308
309
|
this.activeInit = operation;
|
|
309
|
-
|
|
310
|
-
email: authUser.email || undefined,
|
|
311
|
-
emailIsVerified: authUser.emailVerified,
|
|
312
|
-
authProvider: authUser?.providerId,
|
|
313
|
-
};
|
|
314
|
-
if (authUser?.displayName) {
|
|
315
|
-
request = { ...request, names: { fullName: authUser.displayName } };
|
|
316
|
-
}
|
|
310
|
+
const request = initUserRecordRequestFromAuthUser(authUser);
|
|
317
311
|
this.userRecordService.initUserRecord(request).subscribe({
|
|
318
312
|
next: () => {
|
|
319
313
|
if (this.activeInit === operation)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sneat-user.service.js","sourceRoot":"","sources":["../../../../../../../libs/auth/core/src/lib/user/sneat-user.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Injectable,\n inject,\n Injector,\n runInInjectionContext,\n} from '@angular/core';\nimport {\n // Action,\n Firestore as AngularFirestore,\n CollectionReference,\n DocumentSnapshot,\n collection,\n doc,\n onSnapshot,\n Unsubscribe,\n} from 'firebase/firestore';\nimport { SneatApiService } from '@sneat/api';\nimport { IUserRecord } from '@sneat/auth-models';\nimport {\n ErrorLogger,\n IErrorLogger,\n SneatUrlOperationBlocker,\n} from '@sneat/core';\nimport {\n initialSneatAuthState,\n AuthStatuses,\n ISneatAuthState,\n ISneatAuthUser,\n SneatAuthStateService,\n} from '../sneat-auth-state-service';\nimport { BehaviorSubject, Observable, ReplaySubject } from 'rxjs';\nimport {\n IInitUserRecordRequest,\n UserRecordService,\n} from './user-record.service';\n\nexport interface ISneatUserState extends ISneatAuthState {\n record?: IUserRecord | null; // undefined => not loaded yet, null = does not exists\n /** Ready only after a matching persisted Firestore user record is observed. */\n userRecordStatus?: 'loading' | 'ready' | 'failed';\n}\n\nconst UsersCollection = 'users';\n\n@Injectable({ providedIn: 'root' }) // TODO: lazy loading\nexport class SneatUserService {\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n private readonly sneatApiService = inject(SneatApiService);\n private readonly userRecordService = inject(UserRecordService);\n private readonly operationBlocker = inject(SneatUrlOperationBlocker);\n\n // private userDocSubscription?: Subscription;\n private readonly injector = inject(Injector);\n private readonly userCollection: CollectionReference<IUserRecord>;\n private readonly userDocRef = (uid: string) =>\n runInInjectionContext(this.injector, () => doc(this.userCollection, uid));\n\n private uid?: string;\n private pendingUID?: string;\n private currentAuthState?: ISneatAuthState;\n private pendingAuthState?: ISneatAuthState;\n private deferredMissingUserDocSnapshot?: DocumentSnapshot<IUserRecord>;\n private $userTitle?: string;\n private watchTimer?: ReturnType<typeof setTimeout>;\n private watchGeneration = 0;\n private accountGeneration = 0;\n private initOperationID = 0;\n private activeInit?: { uid: string; accountGeneration: number; id: number };\n private initAcknowledged?: { uid: string; accountGeneration: number };\n\n private readonly userChanged$ = new ReplaySubject<string | undefined>(1);\n public readonly userChanged = this.userChanged$.asObservable();\n\n private readonly userState$ = new BehaviorSubject<ISneatUserState>(\n initialSneatAuthState,\n );\n\n public readonly userState = this.userState$.asObservable();\n\n private _unsubscribeFromUserDoc?: Unsubscribe;\n\n private unsubscribeFromUserDoc() {\n clearTimeout(this.watchTimer);\n this.watchTimer = undefined;\n this.watchGeneration++;\n if (this._unsubscribeFromUserDoc) {\n this._unsubscribeFromUserDoc();\n this._unsubscribeFromUserDoc = undefined;\n }\n }\n\n constructor() {\n const afs = inject(AngularFirestore);\n const sneatAuthStateService = inject(SneatAuthStateService);\n this.userCollection = collection(\n afs,\n UsersCollection,\n ) as CollectionReference<IUserRecord>;\n sneatAuthStateService.authState.subscribe({\n next: this.onAuthStateChanged,\n error: this.errorLogger.logErrorHandler('failed to get sneat auth state'),\n });\n }\n\n public get currentUserID(): string | undefined {\n return this.uid;\n }\n\n // public get userTitle(): string | undefined {\n // \treturn this.$userTitle;\n // }\n\n public setUserCountry(countryID: string): Observable<void> {\n return this.sneatApiService.post('users/set_user_country', { countryID });\n }\n\n /**\n * Watches another user's readable profile record without changing the\n * authenticated user's state. Firestore rules remain the authorization\n * boundary (for example, shared-Space membership); callers only depend on\n * this user-domain service rather than the persistence SDK.\n */\n public watchUserRecordByID(userID: string): Observable<IUserRecord | null> {\n return new Observable<IUserRecord | null>((subscriber) => {\n if (!userID || this.operationBlocker.isBlocked('server-requests')) {\n subscriber.next(null);\n subscriber.complete();\n return undefined;\n }\n const userDocRef = this.userDocRef(userID);\n return runInInjectionContext(this.injector, () =>\n onSnapshot(userDocRef, {\n next: (snapshot) =>\n subscriber.next(snapshot.exists() ? snapshot.data() : null),\n error: (error) => subscriber.error(error),\n }),\n );\n });\n }\n\n public onUserSignedIn(authState: ISneatAuthState): void {\n const authUser = authState.user;\n // afUser.getIdToken().then(idToken => {\n // \tconsole.log('Firebase idToken:', idToken);\n // }).catch(err => this.errorLoggerService.logError(err, 'Failed to get Firebase ID token'));\n if (authUser?.email && authUser.emailVerified) {\n this.$userTitle = authUser.email;\n }\n this.pendingUID = undefined;\n if (this.uid === authUser?.uid) {\n this.currentAuthState = authState;\n this.pendingAuthState = undefined;\n const current = this.userState$.value;\n if (current.user?.isAnonymous !== authUser?.isAnonymous) {\n this.userState$.next({\n ...authState,\n record: current.record,\n userRecordStatus: current.userRecordStatus,\n });\n }\n const deferredSnapshot = this.deferredMissingUserDocSnapshot;\n this.deferredMissingUserDocSnapshot = undefined;\n if (deferredSnapshot) {\n this.userDocChanged(deferredSnapshot, authState, this.watchGeneration);\n }\n return;\n }\n this.pendingAuthState = undefined;\n this.deferredMissingUserDocSnapshot = undefined;\n this.unsubscribeFromUserDoc();\n if (!authUser) {\n if (this.userState$.value?.record !== null) {\n this.userState$.next({ ...this.userState$.value });\n }\n return;\n }\n const { uid } = authUser;\n this.currentAuthState = authState;\n this.accountGeneration++;\n this.initAcknowledged = undefined;\n this.uid = uid;\n this.userState$.next({\n ...authState,\n userRecordStatus: 'loading',\n });\n this.userChanged$.next(uid);\n this.watchUserRecord(uid, authState);\n }\n\n private watchUserRecord(uid: string, authState: ISneatAuthState): void {\n // console.log(\n // `SneatUserService.watchUserRecord(uid=${uid}): Loading user record...`,\n // );\n this.unsubscribeFromUserDoc();\n const generation = this.watchGeneration;\n if (this.operationBlocker.isBlocked('server-requests')) {\n this.setUserRecordStatus(uid, authState, 'failed');\n return;\n }\n\n // TODO: Remove - setTimeout() not needed but trying to troubleshoot user record issue\n this.watchTimer = setTimeout(() => {\n this.watchTimer = undefined;\n if (!this.isCurrentIdentity(uid, authState, generation)) return;\n if (this.operationBlocker.isBlocked('server-requests')) {\n this.setUserRecordStatus(uid, authState, 'failed');\n return;\n }\n try {\n const userDocRef = this.userDocRef(uid);\n const unsubscribe = runInInjectionContext(\n this.injector,\n () =>\n onSnapshot(userDocRef, {\n next: (userDocSnapshot) => {\n const currentAuthState = this.currentAuthState;\n if (\n !currentAuthState ||\n !this.isCurrentIdentity(uid, currentAuthState, generation)\n )\n return;\n // console.log(\n // `SneatUserService.watchUserRecord(uid=${uid}) => userDocSnapshot:`,\n // userDocSnapshot,\n // );\n this.userDocChanged(\n userDocSnapshot,\n currentAuthState,\n generation,\n );\n },\n error: (err) => {\n const currentAuthState = this.currentAuthState;\n if (\n !currentAuthState ||\n !this.isCurrentIdentity(uid, currentAuthState, generation)\n )\n return;\n this.deferredMissingUserDocSnapshot = undefined;\n this.setUserRecordStatus(uid, currentAuthState, 'failed');\n this.unsubscribeFromUserDoc();\n this.errorLogger.logError(err, 'Failed to read user record');\n },\n }),\n );\n if (this.watchGeneration === generation) {\n this._unsubscribeFromUserDoc = unsubscribe;\n } else {\n unsubscribe();\n }\n } catch (err) {\n const currentAuthState = this.currentAuthState;\n if (\n currentAuthState &&\n this.isCurrentIdentity(uid, currentAuthState, generation)\n ) {\n this.deferredMissingUserDocSnapshot = undefined;\n this.setUserRecordStatus(uid, currentAuthState, 'failed');\n this.errorLogger.logError(err, 'Failed to watch user record');\n }\n return;\n }\n }, 100);\n }\n\n private onAuthStateChanged = (authState: ISneatAuthState): void => {\n // console.log('SneatUserService => authState changed:', authState);\n if (authState.user) {\n if (this.isReadyForUserRecord(authState)) {\n this.onUserSignedIn(authState);\n } else {\n this.onAuthStatePending(authState);\n }\n } else {\n this.userState$.next(authState);\n this.userChanged$.next(undefined);\n this.onUserSignedOut();\n }\n };\n\n private isReadyForUserRecord(authState: ISneatAuthState): boolean {\n if (authState.status !== AuthStatuses.authenticated) return false;\n // Older callers that provide the original minimal auth-state shape remain\n // supported. SneatAuthStateService always includes loadingPhase and token.\n return authState.loadingPhase === undefined ||\n (authState.loadingPhase === 'ready' && !!authState.token);\n }\n\n private onAuthStatePending(authState: ISneatAuthState): void {\n const uid = authState.user?.uid;\n if (!uid) return;\n\n // A token refresh for the account already owning this watcher must not\n // replace its stable authenticated identity with a transient auth state.\n if (this.uid === uid && this.currentAuthState?.status === AuthStatuses.authenticated) {\n this.pendingAuthState = authState;\n return;\n }\n\n // A different identity is visible before its token is ready. Retire the\n // previous account immediately, but do not assign this UID or start a\n // watcher until the auth service publishes the matching ready token.\n if (this.pendingUID !== uid || this.uid) {\n this.accountGeneration++;\n this.initAcknowledged = undefined;\n this.activeInit = undefined;\n this.pendingAuthState = undefined;\n this.deferredMissingUserDocSnapshot = undefined;\n const hadCurrentUID = !!this.uid;\n this.uid = undefined;\n this.currentAuthState = undefined;\n this.pendingUID = uid;\n this.unsubscribeFromUserDoc();\n if (hadCurrentUID) this.userChanged$.next(undefined);\n }\n this.userState$.next({\n ...authState,\n record: undefined,\n userRecordStatus: 'loading',\n });\n }\n\n private userDocChanged(\n userDocSnapshot: DocumentSnapshot<IUserRecord>,\n authState: ISneatAuthState,\n generation: number,\n ): void {\n // console.log(\n // 'SneatUserService.userDocChanged() => userDocSnapshot.exists:',\n // userDocSnapshot.exists(),\n // 'authState:',\n // authState,\n // 'userDocSnapshot:',\n // userDocSnapshot,\n // );\n if (\n !this.isCurrentIdentity(\n authState.user?.uid ?? '',\n authState,\n generation,\n ) ||\n userDocSnapshot.ref.id !== this.uid\n ) {\n console.error(\n 'userDocSnapshot.ref.id !== this.uid - Should always be equal as we unsubscribe if uid changes',\n );\n return;\n }\n // console.log('SneatUserService => userDocSnapshot.exists:', userDocSnapshot.exists)\n const authUser = authState.user;\n const recordExists = userDocSnapshot.exists();\n const initAcknowledged = this.initAcknowledged;\n if (\n recordExists &&\n authUser?.uid === initAcknowledged?.uid &&\n this.accountGeneration === initAcknowledged?.accountGeneration\n ) {\n this.initAcknowledged = undefined;\n }\n const userRecord: IUserRecord | null = recordExists\n ? (userDocSnapshot.data() as IUserRecord)\n : authUser\n ? { title: authUser.displayName || authUser.email || authUser.uid }\n : null;\n if (recordExists) {\n this.deferredMissingUserDocSnapshot = undefined;\n } else if (this.pendingAuthState?.user?.uid === authUser?.uid) {\n this.deferredMissingUserDocSnapshot = userDocSnapshot;\n } else {\n this.deferredMissingUserDocSnapshot = undefined;\n }\n const current = this.userState$.value;\n this.userState$.next({\n ...authState,\n record: userRecord,\n userRecordStatus: recordExists\n ? 'ready'\n : current.userRecordStatus === 'failed'\n ? 'failed'\n : 'loading',\n });\n if (\n authUser &&\n !recordExists &&\n current.userRecordStatus !== 'failed' &&\n !this.pendingAuthState &&\n !(\n this.initAcknowledged?.uid === authUser.uid &&\n this.initAcknowledged.accountGeneration === this.accountGeneration\n )\n ) {\n this.initUserRecordFromAuthUser(authUser);\n }\n }\n\n private initUserRecordFromAuthUser(authUser: ISneatAuthUser): void {\n const uid = authUser.uid;\n const accountGeneration = this.accountGeneration;\n if (!uid || !this.isCurrentAuthIdentity(uid, authUser, accountGeneration))\n return;\n if (\n this.activeInit?.uid === uid &&\n this.activeInit.accountGeneration === accountGeneration\n ) {\n return;\n }\n const operation = { uid, accountGeneration, id: ++this.initOperationID };\n this.activeInit = operation;\n let request: IInitUserRecordRequest = {\n email: authUser.email || undefined,\n emailIsVerified: authUser.emailVerified,\n authProvider: authUser?.providerId,\n };\n if (authUser?.displayName) {\n request = { ...request, names: { fullName: authUser.displayName } };\n }\n this.userRecordService.initUserRecord(request).subscribe({\n next: () => {\n if (this.activeInit === operation) this.activeInit = undefined;\n if (\n !this.isCurrentAuthIdentity(uid, authUser, accountGeneration) ||\n this.userState$.value.userRecordStatus === 'ready'\n )\n return;\n this.initAcknowledged = { uid, accountGeneration };\n // API acknowledgement is not readiness. Wait for the persisted snapshot.\n },\n error: (error) => {\n if (this.activeInit === operation) this.activeInit = undefined;\n if (\n !this.isCurrentAuthIdentity(uid, authUser, accountGeneration) ||\n this.userState$.value.userRecordStatus === 'ready'\n )\n return;\n this.setUserRecordStatus(\n uid,\n { status: 'authenticated', user: authUser },\n 'failed',\n );\n this.errorLogger.logError(error, 'Failed to initialize user record');\n },\n });\n }\n\n /** Retry record watch and initialization after a failed first-load attempt. */\n public retryUserRecordInitialization(): void {\n const current = this.userState$.value;\n const uid = this.uid;\n if (\n !uid ||\n current.status !== 'authenticated' ||\n current.user?.uid !== uid ||\n current.userRecordStatus !== 'failed'\n ) {\n return;\n }\n this.userState$.next({ ...current, userRecordStatus: 'loading' });\n this.watchUserRecord(uid, current);\n }\n\n private isCurrentIdentity(\n uid: string,\n authState: ISneatAuthState,\n generation: number,\n ): boolean {\n return (\n !!uid &&\n this.uid === uid &&\n this.watchGeneration === generation &&\n authState.status === 'authenticated' &&\n authState.user?.uid === uid &&\n this.userState$.value.user?.uid === uid\n );\n }\n\n private isCurrentAuthIdentity(\n uid: string,\n authUser: ISneatAuthUser,\n accountGeneration: number,\n ): boolean {\n return (\n uid === this.uid &&\n accountGeneration === this.accountGeneration &&\n this.userState$.value.status === 'authenticated' &&\n this.userState$.value.user?.uid === uid &&\n authUser.uid === uid\n );\n }\n\n private setUserRecordStatus(\n uid: string,\n authState: ISneatAuthState,\n userRecordStatus: ISneatUserState['userRecordStatus'],\n ): void {\n if (\n uid !== this.uid ||\n authState.user?.uid !== uid ||\n this.userState$.value.user?.uid !== uid\n ) {\n return;\n }\n this.userState$.next({ ...this.userState$.value, userRecordStatus });\n }\n\n private onUserSignedOut(): void {\n this.accountGeneration++;\n this.initAcknowledged = undefined;\n this.uid = undefined;\n this.pendingUID = undefined;\n this.currentAuthState = undefined;\n this.pendingAuthState = undefined;\n this.deferredMissingUserDocSnapshot = undefined;\n this.unsubscribeFromUserDoc();\n }\n\n // private createUserRecord(userDocRef: DocumentReference, authUser: ISneatAuthUser): void {\n // \tif (this.userState$.value) {\n // \t\treturn;\n // \t}\n // \tthis.db.firestore.runTransaction(async tx => {\n // \t\tif (this.userState$.value) {\n // \t\t\treturn undefined;\n // \t\t}\n // \t\tconst u = await tx.get(userDocRef);\n // \t\tif (!u.exists) {\n // \t\t\tconst title = authUser.displayName || authUser.email || authUser.uid;\n // \t\t\tconst user: IUserRecord = authUser.email\n // \t\t\t\t? {title, email: authUser.email, emailVerified: authUser.emailVerified}\n // \t\t\t\t: {title};\n // \t\t\tawait tx.set(userDocRef, user);\n // \t\t\treturn user;\n // \t\t}\n // \t\treturn undefined;\n // \t}).then(user => {\n // \t\tif (user) {\n // \t\t\tconsole.log('user record created:', user);\n // \t\t}\n // \t\tif (!this.userState$.value) {\n // \t\t\tconst userState: ISneatUserState = {\n // \t\t\t\tstatus: AuthStatuses.authenticated,\n // \t\t\t\trecord: user,\n // \t\t\t\tuser: authUser,\n // \t\t\t};\n // \t\t\tthis.userState$.next(userState);\n // \t\t}\n // \t}).catch(this.errorLogger.logErrorHandler('failed to create user record'));\n // }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sneat-user.service.js","sourceRoot":"","sources":["../../../../../../../libs/auth/core/src/lib/user/sneat-user.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Injectable,\n inject,\n Injector,\n runInInjectionContext,\n} from '@angular/core';\nimport {\n // Action,\n Firestore as AngularFirestore,\n CollectionReference,\n DocumentSnapshot,\n collection,\n doc,\n onSnapshot,\n Unsubscribe,\n} from 'firebase/firestore';\nimport { SneatApiService } from '@sneat/api';\nimport { IUserRecord } from '@sneat/auth-models';\nimport {\n ErrorLogger,\n IErrorLogger,\n SneatUrlOperationBlocker,\n} from '@sneat/core';\nimport {\n initialSneatAuthState,\n AuthStatuses,\n ISneatAuthState,\n ISneatAuthUser,\n SneatAuthStateService,\n} from '../sneat-auth-state-service';\nimport { BehaviorSubject, Observable, ReplaySubject } from 'rxjs';\nimport { initUserRecordRequestFromAuthUser } from './init-user-record-request';\nimport { UserRecordService } from './user-record.service';\n\nexport interface ISneatUserState extends ISneatAuthState {\n record?: IUserRecord | null; // undefined => not loaded yet, null = does not exists\n /** Ready only after a matching persisted Firestore user record is observed. */\n userRecordStatus?: 'loading' | 'ready' | 'failed';\n}\n\nconst UsersCollection = 'users';\n\n@Injectable({ providedIn: 'root' }) // TODO: lazy loading\nexport class SneatUserService {\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n private readonly sneatApiService = inject(SneatApiService);\n private readonly userRecordService = inject(UserRecordService);\n private readonly operationBlocker = inject(SneatUrlOperationBlocker);\n\n // private userDocSubscription?: Subscription;\n private readonly injector = inject(Injector);\n private readonly userCollection: CollectionReference<IUserRecord>;\n private readonly userDocRef = (uid: string) =>\n runInInjectionContext(this.injector, () => doc(this.userCollection, uid));\n\n private uid?: string;\n private pendingUID?: string;\n private currentAuthState?: ISneatAuthState;\n private pendingAuthState?: ISneatAuthState;\n private deferredMissingUserDocSnapshot?: DocumentSnapshot<IUserRecord>;\n private $userTitle?: string;\n private watchTimer?: ReturnType<typeof setTimeout>;\n private watchGeneration = 0;\n private accountGeneration = 0;\n private initOperationID = 0;\n private activeInit?: { uid: string; accountGeneration: number; id: number };\n private initAcknowledged?: { uid: string; accountGeneration: number };\n\n private readonly userChanged$ = new ReplaySubject<string | undefined>(1);\n public readonly userChanged = this.userChanged$.asObservable();\n\n private readonly userState$ = new BehaviorSubject<ISneatUserState>(\n initialSneatAuthState,\n );\n\n public readonly userState = this.userState$.asObservable();\n\n private _unsubscribeFromUserDoc?: Unsubscribe;\n\n private unsubscribeFromUserDoc() {\n clearTimeout(this.watchTimer);\n this.watchTimer = undefined;\n this.watchGeneration++;\n if (this._unsubscribeFromUserDoc) {\n this._unsubscribeFromUserDoc();\n this._unsubscribeFromUserDoc = undefined;\n }\n }\n\n constructor() {\n const afs = inject(AngularFirestore);\n const sneatAuthStateService = inject(SneatAuthStateService);\n this.userCollection = collection(\n afs,\n UsersCollection,\n ) as CollectionReference<IUserRecord>;\n sneatAuthStateService.authState.subscribe({\n next: this.onAuthStateChanged,\n error: this.errorLogger.logErrorHandler('failed to get sneat auth state'),\n });\n }\n\n public get currentUserID(): string | undefined {\n return this.uid;\n }\n\n // public get userTitle(): string | undefined {\n // \treturn this.$userTitle;\n // }\n\n public setUserCountry(countryID: string): Observable<void> {\n return this.sneatApiService.post('users/set_user_country', { countryID });\n }\n\n /**\n * Watches another user's readable profile record without changing the\n * authenticated user's state. Firestore rules remain the authorization\n * boundary (for example, shared-Space membership); callers only depend on\n * this user-domain service rather than the persistence SDK.\n */\n public watchUserRecordByID(userID: string): Observable<IUserRecord | null> {\n return new Observable<IUserRecord | null>((subscriber) => {\n if (!userID || this.operationBlocker.isBlocked('server-requests')) {\n subscriber.next(null);\n subscriber.complete();\n return undefined;\n }\n const userDocRef = this.userDocRef(userID);\n return runInInjectionContext(this.injector, () =>\n onSnapshot(userDocRef, {\n next: (snapshot) =>\n subscriber.next(snapshot.exists() ? snapshot.data() : null),\n error: (error) => subscriber.error(error),\n }),\n );\n });\n }\n\n public onUserSignedIn(authState: ISneatAuthState): void {\n const authUser = authState.user;\n // afUser.getIdToken().then(idToken => {\n // \tconsole.log('Firebase idToken:', idToken);\n // }).catch(err => this.errorLoggerService.logError(err, 'Failed to get Firebase ID token'));\n if (authUser?.email && authUser.emailVerified) {\n this.$userTitle = authUser.email;\n }\n this.pendingUID = undefined;\n if (this.uid === authUser?.uid) {\n this.currentAuthState = authState;\n this.pendingAuthState = undefined;\n const current = this.userState$.value;\n if (current.user?.isAnonymous !== authUser?.isAnonymous) {\n this.userState$.next({\n ...authState,\n record: current.record,\n userRecordStatus: current.userRecordStatus,\n });\n }\n const deferredSnapshot = this.deferredMissingUserDocSnapshot;\n this.deferredMissingUserDocSnapshot = undefined;\n if (deferredSnapshot) {\n this.userDocChanged(deferredSnapshot, authState, this.watchGeneration);\n }\n return;\n }\n this.pendingAuthState = undefined;\n this.deferredMissingUserDocSnapshot = undefined;\n this.unsubscribeFromUserDoc();\n if (!authUser) {\n if (this.userState$.value?.record !== null) {\n this.userState$.next({ ...this.userState$.value });\n }\n return;\n }\n const { uid } = authUser;\n this.currentAuthState = authState;\n this.accountGeneration++;\n this.initAcknowledged = undefined;\n this.uid = uid;\n this.userState$.next({\n ...authState,\n userRecordStatus: 'loading',\n });\n this.userChanged$.next(uid);\n this.watchUserRecord(uid, authState);\n }\n\n private watchUserRecord(uid: string, authState: ISneatAuthState): void {\n // console.log(\n // `SneatUserService.watchUserRecord(uid=${uid}): Loading user record...`,\n // );\n this.unsubscribeFromUserDoc();\n const generation = this.watchGeneration;\n if (this.operationBlocker.isBlocked('server-requests')) {\n this.setUserRecordStatus(uid, authState, 'failed');\n return;\n }\n\n // TODO: Remove - setTimeout() not needed but trying to troubleshoot user record issue\n this.watchTimer = setTimeout(() => {\n this.watchTimer = undefined;\n if (!this.isCurrentIdentity(uid, authState, generation)) return;\n if (this.operationBlocker.isBlocked('server-requests')) {\n this.setUserRecordStatus(uid, authState, 'failed');\n return;\n }\n try {\n const userDocRef = this.userDocRef(uid);\n const unsubscribe = runInInjectionContext(\n this.injector,\n () =>\n onSnapshot(userDocRef, {\n next: (userDocSnapshot) => {\n const currentAuthState = this.currentAuthState;\n if (\n !currentAuthState ||\n !this.isCurrentIdentity(uid, currentAuthState, generation)\n )\n return;\n // console.log(\n // `SneatUserService.watchUserRecord(uid=${uid}) => userDocSnapshot:`,\n // userDocSnapshot,\n // );\n this.userDocChanged(\n userDocSnapshot,\n currentAuthState,\n generation,\n );\n },\n error: (err) => {\n const currentAuthState = this.currentAuthState;\n if (\n !currentAuthState ||\n !this.isCurrentIdentity(uid, currentAuthState, generation)\n )\n return;\n this.deferredMissingUserDocSnapshot = undefined;\n this.setUserRecordStatus(uid, currentAuthState, 'failed');\n this.unsubscribeFromUserDoc();\n this.errorLogger.logError(err, 'Failed to read user record');\n },\n }),\n );\n if (this.watchGeneration === generation) {\n this._unsubscribeFromUserDoc = unsubscribe;\n } else {\n unsubscribe();\n }\n } catch (err) {\n const currentAuthState = this.currentAuthState;\n if (\n currentAuthState &&\n this.isCurrentIdentity(uid, currentAuthState, generation)\n ) {\n this.deferredMissingUserDocSnapshot = undefined;\n this.setUserRecordStatus(uid, currentAuthState, 'failed');\n this.errorLogger.logError(err, 'Failed to watch user record');\n }\n return;\n }\n }, 100);\n }\n\n private onAuthStateChanged = (authState: ISneatAuthState): void => {\n // console.log('SneatUserService => authState changed:', authState);\n if (authState.user) {\n if (this.isReadyForUserRecord(authState)) {\n this.onUserSignedIn(authState);\n } else {\n this.onAuthStatePending(authState);\n }\n } else {\n this.userState$.next(authState);\n this.userChanged$.next(undefined);\n this.onUserSignedOut();\n }\n };\n\n private isReadyForUserRecord(authState: ISneatAuthState): boolean {\n if (authState.status !== AuthStatuses.authenticated) return false;\n // Older callers that provide the original minimal auth-state shape remain\n // supported. SneatAuthStateService always includes loadingPhase and token.\n return authState.loadingPhase === undefined ||\n (authState.loadingPhase === 'ready' && !!authState.token);\n }\n\n private onAuthStatePending(authState: ISneatAuthState): void {\n const uid = authState.user?.uid;\n if (!uid) return;\n\n // A token refresh for the account already owning this watcher must not\n // replace its stable authenticated identity with a transient auth state.\n if (this.uid === uid && this.currentAuthState?.status === AuthStatuses.authenticated) {\n this.pendingAuthState = authState;\n return;\n }\n\n // A different identity is visible before its token is ready. Retire the\n // previous account immediately, but do not assign this UID or start a\n // watcher until the auth service publishes the matching ready token.\n if (this.pendingUID !== uid || this.uid) {\n this.accountGeneration++;\n this.initAcknowledged = undefined;\n this.activeInit = undefined;\n this.pendingAuthState = undefined;\n this.deferredMissingUserDocSnapshot = undefined;\n const hadCurrentUID = !!this.uid;\n this.uid = undefined;\n this.currentAuthState = undefined;\n this.pendingUID = uid;\n this.unsubscribeFromUserDoc();\n if (hadCurrentUID) this.userChanged$.next(undefined);\n }\n this.userState$.next({\n ...authState,\n record: undefined,\n userRecordStatus: 'loading',\n });\n }\n\n private userDocChanged(\n userDocSnapshot: DocumentSnapshot<IUserRecord>,\n authState: ISneatAuthState,\n generation: number,\n ): void {\n // console.log(\n // 'SneatUserService.userDocChanged() => userDocSnapshot.exists:',\n // userDocSnapshot.exists(),\n // 'authState:',\n // authState,\n // 'userDocSnapshot:',\n // userDocSnapshot,\n // );\n if (\n !this.isCurrentIdentity(\n authState.user?.uid ?? '',\n authState,\n generation,\n ) ||\n userDocSnapshot.ref.id !== this.uid\n ) {\n console.error(\n 'userDocSnapshot.ref.id !== this.uid - Should always be equal as we unsubscribe if uid changes',\n );\n return;\n }\n // console.log('SneatUserService => userDocSnapshot.exists:', userDocSnapshot.exists)\n const authUser = authState.user;\n const recordExists = userDocSnapshot.exists();\n const initAcknowledged = this.initAcknowledged;\n if (\n recordExists &&\n authUser?.uid === initAcknowledged?.uid &&\n this.accountGeneration === initAcknowledged?.accountGeneration\n ) {\n this.initAcknowledged = undefined;\n }\n const userRecord: IUserRecord | null = recordExists\n ? (userDocSnapshot.data() as IUserRecord)\n : authUser\n ? { title: authUser.displayName || authUser.email || authUser.uid }\n : null;\n if (recordExists) {\n this.deferredMissingUserDocSnapshot = undefined;\n } else if (this.pendingAuthState?.user?.uid === authUser?.uid) {\n this.deferredMissingUserDocSnapshot = userDocSnapshot;\n } else {\n this.deferredMissingUserDocSnapshot = undefined;\n }\n const current = this.userState$.value;\n this.userState$.next({\n ...authState,\n record: userRecord,\n userRecordStatus: recordExists\n ? 'ready'\n : current.userRecordStatus === 'failed'\n ? 'failed'\n : 'loading',\n });\n if (\n authUser &&\n !recordExists &&\n current.userRecordStatus !== 'failed' &&\n !this.pendingAuthState &&\n !(\n this.initAcknowledged?.uid === authUser.uid &&\n this.initAcknowledged.accountGeneration === this.accountGeneration\n )\n ) {\n this.initUserRecordFromAuthUser(authUser);\n }\n }\n\n private initUserRecordFromAuthUser(authUser: ISneatAuthUser): void {\n const uid = authUser.uid;\n const accountGeneration = this.accountGeneration;\n if (!uid || !this.isCurrentAuthIdentity(uid, authUser, accountGeneration))\n return;\n if (\n this.activeInit?.uid === uid &&\n this.activeInit.accountGeneration === accountGeneration\n ) {\n return;\n }\n const operation = { uid, accountGeneration, id: ++this.initOperationID };\n this.activeInit = operation;\n const request = initUserRecordRequestFromAuthUser(authUser);\n this.userRecordService.initUserRecord(request).subscribe({\n next: () => {\n if (this.activeInit === operation) this.activeInit = undefined;\n if (\n !this.isCurrentAuthIdentity(uid, authUser, accountGeneration) ||\n this.userState$.value.userRecordStatus === 'ready'\n )\n return;\n this.initAcknowledged = { uid, accountGeneration };\n // API acknowledgement is not readiness. Wait for the persisted snapshot.\n },\n error: (error) => {\n if (this.activeInit === operation) this.activeInit = undefined;\n if (\n !this.isCurrentAuthIdentity(uid, authUser, accountGeneration) ||\n this.userState$.value.userRecordStatus === 'ready'\n )\n return;\n this.setUserRecordStatus(\n uid,\n { status: 'authenticated', user: authUser },\n 'failed',\n );\n this.errorLogger.logError(error, 'Failed to initialize user record');\n },\n });\n }\n\n /** Retry record watch and initialization after a failed first-load attempt. */\n public retryUserRecordInitialization(): void {\n const current = this.userState$.value;\n const uid = this.uid;\n if (\n !uid ||\n current.status !== 'authenticated' ||\n current.user?.uid !== uid ||\n current.userRecordStatus !== 'failed'\n ) {\n return;\n }\n this.userState$.next({ ...current, userRecordStatus: 'loading' });\n this.watchUserRecord(uid, current);\n }\n\n private isCurrentIdentity(\n uid: string,\n authState: ISneatAuthState,\n generation: number,\n ): boolean {\n return (\n !!uid &&\n this.uid === uid &&\n this.watchGeneration === generation &&\n authState.status === 'authenticated' &&\n authState.user?.uid === uid &&\n this.userState$.value.user?.uid === uid\n );\n }\n\n private isCurrentAuthIdentity(\n uid: string,\n authUser: ISneatAuthUser,\n accountGeneration: number,\n ): boolean {\n return (\n uid === this.uid &&\n accountGeneration === this.accountGeneration &&\n this.userState$.value.status === 'authenticated' &&\n this.userState$.value.user?.uid === uid &&\n authUser.uid === uid\n );\n }\n\n private setUserRecordStatus(\n uid: string,\n authState: ISneatAuthState,\n userRecordStatus: ISneatUserState['userRecordStatus'],\n ): void {\n if (\n uid !== this.uid ||\n authState.user?.uid !== uid ||\n this.userState$.value.user?.uid !== uid\n ) {\n return;\n }\n this.userState$.next({ ...this.userState$.value, userRecordStatus });\n }\n\n private onUserSignedOut(): void {\n this.accountGeneration++;\n this.initAcknowledged = undefined;\n this.uid = undefined;\n this.pendingUID = undefined;\n this.currentAuthState = undefined;\n this.pendingAuthState = undefined;\n this.deferredMissingUserDocSnapshot = undefined;\n this.unsubscribeFromUserDoc();\n }\n\n // private createUserRecord(userDocRef: DocumentReference, authUser: ISneatAuthUser): void {\n // \tif (this.userState$.value) {\n // \t\treturn;\n // \t}\n // \tthis.db.firestore.runTransaction(async tx => {\n // \t\tif (this.userState$.value) {\n // \t\t\treturn undefined;\n // \t\t}\n // \t\tconst u = await tx.get(userDocRef);\n // \t\tif (!u.exists) {\n // \t\t\tconst title = authUser.displayName || authUser.email || authUser.uid;\n // \t\t\tconst user: IUserRecord = authUser.email\n // \t\t\t\t? {title, email: authUser.email, emailVerified: authUser.emailVerified}\n // \t\t\t\t: {title};\n // \t\t\tawait tx.set(userDocRef, user);\n // \t\t\treturn user;\n // \t\t}\n // \t\treturn undefined;\n // \t}).then(user => {\n // \t\tif (user) {\n // \t\t\tconsole.log('user record created:', user);\n // \t\t}\n // \t\tif (!this.userState$.value) {\n // \t\t\tconst userState: ISneatUserState = {\n // \t\t\t\tstatus: AuthStatuses.authenticated,\n // \t\t\t\trecord: user,\n // \t\t\t\tuser: authUser,\n // \t\t\t};\n // \t\t\tthis.userState$.next(userState);\n // \t\t}\n // \t}).catch(this.errorLogger.logErrorHandler('failed to create user record'));\n // }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ISneatAuthUser } from '../sneat-auth-state-service';
|
|
2
|
+
import type { IInitUserRecordRequest } from './user-record.service';
|
|
3
|
+
/**
|
|
4
|
+
* The auth provider IDs that `POST /v0/users/init_user_record` accepts: the server's `knownAuthProviderIDs`
|
|
5
|
+
* (strongoapp `strongoauth`). Any other value, including Firebase's own `"firebase"`, answers 400
|
|
6
|
+
* `authProvider: supported auth providers=...`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const INIT_USER_RECORD_AUTH_PROVIDERS: readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* The provider to report for a signed-in Firebase user. `user.providerId` is `"firebase"` for an account that has
|
|
11
|
+
* more than one linked provider (Google plus GitHub, say), which the server rejects with 400, so the first linked
|
|
12
|
+
* provider the server knows is reported instead. `undefined` when none is known: the field is then left out.
|
|
13
|
+
*/
|
|
14
|
+
export declare function initUserRecordAuthProvider(user: Pick<ISneatAuthUser, 'providerId' | 'providerData'>): string | undefined;
|
|
15
|
+
export declare function initUserRecordRequestFromAuthUser(user: ISneatAuthUser): IInitUserRecordRequest;
|