@finatic/client 0.0.138 → 0.0.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +278 -461
- package/dist/index.d.ts +59 -516
- package/dist/index.js +337 -456
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +338 -456
- package/dist/index.mjs.map +1 -1
- package/dist/types/core/client/ApiClient.d.ts +12 -26
- package/dist/types/core/client/FinaticConnect.d.ts +20 -103
- package/dist/types/index.d.ts +1 -2
- package/dist/types/mocks/MockApiClient.d.ts +2 -4
- package/dist/types/mocks/utils.d.ts +0 -5
- package/dist/types/types/api/auth.d.ts +12 -30
- package/dist/types/types/api/broker.d.ts +1 -1
- package/dist/types/types/connect.d.ts +4 -1
- package/package.json +7 -3
- package/src/core/client/ApiClient.ts +1721 -0
- package/src/core/client/FinaticConnect.ts +1476 -0
- package/src/core/portal/PortalUI.ts +300 -0
- package/src/index.d.ts +23 -0
- package/src/index.ts +87 -0
- package/src/mocks/MockApiClient.ts +1032 -0
- package/src/mocks/MockDataProvider.ts +986 -0
- package/src/mocks/MockFactory.ts +97 -0
- package/src/mocks/utils.ts +133 -0
- package/src/themes/portalPresets.ts +1307 -0
- package/src/types/api/auth.ts +112 -0
- package/src/types/api/broker.ts +330 -0
- package/src/types/api/core.ts +53 -0
- package/src/types/api/errors.ts +35 -0
- package/src/types/api/orders.ts +45 -0
- package/src/types/api/portfolio.ts +59 -0
- package/src/types/common/pagination.ts +138 -0
- package/src/types/connect.ts +56 -0
- package/src/types/index.ts +25 -0
- package/src/types/portal.ts +214 -0
- package/src/types/ui/theme.ts +105 -0
- package/src/utils/brokerUtils.ts +85 -0
- package/src/utils/errors.ts +104 -0
- package/src/utils/events.ts +54 -0
- package/src/utils/themeUtils.ts +146 -0
package/dist/index.js
CHANGED
|
@@ -205,15 +205,13 @@ class TradingNotEnabledError extends ApiError {
|
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
// Supabase import removed - SDK no longer depends on Supabase
|
|
208
209
|
class ApiClient {
|
|
209
210
|
constructor(baseUrl, deviceInfo) {
|
|
210
211
|
this.currentSessionState = null;
|
|
211
212
|
this.currentSessionId = null;
|
|
212
213
|
this.tradingContext = {};
|
|
213
|
-
//
|
|
214
|
-
this.tokenInfo = null;
|
|
215
|
-
this.refreshPromise = null;
|
|
216
|
-
this.REFRESH_BUFFER_MINUTES = 5; // Refresh token 5 minutes before expiry
|
|
214
|
+
// Session management (no Supabase needed)
|
|
217
215
|
// Session and company context
|
|
218
216
|
this.companyId = null;
|
|
219
217
|
this.csrfToken = null;
|
|
@@ -225,7 +223,9 @@ class ApiClient {
|
|
|
225
223
|
if (!this.baseUrl.includes('/api/v1')) {
|
|
226
224
|
this.baseUrl = `${this.baseUrl}/api/v1`;
|
|
227
225
|
}
|
|
226
|
+
// No Supabase initialization needed - SDK is clean
|
|
228
227
|
}
|
|
228
|
+
// Supabase initialization removed - SDK no longer depends on Supabase
|
|
229
229
|
/**
|
|
230
230
|
* Set session context (session ID, company ID, CSRF token)
|
|
231
231
|
*/
|
|
@@ -253,105 +253,30 @@ class ApiClient {
|
|
|
253
253
|
return this.csrfToken;
|
|
254
254
|
}
|
|
255
255
|
/**
|
|
256
|
-
*
|
|
257
|
-
*/
|
|
258
|
-
setTokens(accessToken, refreshToken, expiresAt, userId) {
|
|
259
|
-
this.tokenInfo = {
|
|
260
|
-
accessToken,
|
|
261
|
-
refreshToken,
|
|
262
|
-
expiresAt,
|
|
263
|
-
userId,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Get the current access token, refreshing if necessary
|
|
256
|
+
* Get a valid access token (session-based auth - no tokens needed)
|
|
268
257
|
*/
|
|
269
258
|
async getValidAccessToken() {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
// Check if token is expired or about to expire
|
|
274
|
-
if (this.isTokenExpired()) {
|
|
275
|
-
await this.refreshTokens();
|
|
276
|
-
}
|
|
277
|
-
return this.tokenInfo.accessToken;
|
|
259
|
+
// Session-based auth - return empty token as we use session headers
|
|
260
|
+
return '';
|
|
278
261
|
}
|
|
262
|
+
// Token expiration check removed - session-based auth doesn't use expiring tokens
|
|
263
|
+
// Supabase refresh method removed - SDK no longer uses Supabase tokens
|
|
279
264
|
/**
|
|
280
|
-
*
|
|
265
|
+
* Perform the actual Supabase session refresh
|
|
281
266
|
*/
|
|
282
|
-
|
|
283
|
-
if (!this.tokenInfo)
|
|
284
|
-
return true;
|
|
285
|
-
const expiryTime = new Date(this.tokenInfo.expiresAt).getTime();
|
|
286
|
-
const currentTime = Date.now();
|
|
287
|
-
const bufferTime = this.REFRESH_BUFFER_MINUTES * 60 * 1000; // 5 minutes in milliseconds
|
|
288
|
-
return currentTime >= expiryTime - bufferTime;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Refresh the access token using the refresh token
|
|
292
|
-
*/
|
|
293
|
-
async refreshTokens() {
|
|
294
|
-
if (!this.tokenInfo) {
|
|
295
|
-
throw new AuthenticationError('No refresh token available.');
|
|
296
|
-
}
|
|
297
|
-
// If a refresh is already in progress, wait for it
|
|
298
|
-
if (this.refreshPromise) {
|
|
299
|
-
await this.refreshPromise;
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
// Start a new refresh
|
|
303
|
-
this.refreshPromise = this.performTokenRefresh();
|
|
304
|
-
try {
|
|
305
|
-
await this.refreshPromise;
|
|
306
|
-
}
|
|
307
|
-
finally {
|
|
308
|
-
this.refreshPromise = null;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
267
|
+
// Supabase refresh method removed - SDK no longer uses Supabase tokens
|
|
311
268
|
/**
|
|
312
|
-
*
|
|
313
|
-
*/
|
|
314
|
-
async performTokenRefresh() {
|
|
315
|
-
if (!this.tokenInfo) {
|
|
316
|
-
throw new AuthenticationError('No refresh token available.');
|
|
317
|
-
}
|
|
318
|
-
try {
|
|
319
|
-
const response = await this.request('/company/auth/refresh', {
|
|
320
|
-
method: 'POST',
|
|
321
|
-
headers: {
|
|
322
|
-
'Content-Type': 'application/json',
|
|
323
|
-
},
|
|
324
|
-
body: {
|
|
325
|
-
refresh_token: this.tokenInfo.refreshToken,
|
|
326
|
-
},
|
|
327
|
-
});
|
|
328
|
-
// Update stored tokens
|
|
329
|
-
this.tokenInfo = {
|
|
330
|
-
accessToken: response.response_data.access_token,
|
|
331
|
-
refreshToken: response.response_data.refresh_token,
|
|
332
|
-
expiresAt: response.response_data.expires_at,
|
|
333
|
-
userId: this.tokenInfo.userId,
|
|
334
|
-
};
|
|
335
|
-
return this.tokenInfo;
|
|
336
|
-
}
|
|
337
|
-
catch (error) {
|
|
338
|
-
// Clear tokens on refresh failure
|
|
339
|
-
this.tokenInfo = null;
|
|
340
|
-
throw new AuthenticationError('Token refresh failed. Please re-authenticate.', error);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Clear stored tokens (useful for logout)
|
|
269
|
+
* Clear session tokens (useful for logout)
|
|
345
270
|
*/
|
|
346
271
|
clearTokens() {
|
|
347
|
-
|
|
348
|
-
this.refreshPromise = null;
|
|
272
|
+
// Session-based auth - no tokens to clear
|
|
349
273
|
}
|
|
350
274
|
/**
|
|
351
|
-
* Get current
|
|
275
|
+
* Get current session info (for debugging/testing) - session-based auth
|
|
352
276
|
*/
|
|
353
277
|
getTokenInfo() {
|
|
354
|
-
|
|
278
|
+
// Session-based auth - no tokens to return
|
|
279
|
+
return null;
|
|
355
280
|
}
|
|
356
281
|
/**
|
|
357
282
|
* Make a request to the API.
|
|
@@ -365,9 +290,12 @@ class ApiClient {
|
|
|
365
290
|
url.searchParams.append(key, value);
|
|
366
291
|
});
|
|
367
292
|
}
|
|
293
|
+
// Get Supabase JWT token
|
|
294
|
+
const accessToken = await this.getValidAccessToken();
|
|
368
295
|
// Build comprehensive headers object with all available session data
|
|
369
296
|
const comprehensiveHeaders = {
|
|
370
297
|
'Content-Type': 'application/json',
|
|
298
|
+
Authorization: `Bearer ${accessToken}`,
|
|
371
299
|
};
|
|
372
300
|
// Add device info if available
|
|
373
301
|
if (this.deviceInfo) {
|
|
@@ -535,7 +463,7 @@ class ApiClient {
|
|
|
535
463
|
}
|
|
536
464
|
// Session Management
|
|
537
465
|
async startSession(token, userId) {
|
|
538
|
-
const response = await this.request('/
|
|
466
|
+
const response = await this.request('/session/start', {
|
|
539
467
|
method: 'POST',
|
|
540
468
|
headers: {
|
|
541
469
|
'Content-Type': 'application/json',
|
|
@@ -589,11 +517,8 @@ class ApiClient {
|
|
|
589
517
|
otp,
|
|
590
518
|
},
|
|
591
519
|
});
|
|
592
|
-
//
|
|
593
|
-
if (response.success && response.data)
|
|
594
|
-
const expiresAt = new Date(Date.now() + response.data.expires_in * 1000).toISOString();
|
|
595
|
-
this.setTokens(response.data.access_token, response.data.refresh_token, expiresAt, response.data.user_id);
|
|
596
|
-
}
|
|
520
|
+
// OTP verification successful - tokens are handled by Supabase client
|
|
521
|
+
if (response.success && response.data) ;
|
|
597
522
|
return response;
|
|
598
523
|
}
|
|
599
524
|
// Direct Authentication
|
|
@@ -602,7 +527,7 @@ class ApiClient {
|
|
|
602
527
|
if (this.currentSessionState !== SessionState.ACTIVE) {
|
|
603
528
|
throw new SessionError('Session must be in ACTIVE state to authenticate');
|
|
604
529
|
}
|
|
605
|
-
const response = await this.request('/
|
|
530
|
+
const response = await this.request('/session/authenticate', {
|
|
606
531
|
method: 'POST',
|
|
607
532
|
headers: {
|
|
608
533
|
'Content-Type': 'application/json',
|
|
@@ -620,11 +545,7 @@ class ApiClient {
|
|
|
620
545
|
},
|
|
621
546
|
});
|
|
622
547
|
// Store tokens after successful direct authentication
|
|
623
|
-
if (response.success && response.data)
|
|
624
|
-
// For direct auth, we don't get expires_in, so we'll set a default 1-hour expiry
|
|
625
|
-
const expiresAt = new Date(Date.now() + 60 * 60 * 1000).toISOString(); // 1 hour
|
|
626
|
-
this.setTokens(response.data.access_token, response.data.refresh_token, expiresAt, userId);
|
|
627
|
-
}
|
|
548
|
+
if (response.success && response.data) ;
|
|
628
549
|
return response;
|
|
629
550
|
}
|
|
630
551
|
// Portal Management
|
|
@@ -638,7 +559,7 @@ class ApiClient {
|
|
|
638
559
|
if (this.currentSessionState !== SessionState.ACTIVE) {
|
|
639
560
|
throw new SessionError('Session must be in ACTIVE state to get portal URL');
|
|
640
561
|
}
|
|
641
|
-
return this.request('/
|
|
562
|
+
return this.request('/session/portal', {
|
|
642
563
|
method: 'GET',
|
|
643
564
|
headers: {
|
|
644
565
|
'Content-Type': 'application/json',
|
|
@@ -799,12 +720,6 @@ class ApiClient {
|
|
|
799
720
|
this.tradingContext.accountNumber = accountNumber;
|
|
800
721
|
this.tradingContext.accountId = accountId;
|
|
801
722
|
}
|
|
802
|
-
getTradingContext() {
|
|
803
|
-
return { ...this.tradingContext };
|
|
804
|
-
}
|
|
805
|
-
clearTradingContext() {
|
|
806
|
-
this.tradingContext = {};
|
|
807
|
-
}
|
|
808
723
|
// Stock convenience methods
|
|
809
724
|
async placeStockMarketOrder(symbol, orderQty, action, broker, accountNumber, extras = {}, connection_id) {
|
|
810
725
|
return this.placeBrokerOrder({
|
|
@@ -812,7 +727,7 @@ class ApiClient {
|
|
|
812
727
|
orderQty,
|
|
813
728
|
action,
|
|
814
729
|
orderType: 'Market',
|
|
815
|
-
assetType: '
|
|
730
|
+
assetType: 'equity',
|
|
816
731
|
timeInForce: 'day',
|
|
817
732
|
broker,
|
|
818
733
|
accountNumber,
|
|
@@ -824,7 +739,7 @@ class ApiClient {
|
|
|
824
739
|
orderQty,
|
|
825
740
|
action,
|
|
826
741
|
orderType: 'Limit',
|
|
827
|
-
assetType: '
|
|
742
|
+
assetType: 'equity',
|
|
828
743
|
price,
|
|
829
744
|
timeInForce,
|
|
830
745
|
broker,
|
|
@@ -837,7 +752,7 @@ class ApiClient {
|
|
|
837
752
|
orderQty,
|
|
838
753
|
action,
|
|
839
754
|
orderType: 'Stop',
|
|
840
|
-
assetType: '
|
|
755
|
+
assetType: 'equity',
|
|
841
756
|
stopPrice,
|
|
842
757
|
timeInForce,
|
|
843
758
|
broker,
|
|
@@ -851,7 +766,7 @@ class ApiClient {
|
|
|
851
766
|
orderQty,
|
|
852
767
|
action,
|
|
853
768
|
orderType: 'Market',
|
|
854
|
-
assetType: '
|
|
769
|
+
assetType: 'crypto',
|
|
855
770
|
timeInForce: 'day',
|
|
856
771
|
broker,
|
|
857
772
|
accountNumber,
|
|
@@ -864,7 +779,7 @@ class ApiClient {
|
|
|
864
779
|
orderQty,
|
|
865
780
|
action,
|
|
866
781
|
orderType: 'Limit',
|
|
867
|
-
assetType: '
|
|
782
|
+
assetType: 'crypto',
|
|
868
783
|
price,
|
|
869
784
|
timeInForce,
|
|
870
785
|
broker,
|
|
@@ -879,7 +794,7 @@ class ApiClient {
|
|
|
879
794
|
orderQty,
|
|
880
795
|
action,
|
|
881
796
|
orderType: 'Market',
|
|
882
|
-
assetType: '
|
|
797
|
+
assetType: 'equity_option',
|
|
883
798
|
timeInForce: 'day',
|
|
884
799
|
broker,
|
|
885
800
|
accountNumber,
|
|
@@ -892,7 +807,7 @@ class ApiClient {
|
|
|
892
807
|
orderQty,
|
|
893
808
|
action,
|
|
894
809
|
orderType: 'Limit',
|
|
895
|
-
assetType: '
|
|
810
|
+
assetType: 'equity_option',
|
|
896
811
|
price,
|
|
897
812
|
timeInForce,
|
|
898
813
|
broker,
|
|
@@ -907,7 +822,7 @@ class ApiClient {
|
|
|
907
822
|
orderQty,
|
|
908
823
|
action,
|
|
909
824
|
orderType: 'Market',
|
|
910
|
-
assetType: '
|
|
825
|
+
assetType: 'future',
|
|
911
826
|
timeInForce: 'day',
|
|
912
827
|
broker,
|
|
913
828
|
accountNumber,
|
|
@@ -919,7 +834,7 @@ class ApiClient {
|
|
|
919
834
|
orderQty,
|
|
920
835
|
action,
|
|
921
836
|
orderType: 'Limit',
|
|
922
|
-
assetType: '
|
|
837
|
+
assetType: 'future',
|
|
923
838
|
price,
|
|
924
839
|
timeInForce,
|
|
925
840
|
broker,
|
|
@@ -1023,7 +938,7 @@ class ApiClient {
|
|
|
1023
938
|
}
|
|
1024
939
|
async getUserToken(sessionId) {
|
|
1025
940
|
const accessToken = await this.getValidAccessToken();
|
|
1026
|
-
return this.request(`/
|
|
941
|
+
return this.request(`/session/${sessionId}/user`, {
|
|
1027
942
|
method: 'GET',
|
|
1028
943
|
headers: {
|
|
1029
944
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -1038,18 +953,27 @@ class ApiClient {
|
|
|
1038
953
|
}
|
|
1039
954
|
/**
|
|
1040
955
|
* Refresh the current session to extend its lifetime
|
|
956
|
+
* Note: This now uses Supabase session refresh instead of custom endpoint
|
|
1041
957
|
*/
|
|
1042
958
|
async refreshSession() {
|
|
1043
959
|
if (!this.currentSessionId || !this.companyId) {
|
|
1044
960
|
throw new SessionError('No active session to refresh');
|
|
1045
961
|
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
962
|
+
// Session-based auth - no token refresh needed
|
|
963
|
+
// Return session info in expected format
|
|
964
|
+
return {
|
|
965
|
+
success: true,
|
|
966
|
+
response_data: {
|
|
967
|
+
session_id: this.currentSessionId,
|
|
968
|
+
company_id: this.companyId,
|
|
969
|
+
status: 'active',
|
|
970
|
+
expires_at: new Date(Date.now() + 60 * 60 * 1000).toISOString(), // 1 hour from now
|
|
971
|
+
user_id: '', // Session-based auth - user_id comes from session
|
|
972
|
+
auto_login: false,
|
|
1051
973
|
},
|
|
1052
|
-
|
|
974
|
+
message: 'Session refreshed successfully',
|
|
975
|
+
status_code: 200,
|
|
976
|
+
};
|
|
1053
977
|
}
|
|
1054
978
|
// Broker Data Management
|
|
1055
979
|
async getBrokerList() {
|
|
@@ -1672,13 +1596,17 @@ class PortalUI {
|
|
|
1672
1596
|
console.warn('[PortalUI] Received message from unauthorized origin:', event.origin, 'Expected:', this.portalOrigin);
|
|
1673
1597
|
return;
|
|
1674
1598
|
}
|
|
1675
|
-
const { type, userId, error, height, data } = event.data;
|
|
1599
|
+
const { type, userId, access_token, refresh_token, error, height, data } = event.data;
|
|
1676
1600
|
console.log('[PortalUI] Received message:', event.data);
|
|
1677
1601
|
switch (type) {
|
|
1678
1602
|
case 'portal-success': {
|
|
1679
1603
|
// Handle both direct userId and data.userId formats
|
|
1680
1604
|
const successUserId = userId || (data && data.userId);
|
|
1681
|
-
|
|
1605
|
+
const tokens = {
|
|
1606
|
+
access_token: access_token || (data && data.access_token),
|
|
1607
|
+
refresh_token: refresh_token || (data && data.refresh_token)
|
|
1608
|
+
};
|
|
1609
|
+
this.handlePortalSuccess(successUserId, tokens);
|
|
1682
1610
|
break;
|
|
1683
1611
|
}
|
|
1684
1612
|
case 'portal-error': {
|
|
@@ -1710,14 +1638,17 @@ class PortalUI {
|
|
|
1710
1638
|
console.warn('[PortalUI] Received unhandled message type:', type);
|
|
1711
1639
|
}
|
|
1712
1640
|
}
|
|
1713
|
-
handlePortalSuccess(userId) {
|
|
1641
|
+
handlePortalSuccess(userId, tokens) {
|
|
1714
1642
|
if (!userId) {
|
|
1715
1643
|
console.error('[PortalUI] Missing userId in portal-success message');
|
|
1716
1644
|
return;
|
|
1717
1645
|
}
|
|
1718
1646
|
console.log('[PortalUI] Portal success - User connected:', userId);
|
|
1647
|
+
if (tokens?.access_token && tokens?.refresh_token) {
|
|
1648
|
+
console.log('[PortalUI] Tokens received for user:', userId);
|
|
1649
|
+
}
|
|
1719
1650
|
// Pass userId to parent (SDK will handle tokens internally)
|
|
1720
|
-
this.options?.onSuccess?.(userId);
|
|
1651
|
+
this.options?.onSuccess?.(userId, tokens);
|
|
1721
1652
|
}
|
|
1722
1653
|
handlePortalError(error) {
|
|
1723
1654
|
console.error('[PortalUI] Portal error:', error);
|
|
@@ -1813,15 +1744,11 @@ class MockDataProvider {
|
|
|
1813
1744
|
* Generate mock tokens
|
|
1814
1745
|
*/
|
|
1815
1746
|
generateTokens(userId) {
|
|
1816
|
-
|
|
1817
|
-
|
|
1747
|
+
`mock_access_${uuid.v4().replace(/-/g, '')}`;
|
|
1748
|
+
`mock_refresh_${uuid.v4().replace(/-/g, '')}`;
|
|
1818
1749
|
return {
|
|
1819
|
-
accessToken,
|
|
1820
|
-
refreshToken,
|
|
1821
|
-
expiresIn: 3600, // 1 hour
|
|
1822
1750
|
user_id: userId,
|
|
1823
|
-
|
|
1824
|
-
scope: 'read write',
|
|
1751
|
+
// Removed token fields - we no longer use Supabase tokens in the SDK
|
|
1825
1752
|
};
|
|
1826
1753
|
}
|
|
1827
1754
|
// Authentication & Session Management Mocks
|
|
@@ -1841,6 +1768,7 @@ class MockDataProvider {
|
|
|
1841
1768
|
};
|
|
1842
1769
|
this.sessionData.set(sessionId, sessionData);
|
|
1843
1770
|
return {
|
|
1771
|
+
success: true,
|
|
1844
1772
|
data: sessionData,
|
|
1845
1773
|
message: 'Session started successfully',
|
|
1846
1774
|
};
|
|
@@ -1862,12 +1790,12 @@ class MockDataProvider {
|
|
|
1862
1790
|
success: true,
|
|
1863
1791
|
message: 'OTP verified successfully',
|
|
1864
1792
|
data: {
|
|
1865
|
-
access_token: tokens
|
|
1866
|
-
refresh_token: tokens
|
|
1793
|
+
access_token: '', // No longer using Supabase tokens
|
|
1794
|
+
refresh_token: '', // No longer using Supabase tokens
|
|
1867
1795
|
user_id: userId,
|
|
1868
|
-
expires_in:
|
|
1869
|
-
scope:
|
|
1870
|
-
token_type:
|
|
1796
|
+
expires_in: 0, // No token expiration for session-based auth
|
|
1797
|
+
scope: 'api:access',
|
|
1798
|
+
token_type: 'Bearer',
|
|
1871
1799
|
},
|
|
1872
1800
|
};
|
|
1873
1801
|
}
|
|
@@ -1879,8 +1807,8 @@ class MockDataProvider {
|
|
|
1879
1807
|
success: true,
|
|
1880
1808
|
message: 'Authentication successful',
|
|
1881
1809
|
data: {
|
|
1882
|
-
access_token: tokens
|
|
1883
|
-
refresh_token: tokens
|
|
1810
|
+
access_token: '', // No longer using Supabase tokens
|
|
1811
|
+
refresh_token: '', // No longer using Supabase tokens
|
|
1884
1812
|
},
|
|
1885
1813
|
};
|
|
1886
1814
|
}
|
|
@@ -1926,6 +1854,8 @@ class MockDataProvider {
|
|
|
1926
1854
|
valid: true,
|
|
1927
1855
|
company_id: this.generateCompanyId(),
|
|
1928
1856
|
status: 'active',
|
|
1857
|
+
is_sandbox: false,
|
|
1858
|
+
environment: 'production',
|
|
1929
1859
|
};
|
|
1930
1860
|
}
|
|
1931
1861
|
async mockCompletePortalSession(sessionId) {
|
|
@@ -2029,6 +1959,12 @@ class MockDataProvider {
|
|
|
2029
1959
|
created_at: new Date().toISOString(),
|
|
2030
1960
|
updated_at: new Date().toISOString(),
|
|
2031
1961
|
last_synced_at: new Date().toISOString(),
|
|
1962
|
+
positions_synced_at: new Date().toISOString(),
|
|
1963
|
+
orders_synced_at: new Date().toISOString(),
|
|
1964
|
+
balances_synced_at: new Date().toISOString(),
|
|
1965
|
+
account_created_at: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString(), // 1 year ago
|
|
1966
|
+
account_updated_at: new Date().toISOString(),
|
|
1967
|
+
account_first_trade_at: new Date(Date.now() - 300 * 24 * 60 * 60 * 1000).toISOString(), // 300 days ago
|
|
2032
1968
|
},
|
|
2033
1969
|
{
|
|
2034
1970
|
id: uuid.v4(),
|
|
@@ -2043,6 +1979,12 @@ class MockDataProvider {
|
|
|
2043
1979
|
created_at: new Date().toISOString(),
|
|
2044
1980
|
updated_at: new Date().toISOString(),
|
|
2045
1981
|
last_synced_at: new Date().toISOString(),
|
|
1982
|
+
positions_synced_at: new Date().toISOString(),
|
|
1983
|
+
orders_synced_at: new Date().toISOString(),
|
|
1984
|
+
balances_synced_at: new Date().toISOString(),
|
|
1985
|
+
account_created_at: new Date(Date.now() - 730 * 24 * 60 * 60 * 1000).toISOString(), // 2 years ago
|
|
1986
|
+
account_updated_at: new Date().toISOString(),
|
|
1987
|
+
account_first_trade_at: new Date(Date.now() - 700 * 24 * 60 * 60 * 1000).toISOString(), // 700 days ago
|
|
2046
1988
|
},
|
|
2047
1989
|
];
|
|
2048
1990
|
return {
|
|
@@ -2528,6 +2470,12 @@ class MockDataProvider {
|
|
|
2528
2470
|
created_at: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(), // Random date within last year
|
|
2529
2471
|
updated_at: new Date().toISOString(),
|
|
2530
2472
|
last_synced_at: new Date().toISOString(),
|
|
2473
|
+
positions_synced_at: new Date().toISOString(),
|
|
2474
|
+
orders_synced_at: new Date().toISOString(),
|
|
2475
|
+
balances_synced_at: new Date().toISOString(),
|
|
2476
|
+
account_created_at: new Date(Date.now() - Math.random() * 730 * 24 * 60 * 60 * 1000).toISOString(), // Random date within last 2 years
|
|
2477
|
+
account_updated_at: new Date().toISOString(),
|
|
2478
|
+
account_first_trade_at: new Date(Date.now() - Math.random() * 500 * 24 * 60 * 60 * 1000).toISOString(), // Random date within last 500 days
|
|
2531
2479
|
});
|
|
2532
2480
|
}
|
|
2533
2481
|
return accounts;
|
|
@@ -2864,12 +2812,6 @@ class MockApiClient {
|
|
|
2864
2812
|
this.tradingContext.accountId = accountId;
|
|
2865
2813
|
console.log('MockApiClient.setAccount Debug - Updated context:', this.tradingContext);
|
|
2866
2814
|
}
|
|
2867
|
-
getTradingContext() {
|
|
2868
|
-
return { ...this.tradingContext };
|
|
2869
|
-
}
|
|
2870
|
-
clearTradingContext() {
|
|
2871
|
-
this.tradingContext = {};
|
|
2872
|
-
}
|
|
2873
2815
|
// Stock convenience methods
|
|
2874
2816
|
async placeStockMarketOrder(symbol, orderQty, action, broker, accountNumber, extras = {}) {
|
|
2875
2817
|
return this.placeBrokerOrder({
|
|
@@ -2879,7 +2821,7 @@ class MockApiClient {
|
|
|
2879
2821
|
orderQty,
|
|
2880
2822
|
action,
|
|
2881
2823
|
orderType: 'Market',
|
|
2882
|
-
assetType: '
|
|
2824
|
+
assetType: 'equity',
|
|
2883
2825
|
timeInForce: 'day',
|
|
2884
2826
|
}, extras);
|
|
2885
2827
|
}
|
|
@@ -2891,7 +2833,7 @@ class MockApiClient {
|
|
|
2891
2833
|
orderQty,
|
|
2892
2834
|
action,
|
|
2893
2835
|
orderType: 'Limit',
|
|
2894
|
-
assetType: '
|
|
2836
|
+
assetType: 'equity',
|
|
2895
2837
|
timeInForce,
|
|
2896
2838
|
price,
|
|
2897
2839
|
}, extras);
|
|
@@ -2904,7 +2846,7 @@ class MockApiClient {
|
|
|
2904
2846
|
orderQty,
|
|
2905
2847
|
action,
|
|
2906
2848
|
orderType: 'Stop',
|
|
2907
|
-
assetType: '
|
|
2849
|
+
assetType: 'equity',
|
|
2908
2850
|
timeInForce,
|
|
2909
2851
|
stopPrice,
|
|
2910
2852
|
}, extras);
|
|
@@ -2918,7 +2860,7 @@ class MockApiClient {
|
|
|
2918
2860
|
orderQty: options.quantity || orderQty,
|
|
2919
2861
|
action,
|
|
2920
2862
|
orderType: 'Market',
|
|
2921
|
-
assetType: '
|
|
2863
|
+
assetType: 'crypto',
|
|
2922
2864
|
timeInForce: 'gtc', // Crypto typically uses GTC
|
|
2923
2865
|
};
|
|
2924
2866
|
return this.placeBrokerOrder(orderParams, extras);
|
|
@@ -2931,7 +2873,7 @@ class MockApiClient {
|
|
|
2931
2873
|
orderQty: options.quantity || orderQty,
|
|
2932
2874
|
action,
|
|
2933
2875
|
orderType: 'Limit',
|
|
2934
|
-
assetType: '
|
|
2876
|
+
assetType: 'crypto',
|
|
2935
2877
|
timeInForce,
|
|
2936
2878
|
price,
|
|
2937
2879
|
};
|
|
@@ -2946,7 +2888,7 @@ class MockApiClient {
|
|
|
2946
2888
|
orderQty,
|
|
2947
2889
|
action,
|
|
2948
2890
|
orderType: 'Market',
|
|
2949
|
-
assetType: '
|
|
2891
|
+
assetType: 'equity_option',
|
|
2950
2892
|
timeInForce: 'day',
|
|
2951
2893
|
};
|
|
2952
2894
|
return this.placeBrokerOrder(orderParams, extras);
|
|
@@ -2959,7 +2901,7 @@ class MockApiClient {
|
|
|
2959
2901
|
orderQty,
|
|
2960
2902
|
action,
|
|
2961
2903
|
orderType: 'Limit',
|
|
2962
|
-
assetType: '
|
|
2904
|
+
assetType: 'equity_option',
|
|
2963
2905
|
timeInForce,
|
|
2964
2906
|
price,
|
|
2965
2907
|
};
|
|
@@ -2974,7 +2916,7 @@ class MockApiClient {
|
|
|
2974
2916
|
orderQty,
|
|
2975
2917
|
action,
|
|
2976
2918
|
orderType: 'Market',
|
|
2977
|
-
assetType: '
|
|
2919
|
+
assetType: 'future',
|
|
2978
2920
|
timeInForce: 'day',
|
|
2979
2921
|
}, extras);
|
|
2980
2922
|
}
|
|
@@ -2986,7 +2928,7 @@ class MockApiClient {
|
|
|
2986
2928
|
orderQty,
|
|
2987
2929
|
action,
|
|
2988
2930
|
orderType: 'Limit',
|
|
2989
|
-
assetType: '
|
|
2931
|
+
assetType: 'future',
|
|
2990
2932
|
timeInForce,
|
|
2991
2933
|
price,
|
|
2992
2934
|
}, extras);
|
|
@@ -3200,6 +3142,8 @@ class MockApiClient {
|
|
|
3200
3142
|
/**
|
|
3201
3143
|
* Utility functions for mock system environment detection
|
|
3202
3144
|
*/
|
|
3145
|
+
// Type declarations for Node.js environment
|
|
3146
|
+
// Note: process is already declared globally in Node.js types
|
|
3203
3147
|
/**
|
|
3204
3148
|
* Check if mocks should be used based on environment variables
|
|
3205
3149
|
* Supports both browser and Node.js environments
|
|
@@ -4902,95 +4846,161 @@ class FinaticConnect extends EventEmitter {
|
|
|
4902
4846
|
// Register automatic session cleanup
|
|
4903
4847
|
this.registerSessionCleanup();
|
|
4904
4848
|
}
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4849
|
+
async linkUserToSession(userId) {
|
|
4850
|
+
try {
|
|
4851
|
+
if (!this.sessionId) {
|
|
4852
|
+
console.error('No session ID available for user linking');
|
|
4853
|
+
return false;
|
|
4854
|
+
}
|
|
4855
|
+
// Call API endpoint to authenticate user with session
|
|
4856
|
+
const response = await this.apiClient.request('/session/authenticate', {
|
|
4857
|
+
method: 'POST',
|
|
4858
|
+
body: {
|
|
4859
|
+
session_id: this.sessionId,
|
|
4860
|
+
user_id: userId,
|
|
4861
|
+
},
|
|
4862
|
+
});
|
|
4863
|
+
if (response.error) {
|
|
4864
|
+
console.error('Failed to link user to session:', response.error);
|
|
4865
|
+
return false;
|
|
4866
|
+
}
|
|
4867
|
+
console.log('User linked to session successfully');
|
|
4868
|
+
return true;
|
|
4869
|
+
}
|
|
4870
|
+
catch (error) {
|
|
4871
|
+
console.error('Error linking user to session:', error);
|
|
4872
|
+
return false;
|
|
4908
4873
|
}
|
|
4909
|
-
// Keep existing user_id or use empty string as fallback
|
|
4910
|
-
const userId = this.userToken?.user_id || '';
|
|
4911
|
-
this.userToken = {
|
|
4912
|
-
accessToken: tokens.access_token,
|
|
4913
|
-
refreshToken: tokens.refresh_token,
|
|
4914
|
-
expiresIn: 3600, // Default to 1 hour if not provided
|
|
4915
|
-
user_id: userId,
|
|
4916
|
-
tokenType: 'Bearer',
|
|
4917
|
-
scope: 'api:access',
|
|
4918
|
-
};
|
|
4919
|
-
// Store tokens in ApiClient for automatic refresh
|
|
4920
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
4921
|
-
this.apiClient.setTokens(tokens.access_token, tokens.refresh_token, expiresAt, userId);
|
|
4922
4874
|
}
|
|
4923
4875
|
/**
|
|
4924
|
-
*
|
|
4925
|
-
* @
|
|
4876
|
+
* Store user ID for authentication state persistence
|
|
4877
|
+
* @param userId - The user ID to store
|
|
4926
4878
|
*/
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
this.userToken
|
|
4879
|
+
storeUserId(userId) {
|
|
4880
|
+
// Initialize userToken if it doesn't exist
|
|
4881
|
+
if (!this.userToken) {
|
|
4882
|
+
this.userToken = {
|
|
4883
|
+
user_id: userId,
|
|
4884
|
+
};
|
|
4885
|
+
}
|
|
4886
|
+
else {
|
|
4887
|
+
// Update existing userToken with new userId
|
|
4888
|
+
this.userToken.user_id = userId;
|
|
4889
|
+
}
|
|
4890
|
+
// Set user ID in ApiClient for session context
|
|
4891
|
+
this.apiClient.setSessionContext(this.sessionId || '', this.companyId, undefined);
|
|
4931
4892
|
}
|
|
4932
4893
|
/**
|
|
4933
|
-
* Check if the
|
|
4934
|
-
* @returns True if authenticated
|
|
4894
|
+
* Check if the user is fully authenticated (has userId in session context)
|
|
4895
|
+
* @returns True if the user is fully authenticated and ready for API calls
|
|
4935
4896
|
*/
|
|
4936
|
-
|
|
4937
|
-
|
|
4897
|
+
async isAuthenticated() {
|
|
4898
|
+
// Check internal session context only - no localStorage dependency
|
|
4899
|
+
return this.userToken?.user_id !== undefined && this.userToken?.user_id !== null;
|
|
4938
4900
|
}
|
|
4939
4901
|
/**
|
|
4940
4902
|
* Get user's orders with pagination and optional filtering
|
|
4941
4903
|
* @param params - Query parameters including page, perPage, and filters
|
|
4942
4904
|
* @returns Promise with paginated result that supports navigation
|
|
4943
4905
|
*/
|
|
4944
|
-
async getOrders(
|
|
4945
|
-
if (!this.
|
|
4906
|
+
async getOrders(page = 1, perPage = 100, options, filters) {
|
|
4907
|
+
if (!(await this.isAuthenticated())) {
|
|
4946
4908
|
throw new AuthenticationError('User is not authenticated');
|
|
4947
4909
|
}
|
|
4948
|
-
const
|
|
4949
|
-
|
|
4950
|
-
const
|
|
4951
|
-
|
|
4910
|
+
const result = await this.apiClient.getBrokerOrdersPage(page, perPage, filters);
|
|
4911
|
+
// Add navigation methods to the result
|
|
4912
|
+
const paginatedResult = result;
|
|
4913
|
+
paginatedResult.next_page = async () => {
|
|
4914
|
+
if (paginatedResult.hasNext) {
|
|
4915
|
+
return this.apiClient.getBrokerOrdersPage(page + 1, perPage, filters);
|
|
4916
|
+
}
|
|
4917
|
+
throw new Error('No next page available');
|
|
4918
|
+
};
|
|
4919
|
+
paginatedResult.previous_page = async () => {
|
|
4920
|
+
if (paginatedResult.has_previous) {
|
|
4921
|
+
return this.apiClient.getBrokerOrdersPage(page - 1, perPage, filters);
|
|
4922
|
+
}
|
|
4923
|
+
throw new Error('No previous page available');
|
|
4924
|
+
};
|
|
4925
|
+
return paginatedResult;
|
|
4952
4926
|
}
|
|
4953
4927
|
/**
|
|
4954
4928
|
* Get user's positions with pagination and optional filtering
|
|
4955
4929
|
* @param params - Query parameters including page, perPage, and filters
|
|
4956
4930
|
* @returns Promise with paginated result that supports navigation
|
|
4957
4931
|
*/
|
|
4958
|
-
async getPositions(
|
|
4959
|
-
if (!this.
|
|
4932
|
+
async getPositions(page = 1, perPage = 100, options, filters) {
|
|
4933
|
+
if (!(await this.isAuthenticated())) {
|
|
4960
4934
|
throw new AuthenticationError('User is not authenticated');
|
|
4961
4935
|
}
|
|
4962
|
-
const
|
|
4963
|
-
|
|
4964
|
-
const
|
|
4965
|
-
|
|
4936
|
+
const result = await this.apiClient.getBrokerPositionsPage(page, perPage, filters);
|
|
4937
|
+
// Add navigation methods to the result
|
|
4938
|
+
const paginatedResult = result;
|
|
4939
|
+
paginatedResult.next_page = async () => {
|
|
4940
|
+
if (paginatedResult.hasNext) {
|
|
4941
|
+
return this.apiClient.getBrokerPositionsPage(page + 1, perPage, filters);
|
|
4942
|
+
}
|
|
4943
|
+
throw new Error('No next page available');
|
|
4944
|
+
};
|
|
4945
|
+
paginatedResult.previous_page = async () => {
|
|
4946
|
+
if (paginatedResult.has_previous) {
|
|
4947
|
+
return this.apiClient.getBrokerPositionsPage(page - 1, perPage, filters);
|
|
4948
|
+
}
|
|
4949
|
+
throw new Error('No previous page available');
|
|
4950
|
+
};
|
|
4951
|
+
return paginatedResult;
|
|
4966
4952
|
}
|
|
4967
4953
|
/**
|
|
4968
4954
|
* Get user's accounts with pagination and optional filtering
|
|
4969
4955
|
* @param params - Query parameters including page, perPage, and filters
|
|
4970
4956
|
* @returns Promise with paginated result that supports navigation
|
|
4971
4957
|
*/
|
|
4972
|
-
async getAccounts(
|
|
4973
|
-
if (!this.
|
|
4958
|
+
async getAccounts(page = 1, perPage = 100, options, filters) {
|
|
4959
|
+
if (!(await this.isAuthenticated())) {
|
|
4974
4960
|
throw new AuthenticationError('User is not authenticated');
|
|
4975
4961
|
}
|
|
4976
|
-
const
|
|
4977
|
-
|
|
4978
|
-
const
|
|
4979
|
-
|
|
4962
|
+
const result = await this.apiClient.getBrokerAccountsPage(page, perPage, filters);
|
|
4963
|
+
// Add navigation methods to the result
|
|
4964
|
+
const paginatedResult = result;
|
|
4965
|
+
paginatedResult.next_page = async () => {
|
|
4966
|
+
if (paginatedResult.hasNext) {
|
|
4967
|
+
return this.apiClient.getBrokerAccountsPage(page + 1, perPage, filters);
|
|
4968
|
+
}
|
|
4969
|
+
throw new Error('No next page available');
|
|
4970
|
+
};
|
|
4971
|
+
paginatedResult.previous_page = async () => {
|
|
4972
|
+
if (paginatedResult.has_previous) {
|
|
4973
|
+
return this.apiClient.getBrokerAccountsPage(page - 1, perPage, filters);
|
|
4974
|
+
}
|
|
4975
|
+
throw new Error('No previous page available');
|
|
4976
|
+
};
|
|
4977
|
+
return paginatedResult;
|
|
4980
4978
|
}
|
|
4981
4979
|
/**
|
|
4982
4980
|
* Get user's balances with pagination and optional filtering
|
|
4983
4981
|
* @param params - Query parameters including page, perPage, and filters
|
|
4984
4982
|
* @returns Promise with paginated result that supports navigation
|
|
4985
4983
|
*/
|
|
4986
|
-
async getBalances(
|
|
4987
|
-
if (!this.
|
|
4984
|
+
async getBalances(page = 1, perPage = 100, options, filters) {
|
|
4985
|
+
if (!(await this.isAuthenticated())) {
|
|
4988
4986
|
throw new AuthenticationError('User is not authenticated');
|
|
4989
4987
|
}
|
|
4990
|
-
const
|
|
4991
|
-
|
|
4992
|
-
const
|
|
4993
|
-
|
|
4988
|
+
const result = await this.apiClient.getBrokerBalancesPage(page, perPage, filters);
|
|
4989
|
+
// Add navigation methods to the result
|
|
4990
|
+
const paginatedResult = result;
|
|
4991
|
+
paginatedResult.next_page = async () => {
|
|
4992
|
+
if (paginatedResult.hasNext) {
|
|
4993
|
+
return this.apiClient.getBrokerBalancesPage(page + 1, perPage, filters);
|
|
4994
|
+
}
|
|
4995
|
+
throw new Error('No next page available');
|
|
4996
|
+
};
|
|
4997
|
+
paginatedResult.previous_page = async () => {
|
|
4998
|
+
if (paginatedResult.has_previous) {
|
|
4999
|
+
return this.apiClient.getBrokerBalancesPage(page - 1, perPage, filters);
|
|
5000
|
+
}
|
|
5001
|
+
throw new Error('No previous page available');
|
|
5002
|
+
};
|
|
5003
|
+
return paginatedResult;
|
|
4994
5004
|
}
|
|
4995
5005
|
/**
|
|
4996
5006
|
* Initialize the Finatic Connect SDK
|
|
@@ -5043,26 +5053,20 @@ class FinaticConnect extends EventEmitter {
|
|
|
5043
5053
|
FinaticConnect.instance.apiClient.setSessionContext(FinaticConnect.instance.sessionId, FinaticConnect.instance.companyId, startResponse.data.csrf_token // If available in response
|
|
5044
5054
|
);
|
|
5045
5055
|
}
|
|
5046
|
-
// If userId is provided,
|
|
5056
|
+
// If userId is provided, try to link user to session
|
|
5047
5057
|
if (normalizedUserId) {
|
|
5048
5058
|
try {
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
FinaticConnect.instance.userToken = userToken;
|
|
5061
|
-
// Set tokens in ApiClient for automatic token management
|
|
5062
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
5063
|
-
FinaticConnect.instance.apiClient.setTokens(authResponse.data.access_token, authResponse.data.refresh_token, expiresAt, normalizedUserId);
|
|
5064
|
-
// Emit success event
|
|
5065
|
-
FinaticConnect.instance.emit('success', normalizedUserId);
|
|
5059
|
+
// Try to link user to session via API
|
|
5060
|
+
const linked = await FinaticConnect.instance.linkUserToSession(normalizedUserId);
|
|
5061
|
+
if (linked) {
|
|
5062
|
+
// Store user ID for authentication state
|
|
5063
|
+
FinaticConnect.instance.storeUserId(normalizedUserId);
|
|
5064
|
+
// Emit success event
|
|
5065
|
+
FinaticConnect.instance.emit('success', normalizedUserId);
|
|
5066
|
+
}
|
|
5067
|
+
else {
|
|
5068
|
+
console.warn('Failed to link user to session during initialization');
|
|
5069
|
+
}
|
|
5066
5070
|
}
|
|
5067
5071
|
catch (error) {
|
|
5068
5072
|
FinaticConnect.instance.emit('error', error);
|
|
@@ -5083,38 +5087,25 @@ class FinaticConnect extends EventEmitter {
|
|
|
5083
5087
|
* Get the user and tokens for a completed session
|
|
5084
5088
|
* @returns Promise with user information and tokens
|
|
5085
5089
|
*/
|
|
5086
|
-
async getSessionUser() {
|
|
5087
|
-
if (!this.isAuthed()) {
|
|
5088
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5089
|
-
}
|
|
5090
|
-
if (!this.userToken) {
|
|
5091
|
-
throw new AuthenticationError('No user token available');
|
|
5092
|
-
}
|
|
5093
|
-
return {
|
|
5094
|
-
user_id: this.userToken.userId,
|
|
5095
|
-
access_token: this.userToken.accessToken,
|
|
5096
|
-
refresh_token: this.userToken.refreshToken,
|
|
5097
|
-
expires_in: this.userToken.expiresIn,
|
|
5098
|
-
token_type: this.userToken.tokenType,
|
|
5099
|
-
scope: this.userToken.scope,
|
|
5100
|
-
company_id: this.companyId,
|
|
5101
|
-
};
|
|
5102
|
-
}
|
|
5103
5090
|
async initializeWithUser(userId) {
|
|
5104
5091
|
try {
|
|
5105
5092
|
if (!this.sessionId) {
|
|
5106
5093
|
throw new SessionError('Session not initialized');
|
|
5107
5094
|
}
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
if (
|
|
5111
|
-
|
|
5112
|
-
|
|
5095
|
+
// Try to link user to session
|
|
5096
|
+
const linked = await this.linkUserToSession(userId);
|
|
5097
|
+
if (!linked) {
|
|
5098
|
+
console.warn('Failed to link user to session during initialization');
|
|
5099
|
+
// Don't throw error, just continue without authentication
|
|
5100
|
+
return;
|
|
5113
5101
|
}
|
|
5102
|
+
// Store user ID for authentication state
|
|
5103
|
+
this.storeUserId(userId);
|
|
5114
5104
|
this.emit('success', userId);
|
|
5115
5105
|
}
|
|
5116
5106
|
catch (error) {
|
|
5117
5107
|
this.emit('error', error);
|
|
5108
|
+
throw error;
|
|
5118
5109
|
}
|
|
5119
5110
|
}
|
|
5120
5111
|
/**
|
|
@@ -5167,6 +5158,15 @@ class FinaticConnect extends EventEmitter {
|
|
|
5167
5158
|
url.searchParams.set('email', options.email);
|
|
5168
5159
|
themedPortalUrl = url.toString();
|
|
5169
5160
|
}
|
|
5161
|
+
// Add session ID to portal URL so the portal can use it
|
|
5162
|
+
const url = new URL(themedPortalUrl);
|
|
5163
|
+
if (this.sessionId) {
|
|
5164
|
+
url.searchParams.set('session_id', this.sessionId);
|
|
5165
|
+
}
|
|
5166
|
+
if (this.companyId) {
|
|
5167
|
+
url.searchParams.set('company_id', this.companyId);
|
|
5168
|
+
}
|
|
5169
|
+
themedPortalUrl = url.toString();
|
|
5170
5170
|
// Create portal UI if not exists
|
|
5171
5171
|
if (!this.portalUI) {
|
|
5172
5172
|
this.portalUI = new PortalUI(this.baseUrl);
|
|
@@ -5178,6 +5178,13 @@ class FinaticConnect extends EventEmitter {
|
|
|
5178
5178
|
if (!this.sessionId) {
|
|
5179
5179
|
throw new SessionError('Session not initialized');
|
|
5180
5180
|
}
|
|
5181
|
+
// Store the userId for authentication state
|
|
5182
|
+
this.storeUserId(userId);
|
|
5183
|
+
// Try to link user to session via API
|
|
5184
|
+
const linked = await this.linkUserToSession(userId);
|
|
5185
|
+
if (!linked) {
|
|
5186
|
+
console.warn('Failed to link user to session, but continuing with authentication');
|
|
5187
|
+
}
|
|
5181
5188
|
// Emit portal success event
|
|
5182
5189
|
this.emit('portal:success', userId);
|
|
5183
5190
|
// Emit legacy success event
|
|
@@ -5267,32 +5274,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5267
5274
|
* Place a new order using the broker order API
|
|
5268
5275
|
* @param order - Order details with broker context
|
|
5269
5276
|
*/
|
|
5270
|
-
async placeOrder(order) {
|
|
5271
|
-
if (!this.
|
|
5272
|
-
throw new
|
|
5277
|
+
async placeOrder(order, extras) {
|
|
5278
|
+
if (!(await this.isAuthenticated())) {
|
|
5279
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5280
|
+
}
|
|
5281
|
+
if (!this.userToken?.user_id) {
|
|
5282
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5273
5283
|
}
|
|
5274
5284
|
try {
|
|
5275
|
-
//
|
|
5276
|
-
|
|
5277
|
-
symbol: order.symbol,
|
|
5278
|
-
orderQty: order.quantity,
|
|
5279
|
-
action: order.side === 'buy' ? 'Buy' : 'Sell',
|
|
5280
|
-
orderType: order.orderType === 'market'
|
|
5281
|
-
? 'Market'
|
|
5282
|
-
: order.orderType === 'limit'
|
|
5283
|
-
? 'Limit'
|
|
5284
|
-
: order.orderType === 'stop'
|
|
5285
|
-
? 'Stop'
|
|
5286
|
-
: 'StopLimit',
|
|
5287
|
-
assetType: order.assetType || 'Stock',
|
|
5288
|
-
timeInForce: order.timeInForce,
|
|
5289
|
-
price: order.price,
|
|
5290
|
-
stopPrice: order.stopPrice,
|
|
5291
|
-
broker: order.broker,
|
|
5292
|
-
accountNumber: order.accountNumber,
|
|
5293
|
-
order_id: order.order_id,
|
|
5294
|
-
};
|
|
5295
|
-
return await this.apiClient.placeBrokerOrder(this.userToken.accessToken, brokerOrder, {}, order.connection_id);
|
|
5285
|
+
// Use the order parameter directly since it's already BrokerOrderParams
|
|
5286
|
+
return await this.apiClient.placeBrokerOrder(order, extras || {}, order.connection_id);
|
|
5296
5287
|
}
|
|
5297
5288
|
catch (error) {
|
|
5298
5289
|
this.emit('error', error);
|
|
@@ -5306,8 +5297,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5306
5297
|
* @param connection_id - Optional connection ID for testing bypass
|
|
5307
5298
|
*/
|
|
5308
5299
|
async cancelOrder(orderId, broker, connection_id) {
|
|
5309
|
-
if (!this.
|
|
5310
|
-
throw new
|
|
5300
|
+
if (!(await this.isAuthenticated())) {
|
|
5301
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5302
|
+
}
|
|
5303
|
+
if (!this.userToken?.user_id) {
|
|
5304
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5311
5305
|
}
|
|
5312
5306
|
try {
|
|
5313
5307
|
return await this.apiClient.cancelBrokerOrder(orderId, broker, {}, connection_id);
|
|
@@ -5325,8 +5319,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5325
5319
|
* @param connection_id - Optional connection ID for testing bypass
|
|
5326
5320
|
*/
|
|
5327
5321
|
async modifyOrder(orderId, modifications, broker, connection_id) {
|
|
5328
|
-
if (!this.
|
|
5329
|
-
throw new
|
|
5322
|
+
if (!(await this.isAuthenticated())) {
|
|
5323
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5324
|
+
}
|
|
5325
|
+
if (!this.userToken?.user_id) {
|
|
5326
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5330
5327
|
}
|
|
5331
5328
|
try {
|
|
5332
5329
|
// Convert modifications to broker format
|
|
@@ -5354,39 +5351,15 @@ class FinaticConnect extends EventEmitter {
|
|
|
5354
5351
|
throw error;
|
|
5355
5352
|
}
|
|
5356
5353
|
}
|
|
5357
|
-
/**
|
|
5358
|
-
* Set the broker context for trading
|
|
5359
|
-
* @param broker - The broker to use for trading
|
|
5360
|
-
*/
|
|
5361
|
-
setTradingContextBroker(broker) {
|
|
5362
|
-
this.apiClient.setBroker(broker);
|
|
5363
|
-
}
|
|
5364
|
-
/**
|
|
5365
|
-
* Set the account context for trading
|
|
5366
|
-
* @param accountNumber - The account number to use for trading
|
|
5367
|
-
* @param accountId - Optional account ID
|
|
5368
|
-
*/
|
|
5369
|
-
setTradingContextAccount(accountNumber, accountId) {
|
|
5370
|
-
this.apiClient.setAccount(accountNumber, accountId);
|
|
5371
|
-
}
|
|
5372
|
-
/**
|
|
5373
|
-
* Get the current trading context
|
|
5374
|
-
*/
|
|
5375
|
-
getTradingContext() {
|
|
5376
|
-
return this.apiClient.getTradingContext();
|
|
5377
|
-
}
|
|
5378
|
-
/**
|
|
5379
|
-
* Clear the trading context
|
|
5380
|
-
*/
|
|
5381
|
-
clearTradingContext() {
|
|
5382
|
-
this.apiClient.clearTradingContext();
|
|
5383
|
-
}
|
|
5384
5354
|
/**
|
|
5385
5355
|
* Place a stock market order (convenience method)
|
|
5386
5356
|
*/
|
|
5387
5357
|
async placeStockMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5388
|
-
if (!this.
|
|
5389
|
-
throw new
|
|
5358
|
+
if (!(await this.isAuthenticated())) {
|
|
5359
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5360
|
+
}
|
|
5361
|
+
if (!this.userToken?.user_id) {
|
|
5362
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5390
5363
|
}
|
|
5391
5364
|
try {
|
|
5392
5365
|
return await this.apiClient.placeStockMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5400,8 +5373,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5400
5373
|
* Place a stock limit order (convenience method)
|
|
5401
5374
|
*/
|
|
5402
5375
|
async placeStockLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5403
|
-
if (!this.
|
|
5404
|
-
throw new
|
|
5376
|
+
if (!(await this.isAuthenticated())) {
|
|
5377
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5378
|
+
}
|
|
5379
|
+
if (!this.userToken?.user_id) {
|
|
5380
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5405
5381
|
}
|
|
5406
5382
|
try {
|
|
5407
5383
|
return await this.apiClient.placeStockLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5415,8 +5391,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5415
5391
|
* Place a stock stop order (convenience method)
|
|
5416
5392
|
*/
|
|
5417
5393
|
async placeStockStopOrder(symbol, quantity, side, stopPrice, timeInForce = 'gtc', broker, accountNumber) {
|
|
5418
|
-
if (!this.
|
|
5419
|
-
throw new
|
|
5394
|
+
if (!(await this.isAuthenticated())) {
|
|
5395
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5396
|
+
}
|
|
5397
|
+
if (!this.userToken?.user_id) {
|
|
5398
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5420
5399
|
}
|
|
5421
5400
|
try {
|
|
5422
5401
|
return await this.apiClient.placeStockStopOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', stopPrice, timeInForce, broker, accountNumber);
|
|
@@ -5430,8 +5409,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5430
5409
|
* Place a crypto market order (convenience method)
|
|
5431
5410
|
*/
|
|
5432
5411
|
async placeCryptoMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5433
|
-
if (!this.
|
|
5434
|
-
throw new
|
|
5412
|
+
if (!(await this.isAuthenticated())) {
|
|
5413
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5414
|
+
}
|
|
5415
|
+
if (!this.userToken?.user_id) {
|
|
5416
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5435
5417
|
}
|
|
5436
5418
|
try {
|
|
5437
5419
|
return await this.apiClient.placeCryptoMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5445,8 +5427,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5445
5427
|
* Place a crypto limit order (convenience method)
|
|
5446
5428
|
*/
|
|
5447
5429
|
async placeCryptoLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5448
|
-
if (!this.
|
|
5449
|
-
throw new
|
|
5430
|
+
if (!(await this.isAuthenticated())) {
|
|
5431
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5432
|
+
}
|
|
5433
|
+
if (!this.userToken?.user_id) {
|
|
5434
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5450
5435
|
}
|
|
5451
5436
|
try {
|
|
5452
5437
|
return await this.apiClient.placeCryptoLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5460,8 +5445,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5460
5445
|
* Place an options market order (convenience method)
|
|
5461
5446
|
*/
|
|
5462
5447
|
async placeOptionsMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5463
|
-
if (!this.
|
|
5464
|
-
throw new
|
|
5448
|
+
if (!(await this.isAuthenticated())) {
|
|
5449
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5450
|
+
}
|
|
5451
|
+
if (!this.userToken?.user_id) {
|
|
5452
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5465
5453
|
}
|
|
5466
5454
|
try {
|
|
5467
5455
|
return await this.apiClient.placeOptionsMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5475,8 +5463,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5475
5463
|
* Place an options limit order (convenience method)
|
|
5476
5464
|
*/
|
|
5477
5465
|
async placeOptionsLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5478
|
-
if (!this.
|
|
5479
|
-
throw new
|
|
5466
|
+
if (!(await this.isAuthenticated())) {
|
|
5467
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5468
|
+
}
|
|
5469
|
+
if (!this.userToken?.user_id) {
|
|
5470
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5480
5471
|
}
|
|
5481
5472
|
try {
|
|
5482
5473
|
return await this.apiClient.placeOptionsLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5490,8 +5481,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5490
5481
|
* Place a futures market order (convenience method)
|
|
5491
5482
|
*/
|
|
5492
5483
|
async placeFuturesMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5493
|
-
if (!this.
|
|
5494
|
-
throw new
|
|
5484
|
+
if (!(await this.isAuthenticated())) {
|
|
5485
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5486
|
+
}
|
|
5487
|
+
if (!this.userToken?.user_id) {
|
|
5488
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5495
5489
|
}
|
|
5496
5490
|
try {
|
|
5497
5491
|
return await this.apiClient.placeFuturesMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5505,8 +5499,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5505
5499
|
* Place a futures limit order (convenience method)
|
|
5506
5500
|
*/
|
|
5507
5501
|
async placeFuturesLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5508
|
-
if (!this.
|
|
5509
|
-
throw new
|
|
5502
|
+
if (!(await this.isAuthenticated())) {
|
|
5503
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5504
|
+
}
|
|
5505
|
+
if (!this.userToken?.user_id) {
|
|
5506
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5510
5507
|
}
|
|
5511
5508
|
try {
|
|
5512
5509
|
return await this.apiClient.placeFuturesLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5521,8 +5518,8 @@ class FinaticConnect extends EventEmitter {
|
|
|
5521
5518
|
* @returns The current user ID or undefined if not authenticated
|
|
5522
5519
|
* @throws AuthenticationError if user is not authenticated
|
|
5523
5520
|
*/
|
|
5524
|
-
getUserId() {
|
|
5525
|
-
if (!this.
|
|
5521
|
+
async getUserId() {
|
|
5522
|
+
if (!(await this.isAuthenticated())) {
|
|
5526
5523
|
return null;
|
|
5527
5524
|
}
|
|
5528
5525
|
if (!this.userToken?.user_id) {
|
|
@@ -5535,7 +5532,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5535
5532
|
* @returns Promise with array of broker information
|
|
5536
5533
|
*/
|
|
5537
5534
|
async getBrokerList() {
|
|
5538
|
-
// if (!this.
|
|
5535
|
+
// if (!this.isAuthenticated()) {
|
|
5539
5536
|
// throw new AuthenticationError('Not authenticated');
|
|
5540
5537
|
// }
|
|
5541
5538
|
const response = await this.apiClient.getBrokerList();
|
|
@@ -5552,7 +5549,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5552
5549
|
* @throws AuthenticationError if user is not authenticated
|
|
5553
5550
|
*/
|
|
5554
5551
|
async getBrokerConnections() {
|
|
5555
|
-
if (!this.
|
|
5552
|
+
if (!(await this.isAuthenticated())) {
|
|
5556
5553
|
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5557
5554
|
}
|
|
5558
5555
|
if (!this.userToken?.user_id) {
|
|
@@ -5626,118 +5623,22 @@ class FinaticConnect extends EventEmitter {
|
|
|
5626
5623
|
return this.getAllPositions({ broker_id: brokerId });
|
|
5627
5624
|
}
|
|
5628
5625
|
// Pagination methods
|
|
5629
|
-
/**
|
|
5630
|
-
* Get a specific page of orders with pagination metadata
|
|
5631
|
-
* @param page - Page number (default: 1)
|
|
5632
|
-
* @param perPage - Items per page (default: 100)
|
|
5633
|
-
* @param filter - Optional filter parameters
|
|
5634
|
-
* @returns Promise with paginated orders result
|
|
5635
|
-
*/
|
|
5636
|
-
async getOrdersPage(page = 1, perPage = 100, filter) {
|
|
5637
|
-
if (!this.isAuthed()) {
|
|
5638
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5639
|
-
}
|
|
5640
|
-
return this.apiClient.getBrokerOrdersPage(page, perPage, filter);
|
|
5641
|
-
}
|
|
5642
|
-
/**
|
|
5643
|
-
* Get a specific page of positions with pagination metadata
|
|
5644
|
-
* @param page - Page number (default: 1)
|
|
5645
|
-
* @param perPage - Items per page (default: 100)
|
|
5646
|
-
* @param filter - Optional filter parameters
|
|
5647
|
-
* @returns Promise with paginated positions result
|
|
5648
|
-
*/
|
|
5649
|
-
async getPositionsPage(page = 1, perPage = 100, filter) {
|
|
5650
|
-
if (!this.isAuthed()) {
|
|
5651
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5652
|
-
}
|
|
5653
|
-
return this.apiClient.getBrokerPositionsPage(page, perPage, filter);
|
|
5654
|
-
}
|
|
5655
|
-
/**
|
|
5656
|
-
* Get a specific page of accounts with pagination metadata
|
|
5657
|
-
* @param page - Page number (default: 1)
|
|
5658
|
-
* @param perPage - Items per page (default: 100)
|
|
5659
|
-
* @param filter - Optional filter parameters
|
|
5660
|
-
* @returns Promise with paginated accounts result
|
|
5661
|
-
*/
|
|
5662
|
-
async getAccountsPage(page = 1, perPage = 100, filter) {
|
|
5663
|
-
if (!this.isAuthed()) {
|
|
5664
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5665
|
-
}
|
|
5666
|
-
return this.apiClient.getBrokerAccountsPage(page, perPage, filter);
|
|
5667
|
-
}
|
|
5668
|
-
async getBalancesPage(page = 1, perPage = 100, filter) {
|
|
5669
|
-
if (!this.isAuthed()) {
|
|
5670
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5671
|
-
}
|
|
5672
|
-
return this.apiClient.getBrokerBalancesPage(page, perPage, filter);
|
|
5673
|
-
}
|
|
5674
|
-
/**
|
|
5675
|
-
* Get the next page of orders
|
|
5676
|
-
* @param previousResult - The previous paginated result
|
|
5677
|
-
* @returns Promise with next page of orders or null if no more pages
|
|
5678
|
-
*/
|
|
5679
|
-
async getNextOrdersPage(previousResult) {
|
|
5680
|
-
if (!this.isAuthed()) {
|
|
5681
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5682
|
-
}
|
|
5683
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5684
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5685
|
-
return this.apiClient.getBrokerOrdersPage(page, limit);
|
|
5686
|
-
});
|
|
5687
|
-
}
|
|
5688
|
-
/**
|
|
5689
|
-
* Get the next page of positions
|
|
5690
|
-
* @param previousResult - The previous paginated result
|
|
5691
|
-
* @returns Promise with next page of positions or null if no more pages
|
|
5692
|
-
*/
|
|
5693
|
-
async getNextPositionsPage(previousResult) {
|
|
5694
|
-
if (!this.isAuthed()) {
|
|
5695
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5696
|
-
}
|
|
5697
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5698
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5699
|
-
return this.apiClient.getBrokerPositionsPage(page, limit);
|
|
5700
|
-
});
|
|
5701
|
-
}
|
|
5702
|
-
/**
|
|
5703
|
-
* Get the next page of accounts
|
|
5704
|
-
* @param previousResult - The previous paginated result
|
|
5705
|
-
* @returns Promise with next page of accounts or null if no more pages
|
|
5706
|
-
*/
|
|
5707
|
-
async getNextAccountsPage(previousResult) {
|
|
5708
|
-
if (!this.isAuthed()) {
|
|
5709
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5710
|
-
}
|
|
5711
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5712
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5713
|
-
return this.apiClient.getBrokerAccountsPage(page, limit);
|
|
5714
|
-
});
|
|
5715
|
-
}
|
|
5716
|
-
async getNextBalancesPage(previousResult) {
|
|
5717
|
-
if (!this.isAuthed()) {
|
|
5718
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5719
|
-
}
|
|
5720
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5721
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5722
|
-
return this.apiClient.getBrokerBalancesPage(page, limit);
|
|
5723
|
-
});
|
|
5724
|
-
}
|
|
5725
5626
|
/**
|
|
5726
5627
|
* Get all orders across all pages (convenience method)
|
|
5727
5628
|
* @param filter - Optional filter parameters
|
|
5728
5629
|
* @returns Promise with all orders
|
|
5729
5630
|
*/
|
|
5730
5631
|
async getAllOrders(filter) {
|
|
5731
|
-
if (!this.
|
|
5632
|
+
if (!(await this.isAuthenticated())) {
|
|
5732
5633
|
throw new AuthenticationError('User is not authenticated');
|
|
5733
5634
|
}
|
|
5734
5635
|
const allData = [];
|
|
5735
|
-
let currentResult = await this.
|
|
5636
|
+
let currentResult = await this.apiClient.getBrokerOrdersPage(1, 100, filter);
|
|
5736
5637
|
while (currentResult) {
|
|
5737
5638
|
allData.push(...currentResult.data);
|
|
5738
5639
|
if (!currentResult.hasNext)
|
|
5739
5640
|
break;
|
|
5740
|
-
const nextResult = await
|
|
5641
|
+
const nextResult = await currentResult.nextPage();
|
|
5741
5642
|
if (!nextResult)
|
|
5742
5643
|
break;
|
|
5743
5644
|
currentResult = nextResult;
|
|
@@ -5750,16 +5651,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5750
5651
|
* @returns Promise with all positions
|
|
5751
5652
|
*/
|
|
5752
5653
|
async getAllPositions(filter) {
|
|
5753
|
-
if (!this.
|
|
5654
|
+
if (!(await this.isAuthenticated())) {
|
|
5754
5655
|
throw new AuthenticationError('User is not authenticated');
|
|
5755
5656
|
}
|
|
5756
5657
|
const allData = [];
|
|
5757
|
-
let currentResult = await this.
|
|
5658
|
+
let currentResult = await this.apiClient.getBrokerPositionsPage(1, 100, filter);
|
|
5758
5659
|
while (currentResult) {
|
|
5759
5660
|
allData.push(...currentResult.data);
|
|
5760
5661
|
if (!currentResult.hasNext)
|
|
5761
5662
|
break;
|
|
5762
|
-
const nextResult = await
|
|
5663
|
+
const nextResult = await currentResult.nextPage();
|
|
5763
5664
|
if (!nextResult)
|
|
5764
5665
|
break;
|
|
5765
5666
|
currentResult = nextResult;
|
|
@@ -5772,16 +5673,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5772
5673
|
* @returns Promise with all accounts
|
|
5773
5674
|
*/
|
|
5774
5675
|
async getAllAccounts(filter) {
|
|
5775
|
-
if (!this.
|
|
5676
|
+
if (!(await this.isAuthenticated())) {
|
|
5776
5677
|
throw new AuthenticationError('User is not authenticated');
|
|
5777
5678
|
}
|
|
5778
5679
|
const allData = [];
|
|
5779
|
-
let currentResult = await this.
|
|
5680
|
+
let currentResult = await this.apiClient.getBrokerAccountsPage(1, 100, filter);
|
|
5780
5681
|
while (currentResult) {
|
|
5781
5682
|
allData.push(...currentResult.data);
|
|
5782
5683
|
if (!currentResult.hasNext)
|
|
5783
5684
|
break;
|
|
5784
|
-
const nextResult = await
|
|
5685
|
+
const nextResult = await currentResult.nextPage();
|
|
5785
5686
|
if (!nextResult)
|
|
5786
5687
|
break;
|
|
5787
5688
|
currentResult = nextResult;
|
|
@@ -5789,16 +5690,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5789
5690
|
return allData;
|
|
5790
5691
|
}
|
|
5791
5692
|
async getAllBalances(filter) {
|
|
5792
|
-
if (!this.
|
|
5693
|
+
if (!(await this.isAuthenticated())) {
|
|
5793
5694
|
throw new AuthenticationError('User is not authenticated');
|
|
5794
5695
|
}
|
|
5795
5696
|
const allData = [];
|
|
5796
|
-
let currentResult = await this.
|
|
5697
|
+
let currentResult = await this.apiClient.getBrokerBalancesPage(1, 100, filter);
|
|
5797
5698
|
while (currentResult) {
|
|
5798
5699
|
allData.push(...currentResult.data);
|
|
5799
5700
|
if (!currentResult.hasNext)
|
|
5800
5701
|
break;
|
|
5801
|
-
const nextResult = await
|
|
5702
|
+
const nextResult = await currentResult.nextPage();
|
|
5802
5703
|
if (!nextResult)
|
|
5803
5704
|
break;
|
|
5804
5705
|
currentResult = nextResult;
|
|
@@ -5843,7 +5744,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5843
5744
|
* Validate session for keep-alive purposes and handle automatic refresh
|
|
5844
5745
|
*/
|
|
5845
5746
|
async validateSessionKeepAlive() {
|
|
5846
|
-
if (!this.sessionId || !this.
|
|
5747
|
+
if (!this.sessionId || !(await this.isAuthenticated())) {
|
|
5847
5748
|
console.log('[FinaticConnect] Session keep-alive skipped - no active session');
|
|
5848
5749
|
return;
|
|
5849
5750
|
}
|
|
@@ -5954,7 +5855,6 @@ class FinaticConnect extends EventEmitter {
|
|
|
5954
5855
|
const response = await fetch(`${this.baseUrl}/portal/${sessionId}/complete`, {
|
|
5955
5856
|
method: 'POST',
|
|
5956
5857
|
headers: {
|
|
5957
|
-
Authorization: `Bearer ${this.userToken?.accessToken || ''}`,
|
|
5958
5858
|
'Content-Type': 'application/json',
|
|
5959
5859
|
},
|
|
5960
5860
|
});
|
|
@@ -5977,7 +5877,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5977
5877
|
* @throws AuthenticationError if user is not authenticated
|
|
5978
5878
|
*/
|
|
5979
5879
|
async disconnectCompany(connectionId) {
|
|
5980
|
-
if (!this.
|
|
5880
|
+
if (!(await this.isAuthenticated())) {
|
|
5981
5881
|
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5982
5882
|
}
|
|
5983
5883
|
if (!this.userToken?.user_id) {
|
|
@@ -5985,24 +5885,6 @@ class FinaticConnect extends EventEmitter {
|
|
|
5985
5885
|
}
|
|
5986
5886
|
return this.apiClient.disconnectCompany(connectionId);
|
|
5987
5887
|
}
|
|
5988
|
-
/**
|
|
5989
|
-
* Get account balances for the authenticated user
|
|
5990
|
-
* @param filters - Optional filters for balances
|
|
5991
|
-
* @returns Promise with balance data
|
|
5992
|
-
*/
|
|
5993
|
-
async getBalances(filters) {
|
|
5994
|
-
if (!this.isAuthed()) {
|
|
5995
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5996
|
-
}
|
|
5997
|
-
try {
|
|
5998
|
-
const response = await this.apiClient.getBalances(filters);
|
|
5999
|
-
return response.response_data || [];
|
|
6000
|
-
}
|
|
6001
|
-
catch (error) {
|
|
6002
|
-
this.emit('error', error);
|
|
6003
|
-
throw error;
|
|
6004
|
-
}
|
|
6005
|
-
}
|
|
6006
5888
|
}
|
|
6007
5889
|
FinaticConnect.instance = null;
|
|
6008
5890
|
|
|
@@ -6014,7 +5896,6 @@ exports.BaseError = BaseError;
|
|
|
6014
5896
|
exports.CompanyAccessError = CompanyAccessError;
|
|
6015
5897
|
exports.EventEmitter = EventEmitter;
|
|
6016
5898
|
exports.FinaticConnect = FinaticConnect;
|
|
6017
|
-
exports.MockFactory = MockFactory;
|
|
6018
5899
|
exports.NetworkError = NetworkError;
|
|
6019
5900
|
exports.OrderError = OrderError;
|
|
6020
5901
|
exports.OrderValidationError = OrderValidationError;
|