svelte-firekit 0.0.1 → 0.0.2
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 +1 -1
- package/dist/auth/sign-in.svelte +2 -2
- package/dist/auth/sign-in.svelte.d.ts +1 -1
- package/dist/components/auth/google-sign-in.svelte +15 -1
- package/dist/components/auth/reset-password-form.svelte +16 -17
- package/dist/components/auth/sign-in-form.svelte +24 -23
- package/dist/components/auth/sign-up-form.svelte +52 -45
- package/dist/{auth → components/auth}/user-button.svelte +35 -34
- package/dist/{auth → components/auth}/user-button.svelte.d.ts +2 -2
- package/dist/components/firestore/collection.svelte +45 -0
- package/dist/components/firestore/collection.svelte.d.ts +25 -0
- package/dist/components/firestore/doc.svelte +39 -0
- package/dist/components/firestore/doc.svelte.d.ts +25 -0
- package/dist/components/nav/app-sidebar.svelte +46 -0
- package/dist/components/nav/app-sidebar.svelte.d.ts +8 -0
- package/dist/components/nav/breadcrumb.svelte +42 -0
- package/dist/components/nav/breadcrumb.svelte.d.ts +19 -0
- package/dist/components/nav/dark-mode-toggle.svelte +16 -0
- package/dist/components/nav/dark-mode-toggle.svelte.d.ts +18 -0
- package/dist/components/nav/nav.d.ts +11 -0
- package/dist/components/nav/nav.js +157 -0
- package/dist/components/nav/search-form.svelte +21 -0
- package/dist/components/nav/search-form.svelte.d.ts +4 -0
- package/dist/components/nav/version-switcher.svelte +48 -0
- package/dist/components/nav/version-switcher.svelte.d.ts +5 -0
- package/dist/components/storage/upload.svelte +134 -0
- package/dist/components/storage/upload.svelte.d.ts +11 -0
- package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +23 -0
- package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte.d.ts +4 -0
- package/dist/components/ui/breadcrumb/breadcrumb-item.svelte +16 -0
- package/dist/components/ui/breadcrumb/breadcrumb-item.svelte.d.ts +4 -0
- package/dist/components/ui/breadcrumb/breadcrumb-link.svelte +31 -0
- package/dist/components/ui/breadcrumb/breadcrumb-link.svelte.d.ts +10 -0
- package/dist/components/ui/breadcrumb/breadcrumb-list.svelte +23 -0
- package/dist/components/ui/breadcrumb/breadcrumb-list.svelte.d.ts +4 -0
- package/dist/components/ui/breadcrumb/breadcrumb-page.svelte +23 -0
- package/dist/components/ui/breadcrumb/breadcrumb-page.svelte.d.ts +4 -0
- package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +27 -0
- package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte.d.ts +4 -0
- package/dist/components/ui/breadcrumb/breadcrumb.svelte +15 -0
- package/dist/components/ui/breadcrumb/breadcrumb.svelte.d.ts +4 -0
- package/dist/components/ui/breadcrumb/index.d.ts +8 -0
- package/dist/components/ui/breadcrumb/index.js +10 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +10 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +4 -3
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +1 -0
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/separator/index.d.ts +2 -0
- package/dist/components/ui/separator/index.js +4 -0
- package/dist/components/ui/separator/separator.svelte +22 -0
- package/dist/components/ui/separator/separator.svelte.d.ts +3 -0
- package/dist/components/ui/sheet/index.js +14 -0
- package/dist/components/ui/sheet/sheet-content.svelte +52 -0
- package/dist/components/ui/sheet/sheet-content.svelte.d.ts +59 -0
- package/dist/components/ui/sheet/sheet-description.svelte +16 -0
- package/dist/components/ui/sheet/sheet-description.svelte.d.ts +3 -0
- package/dist/components/ui/sheet/sheet-footer.svelte +20 -0
- package/dist/components/ui/sheet/sheet-footer.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/sheet-header.svelte +20 -0
- package/dist/components/ui/sheet/sheet-header.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/sheet-overlay.svelte +19 -0
- package/dist/components/ui/sheet/sheet-overlay.svelte.d.ts +3 -0
- package/dist/components/ui/sheet/sheet-title.svelte +16 -0
- package/dist/components/ui/sheet/sheet-title.svelte.d.ts +3 -0
- package/dist/components/ui/sidebar/constants.d.ts +6 -0
- package/dist/components/ui/sidebar/constants.js +6 -0
- package/dist/components/ui/sidebar/context.svelte.d.ts +42 -0
- package/dist/components/ui/sidebar/context.svelte.js +54 -0
- package/dist/components/ui/sidebar/index.d.ts +25 -0
- package/dist/components/ui/sidebar/index.js +27 -0
- package/dist/components/ui/sidebar/sidebar-content.svelte +24 -0
- package/dist/components/ui/sidebar/sidebar-content.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-footer.svelte +21 -0
- package/dist/components/ui/sidebar/sidebar-footer.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-group-action.svelte +36 -0
- package/dist/components/ui/sidebar/sidebar-group-action.svelte.d.ts +10 -0
- package/dist/components/ui/sidebar/sidebar-group-content.svelte +21 -0
- package/dist/components/ui/sidebar/sidebar-group-content.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-group-label.svelte +34 -0
- package/dist/components/ui/sidebar/sidebar-group-label.svelte.d.ts +10 -0
- package/dist/components/ui/sidebar/sidebar-group.svelte +21 -0
- package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-header.svelte +21 -0
- package/dist/components/ui/sidebar/sidebar-header.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-input.svelte +23 -0
- package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-inset.svelte +24 -0
- package/dist/components/ui/sidebar/sidebar-inset.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-menu-action.svelte +43 -0
- package/dist/components/ui/sidebar/sidebar-menu-action.svelte.d.ts +11 -0
- package/dist/components/ui/sidebar/sidebar-menu-badge.svelte +29 -0
- package/dist/components/ui/sidebar/sidebar-menu-badge.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-menu-button.svelte +97 -0
- package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +91 -0
- package/dist/components/ui/sidebar/sidebar-menu-item.svelte +21 -0
- package/dist/components/ui/sidebar/sidebar-menu-item.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-menu-skeleton.svelte +36 -0
- package/dist/components/ui/sidebar/sidebar-menu-skeleton.svelte.d.ts +7 -0
- package/dist/components/ui/sidebar/sidebar-menu-sub-button.svelte +43 -0
- package/dist/components/ui/sidebar/sidebar-menu-sub-button.svelte.d.ts +12 -0
- package/dist/components/ui/sidebar/sidebar-menu-sub-item.svelte +14 -0
- package/dist/components/ui/sidebar/sidebar-menu-sub-item.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-menu-sub.svelte +25 -0
- package/dist/components/ui/sidebar/sidebar-menu-sub.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-menu.svelte +21 -0
- package/dist/components/ui/sidebar/sidebar-menu.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-provider.svelte +59 -0
- package/dist/components/ui/sidebar/sidebar-provider.svelte.d.ts +9 -0
- package/dist/components/ui/sidebar/sidebar-rail.svelte +36 -0
- package/dist/components/ui/sidebar/sidebar-rail.svelte.d.ts +4 -0
- package/dist/components/ui/sidebar/sidebar-separator.svelte +18 -0
- package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +12 -0
- package/dist/components/ui/sidebar/sidebar-trigger.svelte +34 -0
- package/dist/components/ui/sidebar/sidebar-trigger.svelte.d.ts +9 -0
- package/dist/components/ui/sidebar/sidebar.svelte +98 -0
- package/dist/components/ui/sidebar/sidebar.svelte.d.ts +9 -0
- package/dist/components/ui/skeleton/index.d.ts +2 -0
- package/dist/components/ui/skeleton/index.js +4 -0
- package/dist/components/ui/skeleton/skeleton.svelte +17 -0
- package/dist/components/ui/skeleton/skeleton.svelte.d.ts +4 -0
- package/dist/components/ui/tooltip/index.js +8 -0
- package/dist/components/ui/tooltip/tooltip-content.svelte +21 -0
- package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +3 -0
- package/dist/firebase/auth/auth-guard.svelte.d.ts +25 -0
- package/dist/firebase/auth/auth-guard.svelte.js +79 -0
- package/dist/firebase/auth/auth.d.ts +21 -0
- package/dist/firebase/auth/auth.js +71 -0
- package/dist/firebase/auth/user.svelte.d.ts +50 -0
- package/dist/firebase/auth/user.svelte.js +115 -0
- package/dist/firebase/config.js +44 -0
- package/dist/firebase/firebase.d.ts +28 -0
- package/dist/firebase/firebase.js +86 -0
- package/dist/firebase/firestore/awaitable-doc.svelte.d.ts +15 -0
- package/dist/firebase/firestore/awaitable-doc.svelte.js +57 -0
- package/dist/firebase/firestore/collection.svelte.d.ts +17 -0
- package/dist/firebase/firestore/collection.svelte.js +58 -0
- package/dist/firebase/firestore/doc.svelte.d.ts +16 -0
- package/dist/firebase/firestore/doc.svelte.js +56 -0
- package/dist/firebase/firestore/document-mutations.svelte.d.ts +18 -0
- package/dist/firebase/firestore/document-mutations.svelte.js +58 -0
- package/dist/firebase/storage/download-url.svelte.d.ts +14 -0
- package/dist/firebase/storage/download-url.svelte.js +45 -0
- package/dist/firebase/storage/storage-list.svelte.d.ts +17 -0
- package/dist/firebase/storage/storage-list.svelte.js +51 -0
- package/dist/firebase/storage/upload-task.svelte.d.ts +22 -0
- package/dist/firebase/storage/upload-task.svelte.js +65 -0
- package/dist/hooks/is-mobile.svelte.d.ts +5 -0
- package/dist/hooks/is-mobile.svelte.js +23 -0
- package/dist/index.d.ts +22 -2
- package/dist/index.js +29 -3
- package/dist/types/docs.d.ts +50 -0
- package/dist/utils.d.ts +27 -1
- package/dist/utils.js +85 -9
- package/package.json +9 -7
- package/dist/auth/uid.js +0 -7
- package/dist/auth/user.svelte.d.ts +0 -10
- package/dist/auth/user.svelte.js +0 -21
- package/dist/auth.d.ts +0 -39
- package/dist/auth.js +0 -100
- package/dist/config.js +0 -39
- package/dist/firebase.d.ts +0 -43
- package/dist/firebase.js +0 -110
- package/dist/firestore/Collection.svelte +0 -148
- package/dist/firestore/Collection.svelte.d.ts +0 -27
- package/dist/firestore/collection.svelte.js +0 -207
- package/dist/firestore/doc.svelte.d.ts +0 -1
- package/dist/firestore/doc.svelte.js +0 -1
- package/dist/firestore/firestore.d.ts +0 -31
- package/dist/firestore/firestore.js +0 -100
- package/dist/firestore/perf.d.ts +0 -3
- package/dist/firestore/perf.js +0 -12
- /package/dist/{config.d.ts → firebase/config.d.ts} +0 -0
- /package/dist/{auth/uid.d.ts → types/docs.js} +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
declare class FirekitAuth {
|
|
2
|
+
private static instance;
|
|
3
|
+
private auth;
|
|
4
|
+
private firestore;
|
|
5
|
+
private constructor();
|
|
6
|
+
static getInstance(): FirekitAuth;
|
|
7
|
+
signInWithGoogle(): Promise<void>;
|
|
8
|
+
signInWithEmail(email: string, password: string): Promise<void>;
|
|
9
|
+
registerWithEmail(email: string, password: string, displayName: string): Promise<void>;
|
|
10
|
+
private updateUserInFirestore;
|
|
11
|
+
logOut(): Promise<void>;
|
|
12
|
+
sendPasswordReset(email: string): Promise<void>;
|
|
13
|
+
sendEmailVerificationToUser(): Promise<void>;
|
|
14
|
+
updateUserProfile(profile: {
|
|
15
|
+
displayName?: string;
|
|
16
|
+
photoURL?: string;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
updateUserPassword(newPassword: string): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare const firekitAuth: FirekitAuth;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { GoogleAuthProvider, sendPasswordResetEmail, signInWithEmailAndPassword, signInWithPopup, signOut, createUserWithEmailAndPassword, sendEmailVerification, updateProfile, updatePassword } from 'firebase/auth';
|
|
2
|
+
import { doc, setDoc } from 'firebase/firestore';
|
|
3
|
+
import { firebaseService } from '../firebase.js';
|
|
4
|
+
class FirekitAuth {
|
|
5
|
+
static instance;
|
|
6
|
+
auth = firebaseService.getAuthInstance();
|
|
7
|
+
firestore = firebaseService.getDb();
|
|
8
|
+
constructor() { }
|
|
9
|
+
static getInstance() {
|
|
10
|
+
if (!FirekitAuth.instance) {
|
|
11
|
+
FirekitAuth.instance = new FirekitAuth();
|
|
12
|
+
}
|
|
13
|
+
return FirekitAuth.instance;
|
|
14
|
+
}
|
|
15
|
+
async signInWithGoogle() {
|
|
16
|
+
const provider = new GoogleAuthProvider();
|
|
17
|
+
const result = await signInWithPopup(this.auth, provider);
|
|
18
|
+
await this.updateUserInFirestore(result.user);
|
|
19
|
+
}
|
|
20
|
+
async signInWithEmail(email, password) {
|
|
21
|
+
const result = await signInWithEmailAndPassword(this.auth, email, password);
|
|
22
|
+
await this.updateUserInFirestore(result.user);
|
|
23
|
+
}
|
|
24
|
+
async registerWithEmail(email, password, displayName) {
|
|
25
|
+
const result = await createUserWithEmailAndPassword(this.auth, email, password);
|
|
26
|
+
const user = result.user;
|
|
27
|
+
if (user) {
|
|
28
|
+
await updateProfile(user, { displayName });
|
|
29
|
+
await this.updateUserInFirestore(user);
|
|
30
|
+
await sendEmailVerification(user);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async updateUserInFirestore(user) {
|
|
34
|
+
const ref = doc(this.firestore, 'users', user.uid);
|
|
35
|
+
const userData = {
|
|
36
|
+
uid: user.uid,
|
|
37
|
+
email: user.email,
|
|
38
|
+
emailVerified: user.emailVerified,
|
|
39
|
+
displayName: user.displayName,
|
|
40
|
+
photoURL: user.photoURL,
|
|
41
|
+
isAnonymous: user.isAnonymous,
|
|
42
|
+
providerId: user.providerId,
|
|
43
|
+
phoneNumber: user.phoneNumber,
|
|
44
|
+
providerData: user.providerData
|
|
45
|
+
};
|
|
46
|
+
await setDoc(ref, userData, { merge: true });
|
|
47
|
+
}
|
|
48
|
+
async logOut() {
|
|
49
|
+
await signOut(this.auth);
|
|
50
|
+
}
|
|
51
|
+
async sendPasswordReset(email) {
|
|
52
|
+
await sendPasswordResetEmail(this.auth, email);
|
|
53
|
+
}
|
|
54
|
+
async sendEmailVerificationToUser() {
|
|
55
|
+
if (this.auth.currentUser) {
|
|
56
|
+
await sendEmailVerification(this.auth.currentUser);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async updateUserProfile(profile) {
|
|
60
|
+
if (this.auth.currentUser) {
|
|
61
|
+
await updateProfile(this.auth.currentUser, profile);
|
|
62
|
+
await this.updateUserInFirestore(this.auth.currentUser);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async updateUserPassword(newPassword) {
|
|
66
|
+
if (this.auth.currentUser) {
|
|
67
|
+
await updatePassword(this.auth.currentUser, newPassword);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export const firekitAuth = FirekitAuth.getInstance();
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { firebaseService } from '../firebase.js';
|
|
2
|
+
import { onAuthStateChanged, updateCurrentUser, updateEmail, updatePassword } from "firebase/auth";
|
|
3
|
+
import { doc, getDoc, setDoc, updateDoc } from 'firebase/firestore';
|
|
4
|
+
export class FirekitUser {
|
|
5
|
+
static instance;
|
|
6
|
+
_user = $state();
|
|
7
|
+
_userData = $state(null);
|
|
8
|
+
_claims = $state({});
|
|
9
|
+
isLoggedIn = $derived(Boolean(this._user));
|
|
10
|
+
uid = $derived(this._user?.uid);
|
|
11
|
+
email = $derived(this._user?.email);
|
|
12
|
+
displayName = $derived(this._user?.displayName);
|
|
13
|
+
photoURL = $derived(this._user?.photoURL);
|
|
14
|
+
emailVerified = $derived(this._user?.emailVerified);
|
|
15
|
+
claims = $derived(this._claims);
|
|
16
|
+
data = $derived(this._userData);
|
|
17
|
+
constructor() {
|
|
18
|
+
onAuthStateChanged(firebaseService.getAuthInstance(), async (user) => {
|
|
19
|
+
this._user = user;
|
|
20
|
+
if (user) {
|
|
21
|
+
await Promise.all([
|
|
22
|
+
this.loadUserData(),
|
|
23
|
+
this.loadUserClaims()
|
|
24
|
+
]);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
this._userData = null;
|
|
28
|
+
this._claims = {};
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
static getInstance() {
|
|
33
|
+
if (!FirekitUser.instance) {
|
|
34
|
+
FirekitUser.instance = new FirekitUser();
|
|
35
|
+
}
|
|
36
|
+
return FirekitUser.instance;
|
|
37
|
+
}
|
|
38
|
+
async loadUserData() {
|
|
39
|
+
if (!this._user?.uid)
|
|
40
|
+
return;
|
|
41
|
+
const docRef = doc(firebaseService.getDb(), 'users', this._user.uid);
|
|
42
|
+
const docSnap = await getDoc(docRef);
|
|
43
|
+
if (docSnap.exists()) {
|
|
44
|
+
this._userData = docSnap.data();
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Initialize user document if it doesn't exist
|
|
48
|
+
const initialData = {
|
|
49
|
+
displayName: this._user.displayName || '',
|
|
50
|
+
email: this._user.email || '',
|
|
51
|
+
photoURL: this._user.photoURL || '',
|
|
52
|
+
createdAt: new Date(),
|
|
53
|
+
updatedAt: new Date(),
|
|
54
|
+
isProfileComplete: false
|
|
55
|
+
};
|
|
56
|
+
await this.saveUserData(initialData);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async loadUserClaims() {
|
|
60
|
+
if (!this._user)
|
|
61
|
+
return;
|
|
62
|
+
const tokenResult = await this._user.getIdTokenResult();
|
|
63
|
+
this._claims = tokenResult.claims;
|
|
64
|
+
}
|
|
65
|
+
get user() {
|
|
66
|
+
return this._user;
|
|
67
|
+
}
|
|
68
|
+
async updateEmail(email) {
|
|
69
|
+
if (!this._user)
|
|
70
|
+
throw new Error('No authenticated user');
|
|
71
|
+
await updateEmail(this._user, email);
|
|
72
|
+
}
|
|
73
|
+
async updatePassword(password) {
|
|
74
|
+
if (!this._user)
|
|
75
|
+
throw new Error('No authenticated user');
|
|
76
|
+
await updatePassword(this._user, password);
|
|
77
|
+
}
|
|
78
|
+
async updateProfile({ displayName, photoURL }) {
|
|
79
|
+
if (!this._user)
|
|
80
|
+
throw new Error('No authenticated user');
|
|
81
|
+
}
|
|
82
|
+
async updateUserData(data) {
|
|
83
|
+
if (!this._user?.uid)
|
|
84
|
+
throw new Error('No authenticated user');
|
|
85
|
+
const docRef = doc(firebaseService.getDb(), 'users', this._user.uid);
|
|
86
|
+
const updateData = {
|
|
87
|
+
...data,
|
|
88
|
+
updatedAt: new Date()
|
|
89
|
+
};
|
|
90
|
+
await updateDoc(docRef, updateData);
|
|
91
|
+
await this.loadUserData(); // Reload user data
|
|
92
|
+
}
|
|
93
|
+
async saveUserData(data) {
|
|
94
|
+
if (!this._user?.uid)
|
|
95
|
+
throw new Error('No authenticated user');
|
|
96
|
+
const docRef = doc(firebaseService.getDb(), 'users', this._user.uid);
|
|
97
|
+
const saveData = {
|
|
98
|
+
...data,
|
|
99
|
+
createdAt: data.createdAt || new Date(),
|
|
100
|
+
updatedAt: new Date()
|
|
101
|
+
};
|
|
102
|
+
await setDoc(docRef, saveData);
|
|
103
|
+
await this.loadUserData(); // Reload user data
|
|
104
|
+
}
|
|
105
|
+
hasRequiredClaims(requiredClaims) {
|
|
106
|
+
return requiredClaims.every(claim => this._claims[claim]);
|
|
107
|
+
}
|
|
108
|
+
isAdmin() {
|
|
109
|
+
return Boolean(this._claims.admin);
|
|
110
|
+
}
|
|
111
|
+
isPremium() {
|
|
112
|
+
return Boolean(this._claims.premium);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export const firekitUser = new FirekitUser();
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { PUBLIC_FIREBASE_API_KEY, PUBLIC_FIREBASE_AUTH_DOMAIN, PUBLIC_FIREBASE_PROJECT_ID, PUBLIC_FIREBASE_STORAGE_BUCKET, PUBLIC_FIREBASE_MESSAGING_SENDER_ID, PUBLIC_FIREBASE_APP_ID, PUBLIC_FIREBASE_MEASUREMENT_ID } from '$env/static/public';
|
|
2
|
+
class FirebaseConfig {
|
|
3
|
+
static instance;
|
|
4
|
+
config;
|
|
5
|
+
constructor() {
|
|
6
|
+
const missingVars = this.getMissingFirebaseConfigVars();
|
|
7
|
+
if (missingVars.length > 0) {
|
|
8
|
+
throw Error(`The following Firebase configuration variables are missing: ${missingVars.join(', ')}`);
|
|
9
|
+
}
|
|
10
|
+
this.config = {
|
|
11
|
+
apiKey: PUBLIC_FIREBASE_API_KEY,
|
|
12
|
+
authDomain: PUBLIC_FIREBASE_AUTH_DOMAIN,
|
|
13
|
+
projectId: PUBLIC_FIREBASE_PROJECT_ID,
|
|
14
|
+
storageBucket: PUBLIC_FIREBASE_STORAGE_BUCKET,
|
|
15
|
+
messagingSenderId: PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
|
16
|
+
appId: PUBLIC_FIREBASE_APP_ID,
|
|
17
|
+
measurementId: PUBLIC_FIREBASE_MEASUREMENT_ID
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
getMissingFirebaseConfigVars() {
|
|
21
|
+
const requiredVars = {
|
|
22
|
+
'PUBLIC_FIREBASE_API_KEY': PUBLIC_FIREBASE_API_KEY,
|
|
23
|
+
'PUBLIC_FIREBASE_AUTH_DOMAIN': PUBLIC_FIREBASE_AUTH_DOMAIN,
|
|
24
|
+
'PUBLIC_FIREBASE_PROJECT_ID': PUBLIC_FIREBASE_PROJECT_ID,
|
|
25
|
+
'PUBLIC_FIREBASE_STORAGE_BUCKET': PUBLIC_FIREBASE_STORAGE_BUCKET,
|
|
26
|
+
'PUBLIC_FIREBASE_MESSAGING_SENDER_ID': PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
|
27
|
+
'PUBLIC_FIREBASE_APP_ID': PUBLIC_FIREBASE_APP_ID,
|
|
28
|
+
'PUBLIC_FIREBASE_MEASUREMENT_ID': PUBLIC_FIREBASE_MEASUREMENT_ID
|
|
29
|
+
};
|
|
30
|
+
return Object.entries(requiredVars)
|
|
31
|
+
.filter(([_, value]) => !value)
|
|
32
|
+
.map(([key]) => key);
|
|
33
|
+
}
|
|
34
|
+
static getInstance() {
|
|
35
|
+
if (!FirebaseConfig.instance) {
|
|
36
|
+
FirebaseConfig.instance = new FirebaseConfig();
|
|
37
|
+
}
|
|
38
|
+
return FirebaseConfig.instance;
|
|
39
|
+
}
|
|
40
|
+
getConfig() {
|
|
41
|
+
return this.config;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export const firebaseConfig = FirebaseConfig.getInstance().getConfig();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type FirebaseApp } from 'firebase/app';
|
|
2
|
+
import { type Firestore } from 'firebase/firestore';
|
|
3
|
+
import { type Auth } from 'firebase/auth';
|
|
4
|
+
import { type Functions } from 'firebase/functions';
|
|
5
|
+
import { type Database } from 'firebase/database';
|
|
6
|
+
import { type FirebaseStorage } from 'firebase/storage';
|
|
7
|
+
declare class FirebaseService {
|
|
8
|
+
private static instance;
|
|
9
|
+
private firebaseApp;
|
|
10
|
+
private db;
|
|
11
|
+
private auth;
|
|
12
|
+
private functions;
|
|
13
|
+
private database;
|
|
14
|
+
private storage;
|
|
15
|
+
private readonly isBrowser;
|
|
16
|
+
private constructor();
|
|
17
|
+
static getInstance(): FirebaseService;
|
|
18
|
+
getFirebaseApp(): FirebaseApp;
|
|
19
|
+
private initializeFirestoreInstance;
|
|
20
|
+
getDb(): Firestore;
|
|
21
|
+
getAuthInstance(): Auth;
|
|
22
|
+
getFunctionsInstance(): Functions;
|
|
23
|
+
getDatabaseInstance(): Database;
|
|
24
|
+
getStorageInstance(): FirebaseStorage;
|
|
25
|
+
getBatch(): import("@firebase/firestore").WriteBatch;
|
|
26
|
+
}
|
|
27
|
+
export declare const firebaseService: FirebaseService;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { initializeApp, getApps } from 'firebase/app';
|
|
2
|
+
import { initializeFirestore, CACHE_SIZE_UNLIMITED, persistentLocalCache, persistentMultipleTabManager, enablePersistentCacheIndexAutoCreation, getPersistentCacheIndexManager, writeBatch } from 'firebase/firestore';
|
|
3
|
+
import { getAuth } from 'firebase/auth';
|
|
4
|
+
import { getFunctions } from 'firebase/functions';
|
|
5
|
+
import { getDatabase } from 'firebase/database';
|
|
6
|
+
import { getStorage } from 'firebase/storage';
|
|
7
|
+
import { firebaseConfig } from './config.js';
|
|
8
|
+
class FirebaseService {
|
|
9
|
+
static instance;
|
|
10
|
+
firebaseApp = null;
|
|
11
|
+
db = null;
|
|
12
|
+
auth = null;
|
|
13
|
+
functions = null;
|
|
14
|
+
database = null;
|
|
15
|
+
storage = null;
|
|
16
|
+
isBrowser = typeof window !== 'undefined';
|
|
17
|
+
constructor() {
|
|
18
|
+
}
|
|
19
|
+
static getInstance() {
|
|
20
|
+
if (!FirebaseService.instance) {
|
|
21
|
+
FirebaseService.instance = new FirebaseService();
|
|
22
|
+
}
|
|
23
|
+
return FirebaseService.instance;
|
|
24
|
+
}
|
|
25
|
+
getFirebaseApp() {
|
|
26
|
+
if (this.firebaseApp)
|
|
27
|
+
return this.firebaseApp;
|
|
28
|
+
const existingApps = getApps();
|
|
29
|
+
if (existingApps.length) {
|
|
30
|
+
this.firebaseApp = existingApps[0];
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
this.firebaseApp = initializeApp(firebaseConfig);
|
|
34
|
+
console.log(`${firebaseConfig.projectId} initialized on ${this.isBrowser ? 'client' : 'server'}`);
|
|
35
|
+
}
|
|
36
|
+
this.initializeFirestoreInstance();
|
|
37
|
+
return this.firebaseApp;
|
|
38
|
+
}
|
|
39
|
+
initializeFirestoreInstance() {
|
|
40
|
+
if (this.db || !this.isBrowser)
|
|
41
|
+
return;
|
|
42
|
+
this.db = initializeFirestore(this.firebaseApp, {
|
|
43
|
+
localCache: persistentLocalCache({
|
|
44
|
+
cacheSizeBytes: CACHE_SIZE_UNLIMITED,
|
|
45
|
+
tabManager: persistentMultipleTabManager()
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
const indexManager = getPersistentCacheIndexManager(this.db);
|
|
49
|
+
if (indexManager) {
|
|
50
|
+
enablePersistentCacheIndexAutoCreation(indexManager);
|
|
51
|
+
console.log('Firestore persistent cache indexing is enabled');
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.warn('Failed to initialize the Firestore cache index manager');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
getDb() {
|
|
58
|
+
if (!this.db)
|
|
59
|
+
this.getFirebaseApp();
|
|
60
|
+
return this.db;
|
|
61
|
+
}
|
|
62
|
+
getAuthInstance() {
|
|
63
|
+
if (!this.auth)
|
|
64
|
+
this.auth = getAuth(this.getFirebaseApp());
|
|
65
|
+
return this.auth;
|
|
66
|
+
}
|
|
67
|
+
getFunctionsInstance() {
|
|
68
|
+
if (!this.functions)
|
|
69
|
+
this.functions = getFunctions(this.getFirebaseApp());
|
|
70
|
+
return this.functions;
|
|
71
|
+
}
|
|
72
|
+
getDatabaseInstance() {
|
|
73
|
+
if (!this.database)
|
|
74
|
+
this.database = getDatabase(this.getFirebaseApp());
|
|
75
|
+
return this.database;
|
|
76
|
+
}
|
|
77
|
+
getStorageInstance() {
|
|
78
|
+
if (!this.storage)
|
|
79
|
+
this.storage = getStorage(this.getFirebaseApp());
|
|
80
|
+
return this.storage;
|
|
81
|
+
}
|
|
82
|
+
getBatch() {
|
|
83
|
+
return writeBatch(this.getDb());
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export const firebaseService = FirebaseService.getInstance();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type DocumentReference, type DocumentData } from "firebase/firestore";
|
|
2
|
+
declare class FirekitAwaitableDoc<T> {
|
|
3
|
+
private _data;
|
|
4
|
+
private _loading;
|
|
5
|
+
private _error;
|
|
6
|
+
private docRef;
|
|
7
|
+
constructor(ref: string | DocumentReference<T>, startWith?: T);
|
|
8
|
+
private initializeDoc;
|
|
9
|
+
getData(): Promise<T | null>;
|
|
10
|
+
get data(): T | null;
|
|
11
|
+
get loading(): boolean;
|
|
12
|
+
get error(): Error | null;
|
|
13
|
+
}
|
|
14
|
+
export declare function firekitAwaitableDoc<T extends DocumentData>(path: string, startWith?: T): FirekitAwaitableDoc<T>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { doc, getDoc, onSnapshot } from "firebase/firestore";
|
|
2
|
+
import { firebaseService } from "../firebase.js";
|
|
3
|
+
import { browser } from "$app/environment";
|
|
4
|
+
class FirekitAwaitableDoc {
|
|
5
|
+
_data = $state(null);
|
|
6
|
+
_loading = $state(true);
|
|
7
|
+
_error = $state(null);
|
|
8
|
+
docRef = null;
|
|
9
|
+
constructor(ref, startWith) {
|
|
10
|
+
this._data = startWith ?? null;
|
|
11
|
+
if (browser) {
|
|
12
|
+
this.initializeDoc(ref);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async initializeDoc(ref) {
|
|
16
|
+
try {
|
|
17
|
+
const firestore = firebaseService.getDb();
|
|
18
|
+
this.docRef = typeof ref === "string"
|
|
19
|
+
? doc(firestore, ref)
|
|
20
|
+
: ref;
|
|
21
|
+
// Initial fetch
|
|
22
|
+
const snapshot = await getDoc(this.docRef);
|
|
23
|
+
this._data = snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null;
|
|
24
|
+
// Setup real-time updates
|
|
25
|
+
onSnapshot(this.docRef, (snapshot) => {
|
|
26
|
+
this._data = snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null;
|
|
27
|
+
this._loading = false;
|
|
28
|
+
this._error = null;
|
|
29
|
+
}, (error) => {
|
|
30
|
+
this._error = error;
|
|
31
|
+
this._loading = false;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
this._error = error;
|
|
36
|
+
this._loading = false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async getData() {
|
|
40
|
+
if (!this.docRef)
|
|
41
|
+
return null;
|
|
42
|
+
const snapshot = await getDoc(this.docRef);
|
|
43
|
+
return snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null;
|
|
44
|
+
}
|
|
45
|
+
get data() {
|
|
46
|
+
return this._data;
|
|
47
|
+
}
|
|
48
|
+
get loading() {
|
|
49
|
+
return this._loading;
|
|
50
|
+
}
|
|
51
|
+
get error() {
|
|
52
|
+
return this._error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function firekitAwaitableDoc(path, startWith) {
|
|
56
|
+
return new FirekitAwaitableDoc(path, startWith);
|
|
57
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CollectionReference, type DocumentData, type QueryConstraint } from "firebase/firestore";
|
|
2
|
+
declare class FirekitCollection<T> {
|
|
3
|
+
private _data;
|
|
4
|
+
private _loading;
|
|
5
|
+
private _error;
|
|
6
|
+
private colRef;
|
|
7
|
+
private queryRef;
|
|
8
|
+
constructor(path: string, ...queryConstraints: QueryConstraint[]);
|
|
9
|
+
get data(): T[];
|
|
10
|
+
get loading(): boolean;
|
|
11
|
+
get error(): Error | null;
|
|
12
|
+
get empty(): boolean;
|
|
13
|
+
get size(): number;
|
|
14
|
+
get ref(): CollectionReference<T, DocumentData>;
|
|
15
|
+
}
|
|
16
|
+
export declare function firekitCollection<T extends DocumentData>(path: string, ...queryConstraints: QueryConstraint[]): FirekitCollection<T>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { collection, query, onSnapshot } from "firebase/firestore";
|
|
2
|
+
import { firebaseService } from "../firebase.js";
|
|
3
|
+
import { browser } from "$app/environment";
|
|
4
|
+
class FirekitCollection {
|
|
5
|
+
_data = $state([]);
|
|
6
|
+
_loading = $state(true);
|
|
7
|
+
_error = $state(null);
|
|
8
|
+
colRef = null;
|
|
9
|
+
queryRef = null;
|
|
10
|
+
constructor(path, ...queryConstraints) {
|
|
11
|
+
if (browser) {
|
|
12
|
+
try {
|
|
13
|
+
const firestore = firebaseService.getDb();
|
|
14
|
+
this.colRef = collection(firestore, path);
|
|
15
|
+
this.queryRef = query(this.colRef, ...queryConstraints);
|
|
16
|
+
onSnapshot(this.queryRef, (snapshot) => {
|
|
17
|
+
this._data = snapshot.docs.map(doc => ({
|
|
18
|
+
id: doc.id,
|
|
19
|
+
...doc.data()
|
|
20
|
+
}));
|
|
21
|
+
this._loading = false;
|
|
22
|
+
this._error = null;
|
|
23
|
+
}, (error) => {
|
|
24
|
+
this._error = error;
|
|
25
|
+
this._loading = false;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
this._error = error;
|
|
30
|
+
this._loading = false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
get data() {
|
|
35
|
+
return this._data;
|
|
36
|
+
}
|
|
37
|
+
get loading() {
|
|
38
|
+
return this._loading;
|
|
39
|
+
}
|
|
40
|
+
get error() {
|
|
41
|
+
return this._error;
|
|
42
|
+
}
|
|
43
|
+
get empty() {
|
|
44
|
+
return this._data.length === 0;
|
|
45
|
+
}
|
|
46
|
+
get size() {
|
|
47
|
+
return this._data.length;
|
|
48
|
+
}
|
|
49
|
+
get ref() {
|
|
50
|
+
if (!this.colRef) {
|
|
51
|
+
throw new Error("Collection reference is not available");
|
|
52
|
+
}
|
|
53
|
+
return this.colRef;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function firekitCollection(path, ...queryConstraints) {
|
|
57
|
+
return new FirekitCollection(path, ...queryConstraints);
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DocumentReference } from "firebase/firestore";
|
|
2
|
+
declare class FirekitDoc<T> {
|
|
3
|
+
private _data;
|
|
4
|
+
private _loading;
|
|
5
|
+
private _error;
|
|
6
|
+
private docRef;
|
|
7
|
+
constructor(ref: string | DocumentReference<T>, startWith?: T);
|
|
8
|
+
get data(): T | null;
|
|
9
|
+
get id(): string;
|
|
10
|
+
get loading(): boolean;
|
|
11
|
+
get error(): Error | null;
|
|
12
|
+
get ref(): DocumentReference<T, import("@firebase/firestore").DocumentData>;
|
|
13
|
+
get exists(): boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function firekitDoc<T>(ref: string | DocumentReference<T>, startWith?: T): FirekitDoc<T>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { doc, DocumentReference, onSnapshot } from "firebase/firestore";
|
|
2
|
+
import { firebaseService } from "../firebase.js";
|
|
3
|
+
import { browser } from "$app/environment";
|
|
4
|
+
class FirekitDoc {
|
|
5
|
+
_data = $state(null);
|
|
6
|
+
_loading = $state(true);
|
|
7
|
+
_error = $state(null);
|
|
8
|
+
docRef = null;
|
|
9
|
+
constructor(ref, startWith) {
|
|
10
|
+
this._data = startWith ?? null;
|
|
11
|
+
if (browser) {
|
|
12
|
+
try {
|
|
13
|
+
const firestore = firebaseService.getDb();
|
|
14
|
+
this.docRef = typeof ref === "string"
|
|
15
|
+
? doc(firestore, ref)
|
|
16
|
+
: ref;
|
|
17
|
+
onSnapshot(this.docRef, (snapshot) => {
|
|
18
|
+
this._data = snapshot.data() ?? null;
|
|
19
|
+
this._loading = false;
|
|
20
|
+
this._error = null;
|
|
21
|
+
}, (error) => {
|
|
22
|
+
this._error = error;
|
|
23
|
+
this._loading = false;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
this._error = error;
|
|
28
|
+
this._loading = false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
get data() {
|
|
33
|
+
return this._data;
|
|
34
|
+
}
|
|
35
|
+
get id() {
|
|
36
|
+
return this.docRef?.id ?? '';
|
|
37
|
+
}
|
|
38
|
+
get loading() {
|
|
39
|
+
return this._loading;
|
|
40
|
+
}
|
|
41
|
+
get error() {
|
|
42
|
+
return this._error;
|
|
43
|
+
}
|
|
44
|
+
get ref() {
|
|
45
|
+
if (this.docRef === null) {
|
|
46
|
+
throw new Error("Document reference is not available yet.");
|
|
47
|
+
}
|
|
48
|
+
return this.docRef;
|
|
49
|
+
}
|
|
50
|
+
get exists() {
|
|
51
|
+
return this._data !== null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function firekitDoc(ref, startWith) {
|
|
55
|
+
return new FirekitDoc(ref, startWith);
|
|
56
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type DocumentData, type WithFieldValue, type PartialWithFieldValue } from "firebase/firestore";
|
|
2
|
+
declare class FirekitDocumentMutations {
|
|
3
|
+
constructor();
|
|
4
|
+
add<T extends DocumentData>(collectionPath: string, data: WithFieldValue<T>, options?: {
|
|
5
|
+
timestamps?: boolean;
|
|
6
|
+
}): Promise<import("@firebase/firestore").DocumentReference<DocumentData, DocumentData>>;
|
|
7
|
+
set<T extends DocumentData>(path: string, data: WithFieldValue<T>, options?: {
|
|
8
|
+
merge?: boolean;
|
|
9
|
+
timestamps?: boolean;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
update<T extends DocumentData>(path: string, data: PartialWithFieldValue<T>, options?: {
|
|
12
|
+
timestamps?: boolean;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
delete(path: string): Promise<void>;
|
|
15
|
+
exists(path: string): Promise<boolean>;
|
|
16
|
+
}
|
|
17
|
+
export declare const firekitDocMutations: FirekitDocumentMutations;
|
|
18
|
+
export {};
|