@umituz/web-firebase 1.0.5 → 2.1.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.
Files changed (69) hide show
  1. package/README.md +555 -0
  2. package/dist/application/index.d.mts +273 -0
  3. package/dist/application/index.d.ts +273 -0
  4. package/dist/application/index.js +490 -0
  5. package/dist/application/index.mjs +19 -0
  6. package/dist/chunk-34DL2QWQ.mjs +87 -0
  7. package/dist/chunk-4FP2ELQ5.mjs +96 -0
  8. package/dist/chunk-7TX3OU3O.mjs +721 -0
  9. package/dist/chunk-I6WGBPFB.mjs +439 -0
  10. package/dist/chunk-RZ4QR6TB.mjs +96 -0
  11. package/dist/chunk-U2XI4MGO.mjs +397 -0
  12. package/dist/domain/index.d.mts +325 -0
  13. package/dist/domain/index.d.ts +325 -0
  14. package/dist/domain/index.js +662 -0
  15. package/dist/domain/index.mjs +36 -0
  16. package/dist/file.repository.interface-v5vHgVsZ.d.mts +241 -0
  17. package/dist/file.repository.interface-v5vHgVsZ.d.ts +241 -0
  18. package/dist/firebase.entity-xvfEPjXZ.d.mts +15 -0
  19. package/dist/firebase.entity-xvfEPjXZ.d.ts +15 -0
  20. package/dist/index.d.mts +14 -96
  21. package/dist/index.d.ts +14 -96
  22. package/dist/index.js +1717 -78
  23. package/dist/index.mjs +88 -175
  24. package/dist/infrastructure/index.d.mts +170 -0
  25. package/dist/infrastructure/index.d.ts +170 -0
  26. package/dist/infrastructure/index.js +856 -0
  27. package/dist/infrastructure/index.mjs +46 -0
  28. package/dist/presentation/index.d.mts +25 -0
  29. package/dist/presentation/index.d.ts +25 -0
  30. package/dist/presentation/index.js +105 -0
  31. package/dist/presentation/index.mjs +6 -0
  32. package/dist/user.repository.interface-DS74TsJ5.d.mts +298 -0
  33. package/dist/user.repository.interface-DS74TsJ5.d.ts +298 -0
  34. package/package.json +37 -11
  35. package/src/application/dto/auth.dto.ts +69 -0
  36. package/src/application/dto/index.ts +7 -0
  37. package/src/application/dto/user.dto.ts +64 -0
  38. package/src/application/index.ts +7 -0
  39. package/src/application/use-cases/auth/reset-password.use-case.ts +66 -0
  40. package/src/application/use-cases/auth/sign-in-with-google.use-case.ts +86 -0
  41. package/src/application/use-cases/auth/sign-in.use-case.ts +77 -0
  42. package/src/application/use-cases/auth/sign-out.use-case.ts +22 -0
  43. package/src/application/use-cases/auth/sign-up.use-case.ts +99 -0
  44. package/src/application/use-cases/index.ts +12 -0
  45. package/src/application/use-cases/user/delete-account.use-case.ts +77 -0
  46. package/src/application/use-cases/user/update-profile.use-case.ts +98 -0
  47. package/src/domain/entities/file.entity.ts +151 -0
  48. package/src/domain/entities/timestamp.entity.ts +116 -0
  49. package/src/domain/entities/user.entity.ts +193 -0
  50. package/src/domain/errors/auth.errors.ts +115 -0
  51. package/src/domain/errors/repository.errors.ts +121 -0
  52. package/src/domain/index.ts +25 -2
  53. package/src/domain/interfaces/auth.repository.interface.ts +83 -0
  54. package/src/domain/interfaces/file.repository.interface.ts +143 -0
  55. package/src/domain/interfaces/user.repository.interface.ts +75 -0
  56. package/src/domain/value-objects/email.vo.ts +105 -0
  57. package/src/domain/value-objects/file-path.vo.ts +184 -0
  58. package/src/domain/value-objects/user-id.vo.ts +87 -0
  59. package/src/index.ts +19 -4
  60. package/src/infrastructure/firebase/auth.adapter.ts +220 -0
  61. package/src/infrastructure/firebase/client.ts +141 -0
  62. package/src/infrastructure/firebase/firestore.adapter.ts +190 -0
  63. package/src/infrastructure/firebase/storage.adapter.ts +323 -0
  64. package/src/infrastructure/index.ts +10 -5
  65. package/src/infrastructure/utils/storage.util.ts +3 -3
  66. package/src/presentation/hooks/useAuth.ts +108 -0
  67. package/src/presentation/hooks/useFirestore.ts +125 -0
  68. package/src/presentation/hooks/useStorage.ts +141 -0
  69. package/src/presentation/providers/FirebaseProvider.tsx +95 -0
