b5-api-client 0.0.25 → 0.0.27

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,10 +1,19 @@
1
- import { CreateOrderRequest, CreateUserRequest, Order, OrderResponse, TakeOrderRequest, TestEventParams, UpdateOrderRequest, TransactionStatusResponse, RateUserRequest, OrderEventsResponse, PushNotificationsRegisterRequest, ConfigResponse, DashboardMetricsResponse, UsersResponse, GetOrdersParams, CreateDisputeRequest, DisputesResponse, OrderOffersResponse, TransactionRequest, KioscoinOperationResponse, UpdateUserSettingsRequest } from './types';
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;
6
+ }
2
7
  declare class P2PMarketplaceAPIClient {
3
8
  private readonly client;
4
9
  private readonly defaultHeaders;
10
+ private authTokenProvider?;
11
+ private refreshTokenPromise?;
5
12
  constructor(baseURL: string, timeout?: number);
13
+ setAuthTokenProvider(provider?: AuthTokenProvider): void;
6
14
  private mergeHeaders;
7
15
  private createConfig;
16
+ private getRefreshedToken;
8
17
  get<T>(url: string, headers?: Record<string, string>): Promise<T>;
9
18
  post<T>(url: string, data: any, headers?: Record<string, string>): Promise<T>;
10
19
  getOrders(props: GetOrdersParams, headers?: Record<string, string>): Promise<OrderResponse>;
@@ -16,14 +25,15 @@ declare class P2PMarketplaceAPIClient {
16
25
  getUser(userId: string, headers?: Record<string, string>): Promise<UsersResponse>;
17
26
  rateUser(rateUserRequest: RateUserRequest, headers?: Record<string, string>): Promise<any>;
18
27
  updateUserSettings(request: UpdateUserSettingsRequest, headers?: Record<string, string>): Promise<UsersResponse>;
28
+ verifyUserEmail(request: VerifyEmailRequest, headers?: Record<string, string>): Promise<UsersResponse>;
19
29
  registerPushToken(registerRequest: PushNotificationsRegisterRequest, headers?: Record<string, string>): Promise<any>;
30
+ listNotifications(limit?: number, offset?: number, headers?: Record<string, string>): Promise<NotificationsResponse>;
31
+ markNotificationAsRead(notificationId: string, headers?: Record<string, string>): Promise<NotificationsResponse>;
20
32
  getConfig<T>(): Promise<ConfigResponse<T>>;
21
33
  getOrderEvents(id: string, headers?: Record<string, string>): Promise<OrderEventsResponse>;
22
34
  getDashboardMetrics(headers?: Record<string, string>): Promise<DashboardMetricsResponse>;
23
35
  getOrderOffers(headers?: Record<string, string>): Promise<OrderOffersResponse>;
24
36
  pointOfSaleTransact(request: TransactionRequest, headers?: Record<string, string>): Promise<KioscoinOperationResponse>;
25
- testLockFunds(order: Order, testParams?: TestEventParams, headers?: Record<string, string>): Promise<void>;
26
- testReleaseFunds(order: Order, testParams?: TestEventParams, headers?: Record<string, string>): Promise<void>;
27
37
  releaseFunds(order: Order, testParams?: TestEventParams, headers?: Record<string, string>): Promise<string>;
28
38
  getTransactionStatus(txHash: string, headers?: Record<string, string>): Promise<TransactionStatusResponse>;
29
39
  createDispute(request: CreateDisputeRequest, headers?: Record<string, string>): Promise<DisputesResponse>;
@@ -25,12 +25,29 @@ class P2PMarketplaceAPIClient {
25
25
  'x-blockchain': 'rsk_testnet'
26
26
  };
27
27
  // Add a request interceptor to transform request data to snake_case
28
- this.client.interceptors.request.use((config) => {
28
+ this.client.interceptors.request.use((config) => __awaiter(this, void 0, void 0, function* () {
29
29
  if (config.data) {
30
30
  config.data = toSnakeCase(config.data);
31
31
  }
32
- return config;
33
- }, (error) => {
32
+ const provider = this.authTokenProvider;
33
+ if (!provider) {
34
+ return config;
35
+ }
36
+ return provider
37
+ .getToken()
38
+ .then((token) => {
39
+ var _a;
40
+ if (token) {
41
+ config.headers = (_a = config.headers) !== null && _a !== void 0 ? _a : {};
42
+ config.headers['Authorization'] = `Bearer ${token}`;
43
+ }
44
+ return config;
45
+ })
46
+ .catch((error) => {
47
+ console.warn('[P2PMarketplaceAPIClient] Failed to obtain auth token before request:', error);
48
+ return config;
49
+ });
50
+ }), (error) => {
34
51
  return Promise.reject(error);
35
52
  });
36
53
  // Add a response interceptor to transform response data to camelCase
@@ -39,9 +56,37 @@ class P2PMarketplaceAPIClient {
39
56
  response.data = toCamelCase(response.data);
40
57
  }
41
58
  return response;
42
- }, (error) => {
43
- return Promise.reject(error);
44
- });
59
+ }, (error) => __awaiter(this, void 0, void 0, function* () {
60
+ var _a, _b;
61
+ const { response, config } = error;
62
+ if (!this.authTokenProvider || (response === null || response === void 0 ? void 0 : response.status) !== 401 || !config) {
63
+ return Promise.reject(error);
64
+ }
65
+ const originalRequest = config;
66
+ if (originalRequest._retry) {
67
+ return Promise.reject(error);
68
+ }
69
+ originalRequest._retry = true;
70
+ try {
71
+ const newToken = yield this.getRefreshedToken();
72
+ if (!newToken) {
73
+ return Promise.reject(error);
74
+ }
75
+ originalRequest.headers = (_a = originalRequest.headers) !== null && _a !== void 0 ? _a : {};
76
+ originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
77
+ return this.client(originalRequest);
78
+ }
79
+ catch (refreshError) {
80
+ if ((_b = this.authTokenProvider) === null || _b === void 0 ? void 0 : _b.onRefreshFailure) {
81
+ this.authTokenProvider.onRefreshFailure(refreshError);
82
+ }
83
+ return Promise.reject(error);
84
+ }
85
+ }));
86
+ }
87
+ setAuthTokenProvider(provider) {
88
+ this.authTokenProvider = provider;
89
+ this.refreshTokenPromise = undefined;
45
90
  }
