@sneat/auth-core 0.1.3 → 0.1.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.
Files changed (59) hide show
  1. package/esm2022/index.js +8 -0
  2. package/esm2022/index.js.map +1 -0
  3. package/esm2022/lib/login-required-service.service.js +20 -0
  4. package/esm2022/lib/login-required-service.service.js.map +1 -0
  5. package/esm2022/lib/private-token-store.service.js +36 -0
  6. package/esm2022/lib/private-token-store.service.js.map +1 -0
  7. package/esm2022/lib/sneat-auth-guard.js +79 -0
  8. package/esm2022/lib/sneat-auth-guard.js.map +1 -0
  9. package/esm2022/lib/sneat-auth-state-service.js +267 -0
  10. package/esm2022/lib/sneat-auth-state-service.js.map +1 -0
  11. package/{src/lib/sneat-auth.interface.ts → esm2022/lib/sneat-auth.interface.js} +1 -5
  12. package/esm2022/lib/sneat-auth.interface.js.map +1 -0
  13. package/esm2022/lib/telegram-auth.service.js +39 -0
  14. package/esm2022/lib/telegram-auth.service.js.map +1 -0
  15. package/esm2022/lib/user/index.js +3 -0
  16. package/esm2022/lib/user/index.js.map +1 -0
  17. package/esm2022/lib/user/sneat-user.service.js +171 -0
  18. package/esm2022/lib/user/sneat-user.service.js.map +1 -0
  19. package/esm2022/lib/user/user-record.service.js +30 -0
  20. package/esm2022/lib/user/user-record.service.js.map +1 -0
  21. package/esm2022/sneat-auth-core.js +5 -0
  22. package/esm2022/sneat-auth-core.js.map +1 -0
  23. package/lib/login-required-service.service.d.ts +6 -0
  24. package/lib/private-token-store.service.d.ts +8 -0
  25. package/lib/sneat-auth-guard.d.ts +26 -0
  26. package/lib/sneat-auth-state-service.d.ts +51 -0
  27. package/lib/sneat-auth.interface.d.ts +5 -0
  28. package/lib/telegram-auth.service.d.ts +9 -0
  29. package/lib/user/sneat-user.service.d.ts +34 -0
  30. package/lib/user/user-record.service.d.ts +25 -0
  31. package/package.json +14 -2
  32. package/sneat-auth-core.d.ts +5 -0
  33. package/tsconfig.lib.prod.tsbuildinfo +1 -0
  34. package/eslint.config.js +0 -7
  35. package/ng-package.json +0 -7
  36. package/project.json +0 -38
  37. package/src/lib/login-required-service.service.spec.ts +0 -39
  38. package/src/lib/login-required-service.service.ts +0 -14
  39. package/src/lib/private-token-store.service.spec.ts +0 -75
  40. package/src/lib/private-token-store.service.ts +0 -36
  41. package/src/lib/sneat-auth-guard.spec.ts +0 -124
  42. package/src/lib/sneat-auth-guard.ts +0 -107
  43. package/src/lib/sneat-auth-state-service.spec.ts +0 -332
  44. package/src/lib/sneat-auth-state-service.ts +0 -387
  45. package/src/lib/sneat-auth.interface.spec.ts +0 -39
  46. package/src/lib/telegram-auth.service.spec.ts +0 -186
  47. package/src/lib/telegram-auth.service.ts +0 -49
  48. package/src/lib/user/sneat-user.service.spec.ts +0 -151
  49. package/src/lib/user/sneat-user.service.ts +0 -266
  50. package/src/lib/user/user-record.service.spec.ts +0 -145
  51. package/src/lib/user/user-record.service.ts +0 -38
  52. package/src/test-setup.ts +0 -3
  53. package/tsconfig.json +0 -13
  54. package/tsconfig.lib.json +0 -19
  55. package/tsconfig.lib.prod.json +0 -7
  56. package/tsconfig.spec.json +0 -31
  57. package/vite.config.mts +0 -10
  58. /package/{src/index.ts → index.d.ts} +0 -0
  59. /package/{src/lib/user/index.ts → lib/user/index.d.ts} +0 -0
