@umituz/web-firebase 1.0.5 → 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 +37 -11
- 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/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 +25 -2
- package/src/domain/interfaces/auth.repository.interface.ts +83 -0
- package/src/domain/interfaces/file.repository.interface.ts +143 -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 +19 -4
- 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 +10 -5
- package/src/infrastructure/utils/storage.util.ts +3 -3
- package/src/presentation/hooks/useAuth.ts +153 -0
- package/src/presentation/hooks/useFirestore.ts +125 -0
- package/src/presentation/hooks/useStorage.ts +141 -0
- package/src/presentation/providers/FirebaseProvider.tsx +40 -0
|
@@ -0,0 +1,490 @@
|
|
|
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/application/index.ts
|
|
21
|
+
var application_exports = {};
|
|
22
|
+
__export(application_exports, {
|
|
23
|
+
DeleteAccountUseCase: () => DeleteAccountUseCase,
|
|
24
|
+
ResetPasswordUseCase: () => ResetPasswordUseCase,
|
|
25
|
+
SignInUseCase: () => SignInUseCase,
|
|
26
|
+
SignInWithGoogleUseCase: () => SignInWithGoogleUseCase,
|
|
27
|
+
SignOutUseCase: () => SignOutUseCase,
|
|
28
|
+
SignUpUseCase: () => SignUpUseCase,
|
|
29
|
+
UpdateProfileUseCase: () => UpdateProfileUseCase
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(application_exports);
|
|
32
|
+
|
|
33
|
+
// src/domain/errors/auth.errors.ts
|
|
34
|
+
var AuthError = class extends Error {
|
|
35
|
+
constructor(message, code, originalError) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.code = code;
|
|
38
|
+
this.originalError = originalError;
|
|
39
|
+
this.name = "AuthError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
function createAuthError(code, message, originalError) {
|
|
43
|
+
const defaultMessage = getAuthErrorMessage(code);
|
|
44
|
+
return new AuthError(message || defaultMessage, code, originalError);
|
|
45
|
+
}
|
|
46
|
+
function getAuthErrorMessage(code) {
|
|
47
|
+
switch (code) {
|
|
48
|
+
case "USER_NOT_FOUND" /* USER_NOT_FOUND */:
|
|
49
|
+
return "User not found";
|
|
50
|
+
case "USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */:
|
|
51
|
+
return "User already exists";
|
|
52
|
+
case "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */:
|
|
53
|
+
return "Invalid credentials";
|
|
54
|
+
case "WEAK_PASSWORD" /* WEAK_PASSWORD */:
|
|
55
|
+
return "Password is too weak";
|
|
56
|
+
case "EMAIL_NOT_VERIFIED" /* EMAIL_NOT_VERIFIED */:
|
|
57
|
+
return "Email not verified";
|
|
58
|
+
case "SESSION_EXPIRED" /* SESSION_EXPIRED */:
|
|
59
|
+
return "Session expired";
|
|
60
|
+
case "UNAUTHENTICATED" /* UNAUTHENTICATED */:
|
|
61
|
+
return "User not authenticated";
|
|
62
|
+
case "TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */:
|
|
63
|
+
return "Too many requests";
|
|
64
|
+
case "OAUTH_ERROR" /* OAUTH_ERROR */:
|
|
65
|
+
return "OAuth error occurred";
|
|
66
|
+
case "OAUTH_CANCELLED" /* OAUTH_CANCELLED */:
|
|
67
|
+
return "OAuth cancelled by user";
|
|
68
|
+
case "OAUTH_ACCOUNT_EXISTS" /* OAUTH_ACCOUNT_EXISTS */:
|
|
69
|
+
return "Account already exists with this provider";
|
|
70
|
+
case "SIGN_IN_FAILED" /* SIGN_IN_FAILED */:
|
|
71
|
+
return "Sign in failed";
|
|
72
|
+
case "SIGN_UP_FAILED" /* SIGN_UP_FAILED */:
|
|
73
|
+
return "Sign up failed";
|
|
74
|
+
case "SIGN_OUT_FAILED" /* SIGN_OUT_FAILED */:
|
|
75
|
+
return "Sign out failed";
|
|
76
|
+
case "PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */:
|
|
77
|
+
return "Password reset failed";
|
|
78
|
+
case "EMAIL_VERIFICATION_FAILED" /* EMAIL_VERIFICATION_FAILED */:
|
|
79
|
+
return "Email verification failed";
|
|
80
|
+
case "PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */:
|
|
81
|
+
return "Profile update failed";
|
|
82
|
+
case "EMAIL_UPDATE_FAILED" /* EMAIL_UPDATE_FAILED */:
|
|
83
|
+
return "Email update failed";
|
|
84
|
+
case "PASSWORD_UPDATE_FAILED" /* PASSWORD_UPDATE_FAILED */:
|
|
85
|
+
return "Password update failed";
|
|
86
|
+
case "ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */:
|
|
87
|
+
return "Account deletion failed";
|
|
88
|
+
case "REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */:
|
|
89
|
+
return "Reauthentication required";
|
|
90
|
+
case "REAUTHENTICATION_FAILED" /* REAUTHENTICATION_FAILED */:
|
|
91
|
+
return "Reauthentication failed";
|
|
92
|
+
case "UNKNOWN" /* UNKNOWN */:
|
|
93
|
+
default:
|
|
94
|
+
return "An unknown error occurred";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/application/use-cases/auth/sign-in.use-case.ts
|
|
99
|
+
var SignInUseCase = class {
|
|
100
|
+
constructor(authRepository) {
|
|
101
|
+
this.authRepository = authRepository;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Execute sign in use case
|
|
105
|
+
*/
|
|
106
|
+
async execute(dto) {
|
|
107
|
+
try {
|
|
108
|
+
this.validateDTO(dto);
|
|
109
|
+
const result = await this.authRepository.signIn(dto.email, dto.password);
|
|
110
|
+
return result;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
throw this.handleError(error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Validate DTO
|
|
117
|
+
*/
|
|
118
|
+
validateDTO(dto) {
|
|
119
|
+
if (!dto.email) {
|
|
120
|
+
throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Email is required");
|
|
121
|
+
}
|
|
122
|
+
if (!dto.password) {
|
|
123
|
+
throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Password is required");
|
|
124
|
+
}
|
|
125
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
126
|
+
if (!emailRegex.test(dto.email)) {
|
|
127
|
+
throw createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid email format");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Handle errors
|
|
132
|
+
*/
|
|
133
|
+
handleError(error) {
|
|
134
|
+
if (error instanceof Error) {
|
|
135
|
+
const message = error.message.toLowerCase();
|
|
136
|
+
if (message.includes("user-not-found") || message.includes("invalid-email")) {
|
|
137
|
+
return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "User not found", error);
|
|
138
|
+
}
|
|
139
|
+
if (message.includes("wrong-password") || message.includes("invalid-credential")) {
|
|
140
|
+
return createAuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, "Invalid credentials", error);
|
|
141
|
+
}
|
|
142
|
+
if (message.includes("too-many-requests")) {
|
|
143
|
+
return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many attempts", error);
|
|
144
|
+
}
|
|
145
|
+
if (message.includes("user-disabled")) {
|
|
146
|
+
return createAuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, "Account disabled", error);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return createAuthError("SIGN_IN_FAILED" /* SIGN_IN_FAILED */, "Sign in failed", error);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// src/application/use-cases/auth/sign-up.use-case.ts
|
|
154
|
+
var SignUpUseCase = class {
|
|
155
|
+
constructor(authRepository, userRepository) {
|
|
156
|
+
this.authRepository = authRepository;
|
|
157
|
+
this.userRepository = userRepository;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Execute sign up use case
|
|
161
|
+
*/
|
|
162
|
+
async execute(dto) {
|
|
163
|
+
try {
|
|
164
|
+
this.validateDTO(dto);
|
|
165
|
+
const existingUser = await this.userRepository.getUserByEmail(dto.email);
|
|
166
|
+
if (existingUser) {
|
|
167
|
+
throw createAuthError("USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */, "User already exists");
|
|
168
|
+
}
|
|
169
|
+
const result = await this.authRepository.signUp(dto.email, dto.password, dto.displayName);
|
|
170
|
+
return {
|
|
171
|
+
...result,
|
|
172
|
+
userId: result.user.uid,
|
|
173
|
+
emailVerified: result.user.emailVerified
|
|
174
|
+
};
|
|
175
|
+
} catch (error) {
|
|
176
|
+
throw this.handleError(error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Validate DTO
|
|
181
|
+
*/
|
|
182
|
+
validateDTO(dto) {
|
|
183
|
+
if (!dto.email) {
|
|
184
|
+
throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Email is required");
|
|
185
|
+
}
|
|
186
|
+
if (!dto.password) {
|
|
187
|
+
throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Password is required");
|
|
188
|
+
}
|
|
189
|
+
if (!dto.displayName || dto.displayName.trim().length === 0) {
|
|
190
|
+
throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Display name is required");
|
|
191
|
+
}
|
|
192
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
193
|
+
if (!emailRegex.test(dto.email)) {
|
|
194
|
+
throw createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Invalid email format");
|
|
195
|
+
}
|
|
196
|
+
if (dto.password.length < 6) {
|
|
197
|
+
throw createAuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, "Password must be at least 6 characters");
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Handle errors
|
|
202
|
+
*/
|
|
203
|
+
handleError(error) {
|
|
204
|
+
if (error instanceof Error && "code" in error) {
|
|
205
|
+
const code = error.code;
|
|
206
|
+
if (code === "auth/email-already-in-use") {
|
|
207
|
+
return createAuthError("USER_ALREADY_EXISTS" /* USER_ALREADY_EXISTS */, "Email already in use", error);
|
|
208
|
+
}
|
|
209
|
+
if (code === "auth/invalid-email") {
|
|
210
|
+
return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Invalid email", error);
|
|
211
|
+
}
|
|
212
|
+
if (code === "auth/weak-password") {
|
|
213
|
+
return createAuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, "Password is too weak", error);
|
|
214
|
+
}
|
|
215
|
+
if (code === "auth/operation-not-allowed") {
|
|
216
|
+
return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Email/password accounts not enabled", error);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return createAuthError("SIGN_UP_FAILED" /* SIGN_UP_FAILED */, "Sign up failed", error);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// src/application/use-cases/auth/sign-in-with-google.use-case.ts
|
|
224
|
+
var SignInWithGoogleUseCase = class {
|
|
225
|
+
constructor(authRepository, userRepository) {
|
|
226
|
+
this.authRepository = authRepository;
|
|
227
|
+
this.userRepository = userRepository;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Execute Google sign in use case
|
|
231
|
+
*/
|
|
232
|
+
async execute() {
|
|
233
|
+
try {
|
|
234
|
+
const result = await this.authRepository.signInWithGoogle();
|
|
235
|
+
const existingUser = await this.userRepository.getUser(result.user.uid);
|
|
236
|
+
if (!existingUser) {
|
|
237
|
+
const createUserDTO = {
|
|
238
|
+
id: result.user.uid,
|
|
239
|
+
email: result.user.email || "",
|
|
240
|
+
displayName: result.user.displayName || "",
|
|
241
|
+
photoURL: result.user.photoURL || void 0,
|
|
242
|
+
phoneNumber: result.user.phoneNumber || void 0,
|
|
243
|
+
emailVerified: result.user.emailVerified
|
|
244
|
+
};
|
|
245
|
+
await this.authRepository.createUserDocument(result.user.uid, createUserDTO);
|
|
246
|
+
}
|
|
247
|
+
return result;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
throw this.handleError(error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Handle errors
|
|
254
|
+
*/
|
|
255
|
+
handleError(error) {
|
|
256
|
+
if (error instanceof Error && "code" in error) {
|
|
257
|
+
const code = error.code;
|
|
258
|
+
if (code === "auth/popup-closed-by-user") {
|
|
259
|
+
return createAuthError("OAUTH_CANCELLED" /* OAUTH_CANCELLED */, "Google sign in cancelled", error);
|
|
260
|
+
}
|
|
261
|
+
if (code === "auth/popup-blocked") {
|
|
262
|
+
return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Popup blocked by browser", error);
|
|
263
|
+
}
|
|
264
|
+
if (code === "auth/account-exists-with-different-credential") {
|
|
265
|
+
return createAuthError(
|
|
266
|
+
"OAUTH_ACCOUNT_EXISTS" /* OAUTH_ACCOUNT_EXISTS */,
|
|
267
|
+
"Account already exists with different credential",
|
|
268
|
+
error
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
if (code === "auth/auth-domain-policy-required") {
|
|
272
|
+
return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Auth domain not configured", error);
|
|
273
|
+
}
|
|
274
|
+
if (code === "auth/unauthorized-domain") {
|
|
275
|
+
return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Unauthorized domain", error);
|
|
276
|
+
}
|
|
277
|
+
if (code === "auth/cancelled-popup-request") {
|
|
278
|
+
return createAuthError("OAUTH_CANCELLED" /* OAUTH_CANCELLED */, "Sign in cancelled", error);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return createAuthError("OAUTH_ERROR" /* OAUTH_ERROR */, "Google sign in failed", error);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// src/application/use-cases/auth/reset-password.use-case.ts
|
|
286
|
+
var ResetPasswordUseCase = class {
|
|
287
|
+
constructor(authRepository) {
|
|
288
|
+
this.authRepository = authRepository;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Execute password reset use case
|
|
292
|
+
*/
|
|
293
|
+
async execute(dto) {
|
|
294
|
+
try {
|
|
295
|
+
this.validateDTO(dto);
|
|
296
|
+
await this.authRepository.sendPasswordReset(dto.email);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
throw this.handleError(error);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Validate DTO
|
|
303
|
+
*/
|
|
304
|
+
validateDTO(dto) {
|
|
305
|
+
if (!dto.email) {
|
|
306
|
+
throw createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Email is required");
|
|
307
|
+
}
|
|
308
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
309
|
+
if (!emailRegex.test(dto.email)) {
|
|
310
|
+
throw createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Invalid email format");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Handle errors
|
|
315
|
+
*/
|
|
316
|
+
handleError(error) {
|
|
317
|
+
if (error instanceof Error && "code" in error) {
|
|
318
|
+
const code = error.code;
|
|
319
|
+
if (code === "auth/invalid-email") {
|
|
320
|
+
return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Invalid email", error);
|
|
321
|
+
}
|
|
322
|
+
if (code === "auth/user-not-found") {
|
|
323
|
+
return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Password reset email sent if account exists");
|
|
324
|
+
}
|
|
325
|
+
if (code === "auth/too-many-requests") {
|
|
326
|
+
return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many requests", error);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return createAuthError("PASSWORD_RESET_FAILED" /* PASSWORD_RESET_FAILED */, "Password reset failed", error);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// src/application/use-cases/auth/sign-out.use-case.ts
|
|
334
|
+
var SignOutUseCase = class {
|
|
335
|
+
constructor(authRepository) {
|
|
336
|
+
this.authRepository = authRepository;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Execute sign out use case
|
|
340
|
+
*/
|
|
341
|
+
async execute() {
|
|
342
|
+
try {
|
|
343
|
+
await this.authRepository.signOut();
|
|
344
|
+
} catch (error) {
|
|
345
|
+
throw createAuthError("SIGN_OUT_FAILED" /* SIGN_OUT_FAILED */, "Sign out failed", error);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// src/application/use-cases/user/update-profile.use-case.ts
|
|
351
|
+
var UpdateProfileUseCase = class {
|
|
352
|
+
constructor(authRepository) {
|
|
353
|
+
this.authRepository = authRepository;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Execute profile update use case
|
|
357
|
+
*/
|
|
358
|
+
async execute(dto) {
|
|
359
|
+
try {
|
|
360
|
+
this.validateDTO(dto);
|
|
361
|
+
const currentUser = this.authRepository.getCurrentUser();
|
|
362
|
+
if (!currentUser) {
|
|
363
|
+
throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
|
|
364
|
+
}
|
|
365
|
+
await this.authRepository.updateProfile(dto);
|
|
366
|
+
} catch (error) {
|
|
367
|
+
throw this.handleError(error);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Validate DTO
|
|
372
|
+
*/
|
|
373
|
+
validateDTO(dto) {
|
|
374
|
+
if (!dto.displayName && !dto.photoURL) {
|
|
375
|
+
throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "At least one field must be provided");
|
|
376
|
+
}
|
|
377
|
+
if (dto.displayName !== void 0) {
|
|
378
|
+
if (typeof dto.displayName !== "string") {
|
|
379
|
+
throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name must be a string");
|
|
380
|
+
}
|
|
381
|
+
if (dto.displayName.trim().length === 0) {
|
|
382
|
+
throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name cannot be empty");
|
|
383
|
+
}
|
|
384
|
+
if (dto.displayName.length > 100) {
|
|
385
|
+
throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Display name too long (max 100 characters)");
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (dto.photoURL !== void 0 && dto.photoURL !== null) {
|
|
389
|
+
if (typeof dto.photoURL !== "string") {
|
|
390
|
+
throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Photo URL must be a string");
|
|
391
|
+
}
|
|
392
|
+
if (dto.photoURL && !this.isValidURL(dto.photoURL)) {
|
|
393
|
+
throw createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Invalid photo URL");
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Validate URL format
|
|
399
|
+
*/
|
|
400
|
+
isValidURL(url) {
|
|
401
|
+
try {
|
|
402
|
+
new URL(url);
|
|
403
|
+
return true;
|
|
404
|
+
} catch {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Handle errors
|
|
410
|
+
*/
|
|
411
|
+
handleError(error) {
|
|
412
|
+
if (error instanceof Error && "code" in error) {
|
|
413
|
+
const code = error.code;
|
|
414
|
+
if (code === "auth/requires-recent-login") {
|
|
415
|
+
return createAuthError("REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */, "Please reauthenticate first", error);
|
|
416
|
+
}
|
|
417
|
+
if (code === "auth/invalid-photo-url") {
|
|
418
|
+
return createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Invalid photo URL", error);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return createAuthError("PROFILE_UPDATE_FAILED" /* PROFILE_UPDATE_FAILED */, "Profile update failed", error);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// src/application/use-cases/user/delete-account.use-case.ts
|
|
426
|
+
var DeleteAccountUseCase = class {
|
|
427
|
+
constructor(authRepository) {
|
|
428
|
+
this.authRepository = authRepository;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Execute account deletion use case
|
|
432
|
+
*/
|
|
433
|
+
async execute(dto) {
|
|
434
|
+
try {
|
|
435
|
+
this.validateDTO(dto);
|
|
436
|
+
const currentUser = this.authRepository.getCurrentUser();
|
|
437
|
+
if (!currentUser) {
|
|
438
|
+
throw createAuthError("UNAUTHENTICATED" /* UNAUTHENTICATED */, "No user logged in");
|
|
439
|
+
}
|
|
440
|
+
if (!currentUser.email) {
|
|
441
|
+
throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "User email not available");
|
|
442
|
+
}
|
|
443
|
+
await this.authRepository.deleteAccount(dto.password);
|
|
444
|
+
} catch (error) {
|
|
445
|
+
throw this.handleError(error);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Validate DTO
|
|
450
|
+
*/
|
|
451
|
+
validateDTO(dto) {
|
|
452
|
+
if (!dto.password) {
|
|
453
|
+
throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Password is required");
|
|
454
|
+
}
|
|
455
|
+
if (dto.password.length < 1) {
|
|
456
|
+
throw createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Password cannot be empty");
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Handle errors
|
|
461
|
+
*/
|
|
462
|
+
handleError(error) {
|
|
463
|
+
if (error instanceof Error && "code" in error) {
|
|
464
|
+
const code = error.code;
|
|
465
|
+
if (code === "auth/requires-recent-login") {
|
|
466
|
+
return createAuthError("REAUTHENTICATION_REQUIRED" /* REAUTHENTICATION_REQUIRED */, "Please reauthenticate first", error);
|
|
467
|
+
}
|
|
468
|
+
if (code === "auth/wrong-password") {
|
|
469
|
+
return createAuthError("REAUTHENTICATION_FAILED" /* REAUTHENTICATION_FAILED */, "Invalid password", error);
|
|
470
|
+
}
|
|
471
|
+
if (code === "auth/too-many-requests") {
|
|
472
|
+
return createAuthError("TOO_MANY_REQUESTS" /* TOO_MANY_REQUESTS */, "Too many requests", error);
|
|
473
|
+
}
|
|
474
|
+
if (code === "auth/user-not-found") {
|
|
475
|
+
return createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "User not found", error);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return createAuthError("ACCOUNT_DELETE_FAILED" /* ACCOUNT_DELETE_FAILED */, "Account deletion failed", error);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
482
|
+
0 && (module.exports = {
|
|
483
|
+
DeleteAccountUseCase,
|
|
484
|
+
ResetPasswordUseCase,
|
|
485
|
+
SignInUseCase,
|
|
486
|
+
SignInWithGoogleUseCase,
|
|
487
|
+
SignOutUseCase,
|
|
488
|
+
SignUpUseCase,
|
|
489
|
+
UpdateProfileUseCase
|
|
490
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeleteAccountUseCase,
|
|
3
|
+
ResetPasswordUseCase,
|
|
4
|
+
SignInUseCase,
|
|
5
|
+
SignInWithGoogleUseCase,
|
|
6
|
+
SignOutUseCase,
|
|
7
|
+
SignUpUseCase,
|
|
8
|
+
UpdateProfileUseCase
|
|
9
|
+
} from "../chunk-U2XI4MGO.mjs";
|
|
10
|
+
import "../chunk-RZ4QR6TB.mjs";
|
|
11
|
+
export {
|
|
12
|
+
DeleteAccountUseCase,
|
|
13
|
+
ResetPasswordUseCase,
|
|
14
|
+
SignInUseCase,
|
|
15
|
+
SignInWithGoogleUseCase,
|
|
16
|
+
SignOutUseCase,
|
|
17
|
+
SignUpUseCase,
|
|
18
|
+
UpdateProfileUseCase
|
|
19
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/presentation/hooks/useFirebaseAuth.ts
|
|
2
|
+
import { useState, useEffect, useCallback } from "react";
|
|
3
|
+
import {
|
|
4
|
+
onAuthStateChanged,
|
|
5
|
+
signInWithEmailAndPassword,
|
|
6
|
+
createUserWithEmailAndPassword,
|
|
7
|
+
signOut as firebaseSignOut,
|
|
8
|
+
updateProfile,
|
|
9
|
+
updatePassword,
|
|
10
|
+
sendPasswordResetEmail
|
|
11
|
+
} from "firebase/auth";
|
|
12
|
+
function mapUser(u) {
|
|
13
|
+
return {
|
|
14
|
+
uid: u.uid,
|
|
15
|
+
email: u.email,
|
|
16
|
+
displayName: u.displayName,
|
|
17
|
+
photoURL: u.photoURL,
|
|
18
|
+
emailVerified: u.emailVerified
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function useFirebaseAuth(auth, options) {
|
|
22
|
+
const [user, setUser] = useState(null);
|
|
23
|
+
const [loading, setLoading] = useState(true);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const unsub = onAuthStateChanged(auth, (firebaseUser) => {
|
|
26
|
+
const mapped = firebaseUser ? mapUser(firebaseUser) : null;
|
|
27
|
+
setUser(mapped);
|
|
28
|
+
setLoading(false);
|
|
29
|
+
options?.onUserChange?.(mapped);
|
|
30
|
+
});
|
|
31
|
+
return unsub;
|
|
32
|
+
}, [auth, options]);
|
|
33
|
+
const signIn = useCallback(
|
|
34
|
+
(email, password) => signInWithEmailAndPassword(auth, email, password),
|
|
35
|
+
[auth]
|
|
36
|
+
);
|
|
37
|
+
const signUp = useCallback(
|
|
38
|
+
async (email, password, name) => {
|
|
39
|
+
const cred = await createUserWithEmailAndPassword(auth, email, password);
|
|
40
|
+
if (name && cred.user) await updateProfile(cred.user, { displayName: name });
|
|
41
|
+
return cred;
|
|
42
|
+
},
|
|
43
|
+
[auth]
|
|
44
|
+
);
|
|
45
|
+
const signOut = useCallback(() => firebaseSignOut(auth), [auth]);
|
|
46
|
+
const updateUserProfile = useCallback(
|
|
47
|
+
async (name, photoURL) => {
|
|
48
|
+
if (!auth.currentUser) throw new Error("No authenticated user");
|
|
49
|
+
await updateProfile(auth.currentUser, {
|
|
50
|
+
displayName: name,
|
|
51
|
+
...photoURL !== void 0 && { photoURL }
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
[auth]
|
|
55
|
+
);
|
|
56
|
+
const updateUserPassword = useCallback(
|
|
57
|
+
async (newPassword) => {
|
|
58
|
+
if (!auth.currentUser) throw new Error("No authenticated user");
|
|
59
|
+
await updatePassword(auth.currentUser, newPassword);
|
|
60
|
+
},
|
|
61
|
+
[auth]
|
|
62
|
+
);
|
|
63
|
+
const resetPassword = useCallback(
|
|
64
|
+
(email) => sendPasswordResetEmail(auth, email),
|
|
65
|
+
[auth]
|
|
66
|
+
);
|
|
67
|
+
const getIdToken = useCallback(async () => {
|
|
68
|
+
if (!auth.currentUser) throw new Error("No authenticated user");
|
|
69
|
+
return auth.currentUser.getIdToken();
|
|
70
|
+
}, [auth]);
|
|
71
|
+
return {
|
|
72
|
+
user,
|
|
73
|
+
loading,
|
|
74
|
+
isAuthenticated: !!user,
|
|
75
|
+
signIn,
|
|
76
|
+
signUp,
|
|
77
|
+
signOut,
|
|
78
|
+
updateUserProfile,
|
|
79
|
+
updateUserPassword,
|
|
80
|
+
resetPassword,
|
|
81
|
+
getIdToken
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
useFirebaseAuth
|
|
87
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/domain/errors/repository.errors.ts
|
|
2
|
+
var RepositoryError = class extends Error {
|
|
3
|
+
constructor(message, code, originalError) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.originalError = originalError;
|
|
7
|
+
this.name = "RepositoryError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var RepositoryErrorCode = /* @__PURE__ */ ((RepositoryErrorCode2) => {
|
|
11
|
+
RepositoryErrorCode2["DOCUMENT_NOT_FOUND"] = "DOCUMENT_NOT_FOUND";
|
|
12
|
+
RepositoryErrorCode2["DOCUMENT_ALREADY_EXISTS"] = "DOCUMENT_ALREADY_EXISTS";
|
|
13
|
+
RepositoryErrorCode2["DOCUMENT_INVALID"] = "DOCUMENT_INVALID";
|
|
14
|
+
RepositoryErrorCode2["COLLECTION_NOT_FOUND"] = "COLLECTION_NOT_FOUND";
|
|
15
|
+
RepositoryErrorCode2["COLLECTION_INVALID"] = "COLLECTION_INVALID";
|
|
16
|
+
RepositoryErrorCode2["QUERY_INVALID"] = "QUERY_INVALID";
|
|
17
|
+
RepositoryErrorCode2["QUERY_FAILED"] = "QUERY_FAILED";
|
|
18
|
+
RepositoryErrorCode2["TRANSACTION_FAILED"] = "TRANSACTION_FAILED";
|
|
19
|
+
RepositoryErrorCode2["TRANSACTION_ABORTED"] = "TRANSACTION_ABORTED";
|
|
20
|
+
RepositoryErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
21
|
+
RepositoryErrorCode2["TIMEOUT"] = "TIMEOUT";
|
|
22
|
+
RepositoryErrorCode2["OFFLINE"] = "OFFLINE";
|
|
23
|
+
RepositoryErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
|
|
24
|
+
RepositoryErrorCode2["UNAUTHORIZED"] = "UNAUTHORIZED";
|
|
25
|
+
RepositoryErrorCode2["VALIDATION_FAILED"] = "VALIDATION_FAILED";
|
|
26
|
+
RepositoryErrorCode2["INVALID_DATA"] = "INVALID_DATA";
|
|
27
|
+
RepositoryErrorCode2["CONFLICT"] = "CONFLICT";
|
|
28
|
+
RepositoryErrorCode2["VERSION_MISMATCH"] = "VERSION_MISMATCH";
|
|
29
|
+
RepositoryErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
|
|
30
|
+
RepositoryErrorCode2["FILE_NOT_FOUND"] = "FILE_NOT_FOUND";
|
|
31
|
+
RepositoryErrorCode2["FILE_TOO_LARGE"] = "FILE_TOO_LARGE";
|
|
32
|
+
RepositoryErrorCode2["INVALID_FILE_TYPE"] = "INVALID_FILE_TYPE";
|
|
33
|
+
RepositoryErrorCode2["UNKNOWN"] = "UNKNOWN";
|
|
34
|
+
return RepositoryErrorCode2;
|
|
35
|
+
})(RepositoryErrorCode || {});
|
|
36
|
+
function createRepositoryError(code, message, originalError) {
|
|
37
|
+
const defaultMessage = getRepositoryErrorMessage(code);
|
|
38
|
+
return new RepositoryError(message || defaultMessage, code, originalError);
|
|
39
|
+
}
|
|
40
|
+
function getRepositoryErrorMessage(code) {
|
|
41
|
+
switch (code) {
|
|
42
|
+
case "DOCUMENT_NOT_FOUND" /* DOCUMENT_NOT_FOUND */:
|
|
43
|
+
return "Document not found";
|
|
44
|
+
case "DOCUMENT_ALREADY_EXISTS" /* DOCUMENT_ALREADY_EXISTS */:
|
|
45
|
+
return "Document already exists";
|
|
46
|
+
case "DOCUMENT_INVALID" /* DOCUMENT_INVALID */:
|
|
47
|
+
return "Document is invalid";
|
|
48
|
+
case "COLLECTION_NOT_FOUND" /* COLLECTION_NOT_FOUND */:
|
|
49
|
+
return "Collection not found";
|
|
50
|
+
case "COLLECTION_INVALID" /* COLLECTION_INVALID */:
|
|
51
|
+
return "Collection is invalid";
|
|
52
|
+
case "QUERY_INVALID" /* QUERY_INVALID */:
|
|
53
|
+
return "Query is invalid";
|
|
54
|
+
case "QUERY_FAILED" /* QUERY_FAILED */:
|
|
55
|
+
return "Query failed";
|
|
56
|
+
case "TRANSACTION_FAILED" /* TRANSACTION_FAILED */:
|
|
57
|
+
return "Transaction failed";
|
|
58
|
+
case "TRANSACTION_ABORTED" /* TRANSACTION_ABORTED */:
|
|
59
|
+
return "Transaction aborted";
|
|
60
|
+
case "NETWORK_ERROR" /* NETWORK_ERROR */:
|
|
61
|
+
return "Network error";
|
|
62
|
+
case "TIMEOUT" /* TIMEOUT */:
|
|
63
|
+
return "Request timeout";
|
|
64
|
+
case "OFFLINE" /* OFFLINE */:
|
|
65
|
+
return "Client is offline";
|
|
66
|
+
case "PERMISSION_DENIED" /* PERMISSION_DENIED */:
|
|
67
|
+
return "Permission denied";
|
|
68
|
+
case "UNAUTHORIZED" /* UNAUTHORIZED */:
|
|
69
|
+
return "Unauthorized";
|
|
70
|
+
case "VALIDATION_FAILED" /* VALIDATION_FAILED */:
|
|
71
|
+
return "Validation failed";
|
|
72
|
+
case "INVALID_DATA" /* INVALID_DATA */:
|
|
73
|
+
return "Invalid data";
|
|
74
|
+
case "CONFLICT" /* CONFLICT */:
|
|
75
|
+
return "Conflict occurred";
|
|
76
|
+
case "VERSION_MISMATCH" /* VERSION_MISMATCH */:
|
|
77
|
+
return "Version mismatch";
|
|
78
|
+
case "STORAGE_ERROR" /* STORAGE_ERROR */:
|
|
79
|
+
return "Storage error";
|
|
80
|
+
case "FILE_NOT_FOUND" /* FILE_NOT_FOUND */:
|
|
81
|
+
return "File not found";
|
|
82
|
+
case "FILE_TOO_LARGE" /* FILE_TOO_LARGE */:
|
|
83
|
+
return "File is too large";
|
|
84
|
+
case "INVALID_FILE_TYPE" /* INVALID_FILE_TYPE */:
|
|
85
|
+
return "Invalid file type";
|
|
86
|
+
case "UNKNOWN" /* UNKNOWN */:
|
|
87
|
+
default:
|
|
88
|
+
return "An unknown error occurred";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
RepositoryError,
|
|
94
|
+
RepositoryErrorCode,
|
|
95
|
+
createRepositoryError
|
|
96
|
+
};
|