46
91
  mergeHeaders(customHeaders) {
47
92
  return Object.assign(Object.assign({}, this.defaultHeaders), customHeaders);
@@ -51,6 +96,28 @@ class P2PMarketplaceAPIClient {
51
96
  headers: this.mergeHeaders(headers)
52
97
  };
53
98
  }
99
+ getRefreshedToken() {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ if (!this.authTokenProvider) {
102
+ return null;
103
+ }
104
+ if (!this.refreshTokenPromise) {
105
+ this.refreshTokenPromise = this.authTokenProvider
106
+ .refreshToken()
107
+ .catch((error) => {
108
+ var _a;
109
+ if ((_a = this.authTokenProvider) === null || _a === void 0 ? void 0 : _a.onRefreshFailure) {
110
+ this.authTokenProvider.onRefreshFailure(error);
111
+ }
112
+ throw error;
113
+ })
114
+ .finally(() => {
115
+ this.refreshTokenPromise = undefined;
116
+ });
117
+ }
118
+ return this.refreshTokenPromise;
119
+ });
120
+ }
54
121
  get(url, headers) {
55
122
  return __awaiter(this, void 0, void 0, function* () {
56
123
  const config = this.createConfig(headers);
@@ -157,12 +224,30 @@ class P2PMarketplaceAPIClient {
157
224
  return this.post(url, request, headers);
158
225
  });
159
226
  }
227
+ verifyUserEmail(request, headers) {
228
+ return __awaiter(this, void 0, void 0, function* () {
229
+ const url = '/api/users/verify_email';
230
+ return this.post(url, request, headers);
231
+ });
232
+ }
160
233
  registerPushToken(registerRequest, headers) {
161
234
  return __awaiter(this, void 0, void 0, function* () {
162
235
  const url = `/api/notifications/register-push`;
163
236
  return this.post(url, registerRequest, headers);
164
237
  });
165
238
  }
239
+ listNotifications(limit = 10, offset = 0, headers) {
240
+ return __awaiter(this, void 0, void 0, function* () {
241
+ const url = `/api/notifications?limit=${limit}&offset=${offset}`;
242
+ return this.get(url, headers);
243
+ });
244
+ }
245
+ markNotificationAsRead(notificationId, headers) {
246
+ return __awaiter(this, void 0, void 0, function* () {
247
+ const url = `/api/notifications/${notificationId}/read`;
248
+ return this.post(url, {}, headers);
249
+ });
250
+ }
166
251
  getConfig() {
167
252
  return __awaiter(this, void 0, void 0, function* () {
168
253
  const url = '/api/configuration';
@@ -193,59 +278,6 @@ class P2PMarketplaceAPIClient {
193
278
  return this.post(url, request, headers);
194
279
  });
195
280
  }
196
- testLockFunds(order, testParams, headers) {
197
- var _a, _b, _c, _d;
198
- return __awaiter(this, void 0, void 0, function* () {
199
- const orderEvent = {
200
- type: "LOCKED",
201
- orderId: (_a = order.id) !== null && _a !== void 0 ? _a : "",
202
- buyerAddress: (_b = order.buyerAddress) !== null && _b !== void 0 ? _b : "",
203
- amount: (_d = (_c = order.amount) === null || _c === void 0 ? void 0 : _c.toString()) !== null && _d !== void 0 ? _d : "0",
204
- transaction: {
205
- hash: "0x976d8c61b958e286d907a2e1c5ffde8c9316800ab4de1396a54927a39dc533a2",
206
- },
207
- tokenContractAddress: "0xee5e8291b551603a19ef41eea69ae49592ed14f8",
208
- buyerHash: "02809d5cc2ec09a7503ef77358654a5bfc958e08c04ecb33f412884c0933be68",
209
- sellerAddress: "0x2A4E89D18C2742FEDC65444d339cC5fAF3dE4dF1",
210
- sellerHash: "4b3560738b8e3cb8a0a30ac664b12de2ace977c62ade94bc08a37fe5b93bf34b",
211
- fee: "30000000000000000",
212
- timestamp: new Date().toISOString(),
213
- };
214
- const url = "api/events/simulate/lock";
215
- try {
216
- yield this.post(url, orderEvent, headers);
217
- }
218
- catch (error) {
219
- console.error("Error locking funds:", error);
220
- throw new Error("Failed to lock funds");
221
- }
222
- });
223
- }
224
- testReleaseFunds(order, testParams, headers) {
225
- var _a, _b, _c, _d;
226
- return __awaiter(this, void 0, void 0, function* () {
227
- const releaseOrderEvent = {
228
- type: "RELEASED",
229
- orderId: (_a = order.id) !== null && _a !== void 0 ? _a : "",
230
- buyerAddress: (_b = order.buyerAddress) !== null && _b !== void 0 ? _b : "",
231
- amount: (_d = (_c = order.amount) === null || _c === void 0 ? void 0 : _c.toString()) !== null && _d !== void 0 ? _d : "0",
232
- transaction: {
233
- hash: "0xeab4797bf0e13dff0bda481503a544698127c5f97dd826c465ebdb41bcfec3f5",
234
- },
235
- tokenContractAddress: "0xee5e8291b551603a19ef41eea69ae49592ed14f8",
236
- adminAction: true,
237
- timestamp: new Date().toISOString(),
238
- };
239
- const url = "api/events/simulate/release";
240
- try {
241
- yield this.post(url, releaseOrderEvent, headers);
242
- }
243
- catch (error) {
244
- console.error("Error releasing funds:", error);
245
- throw new Error("Failed to release funds");
246
- }
247
- });
248
- }
249
281
  releaseFunds(order, testParams, headers) {
250
282
  var _a;
251
283
  return __awaiter(this, void 0, void 0, function* () {
@@ -52,10 +52,18 @@ export declare class FirebaseUnifiedService implements LoginService {
52
52
  private messaging;
53
53
  private auth;
54
54
  private readonly actionCodeSettings;
55
+ private readonly emailVerificationUrl;
56
+ private readonly emailVerificationContinueUrl?;
55
57
  private client;
58
+ private readonly initializationPromise;
56
59
  constructor(client: P2PMarketplaceAPIClient, config?: FirebaseLoginServiceConfig);
57
60
  private initializeFirebase;
61
+ private ensureAuthInstance;
62
+ private buildAuthTokenProvider;
58
63
  private fetchFirebaseConfig;
64
+ private buildEmailVerificationSettings;
65
+ private buildEmailVerificationUrl;
66
+ private ensureBackendVerification;
59
67
  requestNotificationPermission(): Promise<string | null>;
60
68
  fetchToken(): Promise<string | null>;
61
69
  onMessageListener(callback: (payload: any) => void): void;
@@ -72,6 +80,7 @@ export declare class FirebaseUnifiedService implements LoginService {
72
80
  isSignInWithEmailLink(): boolean;
73
81
  signInWithEmailLink(email: string): Promise<AuthResult>;
74
82
  getEmailForSignIn(): string | null;
83
+ applyEmailVerificationCode(oobCode: string): Promise<void>;
75
84
  private _createSuccessAuthResult;
76
85
  private getUserFromBackend;
77
86
  private createUserInBackend;
@@ -8,12 +8,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var _a;
11
12
  Object.defineProperty(exports, "__esModule", { value: true });
12
13
  exports.FirebaseUnifiedService = exports.AuthResult = exports.UserData = exports.AuthState = exports.AuthProvider = void 0;
13
14
  const app_1 = require("firebase/app");
14
15
  const auth_1 = require("firebase/auth");
15
16
  const messaging_1 = require("firebase/messaging");
16
17
  const UserContext_1 = require("./UserContext");
18
+ const DEFAULT_EMAIL_VERIFICATION_PAGE = (_a = process.env.NEXT_PUBLIC_EMAIL_VERIFICATION_URL) !== null && _a !== void 0 ? _a : "http://localhost:3000/auth/email-verified";
19
+ const trimTrailingSlash = (value) => value.replace(/\/+$/, "");
20
+ const appendQueryParams = (base, params) => {
21
+ const query = Object.entries(params)
22
+ .filter(([, value]) => value !== undefined && value !== null)
23
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
24
+ .join("&");
25
+ if (!query) {
26
+ return base;
27
+ }
28
+ const separator = base.includes("?") ? "&" : "?";
29
+ return `${base}${separator}${query}`;
30
+ };
17
31
  // Auth provider type for better type safety
18
32
  var AuthProvider;
19
33
  (function (AuthProvider) {
@@ -75,19 +89,28 @@ class AuthResult {
75
89
  exports.AuthResult = AuthResult;
76
90
  class FirebaseUnifiedService {
77
91
  constructor(client, config) {
78
- var _a;
92
+ var _a, _b, _c, _d, _e;
79
93
  this.app = null;
80
94
  this.messaging = null;
81
95
  this.auth = null;
82
96
  this.client = client;
83
- this.actionCodeSettings = (_a = config === null || config === void 0 ? void 0 : config.actionCodeSettings) !== null && _a !== void 0 ? _a : {
84
- url: 'http://localhost:3000/auth/verify-email',
85
- handleCodeInApp: true,
97
+ const fallbackVerificationPage = (_a = config === null || config === void 0 ? void 0 : config.emailVerificationUrl) !== null && _a !== void 0 ? _a : DEFAULT_EMAIL_VERIFICATION_PAGE;
98
+ 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";
102
+ this.actionCodeSettings = {
103
+ url: defaultActionUrl,
104
+ handleCodeInApp: (_e = configuredActionSettings === null || configuredActionSettings === void 0 ? void 0 : configuredActionSettings.handleCodeInApp) !== null && _e !== void 0 ? _e : true,
86
105
  };
87
- this.initializeFirebase();
106
+ this.initializationPromise = this.initializeFirebase();
107
+ this.client.setAuthTokenProvider(this.buildAuthTokenProvider());
88
108
  }
89
109
  initializeFirebase() {
90
110
  return __awaiter(this, void 0, void 0, function* () {
111
+ if (this.app) {
112
+ return;
113
+ }
91
114
  try {
92
115
  const firebaseConfig = yield this.fetchFirebaseConfig();
93
116
  this.app = (0, app_1.initializeApp)(firebaseConfig);
@@ -98,6 +121,42 @@ class FirebaseUnifiedService {
98
121
  }
99
122
  });
100
123
  }
124
+ ensureAuthInstance() {
125
+ return __awaiter(this, void 0, void 0, function* () {
126
+ try {
127
+ yield this.initializationPromise;
128
+ }
129
+ catch (_error) {
130
+ return null;
131
+ }
132
+ return this.auth;
133
+ });
134
+ }
135
+ buildAuthTokenProvider() {
136
+ return {
137
+ 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;
140
+ if (!currentUser) {
141
+ return null;
142
+ }
143
+ return currentUser.getIdToken();
144
+ }),
145
+ refreshToken: () => __awaiter(this, void 0, void 0, function* () {
146
+ const auth = yield this.ensureAuthInstance();
147
+ const currentUser = auth === null || auth === void 0 ? void 0 : auth.currentUser;
148
+ if (!currentUser) {
149
+ return null;
150
+ }
151
+ const refreshedToken = yield currentUser.getIdToken(true);
152
+ UserContext_1.userContext.updateUser({ idToken: refreshedToken });
153
+ return refreshedToken;
154
+ }),
155
+ onRefreshFailure: (error) => {
156
+ console.error("Failed to refresh Firebase ID token:", error);
157
+ }
158
+ };
159
+ }
101
160
  fetchFirebaseConfig() {
102
161
  return __awaiter(this, void 0, void 0, function* () {
103
162
  try {
@@ -110,6 +169,54 @@ class FirebaseUnifiedService {
110
169
  }
111
170
  });
112
171
  }
172
+ buildEmailVerificationSettings(loginId) {
173
+ return {
174
+ url: this.buildEmailVerificationUrl(loginId),
175
+ handleCodeInApp: false,
176
+ };
177
+ }
178
+ buildEmailVerificationUrl(loginId) {
179
+ return appendQueryParams(this.emailVerificationUrl, {
180
+ loginId,
181
+ continueUrl: this.emailVerificationContinueUrl,
182
+ });
183
+ }
184
+ ensureBackendVerification(firebaseUser, backendUser, idToken) {
185
+ var _a, _b, _c, _d, _e, _f, _g;
186
+ return __awaiter(this, void 0, void 0, function* () {
187
+ const firebaseVerified = firebaseUser.emailVerified;
188
+ const backendVerified = (_b = (_a = backendUser.settings) === null || _a === void 0 ? void 0 : _a.hasVerified) !== null && _b !== void 0 ? _b : false;
189
+ if (!firebaseVerified || backendVerified) {
190
+ return backendUser;
191
+ }
192
+ if (!backendUser.id) {
193
+ console.warn("Missing backend user id when attempting to mark verification status.");
194
+ return backendUser;
195
+ }
196
+ const settingsUpdate = {
197
+ paymentMethods: ((_d = (_c = backendUser.settings) === null || _c === void 0 ? void 0 : _c.paymentMethods) !== null && _d !== void 0 ? _d : []).map((method) => (Object.assign({}, method))),
198
+ hasVerified: true,
199
+ };
200
+ const preferredToken = (_e = backendUser.settings) === null || _e === void 0 ? void 0 : _e.preferredTokenCode;
201
+ if (preferredToken !== undefined && preferredToken !== null) {
202
+ settingsUpdate.preferredTokenCode = preferredToken;
203
+ }
204
+ const request = {
205
+ userId: backendUser.id,
206
+ settings: settingsUpdate,
207
+ };
208
+ try {
209
+ const response = yield this.client.updateUserSettings(request, {
210
+ Authorization: `Bearer ${idToken}`,
211
+ });
212
+ return (_g = (_f = response.users) === null || _f === void 0 ? void 0 : _f[0]) !== null && _g !== void 0 ? _g : backendUser;
213
+ }
214
+ catch (error) {
215
+ console.error("Failed to update backend verification status:", error);
216
+ return backendUser;
217
+ }
218
+ });
219
+ }
113
220
  // Messaging methods
114
221
  requestNotificationPermission() {
115
222
  return __awaiter(this, void 0, void 0, function* () {
@@ -169,22 +276,24 @@ class FirebaseUnifiedService {
169
276
  signInWithEmail(email, password) {
170
277
  return __awaiter(this, void 0, void 0, function* () {
171
278
  try {
172
- if (!this.auth) {
279
+ const auth = yield this.ensureAuthInstance();
280
+ if (!auth) {
173
281
  console.error("Firebase Auth not initialized");
174
282
  return AuthResult.failure("Firebase Auth not initialized");
175
283
  }
176
- const userCredential = yield (0, auth_1.signInWithEmailAndPassword)(this.auth, email, password);
284
+ const userCredential = yield (0, auth_1.signInWithEmailAndPassword)(auth, email, password);
177
285
  const idToken = yield userCredential.user.getIdToken();
178
286
  const backendUser = yield this.getUserFromBackend(userCredential.user.uid, idToken);
179
287
  if (backendUser) {
180
- const authResult = this._createSuccessAuthResult(userCredential.user, backendUser, AuthProvider.EMAIL, idToken);
288
+ const syncedBackendUser = yield this.ensureBackendVerification(userCredential.user, backendUser, idToken);
289
+ const authResult = this._createSuccessAuthResult(userCredential.user, syncedBackendUser, AuthProvider.EMAIL, idToken);
181
290
  // Update UserContext
182
291
  UserContext_1.userContext.setUser({
183
292
  id: userCredential.user.uid,
184
- username: backendUser.username || '',
293
+ username: syncedBackendUser.username || '',
185
294
  email: userCredential.user.email || '',
186
- idToken: idToken,
187
- isAdmin: backendUser.admin || false
295
+ idToken,
296
+ isAdmin: syncedBackendUser.admin || false
188
297
  });
189
298
  return authResult;
190
299
  }
@@ -205,15 +314,16 @@ class FirebaseUnifiedService {
205
314
  createUserWithEmail(email, password, username) {
206
315
  return __awaiter(this, void 0, void 0, function* () {
207
316
  try {
208
- if (!this.auth) {
317
+ const auth = yield this.ensureAuthInstance();
318
+ if (!auth) {
209
319
  return AuthResult.failure("Firebase Auth not initialized");
210
320
  }
211
321
  // First create the user in Firebase
212
- const userCredential = yield (0, auth_1.createUserWithEmailAndPassword)(this.auth, email, password);
322
+ const userCredential = yield (0, auth_1.createUserWithEmailAndPassword)(auth, email, password);
213
323
  const user = userCredential.user;
214
324
  const idToken = yield user.getIdToken();
215
325
  // Send email verification
216
- yield (0, auth_1.sendEmailVerification)(user);
326
+ yield (0, auth_1.sendEmailVerification)(user, this.buildEmailVerificationSettings(user.uid));
217
327
  const backendUser = yield this.createUserInBackend(user.uid, username, idToken);
218
328
  if (backendUser) {
219
329
  return this._createSuccessAuthResult(user, backendUser, AuthProvider.EMAIL, idToken);
@@ -231,18 +341,20 @@ class FirebaseUnifiedService {
231
341
  signInWithGoogle() {
232
342
  return __awaiter(this, void 0, void 0, function* () {
233
343
  try {
234
- if (!this.auth) {
344
+ const auth = yield this.ensureAuthInstance();
345
+ if (!auth) {
235
346
  return AuthResult.failure("Firebase Auth not initialized");
236
347
  }
237
348
  const provider = new auth_1.GoogleAuthProvider();
238
- const userCredential = yield (0, auth_1.signInWithPopup)(this.auth, provider);
349
+ const userCredential = yield (0, auth_1.signInWithPopup)(auth, provider);
239
350
  const user = userCredential.user;
240
- // Get or create user in your Kotlin backend
241
- const backendUser = yield this.getUserFromBackend(user.uid, user.displayName || '');
242
351
  const idToken = yield user.getIdToken();
352
+ // Get or create user in your Kotlin backend
353
+ const backendUser = yield this.getUserFromBackend(user.uid, idToken);
243
354
  if (backendUser) {
355
+ const syncedBackendUser = yield this.ensureBackendVerification(user, backendUser, idToken);
244
356
  // Use the new helper method
245
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.GOOGLE, idToken);
357
+ return this._createSuccessAuthResult(user, syncedBackendUser, AuthProvider.GOOGLE, idToken);
246
358
  }
247
359
  else {
248
360
  return AuthResult.failure('Failed to get or create user in backend');
@@ -257,18 +369,20 @@ class FirebaseUnifiedService {
257
369
  signInWithFacebook() {
258
370
  return __awaiter(this, void 0, void 0, function* () {
259
371
  try {
260
- if (!this.auth) {
372
+ const auth = yield this.ensureAuthInstance();
373
+ if (!auth) {
261
374
  return AuthResult.failure("Firebase Auth not initialized");
262
375
  }
263
376
  const provider = new auth_1.FacebookAuthProvider();
264
- const userCredential = yield (0, auth_1.signInWithPopup)(this.auth, provider);
377
+ const userCredential = yield (0, auth_1.signInWithPopup)(auth, provider);
265
378
  const user = userCredential.user;
266
- // Get or create user in your Kotlin backend
267
- const backendUser = yield this.getUserFromBackend(user.uid, user.displayName || '');
268
379
  const idToken = yield user.getIdToken();
380
+ // Get or create user in your Kotlin backend
381
+ const backendUser = yield this.getUserFromBackend(user.uid, idToken);
269
382
  if (backendUser) {
383
+ const syncedBackendUser = yield this.ensureBackendVerification(user, backendUser, idToken);
270
384
  // Use the new helper method
271
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.FACEBOOK, idToken);
385
+ return this._createSuccessAuthResult(user, syncedBackendUser, AuthProvider.FACEBOOK, idToken);
272
386
  }
273
387
  else {
274
388
  return AuthResult.failure('Failed to get or create user in backend');
@@ -283,18 +397,20 @@ class FirebaseUnifiedService {
283
397
  signInWithTwitter() {
284
398
  return __awaiter(this, void 0, void 0, function* () {
285
399
  try {
286
- if (!this.auth) {
400
+ const auth = yield this.ensureAuthInstance();
401
+ if (!auth) {
287
402
  return AuthResult.failure("Firebase Auth not initialized");
288
403
  }
289
404
  const provider = new auth_1.TwitterAuthProvider();
290
- const userCredential = yield (0, auth_1.signInWithPopup)(this.auth, provider);
405
+ const userCredential = yield (0, auth_1.signInWithPopup)(auth, provider);
291
406
  const user = userCredential.user;
292
- // Get or create user in your Kotlin backend
293
- const backendUser = yield this.getUserFromBackend(user.uid, user.displayName || '');
294
407
  const idToken = yield user.getIdToken();
408
+ // Get or create user in your Kotlin backend
409
+ const backendUser = yield this.getUserFromBackend(user.uid, idToken);
295
410
  if (backendUser) {
411
+ const syncedBackendUser = yield this.ensureBackendVerification(user, backendUser, idToken);
296
412
  // Use the new helper method
297
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.TWITTER, idToken);
413
+ return this._createSuccessAuthResult(user, syncedBackendUser, AuthProvider.TWITTER, idToken);
298
414
  }
299
415
  else {
300
416
  return AuthResult.failure('Failed to get or create user in backend');
@@ -309,12 +425,13 @@ class FirebaseUnifiedService {
309
425
  sendEmailVerification() {
310
426
  return __awaiter(this, void 0, void 0, function* () {
311
427
  try {
312
- if (!this.auth) {
428
+ const auth = yield this.ensureAuthInstance();
429
+ if (!auth) {
313
430
  return false;
314
431
  }
315
- const user = this.auth.currentUser;
432
+ const user = auth.currentUser;
316
433
  if (user) {
317
- yield (0, auth_1.sendEmailVerification)(user);
434
+ yield (0, auth_1.sendEmailVerification)(user, this.buildEmailVerificationSettings(user.uid));
318
435
  return true;
319
436
  }
320
437
  return false;
@@ -328,10 +445,11 @@ class FirebaseUnifiedService {
328
445
  sendPasswordResetEmail(email) {
329
446
  return __awaiter(this, void 0, void 0, function* () {
330
447
  try {
331
- if (!this.auth) {
448
+ const auth = yield this.ensureAuthInstance();
449
+ if (!auth) {
332
450
  return false;
333
451
  }
334
- yield (0, auth_1.sendPasswordResetEmail)(this.auth, email);
452
+ yield (0, auth_1.sendPasswordResetEmail)(auth, email);
335
453
  return true;
336
454
  }
337
455
  catch (error) {
@@ -343,10 +461,12 @@ class FirebaseUnifiedService {
343
461
  signOut() {
344
462
  return __awaiter(this, void 0, void 0, function* () {
345
463
  try {
346
- if (!this.auth) {
464
+ const auth = yield this.ensureAuthInstance();
465
+ if (!auth) {
466
+ UserContext_1.userContext.clearUser();
347
467
  return;
348
468
  }
349
- yield (0, auth_1.signOut)(this.auth);
469
+ yield (0, auth_1.signOut)(auth);
350
470
  // Clear UserContext
351
471
  UserContext_1.userContext.clearUser();
352
472
  }
@@ -364,10 +484,11 @@ class FirebaseUnifiedService {
364
484
  sendSignInLinkToEmail(email) {
365
485
  return __awaiter(this, void 0, void 0, function* () {
366
486
  try {
367
- if (!this.auth) {
487
+ const auth = yield this.ensureAuthInstance();
488
+ if (!auth) {
368
489
  return false;
369
490
  }
370
- yield (0, auth_1.sendSignInLinkToEmail)(this.auth, email, this.actionCodeSettings);
491
+ yield (0, auth_1.sendSignInLinkToEmail)(auth, email, this.actionCodeSettings);
371
492
  // Save the email locally to use it later when the user clicks the link
372
493
  window.localStorage.setItem('emailForSignIn', email);
373
494
  return true;
@@ -387,22 +508,24 @@ class FirebaseUnifiedService {
387
508
  signInWithEmailLink(email) {
388
509
  return __awaiter(this, void 0, void 0, function* () {
389
510
  try {
390
- if (!this.auth) {
511
+ const auth = yield this.ensureAuthInstance();
512
+ if (!auth) {
391
513
  return AuthResult.failure("Firebase Auth not initialized");
392
514
  }
393
- if (!this.isSignInWithEmailLink()) {
515
+ if (!(0, auth_1.isSignInWithEmailLink)(auth, window.location.href)) {
394
516
  return AuthResult.failure("Invalid sign-in link");
395
517
  }
396
- const userCredential = yield (0, auth_1.signInWithEmailLink)(this.auth, email, window.location.href);
518
+ const userCredential = yield (0, auth_1.signInWithEmailLink)(auth, email, window.location.href);
397
519
  const user = userCredential.user;
398
520
  // Clear the email from localStorage
399
521
  window.localStorage.removeItem('emailForSignIn');
400
- // Get or create user in your Kotlin backend
401
- const backendUser = yield this.getUserFromBackend(user.uid, user.displayName || '');
402
522
  const idToken = yield user.getIdToken();
523
+ // Get or create user in your Kotlin backend
524
+ const backendUser = yield this.getUserFromBackend(user.uid, idToken);
403
525
  if (backendUser) {
526
+ const syncedBackendUser = yield this.ensureBackendVerification(user, backendUser, idToken);
404
527
  // Use the new helper method
405
- return this._createSuccessAuthResult(user, backendUser, AuthProvider.EMAIL, idToken);
528
+ return this._createSuccessAuthResult(user, syncedBackendUser, AuthProvider.EMAIL, idToken);
406
529
  }
407
530
  else {
408
531
  return AuthResult.failure('Failed to get or create user in backend');
@@ -417,17 +540,26 @@ class FirebaseUnifiedService {
417
540
  getEmailForSignIn() {
418
541
  return window.localStorage.getItem('emailForSignIn');
419
542
  }
543
+ applyEmailVerificationCode(oobCode) {
544
+ return __awaiter(this, void 0, void 0, function* () {
545
+ const auth = yield this.ensureAuthInstance();
546
+ if (!auth) {
547
+ throw new Error("Firebase Auth not initialized");
548
+ }
549
+ yield (0, auth_1.applyActionCode)(auth, oobCode);
550
+ });
551
+ }
420
552
  // Helper method to create success AuthResult
421
553
  _createSuccessAuthResult(user, backendUser, provider, idToken) {
422
554
  const userData = UserData.create(user.uid, user.email || '', backendUser.username || '', user.emailVerified, idToken, backendUser.admin || false);
423
555
  return AuthResult.success(backendUser, userData, provider);
424
556
  }
425
557
  // Backend integration methods
426
- getUserFromBackend(userId, loginId) {
558
+ getUserFromBackend(userId, authToken) {
427
559
  return __awaiter(this, void 0, void 0, function* () {
428
560
  try {
429
561
  const response = yield this.client.getUser(userId, {
430
- Authorization: `Bearer ${loginId}`,
562
+ Authorization: `Bearer ${authToken}`,
431
563
  });
432
564
  return response.users[0];
433
565
  }