@@ -0,0 +1,171 @@
1
+ import { Injectable, inject, Injector, runInInjectionContext, } from '@angular/core';
2
+ import {
3
+ // Action,
4
+ Firestore as AngularFirestore, collection, doc, onSnapshot, } from '@angular/fire/firestore';
5
+ import { SneatApiService } from '@sneat/api';
6
+ import { ErrorLogger } from '@sneat/core';
7
+ import { initialSneatAuthState, SneatAuthStateService, } from '../sneat-auth-state-service';
8
+ import { BehaviorSubject, ReplaySubject } from 'rxjs';
9
+ import { UserRecordService, } from './user-record.service';
10
+ import * as i0 from "@angular/core";
11
+ const UsersCollection = 'users';
12
+ export class SneatUserService {
13
+ unsubscribeFromUserDoc(_from) {
14
+ if (this._unsubscribeFromUserDoc) {
15
+ // console.log(
16
+ // 'SneatUserService.unsubscribeFromUserDoc() called from ' + _from,
17
+ // );
18
+ this._unsubscribeFromUserDoc();
19
+ this._unsubscribeFromUserDoc = undefined;
20
+ }
21
+ }
22
+ constructor() {
23
+ this.errorLogger = inject(ErrorLogger);
24
+ this.sneatApiService = inject(SneatApiService);
25
+ this.userRecordService = inject(UserRecordService);
26
+ // private userDocSubscription?: Subscription;
27
+ this.injector = inject(Injector);
28
+ this.userDocRef = (uid) => runInInjectionContext(this.injector, () => doc(this.userCollection, uid));
29
+ this.userChanged$ = new ReplaySubject(1);
30
+ this.userChanged = this.userChanged$.asObservable();
31
+ this.userState$ = new BehaviorSubject(initialSneatAuthState);
32
+ this.userState = this.userState$.asObservable();
33
+ this.onAuthStateChanged = (authState) => {
34
+ // console.log('SneatUserService => authState changed:', authState);
35
+ if (authState.user) {
36
+ this.onUserSignedIn(authState);
37
+ }
38
+ else {
39
+ this.userState$.next(authState);
40
+ this.userChanged$.next(undefined);
41
+ this.onUserSignedOut();
42
+ }
43
+ };
44
+ const afs = inject(AngularFirestore);
45
+ const sneatAuthStateService = inject(SneatAuthStateService);
46
+ this.userCollection = collection(afs, UsersCollection);
47
+ sneatAuthStateService.authState.subscribe({
48
+ next: this.onAuthStateChanged,
49
+ error: this.errorLogger.logErrorHandler('failed to get sneat auth state'),
50
+ });
51
+ }
52
+ get currentUserID() {
53
+ return this.uid;
54
+ }
55
+ // public get userTitle(): string | undefined {
56
+ // return this.$userTitle;
57
+ // }
58
+ setUserCountry(countryID) {
59
+ return this.sneatApiService.post('users/set_user_country', { countryID });
60
+ }
61
+ onUserSignedIn(authState) {
62
+ const authUser = authState.user;
63
+ // afUser.getIdToken().then(idToken => {
64
+ // console.log('Firebase idToken:', idToken);
65
+ // }).catch(err => this.errorLoggerService.logError(err, 'Failed to get Firebase ID token'));
66
+ if (authUser?.email && authUser.emailVerified) {
67
+ this.$userTitle = authUser.email;
68
+ }
69
+ if (this.uid === authUser?.uid) {
70
+ return;
71
+ }
72
+ this.unsubscribeFromUserDoc('onUserSignedIn()');
73
+ if (!authUser) {
74
+ if (this.userState$.value?.record !== null) {
75
+ this.userState$.next({ ...this.userState$.value });
76
+ }
77
+ return;
78
+ }
79
+ const { uid } = authUser;
80
+ this.uid = uid;
81
+ this.userState$.next({
82
+ ...authState,
83
+ });
84
+ this.userChanged$.next(uid);
85
+ this.watchUserRecord(uid, authState);
86
+ }
87
+ watchUserRecord(uid, authState) {
88
+ // console.log(
89
+ // `SneatUserService.watchUserRecord(uid=${uid}): Loading user record...`,
90
+ // );
91
+ this.unsubscribeFromUserDoc('whatUserRecord()');
92
+ // TODO: Remove - setTimeout() not needed but trying to troubleshoot user record issue
93
+ setTimeout(() => {
94
+ try {
95
+ const userDocRef = this.userDocRef(uid);
96
+ this._unsubscribeFromUserDoc = runInInjectionContext(this.injector, () => onSnapshot(userDocRef, {
97
+ next: (userDocSnapshot) => {
98
+ // console.log(
99
+ // `SneatUserService.watchUserRecord(uid=${uid}) => userDocSnapshot:`,
100
+ // userDocSnapshot,
101
+ // );
102
+ this.onAuthStateChanged(authState);
103
+ this.userDocChanged(userDocSnapshot, authState);
104
+ },
105
+ error: (err) => {
106
+ console.error(`SneatUserService.watchUserRecord(uid=${uid}) => failed:`, err);
107
+ },
108
+ }));
109
+ }
110
+ catch (err) {
111
+ console.error(`SneatUserService.watchUserRecord(uid=${uid}) => Failed to setup watcher for user record::`, err);
112
+ return;
113
+ }
114
+ }, 100);
115
+ }
116
+ userDocChanged(userDocSnapshot, authState) {
117
+ // console.log(
118
+ // 'SneatUserService.userDocChanged() => userDocSnapshot.exists:',
119
+ // userDocSnapshot.exists(),
120
+ // 'authState:',
121
+ // authState,
122
+ // 'userDocSnapshot:',
123
+ // userDocSnapshot,
124
+ // );
125
+ if (userDocSnapshot.ref.id !== this.uid) {
126
+ console.error('userDocSnapshot.ref.id !== this.uid - Should always be equal as we unsubscribe if uid changes');
127
+ return;
128
+ }
129
+ // console.log('SneatUserService => userDocSnapshot.exists:', userDocSnapshot.exists)
130
+ const authUser = authState.user;
131
+ if (authUser && !userDocSnapshot.exists()) {
132
+ this.initUserRecordFromAuthUser(authUser);
133
+ }
134
+ const userRecord = userDocSnapshot.exists()
135
+ ? userDocSnapshot.data()
136
+ : authUser
137
+ ? { title: authUser.displayName || authUser.email || authUser.uid }
138
+ : null;
139
+ this.userState$.next({
140
+ ...authState,
141
+ record: userRecord,
142
+ });
143
+ }
144
+ initUserRecordFromAuthUser(authUser) {
145
+ let request = {
146
+ email: authUser.email || undefined,
147
+ emailIsVerified: authUser.emailVerified,
148
+ authProvider: authUser?.providerId,
149
+ };
150
+ if (authUser?.displayName) {
151
+ request = { ...request, names: { fullName: authUser.displayName } };
152
+ }
153
+ this.userRecordService.initUserRecord(request).subscribe({
154
+ next: (_userDto) => {
155
+ // User record created successfully - no additional action needed
156
+ },
157
+ error: this.errorLogger.logErrorHandler('failed to create user record'),
158
+ });
159
+ }
160
+ onUserSignedOut() {
161
+ this.uid = undefined;
162
+ this.unsubscribeFromUserDoc('onUserSignedOut()');
163
+ }
164
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SneatUserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
165
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SneatUserService, providedIn: 'root' }); }
166
+ }
167
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SneatUserService, decorators: [{
168
+ type: Injectable,
169
+ args: [{ providedIn: 'root' }]
170
+ }], ctorParameters: () => [] });
171
+ //# sourceMappingURL=sneat-user.service.js.map
@@ -0,0 +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 '@angular/fire/firestore';\nimport { SneatApiService } from '@sneat/api';\nimport { IUserRecord } from '@sneat/auth-models';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\nimport {\n initialSneatAuthState,\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}\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\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 $userTitle?: string;\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(_from: string) {\n if (this._unsubscribeFromUserDoc) {\n // console.log(\n // 'SneatUserService.unsubscribeFromUserDoc() called from ' + _from,\n // );\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 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 if (this.uid === authUser?.uid) {\n return;\n }\n this.unsubscribeFromUserDoc('onUserSignedIn()');\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.uid = uid;\n this.userState$.next({\n ...authState,\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('whatUserRecord()');\n\n // TODO: Remove - setTimeout() not needed but trying to troubleshoot user record issue\n setTimeout(() => {\n try {\n const userDocRef = this.userDocRef(uid);\n this._unsubscribeFromUserDoc = runInInjectionContext(\n this.injector,\n () =>\n onSnapshot(userDocRef, {\n next: (userDocSnapshot) => {\n // console.log(\n // `SneatUserService.watchUserRecord(uid=${uid}) => userDocSnapshot:`,\n // userDocSnapshot,\n // );\n this.onAuthStateChanged(authState);\n this.userDocChanged(userDocSnapshot, authState);\n },\n error: (err) => {\n console.error(\n `SneatUserService.watchUserRecord(uid=${uid}) => failed:`,\n err,\n );\n },\n }),\n );\n } catch (err) {\n console.error(\n `SneatUserService.watchUserRecord(uid=${uid}) => Failed to setup watcher for user record::`,\n err,\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 this.onUserSignedIn(authState);\n } else {\n this.userState$.next(authState);\n this.userChanged$.next(undefined);\n this.onUserSignedOut();\n }\n };\n\n private userDocChanged(\n userDocSnapshot: DocumentSnapshot<IUserRecord>,\n authState: ISneatAuthState,\n ): void {\n // console.log(\n // 'SneatUserService.userDocChanged() => userDocSnapshot.exists:',\n // userDocSnapshot.exists(),\n // 'authState:',\n // authState,\n // 'userDocSnapshot:',\n // userDocSnapshot,\n // );\n if (userDocSnapshot.ref.id !== this.uid) {\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 if (authUser && !userDocSnapshot.exists()) {\n this.initUserRecordFromAuthUser(authUser);\n }\n const userRecord: IUserRecord | null = userDocSnapshot.exists()\n ? (userDocSnapshot.data() as IUserRecord)\n : authUser\n ? { title: authUser.displayName || authUser.email || authUser.uid }\n : null;\n\n this.userState$.next({\n ...authState,\n record: userRecord,\n });\n }\n\n private initUserRecordFromAuthUser(authUser: ISneatAuthUser): void {\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: (_userDto) => {\n // User record created successfully - no additional action needed\n },\n error: this.errorLogger.logErrorHandler('failed to create user record'),\n });\n }\n\n private onUserSignedOut(): void {\n this.uid = undefined;\n this.unsubscribeFromUserDoc('onUserSignedOut()');\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,30 @@
1
+ import { Injectable, inject } from '@angular/core';
2
+ import { SneatApiService } from '@sneat/api';
3
+ import { excludeUndefined } from '@sneat/core';
4
+ import { share } from 'rxjs';
5
+ import * as i0 from "@angular/core";
6
+ export class UserRecordService {
7
+ constructor() {
8
+ this.sneatApiService = inject(SneatApiService);
9
+ }
10
+ initUserRecord(request) {
11
+ if (!request.ianaTimezone) {
12
+ request = {
13
+ ...request,
14
+ ianaTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
15
+ };
16
+ }
17
+ request = excludeUndefined(request);
18
+ this.initUserRecord$ = this.sneatApiService
19
+ .post('users/init_user_record', request)
20
+ .pipe(share());
21
+ return this.initUserRecord$;
22
+ }
23
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: UserRecordService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
24
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: UserRecordService, providedIn: 'root' }); }
25
+ }
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: UserRecordService, decorators: [{
27
+ type: Injectable,
28
+ args: [{ providedIn: 'root' }]
29
+ }] });
30
+ //# sourceMappingURL=user-record.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-record.service.js","sourceRoot":"","sources":["../../../../../../../libs/auth/core/src/lib/user/user-record.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAc,gBAAgB,EAAqB,MAAM,aAAa,CAAC;AAE9E,OAAO,EAAc,KAAK,EAAE,MAAM,MAAM,CAAC;;AAGzC,MAAM,OAAO,iBAAiB;IAD9B;QAEmB,oBAAe,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;KAiB5D;IAbQ,cAAc,CAAC,OAA+B;QACnD,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YAC1B,OAAO,GAAG;gBACR,GAAG,OAAO;gBACV,YAAY,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,QAAQ;aAC/D,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe;aACxC,IAAI,CAAW,wBAAwB,EAAE,OAAO,CAAC;aACjD,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;8GAjBU,iBAAiB;kHAAjB,iBAAiB,cADJ,MAAM;;2FACnB,iBAAiB;kBAD7B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { Injectable, inject } from '@angular/core';\nimport { SneatApiService } from '@sneat/api';\nimport { IPersonNames } from '@sneat/auth-models';\nimport { AgeGroupID, excludeUndefined, Gender, SpaceType } from '@sneat/core';\nimport { IUserDbo } from '@sneat/dto';\nimport { Observable, share } from 'rxjs';\n\n@Injectable({ providedIn: 'root' })\nexport class UserRecordService {\n private readonly sneatApiService = inject(SneatApiService);\n\n private initUserRecord$?: Observable<IUserDbo>;\n\n public initUserRecord(request: IInitUserRecordRequest): Observable<IUserDbo> {\n if (!request.ianaTimezone) {\n request = {\n ...request,\n ianaTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n };\n }\n request = excludeUndefined(request);\n this.initUserRecord$ = this.sneatApiService\n .post<IUserDbo>('users/init_user_record', request)\n .pipe(share());\n return this.initUserRecord$;\n }\n}\n\nexport interface IInitUserRecordRequest {\n readonly authProvider?: string;\n readonly gender?: Gender;\n readonly ageGroup?: AgeGroupID;\n readonly names?: IPersonNames;\n readonly email?: string;\n readonly emailIsVerified?: boolean;\n readonly ianaTimezone?: string;\n readonly space?: { type: SpaceType; title: string };\n}\n"]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=sneat-auth-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sneat-auth-core.js","sourceRoot":"","sources":["../../../../../libs/auth/core/src/sneat-auth-core.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,SAAS,CAAC","sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"]}
@@ -0,0 +1,6 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class LoginRequiredServiceService {
3
+ constructor();
4
+ static ɵfac: i0.ɵɵFactoryDeclaration<LoginRequiredServiceService, never>;
5
+ static ɵprov: i0.ɵɵInjectableDeclaration<LoginRequiredServiceService>;
6
+ }
@@ -0,0 +1,8 @@
1
+ import { Observable } from 'rxjs';
2
+ import * as i0 from "@angular/core";
3
+ export declare const canceledByUser = "canceled by user";
4
+ export declare class PrivateTokenStoreService {
5
+ getPrivateToken(domain: string, projectId: string): Observable<string>;
6
+ static ɵfac: i0.ɵɵFactoryDeclaration<PrivateTokenStoreService, never>;
7
+ static ɵprov: i0.ɵɵInjectableDeclaration<PrivateTokenStoreService>;
8
+ }
@@ -0,0 +1,26 @@
1
+ import { ActivatedRouteSnapshot, Route, RouterStateSnapshot, UrlSegment, UrlTree } from '@angular/router';
2
+ import { Observable } from 'rxjs';
3
+ import { AuthPipe } from '@angular/fire/auth-guard';
4
+ import * as i0 from "@angular/core";
5
+ type AuthCanLoadPipeGenerator = (route: Route, segments: UrlSegment[]) => AuthPipe;
6
+ export declare const redirectToLoginIfNotSignedIn: AuthPipe;
7
+ export declare class SneatAuthGuard {
8
+ private readonly router;
9
+ private readonly auth;
10
+ canLoad(_route: Route, _segments: UrlSegment[]): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;
11
+ canActivate(_route: ActivatedRouteSnapshot, _state: RouterStateSnapshot): boolean;
12
+ canActivateChild(_childRoute: ActivatedRouteSnapshot, _state: RouterStateSnapshot): boolean;
13
+ static ɵfac: i0.ɵɵFactoryDeclaration<SneatAuthGuard, never>;
14
+ static ɵprov: i0.ɵɵInjectableDeclaration<SneatAuthGuard>;
15
+ }
16
+ export declare const canLoad: (pipe?: AuthCanLoadPipeGenerator) => {
17
+ canLoad: (typeof SneatAuthGuard)[];
18
+ data: {
19
+ authCanLoadGuardPipe: AuthCanLoadPipeGenerator | undefined;
20
+ };
21
+ };
22
+ export declare const SNEAT_AUTH_GUARDS: {
23
+ canActivate: (typeof SneatAuthGuard)[];
24
+ canLoad: (typeof SneatAuthGuard)[];
25
+ };
26
+ export {};
@@ -0,0 +1,51 @@
1
+ import { EnumAsUnionOfKeys } from '@sneat/core';
2
+ import { Observable } from 'rxjs';
3
+ import { Auth, UserCredential, UserInfo } from '@angular/fire/auth';
4
+ import * as i0 from "@angular/core";
5
+ export declare enum AuthStatuses {
6
+ authenticating = "authenticating",
7
+ authenticated = "authenticated",
8
+ notAuthenticated = "notAuthenticated"
9
+ }
10
+ export type AuthStatus = EnumAsUnionOfKeys<typeof AuthStatuses>;
11
+ export interface ISneatAuthUser extends UserInfo {
12
+ readonly isAnonymous: boolean;
13
+ readonly emailVerified: boolean;
14
+ readonly providerData: readonly UserInfo[];
15
+ }
16
+ export interface ISneatAuthState {
17
+ readonly status: AuthStatus;
18
+ readonly token?: string | null;
19
+ readonly user?: ISneatAuthUser | null;
20
+ readonly err?: unknown;
21
+ }
22
+ export declare const initialSneatAuthState: {
23
+ status: AuthStatuses;
24
+ };
25
+ export declare class SneatAuthStateService {
26
+ private readonly errorLogger;
27
+ private readonly analyticsService;
28
+ readonly fbAuth: Auth;
29
+ private readonly id;
30
+ private readonly authStatus$;
31
+ readonly authStatus: Observable<"authenticating" | "authenticated" | "notAuthenticated">;
32
+ private readonly authUser$;
33
+ readonly authUser: Observable<ISneatAuthUser | null | undefined>;
34
+ private readonly authState$;
35
+ readonly authState: Observable<ISneatAuthState>;
36
+ constructor();
37
+ signOut(): Promise<void>;
38
+ signInWithToken(token: string): Promise<UserCredential>;
39
+ signInWithEmailLink(email: string): Observable<UserCredential>;
40
+ private isSigningInWith?;
41
+ private signInOnNativeLayer;
42
+ private authenticateOnWebviewLayer;
43
+ private signInWithWebSDK;
44
+ linkWith(authProviderID: AuthProviderID): Promise<UserCredential | undefined>;
45
+ unlinkAuthProvider(authProviderID: string): Promise<void>;
46
+ signInWith(authProviderID: AuthProviderID): Promise<UserCredential | undefined>;
47
+ static ɵfac: i0.ɵɵFactoryDeclaration<SneatAuthStateService, never>;
48
+ static ɵprov: i0.ɵɵInjectableDeclaration<SneatAuthStateService>;
49
+ }
50
+ export type AuthProviderID = 'apple.com' | 'google.com' | 'microsoft.com' | 'facebook.com' | 'github.com' | 'phone';
51
+ export type AuthProviderName = 'Google' | 'Apple' | 'Microsoft' | 'Facebook' | 'GitHub';
@@ -0,0 +1,5 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ export interface ILoginEventsHandler {
3
+ onLoggedIn(): void;
4
+ }
5
+ export declare const LoginEventsHandler: InjectionToken<unknown>;
@@ -0,0 +1,9 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class TelegramAuthService {
3
+ private readonly errorLogger;
4
+ private readonly authStateService;
5
+ private readonly sneatApiService;
6
+ authenticateIfTelegramWebApp(): void;
7
+ static ɵfac: i0.ɵɵFactoryDeclaration<TelegramAuthService, never>;
8
+ static ɵprov: i0.ɵɵInjectableDeclaration<TelegramAuthService>;
9
+ }
@@ -0,0 +1,34 @@
1
+ import { IUserRecord } from '@sneat/auth-models';
2
+ import { ISneatAuthState } from '../sneat-auth-state-service';
3
+ import { Observable } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ export interface ISneatUserState extends ISneatAuthState {
6
+ record?: IUserRecord | null;
7
+ }
8
+ export declare class SneatUserService {
9
+ private readonly errorLogger;
10
+ private readonly sneatApiService;
11
+ private readonly userRecordService;
12
+ private readonly injector;
13
+ private readonly userCollection;
14
+ private readonly userDocRef;
15
+ private uid?;
16
+ private $userTitle?;
17
+ private readonly userChanged$;
18
+ readonly userChanged: Observable<string | undefined>;
19
+ private readonly userState$;
20
+ readonly userState: Observable<ISneatUserState>;
21
+ private _unsubscribeFromUserDoc?;
22
+ private unsubscribeFromUserDoc;
23
+ constructor();
24
+ get currentUserID(): string | undefined;
25
+ setUserCountry(countryID: string): Observable<void>;
26
+ onUserSignedIn(authState: ISneatAuthState): void;
27
+ private watchUserRecord;
28
+ private onAuthStateChanged;
29
+ private userDocChanged;
30
+ private initUserRecordFromAuthUser;
31
+ private onUserSignedOut;
32
+ static ɵfac: i0.ɵɵFactoryDeclaration<SneatUserService, never>;
33
+ static ɵprov: i0.ɵɵInjectableDeclaration<SneatUserService>;
34
+ }
@@ -0,0 +1,25 @@
1
+ import { IPersonNames } from '@sneat/auth-models';
2
+ import { AgeGroupID, Gender, SpaceType } from '@sneat/core';
3
+ import { IUserDbo } from '@sneat/dto';
4
+ import { Observable } from 'rxjs';
5
+ import * as i0 from "@angular/core";
6
+ export declare class UserRecordService {
7
+ private readonly sneatApiService;
8
+ private initUserRecord$?;
9
+ initUserRecord(request: IInitUserRecordRequest): Observable<IUserDbo>;
10
+ static ɵfac: i0.ɵɵFactoryDeclaration<UserRecordService, never>;
11
+ static ɵprov: i0.ɵɵInjectableDeclaration<UserRecordService>;
12
+ }
13
+ export interface IInitUserRecordRequest {
14
+ readonly authProvider?: string;
15
+ readonly gender?: Gender;
16
+ readonly ageGroup?: AgeGroupID;
17
+ readonly names?: IPersonNames;
18
+ readonly email?: string;
19
+ readonly emailIsVerified?: boolean;
20
+ readonly ianaTimezone?: string;
21
+ readonly space?: {
22
+ type: SpaceType;
23
+ title: string;
24
+ };
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sneat/auth-core",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -13,5 +13,17 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "tslib": "2.8.1"
16
- }
16
+ },
17
+ "module": "esm2022/sneat-auth-core.js",
18
+ "typings": "sneat-auth-core.d.ts",
19
+ "exports": {
20
+ "./package.json": {
21
+ "default": "./package.json"
22
+ },
23
+ ".": {
24
+ "types": "./sneat-auth-core.d.ts",
25
+ "default": "./esm2022/sneat-auth-core.js"
26
+ }
27
+ },
28
+ "sideEffects": false
17
29
  }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="@sneat/auth-core" />
5
+ export * from './index';