b5-api-client 0.0.27 → 0.0.29

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.
@@ -1,8 +1,8 @@
1
- import { CreateOrderRequest, CreateUserRequest, Order, OrderResponse, TakeOrderRequest, TestEventParams, UpdateOrderRequest, TransactionStatusResponse, RateUserRequest, OrderEventsResponse, PushNotificationsRegisterRequest, ConfigResponse, DashboardMetricsResponse, UsersResponse, GetOrdersParams, CreateDisputeRequest, DisputesResponse, OrderOffersResponse, TransactionRequest, KioscoinOperationResponse, UpdateUserSettingsRequest, NotificationsResponse, VerifyEmailRequest } from './types';
2
- export interface AuthTokenProvider {
3
- getToken(): Promise<string | null>;
4
- refreshToken(): Promise<string | null>;
5
- onRefreshFailure?(error: unknown): void;
1
+ import { AxiosRequestConfig } from 'axios';
2
+ import { CreateOrderRequest, CreateUserRequest, Order, OrderResponse, TakeOrderRequest, TestEventParams, UpdateOrderRequest, TransactionStatusResponse, RateUserRequest, OrderEventsResponse, PushNotificationsRegisterRequest, ConfigResponse, DashboardMetricsResponse, UsersResponse, GetOrdersParams, CreateDisputeRequest, DisputesResponse, OrderOffersResponse, TransactionRequest, KioscoinOperationResponse, UpdateUserSettingsRequest, NotificationsResponse, VerifyEmailRequest, CreateSessionRequest, CreateSessionResponse } from './types';
3
+ import { AuthTokenProvider } from './auth/AuthTokenProvider';
4
+ export interface RequestConfigWithRetry extends AxiosRequestConfig {
5
+ _retry?: boolean;
6
6
  }
7
7
  declare class P2PMarketplaceAPIClient {
8
8
  private readonly client;
@@ -37,5 +37,22 @@ declare class P2PMarketplaceAPIClient {
37
37
  releaseFunds(order: Order, testParams?: TestEventParams, headers?: Record<string, string>): Promise<string>;
38
38
  getTransactionStatus(txHash: string, headers?: Record<string, string>): Promise<TransactionStatusResponse>;
39
39
  createDispute(request: CreateDisputeRequest, headers?: Record<string, string>): Promise<DisputesResponse>;
40
+ /**
41
+ * Create or refresh a session with Firebase ID token
42
+ * Sets a session cookie that will be used for WebSocket authentication
43
+ */
44
+ createSession(request: CreateSessionRequest, headers?: Record<string, string>): Promise<CreateSessionResponse>;
45
+ /**
46
+ * Check if the current session is valid
47
+ * Returns session status and userId if valid
48
+ */
49
+ getSessionStatus(headers?: Record<string, string>): Promise<CreateSessionResponse>;
50
+ /**
51
+ * Clear the session cookie (logout)
52
+ * Destroys the session on the backend
53
+ */
54
+ clearSession(headers?: Record<string, string>): Promise<{
55
+ success: boolean;
56
+ }>;
40
57
  }
41
58
  export default P2PMarketplaceAPIClient;
@@ -19,6 +19,7 @@ class P2PMarketplaceAPIClient {
19
19
  this.client = axios_1.default.create({
20
20
  baseURL,
21
21
  timeout,
22
+ withCredentials: true, // Enable sending/receiving cookies
22
23
  });
23
24
  this.defaultHeaders = {
24
25
  'x-api-secret': 'test',
@@ -307,6 +308,45 @@ class P2PMarketplaceAPIClient {
307
308
  return this.post(url, request, headers);
308
309
  });
309
310
  }
311
+ // Session Management
312
+ /**
313
+ * Create or refresh a session with Firebase ID token
314
+ * Sets a session cookie that will be used for WebSocket authentication
315
+ */
316
+ createSession(request, headers) {
317
+ return __awaiter(this, void 0, void 0, function* () {
318
+ const url = '/api/session';
319
+ return this.post(url, request, headers);
320
+ });
321
+ }
322
+ /**
323
+ * Check if the current session is valid
324
+ * Returns session status and userId if valid
325
+ */
326
+ getSessionStatus(headers) {
327
+ return __awaiter(this, void 0, void 0, function* () {
328
+ const url = '/api/session';
329
+ return this.get(url, headers);
330
+ });
331
+ }
332
+ /**
333
+ * Clear the session cookie (logout)
334
+ * Destroys the session on the backend
335
+ */
336
+ clearSession(headers) {
337
+ return __awaiter(this, void 0, void 0, function* () {
338
+ const url = '/api/session';
339
+ const config = this.createConfig(headers);
340
+ try {
341
+ const response = yield this.client.delete(url, config);
342
+ return response.data;
343
+ }
344
+ catch (error) {
345
+ console.error(`DELETE request to ${url} failed:`, error);
346
+ throw error;
347
+ }
348
+ });
349
+ }
310
350
  }
311
351
  function toSnakeCase(obj) {
312
352
  if (Array.isArray(obj)) {
@@ -0,0 +1,5 @@
1
+ export interface AuthTokenProvider {
2
+ getToken(): Promise<string | null>;
3
+ refreshToken(): Promise<string | null>;
4
+ onRefreshFailure?(error: unknown): void;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -8,14 +8,6 @@ export declare enum AuthProvider {
8
8
  FACEBOOK = "FACEBOOK",
9
9
  TWITTER = "TWITTER"
10
10
  }
11
- export declare class AuthState {
12
- readonly isAuthenticated: boolean;
13
- readonly user: UserData | null;
14
- readonly provider: AuthProvider | null;
15
- private constructor();
16
- static authenticated(user: UserData, provider: AuthProvider): AuthState;
17
- static unauthenticated(): AuthState;
18
- }
19
11
  export declare class UserData {
20
12
  readonly id: string;
21
13
  readonly email: string;
@@ -47,7 +39,7 @@ export interface FirebaseConfig {
47
39
  appId: string;
48
40
  measurementId?: string;
49
41
  }
50
- export declare class FirebaseUnifiedService implements LoginService {
42
+ export declare class FirebaseService implements LoginService {
51
43
  private app;
52
44
  private messaging;
53
45
  private auth;
@@ -56,7 +48,7 @@ export declare class FirebaseUnifiedService implements LoginService {
56
48
  private readonly emailVerificationContinueUrl?;
57
49
  private client;
58
50
  private readonly initializationPromise;
59
- constructor(client: P2PMarketplaceAPIClient, config?: FirebaseLoginServiceConfig);
51
+ constructor(backendClient: P2PMarketplaceAPIClient, firebaseLoginConfig?: FirebaseLoginServiceConfig);
60
52
  private initializeFirebase;
61
53
  private ensureAuthInstance;
62
54
  private buildAuthTokenProvider;
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  var _a;
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.FirebaseUnifiedService = exports.AuthResult = exports.UserData = exports.AuthState = exports.AuthProvider = void 0;
13
+ exports.FirebaseService = exports.AuthResult = exports.UserData = exports.AuthProvider = void 0;
14
14
  const app_1 = require("firebase/app");
15
15
  const auth_1 = require("firebase/auth");
16
16
  const messaging_1 = require("firebase/messaging");
@@ -36,22 +36,6 @@ var AuthProvider;
36
36
  AuthProvider["FACEBOOK"] = "FACEBOOK";
37
37
  AuthProvider["TWITTER"] = "TWITTER";
38
38
  })(AuthProvider = exports.AuthProvider || (exports.AuthProvider = {}));
39
- // Immutable auth state class
40
- class AuthState {
41
- constructor(isAuthenticated, user, provider) {
42
- this.isAuthenticated = isAuthenticated;
43
- this.user = user;
44
- this.provider = provider;
45
- }
46
- static authenticated(user, provider) {
47
- return new AuthState(true, user, provider);
48
- }
49
- static unauthenticated() {
50
- return new AuthState(false, null, null);
51
- }
52
- }
53
- exports.AuthState = AuthState;
54
- // Enhanced UserData class with additional safety
55
39
  class UserData {
56
40
  constructor(id, email, username, isEmailVerified, idToken, isAdmin) {
57
41
  this.id = id;
@@ -87,24 +71,27 @@ class AuthResult {
87
71
  }
88
72
  }
89
73
  exports.AuthResult = AuthResult;
90
- class FirebaseUnifiedService {
91
- constructor(client, config) {
92
- var _a, _b, _c, _d, _e;
74
+ class FirebaseService {
75
+ constructor(backendClient, firebaseLoginConfig) {
76
+ var _a, _b, _c, _d;
93
77
  this.app = null;
94
78
  this.messaging = null;
95
79
  this.auth = null;
96
- this.client = client;
97
- const fallbackVerificationPage = (_a = config === null || config === void 0 ? void 0 : config.emailVerificationUrl) !== null && _a !== void 0 ? _a : DEFAULT_EMAIL_VERIFICATION_PAGE;
80
+ this.client = backendClient;
81
+ const fallbackVerificationPage = (_a = firebaseLoginConfig === null || firebaseLoginConfig === void 0 ? void 0 : firebaseLoginConfig.emailVerificationUrl) !== null && _a !== void 0 ? _a : DEFAULT_EMAIL_VERIFICATION_PAGE;
98
82
  this.emailVerificationUrl = trimTrailingSlash(fallbackVerificationPage);
99
- this.emailVerificationContinueUrl = config === null || config === void 0 ? void 0 : config.emailVerificationContinueUrl;
100
- const configuredActionSettings = config === null || config === void 0 ? void 0 : config.actionCodeSettings;
101
- const defaultActionUrl = (_d = (_c = (_b = configuredActionSettings === null || configuredActionSettings === void 0 ? void 0 : configuredActionSettings.url) !== null && _b !== void 0 ? _b : process.env.REACT_APP_EMAIL_LINK_URL) !== null && _c !== void 0 ? _c : process.env.NEXT_PUBLIC_EMAIL_LINK_URL) !== null && _d !== void 0 ? _d : "http://localhost:3000/auth/verify-email";
83
+ this.emailVerificationContinueUrl = firebaseLoginConfig === null || firebaseLoginConfig === void 0 ? void 0 : firebaseLoginConfig.emailVerificationContinueUrl;
84
+ const configuredActionSettings = firebaseLoginConfig === null || firebaseLoginConfig === void 0 ? void 0 : firebaseLoginConfig.actionCodeSettings;
85
+ const defaultActionUrl = (_c = (_b = configuredActionSettings === null || configuredActionSettings === void 0 ? void 0 : configuredActionSettings.url) !== null && _b !== void 0 ? _b : process.env.REACT_APP_EMAIL_LINK_URL) !== null && _c !== void 0 ? _c : process.env.NEXT_PUBLIC_EMAIL_LINK_URL;
102
86
  this.actionCodeSettings = {
103
- url: defaultActionUrl,
104
- handleCodeInApp: (_e = configuredActionSettings === null || configuredActionSettings === void 0 ? void 0 : configuredActionSettings.handleCodeInApp) !== null && _e !== void 0 ? _e : true,
87
+ url: defaultActionUrl !== null && defaultActionUrl !== void 0 ? defaultActionUrl : "http://localhost:3000/auth/verify-email",
88
+ handleCodeInApp: (_d = configuredActionSettings === null || configuredActionSettings === void 0 ? void 0 : configuredActionSettings.handleCodeInApp) !== null && _d !== void 0 ? _d : true,
105
89
  };
106
- this.initializationPromise = this.initializeFirebase();
90
+ // Set the auth token provider first (before initialization)
91
+ // It will gracefully return null until auth is ready
107
92
  this.client.setAuthTokenProvider(this.buildAuthTokenProvider());
93
+ // Start initialization (this will fetch config, which needs to work without auth)
94
+ this.initializationPromise = this.initializeFirebase();
108
95
  }
109
96
  initializeFirebase() {
110
97
  return __awaiter(this, void 0, void 0, function* () {
@@ -135,14 +122,19 @@ class FirebaseUnifiedService {
135
122
  buildAuthTokenProvider() {
136
123
  return {
137
124
  getToken: () => __awaiter(this, void 0, void 0, function* () {
138
- const auth = yield this.ensureAuthInstance();
139
- const currentUser = auth === null || auth === void 0 ? void 0 : auth.currentUser;
125
+ // Check if auth is available without waiting for initialization
126
+ // This prevents circular dependency during initial config fetch
127
+ if (!this.auth) {
128
+ return null;
129
+ }
130
+ const currentUser = this.auth.currentUser;
140
131
  if (!currentUser) {
141
132
  return null;
142
133
  }
143
134
  return currentUser.getIdToken();
144
135
  }),
145
136
  refreshToken: () => __awaiter(this, void 0, void 0, function* () {
137
+ // For token refresh, we need to ensure auth is initialized
146
138
  const auth = yield this.ensureAuthInstance();
147
139
  const currentUser = auth === null || auth === void 0 ? void 0 : auth.currentUser;
148
140
  if (!currentUser) {
@@ -293,7 +285,8 @@ class FirebaseUnifiedService {
293
285
  username: syncedBackendUser.username || '',
294
286
  email: userCredential.user.email || '',
295
287
  idToken,
296
- isAdmin: syncedBackendUser.admin || false
288
+ isAdmin: syncedBackendUser.admin || false,
289
+ isEmailVerified: userCredential.user.emailVerified
297
290
  });
298
291
  return authResult;
299
292
  }
@@ -588,4 +581,4 @@ class FirebaseUnifiedService {
588
581
  });
589
582
  }
590
583
  }
591
- exports.FirebaseUnifiedService = FirebaseUnifiedService;
584
+ exports.FirebaseService = FirebaseService;
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createLoginService = void 0;
4
+ const FirebaseLoginService_1 = require("./FirebaseLoginService");
4
5
  function createLoginService(config) {
5
6
  const { provider, apiClient } = config;
6
7
  if (provider === 'firebase') {
7
- const { FirebaseUnifiedService } = require('../FirebaseLoginService');
8
- return new FirebaseUnifiedService(apiClient, config.firebase);
8
+ return new FirebaseLoginService_1.FirebaseService(apiClient, config.firebase);
9
9
  }
10
10
  throw new Error(`Unsupported login provider: ${provider}`);
11
11
  }
@@ -4,6 +4,7 @@ export interface User {
4
4
  email: string;
5
5
  idToken: string;
6
6
  isAdmin: boolean;
7
+ isEmailVerified: boolean;
7
8
  }
8
9
  export interface UserContext {
9
10
  user: User | null;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { default as P2PMarketplaceAPIClient } from './P2PMarketplaceAPIClient';
2
2
  export { generateSecretAndHash } from './cryptoUtils';
3
3
  export * from './types';
4
- export { FirebaseUnifiedService } from './auth/FirebaseLoginService';
4
+ export { FirebaseService, AuthProvider, UserData, AuthResult } from './auth/FirebaseLoginService';
5
5
  export { createLoginService } from './auth/LoginService';
6
6
  export { userContext } from './auth/UserContext';
package/dist/index.js CHANGED
@@ -17,14 +17,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.userContext = exports.createLoginService = exports.FirebaseUnifiedService = exports.generateSecretAndHash = exports.P2PMarketplaceAPIClient = void 0;
20
+ exports.userContext = exports.createLoginService = exports.AuthResult = exports.UserData = exports.AuthProvider = exports.FirebaseService = exports.generateSecretAndHash = exports.P2PMarketplaceAPIClient = void 0;
21
21
  var P2PMarketplaceAPIClient_1 = require("./P2PMarketplaceAPIClient");
22
22
  Object.defineProperty(exports, "P2PMarketplaceAPIClient", { enumerable: true, get: function () { return __importDefault(P2PMarketplaceAPIClient_1).default; } });
23
23
  var cryptoUtils_1 = require("./cryptoUtils");
24
24
  Object.defineProperty(exports, "generateSecretAndHash", { enumerable: true, get: function () { return cryptoUtils_1.generateSecretAndHash; } });
25
25
  __exportStar(require("./types"), exports);
26
26
  var FirebaseLoginService_1 = require("./auth/FirebaseLoginService");
27
- Object.defineProperty(exports, "FirebaseUnifiedService", { enumerable: true, get: function () { return FirebaseLoginService_1.FirebaseUnifiedService; } });
27
+ Object.defineProperty(exports, "FirebaseService", { enumerable: true, get: function () { return FirebaseLoginService_1.FirebaseService; } });
28
+ Object.defineProperty(exports, "AuthProvider", { enumerable: true, get: function () { return FirebaseLoginService_1.AuthProvider; } });
29
+ Object.defineProperty(exports, "UserData", { enumerable: true, get: function () { return FirebaseLoginService_1.UserData; } });
30
+ Object.defineProperty(exports, "AuthResult", { enumerable: true, get: function () { return FirebaseLoginService_1.AuthResult; } });
28
31
  var LoginService_1 = require("./auth/LoginService");
29
32
  Object.defineProperty(exports, "createLoginService", { enumerable: true, get: function () { return LoginService_1.createLoginService; } });
30
33
  var UserContext_1 = require("./auth/UserContext");
package/dist/types.d.ts CHANGED
@@ -64,6 +64,13 @@ export interface UpdateUserSettingsRequest {
64
64
  export interface VerifyEmailRequest {
65
65
  loginId: string;
66
66
  }
67
+ export interface CreateSessionRequest {
68
+ idToken: string;
69
+ }
70
+ export interface CreateSessionResponse {
71
+ success: boolean;
72
+ userId?: string;
73
+ }
67
74
  export interface PaymentMethod {
68
75
  type: string;
69
76
  alias?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "b5-api-client",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "description": "Escrow Backend API client",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,17 +1,12 @@
1
- import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
2
- import { CreateOrderRequest, CreateUserRequest, Order, OrderResponse, TakeOrderRequest, TestEventParams, UpdateOrderRequest, TransactionStatusResponse, RateUserRequest, OrderEventsResponse, PushNotificationsRegisterRequest, ConfigResponse, DashboardMetricsResponse, KioscoinUser, UsersResponse, PaymentMethod, GetOrdersParams, CreateDisputeRequest, DisputesResponse, OrderOffersResponse, TransactionRequest, KioscoinOperationResponse, UpdateUserSettingsRequest, NotificationsResponse, VerifyEmailRequest } from './types';
1
+ import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios';
2
+ import { CreateOrderRequest, CreateUserRequest, Order, OrderResponse, TakeOrderRequest, TestEventParams, UpdateOrderRequest, TransactionStatusResponse, RateUserRequest, OrderEventsResponse, PushNotificationsRegisterRequest, ConfigResponse, DashboardMetricsResponse, UsersResponse, GetOrdersParams, CreateDisputeRequest, DisputesResponse, OrderOffersResponse, TransactionRequest, KioscoinOperationResponse, UpdateUserSettingsRequest, NotificationsResponse, VerifyEmailRequest, CreateSessionRequest, CreateSessionResponse } from './types';
3
+ import { AuthTokenProvider } from './auth/AuthTokenProvider';
3
4
  import { isPlainObject, camelCase, snakeCase, transform } from 'lodash';
4
5
 
5
- interface RequestConfigWithRetry extends AxiosRequestConfig {
6
+ export interface RequestConfigWithRetry extends AxiosRequestConfig {
6
7
  _retry?: boolean;
7
8
  }
8
9
 
9
- export interface AuthTokenProvider {
10
- getToken(): Promise<string | null>;
11
- refreshToken(): Promise<string | null>;
12
- onRefreshFailure?(error: unknown): void;
13
- }
14
-
15
10
  class P2PMarketplaceAPIClient {
16
11
  private readonly client: AxiosInstance;
17
12
  private readonly defaultHeaders: Record<string, string>;
@@ -22,6 +17,7 @@ class P2PMarketplaceAPIClient {
22
17
  this.client = axios.create({
23
18
  baseURL,
24
19
  timeout,
20
+ withCredentials: true, // Enable sending/receiving cookies
25
21
  });
26
22
 
27
23
  this.defaultHeaders = {
@@ -295,6 +291,42 @@ class P2PMarketplaceAPIClient {
295
291
  return this.post<DisputesResponse>(url, request, headers);
296
292
  }
297
293
 
294
+ // Session Management
295
+
296
+ /**
297
+ * Create or refresh a session with Firebase ID token
298
+ * Sets a session cookie that will be used for WebSocket authentication
299
+ */
300
+ public async createSession(request: CreateSessionRequest, headers?: Record<string, string>): Promise<CreateSessionResponse> {
301
+ const url = '/api/session';
302
+ return this.post<CreateSessionResponse>(url, request, headers);
303
+ }
304
+
305
+ /**
306
+ * Check if the current session is valid
307
+ * Returns session status and userId if valid
308
+ */
309
+ public async getSessionStatus(headers?: Record<string, string>): Promise<CreateSessionResponse> {
310
+ const url = '/api/session';
311
+ return this.get<CreateSessionResponse>(url, headers);
312
+ }
313
+
314
+ /**
315
+ * Clear the session cookie (logout)
316
+ * Destroys the session on the backend
317
+ */
318
+ public async clearSession(headers?: Record<string, string>): Promise<{ success: boolean }> {
319
+ const url = '/api/session';
320
+ const config = this.createConfig(headers);
321
+ try {
322
+ const response = await this.client.delete<{ success: boolean }>(url, config);
323
+ return response.data;
324
+ } catch (error) {
325
+ console.error(`DELETE request to ${url} failed:`, error);
326
+ throw error;
327
+ }
328
+ }
329
+
298
330
  }
299
331
 
300
332
  function toSnakeCase(obj: any): any {
@@ -0,0 +1,5 @@
1
+ export interface AuthTokenProvider {
2
+ getToken(): Promise<string | null>;
3
+ refreshToken(): Promise<string | null>;
4
+ onRefreshFailure?(error: unknown): void;
5
+ }
@@ -19,7 +19,8 @@ import {
19
19
  } from "firebase/auth";
20
20
  import { getMessaging, getToken, onMessage } from "firebase/messaging";
21
21
  import { CreateUserRequest, KioscoinUser, UpdateUserSettingsRequest } from "../types";
22
- import P2PMarketplaceAPIClient, { AuthTokenProvider } from "../P2PMarketplaceAPIClient";
22
+ import P2PMarketplaceAPIClient from "../P2PMarketplaceAPIClient";
23
+ import { AuthTokenProvider } from "./AuthTokenProvider";
23
24
  import { FirebaseLoginServiceConfig, LoginService } from "./LoginService";
24
25
  import { userContext } from './UserContext';
25
26
 
@@ -56,24 +57,6 @@ export enum AuthProvider {
56
57
  TWITTER = 'TWITTER'
57
58
  }
58
59
 
59
- // Immutable auth state class
60
- export class AuthState {
61
- private constructor(
62
- public readonly isAuthenticated: boolean,
63
- public readonly user: UserData | null,
64
- public readonly provider: AuthProvider | null
65
- ) { }
66
-
67
- static authenticated(user: UserData, provider: AuthProvider): AuthState {
68
- return new AuthState(true, user, provider);
69
- }
70
-
71
- static unauthenticated(): AuthState {
72
- return new AuthState(false, null, null);
73
- }
74
- }
75
-
76
- // Enhanced UserData class with additional safety
77
60
  export class UserData {
78
61
  private constructor(
79
62
  public readonly id: string,
@@ -144,7 +127,7 @@ export interface FirebaseConfig {
144
127
  measurementId?: string;
145
128
  }
146
129
 
147
- export class FirebaseUnifiedService implements LoginService {
130
+ export class FirebaseService implements LoginService {
148
131
  private app: ReturnType<typeof initializeApp> | null = null;
149
132
  private messaging: ReturnType<typeof getMessaging> | null = null;
150
133
  private auth: Auth | null = null;
@@ -154,24 +137,28 @@ export class FirebaseUnifiedService implements LoginService {
154
137
  private client: P2PMarketplaceAPIClient;
155
138
  private readonly initializationPromise: Promise<void>;
156
139
 
157
- constructor(client: P2PMarketplaceAPIClient, config?: FirebaseLoginServiceConfig) {
158
- this.client = client;
159
- const fallbackVerificationPage = config?.emailVerificationUrl ?? DEFAULT_EMAIL_VERIFICATION_PAGE;
140
+ constructor(backendClient: P2PMarketplaceAPIClient, firebaseLoginConfig?: FirebaseLoginServiceConfig) {
141
+ this.client = backendClient;
142
+ const fallbackVerificationPage = firebaseLoginConfig?.emailVerificationUrl ?? DEFAULT_EMAIL_VERIFICATION_PAGE;
160
143
  this.emailVerificationUrl = trimTrailingSlash(fallbackVerificationPage);
161
- this.emailVerificationContinueUrl = config?.emailVerificationContinueUrl;
162
- const configuredActionSettings = config?.actionCodeSettings;
144
+ this.emailVerificationContinueUrl = firebaseLoginConfig?.emailVerificationContinueUrl;
145
+ const configuredActionSettings = firebaseLoginConfig?.actionCodeSettings;
163
146
  const defaultActionUrl =
164
147
  configuredActionSettings?.url ??
165
148
  process.env.REACT_APP_EMAIL_LINK_URL ??
166
- process.env.NEXT_PUBLIC_EMAIL_LINK_URL ??
167
- "http://localhost:3000/auth/verify-email";
149
+ process.env.NEXT_PUBLIC_EMAIL_LINK_URL
168
150
 
169
151
  this.actionCodeSettings = {
170
- url: defaultActionUrl,
152
+ url: defaultActionUrl ?? "http://localhost:3000/auth/verify-email",
171
153
  handleCodeInApp: configuredActionSettings?.handleCodeInApp ?? true,
172
154
  };
173
- this.initializationPromise = this.initializeFirebase();
155
+
156
+ // Set the auth token provider first (before initialization)
157
+ // It will gracefully return null until auth is ready
174
158
  this.client.setAuthTokenProvider(this.buildAuthTokenProvider());
159
+
160
+ // Start initialization (this will fetch config, which needs to work without auth)
161
+ this.initializationPromise = this.initializeFirebase();
175
162
  }
176
163
 
177
164
  private async initializeFirebase() {
@@ -200,14 +187,19 @@ export class FirebaseUnifiedService implements LoginService {
200
187
  private buildAuthTokenProvider(): AuthTokenProvider {
201
188
  return {
202
189
  getToken: async () => {
203
- const auth = await this.ensureAuthInstance();
204
- const currentUser = auth?.currentUser;
190
+ // Check if auth is available without waiting for initialization
191
+ // This prevents circular dependency during initial config fetch
192
+ if (!this.auth) {
193
+ return null;
194
+ }
195
+ const currentUser = this.auth.currentUser;
205
196
  if (!currentUser) {
206
197
  return null;
207
198
  }
208
199
  return currentUser.getIdToken();
209
200
  },
210
201
  refreshToken: async () => {
202
+ // For token refresh, we need to ensure auth is initialized
211
203
  const auth = await this.ensureAuthInstance();
212
204
  const currentUser = auth?.currentUser;
213
205
  if (!currentUser) {
@@ -372,7 +364,8 @@ export class FirebaseUnifiedService implements LoginService {
372
364
  username: syncedBackendUser.username || '',
373
365
  email: userCredential.user.email || '',
374
366
  idToken,
375
- isAdmin: syncedBackendUser.admin || false
367
+ isAdmin: syncedBackendUser.admin || false,
368
+ isEmailVerified: userCredential.user.emailVerified
376
369
  });
377
370
  return authResult;
378
371
  } else {
@@ -1,5 +1,5 @@
1
1
  import P2PMarketplaceAPIClient from "../P2PMarketplaceAPIClient";
2
- import { AuthResult } from "./FirebaseLoginService";
2
+ import { AuthResult, FirebaseService } from "./FirebaseLoginService";
3
3
 
4
4
  export type LoginProvider = 'firebase' | 'custom';
5
5
 
@@ -28,8 +28,7 @@ export interface FirebaseLoginServiceConfig {
28
28
  export function createLoginService(config: LoginServiceConfig): LoginService {
29
29
  const { provider, apiClient } = config;
30
30
  if (provider === 'firebase') {
31
- const { FirebaseUnifiedService } = require('../FirebaseLoginService');
32
- return new FirebaseUnifiedService(apiClient, config.firebase);
31
+ return new FirebaseService(apiClient, config.firebase);
33
32
  }
34
33
  throw new Error(`Unsupported login provider: ${provider}`);
35
34
  }
@@ -5,6 +5,7 @@ export interface User {
5
5
  email: string;
6
6
  idToken: string;
7
7
  isAdmin: boolean;
8
+ isEmailVerified: boolean;
8
9
  }
9
10
 
10
11
  // Define the UserContext interface
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { default as P2PMarketplaceAPIClient } from './P2PMarketplaceAPIClient';
2
2
  export { generateSecretAndHash } from './cryptoUtils'
3
3
  export * from './types';
4
- export { FirebaseUnifiedService } from './auth/FirebaseLoginService';
4
+ export { FirebaseService, AuthProvider, UserData, AuthResult } from './auth/FirebaseLoginService';
5
5
  export { createLoginService } from './auth/LoginService';
6
6
  export { userContext } from './auth/UserContext';
package/src/types.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { AxiosRequestConfig } from "axios";
2
+
1
3
  export type OrderType = 'SELL' | 'BUY';
2
4
 
3
5
  export type OrderStatus =
@@ -90,6 +92,15 @@ export interface VerifyEmailRequest {
90
92
  loginId: string;
91
93
  }
92
94
 
95
+ export interface CreateSessionRequest {
96
+ idToken: string;
97
+ }
98
+
99
+ export interface CreateSessionResponse {
100
+ success: boolean;
101
+ userId?: string;
102
+ }
103
+
93
104
  export interface PaymentMethod {
94
105
  type: string;
95
106
  alias?: string;