entropic-bond 1.48.1 → 1.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/.github/workflows/release.yml +26 -0
  2. package/CHANGELOG.md +1151 -0
  3. package/docs/.nojekyll +1 -0
  4. package/docs/README.md +94 -0
  5. package/docs/classes/Auth.md +391 -0
  6. package/docs/classes/AuthMock.md +278 -0
  7. package/docs/classes/AuthService.md +188 -0
  8. package/docs/classes/CloudFunctions.md +123 -0
  9. package/docs/classes/CloudFunctionsMock.md +97 -0
  10. package/docs/classes/CloudStorage.md +215 -0
  11. package/docs/classes/DataSource.md +248 -0
  12. package/docs/classes/EntropicComponent.md +666 -0
  13. package/docs/classes/JsonDataSource.md +328 -0
  14. package/docs/classes/MockCloudStorage.md +279 -0
  15. package/docs/classes/Model.md +274 -0
  16. package/docs/classes/Observable.md +120 -0
  17. package/docs/classes/Persistent.md +420 -0
  18. package/docs/classes/ServerAuth.md +211 -0
  19. package/docs/classes/ServerAuthMock.md +176 -0
  20. package/docs/classes/ServerAuthService.md +130 -0
  21. package/docs/classes/Store.md +218 -0
  22. package/docs/classes/StoredFile.md +636 -0
  23. package/docs/enums/StoredFileEvent.md +41 -0
  24. package/docs/interfaces/AuthError.md +30 -0
  25. package/docs/interfaces/CloudFunctionsService.md +69 -0
  26. package/docs/interfaces/Collection.md +13 -0
  27. package/docs/interfaces/CustomCredentials.md +7 -0
  28. package/docs/interfaces/DocumentReference.md +49 -0
  29. package/docs/interfaces/JsonRawData.md +7 -0
  30. package/docs/interfaces/SignData.md +63 -0
  31. package/docs/interfaces/StoreParams.md +52 -0
  32. package/docs/interfaces/StoredFileChange.md +41 -0
  33. package/docs/interfaces/UploadControl.md +90 -0
  34. package/docs/interfaces/UserCredentials.md +113 -0
  35. package/docs/interfaces/Values.md +17 -0
  36. package/docs/modules.md +1273 -0
  37. package/package.json +23 -19
  38. package/src/auth/auth-mock.spec.ts +168 -0
  39. package/src/auth/auth-mock.ts +129 -0
  40. package/src/auth/auth.ts +185 -0
  41. package/src/auth/user-auth-types.ts +21 -0
  42. package/src/cloud-functions/cloud-functions-mock.spec.ts +136 -0
  43. package/src/cloud-functions/cloud-functions-mock.ts +23 -0
  44. package/src/cloud-functions/cloud-functions.ts +83 -0
  45. package/src/cloud-storage/cloud-storage.spec.ts +207 -0
  46. package/src/cloud-storage/cloud-storage.ts +60 -0
  47. package/src/cloud-storage/mock-cloud-storage.ts +72 -0
  48. package/src/cloud-storage/stored-file.ts +102 -0
  49. package/src/index.ts +19 -0
  50. package/src/observable/observable.spec.ts +105 -0
  51. package/src/observable/observable.ts +67 -0
  52. package/src/persistent/entropic-component.spec.ts +143 -0
  53. package/src/persistent/entropic-component.ts +135 -0
  54. package/src/persistent/persistent.spec.ts +828 -0
  55. package/src/persistent/persistent.ts +650 -0
  56. package/src/server-auth/server-auth-mock.spec.ts +53 -0
  57. package/src/server-auth/server-auth-mock.ts +45 -0
  58. package/src/server-auth/server-auth.ts +49 -0
  59. package/src/store/data-source.ts +186 -0
  60. package/src/store/json-data-source.spec.ts +100 -0
  61. package/src/store/json-data-source.ts +256 -0
  62. package/src/store/mocks/mock-data.json +155 -0
  63. package/src/store/mocks/test-user.ts +122 -0
  64. package/src/store/model.spec.ts +659 -0
  65. package/src/store/model.ts +462 -0
  66. package/src/store/store.spec.ts +30 -0
  67. package/src/store/store.ts +113 -0
  68. package/src/types/utility-types.spec.ts +117 -0
  69. package/src/types/utility-types.ts +116 -0
  70. package/src/utils/test-utils/test-person.ts +44 -0
  71. package/src/utils/utils.spec.ts +95 -0
  72. package/{lib/utils/utils.d.ts → src/utils/utils.ts} +34 -10
  73. package/tsconfig-build.json +7 -0
  74. package/tsconfig-cjs.json +9 -0
  75. package/tsconfig.json +33 -0
  76. package/vite.config.ts +22 -0
  77. package/lib/auth/auth-mock.d.ts +0 -21
  78. package/lib/auth/auth-mock.js +0 -108
  79. package/lib/auth/auth-mock.js.map +0 -1
  80. package/lib/auth/auth.d.ts +0 -129
  81. package/lib/auth/auth.js +0 -146
  82. package/lib/auth/auth.js.map +0 -1
  83. package/lib/auth/user-auth-types.d.ts +0 -19
  84. package/lib/auth/user-auth-types.js +0 -3
  85. package/lib/auth/user-auth-types.js.map +0 -1
  86. package/lib/cloud-functions/cloud-functions-mock.d.ts +0 -11
  87. package/lib/cloud-functions/cloud-functions-mock.js +0 -19
  88. package/lib/cloud-functions/cloud-functions-mock.js.map +0 -1
  89. package/lib/cloud-functions/cloud-functions.d.ts +0 -19
  90. package/lib/cloud-functions/cloud-functions.js +0 -64
  91. package/lib/cloud-functions/cloud-functions.js.map +0 -1
  92. package/lib/cloud-storage/cloud-storage.d.ts +0 -24
  93. package/lib/cloud-storage/cloud-storage.js +0 -37
  94. package/lib/cloud-storage/cloud-storage.js.map +0 -1
  95. package/lib/cloud-storage/mock-cloud-storage.d.ts +0 -20
  96. package/lib/cloud-storage/mock-cloud-storage.js +0 -68
  97. package/lib/cloud-storage/mock-cloud-storage.js.map +0 -1
  98. package/lib/cloud-storage/stored-file.d.ts +0 -39
  99. package/lib/cloud-storage/stored-file.js +0 -106
  100. package/lib/cloud-storage/stored-file.js.map +0 -1
  101. package/lib/index.d.ts +0 -19
  102. package/lib/index.js +0 -36
  103. package/lib/index.js.map +0 -1
  104. package/lib/observable/observable.d.ts +0 -52
  105. package/lib/observable/observable.js +0 -66
  106. package/lib/observable/observable.js.map +0 -1
  107. package/lib/persistent/entropic-component.d.ts +0 -76
  108. package/lib/persistent/entropic-component.js +0 -109
  109. package/lib/persistent/entropic-component.js.map +0 -1
  110. package/lib/persistent/persistent.d.ts +0 -281
  111. package/lib/persistent/persistent.js +0 -539
  112. package/lib/persistent/persistent.js.map +0 -1
  113. package/lib/server-auth/server-auth-mock.d.ts +0 -12
  114. package/lib/server-auth/server-auth-mock.js +0 -39
  115. package/lib/server-auth/server-auth-mock.js.map +0 -1
  116. package/lib/server-auth/server-auth.d.ts +0 -24
  117. package/lib/server-auth/server-auth.js +0 -36
  118. package/lib/server-auth/server-auth.js.map +0 -1
  119. package/lib/store/data-source.d.ts +0 -137
  120. package/lib/store/data-source.js +0 -62
  121. package/lib/store/data-source.js.map +0 -1
  122. package/lib/store/json-data-source.d.ts +0 -68
  123. package/lib/store/json-data-source.js +0 -199
  124. package/lib/store/json-data-source.js.map +0 -1
  125. package/lib/store/mocks/test-user.d.ts +0 -49
  126. package/lib/store/mocks/test-user.js +0 -135
  127. package/lib/store/mocks/test-user.js.map +0 -1
  128. package/lib/store/model.d.ts +0 -238
  129. package/lib/store/model.js +0 -417
  130. package/lib/store/model.js.map +0 -1
  131. package/lib/store/store.d.ts +0 -62
  132. package/lib/store/store.js +0 -102
  133. package/lib/store/store.js.map +0 -1
  134. package/lib/types/utility-types.d.ts +0 -45
  135. package/lib/types/utility-types.js +0 -3
  136. package/lib/types/utility-types.js.map +0 -1
  137. package/lib/utils/test-utils/test-person.d.ts +0 -33
  138. package/lib/utils/test-utils/test-person.js +0 -25
  139. package/lib/utils/test-utils/test-person.js.map +0 -1
  140. package/lib/utils/utils.js +0 -76
  141. package/lib/utils/utils.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,17 @@
