svelte-firekit 0.2.3 → 0.2.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/dist/components/AuthGuard.svelte +5 -3
- package/dist/components/CustomGuard.svelte +5 -2
- package/dist/components/FirebaseApp.svelte +4 -0
- package/dist/components/SignedIn.svelte +1 -1
- package/dist/components/SignedOut.svelte +1 -1
- package/dist/services/user.svelte.d.ts +14 -2
- package/dist/services/user.svelte.js +48 -24
- package/package.json +1 -1
|
@@ -45,9 +45,11 @@
|
|
|
45
45
|
return firekitAuth.signOut();
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
//
|
|
48
|
+
// Only react after Firebase Auth has fully initialized (first onAuthStateChanged callback).
|
|
49
|
+
// Uses `initialized` instead of `loading` because `loading` gets reused for profile
|
|
50
|
+
// updates and could cause false redirects mid-operation.
|
|
49
51
|
$effect(() => {
|
|
50
|
-
if (firekitUser.
|
|
52
|
+
if (!firekitUser.initialized) return;
|
|
51
53
|
|
|
52
54
|
const isAuth = firekitUser.isAuthenticated;
|
|
53
55
|
const shouldBlock = requireAuth ? !isAuth : isAuth;
|
|
@@ -55,7 +57,7 @@
|
|
|
55
57
|
});
|
|
56
58
|
</script>
|
|
57
59
|
|
|
58
|
-
{#if firekitUser.
|
|
60
|
+
{#if !firekitUser.initialized}
|
|
59
61
|
{#if fallback}
|
|
60
62
|
{@render fallback()}
|
|
61
63
|
{/if}
|
|
@@ -53,8 +53,11 @@
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// Only react after Firebase Auth has fully initialized (first onAuthStateChanged callback).
|
|
57
|
+
// Uses `initialized` instead of `loading` because `loading` gets reused for profile
|
|
58
|
+
// updates and could cause false redirects mid-operation.
|
|
56
59
|
$effect(() => {
|
|
57
|
-
if (firekitUser.
|
|
60
|
+
if (!firekitUser.initialized) return;
|
|
58
61
|
|
|
59
62
|
const isAuth = firekitUser.isAuthenticated;
|
|
60
63
|
const shouldBlock = requireAuth ? !isAuth : isAuth;
|
|
@@ -78,7 +81,7 @@
|
|
|
78
81
|
});
|
|
79
82
|
</script>
|
|
80
83
|
|
|
81
|
-
{#if firekitUser.
|
|
84
|
+
{#if !firekitUser.initialized || isVerifying}
|
|
82
85
|
{#if fallback}
|
|
83
86
|
{@render fallback()}
|
|
84
87
|
{/if}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { firekitAppCheck } from '../services/app-check.svelte.js';
|
|
9
9
|
import { firekitAnalytics } from '../services/analytics.js';
|
|
10
10
|
import { firekitMessaging } from '../services/messaging.svelte.js';
|
|
11
|
+
import { firekitUser } from '../services/user.svelte.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Root provider component. Initializes Firebase (and optionally App Check) and
|
|
@@ -75,6 +76,9 @@
|
|
|
75
76
|
setContext('firebase/app-check', firekitAppCheck.initialized ? firebaseService.appCheck : null);
|
|
76
77
|
setContext('firebase/analytics', firekitAnalytics);
|
|
77
78
|
setContext('firebase/messaging', firekitMessaging);
|
|
79
|
+
|
|
80
|
+
// Now that Firebase is configured, start the auth state listener.
|
|
81
|
+
firekitUser.initialize();
|
|
78
82
|
}
|
|
79
83
|
</script>
|
|
80
84
|
|
|
@@ -36,9 +36,20 @@ declare class FirekitUserStore {
|
|
|
36
36
|
private _photoURL;
|
|
37
37
|
private _uid;
|
|
38
38
|
private _phoneNumber;
|
|
39
|
+
private _listening;
|
|
39
40
|
private constructor();
|
|
40
41
|
static getInstance(): FirekitUserStore;
|
|
41
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Called by FirebaseApp after initFirekit() to start the auth listener.
|
|
44
|
+
* Safe to call multiple times — only the first call has an effect.
|
|
45
|
+
*/
|
|
46
|
+
initialize(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Ensures the onAuthStateChanged listener is registered.
|
|
49
|
+
* Called lazily from initialize() or from any public getter/method
|
|
50
|
+
* so the store self-heals if Firebase was configured after import.
|
|
51
|
+
*/
|
|
52
|
+
private ensureListening;
|
|
42
53
|
private listenToAuthState;
|
|
43
54
|
private syncToFirestore;
|
|
44
55
|
private currentFirebaseUser;
|
|
@@ -66,9 +77,10 @@ declare class FirekitUserStore {
|
|
|
66
77
|
updateExtendedData(data: Partial<ExtendedUserData>): Promise<void>;
|
|
67
78
|
/**
|
|
68
79
|
* Resolves once Firebase Auth has initialized (first `onAuthStateChanged` callback).
|
|
80
|
+
* Rejects after `timeoutMs` (default 10 000 ms) if auth never initializes.
|
|
69
81
|
* Safe to call server-side — will resolve immediately with null.
|
|
70
82
|
*/
|
|
71
|
-
waitForAuth(): Promise<UserProfile | null>;
|
|
83
|
+
waitForAuth(timeoutMs?: number): Promise<UserProfile | null>;
|
|
72
84
|
clearError(): void;
|
|
73
85
|
}
|
|
74
86
|
export declare const firekitUser: FirekitUserStore;
|
|
@@ -34,10 +34,10 @@ class FirekitUserStore {
|
|
|
34
34
|
_photoURL = $derived(this._user?.photoURL ?? null);
|
|
35
35
|
_uid = $derived(this._user?.uid ?? null);
|
|
36
36
|
_phoneNumber = $derived(this._user?.phoneNumber ?? null);
|
|
37
|
+
_listening = false;
|
|
37
38
|
constructor() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
39
|
+
// Do NOT bootstrap here — Firebase config may not be set yet.
|
|
40
|
+
// Auth listener is set up lazily via initialize() or ensureListening().
|
|
41
41
|
}
|
|
42
42
|
static getInstance() {
|
|
43
43
|
if (!FirekitUserStore.instance) {
|
|
@@ -45,7 +45,23 @@ class FirekitUserStore {
|
|
|
45
45
|
}
|
|
46
46
|
return FirekitUserStore.instance;
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Called by FirebaseApp after initFirekit() to start the auth listener.
|
|
50
|
+
* Safe to call multiple times — only the first call has an effect.
|
|
51
|
+
*/
|
|
52
|
+
initialize() {
|
|
53
|
+
if (typeof window === 'undefined')
|
|
54
|
+
return;
|
|
55
|
+
this.ensureListening();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Ensures the onAuthStateChanged listener is registered.
|
|
59
|
+
* Called lazily from initialize() or from any public getter/method
|
|
60
|
+
* so the store self-heals if Firebase was configured after import.
|
|
61
|
+
*/
|
|
62
|
+
ensureListening() {
|
|
63
|
+
if (this._listening)
|
|
64
|
+
return;
|
|
49
65
|
try {
|
|
50
66
|
this.auth = firebaseService.getAuthInstance();
|
|
51
67
|
try {
|
|
@@ -54,12 +70,11 @@ class FirekitUserStore {
|
|
|
54
70
|
catch {
|
|
55
71
|
this.firestore = null;
|
|
56
72
|
}
|
|
73
|
+
this._listening = true;
|
|
57
74
|
this.listenToAuthState();
|
|
58
75
|
}
|
|
59
|
-
catch
|
|
60
|
-
|
|
61
|
-
this._loading = false;
|
|
62
|
-
this._initialized = true;
|
|
76
|
+
catch {
|
|
77
|
+
// Firebase not yet configured — will retry on next access
|
|
63
78
|
}
|
|
64
79
|
}
|
|
65
80
|
listenToAuthState() {
|
|
@@ -85,18 +100,20 @@ class FirekitUserStore {
|
|
|
85
100
|
return validateCurrentUser(this.auth);
|
|
86
101
|
}
|
|
87
102
|
// ── Public getters (reactive) ────────────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
get
|
|
91
|
-
get
|
|
92
|
-
get
|
|
93
|
-
get
|
|
94
|
-
get
|
|
95
|
-
get
|
|
96
|
-
get
|
|
97
|
-
get
|
|
98
|
-
get
|
|
99
|
-
get
|
|
103
|
+
// Each getter calls ensureListening() so the auth listener is registered
|
|
104
|
+
// on first access, even if initialize() hasn't been called yet.
|
|
105
|
+
get user() { this.ensureListening(); return this._user; }
|
|
106
|
+
get loading() { this.ensureListening(); return this._loading; }
|
|
107
|
+
get initialized() { this.ensureListening(); return this._initialized; }
|
|
108
|
+
get error() { this.ensureListening(); return this._error; }
|
|
109
|
+
get isAuthenticated() { this.ensureListening(); return this._isAuthenticated; }
|
|
110
|
+
get isAnonymous() { this.ensureListening(); return this._isAnonymous; }
|
|
111
|
+
get isEmailVerified() { this.ensureListening(); return this._isEmailVerified; }
|
|
112
|
+
get email() { this.ensureListening(); return this._email; }
|
|
113
|
+
get displayName() { this.ensureListening(); return this._displayName; }
|
|
114
|
+
get photoURL() { this.ensureListening(); return this._photoURL; }
|
|
115
|
+
get uid() { this.ensureListening(); return this._uid; }
|
|
116
|
+
get phoneNumber() { this.ensureListening(); return this._phoneNumber; }
|
|
100
117
|
// ── Profile updates ──────────────────────────────────────────────────────────
|
|
101
118
|
async updateDisplayName(displayName) {
|
|
102
119
|
const user = this.currentFirebaseUser();
|
|
@@ -253,17 +270,24 @@ class FirekitUserStore {
|
|
|
253
270
|
// ── Utility ──────────────────────────────────────────────────────────────────
|
|
254
271
|
/**
|
|
255
272
|
* Resolves once Firebase Auth has initialized (first `onAuthStateChanged` callback).
|
|
273
|
+
* Rejects after `timeoutMs` (default 10 000 ms) if auth never initializes.
|
|
256
274
|
* Safe to call server-side — will resolve immediately with null.
|
|
257
275
|
*/
|
|
258
|
-
waitForAuth() {
|
|
276
|
+
waitForAuth(timeoutMs = 10_000) {
|
|
277
|
+
if (typeof window === 'undefined')
|
|
278
|
+
return Promise.resolve(null);
|
|
279
|
+
this.ensureListening();
|
|
259
280
|
if (this._initialized)
|
|
260
281
|
return Promise.resolve(this._user);
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
282
|
+
return new Promise((resolve, reject) => {
|
|
283
|
+
const timer = setTimeout(() => {
|
|
284
|
+
stop();
|
|
285
|
+
reject(new Error('waitForAuth timed out — Firebase Auth did not initialize.'));
|
|
286
|
+
}, timeoutMs);
|
|
264
287
|
const stop = $effect.root(() => {
|
|
265
288
|
$effect(() => {
|
|
266
289
|
if (this._initialized) {
|
|
290
|
+
clearTimeout(timer);
|
|
267
291
|
stop();
|
|
268
292
|
resolve(this._user);
|
|
269
293
|
}
|