@sneat/auth-core 0.1.3 → 0.1.4
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/index.js +8 -0
- package/esm2022/index.js.map +1 -0
- package/esm2022/lib/login-required-service.service.js +20 -0
- package/esm2022/lib/login-required-service.service.js.map +1 -0
- package/esm2022/lib/private-token-store.service.js +36 -0
- package/esm2022/lib/private-token-store.service.js.map +1 -0
- package/esm2022/lib/sneat-auth-guard.js +79 -0
- package/esm2022/lib/sneat-auth-guard.js.map +1 -0
- package/esm2022/lib/sneat-auth-state-service.js +267 -0
- package/esm2022/lib/sneat-auth-state-service.js.map +1 -0
- package/{src/lib/sneat-auth.interface.ts → esm2022/lib/sneat-auth.interface.js} +1 -5
- package/esm2022/lib/sneat-auth.interface.js.map +1 -0
- package/esm2022/lib/telegram-auth.service.js +39 -0
- package/esm2022/lib/telegram-auth.service.js.map +1 -0
- package/esm2022/lib/user/index.js +3 -0
- package/esm2022/lib/user/index.js.map +1 -0
- package/esm2022/lib/user/sneat-user.service.js +171 -0
- package/esm2022/lib/user/sneat-user.service.js.map +1 -0
- package/esm2022/lib/user/user-record.service.js +30 -0
- package/esm2022/lib/user/user-record.service.js.map +1 -0
- package/esm2022/sneat-auth-core.js +5 -0
- package/esm2022/sneat-auth-core.js.map +1 -0
- package/lib/login-required-service.service.d.ts +6 -0
- package/lib/private-token-store.service.d.ts +8 -0
- package/lib/sneat-auth-guard.d.ts +26 -0
- package/lib/sneat-auth-state-service.d.ts +51 -0
- package/lib/sneat-auth.interface.d.ts +5 -0
- package/lib/telegram-auth.service.d.ts +9 -0
- package/lib/user/sneat-user.service.d.ts +34 -0
- package/lib/user/user-record.service.d.ts +25 -0
- package/package.json +14 -2
- package/sneat-auth-core.d.ts +5 -0
- package/eslint.config.js +0 -7
- package/ng-package.json +0 -7
- package/project.json +0 -38
- package/src/lib/login-required-service.service.spec.ts +0 -39
- package/src/lib/login-required-service.service.ts +0 -14
- package/src/lib/private-token-store.service.spec.ts +0 -75
- package/src/lib/private-token-store.service.ts +0 -36
- package/src/lib/sneat-auth-guard.spec.ts +0 -124
- package/src/lib/sneat-auth-guard.ts +0 -107
- package/src/lib/sneat-auth-state-service.spec.ts +0 -332
- package/src/lib/sneat-auth-state-service.ts +0 -387
- package/src/lib/sneat-auth.interface.spec.ts +0 -39
- package/src/lib/telegram-auth.service.spec.ts +0 -186
- package/src/lib/telegram-auth.service.ts +0 -49
- package/src/lib/user/sneat-user.service.spec.ts +0 -151
- package/src/lib/user/sneat-user.service.ts +0 -266
- package/src/lib/user/user-record.service.spec.ts +0 -145
- package/src/lib/user/user-record.service.ts +0 -38
- package/src/test-setup.ts +0 -3
- package/tsconfig.json +0 -13
- package/tsconfig.lib.json +0 -19
- package/tsconfig.lib.prod.json +0 -7
- package/tsconfig.spec.json +0 -31
- package/vite.config.mts +0 -10
- /package/{src/index.ts → index.d.ts} +0 -0
- /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 @@
|
|
|
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,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,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
|
+
"version": "0.1.4",
|
|
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
|
}
|
package/eslint.config.js
DELETED
package/ng-package.json
DELETED
package/project.json
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "auth-core",
|
|
3
|
-
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"projectType": "library",
|
|
5
|
-
"sourceRoot": "libs/auth/core/src",
|
|
6
|
-
"prefix": "sneat",
|
|
7
|
-
"targets": {
|
|
8
|
-
"build": {
|
|
9
|
-
"executor": "@nx/angular:ng-packagr-lite",
|
|
10
|
-
"outputs": [
|
|
11
|
-
"{workspaceRoot}/dist/libs/auth/core"
|
|
12
|
-
],
|
|
13
|
-
"options": {
|
|
14
|
-
"project": "libs/auth/core/ng-package.json",
|
|
15
|
-
"tsConfig": "libs/auth/core/tsconfig.lib.json"
|
|
16
|
-
},
|
|
17
|
-
"configurations": {
|
|
18
|
-
"production": {
|
|
19
|
-
"tsConfig": "libs/auth/core/tsconfig.lib.prod.json"
|
|
20
|
-
},
|
|
21
|
-
"development": {}
|
|
22
|
-
},
|
|
23
|
-
"defaultConfiguration": "production"
|
|
24
|
-
},
|
|
25
|
-
"test": {
|
|
26
|
-
"executor": "@nx/vitest:test",
|
|
27
|
-
"outputs": [
|
|
28
|
-
"{workspaceRoot}/coverage/libs/auth/core"
|
|
29
|
-
],
|
|
30
|
-
"options": {
|
|
31
|
-
"tsConfig": "libs/auth/core/tsconfig.spec.json"
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"lint": {
|
|
35
|
-
"executor": "@nx/eslint:lint"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { TestBed } from '@angular/core/testing';
|
|
2
|
-
import { LoginRequiredServiceService } from './login-required-service.service';
|
|
3
|
-
import { SneatAuthStateService } from './sneat-auth-state-service';
|
|
4
|
-
import { of } from 'rxjs';
|
|
5
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
6
|
-
|
|
7
|
-
describe('LoginRequiredServiceService', () => {
|
|
8
|
-
let authStateMock: { authState: ReturnType<typeof of> };
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
authStateMock = {
|
|
12
|
-
authState: of({
|
|
13
|
-
status: 'authenticated',
|
|
14
|
-
user: { uid: 'test-uid', email: 'test@example.com' },
|
|
15
|
-
}),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
TestBed.configureTestingModule({
|
|
19
|
-
providers: [
|
|
20
|
-
LoginRequiredServiceService,
|
|
21
|
-
{
|
|
22
|
-
provide: SneatAuthStateService,
|
|
23
|
-
useValue: authStateMock,
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should be created', () => {
|
|
30
|
-
const service = TestBed.inject(LoginRequiredServiceService);
|
|
31
|
-
expect(service).toBeTruthy();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should subscribe to auth state changes', () => {
|
|
35
|
-
const subscribeSpy = vi.spyOn(authStateMock.authState, 'subscribe');
|
|
36
|
-
TestBed.inject(LoginRequiredServiceService);
|
|
37
|
-
expect(subscribeSpy).toHaveBeenCalled();
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from '@angular/core';
|
|
2
|
-
import { SneatAuthStateService } from './sneat-auth-state-service';
|
|
3
|
-
|
|
4
|
-
@Injectable({
|
|
5
|
-
providedIn: 'root',
|
|
6
|
-
})
|
|
7
|
-
export class LoginRequiredServiceService {
|
|
8
|
-
constructor() {
|
|
9
|
-
const authState = inject(SneatAuthStateService);
|
|
10
|
-
authState.authState.subscribe(() => {
|
|
11
|
-
// Intentionally empty - just subscribing to trigger the observable
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { TestBed } from '@angular/core/testing';
|
|
2
|
-
import {
|
|
3
|
-
PrivateTokenStoreService,
|
|
4
|
-
canceledByUser,
|
|
5
|
-
} from './private-token-store.service';
|
|
6
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
7
|
-
import { firstValueFrom } from 'rxjs';
|
|
8
|
-
|
|
9
|
-
describe('PrivateTokenStoreService', () => {
|
|
10
|
-
let service: PrivateTokenStoreService;
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
TestBed.configureTestingModule({
|
|
14
|
-
providers: [PrivateTokenStoreService],
|
|
15
|
-
});
|
|
16
|
-
service = TestBed.inject(PrivateTokenStoreService);
|
|
17
|
-
localStorage.clear();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('should be created', () => {
|
|
21
|
-
expect(service).toBeTruthy();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should return token from localStorage if available', async () => {
|
|
25
|
-
const domain = 'test.com';
|
|
26
|
-
const projectId = 'proj123';
|
|
27
|
-
const token = 'stored-token-123';
|
|
28
|
-
|
|
29
|
-
localStorage.setItem(`private/tokens/${domain}/${projectId}`, token);
|
|
30
|
-
|
|
31
|
-
const result = await firstValueFrom(
|
|
32
|
-
service.getPrivateToken(domain, projectId),
|
|
33
|
-
);
|
|
34
|
-
expect(result).toBe(token);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should prompt user for token if not in localStorage', async () => {
|
|
38
|
-
const domain = 'test.com';
|
|
39
|
-
const projectId = 'proj456';
|
|
40
|
-
const token = 'new-token-456';
|
|
41
|
-
|
|
42
|
-
// Mock the global prompt function
|
|
43
|
-
globalThis.prompt = vi.fn().mockReturnValue(token);
|
|
44
|
-
|
|
45
|
-
const promise = firstValueFrom(service.getPrivateToken(domain, projectId));
|
|
46
|
-
|
|
47
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
48
|
-
|
|
49
|
-
const result = await promise;
|
|
50
|
-
expect(result).toBe(token);
|
|
51
|
-
expect(localStorage.getItem(`private/tokens/${domain}/${projectId}`)).toBe(
|
|
52
|
-
token,
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
// Cleanup
|
|
56
|
-
delete (globalThis as { prompt?: unknown }).prompt;
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should error with canceledByUser if user cancels prompt', async () => {
|
|
60
|
-
const domain = 'test.com';
|
|
61
|
-
const projectId = 'proj789';
|
|
62
|
-
|
|
63
|
-
// Mock the global prompt function
|
|
64
|
-
globalThis.prompt = vi.fn().mockReturnValue(null);
|
|
65
|
-
|
|
66
|
-
const promise = firstValueFrom(service.getPrivateToken(domain, projectId));
|
|
67
|
-
|
|
68
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
69
|
-
|
|
70
|
-
await expect(promise).rejects.toBe(canceledByUser);
|
|
71
|
-
|
|
72
|
-
// Cleanup
|
|
73
|
-
delete (globalThis as { prompt?: unknown }).prompt;
|
|
74
|
-
});
|
|
75
|
-
});
|