@umituz/web-firebase 2.1.1 → 3.0.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 (54) hide show
  1. package/package.json +12 -39
  2. package/src/domains/auth/entities/index.ts +60 -0
  3. package/src/domains/auth/index.ts +13 -0
  4. package/src/domains/auth/services/auth.service.ts +245 -0
  5. package/src/domains/auth/services/index.ts +7 -0
  6. package/src/domains/auth/types/auth-service.interface.ts +72 -0
  7. package/src/domains/auth/types/index.ts +5 -0
  8. package/src/domains/firestore/entities/index.ts +82 -0
  9. package/src/domains/firestore/index.ts +13 -0
  10. package/src/domains/firestore/services/firestore.service.ts +191 -0
  11. package/src/domains/firestore/services/index.ts +7 -0
  12. package/src/domains/firestore/types/firestore-service.interface.ts +64 -0
  13. package/src/domains/firestore/types/index.ts +5 -0
  14. package/src/domains/storage/entities/index.ts +94 -0
  15. package/src/domains/storage/index.ts +13 -0
  16. package/src/domains/storage/services/index.ts +7 -0
  17. package/src/domains/storage/services/storage.service.ts +223 -0
  18. package/src/domains/storage/types/index.ts +5 -0
  19. package/src/domains/storage/types/storage-service.interface.ts +120 -0
  20. package/src/index.ts +12 -16
  21. package/src/presentation/hooks/useAuth.ts +69 -26
  22. package/src/presentation/providers/FirebaseProvider.tsx +9 -14
  23. package/dist/application/index.d.mts +0 -273
  24. package/dist/application/index.d.ts +0 -273
  25. package/dist/application/index.js +0 -490
  26. package/dist/application/index.mjs +0 -19
  27. package/dist/chunk-34DL2QWQ.mjs +0 -87
  28. package/dist/chunk-4FP2ELQ5.mjs +0 -96
  29. package/dist/chunk-7TX3OU3O.mjs +0 -721
  30. package/dist/chunk-I6WGBPFB.mjs +0 -439
  31. package/dist/chunk-RZ4QR6TB.mjs +0 -96
  32. package/dist/chunk-U2XI4MGO.mjs +0 -397
  33. package/dist/domain/index.d.mts +0 -325
  34. package/dist/domain/index.d.ts +0 -325
  35. package/dist/domain/index.js +0 -662
  36. package/dist/domain/index.mjs +0 -36
  37. package/dist/file.repository.interface-v5vHgVsZ.d.mts +0 -241
  38. package/dist/file.repository.interface-v5vHgVsZ.d.ts +0 -241
  39. package/dist/firebase.entity-xvfEPjXZ.d.mts +0 -15
  40. package/dist/firebase.entity-xvfEPjXZ.d.ts +0 -15
  41. package/dist/index.d.mts +0 -14
  42. package/dist/index.d.ts +0 -14
  43. package/dist/index.js +0 -1833
  44. package/dist/index.mjs +0 -98
  45. package/dist/infrastructure/index.d.mts +0 -170
  46. package/dist/infrastructure/index.d.ts +0 -170
  47. package/dist/infrastructure/index.js +0 -856
  48. package/dist/infrastructure/index.mjs +0 -46
  49. package/dist/presentation/index.d.mts +0 -25
  50. package/dist/presentation/index.d.ts +0 -25
  51. package/dist/presentation/index.js +0 -105
  52. package/dist/presentation/index.mjs +0 -6
  53. package/dist/user.repository.interface-DS74TsJ5.d.mts +0 -298
  54. package/dist/user.repository.interface-DS74TsJ5.d.ts +0 -298
