svelte-firekit 0.0.9 → 0.0.11
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/auth/reset-password.svelte +27 -15
- package/dist/auth/reset-password.svelte.d.ts +7 -17
- package/dist/auth/sign-in.svelte +51 -23
- package/dist/auth/sign-in.svelte.d.ts +11 -1
- package/dist/auth/sign-up.svelte +62 -23
- package/dist/auth/sign-up.svelte.d.ts +13 -0
- package/dist/components/app/nav/app-sidebar.svelte +35 -0
- package/dist/components/app/nav/app-sidebar.svelte.d.ts +8 -0
- package/dist/components/app/nav/breadcrumb.svelte +42 -0
- package/dist/components/app/nav/breadcrumb.svelte.d.ts +19 -0
- package/dist/components/auth/google-sign-in.svelte +55 -53
- package/dist/components/auth/reset-password-form.svelte +49 -47
- package/dist/components/auth/reset-password-form.svelte.d.ts +3 -17
- package/dist/components/auth/sign-in-form.svelte +21 -5
- package/dist/components/auth/sign-in-form.svelte.d.ts +7 -17
- package/dist/components/auth/sign-up-form.svelte +127 -110
- package/dist/components/auth/sign-up-form.svelte.d.ts +10 -17
- package/dist/components/auth/user-button/profile-section/avatar-user.svelte +107 -0
- package/dist/components/auth/user-button/profile-section/avatar-user.svelte.d.ts +2 -0
- package/dist/components/auth/user-button/profile-section/connect-user.svelte +45 -0
- package/dist/components/auth/user-button/profile-section/connect-user.svelte.d.ts +18 -0
- package/dist/components/auth/user-button/profile-section/email-user.svelte +81 -0
- package/dist/components/auth/user-button/profile-section/email-user.svelte.d.ts +2 -0
- package/dist/components/auth/user-button/profile-section/phone-user.svelte +122 -0
- package/dist/components/auth/user-button/profile-section/phone-user.svelte.d.ts +2 -0
- package/dist/components/auth/user-button/profile-section/profile-section.svelte +17 -0
- package/dist/components/auth/user-button/profile-section/profile-section.svelte.d.ts +18 -0
- package/dist/components/auth/user-button/settings-dialog.svelte +80 -87
- package/dist/components/auth/user-button/type-account.svelte +35 -0
- package/dist/components/auth/user-button/type-account.svelte.d.ts +4 -0
- package/dist/components/auth/user-button/user-button.svelte +122 -112
- package/dist/components/nav/nav-main.svelte +70 -0
- package/dist/components/nav/nav-main.svelte.d.ts +18 -0
- package/dist/components/ui/badge/badge.svelte +49 -0
- package/dist/components/ui/badge/badge.svelte.d.ts +59 -0
- package/dist/components/ui/badge/index.d.ts +2 -0
- package/dist/components/ui/badge/index.js +2 -0
- package/dist/components/ui/collapsible/index.d.ts +5 -0
- package/dist/components/ui/collapsible/index.js +7 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +28 -0
- package/dist/firebase/auth/auth-guard.svelte.d.ts +0 -30
- package/dist/firebase/auth/auth-guard.svelte.js +119 -102
- package/dist/firebase/auth/auth-manager.svelte.d.ts +73 -0
- package/dist/firebase/auth/auth-manager.svelte.js +257 -0
- package/dist/firebase/auth/auth.js +2 -2
- package/dist/firebase/auth/user.svelte.d.ts +0 -49
- package/dist/firebase/auth/user.svelte.js +177 -115
- package/dist/firebase/firestore/document-mutations.svelte.js +14 -11
- package/dist/firebase/storage/upload-task.svelte.d.ts +1 -0
- package/dist/firebase/storage/upload-task.svelte.js +4 -2
- package/dist/index.d.ts +1 -3
- package/dist/index.js +3 -3
- package/dist/types/nav.d.ts +4 -0
- package/package.json +4 -2
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { browser } from "$app/environment";
|
|
2
|
+
import { goto } from "$app/navigation";
|
|
3
|
+
import { firebaseService } from "../firebase.js";
|
|
4
|
+
import { toast } from "svelte-sonner";
|
|
5
|
+
import { onAuthStateChanged, updateCurrentUser, updateEmail, updatePassword, updatePhoneNumber, updateProfile, } from "firebase/auth";
|
|
6
|
+
import { doc, getDoc, setDoc, updateDoc, } from "firebase/firestore";
|
|
7
|
+
import { firekitAuth } from "./auth.js";
|
|
8
|
+
export class FirekitAuthManager {
|
|
9
|
+
static instance;
|
|
10
|
+
// User-related states
|
|
11
|
+
_user = $state();
|
|
12
|
+
_userData = $state(null);
|
|
13
|
+
_claims = $state({});
|
|
14
|
+
_initialized = $state(false);
|
|
15
|
+
_initPromise = null;
|
|
16
|
+
// Auth-Guard related states
|
|
17
|
+
_loading = $state(true);
|
|
18
|
+
_error = $state(null);
|
|
19
|
+
_lastValidationTime = 0;
|
|
20
|
+
VALIDATION_THROTTLE = 1000; // 1 second
|
|
21
|
+
// Derived states
|
|
22
|
+
isLoggedIn = $derived(Boolean(this._user));
|
|
23
|
+
uid = $derived(this._user?.uid);
|
|
24
|
+
email = $derived(this._user?.email);
|
|
25
|
+
displayName = $derived(this._user?.displayName);
|
|
26
|
+
photoURL = $derived(this._user?.photoURL);
|
|
27
|
+
emailVerified = $derived(this._user?.emailVerified);
|
|
28
|
+
claims = $derived(this._claims);
|
|
29
|
+
data = $derived(this._userData);
|
|
30
|
+
initialized = $derived(this._initialized);
|
|
31
|
+
constructor() {
|
|
32
|
+
if (browser) {
|
|
33
|
+
this.initialize();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
static getInstance() {
|
|
37
|
+
if (!FirekitAuthManager.instance) {
|
|
38
|
+
FirekitAuthManager.instance = new FirekitAuthManager();
|
|
39
|
+
}
|
|
40
|
+
return FirekitAuthManager.instance;
|
|
41
|
+
}
|
|
42
|
+
async initialize() {
|
|
43
|
+
if (this._initialized)
|
|
44
|
+
return;
|
|
45
|
+
this._initPromise = new Promise((resolve) => {
|
|
46
|
+
onAuthStateChanged(firebaseService.getAuthInstance(), async (user) => {
|
|
47
|
+
this._user = user;
|
|
48
|
+
if (user) {
|
|
49
|
+
await Promise.all([this.loadUserData(), this.loadUserClaims()]);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
this._userData = null;
|
|
53
|
+
this._claims = {};
|
|
54
|
+
}
|
|
55
|
+
this._initialized = true;
|
|
56
|
+
resolve();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async waitForInit() {
|
|
61
|
+
if (this._initialized)
|
|
62
|
+
return;
|
|
63
|
+
return this._initPromise || Promise.resolve();
|
|
64
|
+
}
|
|
65
|
+
async loadUserData() {
|
|
66
|
+
if (!this._user?.uid)
|
|
67
|
+
return;
|
|
68
|
+
const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
|
|
69
|
+
const docSnap = await getDoc(docRef);
|
|
70
|
+
if (docSnap.exists()) {
|
|
71
|
+
this._userData = docSnap.data();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const initialData = {
|
|
75
|
+
displayName: this._user.displayName || "",
|
|
76
|
+
email: this._user.email || "",
|
|
77
|
+
photoURL: this._user.photoURL || "",
|
|
78
|
+
createdAt: new Date(),
|
|
79
|
+
updatedAt: new Date(),
|
|
80
|
+
isProfileComplete: false,
|
|
81
|
+
};
|
|
82
|
+
await this.saveUserData(initialData);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async loadUserClaims() {
|
|
86
|
+
if (!this._user)
|
|
87
|
+
return;
|
|
88
|
+
const tokenResult = await this._user.getIdTokenResult();
|
|
89
|
+
this._claims = tokenResult.claims;
|
|
90
|
+
}
|
|
91
|
+
get user() {
|
|
92
|
+
return this._user;
|
|
93
|
+
}
|
|
94
|
+
async updateEmailUser(email) {
|
|
95
|
+
if (!this._user)
|
|
96
|
+
throw new Error("No authenticated user");
|
|
97
|
+
try {
|
|
98
|
+
await updateEmail(this._user, email);
|
|
99
|
+
await this.updateUserData({ email });
|
|
100
|
+
toast.success("Email updated successfully!", {
|
|
101
|
+
description: "Please note that you will be logged out, and you will need to log in again using your new email address.",
|
|
102
|
+
});
|
|
103
|
+
setTimeout(async () => {
|
|
104
|
+
await firekitAuth.logOut();
|
|
105
|
+
}, 4500);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
toast.error(error.message);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async updatePassword(password) {
|
|
112
|
+
if (!this._user)
|
|
113
|
+
throw new Error("No authenticated user");
|
|
114
|
+
await updatePassword(this._user, password);
|
|
115
|
+
}
|
|
116
|
+
async updateProfileInfo({ displayName, photoURL, }) {
|
|
117
|
+
if (!this._user)
|
|
118
|
+
throw new Error("No authenticated user");
|
|
119
|
+
if (!displayName && !photoURL)
|
|
120
|
+
return;
|
|
121
|
+
if (displayName)
|
|
122
|
+
await updateProfile(this._user, { displayName });
|
|
123
|
+
if (photoURL)
|
|
124
|
+
await updateProfile(this._user, { photoURL });
|
|
125
|
+
}
|
|
126
|
+
async updateUserData(data) {
|
|
127
|
+
if (!this._user?.uid)
|
|
128
|
+
throw new Error("No authenticated user");
|
|
129
|
+
const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
|
|
130
|
+
const updateData = { ...data, updatedAt: new Date() };
|
|
131
|
+
await updateDoc(docRef, updateData);
|
|
132
|
+
await this.loadUserData();
|
|
133
|
+
}
|
|
134
|
+
async saveUserData(data) {
|
|
135
|
+
if (!this._user?.uid)
|
|
136
|
+
throw new Error("No authenticated user");
|
|
137
|
+
const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
|
|
138
|
+
const saveData = {
|
|
139
|
+
...data,
|
|
140
|
+
createdAt: data.createdAt || new Date(),
|
|
141
|
+
updatedAt: new Date(),
|
|
142
|
+
};
|
|
143
|
+
await setDoc(docRef, saveData);
|
|
144
|
+
await this.loadUserData();
|
|
145
|
+
}
|
|
146
|
+
hasRequiredClaims(requiredClaims) {
|
|
147
|
+
return requiredClaims.every((claim) => this._claims[claim]);
|
|
148
|
+
}
|
|
149
|
+
isAdmin() {
|
|
150
|
+
return Boolean(this._claims.admin);
|
|
151
|
+
}
|
|
152
|
+
isPremium() {
|
|
153
|
+
return Boolean(this._claims.premium);
|
|
154
|
+
}
|
|
155
|
+
shouldThrottleValidation() {
|
|
156
|
+
const now = Date.now();
|
|
157
|
+
if (now - this._lastValidationTime < this.VALIDATION_THROTTLE) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
this._lastValidationTime = now;
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
async handleRedirect(redirectTo, params) {
|
|
164
|
+
const url = new URL(redirectTo, window.location.origin);
|
|
165
|
+
if (params) {
|
|
166
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
167
|
+
url.searchParams.append(key, value);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
await goto(url.toString());
|
|
171
|
+
}
|
|
172
|
+
async validateClaims(requiredClaims, userClaims) {
|
|
173
|
+
if (!requiredClaims.length)
|
|
174
|
+
return true;
|
|
175
|
+
if (!userClaims)
|
|
176
|
+
return false;
|
|
177
|
+
return requiredClaims.every((claim) => userClaims[claim]);
|
|
178
|
+
}
|
|
179
|
+
async validateAuth({ authRequired = true, redirectTo = "/login", requiredClaims = [], requiredData, allowIf, redirectParams, } = {}) {
|
|
180
|
+
if (!browser)
|
|
181
|
+
return true;
|
|
182
|
+
if (this.shouldThrottleValidation())
|
|
183
|
+
return true;
|
|
184
|
+
try {
|
|
185
|
+
this._loading = true;
|
|
186
|
+
this._error = null;
|
|
187
|
+
await this.waitForInit();
|
|
188
|
+
const isAuthenticated = this.isLoggedIn;
|
|
189
|
+
if (authRequired && !isAuthenticated) {
|
|
190
|
+
await this.handleRedirect(redirectTo, {
|
|
191
|
+
...redirectParams,
|
|
192
|
+
returnTo: window.location.pathname,
|
|
193
|
+
});
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
if (allowIf && !allowIf(this)) {
|
|
197
|
+
await this.handleRedirect(redirectTo, redirectParams);
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
if (requiredClaims.length > 0) {
|
|
201
|
+
const userClaims = await firekitAuthManager.user?.getIdTokenResult();
|
|
202
|
+
const hasClaims = await this.validateClaims(requiredClaims, userClaims?.claims);
|
|
203
|
+
if (!hasClaims) {
|
|
204
|
+
await this.handleRedirect(redirectTo, redirectParams);
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (requiredData && !requiredData(this._userData)) {
|
|
209
|
+
await this.handleRedirect(redirectTo, redirectParams);
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
this._error = error instanceof Error ? error : new Error(String(error));
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
this._loading = false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async requireAuth(redirectTo = "/login", redirectParams) {
|
|
223
|
+
return this.validateAuth({
|
|
224
|
+
authRequired: true,
|
|
225
|
+
redirectTo,
|
|
226
|
+
redirectParams,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
async requireNoAuth(redirectTo = "/dashboard", redirectParams) {
|
|
230
|
+
return this.validateAuth({
|
|
231
|
+
authRequired: false,
|
|
232
|
+
redirectTo,
|
|
233
|
+
redirectParams,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
async requireClaims(claims, redirectTo = "/login", redirectParams) {
|
|
237
|
+
return this.validateAuth({
|
|
238
|
+
requiredClaims: claims,
|
|
239
|
+
redirectTo,
|
|
240
|
+
redirectParams,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async requireData(validator, redirectTo = "/login", redirectParams) {
|
|
244
|
+
return this.validateAuth({
|
|
245
|
+
requiredData: validator,
|
|
246
|
+
redirectTo,
|
|
247
|
+
redirectParams,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
get loading() {
|
|
251
|
+
return this._loading;
|
|
252
|
+
}
|
|
253
|
+
get error() {
|
|
254
|
+
return this._error;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
export const firekitAuthManager = FirekitAuthManager.getInstance();
|
|
@@ -40,8 +40,8 @@ class FirekitAuth {
|
|
|
40
40
|
photoURL: user.photoURL,
|
|
41
41
|
isAnonymous: user.isAnonymous,
|
|
42
42
|
providerId: user.providerId,
|
|
43
|
-
phoneNumber: user.phoneNumber,
|
|
44
|
-
providerData: user.providerData
|
|
43
|
+
// phoneNumber: user.phoneNumber,
|
|
44
|
+
providerData: user.providerData,
|
|
45
45
|
};
|
|
46
46
|
await setDoc(ref, userData, { merge: true });
|
|
47
47
|
}
|
|
@@ -1,50 +1 @@
|
|
|
1
|
-
import { type User } from "firebase/auth";
|
|
2
|
-
import { type DocumentData } from 'firebase/firestore';
|
|
3
|
-
interface UserClaims {
|
|
4
|
-
[key: string]: any;
|
|
5
|
-
admin?: boolean;
|
|
6
|
-
premium?: boolean;
|
|
7
|
-
}
|
|
8
|
-
interface UserData extends DocumentData {
|
|
9
|
-
displayName?: string;
|
|
10
|
-
email?: string;
|
|
11
|
-
photoURL?: string;
|
|
12
|
-
createdAt?: Date;
|
|
13
|
-
updatedAt?: Date;
|
|
14
|
-
isProfileComplete?: boolean;
|
|
15
|
-
role?: string;
|
|
16
|
-
settings?: Record<string, any>;
|
|
17
|
-
[key: string]: any;
|
|
18
|
-
}
|
|
19
|
-
export declare class FirekitUser {
|
|
20
|
-
private static instance;
|
|
21
|
-
private _user;
|
|
22
|
-
private _userData;
|
|
23
|
-
private _claims;
|
|
24
|
-
readonly isLoggedIn: boolean;
|
|
25
|
-
readonly uid: string | undefined;
|
|
26
|
-
readonly email: string | null | undefined;
|
|
27
|
-
readonly displayName: string | null | undefined;
|
|
28
|
-
readonly photoURL: string | null | undefined;
|
|
29
|
-
readonly emailVerified: boolean | undefined;
|
|
30
|
-
readonly claims: UserClaims;
|
|
31
|
-
readonly data: UserData | null;
|
|
32
|
-
constructor();
|
|
33
|
-
static getInstance(): FirekitUser;
|
|
34
|
-
private loadUserData;
|
|
35
|
-
private loadUserClaims;
|
|
36
|
-
get user(): User | null | undefined;
|
|
37
|
-
updateEmail(email: string): Promise<void>;
|
|
38
|
-
updatePassword(password: string): Promise<void>;
|
|
39
|
-
updateProfile({ displayName, photoURL }: {
|
|
40
|
-
displayName?: string;
|
|
41
|
-
photoURL?: string;
|
|
42
|
-
}): Promise<void>;
|
|
43
|
-
updateUserData(data: Partial<UserData>): Promise<void>;
|
|
44
|
-
saveUserData(data: UserData): Promise<void>;
|
|
45
|
-
hasRequiredClaims(requiredClaims: string[]): boolean;
|
|
46
|
-
isAdmin(): boolean;
|
|
47
|
-
isPremium(): boolean;
|
|
48
|
-
}
|
|
49
|
-
export declare const firekitUser: FirekitUser;
|
|
50
1
|
export {};
|
|
@@ -1,115 +1,177 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
// import { browser } from "$app/environment";
|
|
3
|
+
// import { firebaseService } from "../firebase.js";
|
|
4
|
+
// import {
|
|
5
|
+
// onAuthStateChanged,
|
|
6
|
+
// updateCurrentUser,
|
|
7
|
+
// updateEmail,
|
|
8
|
+
// updatePassword,
|
|
9
|
+
// updatePhoneNumber,
|
|
10
|
+
// updateProfile,
|
|
11
|
+
// type User,
|
|
12
|
+
// } from "firebase/auth";
|
|
13
|
+
// import {
|
|
14
|
+
// doc,
|
|
15
|
+
// getDoc,
|
|
16
|
+
// setDoc,
|
|
17
|
+
// updateDoc,
|
|
18
|
+
// type DocumentData,
|
|
19
|
+
// } from "firebase/firestore";
|
|
20
|
+
// import { toast } from "svelte-sonner";
|
|
21
|
+
// import { firekitAuth } from "./auth.js";
|
|
22
|
+
// interface UserClaims {
|
|
23
|
+
// [key: string]: any;
|
|
24
|
+
// admin?: boolean;
|
|
25
|
+
// premium?: boolean;
|
|
26
|
+
// }
|
|
27
|
+
// interface UserData extends DocumentData {
|
|
28
|
+
// displayName?: string;
|
|
29
|
+
// email?: string;
|
|
30
|
+
// photoURL?: string;
|
|
31
|
+
// createdAt?: Date;
|
|
32
|
+
// updatedAt?: Date;
|
|
33
|
+
// isProfileComplete?: boolean;
|
|
34
|
+
// role?: string;
|
|
35
|
+
// settings?: Record<string, any>;
|
|
36
|
+
// [key: string]: any;
|
|
37
|
+
// }
|
|
38
|
+
// export class FirekitUser {
|
|
39
|
+
// private static instance: FirekitUser;
|
|
40
|
+
// private _user: User | null | undefined = $state();
|
|
41
|
+
// private _userData: UserData | null = $state(null);
|
|
42
|
+
// private _claims: UserClaims = $state({});
|
|
43
|
+
// private _initialized = $state(false);
|
|
44
|
+
// readonly isLoggedIn = $derived(Boolean(this._user));
|
|
45
|
+
// readonly uid = $derived(this._user?.uid);
|
|
46
|
+
// readonly email = $derived(this._user?.email);
|
|
47
|
+
// readonly displayName = $derived(this._user?.displayName);
|
|
48
|
+
// readonly photoURL = $derived(this._user?.photoURL);
|
|
49
|
+
// readonly emailVerified = $derived(this._user?.emailVerified);
|
|
50
|
+
// readonly claims = $derived(this._claims);
|
|
51
|
+
// readonly data = $derived(this._userData);
|
|
52
|
+
// readonly initialized = $derived(this._initialized);
|
|
53
|
+
// private _initPromise: Promise<void> | null = null;
|
|
54
|
+
// constructor() {
|
|
55
|
+
// if (browser) {
|
|
56
|
+
// // Add this check
|
|
57
|
+
// this.initialize();
|
|
58
|
+
// }
|
|
59
|
+
// }
|
|
60
|
+
// private async initialize(): Promise<void> {
|
|
61
|
+
// if (this._initialized) return;
|
|
62
|
+
// return new Promise((resolve) => {
|
|
63
|
+
// onAuthStateChanged(firebaseService.getAuthInstance(), async (user) => {
|
|
64
|
+
// this._user = user;
|
|
65
|
+
// if (user) {
|
|
66
|
+
// await Promise.all([this.loadUserData(), this.loadUserClaims()]);
|
|
67
|
+
// } else {
|
|
68
|
+
// this._userData = null;
|
|
69
|
+
// this._claims = {};
|
|
70
|
+
// }
|
|
71
|
+
// this._initialized = true;
|
|
72
|
+
// resolve();
|
|
73
|
+
// });
|
|
74
|
+
// });
|
|
75
|
+
// }
|
|
76
|
+
// async waitForInit(): Promise<void> {
|
|
77
|
+
// if (this._initialized) return;
|
|
78
|
+
// return this._initPromise || Promise.resolve();
|
|
79
|
+
// }
|
|
80
|
+
// static getInstance(): FirekitUser {
|
|
81
|
+
// if (!FirekitUser.instance) {
|
|
82
|
+
// FirekitUser.instance = new FirekitUser();
|
|
83
|
+
// }
|
|
84
|
+
// return FirekitUser.instance;
|
|
85
|
+
// }
|
|
86
|
+
// private async loadUserData() {
|
|
87
|
+
// if (!this._user?.uid) return;
|
|
88
|
+
// const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
|
|
89
|
+
// const docSnap = await getDoc(docRef);
|
|
90
|
+
// if (docSnap.exists()) {
|
|
91
|
+
// this._userData = docSnap.data() as UserData;
|
|
92
|
+
// } else {
|
|
93
|
+
// // Initialize user document if it doesn't exist
|
|
94
|
+
// const initialData: UserData = {
|
|
95
|
+
// displayName: this._user.displayName || "",
|
|
96
|
+
// email: this._user.email || "",
|
|
97
|
+
// photoURL: this._user.photoURL || "",
|
|
98
|
+
// createdAt: new Date(),
|
|
99
|
+
// updatedAt: new Date(),
|
|
100
|
+
// isProfileComplete: false,
|
|
101
|
+
// };
|
|
102
|
+
// await this.saveUserData(initialData);
|
|
103
|
+
// }
|
|
104
|
+
// }
|
|
105
|
+
// private async loadUserClaims() {
|
|
106
|
+
// if (!this._user) return;
|
|
107
|
+
// const tokenResult = await this._user.getIdTokenResult();
|
|
108
|
+
// this._claims = tokenResult.claims as UserClaims;
|
|
109
|
+
// }
|
|
110
|
+
// get user(): User | null | undefined {
|
|
111
|
+
// return this._user;
|
|
112
|
+
// }
|
|
113
|
+
// async updateEmailUser(email: string) {
|
|
114
|
+
// let message: string = "";
|
|
115
|
+
// if (!this._user) throw new Error("No authenticated user");
|
|
116
|
+
// try {
|
|
117
|
+
// await updateEmail(this._user, email);
|
|
118
|
+
// await this.updateUserData({ email });
|
|
119
|
+
// toast.success("Email updated successfully!", {
|
|
120
|
+
// description:
|
|
121
|
+
// "Please note that you will be logged out, and you will need to log in again using your new email address.",
|
|
122
|
+
// });
|
|
123
|
+
// setTimeout(async () => {
|
|
124
|
+
// await firekitAuth.logOut();
|
|
125
|
+
// }, 4500);
|
|
126
|
+
// } catch (error) {
|
|
127
|
+
// toast.error(error.message);
|
|
128
|
+
// }
|
|
129
|
+
// }
|
|
130
|
+
// async updatePassword(password: string) {
|
|
131
|
+
// if (!this._user) throw new Error("No authenticated user");
|
|
132
|
+
// await updatePassword(this._user, password);
|
|
133
|
+
// }
|
|
134
|
+
// async updateProfileInfo({
|
|
135
|
+
// displayName,
|
|
136
|
+
// photoURL,
|
|
137
|
+
// }: {
|
|
138
|
+
// displayName?: string;
|
|
139
|
+
// photoURL?: string;
|
|
140
|
+
// }) {
|
|
141
|
+
// if (!this._user) throw new Error("No authenticated user");
|
|
142
|
+
// if (!displayName && !photoURL) return;
|
|
143
|
+
// if (displayName) await updateProfile(this._user, { displayName });
|
|
144
|
+
// if (photoURL) await updateProfile(this._user, { photoURL });
|
|
145
|
+
// }
|
|
146
|
+
// async updateUserData(data: Partial<UserData>) {
|
|
147
|
+
// if (!this._user?.uid) throw new Error("No authenticated user");
|
|
148
|
+
// const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
|
|
149
|
+
// const updateData = {
|
|
150
|
+
// ...data,
|
|
151
|
+
// updatedAt: new Date(),
|
|
152
|
+
// };
|
|
153
|
+
// await updateDoc(docRef, updateData);
|
|
154
|
+
// await this.loadUserData(); // Reload user data
|
|
155
|
+
// }
|
|
156
|
+
// async saveUserData(data: UserData) {
|
|
157
|
+
// if (!this._user?.uid) throw new Error("No authenticated user");
|
|
158
|
+
// const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
|
|
159
|
+
// const saveData = {
|
|
160
|
+
// ...data,
|
|
161
|
+
// createdAt: data.createdAt || new Date(),
|
|
162
|
+
// updatedAt: new Date(),
|
|
163
|
+
// };
|
|
164
|
+
// await setDoc(docRef, saveData);
|
|
165
|
+
// await this.loadUserData(); // Reload user data
|
|
166
|
+
// }
|
|
167
|
+
// hasRequiredClaims(requiredClaims: string[]): boolean {
|
|
168
|
+
// return requiredClaims.every((claim) => this._claims[claim]);
|
|
169
|
+
// }
|
|
170
|
+
// isAdmin(): boolean {
|
|
171
|
+
// return Boolean(this._claims.admin);
|
|
172
|
+
// }
|
|
173
|
+
// isPremium(): boolean {
|
|
174
|
+
// return Boolean(this._claims.premium);
|
|
175
|
+
// }
|
|
176
|
+
// }
|
|
177
|
+
// export const firekitUser = FirekitUser.getInstance();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { addDoc, setDoc, updateDoc, deleteDoc, doc, getDoc, collection, serverTimestamp } from "firebase/firestore";
|
|
1
|
+
import { addDoc, setDoc, updateDoc, deleteDoc, doc, getDoc, collection, serverTimestamp, } from "firebase/firestore";
|
|
2
2
|
import { firebaseService } from "../firebase.js";
|
|
3
|
-
import {
|
|
3
|
+
import { firekitAuthManager } from "../auth/auth-manager.svelte.js";
|
|
4
4
|
class FirekitDocumentMutations {
|
|
5
5
|
constructor() { }
|
|
6
6
|
async add(collectionPath, data, options = { timestamps: true }) {
|
|
@@ -10,24 +10,27 @@ class FirekitDocumentMutations {
|
|
|
10
10
|
...data,
|
|
11
11
|
...(options.timestamps && {
|
|
12
12
|
createdAt: serverTimestamp(),
|
|
13
|
-
createdBy:
|
|
13
|
+
createdBy: firekitAuthManager.uid,
|
|
14
14
|
updatedAt: serverTimestamp(),
|
|
15
|
-
updatedBy:
|
|
16
|
-
})
|
|
15
|
+
updatedBy: firekitAuthManager.uid,
|
|
16
|
+
}),
|
|
17
17
|
};
|
|
18
18
|
return addDoc(colRef, dataToAdd);
|
|
19
19
|
}
|
|
20
|
-
async set(path, data, options = {
|
|
20
|
+
async set(path, data, options = {
|
|
21
|
+
merge: false,
|
|
22
|
+
timestamps: true,
|
|
23
|
+
}) {
|
|
21
24
|
const firestore = firebaseService.getDb();
|
|
22
25
|
const docRef = doc(firestore, path);
|
|
23
26
|
const dataToSet = {
|
|
24
27
|
...data,
|
|
25
28
|
...(options.timestamps && {
|
|
26
29
|
createdAt: serverTimestamp(),
|
|
27
|
-
createdBy:
|
|
30
|
+
createdBy: firekitAuthManager.uid,
|
|
28
31
|
updatedAt: serverTimestamp(),
|
|
29
|
-
updatedBy:
|
|
30
|
-
})
|
|
32
|
+
updatedBy: firekitAuthManager.uid,
|
|
33
|
+
}),
|
|
31
34
|
};
|
|
32
35
|
return setDoc(docRef, dataToSet, { merge: options.merge });
|
|
33
36
|
}
|
|
@@ -38,8 +41,8 @@ class FirekitDocumentMutations {
|
|
|
38
41
|
...data,
|
|
39
42
|
...(options.timestamps && {
|
|
40
43
|
updatedAt: serverTimestamp(),
|
|
41
|
-
updatedBy:
|
|
42
|
-
})
|
|
44
|
+
updatedBy: firekitAuthManager.uid,
|
|
45
|
+
}),
|
|
43
46
|
};
|
|
44
47
|
return updateDoc(docRef, dataToUpdate);
|
|
45
48
|
}
|