@umituz/web-firebase 1.0.4 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +555 -0
- package/dist/application/index.d.mts +273 -0
- package/dist/application/index.d.ts +273 -0
- package/dist/application/index.js +490 -0
- package/dist/application/index.mjs +19 -0
- package/dist/chunk-34DL2QWQ.mjs +87 -0
- package/dist/chunk-4FP2ELQ5.mjs +96 -0
- package/dist/chunk-7TX3OU3O.mjs +721 -0
- package/dist/chunk-I6WGBPFB.mjs +439 -0
- package/dist/chunk-RZ4QR6TB.mjs +96 -0
- package/dist/chunk-U2XI4MGO.mjs +397 -0
- package/dist/domain/index.d.mts +325 -0
- package/dist/domain/index.d.ts +325 -0
- package/dist/domain/index.js +662 -0
- package/dist/domain/index.mjs +36 -0
- package/dist/file.repository.interface-v5vHgVsZ.d.mts +241 -0
- package/dist/file.repository.interface-v5vHgVsZ.d.ts +241 -0
- package/dist/firebase.entity-xvfEPjXZ.d.mts +15 -0
- package/dist/firebase.entity-xvfEPjXZ.d.ts +15 -0
- package/dist/index.d.mts +14 -96
- package/dist/index.d.ts +14 -96
- package/dist/index.js +1717 -78
- package/dist/index.mjs +88 -175
- package/dist/infrastructure/index.d.mts +170 -0
- package/dist/infrastructure/index.d.ts +170 -0
- package/dist/infrastructure/index.js +856 -0
- package/dist/infrastructure/index.mjs +46 -0
- package/dist/presentation/index.d.mts +25 -0
- package/dist/presentation/index.d.ts +25 -0
- package/dist/presentation/index.js +105 -0
- package/dist/presentation/index.mjs +6 -0
- package/dist/user.repository.interface-DS74TsJ5.d.mts +298 -0
- package/dist/user.repository.interface-DS74TsJ5.d.ts +298 -0
- package/package.json +39 -12
- package/src/application/dto/auth.dto.ts +69 -0
- package/src/application/dto/index.ts +7 -0
- package/src/application/dto/user.dto.ts +64 -0
- package/src/application/index.ts +7 -0
- package/src/application/use-cases/auth/reset-password.use-case.ts +66 -0
- package/src/application/use-cases/auth/sign-in-with-google.use-case.ts +86 -0
- package/src/application/use-cases/auth/sign-in.use-case.ts +77 -0
- package/src/application/use-cases/auth/sign-out.use-case.ts +22 -0
- package/src/application/use-cases/auth/sign-up.use-case.ts +99 -0
- package/src/application/use-cases/index.ts +12 -0
- package/src/application/use-cases/user/delete-account.use-case.ts +77 -0
- package/src/application/use-cases/user/update-profile.use-case.ts +98 -0
- package/src/domain/entities/file.entity.ts +151 -0
- package/src/domain/entities/firebase.entity.ts +13 -0
- package/src/domain/entities/timestamp.entity.ts +116 -0
- package/src/domain/entities/user.entity.ts +193 -0
- package/src/domain/errors/auth.errors.ts +115 -0
- package/src/domain/errors/repository.errors.ts +121 -0
- package/src/domain/index.ts +30 -0
- package/src/domain/interfaces/auth.repository.interface.ts +83 -0
- package/src/domain/interfaces/file.repository.interface.ts +143 -0
- package/src/domain/interfaces/repository.interface.ts +11 -0
- package/src/domain/interfaces/user.repository.interface.ts +75 -0
- package/src/domain/value-objects/email.vo.ts +105 -0
- package/src/domain/value-objects/file-path.vo.ts +184 -0
- package/src/domain/value-objects/user-id.vo.ts +87 -0
- package/src/index.ts +23 -0
- package/src/infrastructure/firebase/auth.adapter.ts +220 -0
- package/src/infrastructure/firebase/client.ts +141 -0
- package/src/infrastructure/firebase/firestore.adapter.ts +190 -0
- package/src/infrastructure/firebase/storage.adapter.ts +323 -0
- package/src/infrastructure/index.ts +13 -0
- package/src/infrastructure/services/firebase.service.ts +30 -0
- package/src/infrastructure/services/firestore.repository.ts +66 -0
- package/src/infrastructure/utils/storage.util.ts +46 -0
- package/src/presentation/hooks/useAuth.ts +153 -0
- package/src/presentation/hooks/useFirebaseAuth.ts +122 -0
- package/src/presentation/hooks/useFirestore.ts +125 -0
- package/src/presentation/hooks/useStorage.ts +141 -0
- package/src/presentation/index.ts +6 -0
- package/src/presentation/providers/FirebaseProvider.tsx +40 -0
|
@@ -0,0 +1,856 @@
|
|
|
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/infrastructure/index.ts
|
|
21
|
+
var infrastructure_exports = {};
|
|
22
|
+
__export(infrastructure_exports, {
|
|
23
|
+
AuthAdapter: () => AuthAdapter,
|
|
24
|
+
FirestoreAdapter: () => FirestoreAdapter,
|
|
25
|
+
StorageAdapter: () => StorageAdapter,
|
|
26
|
+
analytics: () => analytics,
|
|
27
|
+
app: () => app,
|
|
28
|
+
auth: () => auth,
|
|
29
|
+
db: () => db,
|
|
30
|
+
deleteFile: () => deleteFile,
|
|
31
|
+
functions: () => functions,
|
|
32
|
+
getFirebaseAnalytics: () => getFirebaseAnalytics,
|
|
33
|
+
getFirebaseApp: () => getFirebaseApp,
|
|
34
|
+
getFirebaseAuth: () => getFirebaseAuth,
|
|
35
|
+
getFirebaseDB: () => getFirebaseDB,
|
|
36
|
+
getFirebaseFunctions: () => getFirebaseFunctions,
|
|
37
|
+
getFirebaseInstances: () => getFirebaseInstances,
|
|
38
|
+
getFirebaseStorage: () => getFirebaseStorage,
|
|
39
|
+
initializeFirebase: () => initializeFirebase,
|
|
40
|
+
storage: () => storage,
|
|
41
|
+
uploadBase64: () => uploadBase64,
|
|
42
|
+
uploadFile: () => uploadFile
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(infrastructure_exports);
|
|
45
|
+
|
|
46
|
+
// src/infrastructure/firebase/client.ts
|
|
47
|
+
var import_app = require("firebase/app");
|
|
48
|
+
var import_auth = require("firebase/auth");
|
|
49
|
+
var import_firestore = require("firebase/firestore");
|
|
50
|
+
var import_storage = require("firebase/storage");
|
|
51
|
+
var import_analytics = require("firebase/analytics");
|
|
52
|
+
var import_functions = require("firebase/functions");
|
|
53
|
+
var firebaseConfig = {
|
|
54
|
+
apiKey: process.env.VITE_FIREBASE_API_KEY,
|
|
55
|
+
authDomain: process.env.VITE_FIREBASE_AUTH_DOMAIN,
|
|
56
|
+
projectId: process.env.VITE_FIREBASE_PROJECT_ID,
|
|
57
|
+
storageBucket: process.env.VITE_FIREBASE_STORAGE_BUCKET,
|
|
58
|
+
messagingSenderId: process.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
|
|
59
|
+
appId: process.env.VITE_FIREBASE_APP_ID,
|
|
60
|
+
measurementId: process.env.VITE_FIREBASE_MEASUREMENT_ID
|
|
61
|
+
};
|
|
62
|
+
var app;
|
|
63
|
+
var auth;
|
|
64
|
+
var db;
|
|
65
|
+
var storage;
|
|
66
|
+
var functions;
|
|
67
|
+
var analytics = null;
|
|
68
|
+
function initializeFirebase() {
|
|
69
|
+
if (!(0, import_app.getApps)().length) {
|
|
70
|
+
app = (0, import_app.initializeApp)(firebaseConfig);
|
|
71
|
+
} else {
|
|
72
|
+
app = (0, import_app.getApps)()[0];
|
|
73
|
+
}
|
|
74
|
+
return app;
|
|
75
|
+
}
|
|
76
|
+
function getFirebaseApp() {
|
|
77
|
+
return app || initializeFirebase();
|
|
78
|
+
}
|
|
79
|
+
function getFirebaseAuth() {
|
|
80
|
+
if (!auth) {
|
|
81
|
+
const firebaseApp = getFirebaseApp();
|
|
82
|
+
if (typeof window !== "undefined") {
|
|
83
|
+
try {
|
|
84
|
+
auth = (0, import_auth.getAuth)(firebaseApp);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
console.warn("getAuth failed, trying initializeAuth...", e);
|
|
87
|
+
auth = (0, import_auth.initializeAuth)(firebaseApp, {
|
|
88
|
+
persistence: import_auth.browserLocalPersistence
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
auth = (0, import_auth.getAuth)(firebaseApp);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return auth;
|
|
96
|
+
}
|
|
97
|
+
function getFirebaseDB() {
|
|
98
|
+
if (!db) {
|
|
99
|
+
db = (0, import_firestore.getFirestore)(getFirebaseApp());
|
|
100
|
+
}
|
|
101
|
+
return db;
|
|
102
|
+
}
|
|
103
|
+
function getFirebaseStorage() {
|
|
104
|
+
if (!storage) {
|
|
105
|
+
storage = (0, import_storage.getStorage)(getFirebaseApp());
|
|
106
|
+
}
|
|
107
|
+
return storage;
|
|
108
|
+
}
|
|
109
|
+
function getFirebaseFunctions() {
|
|
110
|
+
if (!functions) {
|
|
111
|
+
functions = (0, import_functions.getFunctions)(getFirebaseApp());
|
|
112
|
+
}
|
|
113
|
+
return functions;
|
|
114
|
+
}
|
|
115
|
+
function getFirebaseAnalytics() {
|
|
116
|
+
if (!analytics && typeof window !== "undefined") {
|
|
117
|
+
analytics = (0, import_analytics.getAnalytics)(getFirebaseApp());
|
|
118
|
+
}
|
|
119
|
+
return analytics;
|
|
120
|
+
}
|
|
121
|
+
function getFirebaseInstances() {
|
|
122
|
+
return {
|
|
123
|
+
app: getFirebaseApp(),
|
|
124
|
+
auth: getFirebaseAuth(),
|
|
125
|
+
db: getFirebaseDB(),
|
|
126
|
+
storage: getFirebaseStorage(),
|
|
127
|
+
functions: getFirebaseFunctions(),
|
|
128
|
+
analytics: getFirebaseAnalytics()
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/infrastructure/firebase/auth.adapter.ts
|
|
133
|
+
var import_auth2 = require("firebase/auth");
|
|
134
|
+
var import_auth3 = require("firebase/auth");
|
|
135
|
+
|
|
136
|
+
// src/domain/errors/auth.errors.ts
|
|
137
|
+
var AuthError = class extends Error {
|
|
138
|
+
constructor(message, code, originalError) {
|
|
139
|
+
super(message);
|
|
140
|
+
this.code = code;
|
|
141
|
+
this.originalError = originalError;
|
|
142
|
+
this.name = "AuthError";
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
function createAuthError(code, message, originalError) {
|
|
146
|
+
const defaultMessage = getAuthErrorMessage(code);
|
|
147
|
+
return new AuthError(message || defaultMessage, code, originalError);
|
|
148
|
+
}
|
|
149
|
+
function getAuthErrorMessage(code) {
|
|
150
|
+
switch (code) {
|
|
151
|
+
case "USER_NOT_FOUND" /* USER_NOT_FOUND */:
|
|
152
|
+
return "User not found";
|
|
153
|
+
case "USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */:
|
|
154
|
+
return "User already exists";
|
|
155
|
+
case "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */:
|
|
156
|
+
return "Invalid credentials";
|
|
157
|
+
case "WEAK_PASSWORD" /* WEAK_PASSWORD */:
|
|
158
|
+
return "Password is too weak";
|
|
159
|
+
case "EMAIL_NOT_VERIFIED" /* EMAIL_NOT_VERIFIED */:
|
|
160
|
+
return "Email not verified";
|
|
161
|
+
case "SESSION_EXPIRED" /* SESSION_EXPIRED */:
|
|
162
|
+
return "Session expired";
|
|
163
|
+
case "UNAUTHENTICATED" /* UNAUTHENTICATED */:
|
|
164
|
+
return "User not authenticated";
|
|
165
|
+
case "TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */:
|
|
166
|
+
return "Too many requests";
|
|
167
|
+
case "OAUTH_ERROR" /* OAUTH_ERROR */:
|
|
168
|
+
return "OAuth error occurred";
|
|
169
|
+
case "OAUTH_CANCELLED" /* OAUTH_CANCELLED */:
|
|
170
|
+
return "OAuth cancelled by user";
|
|
171
|
+
case "OAUTH_ACCOUNT_EXISTS" /* OAUTH_ACCOUNT_EXISTS */:
|
|
172
|
+
return "Account already exists with this provider";
|
|
173
|
+
case "SIGN_IN_FAILED" /* SIGN_IN_FAILED */:
|
|
174
|
+
return "Sign in failed";
|
|
175
|
+
case "SIGN_UP_FAILED" /* SIGN_UP_FAILED */:
|
|
176
|
+
return "Sign up failed";
|
|
177
|
+
case "SIGN_OUT_FAILED" /* SIGN_OUT_FAILED */:
|
|
178
|
+
return "Sign out failed";
|
|
179
|
+
case "PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */:
|
|
180
|
+
return "Password reset failed";
|
|
181
|
+
case "EMAIL_VERIFICATION_FAILED" /* EMAIL_VERIFICATION_FAILED */:
|
|
182
|
+
return "Email verification failed";
|
|
183
|
+
case "PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */:
|
|
184
|
+
return "Profile update failed";
|
|
185
|
+
case "EMAIL_UPDATE_FAILED" /* EMAIL_UPDATE_FAILED */:
|
|
186
|
+
return "Email update failed";
|
|
187
|
+
case "PASSWORD_UPDATE_FAILED" /* PASSWORD_UPDATE_FAILED */:
|
|
188
|
+
return "Password update failed";
|
|
189
|
+
case "ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */:
|
|
190
|
+
return "Account deletion failed";
|
|
191
|
+
case "REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */:
|
|
192
|
+
return "Reauthentication required";
|
|
193
|
+
case "REAUTHENTICATION_FAILED" /* REAUTHENTICATION_FAILED */:
|
|
194
|
+
return "Reauthentication failed";
|
|
195
|
+
case "UNKNOWN" /* UNKNOWN */:
|
|
196
|
+
default:
|
|
197
|
+
return "An unknown error occurred";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/infrastructure/firebase/auth.adapter.ts
|
|
202
|
+
var AuthAdapter = class {
|
|
203
|
+
get auth() {
|
|
204
|
+
return getFirebaseAuth();
|
|
205
|
+
}
|
|
206
|
+
// Authentication Methods
|
|
207
|
+
async signIn(email, password) {
|
|
208
|
+
try {
|
|
209
|
+
return await (0, import_auth2.signInWithEmailAndPassword)(this.auth, email, password);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
throw this.handleAuthError(error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async signUp(email, password, displayName) {
|
|
215
|
+
try {
|
|
216
|
+
const result = await (0, import_auth2.createUserWithEmailAndPassword)(this.auth, email, password);
|
|
217
|
+
await (0, import_auth2.updateProfile)(result.user, { displayName });
|
|
218
|
+
await (0, import_auth2.sendEmailVerification)(result.user);
|
|
219
|
+
return result;
|
|
220
|
+
} catch (error) {
|
|
221
|
+
throw this.handleAuthError(error);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async signInWithGoogle() {
|
|
225
|
+
try {
|
|
226
|
+
const provider = new import_auth3.GoogleAuthProvider();
|
|
227
|
+
provider.addScope("profile");
|
|
228
|
+
provider.addScope("email");
|
|
229
|
+
return await (0, import_auth2.signInWithPopup)(this.auth, provider);
|
|
230
|
+
} catch (error) {
|
|
231
|
+
throw this.handleAuthError(error);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async signOut() {
|
|
235
|
+
try {
|
|
236
|
+
await (0, import_auth2.signOut)(this.auth);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
throw createAuthError("SIGN_OUT_FAILED" /* SIGN_OUT_FAILED */, "Sign out failed", error);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async sendPasswordReset(email) {
|
|
242
|
+
try {
|
|
243
|
+
await (0, import_auth2.sendPasswordResetEmail)(this.auth, email);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
throw this.handleAuthError(error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async resendEmailVerification() {
|
|
249
|
+
try {
|
|
250
|
+
const user = this.auth.currentUser;
|
|
251
|
+
if (!user) {
|
|
252
|
+
throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
|
|
253
|
+
}
|
|
254
|
+
await (0, import_auth2.sendEmailVerification)(user);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
throw createAuthError("EMAIL_VERIFICATION_FAILED" /* EMAIL_VERIFICATION_FAILED */, "Failed to resend verification", error);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Profile Management
|
|
260
|
+
async updateProfile(updates) {
|
|
261
|
+
try {
|
|
262
|
+
const user = this.auth.currentUser;
|
|
263
|
+
if (!user) {
|
|
264
|
+
throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
|
|
265
|
+
}
|
|
266
|
+
await (0, import_auth2.updateProfile)(user, updates);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Profile update failed", error);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async updateEmail(newEmail, password) {
|
|
272
|
+
try {
|
|
273
|
+
const user = this.auth.currentUser;
|
|
274
|
+
if (!user || !user.email) {
|
|
275
|
+
throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
|
|
276
|
+
}
|
|
277
|
+
const credential = import_auth2.EmailAuthProvider.credential(user.email, password);
|
|
278
|
+
await (0, import_auth2.reauthenticateWithCredential)(user, credential);
|
|
279
|
+
await (0, import_auth2.updateEmail)(user, newEmail);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
throw createAuthError("EMAIL_UPDATE_FAILED" /* EMAIL_UPDATE_FAILED */, "Email update failed", error);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async updatePassword(currentPassword, newPassword) {
|
|
285
|
+
try {
|
|
286
|
+
const user = this.auth.currentUser;
|
|
287
|
+
if (!user || !user.email) {
|
|
288
|
+
throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
|
|
289
|
+
}
|
|
290
|
+
const credential = import_auth2.EmailAuthProvider.credential(user.email, currentPassword);
|
|
291
|
+
await (0, import_auth2.reauthenticateWithCredential)(user, credential);
|
|
292
|
+
await (0, import_auth2.updatePassword)(user, newPassword);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
throw createAuthError("PASSWORD_UPDATE_FAILED" /* PASSWORD_UPDATE_FAILED */, "Password update failed", error);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
async deleteAccount(password) {
|
|
298
|
+
try {
|
|
299
|
+
const user = this.auth.currentUser;
|
|
300
|
+
if (!user || !user.email) {
|
|
301
|
+
throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
|
|
302
|
+
}
|
|
303
|
+
const credential = import_auth2.EmailAuthProvider.credential(user.email, password);
|
|
304
|
+
await (0, import_auth2.reauthenticateWithCredential)(user, credential);
|
|
305
|
+
await user.delete();
|
|
306
|
+
} catch (error) {
|
|
307
|
+
throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Account deletion failed", error);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// State Management
|
|
311
|
+
getCurrentUser() {
|
|
312
|
+
return this.auth.currentUser;
|
|
313
|
+
}
|
|
314
|
+
onAuthStateChanged(callback) {
|
|
315
|
+
return this.auth.onAuthStateChanged(callback);
|
|
316
|
+
}
|
|
317
|
+
// Note: User document operations should be handled by UserAdapter
|
|
318
|
+
// These methods are part of IAuthRepository interface but should be implemented separately
|
|
319
|
+
async createUserDocument(_userId, _data) {
|
|
320
|
+
throw new Error("createUserDocument should be handled by UserAdapter");
|
|
321
|
+
}
|
|
322
|
+
async updateLastLogin(_userId) {
|
|
323
|
+
throw new Error("updateLastLogin should be handled by UserAdapter");
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Handle Firebase Auth errors
|
|
327
|
+
*/
|
|
328
|
+
handleAuthError(error) {
|
|
329
|
+
if (error instanceof Error && "code" in error) {
|
|
330
|
+
const code = error.code;
|
|
331
|
+
switch (code) {
|
|
332
|
+
case "auth/user-not-found":
|
|
333
|
+
return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "User not found", error);
|
|
334
|
+
case "auth/wrong-password":
|
|
335
|
+
case "auth/invalid-credential":
|
|
336
|
+
return createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid credentials", error);
|
|
337
|
+
case "auth/email-already-in-use":
|
|
338
|
+
return createAuthError("USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */, "Email already in use", error);
|
|
339
|
+
case "auth/weak-password":
|
|
340
|
+
return createAuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, "Password is too weak", error);
|
|
341
|
+
case "auth/invalid-email":
|
|
342
|
+
return createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid email", error);
|
|
343
|
+
case "auth/user-disabled":
|
|
344
|
+
return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "Account disabled", error);
|
|
345
|
+
case "auth/too-many-requests":
|
|
346
|
+
return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many requests", error);
|
|
347
|
+
case "auth/popup-closed-by-user":
|
|
348
|
+
return createAuthError("OAUTH_CANCELLED" /* OAUTH_CANCELLED */, "Sign in cancelled", error);
|
|
349
|
+
case "auth/account-exists-with-different-credential":
|
|
350
|
+
return createAuthError("OAUTH_ACCOUNT_EXISTS" /* OAUTH_ACCOUNT_EXISTS */, "Account exists with different provider", error);
|
|
351
|
+
case "auth/requires-recent-login":
|
|
352
|
+
return createAuthError("REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */, "Please reauthenticate", error);
|
|
353
|
+
default:
|
|
354
|
+
return createAuthError("UNKNOWN" /* UNKNOWN */, `Auth error: ${code}`, error);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return createAuthError("UNKNOWN" /* UNKNOWN */, "Unknown auth error", error);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// src/infrastructure/firebase/firestore.adapter.ts
|
|
362
|
+
var import_firestore2 = require("firebase/firestore");
|
|
363
|
+
|
|
364
|
+
// src/domain/errors/repository.errors.ts
|
|
365
|
+
var RepositoryError = class extends Error {
|
|
366
|
+
constructor(message, code, originalError) {
|
|
367
|
+
super(message);
|
|
368
|
+
this.code = code;
|
|
369
|
+
this.originalError = originalError;
|
|
370
|
+
this.name = "RepositoryError";
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
function createRepositoryError(code, message, originalError) {
|
|
374
|
+
const defaultMessage = getRepositoryErrorMessage(code);
|
|
375
|
+
return new RepositoryError(message || defaultMessage, code, originalError);
|
|
376
|
+
}
|
|
377
|
+
function getRepositoryErrorMessage(code) {
|
|
378
|
+
switch (code) {
|
|
379
|
+
case "DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */:
|
|
380
|
+
return "Document not found";
|
|
381
|
+
case "DOCUMENT_ALREADY_EXISTS" /* DOCUMENT_ALREADY_EXISTS */:
|
|
382
|
+
return "Document already exists";
|
|
383
|
+
case "DOCUMENT_INVALID" /* DOCUMENT_INVALID */:
|
|
384
|
+
return "Document is invalid";
|
|
385
|
+
case "COLLECTION_NOT_FOUND" /* COLLECTION_NOT_FOUND */:
|
|
386
|
+
return "Collection not found";
|
|
387
|
+
case "COLLECTION_INVALID" /* COLLECTION_INVALID */:
|
|
388
|
+
return "Collection is invalid";
|
|
389
|
+
case "QUERY_INVALID" /* QUERY_INVALID */:
|
|
390
|
+
return "Query is invalid";
|
|
391
|
+
case "QUERY_FAILED" /* QUERY_FAILED */:
|
|
392
|
+
return "Query failed";
|
|
393
|
+
case "TRANSACTION_FAILED" /* TRANSACTION_FAILED */:
|
|
394
|
+
return "Transaction failed";
|
|
395
|
+
case "TRANSACTION_ABORTED" /* TRANSACTION_ABORTED */:
|
|
396
|
+
return "Transaction aborted";
|
|
397
|
+
case "NETWORK_ERROR" /* NETWORK_ERROR */:
|
|
398
|
+
return "Network error";
|
|
399
|
+
case "TIMEOUT" /* TIMEOUT */:
|
|
400
|
+
return "Request timeout";
|
|
401
|
+
case "OFFLINE" /* OFFLINE */:
|
|
402
|
+
return "Client is offline";
|
|
403
|
+
case "PERMISSION_DENIED" /* PERMISSION_DENIED */:
|
|
404
|
+
return "Permission denied";
|
|
405
|
+
case "UNAUTHORIZED" /* UNAUTHORIZED */:
|
|
406
|
+
return "Unauthorized";
|
|
407
|
+
case "VALIDATION_FAILED" /* VALIDATION_FAILED */:
|
|
408
|
+
return "Validation failed";
|
|
409
|
+
case "INVALID_DATA" /* INVALID_DATA */:
|
|
410
|
+
return "Invalid data";
|
|
411
|
+
case "CONFLICT" /* CONFLICT */:
|
|
412
|
+
return "Conflict occurred";
|
|
413
|
+
case "VERSION_MISMATCH" /* VERSION_MISMATCH */:
|
|
414
|
+
return "Version mismatch";
|
|
415
|
+
case "STORAGE_ERROR" /* STORAGE_ERROR */:
|
|
416
|
+
return "Storage error";
|
|
417
|
+
case "FILE_NOT_FOUND" /* FILE_NOT_FOUND */:
|
|
418
|
+
return "File not found";
|
|
419
|
+
case "FILE_TOO_LARGE" /* FILE_TOO_LARGE */:
|
|
420
|
+
return "File is too large";
|
|
421
|
+
case "INVALID_FILE_TYPE" /* INVALID_FILE_TYPE */:
|
|
422
|
+
return "Invalid file type";
|
|
423
|
+
case "UNKNOWN" /* UNKNOWN */:
|
|
424
|
+
default:
|
|
425
|
+
return "An unknown error occurred";
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/infrastructure/firebase/firestore.adapter.ts
|
|
430
|
+
var FirestoreAdapter = class {
|
|
431
|
+
get db() {
|
|
432
|
+
return getFirebaseDB();
|
|
433
|
+
}
|
|
434
|
+
USERS_COLLECTION = "users";
|
|
435
|
+
async getUser(userId) {
|
|
436
|
+
try {
|
|
437
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
438
|
+
const snap = await (0, import_firestore2.getDoc)(docRef);
|
|
439
|
+
if (!snap.exists()) {
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
return snap.data();
|
|
443
|
+
} catch (error) {
|
|
444
|
+
throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "User not found", error);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
async getUserByEmail(email) {
|
|
448
|
+
try {
|
|
449
|
+
const q = (0, import_firestore2.query)((0, import_firestore2.collection)(this.db, this.USERS_COLLECTION), (0, import_firestore2.where)("profile.email", "==", email));
|
|
450
|
+
const snap = await (0, import_firestore2.getDocs)(q);
|
|
451
|
+
if (snap.empty) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
const doc2 = snap.docs[0];
|
|
455
|
+
return doc2.data();
|
|
456
|
+
} catch (error) {
|
|
457
|
+
throw createRepositoryError("QUERY_FAILED" /* QUERY_FAILED */, "Failed to query user", error);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
async createUser(userId, data) {
|
|
461
|
+
try {
|
|
462
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
463
|
+
await (0, import_firestore2.setDoc)(docRef, data, { merge: true });
|
|
464
|
+
} catch (error) {
|
|
465
|
+
throw createRepositoryError("DOCUMENT_INVALID" /* DOCUMENT_INVALID */, "Failed to create user", error);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async updateUser(userId, data) {
|
|
469
|
+
try {
|
|
470
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
471
|
+
await (0, import_firestore2.updateDoc)(docRef, {
|
|
472
|
+
...data,
|
|
473
|
+
"profile.updatedAt": Date.now()
|
|
474
|
+
});
|
|
475
|
+
} catch (error) {
|
|
476
|
+
throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update user", error);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
async deleteUser(userId) {
|
|
480
|
+
try {
|
|
481
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
482
|
+
await (0, import_firestore2.deleteDoc)(docRef);
|
|
483
|
+
} catch (error) {
|
|
484
|
+
throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to delete user", error);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
async updateProfile(userId, updates) {
|
|
488
|
+
try {
|
|
489
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
490
|
+
const updateData = {
|
|
491
|
+
"profile.updatedAt": Date.now()
|
|
492
|
+
};
|
|
493
|
+
if (updates.displayName !== void 0) {
|
|
494
|
+
updateData["profile.displayName"] = updates.displayName;
|
|
495
|
+
}
|
|
496
|
+
if (updates.photoURL !== void 0) {
|
|
497
|
+
updateData["profile.photoURL"] = updates.photoURL;
|
|
498
|
+
}
|
|
499
|
+
if (updates.phoneNumber !== void 0) {
|
|
500
|
+
updateData["profile.phoneNumber"] = updates.phoneNumber;
|
|
501
|
+
}
|
|
502
|
+
await (0, import_firestore2.updateDoc)(docRef, updateData);
|
|
503
|
+
} catch (error) {
|
|
504
|
+
throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update profile", error);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
async updateSettings(userId, settings) {
|
|
508
|
+
try {
|
|
509
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
510
|
+
await (0, import_firestore2.updateDoc)(docRef, {
|
|
511
|
+
settings: {
|
|
512
|
+
...settings,
|
|
513
|
+
updatedAt: Date.now()
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
} catch (error) {
|
|
517
|
+
throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update settings", error);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
async updateSubscription(userId, subscription) {
|
|
521
|
+
try {
|
|
522
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
523
|
+
await (0, import_firestore2.updateDoc)(docRef, {
|
|
524
|
+
subscription: {
|
|
525
|
+
...subscription,
|
|
526
|
+
updatedAt: Date.now()
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
} catch (error) {
|
|
530
|
+
throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update subscription", error);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
async updateLastLogin(userId) {
|
|
534
|
+
try {
|
|
535
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
536
|
+
await (0, import_firestore2.updateDoc)(docRef, {
|
|
537
|
+
"profile.lastLoginAt": Date.now()
|
|
538
|
+
});
|
|
539
|
+
} catch (error) {
|
|
540
|
+
throw createRepositoryError("DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */, "Failed to update last login", error);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
async queryUsers(constraints) {
|
|
544
|
+
try {
|
|
545
|
+
const q = (0, import_firestore2.query)((0, import_firestore2.collection)(this.db, this.USERS_COLLECTION), ...constraints);
|
|
546
|
+
const snap = await (0, import_firestore2.getDocs)(q);
|
|
547
|
+
return snap.docs.map((doc2) => doc2.data());
|
|
548
|
+
} catch (error) {
|
|
549
|
+
throw createRepositoryError("QUERY_FAILED" /* QUERY_FAILED */, "Failed to query users", error);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
subscribeToUser(userId, callback, onError) {
|
|
553
|
+
const docRef = (0, import_firestore2.doc)(this.db, this.USERS_COLLECTION, userId);
|
|
554
|
+
const unsubscribe = (0, import_firestore2.onSnapshot)(
|
|
555
|
+
docRef,
|
|
556
|
+
(snap) => {
|
|
557
|
+
if (snap.exists()) {
|
|
558
|
+
callback(snap.data());
|
|
559
|
+
} else {
|
|
560
|
+
callback(null);
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
(error) => {
|
|
564
|
+
onError?.(error);
|
|
565
|
+
}
|
|
566
|
+
);
|
|
567
|
+
return unsubscribe;
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
// src/infrastructure/firebase/storage.adapter.ts
|
|
572
|
+
var import_storage2 = require("firebase/storage");
|
|
573
|
+
var StorageAdapter = class {
|
|
574
|
+
get storage() {
|
|
575
|
+
return getFirebaseStorage();
|
|
576
|
+
}
|
|
577
|
+
// Upload Methods
|
|
578
|
+
async uploadFile(userId, path, file, options) {
|
|
579
|
+
const storageRef = (0, import_storage2.ref)(this.storage, `users/${userId}/${path}`);
|
|
580
|
+
const uploadTask = (0, import_storage2.uploadBytesResumable)(storageRef, file);
|
|
581
|
+
return new Promise((resolve, reject) => {
|
|
582
|
+
uploadTask.on(
|
|
583
|
+
"state_changed",
|
|
584
|
+
(snapshot) => {
|
|
585
|
+
if (options?.onProgress) {
|
|
586
|
+
const progress = {
|
|
587
|
+
bytesTransferred: snapshot.bytesTransferred,
|
|
588
|
+
totalBytes: snapshot.totalBytes,
|
|
589
|
+
progress: snapshot.bytesTransferred / snapshot.totalBytes * 100,
|
|
590
|
+
state: "running"
|
|
591
|
+
};
|
|
592
|
+
options.onProgress(progress);
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
(error) => reject(createRepositoryError("STORAGE_ERROR" /* STORAGE_ERROR */, "Upload failed", error)),
|
|
596
|
+
async () => {
|
|
597
|
+
const downloadURL = await (0, import_storage2.getDownloadURL)(uploadTask.snapshot.ref);
|
|
598
|
+
const metadata = await (0, import_storage2.getMetadata)(uploadTask.snapshot.ref);
|
|
599
|
+
resolve({
|
|
600
|
+
id: uploadTask.snapshot.ref.name,
|
|
601
|
+
name: metadata.name || uploadTask.snapshot.ref.name,
|
|
602
|
+
fullPath: metadata.fullPath || uploadTask.snapshot.ref.fullPath,
|
|
603
|
+
downloadURL,
|
|
604
|
+
contentType: metadata.contentType || "",
|
|
605
|
+
size: metadata.size || 0,
|
|
606
|
+
createdAt: metadata.timeCreated ? new Date(metadata.timeCreated).getTime() : Date.now()
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
);
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
async uploadImage(userId, file, filename) {
|
|
613
|
+
const name = filename || `${Date.now()}_${file.name}`;
|
|
614
|
+
return this.uploadFile(userId, `images/${name}`, file);
|
|
615
|
+
}
|
|
616
|
+
async uploadVideo(userId, file, filename) {
|
|
617
|
+
const name = filename || `${Date.now()}_${file.name}`;
|
|
618
|
+
return this.uploadFile(userId, `videos/${name}`, file);
|
|
619
|
+
}
|
|
620
|
+
async uploadDocument(userId, file, filename) {
|
|
621
|
+
const name = filename || `${Date.now()}_${file.name}`;
|
|
622
|
+
return this.uploadFile(userId, `documents/${name}`, file);
|
|
623
|
+
}
|
|
624
|
+
async uploadProfilePicture(userId, file) {
|
|
625
|
+
const storageRef = (0, import_storage2.ref)(this.storage, `users/${userId}/profile/${Date.now()}_${file.name}`);
|
|
626
|
+
await (0, import_storage2.uploadBytes)(storageRef, file);
|
|
627
|
+
const downloadURL = await (0, import_storage2.getDownloadURL)(storageRef);
|
|
628
|
+
return {
|
|
629
|
+
id: storageRef.name,
|
|
630
|
+
name: file.name,
|
|
631
|
+
fullPath: storageRef.fullPath,
|
|
632
|
+
downloadURL,
|
|
633
|
+
contentType: file.type,
|
|
634
|
+
size: file.size,
|
|
635
|
+
createdAt: Date.now()
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
// Download Methods
|
|
639
|
+
async getDownloadURL(path) {
|
|
640
|
+
try {
|
|
641
|
+
const storageRef = (0, import_storage2.ref)(this.storage, path);
|
|
642
|
+
return await (0, import_storage2.getDownloadURL)(storageRef);
|
|
643
|
+
} catch (error) {
|
|
644
|
+
throw createRepositoryError("FILE_NOT_FOUND" /* FILE_NOT_FOUND */, "File not found", error);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
// Delete Methods
|
|
648
|
+
async deleteFile(path) {
|
|
649
|
+
try {
|
|
650
|
+
const storageRef = (0, import_storage2.ref)(this.storage, path);
|
|
651
|
+
await (0, import_storage2.deleteObject)(storageRef);
|
|
652
|
+
} catch (error) {
|
|
653
|
+
throw createRepositoryError("FILE_NOT_FOUND" /* FILE_NOT_FOUND */, "File not found", error);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
async deleteUserFiles(userId) {
|
|
657
|
+
try {
|
|
658
|
+
const userRef = (0, import_storage2.ref)(this.storage, `users/${userId}`);
|
|
659
|
+
const result = await (0, import_storage2.listAll)(userRef);
|
|
660
|
+
for (const prefix of result.prefixes) {
|
|
661
|
+
const prefixResult = await (0, import_storage2.listAll)(prefix);
|
|
662
|
+
await Promise.all(prefixResult.items.map((item) => (0, import_storage2.deleteObject)(item)));
|
|
663
|
+
}
|
|
664
|
+
await Promise.all(result.items.map((item) => (0, import_storage2.deleteObject)(item)));
|
|
665
|
+
} catch (error) {
|
|
666
|
+
throw createRepositoryError("STORAGE_ERROR" /* STORAGE_ERROR */, "Failed to delete user files", error);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
async deleteImage(userId, filename) {
|
|
670
|
+
await this.deleteFile(`users/${userId}/images/${filename}`);
|
|
671
|
+
}
|
|
672
|
+
async deleteVideo(userId, filename) {
|
|
673
|
+
await this.deleteFile(`users/${userId}/videos/${filename}`);
|
|
674
|
+
}
|
|
675
|
+
async deleteProfilePicture(userId, filename) {
|
|
676
|
+
await this.deleteFile(`users/${userId}/profile/${filename}`);
|
|
677
|
+
}
|
|
678
|
+
// List Methods
|
|
679
|
+
async listUserFiles(userId, path) {
|
|
680
|
+
const userRef = (0, import_storage2.ref)(this.storage, path ? `users/${userId}/${path}` : `users/${userId}`);
|
|
681
|
+
const result = await (0, import_storage2.listAll)(userRef);
|
|
682
|
+
const urls = await Promise.all(result.items.map((item) => (0, import_storage2.getDownloadURL)(item)));
|
|
683
|
+
return urls;
|
|
684
|
+
}
|
|
685
|
+
async listUserImages(userId) {
|
|
686
|
+
return this.listUserFiles(userId, "images");
|
|
687
|
+
}
|
|
688
|
+
async listUserVideos(userId) {
|
|
689
|
+
return this.listUserFiles(userId, "videos");
|
|
690
|
+
}
|
|
691
|
+
// Metadata
|
|
692
|
+
async getFileMetadata(path) {
|
|
693
|
+
try {
|
|
694
|
+
const storageRef = (0, import_storage2.ref)(this.storage, path);
|
|
695
|
+
const metadata = await (0, import_storage2.getMetadata)(storageRef);
|
|
696
|
+
return {
|
|
697
|
+
id: storageRef.name,
|
|
698
|
+
name: metadata.name,
|
|
699
|
+
fullPath: metadata.fullPath,
|
|
700
|
+
contentType: metadata.contentType || "application/octet-stream",
|
|
701
|
+
size: metadata.size,
|
|
702
|
+
createdAt: metadata.timeCreated ? new Date(metadata.timeCreated).getTime() : Date.now(),
|
|
703
|
+
updatedAt: metadata.updated ? new Date(metadata.updated).getTime() : Date.now(),
|
|
704
|
+
userId: this.extractUserId(path) || "unknown",
|
|
705
|
+
type: this.extractFileType(metadata.contentType || "")
|
|
706
|
+
};
|
|
707
|
+
} catch (error) {
|
|
708
|
+
throw createRepositoryError("FILE_NOT_FOUND" /* FILE_NOT_FOUND */, "File not found", error);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
async queryFiles(userId, _filters) {
|
|
712
|
+
const userRef = (0, import_storage2.ref)(this.storage, `users/${userId}`);
|
|
713
|
+
const result = await (0, import_storage2.listAll)(userRef);
|
|
714
|
+
const files = await Promise.all(
|
|
715
|
+
result.items.map(async (item) => {
|
|
716
|
+
const metadata = await (0, import_storage2.getMetadata)(item);
|
|
717
|
+
return {
|
|
718
|
+
id: item.name,
|
|
719
|
+
name: metadata.name,
|
|
720
|
+
fullPath: metadata.fullPath,
|
|
721
|
+
contentType: metadata.contentType || "application/octet-stream",
|
|
722
|
+
size: metadata.size,
|
|
723
|
+
createdAt: metadata.timeCreated ? new Date(metadata.timeCreated).getTime() : Date.now(),
|
|
724
|
+
updatedAt: metadata.updated ? new Date(metadata.updated).getTime() : Date.now(),
|
|
725
|
+
userId,
|
|
726
|
+
type: this.extractFileType(metadata.contentType || "")
|
|
727
|
+
};
|
|
728
|
+
})
|
|
729
|
+
);
|
|
730
|
+
return {
|
|
731
|
+
files,
|
|
732
|
+
totalCount: files.length,
|
|
733
|
+
hasMore: false
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
async getStorageStats(userId) {
|
|
737
|
+
const { files, totalCount } = await this.queryFiles(userId);
|
|
738
|
+
const stats = {
|
|
739
|
+
totalFiles: totalCount,
|
|
740
|
+
totalSize: files.reduce((sum, file) => sum + file.size, 0),
|
|
741
|
+
filesByType: {
|
|
742
|
+
image: 0,
|
|
743
|
+
video: 0,
|
|
744
|
+
audio: 0,
|
|
745
|
+
document: 0,
|
|
746
|
+
other: 0
|
|
747
|
+
},
|
|
748
|
+
filesByCategory: {
|
|
749
|
+
profile: 0,
|
|
750
|
+
content: 0,
|
|
751
|
+
document: 0,
|
|
752
|
+
attachment: 0,
|
|
753
|
+
backup: 0
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
files.forEach((file) => {
|
|
757
|
+
stats.filesByType[file.type]++;
|
|
758
|
+
stats.lastUploadAt = Math.max(stats.lastUploadAt || 0, file.createdAt);
|
|
759
|
+
});
|
|
760
|
+
return stats;
|
|
761
|
+
}
|
|
762
|
+
// Validation
|
|
763
|
+
validateFile(file, options) {
|
|
764
|
+
const maxSizeBytes = options?.maxSizeBytes || (options?.maxSizeMB ? options.maxSizeMB * 1024 * 1024 : 10 * 1024 * 1024);
|
|
765
|
+
if (file.size > maxSizeBytes) {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
if (options?.allowedTypes && !options.allowedTypes.includes(file.type)) {
|
|
769
|
+
return false;
|
|
770
|
+
}
|
|
771
|
+
return true;
|
|
772
|
+
}
|
|
773
|
+
isImageFile(file) {
|
|
774
|
+
return file.type.startsWith("image/");
|
|
775
|
+
}
|
|
776
|
+
isVideoFile(file) {
|
|
777
|
+
return file.type.startsWith("video/");
|
|
778
|
+
}
|
|
779
|
+
isDocumentFile(file) {
|
|
780
|
+
const docTypes = [
|
|
781
|
+
"application/pdf",
|
|
782
|
+
"application/msword",
|
|
783
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
784
|
+
"application/vnd.ms-excel",
|
|
785
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
786
|
+
"text/plain"
|
|
787
|
+
];
|
|
788
|
+
return docTypes.includes(file.type);
|
|
789
|
+
}
|
|
790
|
+
// Utility Methods
|
|
791
|
+
generateUniqueFilename(originalName) {
|
|
792
|
+
const timestamp = Date.now();
|
|
793
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
794
|
+
const extension = this.getFileExtension(originalName);
|
|
795
|
+
return `${timestamp}_${random}.${extension}`;
|
|
796
|
+
}
|
|
797
|
+
getFileExtension(filename) {
|
|
798
|
+
return filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
|
|
799
|
+
}
|
|
800
|
+
// Helper Methods
|
|
801
|
+
extractUserId(path) {
|
|
802
|
+
const match = path.match(/users\/([^\/]+)/);
|
|
803
|
+
return match ? match[1] : "";
|
|
804
|
+
}
|
|
805
|
+
extractFileType(contentType) {
|
|
806
|
+
if (contentType.startsWith("image/")) return "image";
|
|
807
|
+
if (contentType.startsWith("video/")) return "video";
|
|
808
|
+
if (contentType.startsWith("audio/")) return "audio";
|
|
809
|
+
if (contentType.includes("pdf") || contentType.includes("document") || contentType.includes("text")) {
|
|
810
|
+
return "document";
|
|
811
|
+
}
|
|
812
|
+
return "other";
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
// src/infrastructure/utils/storage.util.ts
|
|
817
|
+
var import_storage3 = require("firebase/storage");
|
|
818
|
+
async function uploadFile(storage2, path, file) {
|
|
819
|
+
const storageRef = (0, import_storage3.ref)(storage2, path);
|
|
820
|
+
await (0, import_storage3.uploadBytes)(storageRef, file);
|
|
821
|
+
const url = await (0, import_storage3.getDownloadURL)(storageRef);
|
|
822
|
+
return { url, path };
|
|
823
|
+
}
|
|
824
|
+
async function uploadBase64(storage2, path, base64, mimeType = "image/jpeg") {
|
|
825
|
+
const storageRef = (0, import_storage3.ref)(storage2, path);
|
|
826
|
+
const dataUrl = base64.startsWith("data:") ? base64 : `data:${mimeType};base64,${base64}`;
|
|
827
|
+
await (0, import_storage3.uploadString)(storageRef, dataUrl, "data_url");
|
|
828
|
+
const url = await (0, import_storage3.getDownloadURL)(storageRef);
|
|
829
|
+
return { url, path };
|
|
830
|
+
}
|
|
831
|
+
async function deleteFile(storage2, path) {
|
|
832
|
+
await (0, import_storage3.deleteObject)((0, import_storage3.ref)(storage2, path));
|
|
833
|
+
}
|
|
834
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
835
|
+
0 && (module.exports = {
|
|
836
|
+
AuthAdapter,
|
|
837
|
+
FirestoreAdapter,
|
|
838
|
+
StorageAdapter,
|
|
839
|
+
analytics,
|
|
840
|
+
app,
|
|
841
|
+
auth,
|
|
842
|
+
db,
|
|
843
|
+
deleteFile,
|
|
844
|
+
functions,
|
|
845
|
+
getFirebaseAnalytics,
|
|
846
|
+
getFirebaseApp,
|
|
847
|
+
getFirebaseAuth,
|
|
848
|
+
getFirebaseDB,
|
|
849
|
+
getFirebaseFunctions,
|
|
850
|
+
getFirebaseInstances,
|
|
851
|
+
getFirebaseStorage,
|
|
852
|
+
initializeFirebase,
|
|
853
|
+
storage,
|
|
854
|
+
uploadBase64,
|
|
855
|
+
uploadFile
|
|
856
|
+
});
|