@umituz/web-firebase 1.0.4 → 1.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/web-firebase",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Universal Firebase utilities for web applications",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -20,7 +20,8 @@
20
20
  "./presentation": "./src/presentation/index.ts"
21
21
  },
22
22
  "files": [
23
- "dist"
23
+ "dist",
24
+ "src"
24
25
  ],
25
26
  "scripts": {
26
27
  "build": "tsup src/index.ts --format cjs,esm --dts --clean --external react --external firebase --external firebase/app --external firebase/auth --external firebase/firestore --external firebase/storage --external firebase/functions",
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Firebase Entity Types
3
+ */
4
+
5
+ export type FirebaseTimestamp = { toDate(): Date } | Date;
6
+
7
+ export interface FirebaseUser {
8
+ uid: string;
9
+ email: string | null;
10
+ displayName: string | null;
11
+ photoURL: string | null;
12
+ emailVerified: boolean;
13
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Domain Layer
3
+ * Subpath: @umituz/web-firebase/domain
4
+ */
5
+
6
+ export * from './entities/firebase.entity';
7
+ export * from './interfaces/repository.interface';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Base Repository Interface
3
+ */
4
+
5
+ export interface IBaseRepository<T> {
6
+ getById(id: string, parentPath?: string): Promise<T | null>;
7
+ getAll(constraints?: any[], parentPath?: string): Promise<T[]>;
8
+ create(id: string, data: Omit<T, 'id'>, parentPath?: string): Promise<void>;
9
+ update(id: string, data: Partial<T>, parentPath?: string): Promise<void>;
10
+ delete(id: string, parentPath?: string): Promise<void>;
11
+ }
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @umituz/web-firebase
3
+ * Universal Firebase utilities for web
4
+ */
5
+
6
+ export * from './domain';
7
+ export * from './infrastructure';
8
+ export * from './presentation';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Infrastructure Layer
3
+ * Subpath: @umituz/web-firebase/infrastructure
4
+ */
5
+
6
+ export * from './services/firebase.service';
7
+ export * from './services/firestore.repository';
8
+ export * from './utils/storage.util';
@@ -0,0 +1,30 @@
1
+ import { initializeApp, getApps, type FirebaseOptions, type FirebaseApp } from 'firebase/app';
2
+ import { getAuth, type Auth } from 'firebase/auth';
3
+ import { getFirestore, type Firestore } from 'firebase/firestore';
4
+ import { getStorage, type FirebaseStorage } from 'firebase/storage';
5
+ import { getFunctions, type Functions } from 'firebase/functions';
6
+
7
+ /**
8
+ * Firebase Service Infrastructure
9
+ * @description Initialization and instance management for Firebase
10
+ */
11
+
12
+ export interface FirebaseInstances {
13
+ app: FirebaseApp;
14
+ auth: Auth;
15
+ db: Firestore;
16
+ storage: FirebaseStorage;
17
+ functions: Functions;
18
+ }
19
+
20
+ export function initializeFirebase(config: FirebaseOptions, appName?: string): FirebaseInstances {
21
+ const existing = getApps().find((a) => a.name === (appName ?? '[DEFAULT]'));
22
+ const app = existing ?? initializeApp(config, appName);
23
+ return {
24
+ app,
25
+ auth: getAuth(app),
26
+ db: getFirestore(app),
27
+ storage: getStorage(app),
28
+ functions: getFunctions(app),
29
+ };
30
+ }
@@ -0,0 +1,66 @@
1
+ import {
2
+ collection,
3
+ doc,
4
+ getDoc,
5
+ getDocs,
6
+ setDoc,
7
+ updateDoc,
8
+ deleteDoc,
9
+ query,
10
+ type QueryConstraint,
11
+ type DocumentData,
12
+ type Firestore,
13
+ type CollectionReference,
14
+ } from 'firebase/firestore';
15
+ import type { IBaseRepository } from '../../domain/interfaces/repository.interface';
16
+
17
+ /**
18
+ * Firestore Repository Implementation
19
+ * @description Generic CRUD operations for Firestore collections
20
+ */
21
+ export class FirestoreRepository<T extends DocumentData> implements IBaseRepository<T> {
22
+ constructor(
23
+ protected db: Firestore,
24
+ protected collectionName: string,
25
+ ) {}
26
+
27
+ protected getCollection(parentPath?: string): CollectionReference<T> {
28
+ const fullPath = parentPath ? `${parentPath}/${this.collectionName}` : this.collectionName;
29
+ return collection(this.db, fullPath) as CollectionReference<T>;
30
+ }
31
+
32
+ protected getDocRef(id: string, parentPath?: string) {
33
+ const fullPath = parentPath ? `${parentPath}/${this.collectionName}` : this.collectionName;
34
+ return doc(this.db, fullPath, id);
35
+ }
36
+
37
+ async getById(id: string, parentPath?: string): Promise<T | null> {
38
+ const snap = await getDoc(this.getDocRef(id, parentPath));
39
+ return snap.exists() ? ({ id: snap.id, ...snap.data() } as unknown as T) : null;
40
+ }
41
+
42
+ async getAll(constraints: QueryConstraint[] = [], parentPath?: string): Promise<T[]> {
43
+ const q = query(this.getCollection(parentPath), ...constraints);
44
+ const snap = await getDocs(q);
45
+ return snap.docs.map((d) => ({ id: d.id, ...d.data() } as unknown as T));
46
+ }
47
+
48
+ async create(id: string, data: Omit<T, 'id'>, parentPath?: string): Promise<void> {
49
+ await setDoc(this.getDocRef(id, parentPath), {
50
+ ...data,
51
+ createdAt: new Date().toISOString(),
52
+ updatedAt: new Date().toISOString(),
53
+ });
54
+ }
55
+
56
+ async update(id: string, data: Partial<T>, parentPath?: string): Promise<void> {
57
+ await updateDoc(this.getDocRef(id, parentPath), {
58
+ ...(data as DocumentData),
59
+ updatedAt: new Date().toISOString(),
60
+ });
61
+ }
62
+
63
+ async delete(id: string, parentPath?: string): Promise<void> {
64
+ await deleteDoc(this.getDocRef(id, parentPath));
65
+ }
66
+ }
@@ -0,0 +1,46 @@
1
+ import {
2
+ ref,
3
+ uploadBytes,
4
+ uploadString,
5
+ getDownloadURL,
6
+ deleteObject,
7
+ type FirebaseStorage,
8
+ } from 'firebase/storage';
9
+
10
+ /**
11
+ * Firebase Storage Utils
12
+ * @description Upload and delete helpers for Firebase Storage
13
+ */
14
+
15
+ export interface UploadResult {
16
+ url: string;
17
+ path: string;
18
+ }
19
+
20
+ export async function uploadFile(
21
+ storage: FirebaseStorage,
22
+ path: string,
23
+ file: File | Blob,
24
+ ): Promise<UploadResult> {
25
+ const storageRef = ref(storage, path);
26
+ await uploadBytes(storageRef, file);
27
+ const url = await getDownloadURL(storageRef);
28
+ return { url, path };
29
+ }
30
+
31
+ export async function uploadBase64(
32
+ storage: FirebaseStorage,
33
+ path: string,
34
+ base64: string,
35
+ mimeType = 'image/jpeg',
36
+ ): Promise<UploadResult> {
37
+ const storageRef = ref(storage, path);
38
+ const dataUrl = base64.startsWith('data:') ? base64 : `data:${mimeType};base64,${base64}`;
39
+ await uploadString(storageRef, dataUrl, 'data_url');
40
+ const url = await getDownloadURL(storageRef);
41
+ return { url, path };
42
+ }
43
+
44
+ export async function deleteFile(storage: FirebaseStorage, path: string): Promise<void> {
45
+ await deleteObject(ref(storage, path));
46
+ }
@@ -0,0 +1,122 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import {
3
+ type Auth,
4
+ type UserCredential,
5
+ type User,
6
+ onAuthStateChanged,
7
+ signInWithEmailAndPassword,
8
+ createUserWithEmailAndPassword,
9
+ signOut as firebaseSignOut,
10
+ updateProfile,
11
+ updatePassword,
12
+ sendPasswordResetEmail,
13
+ } from 'firebase/auth';
14
+ import type { FirebaseUser } from '../../domain/entities/firebase.entity';
15
+
16
+ function mapUser(u: User): FirebaseUser {
17
+ return {
18
+ uid: u.uid,
19
+ email: u.email,
20
+ displayName: u.displayName,
21
+ photoURL: u.photoURL,
22
+ emailVerified: u.emailVerified,
23
+ };
24
+ }
25
+
26
+ /**
27
+ * useFirebaseAuth Hook
28
+ * @description Hook to manage Firebase authentication state and operations
29
+ */
30
+
31
+ export interface UseFirebaseAuthOptions {
32
+ onUserChange?: (user: FirebaseUser | null) => void;
33
+ }
34
+
35
+ export interface UseFirebaseAuthReturn {
36
+ user: FirebaseUser | null;
37
+ loading: boolean;
38
+ isAuthenticated: boolean;
39
+ signIn(email: string, password: string): Promise<UserCredential>;
40
+ signUp(email: string, password: string, name?: string): Promise<UserCredential>;
41
+ signOut(): Promise<void>;
42
+ updateUserProfile(name: string, photoURL?: string): Promise<void>;
43
+ updateUserPassword(newPassword: string): Promise<void>;
44
+ resetPassword(email: string): Promise<void>;
45
+ getIdToken(): Promise<string>;
46
+ }
47
+
48
+ export function useFirebaseAuth(
49
+ auth: Auth,
50
+ options?: UseFirebaseAuthOptions,
51
+ ): UseFirebaseAuthReturn {
52
+ const [user, setUser] = useState<FirebaseUser | null>(null);
53
+ const [loading, setLoading] = useState(true);
54
+
55
+ useEffect(() => {
56
+ const unsub = onAuthStateChanged(auth, (firebaseUser) => {
57
+ const mapped = firebaseUser ? mapUser(firebaseUser) : null;
58
+ setUser(mapped);
59
+ setLoading(false);
60
+ options?.onUserChange?.(mapped);
61
+ });
62
+ return unsub;
63
+ }, [auth, options]);
64
+
65
+ const signIn = useCallback(
66
+ (email: string, password: string) => signInWithEmailAndPassword(auth, email, password),
67
+ [auth],
68
+ );
69
+
70
+ const signUp = useCallback(
71
+ async (email: string, password: string, name?: string) => {
72
+ const cred = await createUserWithEmailAndPassword(auth, email, password);
73
+ if (name && cred.user) await updateProfile(cred.user, { displayName: name });
74
+ return cred;
75
+ },
76
+ [auth],
77
+ );
78
+
79
+ const signOut = useCallback(() => firebaseSignOut(auth), [auth]);
80
+
81
+ const updateUserProfile = useCallback(
82
+ async (name: string, photoURL?: string) => {
83
+ if (!auth.currentUser) throw new Error('No authenticated user');
84
+ await updateProfile(auth.currentUser, {
85
+ displayName: name,
86
+ ...(photoURL !== undefined && { photoURL }),
87
+ });
88
+ },
89
+ [auth],
90
+ );
91
+
92
+ const updateUserPassword = useCallback(
93
+ async (newPassword: string) => {
94
+ if (!auth.currentUser) throw new Error('No authenticated user');
95
+ await updatePassword(auth.currentUser, newPassword);
96
+ },
97
+ [auth],
98
+ );
99
+
100
+ const resetPassword = useCallback(
101
+ (email: string) => sendPasswordResetEmail(auth, email),
102
+ [auth],
103
+ );
104
+
105
+ const getIdToken = useCallback(async () => {
106
+ if (!auth.currentUser) throw new Error('No authenticated user');
107
+ return auth.currentUser.getIdToken();
108
+ }, [auth]);
109
+
110
+ return {
111
+ user,
112
+ loading,
113
+ isAuthenticated: !!user,
114
+ signIn,
115
+ signUp,
116
+ signOut,
117
+ updateUserProfile,
118
+ updateUserPassword,
119
+ resetPassword,
120
+ getIdToken,
121
+ };
122
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Presentation Layer
3
+ * Subpath: @umituz/web-firebase/presentation
4
+ */
5
+
6
+ export * from './hooks/useFirebaseAuth';