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.
- package/dist/P2PMarketplaceAPIClient.d.ts +22 -5
- package/dist/P2PMarketplaceAPIClient.js +40 -0
- package/dist/auth/AuthTokenProvider.d.ts +5 -0
- package/dist/auth/AuthTokenProvider.js +2 -0
- package/dist/auth/FirebaseLoginService.d.ts +2 -10
- package/dist/auth/FirebaseLoginService.js +25 -32
- package/dist/auth/LoginService.js +2 -2
- package/dist/auth/UserContext.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -2
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
- package/src/P2PMarketplaceAPIClient.ts +41 -9
- package/src/auth/AuthTokenProvider.ts +5 -0
- package/src/auth/FirebaseLoginService.ts +25 -32
- package/src/auth/LoginService.ts +2 -3
- package/src/auth/UserContext.ts +1 -0
- package/src/index.ts +1 -1
- package/src/types.ts +11 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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)) {
|
|
@@ -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
|
|
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(
|
|
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.
|
|
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
|
|
91
|
-
constructor(
|
|
92
|
-
var _a, _b, _c, _d
|
|
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 =
|
|
97
|
-
const fallbackVerificationPage = (_a =
|
|
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 =
|
|
100
|
-
const configuredActionSettings =
|
|
101
|
-
const defaultActionUrl = (
|
|
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: (
|
|
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
|
-
|
|
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
|
-
|
|
139
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
}
|
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 {
|
|
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.
|
|
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, "
|
|
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,17 +1,12 @@
|
|
|
1
|
-
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig
|
|
2
|
-
import { CreateOrderRequest, CreateUserRequest, Order, OrderResponse, TakeOrderRequest, TestEventParams, UpdateOrderRequest, TransactionStatusResponse, RateUserRequest, OrderEventsResponse, PushNotificationsRegisterRequest, ConfigResponse, DashboardMetricsResponse,
|
|
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 {
|
|
@@ -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
|
|
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
|
|
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(
|
|
158
|
-
this.client =
|
|
159
|
-
const fallbackVerificationPage =
|
|
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 =
|
|
162
|
-
const configuredActionSettings =
|
|
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
|
-
|
|
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
|
-
|
|
204
|
-
|
|
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 {
|
package/src/auth/LoginService.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
}
|
package/src/auth/UserContext.ts
CHANGED
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 {
|
|
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;
|