@umituz/web-firebase 3.0.1 → 3.2.1

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/README.md CHANGED
@@ -11,6 +11,10 @@ Comprehensive Firebase integration with Domain-Driven Design (DDD) architecture
11
11
  - ✅ **React Hooks** - Ready-to-use presentation layer hooks
12
12
  - ✅ **Error Handling** - Domain-specific error types
13
13
  - ✅ **Zero Code Duplication** - Package-driven development ready
14
+ - ✅ **Google & Apple OAuth** - Built-in support for Google Sign-In and Apple Sign-In
15
+ - ✅ **Configurable Auth** - Enable/disable providers, configure scopes and custom parameters
16
+ - ✅ **Auto User Document Creation** - Automatic Firestore user document creation with custom settings
17
+ - ✅ **Provider Linking/Unlinking** - Link multiple auth providers to a single account
14
18
 
15
19
  ## 📦 Installation
16
20
 
@@ -64,6 +68,61 @@ const firebaseConfig = {
64
68
  initializeFirebaseApp(firebaseConfig)
65
69
  ```
66
70
 
71
+ ### 2. Configure Authentication
72
+
73
+ ```typescript
74
+ import { initAuthConfig } from '@umituz/web-firebase/config'
75
+
76
+ // Initialize auth configuration
77
+ initAuthConfig({
78
+ // Enable/disable email/password authentication
79
+ emailPasswordEnabled: true,
80
+
81
+ // Enable/disable OAuth providers
82
+ googleEnabled: true,
83
+ appleEnabled: true,
84
+
85
+ // Configure Google OAuth
86
+ googleScopes: ['profile', 'email'],
87
+ googleCustomParameters: {
88
+ prompt: 'select_account',
89
+ },
90
+
91
+ // Require email verification for new users
92
+ requireEmailVerification: true,
93
+
94
+ // Automatically create user document in Firestore
95
+ autoCreateUserDocument: true,
96
+
97
+ // Default user settings
98
+ defaultUserSettings: {
99
+ theme: 'system',
100
+ language: 'tr',
101
+ timezone: 'Europe/Istanbul',
102
+ currency: 'TRY',
103
+ notifications: {
104
+ email: true,
105
+ push: true,
106
+ marketing: false,
107
+ security: true,
108
+ weeklyDigest: false,
109
+ },
110
+ privacy: {
111
+ profileVisibility: 'public',
112
+ showEmail: false,
113
+ showPhone: false,
114
+ dataSharing: false,
115
+ },
116
+ },
117
+
118
+ // Default subscription plan
119
+ defaultSubscriptionPlan: 'free',
120
+
121
+ // Session persistence
122
+ persistence: 'local',
123
+ })
124
+ ```
125
+
67
126
  ### 2. Use Domain Layer (Types & Interfaces)
68
127
 
69
128
  ```typescript
@@ -231,6 +290,28 @@ const credential = await auth.signUp('user@example.com', 'password', 'John Doe')
231
290
  // Sign in with Google
232
291
  const credential = await auth.signInWithGoogle()
233
292
 
293
+ // Sign in with Apple
294
+ const credential = await auth.signInWithApple()
295
+
296
+ // Sign in with redirect flow (for mobile/better UX)
297
+ const credential = await auth.signInWithGoogle(true) // useRedirect = true
298
+
299
+ // Link Google to current user
300
+ await auth.linkGoogle()
301
+
302
+ // Link Apple to current user
303
+ await auth.linkApple()
304
+
305
+ // Unlink a provider
306
+ await auth.unlinkProvider('google.com')
307
+
308
+ // Get ID token (for API calls)
309
+ const token = await auth.getIdToken()
310
+ const tokenForceRefresh = await auth.getIdToken(true)
311
+
312
+ // Refresh ID token
313
+ await auth.refreshToken()
314
+
234
315
  // Sign out
235
316
  await auth.signOut()
236
317
 
@@ -385,40 +466,100 @@ import {
385
466
  } from '@umituz/web-firebase/presentation'
386
467
 
387
468
  function MyComponent() {
388
- // Auth hook
469
+ // Auth hook with Google & Apple OAuth
389
470
  const {
390
- user: firebaseUser,
471
+ firebaseUser,
391
472
  user: userData,
392
473
  loading,
393
474
  error,
475
+ // Email/Password
394
476
  signIn,
395
477
  signUp,
478
+ // OAuth Providers
396
479
  signInWithGoogle,
480
+ signInWithApple,
481
+ // Provider management
482
+ linkGoogle,
483
+ linkApple,
484
+ unlinkProvider,
485
+ // Account management
397
486
  signOut,
398
- } = useAuth({
399
- authRepository: new AuthAdapter(),
400
- userRepository: new FirestoreAdapter(),
401
- })
402
-
403
- // User hook
404
- const { user, loading: userLoading } = useUser({
405
- userRepository: new FirestoreAdapter(),
406
- userId: firebaseUser?.uid,
407
- })
487
+ sendPasswordReset,
488
+ resendEmailVerification,
489
+ updateProfile,
490
+ updateEmail,
491
+ updatePassword,
492
+ deleteAccount,
493
+ // Token management
494
+ getIdToken,
495
+ refreshToken,
496
+ // User data
497
+ refreshUser,
498
+ // Config
499
+ googleEnabled,
500
+ appleEnabled,
501
+ emailPasswordEnabled,
502
+ } = useAuth()
503
+
504
+ // Example: Sign in with Google
505
+ const handleGoogleSignIn = async () => {
506
+ try {
507
+ const user = await signInWithGoogle()
508
+ console.log('Signed in with Google:', user)
509
+ } catch (error) {
510
+ console.error('Sign in failed:', error)
511
+ }
512
+ }
513
+
514
+ // Example: Sign in with Apple
515
+ const handleAppleSignIn = async () => {
516
+ try {
517
+ const user = await signInWithApple()
518
+ console.log('Signed in with Apple:', user)
519
+ } catch (error) {
520
+ console.error('Sign in failed:', error)
521
+ }
522
+ }
523
+
524
+ // Example: Get ID token for API call
525
+ const makeApiCall = async () => {
526
+ const token = await getIdToken()
527
+ const response = await fetch('/api/protected', {
528
+ headers: {
529
+ Authorization: `Bearer ${token}`,
530
+ },
531
+ })
532
+ return response.json()
533
+ }
408
534
 
409
- // Storage hook
410
- const {
411
- uploadFile,
412
- uploadImage,
413
- uploadProfilePicture,
414
- deleteFile,
415
- uploading,
416
- progress,
417
- error: storageError,
418
- } = useStorage({
419
- fileRepository: new StorageAdapter(),
420
- userId: firebaseUser?.uid,
421
- })
535
+ return (
536
+ <div>
537
+ {loading ? (
538
+ <p>Loading...</p>
539
+ ) : firebaseUser ? (
540
+ <>
541
+ <p>Welcome, {userData?.profile.displayName}</p>
542
+ <button onClick={handleGoogleSignIn}>Re-authenticate with Google</button>
543
+ <button onClick={() => linkApple()}>Link Apple Account</button>
544
+ <button onClick={() => signOut()}>Sign Out</button>
545
+ </>
546
+ ) : (
547
+ <>
548
+ {emailPasswordEnabled && (
549
+ <button onClick={() => signIn('user@example.com', 'password')}>
550
+ Sign In with Email
551
+ </button>
552
+ )}
553
+ {googleEnabled && (
554
+ <button onClick={handleGoogleSignIn}>Sign In with Google</button>
555
+ )}
556
+ {appleEnabled && (
557
+ <button onClick={handleAppleSignIn}>Sign In with Apple</button>
558
+ )}
559
+ </>
560
+ )}
561
+ </div>
562
+ )
422
563
  }
