@umituz/react-native-auth 3.4.21 → 3.4.23

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.
@@ -0,0 +1,90 @@
1
+ import {
2
+ validatePasswordForLogin,
3
+ validatePasswordForRegister,
4
+ validatePasswordConfirmation,
5
+ } from '../../../src/infrastructure/utils/AuthValidation';
6
+ import { DEFAULT_PASSWORD_CONFIG } from '../../../src/domain/value-objects/AuthConfig';
7
+
8
+ describe('AuthPasswordValidation', () => {
9
+ describe('validatePasswordForLogin', () => {
10
+ it('should reject empty password', () => {
11
+ const result = validatePasswordForLogin('');
12
+ expect(result.isValid).toBe(false);
13
+ expect(result.error).toBe('Password is required');
14
+ });
15
+
16
+ it('should accept any non-empty password', () => {
17
+ const result = validatePasswordForLogin('any');
18
+ expect(result.isValid).toBe(true);
19
+ });
20
+ });
21
+
22
+ describe('validatePasswordForRegister', () => {
23
+ const config = DEFAULT_PASSWORD_CONFIG;
24
+
25
+ it('should reject empty password', () => {
26
+ const result = validatePasswordForRegister('', config);
27
+ expect(result.isValid).toBe(false);
28
+ expect(result.requirements.hasMinLength).toBe(false);
29
+ });
30
+
31
+ it('should reject password that is too short', () => {
32
+ const result = validatePasswordForRegister('123', config);
33
+ expect(result.isValid).toBe(false);
34
+ expect(result.requirements.hasMinLength).toBe(false);
35
+ });
36
+
37
+ it('should validate uppercase requirement', () => {
38
+ const configReq = { ...config, requireUppercase: true };
39
+ expect(validatePasswordForRegister('password', configReq).isValid).toBe(false);
40
+ expect(validatePasswordForRegister('Password', configReq).requirements.hasUppercase).toBe(true);
41
+ });
42
+
43
+ it('should validate lowercase requirement', () => {
44
+ const configReq = { ...config, requireLowercase: true };
45
+ expect(validatePasswordForRegister('PASSWORD', configReq).isValid).toBe(false);
46
+ expect(validatePasswordForRegister('Password', configReq).requirements.hasLowercase).toBe(true);
47
+ });
48
+
49
+ it('should validate number requirement', () => {
50
+ const configReq = { ...config, requireNumber: true };
51
+ expect(validatePasswordForRegister('Password', configReq).isValid).toBe(false);
52
+ expect(validatePasswordForRegister('Password1', configReq).requirements.hasNumber).toBe(true);
53
+ });
54
+
55
+ it('should validate special character requirement', () => {
56
+ const configReq = { ...config, requireSpecialChar: true };
57
+ expect(validatePasswordForRegister('Password1', configReq).isValid).toBe(false);
58
+ expect(validatePasswordForRegister('Password1!', configReq).requirements.hasSpecialChar).toBe(true);
59
+ });
60
+
61
+ it('should accept password that meets all requirements', () => {
62
+ const strictConfig = {
63
+ ...config,
64
+ requireUppercase: true,
65
+ requireLowercase: true,
66
+ requireNumber: true,
67
+ requireSpecialChar: true,
68
+ };
69
+ const result = validatePasswordForRegister('Password1!', strictConfig);
70
+ expect(result.isValid).toBe(true);
71
+ });
72
+ });
73
+
74
+ describe('validatePasswordConfirmation', () => {
75
+ it('should reject empty confirmation', () => {
76
+ const result = validatePasswordConfirmation('password', '');
77
+ expect(result.isValid).toBe(false);
78
+ });
79
+
80
+ it('should reject mismatched passwords', () => {
81
+ const result = validatePasswordConfirmation('password', 'different');
82
+ expect(result.isValid).toBe(false);
83
+ });
84
+
85
+ it('should accept matching passwords', () => {
86
+ const result = validatePasswordConfirmation('password', 'password');
87
+ expect(result.isValid).toBe(true);
88
+ });
89
+ });
90
+ });
package/src/index.ts CHANGED
@@ -1,31 +1,10 @@
1
1
  /**
2
2
  * React Native Auth - Public API
3
- *
4
- * Domain-Driven Design (DDD) Architecture
5
- *
6
- * This is the SINGLE SOURCE OF TRUTH for all Auth operations.
7
- * ALL imports from the Auth package MUST go through this file.
8
- *
9
- * Architecture:
10
- * - domain: Entities, value objects, errors (business logic)
11
- * - application: Ports (interfaces)
12
- * - infrastructure: Auth providers and service implementation
13
- * - presentation: Hooks (React integration)
14
- *
15
- * Usage:
16
- * import { initializeAuthService, useAuth } from '@umituz/react-native-auth';
3
+ * Single source of truth for all Auth operations.
17
4
  */