1
1
  {
2
2
  "name": "entropic-bond",
3
- "version": "1.48.1",
3
+ "type": "module",
4
+ "version": "1.50.0",
5
+ "description": "Tidy up your messy components",
6
+ "main": "./lib/entropic-bond.umd.cjs",
7
+ "module": "./lib/entropic-bond.js",
8
+ "types": "./lib/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./lib/index.js",
12
+ "require": "./lib/entropic-bond.umd.cjs"
13
+ }
14
+ },
4
15
  "publishConfig": {
5
16
  "access": "public",
6
17
  "branches": [
@@ -16,19 +27,10 @@
16
27
  "@semantic-release/github"
17
28
  ]
18
29
  },
19
- "description": "Tidy up your messy components",
20
- "main": "lib/index.js",
21
- "types": "lib/index.d.ts",
22
- "files": [
23
- "lib"
24
- ],
25
30
  "scripts": {
26
31
  "test": "vitest",
27
- "build": "npm run build-cjs",
28
- "prepare": "npm run build",
29
- "build-ts": "cp -r ./src/ ./lib",
30
- "build-cjs": "tsc -p tsconfig-cjs.json",
31
- "build-next": "tsc -p tsconfig.json"
32
+ "build": "tsc -p tsconfig-build.json && vite build",
33
+ "prepare": "npm run build"
32
34
  },
