@umituz/web-firebase 2.1.0 → 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.
- package/package.json +12 -39
- package/src/domains/auth/entities/index.ts +60 -0
- package/src/domains/auth/index.ts +13 -0
- package/src/domains/auth/services/auth.service.ts +245 -0
- package/src/domains/auth/services/index.ts +7 -0
- package/src/domains/auth/types/auth-service.interface.ts +72 -0
- package/src/domains/auth/types/index.ts +5 -0
- package/src/domains/firestore/entities/index.ts +82 -0
- package/src/domains/firestore/index.ts +13 -0
- package/src/domains/firestore/services/firestore.service.ts +191 -0
- package/src/domains/firestore/services/index.ts +7 -0
- package/src/domains/firestore/types/firestore-service.interface.ts +64 -0
- package/src/domains/firestore/types/index.ts +5 -0
- package/src/domains/storage/entities/index.ts +94 -0
- package/src/domains/storage/index.ts +13 -0
- package/src/domains/storage/services/index.ts +7 -0
- package/src/domains/storage/services/storage.service.ts +223 -0
- package/src/domains/storage/types/index.ts +5 -0
- package/src/domains/storage/types/storage-service.interface.ts +120 -0
- package/src/index.ts +12 -16
- package/src/presentation/hooks/useAuth.ts +69 -26
- package/src/presentation/providers/FirebaseProvider.tsx +9 -14
- package/dist/application/index.d.mts +0 -273
- package/dist/application/index.d.ts +0 -273
- package/dist/application/index.js +0 -490
- package/dist/application/index.mjs +0 -19
- package/dist/chunk-34DL2QWQ.mjs +0 -87
- package/dist/chunk-4FP2ELQ5.mjs +0 -96
- package/dist/chunk-7TX3OU3O.mjs +0 -721
- package/dist/chunk-I6WGBPFB.mjs +0 -439
- package/dist/chunk-RZ4QR6TB.mjs +0 -96
- package/dist/chunk-U2XI4MGO.mjs +0 -397
- package/dist/domain/index.d.mts +0 -325
- package/dist/domain/index.d.ts +0 -325
- package/dist/domain/index.js +0 -662
- package/dist/domain/index.mjs +0 -36
- package/dist/file.repository.interface-v5vHgVsZ.d.mts +0 -241
- package/dist/file.repository.interface-v5vHgVsZ.d.ts +0 -241
- package/dist/firebase.entity-xvfEPjXZ.d.mts +0 -15
- package/dist/firebase.entity-xvfEPjXZ.d.ts +0 -15
- package/dist/index.d.mts +0 -14
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -1833
- package/dist/index.mjs +0 -98
- package/dist/infrastructure/index.d.mts +0 -170
- package/dist/infrastructure/index.d.ts +0 -170
- package/dist/infrastructure/index.js +0 -856
- package/dist/infrastructure/index.mjs +0 -46
- package/dist/presentation/index.d.mts +0 -25
- package/dist/presentation/index.d.ts +0 -25
- package/dist/presentation/index.js +0 -105
- package/dist/presentation/index.mjs +0 -6
- package/dist/user.repository.interface-DS74TsJ5.d.mts +0 -298
- 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
|
-
});
|