svelte-firekit 0.0.11 → 0.0.13

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.
@@ -1,4 +1,3 @@
1
- import { type User } from "firebase/auth";
2
1
  import { type DocumentData } from "firebase/firestore";
3
2
  type UserClaims = Record<string, any>;
4
3
  interface UserData extends DocumentData {
@@ -22,15 +21,17 @@ interface GuardConfig {
22
21
  }
23
22
  export declare class FirekitAuthManager {
24
23
  private static instance;
24
+ private readonly SESSION_TIMEOUT;
25
+ private activityInterval;
26
+ private _initPromise;
25
27
  private _user;
26
28
  private _userData;
27
29
  private _claims;
28
30
  private _initialized;
29
- private _initPromise;
30
31
  private _loading;
31
32
  private _error;
33
+ private _currentSession;
32
34
  private _lastValidationTime;
33
- private readonly VALIDATION_THROTTLE;
34
35
  readonly isLoggedIn: boolean;
35
36
  readonly uid: string | undefined;
36
37
  readonly email: string | null | undefined;
@@ -40,13 +41,28 @@ export declare class FirekitAuthManager {
40
41
  readonly claims: UserClaims;
41
42
  readonly data: UserData | null;
42
43
  readonly initialized: boolean;
44
+ readonly loading: boolean;
45
+ readonly error: Error | null;
46
+ readonly sessionActive: boolean;
43
47
  private constructor();
44
48
  static getInstance(): FirekitAuthManager;
45
49
  private initialize;
46
50
  waitForInit(): Promise<void>;
51
+ private handleAuthStateChange;
47
52
  private loadUserData;
48
53
  private loadUserClaims;
49
- get user(): User | null | undefined;
54
+ private setupActivityTracking;
55
+ private initializeSession;
56
+ private updateLastActivity;
57
+ private checkSession;
58
+ private handleSessionTimeout;
59
+ private clearSession;
60
+ private handleError;
61
+ private generateDeviceId;
62
+ private getPlatformInfo;
63
+ private validateClaims;
64
+ private handleRedirect;
65
+ validateAuth({ authRequired, redirectTo, requiredClaims, requiredData, allowIf, redirectParams, }?: GuardConfig): Promise<boolean>;
50
66
  updateEmailUser(email: string): Promise<void>;
51
67
  updatePassword(password: string): Promise<void>;
52
68
  updateProfileInfo({ displayName, photoURL, }: {
@@ -55,19 +71,17 @@ export declare class FirekitAuthManager {
55
71
  }): Promise<void>;
56
72
  updateUserData(data: Partial<UserData>): Promise<void>;
57
73
  saveUserData(data: UserData): Promise<void>;
74
+ sendVerificationEmail(): Promise<void>;
75
+ refreshUserData(): Promise<void>;
58
76
  hasRequiredClaims(requiredClaims: string[]): boolean;
59
77
  isAdmin(): boolean;
60
78
  isPremium(): boolean;
61
- private shouldThrottleValidation;
62
- private handleRedirect;
63
- private validateClaims;
64
- validateAuth({ authRequired, redirectTo, requiredClaims, requiredData, allowIf, redirectParams, }?: GuardConfig): Promise<boolean>;
65
79
  requireAuth(redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
66
80
  requireNoAuth(redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
67
81
  requireClaims(claims: string[], redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
68
82
  requireData(validator: (data: DocumentData | null) => boolean, redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
69
- get loading(): boolean;
70
- get error(): Error | null;
83
+ logOut(): Promise<void>;
84
+ destroy(): void;
71
85
  }
72
86
  export declare const firekitAuthManager: FirekitAuthManager;
73
87
  export {};
@@ -2,23 +2,33 @@ import { browser } from "$app/environment";
2
2
  import { goto } from "$app/navigation";
3
3
  import { firebaseService } from "../firebase.js";
4
4
  import { toast } from "svelte-sonner";
5
- import { onAuthStateChanged, updateCurrentUser, updateEmail, updatePassword, updatePhoneNumber, updateProfile, } from "firebase/auth";
5
+ import { onAuthStateChanged, updateEmail, updatePassword, updateProfile, sendEmailVerification, } from "firebase/auth";
6
6
  import { doc, getDoc, setDoc, updateDoc, } from "firebase/firestore";
7
- import { firekitAuth } from "./auth.js";
7
+ class AuthError extends Error {
8
+ code;
9
+ originalError;
10
+ constructor(message, code = 'unknown', originalError) {
11
+ super(message);
12
+ this.code = code;
13
+ this.originalError = originalError;
14
+ this.name = 'AuthError';
15
+ }
16
+ }
8
17
  export class FirekitAuthManager {
9
18
  static instance;
10
- // User-related states
19
+ SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes
20
+ activityInterval = null;
21
+ _initPromise = null;
22
+ // State using Svelte 5 runes
11
23
  _user = $state();
12
24
  _userData = $state(null);
13
25
  _claims = $state({});
14
26
  _initialized = $state(false);
15
- _initPromise = null;
16
- // Auth-Guard related states
17
27
  _loading = $state(true);
18
28
  _error = $state(null);
19
- _lastValidationTime = 0;
20
- VALIDATION_THROTTLE = 1000; // 1 second
21
- // Derived states
29
+ _currentSession = $state(null);
30
+ _lastValidationTime = $state(0);
31
+ // Derived state
22
32
  isLoggedIn = $derived(Boolean(this._user));
23
33
  uid = $derived(this._user?.uid);
24
34
  email = $derived(this._user?.email);
@@ -28,9 +38,13 @@ export class FirekitAuthManager {
28
38
  claims = $derived(this._claims);
29
39
  data = $derived(this._userData);
30
40
  initialized = $derived(this._initialized);
41
+ loading = $derived(this._loading);
42
+ error = $derived(this._error);
43
+ sessionActive = $derived(Boolean(this._currentSession));
31
44
  constructor() {
32
45
  if (browser) {
33
46
  this.initialize();
47
+ this.setupActivityTracking();
34
48
  }
35
49
  }
36
50
  static getInstance() {
@@ -43,16 +57,11 @@ export class FirekitAuthManager {
43
57
  if (this._initialized)
44
58
  return;
45
59
  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;
60
+ const auth = firebaseService.getAuthInstance();
61
+ if (!auth)
62
+ throw new AuthError('Firebase Auth not initialized', 'init_failed');
63
+ onAuthStateChanged(auth, async (user) => {
64
+ await this.handleAuthStateChange(user);
56
65
  resolve();
57
66
  });
58
67
  });
@@ -62,19 +71,44 @@ export class FirekitAuthManager {
62
71
  return;
63
72
  return this._initPromise || Promise.resolve();
64
73
  }
65
- async loadUserData() {
66
- if (!this._user?.uid)
67
- return;
68
- const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
74
+ async handleAuthStateChange(user) {
75
+ this._loading = true;
76
+ try {
77
+ if (user) {
78
+ this._user = user;
79
+ await Promise.all([
80
+ this.loadUserData(user.uid),
81
+ this.loadUserClaims(user)
82
+ ]);
83
+ this.initializeSession();
84
+ }
85
+ else {
86
+ this._user = null;
87
+ this._userData = null;
88
+ this._claims = {};
89
+ this.clearSession();
90
+ }
91
+ this._initialized = true;
92
+ this._error = null;
93
+ }
94
+ catch (error) {
95
+ this.handleError(error);
96
+ }
97
+ finally {
98
+ this._loading = false;
99
+ }
100
+ }
101
+ async loadUserData(uid) {
102
+ const docRef = doc(firebaseService.getDb(), "users", uid);
69
103
  const docSnap = await getDoc(docRef);
70
104
  if (docSnap.exists()) {
71
105
  this._userData = docSnap.data();
72
106
  }
73
107
  else {
74
108
  const initialData = {
75
- displayName: this._user.displayName || "",
76
- email: this._user.email || "",
77
- photoURL: this._user.photoURL || "",
109
+ displayName: this._user?.displayName || "",
110
+ email: this._user?.email || "",
111
+ photoURL: this._user?.photoURL || "",
78
112
  createdAt: new Date(),
79
113
  updatedAt: new Date(),
80
114
  isProfileComplete: false,
@@ -82,83 +116,70 @@ export class FirekitAuthManager {
82
116
  await this.saveUserData(initialData);
83
117
  }
84
118
  }
85
- async loadUserClaims() {
86
- if (!this._user)
87
- return;
88
- const tokenResult = await this._user.getIdTokenResult();
119
+ async loadUserClaims(user) {
120
+ const tokenResult = await user.getIdTokenResult();
89
121
  this._claims = tokenResult.claims;
90
122
  }
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.",
123
+ setupActivityTracking() {
124
+ if (browser) {
125
+ ['mousedown', 'keydown', 'scroll', 'touchstart'].forEach(eventName => {
126
+ window.addEventListener(eventName, () => this.updateLastActivity());
102
127
  });
103
- setTimeout(async () => {
104
- await firekitAuth.logOut();
105
- }, 4500);
106
- }
107
- catch (error) {
108
- toast.error(error.message);
128
+ this.activityInterval = setInterval(() => this.checkSession(), 60000);
109
129
  }
110
130
  }
111
- async updatePassword(password) {
112
- if (!this._user)
113
- throw new Error("No authenticated user");
114
- await updatePassword(this._user, password);
131
+ initializeSession() {
132
+ this._currentSession = {
133
+ lastActivity: Date.now(),
134
+ deviceId: this.generateDeviceId(),
135
+ platform: this.getPlatformInfo()
136
+ };
115
137
  }
116
- async updateProfileInfo({ displayName, photoURL, }) {
117
- if (!this._user)
118
- throw new Error("No authenticated user");
119
- if (!displayName && !photoURL)
138
+ updateLastActivity() {
139
+ if (this._currentSession) {
140
+ this._currentSession.lastActivity = Date.now();
141
+ }
142
+ }
143
+ async checkSession() {
144
+ if (!this._currentSession)
120
145
  return;
121
- if (displayName)
122
- await updateProfile(this._user, { displayName });
123
- if (photoURL)
124
- await updateProfile(this._user, { photoURL });
146
+ const inactiveTime = Date.now() - this._currentSession.lastActivity;
147
+ if (inactiveTime > this.SESSION_TIMEOUT) {
148
+ await this.handleSessionTimeout();
149
+ }
125
150
  }
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();
151
+ async handleSessionTimeout() {
152
+ toast.warning('Session expired due to inactivity', {
153
+ description: 'Please log in again to continue.',
154
+ duration: 5000
155
+ });
156
+ await this.logOut();
133
157
  }
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();
158
+ clearSession() {
159
+ this._currentSession = null;
160
+ if (this.activityInterval) {
161
+ clearInterval(this.activityInterval);
162
+ this.activityInterval = null;
163
+ }
145
164
  }
146
- hasRequiredClaims(requiredClaims) {
147
- return requiredClaims.every((claim) => this._claims[claim]);
165
+ handleError(error) {
166
+ const authError = error instanceof AuthError
167
+ ? error
168
+ : new AuthError(error instanceof Error ? error.message : 'An unknown error occurred', 'unknown', error instanceof Error ? error : undefined);
169
+ this._error = authError;
170
+ this._loading = false;
171
+ console.error('[FirekitAuthManager]', authError);
148
172
  }
149
- isAdmin() {
150
- return Boolean(this._claims.admin);
173
+ generateDeviceId() {
174
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
151
175
  }
152
- isPremium() {
153
- return Boolean(this._claims.premium);
176
+ getPlatformInfo() {
177
+ if (!browser)
178
+ return 'server';
179
+ return `${navigator.platform} - ${navigator.userAgent}`;
154
180
  }
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;
181
+ validateClaims(requiredClaims, userClaims) {
182
+ return requiredClaims.every(claim => userClaims[claim]);
162
183
  }
163
184
  async handleRedirect(redirectTo, params) {
164
185
  const url = new URL(redirectTo, window.location.origin);
@@ -169,42 +190,41 @@ export class FirekitAuthManager {
169
190
  }
170
191
  await goto(url.toString());
171
192
  }
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
- }
193
+ // Public Methods
179
194
  async validateAuth({ authRequired = true, redirectTo = "/login", requiredClaims = [], requiredData, allowIf, redirectParams, } = {}) {
180
195
  if (!browser)
181
196
  return true;
182
- if (this.shouldThrottleValidation())
183
- return true;
197
+ const now = Date.now();
198
+ if (now - this._lastValidationTime < 1000)
199
+ return false;
200
+ this._lastValidationTime = now;
184
201
  try {
185
202
  this._loading = true;
186
203
  this._error = null;
187
204
  await this.waitForInit();
188
- const isAuthenticated = this.isLoggedIn;
189
- if (authRequired && !isAuthenticated) {
205
+ // Basic auth validation
206
+ if (authRequired && !this._user) {
190
207
  await this.handleRedirect(redirectTo, {
191
208
  ...redirectParams,
192
209
  returnTo: window.location.pathname,
193
210
  });
194
211
  return false;
195
212
  }
213
+ if (!authRequired && this._user) {
214
+ await this.handleRedirect(redirectTo, redirectParams);
215
+ return false;
216
+ }
217
+ // Custom conditions
196
218
  if (allowIf && !allowIf(this)) {
197
219
  await this.handleRedirect(redirectTo, redirectParams);
198
220
  return false;
199
221
  }
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
- }
222
+ // Claims validation
223
+ if (requiredClaims.length > 0 && !this.validateClaims(requiredClaims, this._claims)) {
224
+ await this.handleRedirect(redirectTo, redirectParams);
225
+ return false;
207
226
  }
227
+ // Data validation
208
228
  if (requiredData && !requiredData(this._userData)) {
209
229
  await this.handleRedirect(redirectTo, redirectParams);
210
230
  return false;
@@ -212,13 +232,128 @@ export class FirekitAuthManager {
212
232
  return true;
213
233
  }
214
234
  catch (error) {
215
- this._error = error instanceof Error ? error : new Error(String(error));
235
+ this.handleError(error);
216
236
  return false;
217
237
  }
218
238
  finally {
219
239
  this._loading = false;
220
240
  }
221
241
  }
242
+ async updateEmailUser(email) {
243
+ if (!this._user)
244
+ throw new AuthError("No authenticated user", "no_user");
245
+ try {
246
+ await updateEmail(this._user, email);
247
+ await this.updateUserData({ email });
248
+ toast.success("Email updated successfully!", {
249
+ description: "Please note that you will be logged out, and you will need to log in again using your new email address.",
250
+ });
251
+ setTimeout(async () => {
252
+ await this.logOut();
253
+ }, 4500);
254
+ }
255
+ catch (error) {
256
+ this.handleError(error);
257
+ throw error;
258
+ }
259
+ }
260
+ async updatePassword(password) {
261
+ if (!this._user)
262
+ throw new AuthError("No authenticated user", "no_user");
263
+ try {
264
+ await updatePassword(this._user, password);
265
+ }
266
+ catch (error) {
267
+ this.handleError(error);
268
+ throw error;
269
+ }
270
+ }
271
+ async updateProfileInfo({ displayName, photoURL, }) {
272
+ if (!this._user)
273
+ throw new AuthError("No authenticated user", "no_user");
274
+ if (!displayName && !photoURL)
275
+ return;
276
+ try {
277
+ if (displayName)
278
+ await updateProfile(this._user, { displayName });
279
+ if (photoURL)
280
+ await updateProfile(this._user, { photoURL });
281
+ await this.updateUserData({ displayName, photoURL });
282
+ }
283
+ catch (error) {
284
+ this.handleError(error);
285
+ throw error;
286
+ }
287
+ }
288
+ async updateUserData(data) {
289
+ if (!this._user?.uid)
290
+ throw new AuthError("No authenticated user", "no_user");
291
+ try {
292
+ const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
293
+ const updateData = { ...data, updatedAt: new Date() };
294
+ await updateDoc(docRef, updateData);
295
+ await this.loadUserData(this._user.uid);
296
+ }
297
+ catch (error) {
298
+ this.handleError(error);
299
+ throw error;
300
+ }
301
+ }
302
+ async saveUserData(data) {
303
+ if (!this._user?.uid)
304
+ throw new AuthError("No authenticated user", "no_user");
305
+ try {
306
+ const docRef = doc(firebaseService.getDb(), "users", this._user.uid);
307
+ const saveData = {
308
+ ...data,
309
+ createdAt: data.createdAt || new Date(),
310
+ updatedAt: new Date(),
311
+ };
312
+ await setDoc(docRef, saveData);
313
+ await this.loadUserData(this._user.uid);
314
+ }
315
+ catch (error) {
316
+ this.handleError(error);
317
+ throw error;
318
+ }
319
+ }
320
+ async sendVerificationEmail() {
321
+ if (!this._user)
322
+ throw new AuthError('No authenticated user', 'no_user');
323
+ try {
324
+ await sendEmailVerification(this._user);
325
+ toast.success('Verification email sent!');
326
+ }
327
+ catch (error) {
328
+ this.handleError(error);
329
+ throw error;
330
+ }
331
+ }
332
+ async refreshUserData() {
333
+ if (!this._user)
334
+ return;
335
+ try {
336
+ await Promise.all([
337
+ this.loadUserData(this._user.uid),
338
+ this.loadUserClaims(this._user)
339
+ ]);
340
+ }
341
+ catch (error) {
342
+ this.handleError(error);
343
+ throw error;
344
+ }
345
+ }
346
+ // Helper methods
347
+ hasRequiredClaims(requiredClaims) {
348
+ return requiredClaims.every((claim) => this._claims[claim]);
349
+ }
350
+ isAdmin() {
351
+ return Boolean(this._claims.admin);
352
+ }
353
+ isPremium() {
354
+ return Boolean(this._claims.premium);
355
+ }
356
+ // Convenience methods for route guards
222
357
  async requireAuth(redirectTo = "/login", redirectParams) {
223
358
  return this.validateAuth({
224
359
  authRequired: true,
@@ -247,11 +382,20 @@ export class FirekitAuthManager {
247
382
  redirectParams,
248
383
  });
249
384
  }
250
- get loading() {
251
- return this._loading;
385
+ async logOut() {
386
+ try {
387
+ await firebaseService.getAuthInstance().signOut();
388
+ this.clearSession();
389
+ }
390
+ catch (error) {
391
+ this.handleError(error);
392
+ throw error;
393
+ }
252
394
  }
253
- get error() {
254
- return this._error;
395
+ // Cleanup
396
+ destroy() {
397
+ this.clearSession();
398
+ // Additional cleanup if needed
255
399
  }
256
400
  }
257
401
  export const firekitAuthManager = FirekitAuthManager.getInstance();
@@ -7,7 +7,7 @@ declare class FirekitDocumentMutations {
7
7
  set<T extends DocumentData>(path: string, data: WithFieldValue<T>, options?: {
8
8
  merge?: boolean;
9
9
  timestamps?: boolean;
10
- }): Promise<void>;
10
+ }): Promise<string>;
11
11
  update<T extends DocumentData>(path: string, data: PartialWithFieldValue<T>, options?: {
12
12
  timestamps?: boolean;
13
13
  }): Promise<void>;
@@ -22,7 +22,7 @@ class FirekitDocumentMutations {
22
22
  timestamps: true,
23
23
  }) {
24
24
  const firestore = firebaseService.getDb();
25
- const docRef = doc(firestore, path);
25
+ const docRef = doc(collection(firestore, path));
26
26
  const dataToSet = {
27
27
  ...data,
28
28
  ...(options.timestamps && {
@@ -31,8 +31,10 @@ class FirekitDocumentMutations {
31
31
  updatedAt: serverTimestamp(),
32
32
  updatedBy: firekitAuthManager.uid,
33
33
  }),
34
+ uid: docRef.id,
34
35
  };
35
- return setDoc(docRef, dataToSet, { merge: options.merge });
36
+ await setDoc(docRef, dataToSet, { merge: options.merge });
37
+ return docRef.id;
36
38
  }
37
39
  async update(path, data, options = { timestamps: true }) {
38
40
  const firestore = firebaseService.getDb();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-firekit",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -1 +0,0 @@
1
- export {};
@@ -1,119 +0,0 @@
1
- "use strict";
2
- // import { browser } from "$app/environment";
3
- // import { goto } from "$app/navigation";
4
- // import type { DocumentData } from "firebase/firestore";
5
- // import { firekitUser } from "./user.svelte.js";
6
- // type UserClaims = Record<string, any>;
7
- // interface GuardConfig {
8
- // authRequired?: boolean;
9
- // redirectTo?: string;
10
- // requiredClaims?: string[];
11
- // requiredData?: (data: DocumentData | null) => boolean;
12
- // allowIf?: (user: typeof firekitUser) => boolean;
13
- // redirectParams?: Record<string, string>;
14
- // }
15
- // export class FirekitAuthGuard {
16
- // private static instance: FirekitAuthGuard;
17
- // private _loading = $state(true);
18
- // private _error = $state<Error | null>(null);
19
- // private _lastValidationTime = 0;
20
- // private readonly VALIDATION_THROTTLE = 1000; // 1 second
21
- // private constructor() { }
22
- // static getInstance(): FirekitAuthGuard {
23
- // if (!FirekitAuthGuard.instance) {
24
- // FirekitAuthGuard.instance = new FirekitAuthGuard();
25
- // }
26
- // return FirekitAuthGuard.instance;
27
- // }
28
- // private shouldThrottleValidation(): boolean {
29
- // const now = Date.now();
30
- // if (now - this._lastValidationTime < this.VALIDATION_THROTTLE) {
31
- // return true;
32
- // }
33
- // this._lastValidationTime = now;
34
- // return false;
35
- // }
36
- // private async handleRedirect(redirectTo: string, params?: Record<string, string>): Promise<void> {
37
- // const url = new URL(redirectTo, window.location.origin);
38
- // if (params) {
39
- // Object.entries(params).forEach(([key, value]) => {
40
- // url.searchParams.append(key, value);
41
- // });
42
- // }
43
- // await goto(url.toString());
44
- // }
45
- // private async validateClaims(requiredClaims: string[], userClaims?: UserClaims): Promise<boolean> {
46
- // if (!requiredClaims.length) return true;
47
- // if (!userClaims) return false;
48
- // return requiredClaims.every(claim => userClaims[claim]);
49
- // }
50
- // async validateAuth({
51
- // authRequired = true,
52
- // redirectTo = '/login',
53
- // requiredClaims = [],
54
- // requiredData,
55
- // allowIf,
56
- // redirectParams
57
- // }: GuardConfig = {}): Promise<boolean> {
58
- // if (!browser) return true;
59
- // if (this.shouldThrottleValidation()) return true;
60
- // try {
61
- // this._loading = true;
62
- // this._error = null;
63
- // await firekitUser.waitForInit();
64
- // const isAuthenticated = firekitUser.isLoggedIn;
65
- // if (authRequired && !isAuthenticated) {
66
- // await this.handleRedirect(redirectTo, {
67
- // ...redirectParams,
68
- // returnTo: window.location.pathname
69
- // });
70
- // return false;
71
- // }
72
- // if (allowIf && !allowIf(firekitUser)) {
73
- // await this.handleRedirect(redirectTo, redirectParams);
74
- // return false;
75
- // }
76
- // if (requiredClaims.length > 0) {
77
- // const userClaims = await firekitUser.user?.getIdTokenResult();
78
- // const hasClaims = await this.validateClaims(requiredClaims, userClaims?.claims);
79
- // if (!hasClaims) {
80
- // await this.handleRedirect(redirectTo, redirectParams);
81
- // return false;
82
- // }
83
- // }
84
- // if (requiredData && !requiredData(firekitUser.data)) {
85
- // await this.handleRedirect(redirectTo, redirectParams);
86
- // return false;
87
- // }
88
- // return true;
89
- // } catch (error) {
90
- // this._error = error instanceof Error ? error : new Error(String(error));
91
- // return false;
92
- // } finally {
93
- // this._loading = false;
94
- // }
95
- // }
96
- // async requireAuth(redirectTo = '/login', redirectParams?: Record<string, string>) {
97
- // return this.validateAuth({ authRequired: true, redirectTo, redirectParams });
98
- // }
99
- // async requireNoAuth(redirectTo = '/dashboard', redirectParams?: Record<string, string>) {
100
- // return this.validateAuth({ authRequired: false, redirectTo, redirectParams });
101
- // }
102
- // async requireClaims(claims: string[], redirectTo = '/login', redirectParams?: Record<string, string>) {
103
- // return this.validateAuth({ requiredClaims: claims, redirectTo, redirectParams });
104
- // }
105
- // async requireData(
106
- // validator: (data: DocumentData | null) => boolean,
107
- // redirectTo = '/login',
108
- // redirectParams?: Record<string, string>
109
- // ) {
110
- // return this.validateAuth({ requiredData: validator, redirectTo, redirectParams });
111
- // }
112
- // get loading() {
113
- // return this._loading;
114
- // }
115
- // get error() {
116
- // return this._error;
117
- // }
118
- // }
119
- // export const firekitAuthGuard = FirekitAuthGuard.getInstance();
@@ -1 +0,0 @@
1
- export {};
@@ -1,177 +0,0 @@
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();