Skip to content

Commit 8bd023a

Browse files
committed
feat(auth): getCurrentUser()
1 parent f57c05e commit 8bd023a

File tree

5 files changed

+77
-14
lines changed

5 files changed

+77
-14
lines changed

playground/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"type-check": "vue-tsc --noEmit"
1212
},
1313
"dependencies": {
14-
"pinia": "^2.0.23",
14+
"pinia": "^2.0.24",
1515
"vue": "^3.2.45",
1616
"vue-router": "^4.1.6",
1717
"vuefire": "workspace:*",

playground/src/main.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { createApp } from 'vue'
22
import { createPinia } from 'pinia'
3-
import { firestorePlugin, VueFire, VueFireAuth, VueFireAppCheck } from 'vuefire'
3+
import {
4+
VueFire,
5+
VueFireAuth,
6+
VueFireAppCheck,
7+
VueFireFirestoreOptionsAPI,
8+
VueFireDatabaseOptionsAPI,
9+
getCurrentUser,
10+
} from 'vuefire'
411
import App from './App.vue'
512
import { createFirebaseApp } from './firebase'
613
import { createWebHistory, createRouter } from 'vue-router/auto'
@@ -11,6 +18,10 @@ const router = createRouter({
1118
history: createWebHistory(),
1219
})
1320

21+
router.beforeEach(async () => {
22+
await getCurrentUser()
23+
})
24+
1425
const store = createStore({
1526
// can't work with vuefire
1627
// strict: import.meta.env.DEV,
@@ -34,9 +45,10 @@ app
3445
'6LfJ0vgiAAAAAHheQE7GQVdG_c9m8xipBESx_SKI'
3546
),
3647
}),
48+
VueFireDatabaseOptionsAPI(),
49+
VueFireFirestoreOptionsAPI(),
3750
],
3851
})
39-
.use(firestorePlugin)
4052
.use(store)
4153
.use(router)
4254

src/auth/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useFirebaseApp } from '../app'
55
import { getGlobalScope } from '../globals'
66
import { AuthUserInjectSymbol, setupOnAuthStateChanged } from './user'
77

8-
export { setupOnAuthStateChanged, useCurrentUser } from './user'
8+
export { useCurrentUser, getCurrentUser } from './user'
99

1010
/**
1111
* VueFire Auth Module to be added to the `VueFire` Vue plugin options.

src/auth/user.ts

+55-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { FirebaseApp } from 'firebase/app'
1+
import type { FirebaseApp } from 'firebase/app'
22
import { getAuth, onIdTokenChanged, User } from 'firebase/auth'
33
import { inject, InjectionKey, Ref } from 'vue'
4+
import { useFirebaseApp } from '../app'
5+
import type { _Nullable } from '../shared'
46

57
export const AuthUserInjectSymbol: InjectionKey<Ref<User | null | undefined>> =
68
Symbol('user')
@@ -14,23 +16,67 @@ export function useCurrentUser() {
1416
return inject(AuthUserInjectSymbol)!
1517
}
1618

19+
// @internal
20+
type _UserState =
21+
// state 1 waiting for the initial load
22+
| [Promise<_Nullable<User>>, (user: Ref<_Nullable<User>>) => void]
23+
// state 2 loaded
24+
| Ref<_Nullable<User>>
25+
26+
const initialUserMap = new WeakMap<FirebaseApp, _UserState>()
27+
28+
// @internal
29+
function _getCurrentUserState() {
30+
const firebaseApp = useFirebaseApp()
31+
if (!initialUserMap.has(firebaseApp)) {
32+
let resolve!: (resolvedUser: _Nullable<User>) => void
33+
const promise = new Promise<_Nullable<User>>((_resolve) => {
34+
resolve = _resolve
35+
})
36+
37+
const userState: _UserState = [
38+
promise,
39+
(user: Ref<_Nullable<User>>) => {
40+
initialUserMap.set(firebaseApp, user)
41+
// resolve the actual promise
42+
resolve(user.value)
43+
},
44+
]
45+
46+
initialUserMap.set(firebaseApp, userState)
47+
}
48+
49+
return initialUserMap.get(firebaseApp)!
50+
}
51+
52+
/**
53+
* Returns a promise that resolves the current user once the user is loaded. Must be called after the firebase app is
54+
* initialized.
55+
*/
56+
export function getCurrentUser(): Promise<_Nullable<User>> {
57+
const userOrPromise = _getCurrentUserState()
58+
59+
return Array.isArray(userOrPromise)
60+
? userOrPromise[0]
61+
: Promise.resolve(userOrPromise.value)
62+
}
63+
1764
export function setupOnAuthStateChanged(
18-
user: Ref<User | null | undefined>,
65+
user: Ref<_Nullable<User>>,
1966
app?: FirebaseApp
2067
) {
2168
const auth = getAuth(app)
22-
let resolve!: (value: User | null) => void
23-
const isReady = new Promise((_resolve) => {
24-
resolve = _resolve
25-
})
2669

2770
// onAuthStateChanged doesn't trigger in all scenarios like when the user goes links an existing account and their
2871
// data is updated
2972
// https://github.com/firebase/firebase-js-sdk/issues/4227
3073
onIdTokenChanged(auth, (userData) => {
74+
const userOrPromise = _getCurrentUserState()
3175
user.value = userData
32-
resolve(userData)
76+
// setup the initial user
77+
// afterwards, this will never be an array
78+
if (Array.isArray(userOrPromise)) {
79+
userOrPromise[1](user)
80+
}
3381
})
34-
35-
return { isReady }
3682
}

src/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,12 @@ export type {
5555
export { useFirebaseApp } from './app'
5656

5757
// Auth
58-
export { useCurrentUser, VueFireAuth, useFirebaseAuth } from './auth'
58+
export {
59+
useCurrentUser,
60+
VueFireAuth,
61+
useFirebaseAuth,
62+
getCurrentUser,
63+
} from './auth'
5964

6065
// SSR
6166
export { usePendingPromises } from './ssr/plugin'

0 commit comments

Comments
 (0)