b5-api-client 0.0.24 → 0.0.25

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.
@@ -22,8 +22,9 @@ export declare class UserData {
22
22
  readonly username: string;
23
23
  readonly isEmailVerified: boolean;
24
24
  readonly idToken: string | null;
25
+ readonly isAdmin: boolean;
25
26
  private constructor();
26
- static create(id: string, email: string, username: string, isEmailVerified: boolean, idToken: string | null): UserData;
27
+ static create(id: string, email: string, username: string, isEmailVerified: boolean, idToken: string | null, isAdmin: boolean): UserData;
27
28
  withEmailVerified(): UserData;
28
29
  }
29
30
  export declare class AuthResult {
@@ -32,6 +33,7 @@ export declare class AuthResult {
32
33
  readonly userData: UserData | null;
33
34
  readonly error: string | null;
34
35
  readonly provider: AuthProvider | null;
36
+ readonly isAdmin: boolean;
35
37
  private constructor();
36
38
  static success(user: KioscoinUser, userData: UserData, provider: AuthProvider): AuthResult;
37
39
  static failure(error: string): AuthResult;
@@ -39,35 +39,37 @@ class AuthState {
39
39
  exports.AuthState = AuthState;
40
40
  // Enhanced UserData class with additional safety
41
41
  class UserData {
42
- constructor(id, email, username, isEmailVerified, idToken) {
42
+ constructor(id, email, username, isEmailVerified, idToken, isAdmin) {
43
43
  this.id = id;
44
44
  this.email = email;
45
45
  this.username = username;
46
46
  this.isEmailVerified = isEmailVerified;
47
47
  this.idToken = idToken;
48
+ this.isAdmin = isAdmin;
48
49
  }
49
- static create(id, email, username, isEmailVerified, idToken) {
50
- return new UserData(id, email, username, isEmailVerified, idToken);
50
+ static create(id, email, username, isEmailVerified, idToken, isAdmin) {
51
+ return new UserData(id, email, username, isEmailVerified, idToken, isAdmin);
51
52
  }
52
53
  withEmailVerified() {
53
- return new UserData(this.id, this.email, this.username, true, this.idToken);
54
+ return new UserData(this.id, this.email, this.username, true, this.idToken, this.isAdmin);
54
55
  }
55
56
  }
56
57
  exports.UserData = UserData;
57
58
  // Enhanced AuthResult class
58
59
  class AuthResult {
59
- constructor(success, user, userData, error, provider) {
60
+ constructor(success, user, userData, error, provider, isAdmin) {
60
61
  this.success = success;
61
62
  this.user = user;
62
63
  this.userData = userData;
63
64
  this.error = error;
64
65
  this.provider = provider;
66
+ this.isAdmin = isAdmin;
65
67
  }
66
68
  static success(user, userData, provider) {
67
- return new AuthResult(true, user, userData, null, provider);
69
+ return new AuthResult(true, user, userData, null, provider, userData.isAdmin);
68
70
  }
69
71
  static failure(error) {
70
- return new AuthResult(false, null, null, error, null);
72
+ return new AuthResult(false, null, null, error, null, false);
71
73
  }
72
74
  }
73
75
  exports.AuthResult = AuthResult;
@@ -181,7 +183,8 @@ class FirebaseUnifiedService {
181
183
  id: userCredential.user.uid,
182
184
  username: backendUser.username || '',
183
185
  email: userCredential.user.email || '',
184
- idToken: idToken
186
+ idToken: idToken,
187
+ isAdmin: backendUser.admin || false
185
188
  });
186
189
  return authResult;
187
190
  }
@@ -416,7 +419,7 @@ class FirebaseUnifiedService {
416
419
  }
417
420
  // Helper method to create success AuthResult
418
421
  _createSuccessAuthResult(user, backendUser, provider, idToken) {
419
- const userData = UserData.create(user.uid, user.email || '', backendUser.username || '', user.emailVerified, idToken);
422
+ const userData = UserData.create(user.uid, user.email || '', backendUser.username || '', user.emailVerified, idToken, backendUser.admin || false);
420
423
  return AuthResult.success(backendUser, userData, provider);
421
424
  }
422
425
  // Backend integration methods
@@ -3,6 +3,7 @@ export interface User {
3
3
  username: string;
4
4
  email: string;
5
5
  idToken: string;
6
+ isAdmin: boolean;
6
7
  }
7
8
  export interface UserContext {
8
9
  user: User | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "b5-api-client",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "description": "Escrow Backend API client",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -55,7 +55,8 @@ export class UserData {
55
55
  public readonly email: string,
56
56
  public readonly username: string,
57
57
  public readonly isEmailVerified: boolean,
58
- public readonly idToken: string | null
58
+ public readonly idToken: string | null,
59
+ public readonly isAdmin: boolean
59
60
  ) { }
60
61
 
61
62
  static create(
@@ -63,14 +64,16 @@ export class UserData {
63
64
  email: string,
64
65
  username: string,
65
66
  isEmailVerified: boolean,
66
- idToken: string | null
67
+ idToken: string | null,
68
+ isAdmin: boolean
67
69
  ): UserData {
68
70
  return new UserData(
69
71
  id,
70
72
  email,
71
73
  username,
72
74
  isEmailVerified,
73
- idToken
75
+ idToken,
76
+ isAdmin
74
77
  );
75
78
  }
76
79
 
@@ -80,7 +83,8 @@ export class UserData {
80
83
  this.email,
81
84
  this.username,
82
85
  true,
83
- this.idToken
86
+ this.idToken,
87
+ this.isAdmin
84
88
  );
85
89
  }
86
90
  }
@@ -92,15 +96,16 @@ export class AuthResult {
92
96
  public readonly user: KioscoinUser | null,
93
97
  public readonly userData: UserData | null,
94
98
  public readonly error: string | null,
95
- public readonly provider: AuthProvider | null
99
+ public readonly provider: AuthProvider | null,
100
+ public readonly isAdmin: boolean
96
101
  ) { }
97
102
 
98
103
  static success(user: KioscoinUser, userData: UserData, provider: AuthProvider): AuthResult {
99
- return new AuthResult(true, user, userData, null, provider);
104
+ return new AuthResult(true, user, userData, null, provider, userData.isAdmin);
100
105
  }
101
106
 
102
107
  static failure(error: string): AuthResult {
103
- return new AuthResult(false, null, null, error, null);
108
+ return new AuthResult(false, null, null, error, null, false);
104
109
  }
105
110
  }
106
111
 
@@ -220,7 +225,8 @@ export class FirebaseUnifiedService implements LoginService {
220
225
  id: userCredential.user.uid,
221
226
  username: backendUser.username || '',
222
227
  email: userCredential.user.email || '',
223
- idToken: idToken
228
+ idToken: idToken,
229
+ isAdmin: backendUser.admin || false
224
230
  });
225
231
  return authResult;
226
232
  } else {
@@ -460,7 +466,8 @@ export class FirebaseUnifiedService implements LoginService {
460
466
  user.email || '',
461
467
  backendUser.username || '',
462
468
  user.emailVerified,
463
- idToken
469
+ idToken,
470
+ backendUser.admin || false
464
471
  );
465
472
  return AuthResult.success(backendUser, userData, provider);
466
473
  }
@@ -4,6 +4,7 @@ export interface User {
4
4
  username: string;
5
5
  email: string;
6
6
  idToken: string;
7
+ isAdmin: boolean;
7
8
  }
8
9
 
9
10
  // Define the UserContext interface
@@ -1,496 +0,0 @@
1
- import { initializeApp } from "firebase/app";
2
- import {
3
- getAuth,
4
- signInWithEmailAndPassword,
5
- createUserWithEmailAndPassword,
6
- sendEmailVerification,
7
- sendPasswordResetEmail,
8
- signOut,
9
- User,
10
- GoogleAuthProvider,
11
- FacebookAuthProvider,
12
- TwitterAuthProvider,
13
- signInWithPopup,
14
- isSignInWithEmailLink,
15
- sendSignInLinkToEmail,
16
- signInWithEmailLink,
17
- Auth
18
- } from "firebase/auth";
19
- import { getMessaging, getToken, onMessage, MessagePayload } from "firebase/messaging";
20
- import { CreateUserRequest, KioscoinUser } from "./types";
21
- import P2PMarketplaceAPIClient from "./P2PMarketplaceAPIClient";
22
- import { FirebaseLoginServiceConfig, LoginService } from "./auth/LoginService";
23
- import { userContext } from './auth/UserContext';
24
-
25
-
26
- // Auth provider type for better type safety
27
- export enum AuthProvider {
28
- EMAIL = 'EMAIL',
29
- GOOGLE = 'GOOGLE',
30
- FACEBOOK = 'FACEBOOK',
31
- TWITTER = 'TWITTER'
32
- }
33
-
34
- // Immutable auth state class
35
- export class AuthState {
36
- private constructor(
37
- public readonly isAuthenticated: boolean,
38
- public readonly user: UserData | null,
39
- public readonly provider: AuthProvider | null
40
- ) { }
41
-
42
- static authenticated(user: UserData, provider: AuthProvider): AuthState {
43
- return new AuthState(true, user, provider);
44
- }
45
-
46
- static unauthenticated(): AuthState {
47
- return new AuthState(false, null, null);
48
- }
49
- }
50
-
51
- // Enhanced UserData class with additional safety
52
- export class UserData {
53
- private constructor(
54
- public readonly id: string,
55
- public readonly email: string,
56
- public readonly username: string,
57
- public readonly isEmailVerified: boolean,
58
- public readonly idToken: string | null
59
- ) { }
60
-
61
- static create(
62
- id: string,
63
- email: string,
64
- username: string,
65
- isEmailVerified: boolean,
66
- idToken: string | null
67
- ): UserData {
68
- return new UserData(
69
- id,
70
- email,
71
- username,
72
- isEmailVerified,
73
- idToken
74
- );
75
- }
76
-
77
- withEmailVerified(): UserData {
78
- return new UserData(
79
- this.id,
80
- this.email,
81
- this.username,
82
- true,
83
- this.idToken
84
- );
85
- }
86
- }
87
-
88
- // Enhanced AuthResult class
89
- export class AuthResult {
90
- private constructor(
91
- public readonly success: boolean,
92
- public readonly user: KioscoinUser | null,
93
- public readonly userData: UserData | null,
94
- public readonly error: string | null,
95
- public readonly provider: AuthProvider | null
96
- ) { }
97
-
98
- static success(user: KioscoinUser, userData: UserData, provider: AuthProvider): AuthResult {
99
- return new AuthResult(true, user, userData, null, provider);
100
- }
101
-
102
- static failure(error: string): AuthResult {
103
- return new AuthResult(false, null, null, error, null);
104
- }
105
- }
106
-
107
- export interface FirebaseConfig {
108
- apiKey: string;
109
- authDomain: string;
110
- projectId: string;
111
- storageBucket: string;
112
- messagingSenderId: string;
113
- appId: string;
114
- measurementId?: string;
115
- }
116
-
117
- export class FirebaseUnifiedService implements LoginService {
118
- private app: ReturnType<typeof initializeApp> | null = null;
119
- private messaging: ReturnType<typeof getMessaging> | null = null;
120
- private auth: Auth | null = null;
121
- private readonly actionCodeSettings: { url: string; handleCodeInApp: boolean };
122
- private client: P2PMarketplaceAPIClient;
123
-
124
- constructor(client: P2PMarketplaceAPIClient, config?: FirebaseLoginServiceConfig) {
125
- this.client = client;
126
- this.actionCodeSettings = config?.actionCodeSettings ?? {
127
- url: 'http://localhost:3000/auth/verify-email',
128
- handleCodeInApp: true,
129
- };
130
- this.initializeFirebase();
131
- }
132
-
133
- private async initializeFirebase() {
134
- try {
135
- const firebaseConfig = await this.fetchFirebaseConfig();
136
- this.app = initializeApp(firebaseConfig);
137
- this.auth = getAuth(this.app);
138
- } catch (error) {
139
- console.error("Failed to initialize Firebase app:", error);
140
- }
141
- }
142
-
143
- private async fetchFirebaseConfig(): Promise<FirebaseConfig> {
144
- try {
145
- const response = await this.client.getConfig<{ firebase: FirebaseConfig }>();
146
- return response.config.firebase;
147
- } catch (error) {
148
- console.error("Error fetching Firebase configuration:", error);
149
- throw new Error("Failed to initialize Firebase configuration");
150
- }
151
- }
152
-
153
- // Messaging methods
154
- public async requestNotificationPermission(): Promise<string | null> {
155
- if (!this.app) {
156
- await this.initializeFirebase();
157
- }
158
-
159
- if (!this.messaging) {
160
- console.warn("Messaging is not available");
161
- return null;
162
- }
163
-
164
- try {
165
- const permission = await Notification.requestPermission();
166
- if (permission === "granted") {
167
- const token = await getToken(this.messaging, {
168
- vapidKey: process.env.REACT_APP_FIREBASE_VAPID_KEY,
169
- });
170
- return token;
171
- }
172
- return null;
173
- } catch (error) {
174
- console.error("Failed to get notification token:", error);
175
- return null;
176
- }
177
- }
178
- async fetchToken(): Promise<string | null> {
179
- try {
180
- if (!this.messaging && this.app) {
181
- this.messaging = getMessaging(this.app);
182
- }
183
- if (this.messaging) {
184
- const currentToken = await getToken(this.messaging);
185
- return currentToken;
186
- }
187
- return null;
188
- } catch (error) {
189
- console.error("An error occurred while retrieving token. ", error);
190
- return null;
191
- }
192
- }
193
-
194
- onMessageListener(callback: (payload: any) => void) {
195
- if (!this.messaging && this.app) {
196
- this.messaging = getMessaging(this.app);
197
- }
198
- if (this.messaging) {
199
- onMessage(this.messaging, callback);
200
- } else {
201
- console.error("Messaging is not initialized.");
202
- }
203
- }
204
-
205
- // Authentication methods
206
- async signInWithEmail(email: string, password: string): Promise<AuthResult> {
207
- try {
208
- if (!this.auth) {
209
- console.error("Firebase Auth not initialized");
210
- return AuthResult.failure("Firebase Auth not initialized");
211
- }
212
- const userCredential = await signInWithEmailAndPassword(this.auth, email, password);
213
- const idToken = await userCredential.user.getIdToken();
214
- const backendUser = await this.getUserFromBackend(userCredential.user.uid, idToken);
215
-
216
- if (backendUser) {
217
- const authResult = this._createSuccessAuthResult(userCredential.user, backendUser, AuthProvider.EMAIL, idToken);
218
- // Update UserContext
219
- userContext.setUser({
220
- id: userCredential.user.uid,
221
- username: backendUser.username || '',
222
- email: userCredential.user.email || '',
223
- idToken: idToken
224
- });
225
- return authResult;
226
- } else {
227
- return AuthResult.failure('User not found in backend');
228
- }
229
- } catch (error: any) {
230
- console.error('Detailed error signing in with email:', {
231
- code: error.code,
232
- message: error.message,
233
- fullError: error
234
- });
235
- return AuthResult.failure(error.message || 'Authentication failed');
236
- }
237
- }
238
-
239
- async createUserWithEmail(email: string, password: string, username: string): Promise<AuthResult> {
240
- try {
241
- if (!this.auth) {
242
- return AuthResult.failure("Firebase Auth not initialized");
243
- }
244
-
245
- // First create the user in Firebase
246
- const userCredential = await createUserWithEmailAndPassword(this.auth, email, password);
247
- const user = userCredential.user;
248
- const idToken = await user.getIdToken();
249
- // Send email verification
250
- await sendEmailVerification(user);
251
-
252
- const backendUser = await this.createUserInBackend(user.uid, username, idToken);
253
-
254
- if (backendUser) {
255
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.EMAIL, idToken);
256
- } else {
257
- return AuthResult.failure('Failed to create user in backend');
258
- }
259
- } catch (error: any) {
260
- console.error('Error creating user with email:', error);
261
- return AuthResult.failure(error.message || 'User creation failed');
262
- }
263
- }
264
-
265
- async signInWithGoogle(): Promise<AuthResult> {
266
- try {
267
- if (!this.auth) {
268
- return AuthResult.failure("Firebase Auth not initialized");
269
- }
270
-
271
- const provider = new GoogleAuthProvider();
272
- const userCredential = await signInWithPopup(this.auth, provider);
273
- const user = userCredential.user;
274
-
275
- // Get or create user in your Kotlin backend
276
- const backendUser = await this.getUserFromBackend(user.uid, user.displayName || '');
277
- const idToken = await user.getIdToken();
278
- if (backendUser) {
279
- // Use the new helper method
280
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.GOOGLE, idToken);
281
- } else {
282
- return AuthResult.failure('Failed to get or create user in backend');
283
- }
284
- } catch (error: any) {
285
- console.error('Error signing in with Google:', error);
286
- return AuthResult.failure(error.message || 'Google authentication failed');
287
- }
288
- }
289
-
290
- async signInWithFacebook(): Promise<AuthResult> {
291
- try {
292
- if (!this.auth) {
293
- return AuthResult.failure("Firebase Auth not initialized");
294
- }
295
-
296
- const provider = new FacebookAuthProvider();
297
- const userCredential = await signInWithPopup(this.auth, provider);
298
- const user = userCredential.user;
299
-
300
- // Get or create user in your Kotlin backend
301
- const backendUser = await this.getUserFromBackend(user.uid, user.displayName || '');
302
- const idToken = await user.getIdToken();
303
- if (backendUser) {
304
- // Use the new helper method
305
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.FACEBOOK, idToken);
306
- } else {
307
- return AuthResult.failure('Failed to get or create user in backend');
308
- }
309
- } catch (error: any) {
310
- console.error('Error signing in with Facebook:', error);
311
- return AuthResult.failure(error.message || 'Facebook authentication failed');
312
- }
313
- }
314
-
315
- async signInWithTwitter(): Promise<AuthResult> {
316
- try {
317
- if (!this.auth) {
318
- return AuthResult.failure("Firebase Auth not initialized");
319
- }
320
-
321
- const provider = new TwitterAuthProvider();
322
- const userCredential = await signInWithPopup(this.auth, provider);
323
- const user = userCredential.user;
324
-
325
- // Get or create user in your Kotlin backend
326
- const backendUser = await this.getUserFromBackend(user.uid, user.displayName || '');
327
- const idToken = await user.getIdToken();
328
- if (backendUser) {
329
- // Use the new helper method
330
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.TWITTER, idToken);
331
- } else {
332
- return AuthResult.failure('Failed to get or create user in backend');
333
- }
334
- } catch (error: any) {
335
- console.error('Error signing in with Twitter:', error);
336
- return AuthResult.failure(error.message || 'Twitter authentication failed');
337
- }
338
- }
339
-
340
- async sendEmailVerification(): Promise<boolean> {
341
- try {
342
- if (!this.auth) {
343
- return false;
344
- }
345
-
346
- const user = this.auth.currentUser;
347
- if (user) {
348
- await sendEmailVerification(user);
349
- return true;
350
- }
351
- return false;
352
- } catch (error) {
353
- console.error('Error sending email verification:', error);
354
- return false;
355
- }
356
- }
357
-
358
- async sendPasswordResetEmail(email: string): Promise<boolean> {
359
- try {
360
- if (!this.auth) {
361
- return false;
362
- }
363
-
364
- await sendPasswordResetEmail(this.auth, email);
365
- return true;
366
- } catch (error) {
367
- console.error('Error sending password reset email:', error);
368
- return false;
369
- }
370
- }
371
-
372
- async signOut(): Promise<void> {
373
- try {
374
- if (!this.auth) {
375
- return;
376
- }
377
-
378
- await signOut(this.auth);
379
- // Clear UserContext
380
- userContext.clearUser();
381
- } catch (error) {
382
- console.error('Error signing out:', error);
383
- }
384
- }
385
-
386
- getCurrentUser(): User | null {
387
- if (!this.auth) {
388
- return null;
389
- }
390
- return this.auth.currentUser;
391
- }
392
-
393
- async sendSignInLinkToEmail(email: string): Promise<boolean> {
394
- try {
395
- if (!this.auth) {
396
- return false;
397
- }
398
-
399
- await sendSignInLinkToEmail(this.auth, email, this.actionCodeSettings);
400
- // Save the email locally to use it later when the user clicks the link
401
- window.localStorage.setItem('emailForSignIn', email);
402
- return true;
403
- } catch (error: any) {
404
- console.error('Error sending sign-in link to email:', error);
405
- return false;
406
- }
407
- }
408
-
409
- isSignInWithEmailLink(): boolean {
410
- if (!this.auth) {
411
- return false;
412
- }
413
- return isSignInWithEmailLink(this.auth, window.location.href);
414
- }
415
-
416
- async signInWithEmailLink(email: string): Promise<AuthResult> {
417
- try {
418
- if (!this.auth) {
419
- return AuthResult.failure("Firebase Auth not initialized");
420
- }
421
-
422
- if (!this.isSignInWithEmailLink()) {
423
- return AuthResult.failure("Invalid sign-in link");
424
- }
425
-
426
- const userCredential = await signInWithEmailLink(this.auth, email, window.location.href);
427
- const user = userCredential.user;
428
-
429
- // Clear the email from localStorage
430
- window.localStorage.removeItem('emailForSignIn');
431
-
432
- // Get or create user in your Kotlin backend
433
- const backendUser = await this.getUserFromBackend(user.uid, user.displayName || '');
434
- const idToken = await user.getIdToken();
435
- if (backendUser) {
436
- // Use the new helper method
437
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.EMAIL, idToken);
438
- } else {
439
- return AuthResult.failure('Failed to get or create user in backend');
440
- }
441
- } catch (error: any) {
442
- console.error('Error signing in with email link:', error);
443
- return AuthResult.failure(error.message || 'Email link authentication failed');
444
- }
445
- }
446
-
447
- getEmailForSignIn(): string | null {
448
- return window.localStorage.getItem('emailForSignIn');
449
- }
450
-
451
- // Helper method to create success AuthResult
452
- private _createSuccessAuthResult(
453
- user: User,
454
- backendUser: KioscoinUser,
455
- provider: AuthProvider,
456
- idToken: string
457
- ): AuthResult {
458
- const userData = UserData.create(
459
- user.uid,
460
- user.email || '',
461
- backendUser.username || '',
462
- user.emailVerified,
463
- idToken
464
- );
465
- return AuthResult.success(backendUser, userData, provider);
466
- }
467
-
468
- // Backend integration methods
469
- private async getUserFromBackend(userId: string, loginId: string): Promise<KioscoinUser | null> {
470
- try {
471
- const response = await this.client.getUser(userId, {
472
- Authorization: `Bearer ${loginId}`,
473
- });
474
- return response.users[0];
475
- } catch (error) {
476
- console.error('Error getting user from backend:', error);
477
- return null;
478
- }
479
- }
480
-
481
- private async createUserInBackend(userId: string, username: string, idToken: string): Promise<KioscoinUser | null> {
482
- try {
483
- const createUserRequest: CreateUserRequest = {
484
- id: userId,
485
- username: username
486
- }
487
- const response = await this.client.createUser(createUserRequest, {
488
- Authorization: `Bearer ${idToken}`
489
- });
490
- return response.users[0];
491
- } catch (error) {
492
- console.error('Error creating user in backend:', error);
493
- return null;
494
- }
495
- }
496
- }