package/dist/index.js DELETED
@@ -1,1833 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- AuthAdapter: () => AuthAdapter,
24
- AuthError: () => AuthError,
25
- AuthErrorCode: () => AuthErrorCode,
26
- DeleteAccountUseCase: () => DeleteAccountUseCase,
27
- Email: () => Email,
28
- FileErrorCode: () => FileErrorCode,
29
- FilePath: () => FilePath,
30
- FirestoreAdapter: () => FirestoreAdapter,
31
- RepositoryError: () => RepositoryError,
32
- RepositoryErrorCode: () => RepositoryErrorCode,
33
- ResetPasswordUseCase: () => ResetPasswordUseCase,
34
- SignInUseCase: () => SignInUseCase,
35
- SignInWithGoogleUseCase: () => SignInWithGoogleUseCase,
36
- SignOutUseCase: () => SignOutUseCase,
37
- SignUpUseCase: () => SignUpUseCase,
38
- StorageAdapter: () => StorageAdapter,
39
- Timestamp: () => Timestamp,
40
- USER_COLLECTIONS: () => USER_COLLECTIONS,
41
- USER_SUBCOLLECTIONS: () => USER_SUBCOLLECTIONS,
42
- UpdateProfileUseCase: () => UpdateProfileUseCase,
43
- UserId: () => UserId,
44
- analytics: () => analytics,
45
- app: () => app,
46
- auth: () => auth,
47
- createAuthError: () => createAuthError,
48
- createRepositoryError: () => createRepositoryError,
49
- db: () => db,
50
- deleteFile: () => deleteFile,
51
- functions: () => functions,
52
- getFirebaseAnalytics: () => getFirebaseAnalytics,
53
- getFirebaseApp: () => getFirebaseApp,
54
- getFirebaseAuth: () => getFirebaseAuth,
55
- getFirebaseDB: () => getFirebaseDB,
56
- getFirebaseFunctions: () => getFirebaseFunctions,
57
- getFirebaseInstances: () => getFirebaseInstances,
58
- getFirebaseStorage: () => getFirebaseStorage,
59
- initializeFirebase: () => initializeFirebase,
60
- serverTimestamp: () => serverTimestamp,
61
- storage: () => storage,
62
- uploadBase64: () => uploadBase64,
63
- uploadFile: () => uploadFile,
64
- useFirebaseAuth: () => useFirebaseAuth
65
- });
66
- module.exports = __toCommonJS(index_exports);
67
-
68
- // src/domain/entities/user.entity.ts
69
- var USER_COLLECTIONS = {
70
- USERS: "users",
71
- CONTENT: "content",
72
- ANALYTICS: "analytics",
73
- CONNECTED_ACCOUNTS: "connectedAccounts"
74
- };
75
- var USER_SUBCOLLECTIONS = {
76
- CONTENT: "content",
77
- ANALYTICS: "analytics",
78
- SCHEDULED: "scheduled",
79
- PUBLISHED: "published",
80
- DRAFTS: "drafts"
81
- };
82
-
83
- // src/domain/entities/file.entity.ts
84
- var FileErrorCode = /* @__PURE__ */ ((FileErrorCode2) => {
85
- FileErrorCode2["FILE_TOO_LARGE"] = "FILE_TOO_LARGE";
86
- FileErrorCode2["INVALID_TYPE"] = "INVALID_TYPE";
87
- FileErrorCode2["INVALID_EXTENSION"] = "INVALID_EXTENSION";
88
- FileErrorCode2["UPLOAD_FAILED"] = "UPLOAD_FAILED";
89
- FileErrorCode2["DOWNLOAD_FAILED"] = "DOWNLOAD_FAILED";
90
- FileErrorCode2["DELETE_FAILED"] = "DELETE_FAILED";
91
- FileErrorCode2["FILE_NOT_FOUND"] = "FILE_NOT_FOUND";
92
- FileErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
93
- FileErrorCode2["CANCELLED"] = "CANCELLED";
94
- return FileErrorCode2;
95
- })(FileErrorCode || {});
96
-
97
- // src/domain/entities/timestamp.entity.ts
98
- var Timestamp = class _Timestamp {
99
- constructor(seconds, nanoseconds) {
100
- this.seconds = seconds;
101
- this.nanoseconds = nanoseconds;
102
- }
103
- /**
104
- * Create Timestamp from JavaScript Date
105
- */
106
- static fromDate(date) {
107
- const milliseconds = date.getTime();
108
- const seconds = Math.floor(milliseconds / 1e3);
109
- const nanoseconds = milliseconds % 1e3 * 1e6;
110
- return new _Timestamp(seconds, nanoseconds);
111
- }
112
- /**
113
- * Create Timestamp from milliseconds
114
- */
115
- static fromMillis(milliseconds) {
116
- const seconds = Math.floor(milliseconds / 1e3);
117
- const nanoseconds = milliseconds % 1e3 * 1e6;
118
- return new _Timestamp(seconds, nanoseconds);
119
- }
120
- /**
121
- * Create Timestamp from Firestore Timestamp
122
- */
123
- static fromFirestoreTimestamp(timestamp) {
124
- return new _Timestamp(timestamp.seconds, timestamp.nanoseconds);
125
- }
126
- /**
127
- * Get current timestamp
128
- */
129
- static now() {
130
- return _Timestamp.fromDate(/* @__PURE__ */ new Date());
131
- }
132
- /**
133
- * Convert to JavaScript Date
134
- */
135
- toDate() {
136
- return new Date(this.seconds * 1e3 + this.nanoseconds / 1e6);
137
- }
138
- /**
139
- * Convert to milliseconds
140
- */
141
- toMillis() {
142
- return this.seconds * 1e3 + this.nanoseconds / 1e6;
143
- }
144
- /**
145
- * Convert to Firestore Timestamp
146
- */
147
- toFirestoreTimestamp() {
148
- return {
149
- seconds: this.seconds,
150
- nanoseconds: this.nanoseconds
151
- };
152
- }
153
- /**
154
- * Convert to ISO string
155
- */
156
- toISOString() {
157
- return this.toDate().toISOString();
158
- }
159
- /**
160
- * Check if timestamp is in the past
161
- */
162
- isPast() {
163
- return this.toMillis() < Date.now();
164
- }
165
- /**
166
- * Check if timestamp is in the future
167
- */
168
- isFuture() {
169
- return this.toMillis() > Date.now();
170
- }
171
- /**
172
- * Get difference in milliseconds with another timestamp
173
- */
174
- diff(other) {
175
- return this.toMillis() - other.toMillis();
176
- }
177
- };
178
- var serverTimestamp = {
179
- __type__: "serverTimestamp"
180
- };
181
-
182
- // src/domain/value-objects/email.vo.ts
183
- var Email = class _Email {
184
- value;
185
- validated;
186
- constructor(email) {
187
- this.value = email.trim().toLowerCase();
188
- this.validated = this.isValid();
189
- if (!this.validated) {
190
- throw new Error(`Invalid email address: ${email}`);
191
- }
192
- }
193
- /**
194
- * Validate email format
195
- */
196
- isValid() {
197
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
198
- return emailRegex.test(this.value);
199
- }
200
- /**
201
- * Get email value
202
- */
203
- getValue() {
204
- return this.value;
205
- }
206
- /**
207
- * Get local part (before @)
208
- */
209
- getLocalPart() {
210
- return this.value.split("@")[0];
211
- }
212
- /**
213
- * Get domain part (after @)
214
- */
215
- getDomain() {
216
- return this.value.split("@")[1] || "";
217
- }
218
- /**
219
- * Check if email is from a specific domain
220
- */
221
- isFromDomain(domain) {
222
- return this.getDomain() === domain.toLowerCase();
223
- }
224
- /**
225
- * Check if email is from a corporate domain (not gmail, yahoo, etc.)
226
- */
227
- isCorporate() {
228
- const freeDomains = [
229
- "gmail.com",
230
- "yahoo.com",
231
- "hotmail.com",
232
- "outlook.com",
233
- "aol.com",
234
- "icloud.com",
235
- "protonmail.com"
236
- ];
237
- return !freeDomains.includes(this.getDomain());
238
- }
239
- /**
240
- * Mask email for display (e.g., u***@gmail.com)
241
- */
242
- mask() {
243
- const [local, domain] = this.value.split("@");
244
- if (local.length <= 2) {
245
- return `${local[0]}***@${domain}`;
246
- }
247
- return `${local[0]}${"*".repeat(local.length - 2)}${local[local.length - 1]}@${domain}`;
248
- }
249
- /**
250
- * Convert to string
251
- */
252
- toString() {
253
- return this.value;
254
- }
255
- /**
256
- * Check equality with another email
257
- */
258
- equals(other) {
259
- return this.value === other.value;
260
- }
261
- /**
262
- * Create Email from string (returns null if invalid)
263
- */
264
- static create(email) {
265
- try {
266
- return new _Email(email);
267
- } catch {
268
- return null;
269
- }
270
- }
271
- };
272
-
273
- // src/domain/errors/repository.errors.ts
274
- var RepositoryError = class extends Error {
275
- constructor(message, code, originalError) {
276
- super(message);
277
- this.code = code;
278
- this.originalError = originalError;
279
- this.name = "RepositoryError";
280
- }
281
- };
282
- var RepositoryErrorCode = /* @__PURE__ */ ((RepositoryErrorCode2) => {
283
- RepositoryErrorCode2["DOCUMENT_NOT_FOUND"] = "DOCUMENT_NOT_FOUND";
284
- RepositoryErrorCode2["DOCUMENT_ALREADY_EXISTS"] = "DOCUMENT_ALREADY_EXISTS";
285
- RepositoryErrorCode2["DOCUMENT_INVALID"] = "DOCUMENT_INVALID";
286
- RepositoryErrorCode2["COLLECTION_NOT_FOUND"] = "COLLECTION_NOT_FOUND";
287
- RepositoryErrorCode2["COLLECTION_INVALID"] = "COLLECTION_INVALID";
288
- RepositoryErrorCode2["QUERY_INVALID"] = "QUERY_INVALID";
289
- RepositoryErrorCode2["QUERY_FAILED"] = "QUERY_FAILED";
290
- RepositoryErrorCode2["TRANSACTION_FAILED"] = "TRANSACTION_FAILED";
291
- RepositoryErrorCode2["TRANSACTION_ABORTED"] = "TRANSACTION_ABORTED";
292
- RepositoryErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
293
- RepositoryErrorCode2["TIMEOUT"] = "TIMEOUT";
294
- RepositoryErrorCode2["OFFLINE"] = "OFFLINE";
295
- RepositoryErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
296
- RepositoryErrorCode2["UNAUTHORIZED"] = "UNAUTHORIZED";
297
- RepositoryErrorCode2["VALIDATION_FAILED"] = "VALIDATION_FAILED";
298
- RepositoryErrorCode2["INVALID_DATA"] = "INVALID_DATA";
299
- RepositoryErrorCode2["CONFLICT"] = "CONFLICT";
300
- RepositoryErrorCode2["VERSION_MISMATCH"] = "VERSION_MISMATCH";
301
- RepositoryErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
302
- RepositoryErrorCode2["FILE_NOT_FOUND"] = "FILE_NOT_FOUND";
303
- RepositoryErrorCode2["FILE_TOO_LARGE"] = "FILE_TOO_LARGE";
304
- RepositoryErrorCode2["INVALID_FILE_TYPE"] = "INVALID_FILE_TYPE";
305
- RepositoryErrorCode2["UNKNOWN"] = "UNKNOWN";
306
- return RepositoryErrorCode2;
307
- })(RepositoryErrorCode || {});
308
- function createRepositoryError(code, message, originalError) {
309
- const defaultMessage = getRepositoryErrorMessage(code);
310
- return new RepositoryError(message || defaultMessage, code, originalError);
311
- }
312
- function getRepositoryErrorMessage(code) {
313
- switch (code) {
314
- case "DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */:
315
- return "Document not found";
316
- case "DOCUMENT_ALREADY_EXISTS" /* DOCUMENT_ALREADY_EXISTS */:
317
- return "Document already exists";
318
- case "DOCUMENT_INVALID" /* DOCUMENT_INVALID */:
319
- return "Document is invalid";
320
- case "COLLECTION_NOT_FOUND" /* COLLECTION_NOT_FOUND */:
321
- return "Collection not found";
322
- case "COLLECTION_INVALID" /* COLLECTION_INVALID */:
323
- return "Collection is invalid";
324
- case "QUERY_INVALID" /* QUERY_INVALID */:
325
- return "Query is invalid";
326
- case "QUERY_FAILED" /* QUERY_FAILED */:
327
- return "Query failed";
328
- case "TRANSACTION_FAILED" /* TRANSACTION_FAILED */:
329
- return "Transaction failed";
330
- case "TRANSACTION_ABORTED" /* TRANSACTION_ABORTED */:
331
- return "Transaction aborted";
332
- case "NETWORK_ERROR" /* NETWORK_ERROR */:
333
- return "Network error";
334
- case "TIMEOUT" /* TIMEOUT */:
335
- return "Request timeout";
336
- case "OFFLINE" /* OFFLINE */:
337
- return "Client is offline";
338
- case "PERMISSION_DENIED" /* PERMISSION_DENIED */:
339
- return "Permission denied";
340
- case "UNAUTHORIZED" /* UNAUTHORIZED */:
341
- return "Unauthorized";
342
- case "VALIDATION_FAILED" /* VALIDATION_FAILED */:
343
- return "Validation failed";
344
- case "INVALID_DATA" /* INVALID_DATA */:
345
- return "Invalid data";
346
- case "CONFLICT" /* CONFLICT */:
347
- return "Conflict occurred";
348
- case "VERSION_MISMATCH" /* VERSION_MISMATCH */:
349
- return "Version mismatch";
350
- case "STORAGE_ERROR" /* STORAGE_ERROR */:
351
- return "Storage error";
352
- case "FILE_NOT_FOUND" /* FILE_NOT_FOUND */:
353
- return "File not found";
354
- case "FILE_TOO_LARGE" /* FILE_TOO_LARGE */:
355
- return "File is too large";
356
- case "INVALID_FILE_TYPE" /* INVALID_FILE_TYPE */:
357
- return "Invalid file type";
358
- case "UNKNOWN" /* UNKNOWN */:
359
- default:
360
- return "An unknown error occurred";
361
- }
362
- }
363
-
364
- // src/domain/value-objects/user-id.vo.ts
365
- var UserId = class _UserId {
366
- value;
367
- constructor(id) {
368
- this.value = id;
369
- this.validate();
370
- }
371
- /**
372
- * Validate user ID
373
- */
374
- validate() {
375
- if (!this.value) {
376
- throw createRepositoryError("INVALID_DATA" /* INVALID_DATA */, "User ID cannot be empty");
377
- }
378
- if (this.value.length < 20) {
379
- throw createRepositoryError(
380
- "INVALID_DATA" /* INVALID_DATA */,
381
- "User ID is too short (must be at least 20 characters)"
382
- );
383
- }
384
- const validPattern = /^[a-zA-Z0-9_-]+$/;
385
- if (!validPattern.test(this.value)) {
386
- throw createRepositoryError(
387
- "INVALID_DATA" /* INVALID_DATA */,
388
- "User ID contains invalid characters"
389
- );
390
- }
391
- }
392
- /**
393
- * Get user ID value
394
- */
395
- getValue() {
396
- return this.value;
397
- }
398
- /**
399
- * Check if this is a temporary ID (not yet persisted)
400
- */
401
- isTemporary() {
402
- return this.value.startsWith("temp_");
403
- }
404
- /**
405
- * Convert to string
406
- */
407
- toString() {
408
- return this.value;
409
- }
410
- /**
411
- * Check equality with another user ID
412
- */
413
- equals(other) {
414
- return this.value === other.value;
415
- }
416
- /**
417
- * Generate a temporary user ID
418
- */
419
- static generateTemp() {
420
- return new _UserId(`temp_${Date.now()}_${Math.random().toString(36).substring(7)}`);
421
- }
422
- /**
423
- * Create UserId from string (returns null if invalid)
424
- */
425
- static create(id) {
426
- try {
427
- return new _UserId(id);
428
- } catch {
429
- return null;
430
- }
431
- }
432
- };
433
-
434
- // src/domain/value-objects/file-path.vo.ts
435
- var FilePath = class _FilePath {
436
- value;
437
- parts;
438
- constructor(path) {
439
- this.value = path.trim();
440
- this.parts = this.value.split("/").filter((p) => p.length > 0);
441
- this.validate();
442
- }
443
- /**
444
- * Validate file path
445
- */
446
- validate() {
447
- if (!this.value) {
448
- throw createRepositoryError("INVALID_DATA" /* INVALID_DATA */, "File path cannot be empty");
449
- }
450
- if (this.value.startsWith("/") || this.value.endsWith("/")) {
451
- throw createRepositoryError(
452
- "INVALID_DATA" /* INVALID_DATA */,
453
- "File path should not start or end with /"
454
- );
455
- }
456
- if (this.value.includes("//")) {
457
- throw createRepositoryError("INVALID_DATA" /* INVALID_DATA */, "File path should not contain //");
458
- }
459
- if (this.parts.length === 0) {
460
- throw createRepositoryError("INVALID_DATA" /* INVALID_DATA */, "File path must have at least one segment");
461
- }
462
- for (const part of this.parts) {
463
- if (/[<>:"|?*]/.test(part)) {
464
- throw createRepositoryError(
465
- "INVALID_DATA" /* INVALID_DATA */,
466
- `Invalid characters in path segment: ${part}`
467
- );
468
- }
469
- if (part === "." || part === "..") {
470
- throw createRepositoryError(
471
- "INVALID_DATA" /* INVALID_DATA */,
472
- `Invalid path segment: ${part}`
473
- );
474
- }
475
- }
476
- }
477
- /**
478
- * Get file path value
479
- */
480
- getValue() {
481
- return this.value;
482
- }
483
- /**
484
- * Get path parts
485
- */
486
- getParts() {
487
- return [...this.parts];
488
- }
489
- /**
490
- * Get filename (last part of path)
491
- */
492
- getFileName() {
493
- return this.parts[this.parts.length - 1] || "";
494
- }
495
- /**
496
- * Get directory path (all parts except last)
497
- */
498
- getDirectory() {
499
- return this.parts.slice(0, -1).join("/");
500
- }
501
- /**
502
- * Get file extension
503
- */
504
- getExtension() {
505
- const fileName = this.getFileName();
506
- const lastDot = fileName.lastIndexOf(".");
507
- return lastDot > 0 ? fileName.substring(lastDot + 1) : "";
508
- }
509
- /**
510
- * Get file name without extension
511
- */
512
- getFileNameWithoutExtension() {
513
- const fileName = this.getFileName();
514
- const lastDot = fileName.lastIndexOf(".");
515
- return lastDot > 0 ? fileName.substring(0, lastDot) : fileName;
516
- }
517
- /**
518
- * Check if path is in a specific directory
519
- */
520
- isInDirectory(directory) {
521
- return this.value.startsWith(directory + "/");
522
- }
523
- /**
524
- * Check if file has a specific extension
525
- */
526
- hasExtension(extension) {
527
- return this.getExtension().toLowerCase() === extension.toLowerCase();
528
- }
529
- /**
530
- * Create a new path by appending segments
531
- */
532
- append(...segments) {
533
- return new _FilePath([...this.parts, ...segments].join("/"));
534
- }
535
- /**
536
- * Create a new path in a parent directory
537
- */
538
- withParent(parent) {
539
- return new _FilePath([parent, ...this.parts].join("/"));
540
- }
541
- /**
542
- * Create a new path with a different filename
543
- */
544
- withFileName(fileName) {
545
- const dir = this.getDirectory();
546
- return dir ? new _FilePath(`${dir}/${fileName}`) : new _FilePath(fileName);
547
- }
548
- /**
549
- * Convert to string
550
- */
551
- toString() {
552
- return this.value;
553
- }
554
- /**
555
- * Check equality with another file path
556
- */
557
- equals(other) {
558
- return this.value === other.value;
559
- }
560
- /**
561
- * Create user path (users/{userId}/...)
562
- */
563
- static userPath(userId, ...segments) {
564
- return new _FilePath(["users", userId, ...segments].join("/"));
565
- }
566
- /**
567
- * Create public path (public/...)
568
- */
569
- static publicPath(...segments) {
570
- return new _FilePath(["public", ...segments].join("/"));
571
- }
572
- /**
573
- * Create FilePath from string (returns null if invalid)
574
- */
575
- static create(path) {
576
- try {
577
- return new _FilePath(path);
578
- } catch {
579
- return null;
580
- }
581
- }
582
- };
583
-
584
- // src/domain/errors/auth.errors.ts
585
- var AuthError = class extends Error {
586
- constructor(message, code, originalError) {
587
- super(message);
588
- this.code = code;
589
- this.originalError = originalError;
590
- this.name = "AuthError";
591
- }
592
- };
593
- var AuthErrorCode = /* @__PURE__ */ ((AuthErrorCode2) => {
594
- AuthErrorCode2["USER_NOT_FOUND"] = "USER_NOT_FOUND";
595
- AuthErrorCode2["USER_ALREADY_EXISTS"] = "USER_ALREADY_EXISTS";
596
- AuthErrorCode2["INVALID_CREDENTIALS"] = "INVALID_CREDENTIALS";
597
- AuthErrorCode2["WEAK_PASSWORD"] = "WEAK_PASSWORD";
598
- AuthErrorCode2["EMAIL_NOT_VERIFIED"] = "EMAIL_NOT_VERIFIED";
599
- AuthErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
600
- AuthErrorCode2["UNAUTHENTICATED"] = "UNAUTHENTICATED";
601
- AuthErrorCode2["TOO_MANY_REQUESTS"] = "TOO_MANY_REQUESTS";
602
- AuthErrorCode2["OAUTH_ERROR"] = "OAUTH_ERROR";
603
- AuthErrorCode2["OAUTH_CANCELLED"] = "OAUTH_CANCELLED";
604
- AuthErrorCode2["OAUTH_ACCOUNT_EXISTS"] = "OAUTH_ACCOUNT_EXISTS";
605
- AuthErrorCode2["SIGN_IN_FAILED"] = "SIGN_IN_FAILED";
606
- AuthErrorCode2["SIGN_UP_FAILED"] = "SIGN_UP_FAILED";
607
- AuthErrorCode2["SIGN_OUT_FAILED"] = "SIGN_OUT_FAILED";
608
- AuthErrorCode2["PASSWORD_RESET_FAILED"] = "PASSWORD_RESET_FAILED";
609
- AuthErrorCode2["EMAIL_VERIFICATION_FAILED"] = "EMAIL_VERIFICATION_FAILED";
610
- AuthErrorCode2["PROFILE_UPDATE_FAILED"] = "PROFILE_UPDATE_FAILED";
611
- AuthErrorCode2["EMAIL_UPDATE_FAILED"] = "EMAIL_UPDATE_FAILED";
612
- AuthErrorCode2["PASSWORD_UPDATE_FAILED"] = "PASSWORD_UPDATE_FAILED";
613
- AuthErrorCode2["ACCOUNT_DELETE_FAILED"] = "ACCOUNT_DELETE_FAILED";
614
- AuthErrorCode2["REAUTHENTICATION_REQUIRED"] = "REAUTHENTICATION_REQUIRED";
615
- AuthErrorCode2["REAUTHENTICATION_FAILED"] = "REAUTHENTICATION_FAILED";
616
- AuthErrorCode2["UNKNOWN"] = "UNKNOWN";
617
- return AuthErrorCode2;
618
- })(AuthErrorCode || {});
619
- function createAuthError(code, message, originalError) {
620
- const defaultMessage = getAuthErrorMessage(code);
621
- return new AuthError(message || defaultMessage, code, originalError);
622
- }
623
- function getAuthErrorMessage(code) {
624
- switch (code) {
625
- case "USER_NOT_FOUND" /* USER_NOT_FOUND */:
626
- return "User not found";
627
- case "USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */:
628
- return "User already exists";
629
- case "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */:
630
- return "Invalid credentials";
631
- case "WEAK_PASSWORD" /* WEAK_PASSWORD */:
632
- return "Password is too weak";
633
- case "EMAIL_NOT_VERIFIED" /* EMAIL_NOT_VERIFIED */:
634
- return "Email not verified";
635
- case "SESSION_EXPIRED" /* SESSION_EXPIRED */:
636
- return "Session expired";
637
- case "UNAUTHENTICATED" /* UNAUTHENTICATED */:
638
- return "User not authenticated";
639
- case "TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */:
640
- return "Too many requests";
641
- case "OAUTH_ERROR" /* OAUTH_ERROR */:
642
- return "OAuth error occurred";
643
- case "OAUTH_CANCELLED" /* OAUTH_CANCELLED */:
644
- return "OAuth cancelled by user";
645
- case "OAUTH_ACCOUNT_EXISTS" /* OAUTH_ACCOUNT_EXISTS */:
646
- return "Account already exists with this provider";
647
- case "SIGN_IN_FAILED" /* SIGN_IN_FAILED */:
648
- return "Sign in failed";
649
- case "SIGN_UP_FAILED" /* SIGN_UP_FAILED */:
650
- return "Sign up failed";
651
- case "SIGN_OUT_FAILED" /* SIGN_OUT_FAILED */:
652
- return "Sign out failed";
653
- case "PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */:
654
- return "Password reset failed";
655
- case "EMAIL_VERIFICATION_FAILED" /* EMAIL_VERIFICATION_FAILED */:
656
- return "Email verification failed";
657
- case "PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */:
658
- return "Profile update failed";
659
- case "EMAIL_UPDATE_FAILED" /* EMAIL_UPDATE_FAILED */:
660
- return "Email update failed";
661
- case "PASSWORD_UPDATE_FAILED" /* PASSWORD_UPDATE_FAILED */:
662
- return "Password update failed";
663
- case "ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */:
664
- return "Account deletion failed";
665
- case "REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */:
666
- return "Reauthentication required";
667
- case "REAUTHENTICATION_FAILED" /* REAUTHENTICATION_FAILED */:
668
- return "Reauthentication failed";
669
- case "UNKNOWN" /* UNKNOWN */:
670
- default:
671
- return "An unknown error occurred";
672
- }
673
- }
674
-
675
- // src/application/use-cases/auth/sign-in.use-case.ts
676
- var SignInUseCase = class {
677
- constructor(authRepository) {
678
- this.authRepository = authRepository;
679
- }
680
- /**
681
- * Execute sign in use case
682
- */
683
- async execute(dto) {
684
- try {
685
- this.validateDTO(dto);
686
- const result = await this.authRepository.signIn(dto.email, dto.password);
687
- return result;
688
- } catch (error) {
689
- throw this.handleError(error);
690
- }
691
- }
692
- /**
693
- * Validate DTO
694
- */
695
- validateDTO(dto) {
696
- if (!dto.email) {
697
- throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Email is required");
698
- }
699
- if (!dto.password) {
700
- throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Password is required");
701
- }
702
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
703
- if (!emailRegex.test(dto.email)) {
704
- throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid email format");
705
- }
706
- }
707
- /**
708
- * Handle errors
709
- */
710
- handleError(error) {
711
- if (error instanceof Error) {
712
- const message = error.message.toLowerCase();
713
- if (message.includes("user-not-found") || message.includes("invalid-email")) {
714
- return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "User not found", error);
715
- }
716
- if (message.includes("wrong-password") || message.includes("invalid-credential")) {
717
- return createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid credentials", error);
718
- }
719
- if (message.includes("too-many-requests")) {
720
- return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many attempts", error);
721
- }
722
- if (message.includes("user-disabled")) {
723
- return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "Account disabled", error);
724
- }
725
- }
726
- return createAuthError("SIGN_IN_FAILED" /* SIGN_IN_FAILED */, "Sign in failed", error);
727
- }
728
- };
729
-
730
- // src/application/use-cases/auth/sign-up.use-case.ts
731
- var SignUpUseCase = class {
732
- constructor(authRepository, userRepository) {
733
- this.authRepository = authRepository;
734
- this.userRepository = userRepository;
735
- }
736
- /**
737
- * Execute sign up use case
738
- */
739
- async execute(dto) {
740
- try {
741
- this.validateDTO(dto);
742
- const existingUser = await this.userRepository.getUserByEmail(dto.email);
743
- if (existingUser) {
744
- throw createAuthError("USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */, "User already exists");
745
- }
746
- const result = await this.authRepository.signUp(dto.email, dto.password, dto.displayName);
747
- return {
748
- ...result,
749
- userId: result.user.uid,
750
- emailVerified: result.user.emailVerified
751
- };
752
- } catch (error) {
753
- throw this.handleError(error);
754
- }
755
- }
756
- /**
757
- * Validate DTO
758
- */
759
- validateDTO(dto) {
760
- if (!dto.email) {
761
- throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Email is required");
762
- }
763
- if (!dto.password) {
764
- throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Password is required");
765
- }
766
- if (!dto.displayName || dto.displayName.trim().length === 0) {
767
- throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Display name is required");
768
- }
769
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
770
- if (!emailRegex.test(dto.email)) {
771
- throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Invalid email format");
772
- }
773
- if (dto.password.length < 6) {
774
- throw createAuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, "Password must be at least 6 characters");
775
- }
776
- }
777
- /**
778
- * Handle errors
779
- */
780
- handleError(error) {
781
- if (error instanceof Error && "code" in error) {
782
- const code = error.code;
783
- if (code === "auth/email-already-in-use") {
784
- return createAuthError("USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */, "Email already in use", error);
785
- }
786
- if (code === "auth/invalid-email") {
787
- return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Invalid email", error);
788
- }
789
- if (code === "auth/weak-password") {
790
- return createAuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, "Password is too weak", error);
791
- }
792
- if (code === "auth/operation-not-allowed") {
793
- return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Email/password accounts not enabled", error);
794
- }
795
- }
796
- return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Sign up failed", error);
797
- }
798
- };
799
-
800
- // src/application/use-cases/auth/sign-in-with-google.use-case.ts
801
- var SignInWithGoogleUseCase = class {
802
- constructor(authRepository, userRepository) {
803
- this.authRepository = authRepository;
804
- this.userRepository = userRepository;
805
- }
806
- /**
807
- * Execute Google sign in use case
808
- */
809
- async execute() {
810
- try {
811
- const result = await this.authRepository.signInWithGoogle();
812
- const existingUser = await this.userRepository.getUser(result.user.uid);
813
- if (!existingUser) {
814
- const createUserDTO = {
815
- id: result.user.uid,
816
- email: result.user.email || "",
817
- displayName: result.user.displayName || "",
818
- photoURL: result.user.photoURL || void 0,
819
- phoneNumber: result.user.phoneNumber || void 0,
820
- emailVerified: result.user.emailVerified
821
- };
822
- await this.authRepository.createUserDocument(result.user.uid, createUserDTO);
823
- }
824
- return result;
825
- } catch (error) {
826
- throw this.handleError(error);
827
- }
828
- }
829
- /**
830
- * Handle errors
831
- */
832
- handleError(error) {
833
- if (error instanceof Error && "code" in error) {
834
- const code = error.code;
835
- if (code === "auth/popup-closed-by-user") {
836
- return createAuthError("OAUTH_CANCELLED" /* OAUTH_CANCELLED */, "Google sign in cancelled", error);
837
- }
838
- if (code === "auth/popup-blocked") {
839
- return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Popup blocked by browser", error);
840
- }
841
- if (code === "auth/account-exists-with-different-credential") {
842
- return createAuthError(
843
- "OAUTH_ACCOUNT_EXISTS" /* OAUTH_ACCOUNT_EXISTS */,
844
- "Account already exists with different credential",
845
- error
846
- );
847
- }
848
- if (code === "auth/auth-domain-policy-required") {
849
- return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Auth domain not configured", error);
850
- }
851
- if (code === "auth/unauthorized-domain") {
852
- return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Unauthorized domain", error);
853
- }
854
- if (code === "auth/cancelled-popup-request") {
855
- return createAuthError("OAUTH_CANCELLED" /* OAUTH_CANCELLED */, "Sign in cancelled", error);
856
- }
857
- }
858
- return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Google sign in failed", error);
859
- }
860
- };
861
-
862
- // src/application/use-cases/auth/reset-password.use-case.ts
863
- var ResetPasswordUseCase = class {
864
- constructor(authRepository) {
865
- this.authRepository = authRepository;
866
- }
867
- /**
868
- * Execute password reset use case
869
- */
870
- async execute(dto) {
871
- try {
872
- this.validateDTO(dto);
873
- await this.authRepository.sendPasswordReset(dto.email);
874
- } catch (error) {
875
- throw this.handleError(error);
876
- }
877
- }
878
- /**
879
- * Validate DTO
880
- */
881
- validateDTO(dto) {
882
- if (!dto.email) {
883
- throw createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Email is required");
884
- }
885
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
886
- if (!emailRegex.test(dto.email)) {
887
- throw createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Invalid email format");
888
- }
889
- }
890
- /**
891
- * Handle errors
892
- */
893
- handleError(error) {
894
- if (error instanceof Error && "code" in error) {
895
- const code = error.code;
896
- if (code === "auth/invalid-email") {
897
- return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Invalid email", error);
898
- }
899
- if (code === "auth/user-not-found") {
900
- return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Password reset email sent if account exists");
901
- }
902
- if (code === "auth/too-many-requests") {
903
- return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many requests", error);
904
- }
905
- }
906
- return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Password reset failed", error);
907
- }
908
- };
909
-
910
- // src/application/use-cases/auth/sign-out.use-case.ts
911
- var SignOutUseCase = class {
912
- constructor(authRepository) {
913
- this.authRepository = authRepository;
914
- }
915
- /**
916
- * Execute sign out use case
917
- */
918
- async execute() {
919
- try {
920
- await this.authRepository.signOut();
921
- } catch (error) {
922
- throw createAuthError("SIGN_OUT_FAILED" /* SIGN_OUT_FAILED */, "Sign out failed", error);
923
- }
924
- }
925
- };
926
-
927
- // src/application/use-cases/user/update-profile.use-case.ts
928
- var UpdateProfileUseCase = class {
929
- constructor(authRepository) {
930
- this.authRepository = authRepository;
931
- }
932
- /**
933
- * Execute profile update use case
934
- */
935
- async execute(dto) {
936
- try {
937
- this.validateDTO(dto);
938
- const currentUser = this.authRepository.getCurrentUser();
939
- if (!currentUser) {
940
- throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
941
- }
942
- await this.authRepository.updateProfile(dto);
943
- } catch (error) {
944
- throw this.handleError(error);
945
- }
946
- }
947
- /**
948
- * Validate DTO
949
- */
950
- validateDTO(dto) {
951
- if (!dto.displayName && !dto.photoURL) {
952
- throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "At least one field must be provided");
953
- }
954
- if (dto.displayName !== void 0) {
955
- if (typeof dto.displayName !== "string") {
956
- throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name must be a string");
957
- }
958
- if (dto.displayName.trim().length === 0) {
959
- throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name cannot be empty");
960
- }
961
- if (dto.displayName.length > 100) {
962
- throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name too long (max 100 characters)");
963
- }
964
- }
965
- if (dto.photoURL !== void 0 && dto.photoURL !== null) {
966
- if (typeof dto.photoURL !== "string") {
967
- throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Photo URL must be a string");
968
- }
969
- if (dto.photoURL && !this.isValidURL(dto.photoURL)) {
970
- throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Invalid photo URL");
971
- }
972
- }
973
- }
974
- /**
975
- * Validate URL format
976
- */
977
- isValidURL(url) {
978
- try {
979
- new URL(url);
980
- return true;
981
- } catch {
982
- return false;
983
- }
984
- }
985
- /**
986
- * Handle errors
987
- */
988
- handleError(error) {
989
- if (error instanceof Error && "code" in error) {
990
- const code = error.code;
991
- if (code === "auth/requires-recent-login") {
992
- return createAuthError("REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */, "Please reauthenticate first", error);
993
- }
994
- if (code === "auth/invalid-photo-url") {
995
- return createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Invalid photo URL", error);
996
- }
997
- }
998
- return createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Profile update failed", error);
999
- }
1000
- };
1001
-
1002
- // src/application/use-cases/user/delete-account.use-case.ts
1003
- var DeleteAccountUseCase = class {
1004
- constructor(authRepository) {
1005
- this.authRepository = authRepository;
1006
- }
1007
- /**
1008
- * Execute account deletion use case
1009
- */
1010
- async execute(dto) {
1011
- try {
1012
- this.validateDTO(dto);
1013
- const currentUser = this.authRepository.getCurrentUser();
1014
- if (!currentUser) {
1015
- throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
1016
- }
1017
- if (!currentUser.email) {
1018
- throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "User email not available");
1019
- }
1020
- await this.authRepository.deleteAccount(dto.password);
1021
- } catch (error) {
1022
- throw this.handleError(error);
1023
- }
1024
- }
1025
- /**
1026
- * Validate DTO
1027
- */
1028
- validateDTO(dto) {
1029
- if (!dto.password) {
1030
- throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Password is required");
1031
- }
1032
- if (dto.password.length < 1) {
1033
- throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Password cannot be empty");
1034
- }
1035
- }
1036
- /**
1037
- * Handle errors
1038
- */
1039
- handleError(error) {
1040
- if (error instanceof Error && "code" in error) {
1041
- const code = error.code;
1042
- if (code === "auth/requires-recent-login") {
1043
- return createAuthError("REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */, "Please reauthenticate first", error);
1044
- }
1045
- if (code === "auth/wrong-password") {
1046
- return createAuthError("REAUTHENTICATION_FAILED" /* REAUTHENTICATION_FAILED */, "Invalid password", error);
1047
- }
1048
- if (code === "auth/too-many-requests") {
1049
- return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many requests", error);
1050
- }
1051
- if (code === "auth/user-not-found") {
1052
- return createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "User not found", error);
1053
- }
1054
- }
1055
- return createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Account deletion failed", error);
1056
- }
1057
- };
1058
-
1059
- // src/infrastructure/firebase/client.ts
1060
- var import_app = require("firebase/app");
1061
- var import_auth8 = require("firebase/auth");
1062
- var import_firestore = require("firebase/firestore");
1063
- var import_storage = require("firebase/storage");
1064
- var import_analytics = require("firebase/analytics");
1065
- var import_functions = require("firebase/functions");
1066
- var firebaseConfig = {
1067
- apiKey: process.env.VITE_FIREBASE_API_KEY,
1068
- authDomain: process.env.VITE_FIREBASE_AUTH_DOMAIN,
1069
- projectId: process.env.VITE_FIREBASE_PROJECT_ID,
1070
- storageBucket: process.env.VITE_FIREBASE_STORAGE_BUCKET,
1071
- messagingSenderId: process.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
1072
- appId: process.env.VITE_FIREBASE_APP_ID,
1073
- measurementId: process.env.VITE_FIREBASE_MEASUREMENT_ID
1074
- };
1075
- var app;
1076
- var auth;
1077
- var db;
1078
- var storage;
1079
- var functions;
1080
- var analytics = null;
1081
- function initializeFirebase() {
1082
- if (!(0, import_app.getApps)().length) {
1083
- app = (0, import_app.initializeApp)(firebaseConfig);
1084
- } else {
1085
- app = (0, import_app.getApps)()[0];
1086
- }
1087
- return app;
1088
- }
1089
- function getFirebaseApp() {
1090
- return app || initializeFirebase();
1091
- }
1092
- function getFirebaseAuth() {
1093
- if (!auth) {
1094
- const firebaseApp = getFirebaseApp();
1095
- if (typeof window !== "undefined") {
1096
- try {
1097
- auth = (0, import_auth8.getAuth)(firebaseApp);
1098
- } catch (e) {
1099
- console.warn("getAuth failed, trying initializeAuth...", e);
1100
- auth = (0, import_auth8.initializeAuth)(firebaseApp, {
1101
- persistence: import_auth8.browserLocalPersistence
1102
- });
1103
- }
1104
- } else {
1105
- auth = (0, import_auth8.getAuth)(firebaseApp);
1106
- }
1107
- }
1108
- return auth;
1109
- }
1110
- function getFirebaseDB() {
1111
- if (!db) {
1112
- db = (0, import_firestore.getFirestore)(getFirebaseApp());
1113
- }
1114
- return db;
1115
- }
1116
- function getFirebaseStorage() {
1117
- if (!storage) {
1118
- storage = (0, import_storage.getStorage)(getFirebaseApp());
1119
- }
1120
- return storage;
1121
- }
1122
- function getFirebaseFunctions() {
1123
- if (!functions) {
1124
- functions = (0, import_functions.getFunctions)(getFirebaseApp());
1125
- }
1126
- return functions;
1127
- }
1128
- function getFirebaseAnalytics() {
1129
- if (!analytics && typeof window !== "undefined") {
1130
- analytics = (0, import_analytics.getAnalytics)(getFirebaseApp());
1131
- }
1132
- return analytics;
1133
- }
1134
- function getFirebaseInstances() {
1135
- return {
1136
- app: getFirebaseApp(),
1137
- auth: getFirebaseAuth(),
1138
- db: getFirebaseDB(),
1139
- storage: getFirebaseStorage(),
1140
- functions: getFirebaseFunctions(),
1141
- analytics: getFirebaseAnalytics()
1142
- };
1143
- }
1144
-
1145
- // src/infrastructure/firebase/auth.adapter.ts
1146
- var import_auth9 = require("firebase/auth");
1147
- var import_auth10 = require("firebase/auth");
1148
- var AuthAdapter = class {
1149
- get auth() {
1150
- return getFirebaseAuth();
1151
- }
1152
- // Authentication Methods
1153
- async signIn(email, password) {
1154
- try {
1155
- return await (0, import_auth9.signInWithEmailAndPassword)(this.auth, email, password);
1156
- } catch (error) {
1157
- throw this.handleAuthError(error);
1158
- }
1159
- }
1160
- async signUp(email, password, displayName) {
1161
- try {
1162
- const result = await (0, import_auth9.createUserWithEmailAndPassword)(this.auth, email, password);
1163
- await (0, import_auth9.updateProfile)(result.user, { displayName });
1164
- await (0, import_auth9.sendEmailVerification)(result.user);
1165
- return result;
1166
- } catch (error) {
1167
- throw this.handleAuthError(error);
1168
- }
1169
- }
1170
- async signInWithGoogle() {
1171
- try {
1172
- const provider = new import_auth10.GoogleAuthProvider();
1173
- provider.addScope("profile");
1174
- provider.addScope("email");
1175
- return await (0, import_auth9.signInWithPopup)(this.auth, provider);
1176
- } catch (error) {
1177
- throw this.handleAuthError(error);
1178
- }
1179
- }
1180
- async signOut() {
1181
- try {
1182
- await (0, import_auth9.signOut)(this.auth);
1183
- } catch (error) {
1184
- throw createAuthError("SIGN_OUT_FAILED" /* SIGN_OUT_FAILED */, "Sign out failed", error);
1185
- }
1186
- }
1187
- async sendPasswordReset(email) {
1188
- try {
1189
- await (0, import_auth9.sendPasswordResetEmail)(this.auth, email);
1190
- } catch (error) {
1191
- throw this.handleAuthError(error);
1192
- }
1193
- }
1194
- async resendEmailVerification() {
1195
- try {
1196
- const user = this.auth.currentUser;
1197
- if (!user) {
1198
- throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
1199
- }
1200
- await (0, import_auth9.sendEmailVerification)(user);
1201
- } catch (error) {
1202
- throw createAuthError("EMAIL_VERIFICATION_FAILED" /* EMAIL_VERIFICATION_FAILED */, "Failed to resend verification", error);
1203
- }
1204
- }
1205
- // Profile Management
1206
- async updateProfile(updates) {
1207
- try {
1208
- const user = this.auth.currentUser;
1209
- if (!user) {
1210
- throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
1211
- }
1212
- await (0, import_auth9.updateProfile)(user, updates);
1213
- } catch (error) {
1214
- throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Profile update failed", error);
1215
- }
1216
- }
1217
- async updateEmail(newEmail, password) {
1218
- try {
1219
- const user = this.auth.currentUser;
1220
- if (!user || !user.email) {
1221
- throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
1222
- }
1223
- const credential = import_auth9.EmailAuthProvider.credential(user.email, password);
1224
- await (0, import_auth9.reauthenticateWithCredential)(user, credential);
1225
- await (0, import_auth9.updateEmail)(user, newEmail);
1226
- } catch (error) {
1227
- throw createAuthError("EMAIL_UPDATE_FAILED" /* EMAIL_UPDATE_FAILED */, "Email update failed", error);
1228
- }
1229
- }
1230
- async updatePassword(currentPassword, newPassword) {
1231
- try {
1232
- const user = this.auth.currentUser;
1233
- if (!user || !user.email) {
1234
- throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
1235
- }
1236
- const credential = import_auth9.EmailAuthProvider.credential(user.email, currentPassword);
1237
- await (0, import_auth9.reauthenticateWithCredential)(user, credential);
1238
- await (0, import_auth9.updatePassword)(user, newPassword);
1239
- } catch (error) {
1240
- throw createAuthError("PASSWORD_UPDATE_FAILED" /* PASSWORD_UPDATE_FAILED */, "Password update failed", error);
1241
- }
1242
- }
1243
- async deleteAccount(password) {
1244
- try {
1245
- const user = this.auth.currentUser;
1246
- if (!user || !user.email) {
1247
- throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
1248
- }
1249
- const credential = import_auth9.EmailAuthProvider.credential(user.email, password);
1250
- await (0, import_auth9.reauthenticateWithCredential)(user, credential);
1251
- await user.delete();
1252
- } catch (error) {
1253
- throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Account deletion failed", error);
1254
- }
1255
- }
1256
- // State Management
1257
- getCurrentUser() {
1258
- return this.auth.currentUser;
1259
- }
1260
- onAuthStateChanged(callback) {
1261
- return this.auth.onAuthStateChanged(callback);
1262
- }
1263
- // Note: User document operations should be handled by UserAdapter
1264
- // These methods are part of IAuthRepository interface but should be implemented separately
1265
- async createUserDocument(_userId, _data) {
1266
- throw new Error("createUserDocument should be handled by UserAdapter");
1267
- }
1268
- async updateLastLogin(_userId) {
1269
- throw new Error("updateLastLogin should be handled by UserAdapter");
1270
- }
1271
- /**
1272
- * Handle Firebase Auth errors
1273
- */
1274
- handleAuthError(error) {
1275
- if (error instanceof Error && "code" in error) {
1276
- const code = error.code;
1277
- switch (code) {
1278
- case "auth/user-not-found":
1279
- return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "User not found", error);
1280
- case "auth/wrong-password":
1281
- case "auth/invalid-credential":
1282
- return createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid credentials", error);
1283
- case "auth/email-already-in-use":
1284
- return createAuthError("USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */, "Email already in use", error);
1285
- case "auth/weak-password":
1286
- return createAuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, "Password is too weak", error);
1287
- case "auth/invalid-email":
1288
- return createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid email", error);
1289
- case "auth/user-disabled":
1290
- return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "Account disabled", error);
1291
- case "auth/too-many-requests":
1292
- return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many requests", error);
1293
- case "auth/popup-closed-by-user":
1294
- return createAuthError("OAUTH_CANCELLED" /* OAUTH_CANCELLED */, "Sign in cancelled", error);
1295
- case "auth/account-exists-with-different-credential":
1296
- return createAuthError("OAUTH_ACCOUNT_EXISTS" /* OAUTH_ACCOUNT_EXISTS */, "Account exists with different provider", error);
1297
- case "auth/requires-recent-login":
1298
- return createAuthError("REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */, "Please reauthenticate", error);
1299
- default:
1300
- return createAuthError("UNKNOWN" /* UNKNOWN */, `Auth error: ${code}`, error);
1301
- }
1302
- }
1303
- return createAuthError("UNKNOWN" /* UNKNOWN */, "Unknown auth error", error);
1304
- }
1305
- };
1306
-
1307
- // src/infrastructure/firebase/firestore.adapter.ts
1308
- var import_firestore2 = require("firebase/firestore");
1309
- var FirestoreAdapter = class {
1310
- get db() {
1311
- return getFirebaseDB();
1312
- }
1313
- USERS_COLLECTION = "users";
1314
- async getUser(userId) {
1315
- try {
1316
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1317
- const snap = await (0, import_firestore2.getDoc)(docRef);
1318
- if (!snap.exists()) {
1319
- return null;
1320
- }
1321
- return snap.data();
1322
- } catch (error) {
1323
- throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "User not found", error);
1324
- }
1325
- }
1326
- async getUserByEmail(email) {
1327
- try {
1328
- const q = (0, import_firestore2.query)((0, import_firestore2.collection)(this.db, this.USERS_COLLECTION), (0, import_firestore2.where)("profile.email", "==", email));
1329
- const snap = await (0, import_firestore2.getDocs)(q);
1330
- if (snap.empty) {
1331
- return null;
1332
- }
1333
- const doc2 = snap.docs[0];
1334
- return doc2.data();
1335
- } catch (error) {
1336
- throw createRepositoryError("QUERY_FAILED" /* QUERY_FAILED */, "Failed to query user", error);
1337
- }
1338
- }
1339
- async createUser(userId, data) {
1340
- try {
1341
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1342
- await (0, import_firestore2.setDoc)(docRef, data, { merge: true });
1343
- } catch (error) {
1344
- throw createRepositoryError("DOCUMENT_INVALID" /* DOCUMENT_INVALID */, "Failed to create user", error);
1345
- }
1346
- }
1347
- async updateUser(userId, data) {
1348
- try {
1349
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1350
- await (0, import_firestore2.updateDoc)(docRef, {
1351
- ...data,
1352
- "profile.updatedAt": Date.now()
1353
- });
1354
- } catch (error) {
1355
- throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update user", error);
1356
- }
1357
- }
1358
- async deleteUser(userId) {
1359
- try {
1360
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1361
- await (0, import_firestore2.deleteDoc)(docRef);
1362
- } catch (error) {
1363
- throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to delete user", error);
1364
- }
1365
- }
1366
- async updateProfile(userId, updates) {
1367
- try {
1368
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1369
- const updateData = {
1370
- "profile.updatedAt": Date.now()
1371
- };
1372
- if (updates.displayName !== void 0) {
1373
- updateData["profile.displayName"] = updates.displayName;
1374
- }
1375
- if (updates.photoURL !== void 0) {
1376
- updateData["profile.photoURL"] = updates.photoURL;
1377
- }
1378
- if (updates.phoneNumber !== void 0) {
1379
- updateData["profile.phoneNumber"] = updates.phoneNumber;
1380
- }
1381
- await (0, import_firestore2.updateDoc)(docRef, updateData);
1382
- } catch (error) {
1383
- throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update profile", error);
1384
- }
1385
- }
1386
- async updateSettings(userId, settings) {
1387
- try {
1388
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1389
- await (0, import_firestore2.updateDoc)(docRef, {
1390
- settings: {
1391
- ...settings,
1392
- updatedAt: Date.now()
1393
- }
1394
- });
1395
- } catch (error) {
1396
- throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update settings", error);
1397
- }
1398
- }
1399
- async updateSubscription(userId, subscription) {
1400
- try {
1401
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1402
- await (0, import_firestore2.updateDoc)(docRef, {
1403
- subscription: {
1404
- ...subscription,
1405
- updatedAt: Date.now()
1406
- }
1407
- });
1408
- } catch (error) {
1409
- throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update subscription", error);
1410
- }
1411
- }
1412
- async updateLastLogin(userId) {
1413
- try {
1414
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1415
- await (0, import_firestore2.updateDoc)(docRef, {
1416
- "profile.lastLoginAt": Date.now()
1417
- });
1418
- } catch (error) {
1419
- throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update last login", error);
1420
- }
1421
- }
1422
- async queryUsers(constraints) {
1423
- try {
1424
- const q = (0, import_firestore2.query)((0, import_firestore2.collection)(this.db, this.USERS_COLLECTION), ...constraints);
1425
- const snap = await (0, import_firestore2.getDocs)(q);
1426
- return snap.docs.map((doc2) => doc2.data());
1427
- } catch (error) {
1428
- throw createRepositoryError("QUERY_FAILED" /* QUERY_FAILED */, "Failed to query users", error);
1429
- }
1430
- }
1431
- subscribeToUser(userId, callback, onError) {
1432
- const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
1433
- const unsubscribe = (0, import_firestore2.onSnapshot)(
1434
- docRef,
1435
- (snap) => {
1436
- if (snap.exists()) {
1437
- callback(snap.data());
1438
- } else {
1439
- callback(null);
1440
- }
1441
- },
1442
- (error) => {
1443
- onError?.(error);
1444
- }
1445
- );
1446
- return unsubscribe;
1447
- }
1448
- };
1449
-
1450
- // src/infrastructure/firebase/storage.adapter.ts
1451
- var import_storage2 = require("firebase/storage");
1452
- var StorageAdapter = class {
1453
- get storage() {
1454
- return getFirebaseStorage();
1455
- }
1456
- // Upload Methods
1457
- async uploadFile(userId, path, file, options) {
1458
- const storageRef = (0, import_storage2.ref)(this.storage, `users/${userId}/${path}`);
1459
- const uploadTask = (0, import_storage2.uploadBytesResumable)(storageRef, file);
1460
- return new Promise((resolve, reject) => {
1461
- uploadTask.on(
1462
- "state_changed",
1463
- (snapshot) => {
1464
- if (options?.onProgress) {
1465
- const progress = {
1466
- bytesTransferred: snapshot.bytesTransferred,
1467
- totalBytes: snapshot.totalBytes,
1468
- progress: snapshot.bytesTransferred / snapshot.totalBytes * 100,
1469
- state: "running"
1470
- };
1471
- options.onProgress(progress);
1472
- }
1473
- },
1474
- (error) => reject(createRepositoryError("STORAGE_ERROR" /* STORAGE_ERROR */, "Upload failed", error)),
1475
- async () => {
1476
- const downloadURL = await (0, import_storage2.getDownloadURL)(uploadTask.snapshot.ref);
1477
- const metadata = await (0, import_storage2.getMetadata)(uploadTask.snapshot.ref);
1478
- resolve({
1479
- id: uploadTask.snapshot.ref.name,
1480
- name: metadata.name || uploadTask.snapshot.ref.name,
1481
- fullPath: metadata.fullPath || uploadTask.snapshot.ref.fullPath,
1482
- downloadURL,
1483
- contentType: metadata.contentType || "",
1484
- size: metadata.size || 0,
1485
- createdAt: metadata.timeCreated ? new Date(metadata.timeCreated).getTime() : Date.now()
1486
- });
1487
- }
1488
- );
1489
- });
1490
- }
1491
- async uploadImage(userId, file, filename) {
1492
- const name = filename || `${Date.now()}_${file.name}`;
1493
- return this.uploadFile(userId, `images/${name}`, file);
1494
- }
1495
- async uploadVideo(userId, file, filename) {
1496
- const name = filename || `${Date.now()}_${file.name}`;
1497
- return this.uploadFile(userId, `videos/${name}`, file);
1498
- }
1499
- async uploadDocument(userId, file, filename) {
1500
- const name = filename || `${Date.now()}_${file.name}`;
1501
- return this.uploadFile(userId, `documents/${name}`, file);
1502
- }
1503
- async uploadProfilePicture(userId, file) {
1504
- const storageRef = (0, import_storage2.ref)(this.storage, `users/${userId}/profile/${Date.now()}_${file.name}`);
1505
- await (0, import_storage2.uploadBytes)(storageRef, file);
1506
- const downloadURL = await (0, import_storage2.getDownloadURL)(storageRef);
1507
- return {
1508
- id: storageRef.name,
1509
- name: file.name,
1510
- fullPath: storageRef.fullPath,
1511
- downloadURL,
1512
- contentType: file.type,
1513
- size: file.size,
1514
- createdAt: Date.now()
1515
- };
1516
- }
1517
- // Download Methods
1518
- async getDownloadURL(path) {
1519
- try {
1520
- const storageRef = (0, import_storage2.ref)(this.storage, path);
1521
- return await (0, import_storage2.getDownloadURL)(storageRef);
1522
- } catch (error) {
1523
- throw createRepositoryError("FILE_NOT_FOUND" /* FILE_NOT_FOUND */, "File not found", error);
1524
- }
1525
- }
1526
- // Delete Methods
1527
- async deleteFile(path) {
1528
- try {
1529
- const storageRef = (0, import_storage2.ref)(this.storage, path);
1530
- await (0, import_storage2.deleteObject)(storageRef);
1531
- } catch (error) {
1532
- throw createRepositoryError("FILE_NOT_FOUND" /* FILE_NOT_FOUND */, "File not found", error);
1533
- }
1534
- }
1535
- async deleteUserFiles(userId) {
1536
- try {
1537
- const userRef = (0, import_storage2.ref)(this.storage, `users/${userId}`);
1538
- const result = await (0, import_storage2.listAll)(userRef);
1539
- for (const prefix of result.prefixes) {
1540
- const prefixResult = await (0, import_storage2.listAll)(prefix);
1541
- await Promise.all(prefixResult.items.map((item) => (0, import_storage2.deleteObject)(item)));
1542
- }
1543
- await Promise.all(result.items.map((item) => (0, import_storage2.deleteObject)(item)));
1544
- } catch (error) {
1545
- throw createRepositoryError("STORAGE_ERROR" /* STORAGE_ERROR */, "Failed to delete user files", error);
1546
- }
1547
- }
1548
- async deleteImage(userId, filename) {
1549
- await this.deleteFile(`users/${userId}/images/${filename}`);
1550
- }
1551
- async deleteVideo(userId, filename) {
1552
- await this.deleteFile(`users/${userId}/videos/${filename}`);
1553
- }
1554
- async deleteProfilePicture(userId, filename) {
1555
- await this.deleteFile(`users/${userId}/profile/${filename}`);
1556
- }
1557
- // List Methods
1558
- async listUserFiles(userId, path) {
1559
- const userRef = (0, import_storage2.ref)(this.storage, path ? `users/${userId}/${path}` : `users/${userId}`);
1560
- const result = await (0, import_storage2.listAll)(userRef);
1561
- const urls = await Promise.all(result.items.map((item) => (0, import_storage2.getDownloadURL)(item)));
1562
- return urls;
1563
- }
1564
- async listUserImages(userId) {
1565
- return this.listUserFiles(userId, "images");
1566
- }
1567
- async listUserVideos(userId) {
1568
- return this.listUserFiles(userId, "videos");
1569
- }
1570
- // Metadata
1571
- async getFileMetadata(path) {
1572
- try {
1573
- const storageRef = (0, import_storage2.ref)(this.storage, path);
1574
- const metadata = await (0, import_storage2.getMetadata)(storageRef);
1575
- return {
1576
- id: storageRef.name,
1577
- name: metadata.name,
1578
- fullPath: metadata.fullPath,
1579
- contentType: metadata.contentType || "application/octet-stream",
1580
- size: metadata.size,
1581
- createdAt: metadata.timeCreated ? new Date(metadata.timeCreated).getTime() : Date.now(),
1582
- updatedAt: metadata.updated ? new Date(metadata.updated).getTime() : Date.now(),
1583
- userId: this.extractUserId(path) || "unknown",
1584
- type: this.extractFileType(metadata.contentType || "")
1585
- };
1586
- } catch (error) {
1587
- throw createRepositoryError("FILE_NOT_FOUND" /* FILE_NOT_FOUND */, "File not found", error);
1588
- }
1589
- }
1590
- async queryFiles(userId, _filters) {
1591
- const userRef = (0, import_storage2.ref)(this.storage, `users/${userId}`);
1592
- const result = await (0, import_storage2.listAll)(userRef);
1593
- const files = await Promise.all(
1594
- result.items.map(async (item) => {
1595
- const metadata = await (0, import_storage2.getMetadata)(item);
1596
- return {
1597
- id: item.name,
1598
- name: metadata.name,
1599
- fullPath: metadata.fullPath,
1600
- contentType: metadata.contentType || "application/octet-stream",
1601
- size: metadata.size,
1602
- createdAt: metadata.timeCreated ? new Date(metadata.timeCreated).getTime() : Date.now(),
1603
- updatedAt: metadata.updated ? new Date(metadata.updated).getTime() : Date.now(),
1604
- userId,
1605
- type: this.extractFileType(metadata.contentType || "")
1606
- };
1607
- })
1608
- );
1609
- return {
1610
- files,
1611
- totalCount: files.length,
1612
- hasMore: false
1613
- };
1614
- }
1615
- async getStorageStats(userId) {
1616
- const { files, totalCount } = await this.queryFiles(userId);
1617
- const stats = {
1618
- totalFiles: totalCount,
1619
- totalSize: files.reduce((sum, file) => sum + file.size, 0),
1620
- filesByType: {
1621
- image: 0,
1622
- video: 0,
1623
- audio: 0,
1624
- document: 0,
1625
- other: 0
1626
- },
1627
- filesByCategory: {
1628
- profile: 0,
1629
- content: 0,
1630
- document: 0,
1631
- attachment: 0,
1632
- backup: 0
1633
- }
1634
- };
1635
- files.forEach((file) => {
1636
- stats.filesByType[file.type]++;
1637
- stats.lastUploadAt = Math.max(stats.lastUploadAt || 0, file.createdAt);
1638
- });
1639
- return stats;
1640
- }
1641
- // Validation
1642
- validateFile(file, options) {
1643
- const maxSizeBytes = options?.maxSizeBytes || (options?.maxSizeMB ? options.maxSizeMB * 1024 * 1024 : 10 * 1024 * 1024);
1644
- if (file.size > maxSizeBytes) {
1645
- return false;
1646
- }
1647
- if (options?.allowedTypes && !options.allowedTypes.includes(file.type)) {
1648
- return false;
1649
- }
1650
- return true;
1651
- }
1652
- isImageFile(file) {
1653
- return file.type.startsWith("image/");
1654
- }
1655
- isVideoFile(file) {
1656
- return file.type.startsWith("video/");
1657
- }
1658
- isDocumentFile(file) {
1659
- const docTypes = [
1660
- "application/pdf",
1661
- "application/msword",
1662
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1663
- "application/vnd.ms-excel",
1664
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1665
- "text/plain"
1666
- ];
1667
- return docTypes.includes(file.type);
1668
- }
1669
- // Utility Methods
1670
- generateUniqueFilename(originalName) {
1671
- const timestamp = Date.now();
1672
- const random = Math.random().toString(36).substring(2, 8);
1673
- const extension = this.getFileExtension(originalName);
1674
- return `${timestamp}_${random}.${extension}`;
1675
- }
1676
- getFileExtension(filename) {
1677
- return filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
1678
- }
1679
- // Helper Methods
1680
- extractUserId(path) {
1681
- const match = path.match(/users\/([^\/]+)/);
1682
- return match ? match[1] : "";
1683
- }
1684
- extractFileType(contentType) {
1685
- if (contentType.startsWith("image/")) return "image";
1686
- if (contentType.startsWith("video/")) return "video";
1687
- if (contentType.startsWith("audio/")) return "audio";
1688
- if (contentType.includes("pdf") || contentType.includes("document") || contentType.includes("text")) {
1689
- return "document";
1690
- }
1691
- return "other";
1692
- }
1693
- };
1694
-
1695
- // src/infrastructure/utils/storage.util.ts
1696
- var import_storage3 = require("firebase/storage");
1697
- async function uploadFile(storage2, path, file) {
1698
- const storageRef = (0, import_storage3.ref)(storage2, path);
1699
- await (0, import_storage3.uploadBytes)(storageRef, file);
1700
- const url = await (0, import_storage3.getDownloadURL)(storageRef);
1701
- return { url, path };
1702
- }
1703
- async function uploadBase64(storage2, path, base64, mimeType = "image/jpeg") {
1704
- const storageRef = (0, import_storage3.ref)(storage2, path);
1705
- const dataUrl = base64.startsWith("data:") ? base64 : `data:${mimeType};base64,${base64}`;
1706
- await (0, import_storage3.uploadString)(storageRef, dataUrl, "data_url");
1707
- const url = await (0, import_storage3.getDownloadURL)(storageRef);
1708
- return { url, path };
1709
- }
1710
- async function deleteFile(storage2, path) {
1711
- await (0, import_storage3.deleteObject)((0, import_storage3.ref)(storage2, path));
1712
- }
1713
-
1714
- // src/presentation/hooks/useFirebaseAuth.ts
1715
- var import_react = require("react");
1716
- var import_auth12 = require("firebase/auth");
1717
- function mapUser(u) {
1718
- return {
1719
- uid: u.uid,
1720
- email: u.email,
1721
- displayName: u.displayName,
1722
- photoURL: u.photoURL,
1723
- emailVerified: u.emailVerified
1724
- };
1725
- }
1726
- function useFirebaseAuth(auth2, options) {
1727
- const [user, setUser] = (0, import_react.useState)(null);
1728
- const [loading, setLoading] = (0, import_react.useState)(true);
1729
- (0, import_react.useEffect)(() => {
1730
- const unsub = (0, import_auth12.onAuthStateChanged)(auth2, (firebaseUser) => {
1731
- const mapped = firebaseUser ? mapUser(firebaseUser) : null;
1732
- setUser(mapped);
1733
- setLoading(false);
1734
- options?.onUserChange?.(mapped);
1735
- });
1736
- return unsub;
1737
- }, [auth2, options]);
1738
- const signIn = (0, import_react.useCallback)(
1739
- (email, password) => (0, import_auth12.signInWithEmailAndPassword)(auth2, email, password),
1740
- [auth2]
1741
- );
1742
- const signUp = (0, import_react.useCallback)(
1743
- async (email, password, name) => {
1744
- const cred = await (0, import_auth12.createUserWithEmailAndPassword)(auth2, email, password);
1745
- if (name && cred.user) await (0, import_auth12.updateProfile)(cred.user, { displayName: name });
1746
- return cred;
1747
- },
1748
- [auth2]
1749
- );
1750
- const signOut = (0, import_react.useCallback)(() => (0, import_auth12.signOut)(auth2), [auth2]);
1751
- const updateUserProfile = (0, import_react.useCallback)(
1752
- async (name, photoURL) => {
1753
- if (!auth2.currentUser) throw new Error("No authenticated user");
1754
- await (0, import_auth12.updateProfile)(auth2.currentUser, {
1755
- displayName: name,
1756
- ...photoURL !== void 0 && { photoURL }
1757
- });
1758
- },
1759
- [auth2]
1760
- );
1761
- const updateUserPassword = (0, import_react.useCallback)(
1762
- async (newPassword) => {
1763
- if (!auth2.currentUser) throw new Error("No authenticated user");
1764
- await (0, import_auth12.updatePassword)(auth2.currentUser, newPassword);
1765
- },
1766
- [auth2]
1767
- );
1768
- const resetPassword = (0, import_react.useCallback)(
1769
- (email) => (0, import_auth12.sendPasswordResetEmail)(auth2, email),
1770
- [auth2]
1771
- );
1772
- const getIdToken = (0, import_react.useCallback)(async () => {
1773
- if (!auth2.currentUser) throw new Error("No authenticated user");
1774
- return auth2.currentUser.getIdToken();
1775
- }, [auth2]);
1776
- return {
1777
- user,
1778
- loading,
1779
- isAuthenticated: !!user,
1780
- signIn,
1781
- signUp,
1782
- signOut,
1783
- updateUserProfile,
1784
- updateUserPassword,
1785
- resetPassword,
1786
- getIdToken
1787
- };
1788
- }
1789
- // Annotate the CommonJS export names for ESM import in node:
1790
- 0 && (module.exports = {
1791
- AuthAdapter,
1792
- AuthError,
1793
- AuthErrorCode,
1794
- DeleteAccountUseCase,
1795
- Email,
1796
- FileErrorCode,
1797
- FilePath,
1798
- FirestoreAdapter,
1799
- RepositoryError,
1800
- RepositoryErrorCode,
1801
- ResetPasswordUseCase,
1802
- SignInUseCase,
1803
- SignInWithGoogleUseCase,
1804
- SignOutUseCase,
1805
- SignUpUseCase,
1806
- StorageAdapter,
1807
- Timestamp,
1808
- USER_COLLECTIONS,
1809
- USER_SUBCOLLECTIONS,
1810
- UpdateProfileUseCase,
1811
- UserId,
1812
- analytics,
1813
- app,
1814
- auth,
1815
- createAuthError,
1816
- createRepositoryError,
1817
- db,
1818
- deleteFile,
1819
- functions,
1820
- getFirebaseAnalytics,
1821
- getFirebaseApp,
1822
- getFirebaseAuth,
1823
- getFirebaseDB,
1824
- getFirebaseFunctions,
1825
- getFirebaseInstances,
1826
- getFirebaseStorage,
1827
- initializeFirebase,
1828
- serverTimestamp,
1829
- storage,
1830
- uploadBase64,
1831
- uploadFile,
1832
- useFirebaseAuth
1833
- });