423
564
  ```
424
565
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/web-firebase",
3
- "version": "3.0.1",
3
+ "version": "3.2.1",
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",
@@ -13,6 +13,8 @@
13
13
  "./auth": "./src/domains/auth/index.ts",
14
14
  "./firestore": "./src/domains/firestore/index.ts",
15
15
  "./storage": "./src/domains/storage/index.ts",
16
+ "./domain": "./src/domain/index.ts",
17
+ "./config": "./src/domain/config/auth.config.ts",
16
18
  "./package.json": "./package.json"
17
19
  },
18
20
  "files": [
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Auth Configuration
3
+ * @description Configuration options for Firebase Authentication
4
+ * Following DDD principles, this is a domain configuration value object
5
+ */
6
+
7
+ /**
8
+ * Available OAuth Providers
9
+ */
10
+ export type OAuthProviderType =
11
+ | 'google'
12
+ | 'apple'
13
+
14
+ /**
15
+ * OAuth Provider Configuration
16
+ */
17
+ export interface OAuthProviderConfig {
18
+ enabled: boolean
19
+ scopes?: string[]
20
+ customParameters?: Record<string, string>
21
+ }
22
+
23
+ /**
24
+ * Auth Configuration Interface
25
+ */
26
+ export interface AuthConfig {
27
+ // Email/Password Authentication
28
+ emailPasswordEnabled: boolean
29
+
30
+ // OAuth Providers
31
+ // OAuth Providers (Google & Apple)
32
+ googleEnabled: boolean
33
+ appleEnabled: boolean
34
+ googleScopes?: string[]
35
+ googleCustomParameters?: Record<string, string>
36
+
37
+ // Email Verification
38
+ requireEmailVerification: boolean
39
+
40
+ // User Document Creation
41
+ autoCreateUserDocument: boolean
42
+
43
+ // Default User Settings (applied when creating user document)
44
+ defaultUserSettings?: {
45
+ theme?: 'light' | 'dark' | 'system'
46
+ language?: string
47
+ timezone?: string
48
+ currency?: string
49
+ notifications?: {
50
+ email?: boolean
51
+ push?: boolean
52
+ marketing?: boolean
53
+ security?: boolean
54
+ weeklyDigest?: boolean
55
+ }
56
+ privacy?: {
57
+ profileVisibility?: 'public' | 'private'
58
+ showEmail?: boolean
59
+ showPhone?: boolean
60
+ dataSharing?: boolean
61
+ }
62
+ }
63
+
64
+ // Default Subscription Plan
65
+ defaultSubscriptionPlan?: 'free' | 'standard' | 'professional' | 'business'
66
+
67
+ // Token Refresh Settings
68
+ tokenRefreshEnabled: boolean
69
+ tokenRefreshThreshold: number // milliseconds
70
+
71
+ // Session Persistence
72
+ persistence: 'local' | 'session' | 'none'
73
+
74
+ // Error Handling
75
+ throwOnAuthError: boolean
76
+ }
77
+
78
+ /**
79
+ * Default Auth Configuration
80
+ */
81
+ export const DEFAULT_AUTH_CONFIG: AuthConfig = {
82
+ emailPasswordEnabled: true,
83
+ googleEnabled: true,
84
+ appleEnabled: false,
85
+ googleScopes: ['profile', 'email'],
86
+ requireEmailVerification: true,
87
+ autoCreateUserDocument: true,
88
+ defaultUserSettings: {
89
+ theme: 'system',
90
+ language: 'en',
91
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
92
+ currency: 'USD',
93
+ notifications: {
94
+ email: true,
95
+ push: true,
96
+ marketing: false,
97
+ security: true,
98
+ weeklyDigest: false,
99
+ },
100
+ privacy: {
101
+ profileVisibility: 'public',
102
+ showEmail: false,
103
+ showPhone: false,
104
+ dataSharing: false,
105
+ },
106
+ },
107
+ defaultSubscriptionPlan: 'free',
108
+ tokenRefreshEnabled: true,
109
+ tokenRefreshThreshold: 5 * 60 * 1000, // 5 minutes
110
+ persistence: 'local',
111
+ throwOnAuthError: true,
112
+ }
113
+
114
+ /**
115
+ * Auth Configuration Manager
116
+ * Singleton class to manage auth configuration
117
+ */
118
+ export class AuthConfigManager {
119
+ private static instance: AuthConfigManager
120
+ private config: AuthConfig
121
+
122
+ private constructor(config: Partial<AuthConfig> = {}) {
123
+ this.config = {
124
+ ...DEFAULT_AUTH_CONFIG,
125
+ ...config,
126
+ defaultUserSettings: {
127
+ ...DEFAULT_AUTH_CONFIG.defaultUserSettings,
128
+ ...config.defaultUserSettings,
129
+ notifications: {
130
+ ...DEFAULT_AUTH_CONFIG.defaultUserSettings?.notifications,
131
+ ...config.defaultUserSettings?.notifications,
132
+ },
133
+ privacy: {
134
+ ...DEFAULT_AUTH_CONFIG.defaultUserSettings?.privacy,
135
+ ...config.defaultUserSettings?.privacy,
136
+ },
137
+ },
138
+ }
139
+ }
140
+
141
+ static getInstance(config?: Partial<AuthConfig>): AuthConfigManager {
142
+ if (!AuthConfigManager.instance) {
143
+ AuthConfigManager.instance = new AuthConfigManager(config)
144
+ }
145
+ return AuthConfigManager.instance
146
+ }
147
+
148
+ getConfig(): AuthConfig {
149
+ return { ...this.config }
150
+ }
151
+
152
+ updateConfig(updates: Partial<AuthConfig>): void {
153
+ this.config = {
154
+ ...this.config,
155
+ ...updates,
156
+ defaultUserSettings: {
157
+ ...this.config.defaultUserSettings,
158
+ ...updates.defaultUserSettings,
159
+ notifications: {
160
+ ...this.config.defaultUserSettings?.notifications,
161
+ ...updates.defaultUserSettings?.notifications,
162
+ },
163
+ privacy: {
164
+ ...this.config.defaultUserSettings?.privacy,
165
+ ...updates.defaultUserSettings?.privacy,
166
+ },
167
+ },
168
+ }
169
+ }
170
+
171
+ isGoogleEnabled(): boolean {
172
+ return this.config.googleEnabled
173
+ }
174
+
175
+ isAppleEnabled(): boolean {
176
+ return this.config.appleEnabled
177
+ }
178
+
179
+ isEmailPasswordEnabled(): boolean {
180
+ return this.config.emailPasswordEnabled
181
+ }
182
+
183
+ shouldCreateUserDocument(): boolean {
184
+ return this.config.autoCreateUserDocument
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Initialize Auth Config with custom settings
190
+ */
191
+ export function initAuthConfig(config: Partial<AuthConfig> = {}): AuthConfigManager {
192
+ return AuthConfigManager.getInstance(config)
193
+ }
194
+
195
+ /**
196
+ * Get Auth Config instance
197
+ */
198
+ export function getAuthConfig(): AuthConfigManager {
199
+ return AuthConfigManager.getInstance()
200
+ }
@@ -28,3 +28,6 @@ export * from './interfaces/file.repository.interface'
28
28
  // Errors
29
29
  export * from './errors/auth.errors'
30
30
  export * from './errors/repository.errors'
31
+
32
+ // Config
33
+ export * from './config/auth.config'