@umituz/web-firebase 3.2.3 → 3.3.0

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": "3.2.3",
3
+ "version": "3.3.0",
4
4
  "description": "Comprehensive Firebase integration with domain-based architecture for web applications",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -21,7 +21,10 @@
21
21
  "src"
22
22
  ],
23
23
  "scripts": {
24
- "typecheck": "tsc --noEmit"
24
+ "build": "npm run clean && tsc",
25
+ "clean": "rm -rf dist",
26
+ "typecheck": "tsc --noEmit",
27
+ "prepublishOnly": "npm run build"
25
28
  },
26
29
  "keywords": [
27
30
  "firebase",
@@ -6,7 +6,6 @@
6
6
  import type { UserCredential } from 'firebase/auth'
7
7
  import type { IAuthRepository } from '../../../domain/interfaces/auth.repository.interface'
8
8
  import type { IUserRepository } from '../../../domain/interfaces/user.repository.interface'
9
- import type { CreateUserDTO } from '../../dto/user.dto'
10
9
  import { createAuthError, AuthErrorCode } from '../../../domain/errors/auth.errors'
11
10
 
12
11
  export class SignInWithGoogleUseCase {
@@ -27,16 +26,19 @@ export class SignInWithGoogleUseCase {
27
26
  const existingUser = await this.userRepository.getUser(result.user.uid)
28
27
  if (!existingUser) {
29
28
  // New user - create user document
30
- const createUserDTO: CreateUserDTO = {
31
- id: result.user.uid,
32
- email: result.user.email || '',
33
- displayName: result.user.displayName || '',
34
- photoURL: result.user.photoURL || undefined,
35
- phoneNumber: result.user.phoneNumber || undefined,
36
- emailVerified: result.user.emailVerified,
37
- }
38
-
39
- await this.authRepository.createUserDocument(result.user.uid, createUserDTO)
29
+ await this.userRepository.createUser(result.user.uid, {
30
+ profile: {
31
+ id: result.user.uid,
32
+ email: result.user.email || '',
33
+ displayName: result.user.displayName || '',
34
+ photoURL: result.user.photoURL || undefined,
35
+ phoneNumber: result.user.phoneNumber || undefined,
36
+ emailVerified: result.user.emailVerified,
37
+ createdAt: Date.now(),
38
+ updatedAt: Date.now(),
39
+ lastLoginAt: Date.now(),
40
+ }
41
+ } as any)
40
42
  }
41
43
 
42
44
  return result
@@ -3,21 +3,33 @@
3
3
  * @description Generic contract for file storage operations
4
4
  */
5
5
 
6
+ import type { UploadResult, UploadOptions } from '../entities/file.entity'
7
+
6
8
  export interface IFileRepository {
7
9
  /**
8
10
  * Upload file to storage
9
11
  */
10
- uploadFile(userId: string, path: string, file: File | Blob, options?: any): Promise<any>
12
+ uploadFile(userId: string, path: string, file: File | Blob, options?: UploadOptions): Promise<UploadResult>
11
13
 
12
14
  /**
13
15
  * Upload image with automatic categorization
14
16
  */
15
- uploadImage(userId: string, file: File, filename?: string): Promise<any>
17
+ uploadImage(userId: string, file: File, filename?: string): Promise<UploadResult>
18
+
19
+ /**
20
+ * Upload video with automatic categorization
21
+ */
22
+ uploadVideo(userId: string, file: File, filename?: string): Promise<UploadResult>
23
+
24
+ /**
25
+ * Upload document with automatic categorization
26
+ */
27
+ uploadDocument(userId: string, file: File, filename?: string): Promise<UploadResult>
16
28
 
17
29
  /**
18
30
  * Upload profile picture
19
31
  */
20
- uploadProfilePicture(userId: string, file: File): Promise<any>
32
+ uploadProfilePicture(userId: string, file: File): Promise<UploadResult>
21
33
 
22
34
  /**
23
35
  * Get download URL for a file
@@ -34,11 +46,24 @@ export interface IFileRepository {
34
46
  */
35
47
  deleteUserFiles(userId: string): Promise<void>
36
48
 
49
+ /**
50
+ * Delete specific media types
51
+ */
52
+ deleteImage(userId: string, filename: string): Promise<void>
53
+ deleteVideo(userId: string, filename: string): Promise<void>
54
+ deleteProfilePicture(userId: string, filename: string): Promise<void>
55
+
37
56
  /**
38
57
  * List user files
39
58
  */
40
59
  listUserFiles(userId: string, path?: string): Promise<string[]>
41
60
 
61
+ /**
62
+ * List specific media types
63
+ */
64
+ listUserImages(userId: string): Promise<string[]>
65
+ listUserVideos(userId: string): Promise<string[]>
66
+
42
67
  /**
43
68
  * Validate file before upload
44
69
  */
@@ -3,46 +3,18 @@
3
3
  * @description Generic contract for user data operations
4
4
  */
5
5
 
6
- import type { QueryConstraint } from 'firebase/firestore'
6
+ import type { User } from '../entities/user.entity'
7
7
 
8
8
  export interface IUserRepository {
9
- /**
10
- * Get document by ID
11
- */
12
- getById<T>(userId: string): Promise<T | null>
13
-
14
- /**
15
- * Get document by field
16
- */
17
- getByField<T>(collectionPath: string, field: string, value: any): Promise<T | null>
18
-
19
- /**
20
- * Create document
21
- */
22
- create(userId: string, data: any): Promise<void>
23
-
24
- /**
25
- * Update document
26
- */
27
- update(userId: string, data: any, options?: { merge?: boolean }): Promise<void>
28
-
29
- /**
30
- * Delete document
31
- */
32
- delete(userId: string): Promise<void>
33
-
34
- /**
35
- * Query collection with constraints
36
- */
37
- query<T>(collectionPath: string, constraints: QueryConstraint[]): Promise<T[]>
38
-
39
- /**
40
- * Subscribe to document changes
41
- */
42
- subscribeToDoc<T>(docPath: string, callback: (data: T | null) => void): () => void
43
-
44
- /**
45
- * Subscribe to collection changes
46
- */
47
- subscribeToCollection<T>(collectionPath: string, callback: (data: T[]) => void, constraints?: QueryConstraint[]): () => void
9
+ getUser(userId: string): Promise<User | null>
10
+ getUserByEmail(email: string): Promise<User | null>
11
+ createUser(userId: string, data: Partial<User>): Promise<void>
12
+ updateUser(userId: string, data: Partial<User>): Promise<void>
13
+ deleteUser(userId: string): Promise<void>
14
+ updateProfile(userId: string, updates: Partial<Pick<User['profile'], 'displayName' | 'photoURL' | 'phoneNumber'>>): Promise<void>
15
+ updateSettings(userId: string, settings: Partial<User['settings']>): Promise<void>
16
+ updateSubscription(userId: string, subscription: Partial<User['subscription']>): Promise<void>
17
+ updateLastLogin(userId: string): Promise<void>
18
+ queryUsers(constraints: any[]): Promise<User[]>
19
+ subscribeToUser(userId: string, callback: (user: User | null) => void, onError?: (error: Error) => void): () => void
48
20
  }
@@ -21,7 +21,11 @@ import type { User } from '../entities'
21
21
 
22
22
  class FirestoreService implements IFirestoreService {
23
23
  private get db() {
24
- return getFirebaseDB()
24
+ const db = getFirebaseDB()
25
+ if (!db) {
26
+ throw new Error('Firestore not initialized. Call initializeFirebase() first.')
27
+ }
28
+ return db
25
29
  }
26
30
 
27
31
  private readonly USERS_COLLECTION = 'users'
@@ -21,7 +21,11 @@ import type {
21
21
 
22
22
  class StorageService implements IStorageService {
23
23
  private get storage() {
24
- return getFirebaseStorage()
24
+ const storage = getFirebaseStorage()
25
+ if (!storage) {
26
+ throw new Error('Firebase Storage not initialized. Call initializeFirebase() first.')
27
+ }
28
+ return storage
25
29
  }
26
30
 
27
31
  // Upload Methods
package/src/index.ts CHANGED
@@ -1,19 +1,10 @@
1
1
  /**
2
2
  * @umituz/web-firebase
3
- * Firebase integration for web applications with domain-based architecture
3
+ * Firebase client initialization and core services
4
4
  *
5
5
  * Usage:
6
- * import { AuthService } from '@umituz/web-firebase/auth'
7
- * import { FirestoreService } from '@umituz/web-firebase/firestore'
8
- * import { StorageService } from '@umituz/web-firebase/storage'
6
+ * import { initializeFirebase, getFirebaseDB } from '@umituz/web-firebase'
9
7
  */
10
8
 
11
9
  // Firebase client initialization
12
10
  export * from './infrastructure/firebase/client'
13
-
14
- // Presentation Layer (React components & hooks)
15
- export * from './presentation/index'
16
-
17
- // Re-export common types for convenience
18
- export type { FirebaseInstances } from './infrastructure/firebase/client'
19
- export type { FirebaseContextValue, FirebaseProviderProps } from './presentation/providers/FirebaseProvider'
@@ -36,7 +36,11 @@ import { getAuthConfig } from '../../domain/config/auth.config'
36
36
  */
37
37
  export class AuthAdapter implements IAuthRepository {
38
38
  private get auth() {
39
- return getFirebaseAuth()
39
+ const auth = getFirebaseAuth()
40
+ if (!auth) {
41
+ throw new Error('Firebase Auth not initialized. Call initializeFirebase() first.')
42
+ }
43
+ return auth
40
44
  }
41
45
 
42
46
  private config = getAuthConfig()
@@ -320,8 +324,8 @@ export class AuthAdapter implements IAuthRepository {
320
324
  return this.auth.currentUser
321
325
  }
322
326
 
323
- onAuthStateChanged(callback: (user: FirebaseUser | null) => void) {
324
- return this.auth.onAuthStateChanged(callback)
327
+ onAuthStateChanged(callback: (user: FirebaseUser | null) => void, onError?: (error: Error) => void) {
328
+ return this.auth.onAuthStateChanged(callback, onError)
325
329
  }
326
330
 
327
331
  // ==================== Token Management ====================
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Firebase Client
3
3
  * @description Firebase initialization and singleton instances
4
- * Migrated from: /Users/umituz/Desktop/github/umituz/apps/web/app-growth-factory/src/domains/firebase/services/client.ts
4
+ * Migrated from: /Users/umuz/Desktop/github/umituz/apps/web/app-growth-factory/src/domains/firebase/services/client.ts
5
5
  */
6
6
 
7
7
  import { initializeApp, getApps, FirebaseApp } from 'firebase/app'
@@ -11,50 +11,75 @@ import { getStorage, FirebaseStorage } from 'firebase/storage'
11
11
  import { getAnalytics, Analytics } from 'firebase/analytics'
12
12
  import { getFunctions, Functions } from 'firebase/functions'
13
13
 
14
- const firebaseConfig = {
15
- apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
16
- authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
17
- projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
18
- storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
19
- messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
20
- appId: import.meta.env.VITE_FIREBASE_APP_ID,
21
- measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
14
+ /**
15
+ * Firebase Configuration interface
16
+ * Pass this to initializeFirebase()
17
+ */
18
+ export interface FirebaseConfig {
19
+ apiKey: string
20
+ authDomain: string
21
+ projectId: string
22
+ storageBucket: string
23
+ messagingSenderId: string
24
+ appId: string
25
+ measurementId?: string
22
26
  }
23
27
 
24
28
  // Singleton instances
25
- let app: FirebaseApp
26
- let auth: Auth
27
- let db: Firestore
28
- let storage: FirebaseStorage
29
- let functions: Functions
29
+ let app: FirebaseApp | null = null
30
+ let auth: Auth | null = null
31
+ let db: Firestore | null = null
32
+ let storage: FirebaseStorage | null = null
33
+ let functions: Functions | null = null
30
34
  let analytics: Analytics | null = null
31
35
 
32
36
  /**
33
- * Initialize Firebase App
37
+ * Initialize Firebase with provided configuration
38
+ * Must be called before using any Firebase services
39
+ *
40
+ * @param config - Firebase configuration object
41
+ * @returns FirebaseApp instance
34
42
  */
35
- export function initializeFirebase(): FirebaseApp {
36
- if (!getApps().length) {
37
- app = initializeApp(firebaseConfig)
38
- } else {
43
+ export function initializeFirebase(config: FirebaseConfig): FirebaseApp {
44
+ if (app) {
45
+ console.warn('Firebase already initialized')
46
+ return app
47
+ }
48
+
49
+ if (getApps().length > 0) {
39
50
  app = getApps()[0]
51
+ return app
40
52
  }
53
+
54
+ // Validate config
55
+ if (!config.apiKey || !config.projectId) {
56
+ throw new Error('Invalid Firebase config: apiKey and projectId are required')
57
+ }
58
+
59
+ app = initializeApp(config)
41
60
  return app
42
61
  }
43
62
 
44
63
  /**
45
64
  * Get Firebase App instance
65
+ * @returns FirebaseApp instance or null if not initialized
46
66
  */
47
- export function getFirebaseApp(): FirebaseApp {
48
- return app || initializeFirebase()
67
+ export function getFirebaseApp(): FirebaseApp | null {
68
+ return app
49
69
  }
50
70
 
51
71
  /**
52
72
  * Get Firebase Auth instance
73
+ * @returns Auth instance or null if not initialized
53
74
  */
54
- export function getFirebaseAuth(): Auth {
75
+ export function getFirebaseAuth(): Auth | null {
76
+ if (!app) {
77
+ console.warn('Firebase not initialized. Call initializeFirebase(config) first.')
78
+ return null
79
+ }
55
80
  if (!auth) {
56
81
  const firebaseApp = getFirebaseApp()
57
- if (typeof window !== 'undefined') {
82
+ if (firebaseApp && typeof window !== 'undefined') {
58
83
  try {
59
84
  auth = getAuth(firebaseApp)
60
85
  } catch (e) {
@@ -63,7 +88,7 @@ export function getFirebaseAuth(): Auth {
63
88
  persistence: browserLocalPersistence,
64
89
  })
65
90
  }
66
- } else {
91
+ } else if (firebaseApp) {
67
92
  auth = getAuth(firebaseApp)
68
93
  }
69
94
  }
@@ -72,70 +97,99 @@ export function getFirebaseAuth(): Auth {
72
97
 
73
98
  /**
74
99
  * Get Firestore instance
100
+ * @returns Firestore instance or null if not initialized
75
101
  */
76
- export function getFirebaseDB(): Firestore {
102
+ export function getFirebaseDB(): Firestore | null {
103
+ if (!app) {
104
+ console.warn('Firebase not initialized. Call initializeFirebase(config) first.')
105
+ return null
106
+ }
77
107
  if (!db) {
78
- db = getFirestore(getFirebaseApp())
108
+ db = getFirestore(getFirebaseApp()!)
79
109
  }
80
110
  return db
81
111
  }
82
112
 
83
113
  /**
84
114
  * Get Firebase Storage instance
115
+ * @returns FirebaseStorage instance or null if not initialized
85
116
  */
86
- export function getFirebaseStorage(): FirebaseStorage {
117
+ export function getFirebaseStorage(): FirebaseStorage | null {
118
+ if (!app) {
119
+ console.warn('Firebase not initialized. Call initializeFirebase(config) first.')
120
+ return null
121
+ }
87
122
  if (!storage) {
88
- storage = getStorage(getFirebaseApp())
123
+ storage = getStorage(getFirebaseApp()!)
89
124
  }
90
125
  return storage
91
126
  }
92
127
 
93
128
  /**
94
129
  * Get Firebase Functions instance
130
+ * @returns Functions instance or null if not initialized
95
131
  */
96
- export function getFirebaseFunctions(): Functions {
132
+ export function getFirebaseFunctions(): Functions | null {
133
+ if (!app) {
134
+ console.warn('Firebase not initialized. Call initializeFirebase(config) first.')
135
+ return null
136
+ }
97
137
  if (!functions) {
98
- functions = getFunctions(getFirebaseApp())
138
+ functions = getFunctions(getFirebaseApp()!)
99
139
  }
100
140
  return functions
101
141
  }
102
142
 
103
143
  /**
104
144
  * Get Firebase Analytics instance
145
+ * @returns Analytics instance or null (not available in SSR or not initialized)
105
146
  */
106
147
  export function getFirebaseAnalytics(): Analytics | null {
148
+ if (!app) {
149
+ console.warn('Firebase not initialized. Call initializeFirebase(config) first.')
150
+ return null
151
+ }
107
152
  if (!analytics && typeof window !== 'undefined') {
108
- analytics = getAnalytics(getFirebaseApp())
153
+ analytics = getAnalytics(getFirebaseApp()!)
109
154
  }
110
155
  return analytics
111
156
  }
112
157
 
113
158
  /**
114
159
  * Firebase Instances
115
- * All Firebase service instances
160
+ * All Firebase service instances (may be null if not initialized)
116
161
  */
117
162
  export interface FirebaseInstances {
118
163
  app: FirebaseApp
119
- auth: Auth
120
- db: Firestore
121
- storage: FirebaseStorage
122
- functions: Functions
164
+ auth: Auth | null
165
+ db: Firestore | null
166
+ storage: FirebaseStorage | null
167
+ functions: Functions | null
123
168
  analytics: Analytics | null
124
169
  }
125
170
 
126
171
  /**
127
172
  * Get all Firebase instances
173
+ * @returns FirebaseInstances or null if not initialized
128
174
  */
129
- export function getFirebaseInstances(): FirebaseInstances {
175
+ export function getFirebaseInstances(): FirebaseInstances | null {
176
+ const app = getFirebaseApp()
177
+ if (!app) {
178
+ return null
179
+ }
130
180
  return {
131
- app: getFirebaseApp(),
132
- auth: getFirebaseAuth(),
133
- db: getFirebaseDB(),
134
- storage: getFirebaseStorage(),
135
- functions: getFirebaseFunctions(),
181
+ app,
182
+ auth: getFirebaseAuth()!,
183
+ db: getFirebaseDB()!,
184
+ storage: getFirebaseStorage()!,
185
+ functions: getFirebaseFunctions()!,
136
186
  analytics: getFirebaseAnalytics(),
137
187
  }
138
188
  }
139
189
 
140
- // Export singleton instances for convenience
141
- export { app, auth, db, storage, functions, analytics }
190
+ /**
191
+ * Check if Firebase is initialized
192
+ */
193
+ export function isFirebaseInitialized(): boolean {
194
+ return app !== null
195
+ }
@@ -23,7 +23,11 @@ import { createRepositoryError, RepositoryErrorCode } from '../../domain/errors/
23
23
 
24
24
  export class FirestoreAdapter implements IUserRepository {
25
25
  private get db() {
26
- return getFirebaseDB()
26
+ const db = getFirebaseDB()
27
+ if (!db) {
28
+ throw new Error('Firestore not initialized. Call initializeFirebase() first.')
29
+ }
30
+ return db
27
31
  }
28
32
 
29
33
  private readonly USERS_COLLECTION = 'users'
@@ -26,7 +26,11 @@ import { createRepositoryError, RepositoryErrorCode } from '../../domain/errors/
26
26
 
27
27
  export class StorageAdapter implements IFileRepository {
28
28
  private get storage() {
29
- return getFirebaseStorage()
29
+ const storage = getFirebaseStorage()
30
+ if (!storage) {
31
+ throw new Error('Firebase Storage not initialized. Call initializeFirebase() first.')
32
+ }
33
+ return storage
30
34
  }
31
35
 
32
36
  // Upload Methods