18
5
 
19
- // =============================================================================
20
- // DOMAIN LAYER - Entities
21
- // =============================================================================
22
-
6
+ // DOMAIN LAYER
23
7
  export type { AuthUser, AuthProviderType } from './domain/entities/AuthUser';
24
-
25
- // =============================================================================
26
- // DOMAIN LAYER - Errors
27
- // =============================================================================
28
-
29
8
  export {
30
9
  AuthError,
31
10
  AuthInitializationError,
@@ -39,10 +18,6 @@ export {
39
18
  AuthInvalidEmailError,
40
19
  } from './domain/errors/AuthError';
41
20
 
42
- // =============================================================================
43
- // DOMAIN LAYER - Value Objects
44
- // =============================================================================
45
-
46
21
  export type {
47
22
  AuthConfig,
48
23
  PasswordConfig,
@@ -58,10 +33,7 @@ export {
58
33
  DEFAULT_SOCIAL_CONFIG,
59
34
  } from './domain/value-objects/AuthConfig';
60
35
 
61
- // =============================================================================
62
- // APPLICATION LAYER - Ports
63
- // =============================================================================
64
-
36
+ // APPLICATION LAYER
65
37
  export type { IAuthService, SignUpParams, SignInParams } from './application/ports/IAuthService';
66
38
  export type {
67
39
  IAuthProvider,
@@ -70,55 +42,37 @@ export type {
70
42
  SocialSignInResult,
71
43
  } from './application/ports/IAuthProvider';
72
44
 
73
- // =============================================================================
74
- // INFRASTRUCTURE LAYER - Providers
75
- // =============================================================================
76
-
45
+ // INFRASTRUCTURE LAYER
77
46
  export { FirebaseAuthProvider } from './infrastructure/providers/FirebaseAuthProvider';
78
-
79
- // =============================================================================
80
- // INFRASTRUCTURE LAYER - Services
81
- // =============================================================================
82
-
83
47
  export {
84
48
  AuthService,
85
49
  initializeAuthService,
86
50
  getAuthService,
87
51
  resetAuthService,
88
52
  } from './infrastructure/services/AuthService';
89
-
90
53
  export {
91
54
  createStorageProvider,
92
55
  StorageProviderAdapter,
93
56
  } from './infrastructure/adapters/StorageProviderAdapter';
94
-
95
57
  export type { IStorageProvider } from './infrastructure/services/AuthPackage';
96
-
97
58
  export {
98
59
  ensureUserDocument,
99
60
  markUserDeleted,
100
61
  configureUserDocumentService,
101
62
  } from './infrastructure/services/UserDocumentService';
102
-
103
- // Unified Auth Initialization (RECOMMENDED)
104
63
  export {
105
64
  initializeAuth,
106
65
  isAuthInitialized,
107
66
  resetAuthInitialization,
108
67
  } from './infrastructure/services/initializeAuth';
109
-
110
68
  export type { InitializeAuthOptions } from './infrastructure/services/initializeAuth';
111
-
112
69
  export type {
113
70
  UserDocumentConfig,
114
71
  UserDocumentExtras,
115
72
  UserDocumentUser,
116
73
  } from './infrastructure/services/UserDocumentService';
117
74
 
118
- // =============================================================================
119
- // INFRASTRUCTURE LAYER - Validation
120
- // =============================================================================
121
-
75
+ // VALIDATION
122
76
  export {
123
77
  validateEmail,
124
78
  validatePasswordForLogin,
@@ -126,86 +80,57 @@ export {
126
80
  validatePasswordConfirmation,
127
81
  validateDisplayName,
128
82
  } from './infrastructure/utils/AuthValidation';
129
-
130
83
  export type {
131
84
  ValidationResult,
132
85
  PasswordStrengthResult,
133
86
  PasswordRequirements,
134
87
  } from './infrastructure/utils/AuthValidation';
135
88
 
136
- // =============================================================================
137
- // PRESENTATION LAYER - Provider
138
- // =============================================================================
139
-
89
+ // PRESENTATION LAYER
140
90
  export { AuthProvider } from './presentation/providers/AuthProvider';
141
-
142
- // =============================================================================
143
- // PRESENTATION LAYER - Hooks
144
- // =============================================================================
145
-
146
91
  export { useAuth } from './presentation/hooks/useAuth';
147
92
  export type { UseAuthResult } from './presentation/hooks/useAuth';
148
-
149
93
  export { useAuthRequired } from './presentation/hooks/useAuthRequired';
150
94
  export type { UseAuthRequiredResult } from './presentation/hooks/useAuthRequired';
151
-
152
95
  export { useRequireAuth, useUserId } from './presentation/hooks/useRequireAuth';
153
-
154
96
  export { useUserProfile } from './presentation/hooks/useUserProfile';
155
97
  export type { UserProfileData, UseUserProfileParams } from './presentation/hooks/useUserProfile';
156
-
157
98
  export { useAccountManagement } from './presentation/hooks/useAccountManagement';
158
99
  export type { UseAccountManagementReturn } from './presentation/hooks/useAccountManagement';
159
-
160
100
  export { useProfileUpdate } from './presentation/hooks/useProfileUpdate';
161
101
  export type { UseProfileUpdateReturn } from './presentation/hooks/useProfileUpdate';
162
-
163
102
  export { useProfileEdit } from './presentation/hooks/useProfileEdit';
164
103
  export type { UseProfileEditReturn, ProfileEditFormState } from './presentation/hooks/useProfileEdit';
165
-
166
104
  export { useSocialLogin } from './presentation/hooks/useSocialLogin';
167
105
  export type { UseSocialLoginConfig, UseSocialLoginResult } from './presentation/hooks/useSocialLogin';
168
-
169
106
  export { useGoogleAuth } from './presentation/hooks/useGoogleAuth';
170
107
  export type { UseGoogleAuthResult, GoogleAuthConfig as GoogleAuthHookConfig } from './presentation/hooks/useGoogleAuth';
171
-
172
108
  export { useAppleAuth } from './presentation/hooks/useAppleAuth';
173
109
  export type { UseAppleAuthResult } from './presentation/hooks/useAppleAuth';
174
-
175
110
  export { useAuthBottomSheet } from './presentation/hooks/useAuthBottomSheet';
176
- export { useAuthBottomSheetWrapper } from './presentation/hooks/useAuthBottomSheetWrapper';
111
+ export type { SocialAuthConfiguration } from './presentation/hooks/useAuthBottomSheet';
177
112
 
113
+ // DOMAIN ENTITIES & UTILS
178
114
  export type { UserProfile, UpdateProfileParams } from './domain/entities/UserProfile';
179
-
180
- // Domain Utils - Anonymous Names
181
115
  export { generateAnonymousName, getAnonymousDisplayName } from './domain/utils/anonymousNameGenerator';
182
116
  export type { AnonymousNameConfig } from './domain/utils/anonymousNameGenerator';
183
-
184
- // Domain Utils - Migration
185
117
  export { migrateUserData, configureMigration } from './domain/utils/migration';
186
118
  export type { MigrationConfig } from './domain/utils/migration';
187
119
 
188
- // =============================================================================
189
- // PRESENTATION LAYER - Screens & Navigation
190
- // =============================================================================
191
-
120
+ // SCREENS & NAVIGATION
192
121
  export { LoginScreen } from './presentation/screens/LoginScreen';
193
122
  export { RegisterScreen } from './presentation/screens/RegisterScreen';
194
123
  export { AccountScreen } from './presentation/screens/AccountScreen';
195
124
  export type { AccountScreenConfig, AccountScreenProps } from './presentation/screens/AccountScreen';
196
125
  export { EditProfileScreen } from './presentation/screens/EditProfileScreen';
197
126
  export type { EditProfileConfig, EditProfileScreenProps } from './presentation/screens/EditProfileScreen';
198
-
199
127
  export { AuthNavigator } from './presentation/navigation/AuthNavigator';
200
128
  export type {
201
129
  AuthStackParamList,
202
130
  AuthNavigatorProps,
203
131
  } from './presentation/navigation/AuthNavigator';
204
132
 
205
- // =============================================================================
206
- // PRESENTATION LAYER - Components
207
- // =============================================================================
208
-
133
+ // COMPONENTS
209
134
  export { AuthContainer } from './presentation/components/AuthContainer';
210
135
  export { AuthHeader } from './presentation/components/AuthHeader';
211
136
  export { AuthFormCard } from './presentation/components/AuthFormCard';
@@ -219,9 +144,6 @@ export { PasswordMatchIndicator } from './presentation/components/PasswordMatchI
219
144
  export type { PasswordMatchIndicatorProps } from './presentation/components/PasswordMatchIndicator';
220
145
  export { AuthBottomSheet } from './presentation/components/AuthBottomSheet';
221
146
  export type { AuthBottomSheetProps } from './presentation/components/AuthBottomSheet';
222
- export { AuthBottomSheetWrapper } from './presentation/components/AuthBottomSheetWrapper';
223
- export type { AuthBottomSheetWrapperProps } from './presentation/components/AuthBottomSheetWrapper';
224
- export type { SocialAuthConfiguration } from './presentation/hooks/useAuthBottomSheetWrapper';
225
147
  export { SocialLoginButtons } from './presentation/components/SocialLoginButtons';
226
148
  export type { SocialLoginButtonsProps } from './presentation/components/SocialLoginButtons';
227
149
  export { ProfileSection } from './presentation/components/ProfileSection';
@@ -229,13 +151,9 @@ export type { ProfileSectionConfig, ProfileSectionProps } from './presentation/c
229
151
  export { AccountActions } from './presentation/components/AccountActions';
230
152
  export type { AccountActionsConfig, AccountActionsProps } from './presentation/components/AccountActions';
231
153
 
232
- // =============================================================================
233
- // PRESENTATION LAYER - Stores
234
- // =============================================================================
235
-
154
+ // STORES
236
155
  export { useAuthModalStore } from './presentation/stores/authModalStore';
237
156
  export type { AuthModalMode } from './presentation/stores/authModalStore';
238
-
239
157
  export {
240
158
  useAuthStore,
241
159
  initializeAuthListener,
@@ -251,13 +169,8 @@ export {
251
169
  getIsAuthenticated,
252
170
  getIsAnonymous,
253
171
  } from './presentation/stores/authStore';
254
-
255
172
  export type { UserType, AuthState, AuthActions } from './presentation/stores/authStore';
256
173
  export type { AuthListenerOptions } from './types/auth-store.types';
257
174
 
258
- // =============================================================================
259
- // PRESENTATION LAYER - Utilities
260
- // =============================================================================
261
-
175
+ // UTILITIES
262
176
  export { getAuthErrorLocalizationKey } from './presentation/utils/getAuthErrorMessage';
263
-
@@ -0,0 +1,44 @@
1
+ /**
2
+ * User Document Types and Configuration
3
+ */
4
+
5
+ /**
6
+ * Minimal user interface for document creation
7
+ * Compatible with both Firebase User and AuthUser
8
+ */
9
+ export interface UserDocumentUser {
10
+ uid: string;
11
+ displayName?: string | null;
12
+ email?: string | null;
13
+ photoURL?: string | null;
14
+ isAnonymous?: boolean;
15
+ }
16
+
17
+ /**
18
+ * Configuration for user document service
19
+ */
20
+ export interface UserDocumentConfig {
21
+ /** Firestore collection name (default: "users") */
22
+ collectionName?: string;
23
+ /** Additional fields to store with user document */
24
+ extraFields?: Record<string, unknown>;
25
+ /** Callback to collect device/app info */
26
+ collectExtras?: () => Promise<Record<string, unknown>>;
27
+ }
28
+
29
+ /**
30
+ * User document extras from device/app
31
+ */
32
+ export interface UserDocumentExtras {
33
+ deviceId?: string;
34
+ platform?: string;
35
+ deviceModel?: string;
36
+ deviceBrand?: string;
37
+ osVersion?: string;
38
+ appVersion?: string;
39
+ buildNumber?: string;
40
+ locale?: string;
41
+ timezone?: string;
42
+ previousAnonymousUserId?: string;
43
+ signUpMethod?: string;
44
+ }
@@ -1,68 +1,31 @@
1
1
  /**
2
2
  * User Document Service
3
3
  * Generic service for creating/updating user documents in Firestore
4
- * Called automatically on auth state changes
5
4
  */
6
5
 
7
6
  import { doc, getDoc, setDoc, serverTimestamp } from "firebase/firestore";
8
7
  import type { User } from "firebase/auth";
9
8
  import { getFirestore } from "@umituz/react-native-firebase";
9
+ import type {
10
+ UserDocumentUser,
11
+ UserDocumentConfig,
12
+ UserDocumentExtras,
13
+ } from "./UserDocument.types";
14
+
15
+ export type {
16
+ UserDocumentUser,
17
+ UserDocumentConfig,
18
+ UserDocumentExtras,
19
+ } from "./UserDocument.types";
10
20
 
11
21
  declare const __DEV__: boolean;
12
22
 
13
- /**
14
- * Minimal user interface for document creation
15
- * Compatible with both Firebase User and AuthUser
16
- */
17
- export interface UserDocumentUser {
18
- uid: string;
19
- displayName?: string | null;
20
- email?: string | null;
21
- photoURL?: string | null;
22
- isAnonymous?: boolean;
23
- }
24
-
25
- /**
26
- * Configuration for user document service
27
- */
28
- export interface UserDocumentConfig {
29
- /** Firestore collection name (default: "users") */
30
- collectionName?: string;
31
- /** Additional fields to store with user document */
32
- extraFields?: Record<string, unknown>;
33
- /** Callback to collect device/app info */
34
- collectExtras?: () => Promise<Record<string, unknown>>;
35
- }
36
-
37
- /**
38
- * User document extras from device/app
39
- */
40
- export interface UserDocumentExtras {
41
- deviceId?: string;
42
- platform?: string;
43
- deviceModel?: string;
44
- deviceBrand?: string;
45
- osVersion?: string;
46
- appVersion?: string;
47
- buildNumber?: string;
48
- locale?: string;
49
- timezone?: string;
50
- previousAnonymousUserId?: string;
51
- signUpMethod?: string;
52
- }
53
-
54
23
  let userDocumentConfig: UserDocumentConfig = {};
55
24
 
56
- /**
57
- * Configure user document service
58
- */
59
25
  export function configureUserDocumentService(config: UserDocumentConfig): void {
60
26
  userDocumentConfig = { ...config };
61
27
  }
62
28
 
63
- /**
64
- * Get sign-up method from auth user
65
- */
66
29
  function getSignUpMethod(user: UserDocumentUser): string | undefined {
67
30
  if (user.isAnonymous) return "anonymous";
68
31
  if (user.email) {
@@ -80,9 +43,6 @@ function getSignUpMethod(user: UserDocumentUser): string | undefined {
80
43
  return undefined;
81
44
  }
82
45
 
83
- /**
84
- * Build base user data from auth user
85
- */
86
46
  function buildBaseData(
87
47
  user: UserDocumentUser,
88
48
  extras?: UserDocumentExtras,
@@ -94,22 +54,19 @@ function buildBaseData(
94
54
  isAnonymous: user.isAnonymous,
95
55
  };
96
56
 
97
- if (extras?.deviceId) data.deviceId = extras.deviceId;
98
- if (extras?.platform) data.platform = extras.platform;
99
- if (extras?.deviceModel) data.deviceModel = extras.deviceModel;
100
- if (extras?.deviceBrand) data.deviceBrand = extras.deviceBrand;
101
- if (extras?.osVersion) data.osVersion = extras.osVersion;
102
- if (extras?.appVersion) data.appVersion = extras.appVersion;
103
- if (extras?.buildNumber) data.buildNumber = extras.buildNumber;
104
- if (extras?.locale) data.locale = extras.locale;
105
- if (extras?.timezone) data.timezone = extras.timezone;
57
+ const fields: (keyof UserDocumentExtras)[] = [
58
+ 'deviceId', 'platform', 'deviceModel', 'deviceBrand',
59
+ 'osVersion', 'appVersion', 'buildNumber', 'locale', 'timezone'
60
+ ];
61
+
62
+ fields.forEach(field => {
63
+ const val = extras?.[field];
64
+ if (val) data[field] = val;
65
+ });
106
66
 
107
67
  return data;
108
68
  }
109
69
 
110
- /**
111
- * Build create data for new user document
112
- */
113
70
  function buildCreateData(
114
71
  baseData: Record<string, unknown>,
115
72
  extras?: UserDocumentExtras,
@@ -128,16 +85,11 @@ function buildCreateData(
128
85
  createData.convertedAt = serverTimestamp();
129
86
  }
130
87
 
131
- if (extras?.signUpMethod) {
132
- createData.signUpMethod = extras.signUpMethod;
133
- }
88
+ if (extras?.signUpMethod) createData.signUpMethod = extras.signUpMethod;
134
89
 
135
90
  return createData;
136
91
  }
137
92
 
138
- /**
139
- * Build update data for existing user document
140
- */
141
93
  function buildUpdateData(
142
94
  baseData: Record<string, unknown>,
143
95
  extras?: UserDocumentExtras,
@@ -152,55 +104,38 @@ function buildUpdateData(
152
104
  updateData.previousAnonymousUserId = extras.previousAnonymousUserId;
153
105
  updateData.convertedFromAnonymous = true;
154
106
  updateData.convertedAt = serverTimestamp();
155
- if (extras?.signUpMethod) {
156
- updateData.signUpMethod = extras.signUpMethod;
157
- }
107
+ if (extras?.signUpMethod) updateData.signUpMethod = extras.signUpMethod;
158
108
  }
159
109
 
160
110
  return updateData;
161
111
  }
162
112
 
163
- /**
164
- * Ensure user document exists in Firestore
165
- * Creates new document or updates existing one
166
- */
167
113
  export async function ensureUserDocument(
168
114
  user: UserDocumentUser | User,
169
115
  extras?: UserDocumentExtras,
170
116
  ): Promise<boolean> {
171
117
  const db = getFirestore();
172
- if (typeof __DEV__ !== "undefined" && __DEV__) {
173
- // eslint-disable-next-line no-console
174
- console.log("[UserDocumentService] db:", !!db, "type:", typeof db, "constructor:", db?.constructor?.name);
175
- }
176
118
  if (!db || !user.uid) return false;
177
119
 
178
120
  try {
179
- // Collect additional extras if configured
180
121
  let allExtras = extras || {};
181
122
  if (userDocumentConfig.collectExtras) {
182
123
  const collectedExtras = await userDocumentConfig.collectExtras();
183
124
  allExtras = { ...collectedExtras, ...allExtras };
184
125
  }
185
126
 
186
- // Add sign-up method if not provided
187
- if (!allExtras.signUpMethod) {
188
- allExtras.signUpMethod = getSignUpMethod(user);
189
- }
127
+ if (!allExtras.signUpMethod) allExtras.signUpMethod = getSignUpMethod(user);
190
128
 
191
129
  const collectionName = userDocumentConfig.collectionName || "users";
192
130
  const userRef = doc(db, collectionName, user.uid);
193
131
  const userDoc = await getDoc(userRef);
194
132
  const baseData = buildBaseData(user, allExtras);
195
133
 
196
- if (!userDoc.exists()) {
197
- const createData = buildCreateData(baseData, allExtras);
198
- await setDoc(userRef, createData);
199
- } else {
200
- const updateData = buildUpdateData(baseData, allExtras);
201
- await setDoc(userRef, updateData, { merge: true });
202
- }
134
+ const docData = !userDoc.exists()
135
+ ? buildCreateData(baseData, allExtras)
136
+ : buildUpdateData(baseData, allExtras);
203
137
 
138
+ await setDoc(userRef, docData, { merge: true });
204
139
  return true;
205
140
  } catch (error) {
206
141
  if (typeof __DEV__ !== "undefined" && __DEV__) {
@@ -211,25 +146,17 @@ export async function ensureUserDocument(
211
146
  }
212
147
  }
213
148
 
214
- /**
215
- * Mark user as deleted (soft delete)
216
- */
217
149
  export async function markUserDeleted(userId: string): Promise<boolean> {
218
150
  const db = getFirestore();
219
151
  if (!db || !userId) return false;
220
152
 
221
153
  try {
222
- const collectionName = userDocumentConfig.collectionName || "users";
223
- const userRef = doc(db, collectionName, userId);
224
- await setDoc(
225
- userRef,
226
- {
227
- isDeleted: true,
228
- deletedAt: serverTimestamp(),
229
- updatedAt: serverTimestamp(),
230
- },
231
- { merge: true },
232
- );
154
+ const userRef = doc(db, userDocumentConfig.collectionName || "users", userId);
155
+ await setDoc(userRef, {
156
+ isDeleted: true,
157
+ deletedAt: serverTimestamp(),
158
+ updatedAt: serverTimestamp(),
159
+ }, { merge: true });
233
160
  return true;
234
161
  } catch {
235
162
  return false;