33
35
  "repository": {
34
36
  "type": "git",
@@ -50,14 +52,16 @@
50
52
  "@semantic-release/changelog": "^6.0.3",
51
53
  "@semantic-release/git": "^10.0.1",
52
54
  "@type-challenges/utils": "^0.1.1",
53
- "@types/uuid": "^9.0.6",
55
+ "@types/node": "^20.11.16",
56
+ "@types/uuid": "^9.0.8",
54
57
  "git-branch-is": "^4.0.0",
55
- "husky": "^8.0.3",
56
- "semantic-release": "^22.0.5",
57
- "typedoc": "^0.25.2",
58
- "typedoc-plugin-markdown": "^3.16.0",
59
- "typescript": "^5.2.2",
60
- "vitest": "^0.34.6"
58
+ "husky": "^9.0.10",
59
+ "semantic-release": "^23.0.0",
60
+ "typedoc": "^0.25.7",
61
+ "typedoc-plugin-markdown": "^3.17.1",
62
+ "typescript": "^5.3.3",
63
+ "vite-plugin-dts": "^3.7.2",
64
+ "vitest": "^1.2.2"
61
65
  },
62
66
  "dependencies": {
63
67
  "uuid": "^9.0.1"
@@ -0,0 +1,168 @@
1
+ import { Auth } from './auth'
2
+ import { AuthMock } from './auth-mock'
3
+ import { UserCredentials } from './user-auth-types'
4
+
5
+ interface CustomCredentials {
6
+ role: string
7
+ customer: string
8
+ }
9
+
10
+ describe( 'Auth Mock', ()=>{
11
+ let authChangeSpy = vi.fn()
12
+ let mockAuthService: AuthMock
13
+ const fakeUseCredentials = {
14
+ email: 'fakeUser@test.com',
15
+ emailVerified: true,
16
+ creationDate: new Date( '2017-01-01' ).getDate(),
17
+ lastLogin: new Date( '2017-01-03' ).getDate(),
18
+ customData: {
19
+ role: 'testRole',
20
+ customer: 'testCustomer'
21
+ },
22
+ id: 'fakeUser',
23
+ } as UserCredentials<CustomCredentials>
24
+
25
+ beforeEach(()=>{
26
+ Auth.useAuthService( mockAuthService = new AuthMock() )
27
+ Auth.instance.onAuthStateChange( authChangeSpy )
28
+
29
+ mockAuthService.fakeRegisteredUser( fakeUseCredentials )
30
+
31
+ })
32
+
33
+ it( 'should throw if AuthService not set', ()=>{
34
+ Auth.useAuthService( undefined! )
35
+ expect(
36
+ ()=>Auth.instance
37
+ ).toThrow( Auth.error.shouldBeRegistered )
38
+ })
39
+
40
+
41
+ it( 'should emulate sign-up', async ()=>{
42
+ const userCredentials = await Auth.instance.signUp({
43
+ authProvider: 'google',
44
+ email: 'test@test.com',
45
+ password: 'password'
46
+ })
47
+
48
+ expect( userCredentials.email ).toEqual( 'test@test.com' )
49
+ expect( authChangeSpy ).toHaveBeenCalledWith( userCredentials )
50
+ })
51
+
52
+ it( 'should emulate failed sign-up', async ()=>{
53
+ try {
54
+ var userCredentials = await Auth.instance.signUp({
55
+ authProvider: 'email',
56
+ email: 'test@test.com',
57
+ password: 'fail'
58
+ })
59
+ }
60
+ catch {}
61
+
62
+ expect( userCredentials! ).toBeUndefined()
63
+ expect( authChangeSpy ).toHaveBeenCalledWith( undefined )
64
+ })
65
+
66
+ it( 'should login with fake registered user', async ()=>{
67
+ const userCredentials = await Auth.instance.login({
68
+ email: 'fakeUser@test.com',
69
+ password: 'password',
70
+ authProvider: 'google'
71
+ })
72
+
73
+ const modUserCredentials = {
74
+ ...fakeUseCredentials,
75
+ id: fakeUseCredentials.id
76
+ }
77
+
78
+ expect( userCredentials ).toEqual( modUserCredentials )
79
+ expect( authChangeSpy ).toHaveBeenCalledWith( modUserCredentials )
80
+ })
81
+
82
+ it( 'should fail login with email auth provider if does not match fake user credentials', async ()=>{
83
+ try {
84
+ var userCredentials = await Auth.instance.login({
85
+ email: 'test@test.com',
86
+ password: 'password',
87
+ authProvider: 'email'
88
+ })
89
+ } catch {}
90
+
91
+ expect( userCredentials! ).toEqual( undefined )
92
+ expect( authChangeSpy ).toHaveBeenCalledWith( undefined )
93
+ })
94
+
95
+ it( 'should NOT fail login with non email auth provider even if does not match fake user credentials', async ()=>{
96
+ const userCredentials = await Auth.instance.login({
97
+ email: 'test@test.com',
98
+ password: 'password',
99
+ authProvider: 'google'
100
+ })
101
+
102
+ expect( userCredentials.email ).toEqual( 'test@test.com' )
103
+ expect( authChangeSpy ).toHaveBeenCalledWith( undefined )
104
+ })
105
+
106
+ it( 'should logout', async ()=>{
107
+ await Auth.instance.logout()
108
+
109
+ expect( authChangeSpy ).toHaveBeenCalledWith( undefined )
110
+ })
111
+
112
+ it( 'should throw if email does not exists in resetEmailPassword', async ()=>{
113
+ return expect(
114
+ Auth.instance.resetEmailPassword( 'non-existing-email@test.com' )
115
+ ).rejects.toEqual( expect.objectContaining({ code: 'userNotFound' }) )
116
+ })
117
+
118
+ it( 'should retrieve custom credentials', async ()=>{
119
+ const userCredentials = await Auth.instance.login<CustomCredentials>({
120
+ email: 'fakeUser@test.com',
121
+ password: 'password',
122
+ authProvider: 'google'
123
+ })
124
+
125
+ expect( userCredentials.customData?.role ).toEqual( 'testRole' )
126
+ })
127
+
128
+ it( 'should throw if login and not email in email auth provider', ()=>{
129
+ return expect(
130
+ Auth.instance.login({
131
+ authProvider: 'email',
132
+ email: '',
133
+ password: '****'
134
+ })
135
+ ).rejects.toEqual( expect.objectContaining({ code: 'missingEmail' }))
136
+ })
137
+
138
+ it( 'should throw if login and not password in email auth provider', ()=>{
139
+ return expect(
140
+ Auth.instance.login({
141
+ authProvider: 'email',
142
+ email: 'test@test.com',
143
+ password: ''
144
+ })
145
+ ).rejects.toEqual( expect.objectContaining({ code: 'missingPassword' }))
146
+ })
147
+
148
+ it( 'should throw if signup and not email in email auth provider', ()=>{
149
+ return expect(
150
+ Auth.instance.signUp({
151
+ authProvider: 'email',
152
+ email: '',
153
+ password: '****'
154
+ })
155
+ ).rejects.toEqual( expect.objectContaining({ code: 'missingEmail' }))
156
+ })
157
+
158
+ it( 'should throw if signup and not password in email auth provider', ()=>{
159
+ return expect(
160
+ Auth.instance.signUp({
161
+ authProvider: 'email',
162
+ email: 'test@test.com',
163
+ password: ''
164
+ })
165
+ ).rejects.toEqual( expect.objectContaining({ code: 'missingPassword' }))
166
+ })
167
+
168
+ })
@@ -0,0 +1,129 @@
1
+ import { Collection } from '../types/utility-types'
2
+ import { AuthService, RejectedCallback, ResovedCallback } from "./auth"
3
+ import { UserCredentials, SignData, AuthProvider } from "./user-auth-types"
4
+
5
+ export class AuthMock extends AuthService {
6
+
7
+ signUp<T extends {}>( signData: SignData ): Promise<UserCredentials<T>> {
8
+ const { verificationLink, email, password, authProvider } = signData
9
+
10
+ const promise = new Promise<UserCredentials<T>>( async ( resolve: ResovedCallback<T>, reject: RejectedCallback ) => {
11
+ if ( authProvider === 'email' ) {
12
+ if ( !email ) reject({ code: 'missingEmail', message: 'missingEmail' })
13
+ if ( !password ) reject({ code: 'missingPassword', message: 'missingPassword' })
14
+ }
15
+ if ( password !== 'fail' && email !== 'fail' ) {
16
+ this._loggedUser = this.userCredentials<T>( signData )
17
+ this._fakeRegisteredUsers[ this._loggedUser.id ] = this._loggedUser
18
+ resolve( this._loggedUser as UserCredentials<T> )
19
+ this.notifyChange?.( this._loggedUser )
20
+ }
21
+ else {
22
+ reject({ code: 'userNotFound', message: verificationLink || 'Test auth error' })
23
+ this.notifyChange?.( undefined )
24
+ }
25
+ })
26
+ this.pendingPromises.push( promise )
27
+ return promise
28
+ }
29
+
30
+ login<T extends {}>( signData: SignData ): Promise<UserCredentials<T>> {
31
+ const fakeUser = Object.values( this._fakeRegisteredUsers ).find(
32
+ user => user.email === signData.email
33
+ )
34
+
35
+ if ( signData.authProvider === 'email' && !fakeUser && signData.email) {
36
+ signData.email = 'fail'
37
+ }
38
+
39
+ return this.signUp( signData )
40
+ }
41
+
42
+ onAuthStateChange<T extends {}>( onChange: ( userCredentials: UserCredentials<T> )=>void ) {
43
+ this.notifyChange = onChange
44
+ this.notifyChange( this._loggedUser )
45
+ }
46
+
47
+ async logout(): Promise<void> {
48
+ const promise = new Promise<void>( resolve => {
49
+ this._loggedUser = undefined
50
+ resolve()
51
+ this.notifyChange?.( undefined )
52
+ })
53
+ this.pendingPromises.push( promise )
54
+ return promise
55
+ }
56
+
57
+ resetEmailPassword( email: string ) {
58
+ const fakeUserExists = Object.values( this._fakeRegisteredUsers ).find(
59
+ user => user.email === email
60
+ )
61
+
62
+ if ( fakeUserExists ) return Promise.resolve()
63
+ else return Promise.reject({ code: 'userNotFound', message: 'Test auth error' })
64
+ }
65
+
66
+ resendVerificationEmail( email: string, _password: string, _verificationLink: string ) {
67
+ const fakeUserExists = Object.values( this._fakeRegisteredUsers ).find(
68
+ user => user.email === email
69
+ )
70
+
71
+ if ( fakeUserExists ) return Promise.resolve()
72
+ else return Promise.reject({ code: 'userNotFound', message: 'Test auth error' })
73
+ }
74
+
75
+ override refreshToken(): Promise<void> {
76
+ return Promise.resolve()
77
+ }
78
+
79
+ linkAdditionalProvider( provider: AuthProvider ): Promise<unknown> {
80
+ throw new Error('Not implemented.')
81
+ }
82
+
83
+ unlinkProvider( provider: AuthProvider ): Promise<unknown> {
84
+ throw new Error('Not implemented.')
85
+ }
86
+
87
+ async flush() {
88
+ await Promise.all(this.pendingPromises)
89
+ this.pendingPromises = []
90
+ }
91
+
92
+ fakeRegisteredUser<T extends {}>( userCredentials: UserCredentials<T> ) {
93
+ if ( this._fakeRegisteredUsers[ userCredentials.id ] ) throw new Error( `User with id ${ userCredentials.id } already exists in fake user list`)
94
+ this._fakeRegisteredUsers[ userCredentials.id ] = userCredentials
95
+ return this
96
+ }
97
+
98
+ get fakeRegisteredUsers() {
99
+ return this._fakeRegisteredUsers
100
+ }
101
+
102
+ private userCredentials<T extends {}>( signData: SignData ): UserCredentials<T> {
103
+ const fakeUser = Object.values( this._fakeRegisteredUsers ).find(
104
+ user => user.email === signData.email
105
+ )
106
+
107
+ if ( fakeUser ) {
108
+ return { ...fakeUser as UserCredentials<T> }
109
+ }
110
+ else {
111
+ return ({
112
+ id: signData.authProvider || `testUID${ signData.email? '-' + signData.email : '' }`,
113
+ email: signData.email || 'testEmail',
114
+ name: signData.authProvider || `testName${ signData.email? ' ' + signData.email : '' }` ,
115
+ phoneNumber: 'testPhone',
116
+ customData: {
117
+ role: 'test'
118
+ } as unknown as T,
119
+ lastLogin: 0,
120
+ creationDate: 0
121
+ } as UserCredentials<T>)
122
+ }
123
+ }
124
+
125
+ private pendingPromises: Promise<any>[] = []
126
+ private _loggedUser: UserCredentials<{}> | undefined
127
+ private notifyChange: (( userCredentials: UserCredentials<{}> | undefined ) => void ) | undefined
128
+ private _fakeRegisteredUsers: Collection<UserCredentials<{}>> = {}
129
+ }
@@ -0,0 +1,185 @@
1
+ import { Observable } from '../observable/observable'
2
+ import { AuthProvider, SignData, UserCredentials } from "./user-auth-types"
3
+
4
+ /**
5
+ * The AuthService class is an abstract class that defines the interface of an authentication service.
6
+ * You should derive from this class to implement your own authentication service.
7
+ */
8
+ export abstract class AuthService {
9
+ abstract signUp<T extends {}>( signData: SignData ): Promise<UserCredentials<T>>
10
+ abstract login<T extends {}>( signData: SignData ): Promise<UserCredentials<T>>
11
+ abstract logout(): Promise<void>
12
+ abstract resetEmailPassword( email: string ): Promise<void>
13
+ abstract refreshToken(): Promise<void>
14
+ abstract linkAdditionalProvider( provider: AuthProvider ): Promise<unknown>
15
+ abstract unlinkProvider( provider: AuthProvider ): Promise<unknown>
16
+ abstract onAuthStateChange<T extends {}>( onChange: (userCredentials: UserCredentials<T> | undefined) => void ): void
17
+ abstract resendVerificationEmail( email: string, password: string, verificationLink: string ): Promise<void>
18
+ }
19
+
20
+ export type AuthErrorCode = 'wrongPassword' | 'popupClosedByUser' | 'userNotFound' | 'invalidEmail' | 'missingPassword' | 'missingEmail'
21
+
22
+ export interface AuthError {
23
+ code: AuthErrorCode
24
+ message: string
25
+ }
26
+
27
+ /**
28
+ * Types the callback to accept a user credentials object
29
+ */
30
+ export type ResovedCallback<T extends {}> = ( credentials: UserCredentials<T> ) => void
31
+ export type RejectedCallback = ( reason: AuthError ) => void
32
+
33
+ /**
34
+ * The Auth class is a singleton that provides a unified interface to the authentication service.
35
+ * You should register an authentication service by using `Auth.useAuthService`
36
+ * method before using the Auth class.
37
+ */
38
+ export class Auth extends AuthService {
39
+ static error = { shouldBeRegistered: 'You should register an auth service before using Auth.' }
40
+
41
+ protected constructor() {
42
+ super()
43
+ if (!Auth._authService ) throw ( new Error( Auth.error.shouldBeRegistered ) )
44
+ Auth._authService.onAuthStateChange(
45
+ userCredentials => this.authStateChanged( userCredentials )
46
+ )
47
+ }
48
+
49
+ /**
50
+ * Registers an authentication service to be used by the Auth class.
51
+ * You need to register an authentication service before using the Auth class.
52
+ * @param authService the authentication service to be used by the Auth class
53
+ */
54
+ static useAuthService( authService: AuthService ) {
55
+ if ( Auth._authService != authService ) {
56
+ Auth._authService = authService
57
+ this._instance = undefined
58
+ }
59
+ }
60
+
61
+ /**
62
+ * The instance of the Auth class
63
+ * @returns the authentication service
64
+ */
65
+ static get instance() {
66
+ return this._instance || (this._instance = new this() )
67
+ }
68
+
69
+ /**
70
+ * Signs up a new user
71
+ * @param singData the data to be used to sign up the user
72
+ * @returns a promise that resolves to the user credentials
73
+ * @example
74
+ * // Sign up a new user with email and password
75
+ * Auth.instance.signUp({ authProvider: 'email', email: 'john@test.com', password: '123456' })
76
+ * // Sign up a new user with a Google account
77
+ * Auth.instance.signUp({ authProvider: 'google'})
78
+ */
79
+ signUp<T extends {}>( singData: SignData ): Promise<UserCredentials<T>> {
80
+ return Auth._authService.signUp( singData )
81
+ }
82
+
83
+ /**
84
+ * Logs in an existing user
85
+ * @param singData the data to be used to log in the user
86
+ * @returns a promise that resolves to the user credentials
87
+ * @example
88
+ * // Log in an existing user with email and password
89
+ * Auth.instance.login({ authProvider: 'email', email: 'john@test.com', password: '123456' })
90
+ * // Log in an existing user with a Google account
91
+ * Auth.instance.login({ authProvider: 'google'})
92
+ */
93
+ login<T extends {}>( singData: SignData ): Promise<UserCredentials<T>> {
94
+ return Auth._authService.login( singData )
95
+ }
96
+
97
+ /**
98
+ * Logs out the current user
99
+ * @returns a promise that resolves when the user is logged out
100
+ */
101
+ logout(): Promise<void> {
102
+ return Auth._authService.logout()
103
+ }
104
+
105
+ /**
106
+ * Resets the password associated with the email.
107
+ * @param email the email address of the user to reset the password
108
+ * @returns a promise that resolves when the process is done
109
+ */
110
+ resetEmailPassword( email: string ) {
111
+ return Auth._authService.resetEmailPassword( email )
112
+ }
113
+
114
+ /**
115
+ * Resends the email verification to the user.
116
+ * @returns a promise that resolves when the process is done
117
+ */
118
+ override resendVerificationEmail( email: string, password: string, verificationLink: string ): Promise<void> {
119
+ return Auth._authService.resendVerificationEmail( email, password, verificationLink )
120
+ }
121
+
122
+ override refreshToken(): Promise<void> {
123
+ return Auth._authService.refreshToken()
124
+ }
125
+
126
+ /**
127
+ * Adds a listener to be called when the authentication state changes.
128
+ * @param onChange the listener to be called when the authentication state changes.
129
+ * The listener is called with the user credentials as a parameter.
130
+ * If the user is logged out, the listener is called with `undefined` as a parameter.
131
+ * @returns a function to remove the listener
132
+ * @example
133
+ * // Add a listener to be called when the authentication state changes
134
+ * const removeListener = Auth.instance.onAuthStateChange( userCredentials => {
135
+ * if ( userCredentials ) {
136
+ * // The user is logged in
137
+ * } else {
138
+ * // The user is logged out
139
+ * }
140
+ * })
141
+ */
142
+ onAuthStateChange<T extends {}>( onChange: ( userCredentials: UserCredentials<T> )=>void ) {
143
+ return this._onAuthStateChange.subscribe( onChange )
144
+ }
145
+
146
+ /**
147
+ * Removes a listener that was added by `onAuthStateChange` method.
148
+ * @param onChange the listener to be removed
149
+ */
150
+ removeAuthStateChange<T extends {}>( onChange: ( userCredentials: UserCredentials<T> )=>void ) {
151
+ this._onAuthStateChange.unsubscribe( onChange )
152
+ }
153
+
154
+ /**
155
+ * Links an additional authentication provider to the authenticated user.
156
+ * @param provider the provider to be linked
157
+ * @returns a promise that resolves when the process is done
158
+ * @example
159
+ * // Link a Google account to the auth service
160
+ * Auth.instance.linkAdditionalProvider({ authProvider: 'google' })
161
+ */
162
+ linkAdditionalProvider( provider: AuthProvider ): Promise<unknown> {
163
+ return Auth._authService.linkAdditionalProvider( provider )
164
+ }
165
+
166
+ /**
167
+ * Unlinks an authentication provider from the authenticated user.
168
+ * @param provider the provider to be unlinked
169
+ * @returns a promise that resolves when the process is done
170
+ * @example
171
+ * // Unlink the Google account from the auth service
172
+ * Auth.instance.unlinkProvider({ authProvider: 'google' })
173
+ */
174
+ unlinkProvider( provider: AuthProvider ): Promise<unknown> {
175
+ return Auth._authService.unlinkProvider( provider )
176
+ }
177
+
178
+ private authStateChanged( userCredentials: UserCredentials<{}> | undefined ) {
179
+ this._onAuthStateChange.notify( userCredentials )
180
+ }
181
+
182
+ private static _instance: Auth | undefined = undefined
183
+ private static _authService: AuthService
184
+ private _onAuthStateChange: Observable<UserCredentials<{}>> = new Observable<UserCredentials<{}>>()
185
+ }
@@ -0,0 +1,21 @@
1
+ export interface UserCredentials<T extends {} = {}> {
2
+ id: string
3
+ email: string
4
+ name?: string
5
+ pictureUrl?: string
6
+ phoneNumber?: string
7
+ emailVerified?: boolean
8
+ customData?: T
9
+ lastLogin?: number
10
+ creationDate?: number
11
+ }
12
+
13
+ export type AuthProvider = 'email' | 'facebook' | 'google' | 'twitter'
14
+
15
+ export interface SignData {
16
+ authProvider: AuthProvider
17
+ email?: string
18
+ password?: string
19
+ name?: string
20
+ verificationLink?: string
21
+ }