@@ -0,0 +1,397 @@
1
+ import {
2
+ createAuthError
3
+ } from "./chunk-RZ4QR6TB.mjs";
4
+
5
+ // src/application/use-cases/auth/sign-in.use-case.ts
6
+ var SignInUseCase = class {
7
+ constructor(authRepository) {
8
+ this.authRepository = authRepository;
9
+ }
10
+ /**
11
+ * Execute sign in use case
12
+ */
13
+ async execute(dto) {
14
+ try {
15
+ this.validateDTO(dto);
16
+ const result = await this.authRepository.signIn(dto.email, dto.password);
17
+ return result;
18
+ } catch (error) {
19
+ throw this.handleError(error);
20
+ }
21
+ }
22
+ /**
23
+ * Validate DTO
24
+ */
25
+ validateDTO(dto) {
26
+ if (!dto.email) {
27
+ throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Email is required");
28
+ }
29
+ if (!dto.password) {
30
+ throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Password is required");
31
+ }
32
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
33
+ if (!emailRegex.test(dto.email)) {
34
+ throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid email format");
35
+ }
36
+ }
37
+ /**
38
+ * Handle errors
39
+ */
40
+ handleError(error) {
41
+ if (error instanceof Error) {
42
+ const message = error.message.toLowerCase();
43
+ if (message.includes("user-not-found") || message.includes("invalid-email")) {
44
+ return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "User not found", error);
45
+ }
46
+ if (message.includes("wrong-password") || message.includes("invalid-credential")) {
47
+ return createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid credentials", error);
48
+ }
49
+ if (message.includes("too-many-requests")) {
50
+ return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many attempts", error);
51
+ }
52
+ if (message.includes("user-disabled")) {
53
+ return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "Account disabled", error);
54
+ }
55
+ }
56
+ return createAuthError("SIGN_IN_FAILED" /* SIGN_IN_FAILED */, "Sign in failed", error);
57
+ }
58
+ };
59
+
60
+ // src/application/use-cases/auth/sign-up.use-case.ts
61
+ var SignUpUseCase = class {
62
+ constructor(authRepository, userRepository) {
63
+ this.authRepository = authRepository;
64
+ this.userRepository = userRepository;
65
+ }
66
+ /**
67
+ * Execute sign up use case
68
+ */
69
+ async execute(dto) {
70
+ try {
71
+ this.validateDTO(dto);
72
+ const existingUser = await this.userRepository.getUserByEmail(dto.email);
73
+ if (existingUser) {
74
+ throw createAuthError("USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */, "User already exists");
75
+ }
76
+ const result = await this.authRepository.signUp(dto.email, dto.password, dto.displayName);
77
+ return {
78
+ ...result,
79
+ userId: result.user.uid,
80
+ emailVerified: result.user.emailVerified
81
+ };
82
+ } catch (error) {
83
+ throw this.handleError(error);
84
+ }
85
+ }
86
+ /**
87
+ * Validate DTO
88
+ */
89
+ validateDTO(dto) {
90
+ if (!dto.email) {
91
+ throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Email is required");
92
+ }
93
+ if (!dto.password) {
94
+ throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Password is required");
95
+ }
96
+ if (!dto.displayName || dto.displayName.trim().length === 0) {
97
+ throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Display name is required");
98
+ }
99
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
100
+ if (!emailRegex.test(dto.email)) {
101
+ throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Invalid email format");
102
+ }
103
+ if (dto.password.length < 6) {
104
+ throw createAuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, "Password must be at least 6 characters");
105
+ }
106
+ }
107
+ /**
108
+ * Handle errors
109
+ */
110
+ handleError(error) {
111
+ if (error instanceof Error && "code" in error) {
112
+ const code = error.code;
113
+ if (code === "auth/email-already-in-use") {
114
+ return createAuthError("USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */, "Email already in use", error);
115
+ }
116
+ if (code === "auth/invalid-email") {
117
+ return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Invalid email", error);
118
+ }
119
+ if (code === "auth/weak-password") {
120
+ return createAuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, "Password is too weak", error);
121
+ }
122
+ if (code === "auth/operation-not-allowed") {
123
+ return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Email/password accounts not enabled", error);
124
+ }
125
+ }
126
+ return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Sign up failed", error);
127
+ }
128
+ };
129
+
130
+ // src/application/use-cases/auth/sign-in-with-google.use-case.ts
131
+ var SignInWithGoogleUseCase = class {
132
+ constructor(authRepository, userRepository) {
133
+ this.authRepository = authRepository;
134
+ this.userRepository = userRepository;
135
+ }
136
+ /**
137
+ * Execute Google sign in use case
138
+ */
139
+ async execute() {
140
+ try {
141
+ const result = await this.authRepository.signInWithGoogle();
142
+ const existingUser = await this.userRepository.getUser(result.user.uid);
143
+ if (!existingUser) {
144
+ const createUserDTO = {
145
+ id: result.user.uid,
146
+ email: result.user.email || "",
147
+ displayName: result.user.displayName || "",
148
+ photoURL: result.user.photoURL || void 0,
149
+ phoneNumber: result.user.phoneNumber || void 0,
150
+ emailVerified: result.user.emailVerified
151
+ };
152
+ await this.authRepository.createUserDocument(result.user.uid, createUserDTO);
153
+ }
154
+ return result;
155
+ } catch (error) {
156
+ throw this.handleError(error);
157
+ }
158
+ }
159
+ /**
160
+ * Handle errors
161
+ */
162
+ handleError(error) {
163
+ if (error instanceof Error && "code" in error) {
164
+ const code = error.code;
165
+ if (code === "auth/popup-closed-by-user") {
166
+ return createAuthError("OAUTH_CANCELLED" /* OAUTH_CANCELLED */, "Google sign in cancelled", error);
167
+ }
168
+ if (code === "auth/popup-blocked") {
169
+ return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Popup blocked by browser", error);
170
+ }
171
+ if (code === "auth/account-exists-with-different-credential") {
172
+ return createAuthError(
173
+ "OAUTH_ACCOUNT_EXISTS" /* OAUTH_ACCOUNT_EXISTS */,
174
+ "Account already exists with different credential",
175
+ error
176
+ );
177
+ }
178
+ if (code === "auth/auth-domain-policy-required") {
179
+ return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Auth domain not configured", error);
180
+ }
181
+ if (code === "auth/unauthorized-domain") {
182
+ return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Unauthorized domain", error);
183
+ }
184
+ if (code === "auth/cancelled-popup-request") {
185
+ return createAuthError("OAUTH_CANCELLED" /* OAUTH_CANCELLED */, "Sign in cancelled", error);
186
+ }
187
+ }
188
+ return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Google sign in failed", error);
189
+ }
190
+ };
191
+
192
+ // src/application/use-cases/auth/reset-password.use-case.ts
193
+ var ResetPasswordUseCase = class {
194
+ constructor(authRepository) {
195
+ this.authRepository = authRepository;
196
+ }
197
+ /**
198
+ * Execute password reset use case
199
+ */
200
+ async execute(dto) {
201
+ try {
202
+ this.validateDTO(dto);
203
+ await this.authRepository.sendPasswordReset(dto.email);
204
+ } catch (error) {
205
+ throw this.handleError(error);
206
+ }
207
+ }
208
+ /**
209
+ * Validate DTO
210
+ */
211
+ validateDTO(dto) {
212
+ if (!dto.email) {
213
+ throw createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Email is required");
214
+ }
215
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
216
+ if (!emailRegex.test(dto.email)) {
217
+ throw createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Invalid email format");
218
+ }
219
+ }
220
+ /**
221
+ * Handle errors
222
+ */
223
+ handleError(error) {
224
+ if (error instanceof Error && "code" in error) {
225
+ const code = error.code;
226
+ if (code === "auth/invalid-email") {
227
+ return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Invalid email", error);
228
+ }
229
+ if (code === "auth/user-not-found") {
230
+ return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Password reset email sent if account exists");
231
+ }
232
+ if (code === "auth/too-many-requests") {
233
+ return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many requests", error);
234
+ }
235
+ }
236
+ return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Password reset failed", error);
237
+ }
238
+ };
239
+
240
+ // src/application/use-cases/auth/sign-out.use-case.ts
241
+ var SignOutUseCase = class {
242
+ constructor(authRepository) {
243
+ this.authRepository = authRepository;
244
+ }
245
+ /**
246
+ * Execute sign out use case
247
+ */
248
+ async execute() {
249
+ try {
250
+ await this.authRepository.signOut();
251
+ } catch (error) {
252
+ throw createAuthError("SIGN_OUT_FAILED" /* SIGN_OUT_FAILED */, "Sign out failed", error);
253
+ }
254
+ }
255
+ };
256
+
257
+ // src/application/use-cases/user/update-profile.use-case.ts
258
+ var UpdateProfileUseCase = class {
259
+ constructor(authRepository) {
260
+ this.authRepository = authRepository;
261
+ }
262
+ /**
263
+ * Execute profile update use case
264
+ */
265
+ async execute(dto) {
266
+ try {
267
+ this.validateDTO(dto);
268
+ const currentUser = this.authRepository.getCurrentUser();
269
+ if (!currentUser) {
270
+ throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
271
+ }
272
+ await this.authRepository.updateProfile(dto);
273
+ } catch (error) {
274
+ throw this.handleError(error);
275
+ }
276
+ }
277
+ /**
278
+ * Validate DTO
279
+ */
280
+ validateDTO(dto) {
281
+ if (!dto.displayName && !dto.photoURL) {
282
+ throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "At least one field must be provided");
283
+ }
284
+ if (dto.displayName !== void 0) {
285
+ if (typeof dto.displayName !== "string") {
286
+ throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name must be a string");
287
+ }
288
+ if (dto.displayName.trim().length === 0) {
289
+ throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name cannot be empty");
290
+ }
291
+ if (dto.displayName.length > 100) {
292
+ throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name too long (max 100 characters)");
293
+ }
294
+ }
295
+ if (dto.photoURL !== void 0 && dto.photoURL !== null) {
296
+ if (typeof dto.photoURL !== "string") {
297
+ throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Photo URL must be a string");
298
+ }
299
+ if (dto.photoURL && !this.isValidURL(dto.photoURL)) {
300
+ throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Invalid photo URL");
301
+ }
302
+ }
303
+ }
304
+ /**
305
+ * Validate URL format
306
+ */
307
+ isValidURL(url) {
308
+ try {
309
+ new URL(url);
310
+ return true;
311
+ } catch {
312
+ return false;
313
+ }
314
+ }
315
+ /**
316
+ * Handle errors
317
+ */
318
+ handleError(error) {
319
+ if (error instanceof Error && "code" in error) {
320
+ const code = error.code;
321
+ if (code === "auth/requires-recent-login") {
322
+ return createAuthError("REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */, "Please reauthenticate first", error);
323
+ }
324
+ if (code === "auth/invalid-photo-url") {
325
+ return createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Invalid photo URL", error);
326
+ }
327
+ }
328
+ return createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Profile update failed", error);
329
+ }
330
+ };
331
+
332
+ // src/application/use-cases/user/delete-account.use-case.ts
333
+ var DeleteAccountUseCase = class {
334
+ constructor(authRepository) {
335
+ this.authRepository = authRepository;
336
+ }
337
+ /**
338
+ * Execute account deletion use case
339
+ */
340
+ async execute(dto) {
341
+ try {
342
+ this.validateDTO(dto);
343
+ const currentUser = this.authRepository.getCurrentUser();
344
+ if (!currentUser) {
345
+ throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
346
+ }
347
+ if (!currentUser.email) {
348
+ throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "User email not available");
349
+ }
350
+ await this.authRepository.deleteAccount(dto.password);
351
+ } catch (error) {
352
+ throw this.handleError(error);
353
+ }
354
+ }
355
+ /**
356
+ * Validate DTO
357
+ */
358
+ validateDTO(dto) {
359
+ if (!dto.password) {
360
+ throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Password is required");
361
+ }
362
+ if (dto.password.length < 1) {
363
+ throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Password cannot be empty");
364
+ }
365
+ }
366
+ /**
367
+ * Handle errors
368
+ */
369
+ handleError(error) {
370
+ if (error instanceof Error && "code" in error) {
371
+ const code = error.code;
372
+ if (code === "auth/requires-recent-login") {
373
+ return createAuthError("REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */, "Please reauthenticate first", error);
374
+ }
375
+ if (code === "auth/wrong-password") {
376
+ return createAuthError("REAUTHENTICATION_FAILED" /* REAUTHENTICATION_FAILED */, "Invalid password", error);
377
+ }
378
+ if (code === "auth/too-many-requests") {
379
+ return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many requests", error);
380
+ }
381
+ if (code === "auth/user-not-found") {
382
+ return createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "User not found", error);
383
+ }
384
+ }
385
+ return createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Account deletion failed", error);
386
+ }
387
+ };
388
+
389
+ export {
390
+ SignInUseCase,
391
+ SignUpUseCase,
392
+ SignInWithGoogleUseCase,
393
+ ResetPasswordUseCase,
394
+ SignOutUseCase,
395
+ UpdateProfileUseCase,
396
+ DeleteAccountUseCase
397
+ };