@finatic/client 0.0.139 → 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 +55 -515
- package/dist/index.js +326 -456
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +327 -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/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
|
-
}
|
|
267
|
+
// Supabase refresh method removed - SDK no longer uses Supabase tokens
|
|
290
268
|
/**
|
|
291
|
-
*
|
|
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
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Perform the actual token refresh request
|
|
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() {
|
|
@@ -1820,15 +1744,11 @@ class MockDataProvider {
|
|
|
1820
1744
|
* Generate mock tokens
|
|
1821
1745
|
*/
|
|
1822
1746
|
generateTokens(userId) {
|
|
1823
|
-
|
|
1824
|
-
|
|
1747
|
+
`mock_access_${uuid.v4().replace(/-/g, '')}`;
|
|
1748
|
+
`mock_refresh_${uuid.v4().replace(/-/g, '')}`;
|
|
1825
1749
|
return {
|
|
1826
|
-
accessToken,
|
|
1827
|
-
refreshToken,
|
|
1828
|
-
expiresIn: 3600, // 1 hour
|
|
1829
1750
|
user_id: userId,
|
|
1830
|
-
|
|
1831
|
-
scope: 'read write',
|
|
1751
|
+
// Removed token fields - we no longer use Supabase tokens in the SDK
|
|
1832
1752
|
};
|
|
1833
1753
|
}
|
|
1834
1754
|
// Authentication & Session Management Mocks
|
|
@@ -1848,6 +1768,7 @@ class MockDataProvider {
|
|
|
1848
1768
|
};
|
|
1849
1769
|
this.sessionData.set(sessionId, sessionData);
|
|
1850
1770
|
return {
|
|
1771
|
+
success: true,
|
|
1851
1772
|
data: sessionData,
|
|
1852
1773
|
message: 'Session started successfully',
|
|
1853
1774
|
};
|
|
@@ -1869,12 +1790,12 @@ class MockDataProvider {
|
|
|
1869
1790
|
success: true,
|
|
1870
1791
|
message: 'OTP verified successfully',
|
|
1871
1792
|
data: {
|
|
1872
|
-
access_token: tokens
|
|
1873
|
-
refresh_token: tokens
|
|
1793
|
+
access_token: '', // No longer using Supabase tokens
|
|
1794
|
+
refresh_token: '', // No longer using Supabase tokens
|
|
1874
1795
|
user_id: userId,
|
|
1875
|
-
expires_in:
|
|
1876
|
-
scope:
|
|
1877
|
-
token_type:
|
|
1796
|
+
expires_in: 0, // No token expiration for session-based auth
|
|
1797
|
+
scope: 'api:access',
|
|
1798
|
+
token_type: 'Bearer',
|
|
1878
1799
|
},
|
|
1879
1800
|
};
|
|
1880
1801
|
}
|
|
@@ -1886,8 +1807,8 @@ class MockDataProvider {
|
|
|
1886
1807
|
success: true,
|
|
1887
1808
|
message: 'Authentication successful',
|
|
1888
1809
|
data: {
|
|
1889
|
-
access_token: tokens
|
|
1890
|
-
refresh_token: tokens
|
|
1810
|
+
access_token: '', // No longer using Supabase tokens
|
|
1811
|
+
refresh_token: '', // No longer using Supabase tokens
|
|
1891
1812
|
},
|
|
1892
1813
|
};
|
|
1893
1814
|
}
|
|
@@ -1933,6 +1854,8 @@ class MockDataProvider {
|
|
|
1933
1854
|
valid: true,
|
|
1934
1855
|
company_id: this.generateCompanyId(),
|
|
1935
1856
|
status: 'active',
|
|
1857
|
+
is_sandbox: false,
|
|
1858
|
+
environment: 'production',
|
|
1936
1859
|
};
|
|
1937
1860
|
}
|
|
1938
1861
|
async mockCompletePortalSession(sessionId) {
|
|
@@ -2036,6 +1959,12 @@ class MockDataProvider {
|
|
|
2036
1959
|
created_at: new Date().toISOString(),
|
|
2037
1960
|
updated_at: new Date().toISOString(),
|
|
2038
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
|
|
2039
1968
|
},
|
|
2040
1969
|
{
|
|
2041
1970
|
id: uuid.v4(),
|
|
@@ -2050,6 +1979,12 @@ class MockDataProvider {
|
|
|
2050
1979
|
created_at: new Date().toISOString(),
|
|
2051
1980
|
updated_at: new Date().toISOString(),
|
|
2052
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
|
|
2053
1988
|
},
|
|
2054
1989
|
];
|
|
2055
1990
|
return {
|
|
@@ -2535,6 +2470,12 @@ class MockDataProvider {
|
|
|
2535
2470
|
created_at: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(), // Random date within last year
|
|
2536
2471
|
updated_at: new Date().toISOString(),
|
|
2537
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
|
|
2538
2479
|
});
|
|
2539
2480
|
}
|
|
2540
2481
|
return accounts;
|
|
@@ -2871,12 +2812,6 @@ class MockApiClient {
|
|
|
2871
2812
|
this.tradingContext.accountId = accountId;
|
|
2872
2813
|
console.log('MockApiClient.setAccount Debug - Updated context:', this.tradingContext);
|
|
2873
2814
|
}
|
|
2874
|
-
getTradingContext() {
|
|
2875
|
-
return { ...this.tradingContext };
|
|
2876
|
-
}
|
|
2877
|
-
clearTradingContext() {
|
|
2878
|
-
this.tradingContext = {};
|
|
2879
|
-
}
|
|
2880
2815
|
// Stock convenience methods
|
|
2881
2816
|
async placeStockMarketOrder(symbol, orderQty, action, broker, accountNumber, extras = {}) {
|
|
2882
2817
|
return this.placeBrokerOrder({
|
|
@@ -2886,7 +2821,7 @@ class MockApiClient {
|
|
|
2886
2821
|
orderQty,
|
|
2887
2822
|
action,
|
|
2888
2823
|
orderType: 'Market',
|
|
2889
|
-
assetType: '
|
|
2824
|
+
assetType: 'equity',
|
|
2890
2825
|
timeInForce: 'day',
|
|
2891
2826
|
}, extras);
|
|
2892
2827
|
}
|
|
@@ -2898,7 +2833,7 @@ class MockApiClient {
|
|
|
2898
2833
|
orderQty,
|
|
2899
2834
|
action,
|
|
2900
2835
|
orderType: 'Limit',
|
|
2901
|
-
assetType: '
|
|
2836
|
+
assetType: 'equity',
|
|
2902
2837
|
timeInForce,
|
|
2903
2838
|
price,
|
|
2904
2839
|
}, extras);
|
|
@@ -2911,7 +2846,7 @@ class MockApiClient {
|
|
|
2911
2846
|
orderQty,
|
|
2912
2847
|
action,
|
|
2913
2848
|
orderType: 'Stop',
|
|
2914
|
-
assetType: '
|
|
2849
|
+
assetType: 'equity',
|
|
2915
2850
|
timeInForce,
|
|
2916
2851
|
stopPrice,
|
|
2917
2852
|
}, extras);
|
|
@@ -2925,7 +2860,7 @@ class MockApiClient {
|
|
|
2925
2860
|
orderQty: options.quantity || orderQty,
|
|
2926
2861
|
action,
|
|
2927
2862
|
orderType: 'Market',
|
|
2928
|
-
assetType: '
|
|
2863
|
+
assetType: 'crypto',
|
|
2929
2864
|
timeInForce: 'gtc', // Crypto typically uses GTC
|
|
2930
2865
|
};
|
|
2931
2866
|
return this.placeBrokerOrder(orderParams, extras);
|
|
@@ -2938,7 +2873,7 @@ class MockApiClient {
|
|
|
2938
2873
|
orderQty: options.quantity || orderQty,
|
|
2939
2874
|
action,
|
|
2940
2875
|
orderType: 'Limit',
|
|
2941
|
-
assetType: '
|
|
2876
|
+
assetType: 'crypto',
|
|
2942
2877
|
timeInForce,
|
|
2943
2878
|
price,
|
|
2944
2879
|
};
|
|
@@ -2953,7 +2888,7 @@ class MockApiClient {
|
|
|
2953
2888
|
orderQty,
|
|
2954
2889
|
action,
|
|
2955
2890
|
orderType: 'Market',
|
|
2956
|
-
assetType: '
|
|
2891
|
+
assetType: 'equity_option',
|
|
2957
2892
|
timeInForce: 'day',
|
|
2958
2893
|
};
|
|
2959
2894
|
return this.placeBrokerOrder(orderParams, extras);
|
|
@@ -2966,7 +2901,7 @@ class MockApiClient {
|
|
|
2966
2901
|
orderQty,
|
|
2967
2902
|
action,
|
|
2968
2903
|
orderType: 'Limit',
|
|
2969
|
-
assetType: '
|
|
2904
|
+
assetType: 'equity_option',
|
|
2970
2905
|
timeInForce,
|
|
2971
2906
|
price,
|
|
2972
2907
|
};
|
|
@@ -2981,7 +2916,7 @@ class MockApiClient {
|
|
|
2981
2916
|
orderQty,
|
|
2982
2917
|
action,
|
|
2983
2918
|
orderType: 'Market',
|
|
2984
|
-
assetType: '
|
|
2919
|
+
assetType: 'future',
|
|
2985
2920
|
timeInForce: 'day',
|
|
2986
2921
|
}, extras);
|
|
2987
2922
|
}
|
|
@@ -2993,7 +2928,7 @@ class MockApiClient {
|
|
|
2993
2928
|
orderQty,
|
|
2994
2929
|
action,
|
|
2995
2930
|
orderType: 'Limit',
|
|
2996
|
-
assetType: '
|
|
2931
|
+
assetType: 'future',
|
|
2997
2932
|
timeInForce,
|
|
2998
2933
|
price,
|
|
2999
2934
|
}, extras);
|
|
@@ -3207,6 +3142,8 @@ class MockApiClient {
|
|
|
3207
3142
|
/**
|
|
3208
3143
|
* Utility functions for mock system environment detection
|
|
3209
3144
|
*/
|
|
3145
|
+
// Type declarations for Node.js environment
|
|
3146
|
+
// Note: process is already declared globally in Node.js types
|
|
3210
3147
|
/**
|
|
3211
3148
|
* Check if mocks should be used based on environment variables
|
|
3212
3149
|
* Supports both browser and Node.js environments
|
|
@@ -4909,95 +4846,161 @@ class FinaticConnect extends EventEmitter {
|
|
|
4909
4846
|
// Register automatic session cleanup
|
|
4910
4847
|
this.registerSessionCleanup();
|
|
4911
4848
|
}
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
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;
|
|
4915
4873
|
}
|
|
4916
|
-
// Keep existing user_id or use empty string as fallback
|
|
4917
|
-
const userId = this.userToken?.user_id || '';
|
|
4918
|
-
this.userToken = {
|
|
4919
|
-
accessToken: tokens.access_token,
|
|
4920
|
-
refreshToken: tokens.refresh_token,
|
|
4921
|
-
expiresIn: 3600, // Default to 1 hour if not provided
|
|
4922
|
-
user_id: userId,
|
|
4923
|
-
tokenType: 'Bearer',
|
|
4924
|
-
scope: 'api:access',
|
|
4925
|
-
};
|
|
4926
|
-
// Store tokens in ApiClient for automatic refresh
|
|
4927
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
4928
|
-
this.apiClient.setTokens(tokens.access_token, tokens.refresh_token, expiresAt, userId);
|
|
4929
4874
|
}
|
|
4930
4875
|
/**
|
|
4931
|
-
*
|
|
4932
|
-
* @
|
|
4876
|
+
* Store user ID for authentication state persistence
|
|
4877
|
+
* @param userId - The user ID to store
|
|
4933
4878
|
*/
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
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);
|
|
4938
4892
|
}
|
|
4939
4893
|
/**
|
|
4940
|
-
* Check if the
|
|
4941
|
-
* @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
|
|
4942
4896
|
*/
|
|
4943
|
-
|
|
4944
|
-
|
|
4897
|
+
async isAuthenticated() {
|
|
4898
|
+
// Check internal session context only - no localStorage dependency
|
|
4899
|
+
return this.userToken?.user_id !== undefined && this.userToken?.user_id !== null;
|
|
4945
4900
|
}
|
|
4946
4901
|
/**
|
|
4947
4902
|
* Get user's orders with pagination and optional filtering
|
|
4948
4903
|
* @param params - Query parameters including page, perPage, and filters
|
|
4949
4904
|
* @returns Promise with paginated result that supports navigation
|
|
4950
4905
|
*/
|
|
4951
|
-
async getOrders(
|
|
4952
|
-
if (!this.
|
|
4906
|
+
async getOrders(page = 1, perPage = 100, options, filters) {
|
|
4907
|
+
if (!(await this.isAuthenticated())) {
|
|
4953
4908
|
throw new AuthenticationError('User is not authenticated');
|
|
4954
4909
|
}
|
|
4955
|
-
const
|
|
4956
|
-
|
|
4957
|
-
const
|
|
4958
|
-
|
|
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;
|
|
4959
4926
|
}
|
|
4960
4927
|
/**
|
|
4961
4928
|
* Get user's positions with pagination and optional filtering
|
|
4962
4929
|
* @param params - Query parameters including page, perPage, and filters
|
|
4963
4930
|
* @returns Promise with paginated result that supports navigation
|
|
4964
4931
|
*/
|
|
4965
|
-
async getPositions(
|
|
4966
|
-
if (!this.
|
|
4932
|
+
async getPositions(page = 1, perPage = 100, options, filters) {
|
|
4933
|
+
if (!(await this.isAuthenticated())) {
|
|
4967
4934
|
throw new AuthenticationError('User is not authenticated');
|
|
4968
4935
|
}
|
|
4969
|
-
const
|
|
4970
|
-
|
|
4971
|
-
const
|
|
4972
|
-
|
|
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;
|
|
4973
4952
|
}
|
|
4974
4953
|
/**
|
|
4975
4954
|
* Get user's accounts with pagination and optional filtering
|
|
4976
4955
|
* @param params - Query parameters including page, perPage, and filters
|
|
4977
4956
|
* @returns Promise with paginated result that supports navigation
|
|
4978
4957
|
*/
|
|
4979
|
-
async getAccounts(
|
|
4980
|
-
if (!this.
|
|
4958
|
+
async getAccounts(page = 1, perPage = 100, options, filters) {
|
|
4959
|
+
if (!(await this.isAuthenticated())) {
|
|
4981
4960
|
throw new AuthenticationError('User is not authenticated');
|
|
4982
4961
|
}
|
|
4983
|
-
const
|
|
4984
|
-
|
|
4985
|
-
const
|
|
4986
|
-
|
|
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;
|
|
4987
4978
|
}
|
|
4988
4979
|
/**
|
|
4989
4980
|
* Get user's balances with pagination and optional filtering
|
|
4990
4981
|
* @param params - Query parameters including page, perPage, and filters
|
|
4991
4982
|
* @returns Promise with paginated result that supports navigation
|
|
4992
4983
|
*/
|
|
4993
|
-
async getBalances(
|
|
4994
|
-
if (!this.
|
|
4984
|
+
async getBalances(page = 1, perPage = 100, options, filters) {
|
|
4985
|
+
if (!(await this.isAuthenticated())) {
|
|
4995
4986
|
throw new AuthenticationError('User is not authenticated');
|
|
4996
4987
|
}
|
|
4997
|
-
const
|
|
4998
|
-
|
|
4999
|
-
const
|
|
5000
|
-
|
|
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;
|
|
5001
5004
|
}
|
|
5002
5005
|
/**
|
|
5003
5006
|
* Initialize the Finatic Connect SDK
|
|
@@ -5050,26 +5053,20 @@ class FinaticConnect extends EventEmitter {
|
|
|
5050
5053
|
FinaticConnect.instance.apiClient.setSessionContext(FinaticConnect.instance.sessionId, FinaticConnect.instance.companyId, startResponse.data.csrf_token // If available in response
|
|
5051
5054
|
);
|
|
5052
5055
|
}
|
|
5053
|
-
// If userId is provided,
|
|
5056
|
+
// If userId is provided, try to link user to session
|
|
5054
5057
|
if (normalizedUserId) {
|
|
5055
5058
|
try {
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
FinaticConnect.instance.userToken = userToken;
|
|
5068
|
-
// Set tokens in ApiClient for automatic token management
|
|
5069
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
5070
|
-
FinaticConnect.instance.apiClient.setTokens(authResponse.data.access_token, authResponse.data.refresh_token, expiresAt, normalizedUserId);
|
|
5071
|
-
// Emit success event
|
|
5072
|
-
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
|
+
}
|
|
5073
5070
|
}
|
|
5074
5071
|
catch (error) {
|
|
5075
5072
|
FinaticConnect.instance.emit('error', error);
|
|
@@ -5090,38 +5087,25 @@ class FinaticConnect extends EventEmitter {
|
|
|
5090
5087
|
* Get the user and tokens for a completed session
|
|
5091
5088
|
* @returns Promise with user information and tokens
|
|
5092
5089
|
*/
|
|
5093
|
-
async getSessionUser() {
|
|
5094
|
-
if (!this.isAuthed()) {
|
|
5095
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5096
|
-
}
|
|
5097
|
-
if (!this.userToken) {
|
|
5098
|
-
throw new AuthenticationError('No user token available');
|
|
5099
|
-
}
|
|
5100
|
-
return {
|
|
5101
|
-
user_id: this.userToken.userId,
|
|
5102
|
-
access_token: this.userToken.accessToken,
|
|
5103
|
-
refresh_token: this.userToken.refreshToken,
|
|
5104
|
-
expires_in: this.userToken.expiresIn,
|
|
5105
|
-
token_type: this.userToken.tokenType,
|
|
5106
|
-
scope: this.userToken.scope,
|
|
5107
|
-
company_id: this.companyId,
|
|
5108
|
-
};
|
|
5109
|
-
}
|
|
5110
5090
|
async initializeWithUser(userId) {
|
|
5111
5091
|
try {
|
|
5112
5092
|
if (!this.sessionId) {
|
|
5113
5093
|
throw new SessionError('Session not initialized');
|
|
5114
5094
|
}
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
if (
|
|
5118
|
-
|
|
5119
|
-
|
|
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;
|
|
5120
5101
|
}
|
|
5102
|
+
// Store user ID for authentication state
|
|
5103
|
+
this.storeUserId(userId);
|
|
5121
5104
|
this.emit('success', userId);
|
|
5122
5105
|
}
|
|
5123
5106
|
catch (error) {
|
|
5124
5107
|
this.emit('error', error);
|
|
5108
|
+
throw error;
|
|
5125
5109
|
}
|
|
5126
5110
|
}
|
|
5127
5111
|
/**
|
|
@@ -5174,20 +5158,32 @@ class FinaticConnect extends EventEmitter {
|
|
|
5174
5158
|
url.searchParams.set('email', options.email);
|
|
5175
5159
|
themedPortalUrl = url.toString();
|
|
5176
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();
|
|
5177
5170
|
// Create portal UI if not exists
|
|
5178
5171
|
if (!this.portalUI) {
|
|
5179
5172
|
this.portalUI = new PortalUI(this.baseUrl);
|
|
5180
5173
|
}
|
|
5181
5174
|
// Show portal
|
|
5182
5175
|
this.portalUI.show(themedPortalUrl, this.sessionId || '', {
|
|
5183
|
-
onSuccess: async (userId
|
|
5176
|
+
onSuccess: async (userId) => {
|
|
5184
5177
|
try {
|
|
5185
5178
|
if (!this.sessionId) {
|
|
5186
5179
|
throw new SessionError('Session not initialized');
|
|
5187
5180
|
}
|
|
5188
|
-
//
|
|
5189
|
-
|
|
5190
|
-
|
|
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');
|
|
5191
5187
|
}
|
|
5192
5188
|
// Emit portal success event
|
|
5193
5189
|
this.emit('portal:success', userId);
|
|
@@ -5278,32 +5274,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5278
5274
|
* Place a new order using the broker order API
|
|
5279
5275
|
* @param order - Order details with broker context
|
|
5280
5276
|
*/
|
|
5281
|
-
async placeOrder(order) {
|
|
5282
|
-
if (!this.
|
|
5283
|
-
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.');
|
|
5284
5283
|
}
|
|
5285
5284
|
try {
|
|
5286
|
-
//
|
|
5287
|
-
|
|
5288
|
-
symbol: order.symbol,
|
|
5289
|
-
orderQty: order.quantity,
|
|
5290
|
-
action: order.side === 'buy' ? 'Buy' : 'Sell',
|
|
5291
|
-
orderType: order.orderType === 'market'
|
|
5292
|
-
? 'Market'
|
|
5293
|
-
: order.orderType === 'limit'
|
|
5294
|
-
? 'Limit'
|
|
5295
|
-
: order.orderType === 'stop'
|
|
5296
|
-
? 'Stop'
|
|
5297
|
-
: 'StopLimit',
|
|
5298
|
-
assetType: order.assetType || 'Stock',
|
|
5299
|
-
timeInForce: order.timeInForce,
|
|
5300
|
-
price: order.price,
|
|
5301
|
-
stopPrice: order.stopPrice,
|
|
5302
|
-
broker: order.broker,
|
|
5303
|
-
accountNumber: order.accountNumber,
|
|
5304
|
-
order_id: order.order_id,
|
|
5305
|
-
};
|
|
5306
|
-
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);
|
|
5307
5287
|
}
|
|
5308
5288
|
catch (error) {
|
|
5309
5289
|
this.emit('error', error);
|
|
@@ -5317,8 +5297,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5317
5297
|
* @param connection_id - Optional connection ID for testing bypass
|
|
5318
5298
|
*/
|
|
5319
5299
|
async cancelOrder(orderId, broker, connection_id) {
|
|
5320
|
-
if (!this.
|
|
5321
|
-
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.');
|
|
5322
5305
|
}
|
|
5323
5306
|
try {
|
|
5324
5307
|
return await this.apiClient.cancelBrokerOrder(orderId, broker, {}, connection_id);
|
|
@@ -5336,8 +5319,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5336
5319
|
* @param connection_id - Optional connection ID for testing bypass
|
|
5337
5320
|
*/
|
|
5338
5321
|
async modifyOrder(orderId, modifications, broker, connection_id) {
|
|
5339
|
-
if (!this.
|
|
5340
|
-
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.');
|
|
5341
5327
|
}
|
|
5342
5328
|
try {
|
|
5343
5329
|
// Convert modifications to broker format
|
|
@@ -5365,39 +5351,15 @@ class FinaticConnect extends EventEmitter {
|
|
|
5365
5351
|
throw error;
|
|
5366
5352
|
}
|
|
5367
5353
|
}
|
|
5368
|
-
/**
|
|
5369
|
-
* Set the broker context for trading
|
|
5370
|
-
* @param broker - The broker to use for trading
|
|
5371
|
-
*/
|
|
5372
|
-
setTradingContextBroker(broker) {
|
|
5373
|
-
this.apiClient.setBroker(broker);
|
|
5374
|
-
}
|
|
5375
|
-
/**
|
|
5376
|
-
* Set the account context for trading
|
|
5377
|
-
* @param accountNumber - The account number to use for trading
|
|
5378
|
-
* @param accountId - Optional account ID
|
|
5379
|
-
*/
|
|
5380
|
-
setTradingContextAccount(accountNumber, accountId) {
|
|
5381
|
-
this.apiClient.setAccount(accountNumber, accountId);
|
|
5382
|
-
}
|
|
5383
|
-
/**
|
|
5384
|
-
* Get the current trading context
|
|
5385
|
-
*/
|
|
5386
|
-
getTradingContext() {
|
|
5387
|
-
return this.apiClient.getTradingContext();
|
|
5388
|
-
}
|
|
5389
|
-
/**
|
|
5390
|
-
* Clear the trading context
|
|
5391
|
-
*/
|
|
5392
|
-
clearTradingContext() {
|
|
5393
|
-
this.apiClient.clearTradingContext();
|
|
5394
|
-
}
|
|
5395
5354
|
/**
|
|
5396
5355
|
* Place a stock market order (convenience method)
|
|
5397
5356
|
*/
|
|
5398
5357
|
async placeStockMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5399
|
-
if (!this.
|
|
5400
|
-
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.');
|
|
5401
5363
|
}
|
|
5402
5364
|
try {
|
|
5403
5365
|
return await this.apiClient.placeStockMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5411,8 +5373,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5411
5373
|
* Place a stock limit order (convenience method)
|
|
5412
5374
|
*/
|
|
5413
5375
|
async placeStockLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5414
|
-
if (!this.
|
|
5415
|
-
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.');
|
|
5416
5381
|
}
|
|
5417
5382
|
try {
|
|
5418
5383
|
return await this.apiClient.placeStockLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5426,8 +5391,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5426
5391
|
* Place a stock stop order (convenience method)
|
|
5427
5392
|
*/
|
|
5428
5393
|
async placeStockStopOrder(symbol, quantity, side, stopPrice, timeInForce = 'gtc', broker, accountNumber) {
|
|
5429
|
-
if (!this.
|
|
5430
|
-
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.');
|
|
5431
5399
|
}
|
|
5432
5400
|
try {
|
|
5433
5401
|
return await this.apiClient.placeStockStopOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', stopPrice, timeInForce, broker, accountNumber);
|
|
@@ -5441,8 +5409,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5441
5409
|
* Place a crypto market order (convenience method)
|
|
5442
5410
|
*/
|
|
5443
5411
|
async placeCryptoMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5444
|
-
if (!this.
|
|
5445
|
-
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.');
|
|
5446
5417
|
}
|
|
5447
5418
|
try {
|
|
5448
5419
|
return await this.apiClient.placeCryptoMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5456,8 +5427,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5456
5427
|
* Place a crypto limit order (convenience method)
|
|
5457
5428
|
*/
|
|
5458
5429
|
async placeCryptoLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5459
|
-
if (!this.
|
|
5460
|
-
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.');
|
|
5461
5435
|
}
|
|
5462
5436
|
try {
|
|
5463
5437
|
return await this.apiClient.placeCryptoLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5471,8 +5445,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5471
5445
|
* Place an options market order (convenience method)
|
|
5472
5446
|
*/
|
|
5473
5447
|
async placeOptionsMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5474
|
-
if (!this.
|
|
5475
|
-
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.');
|
|
5476
5453
|
}
|
|
5477
5454
|
try {
|
|
5478
5455
|
return await this.apiClient.placeOptionsMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5486,8 +5463,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5486
5463
|
* Place an options limit order (convenience method)
|
|
5487
5464
|
*/
|
|
5488
5465
|
async placeOptionsLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5489
|
-
if (!this.
|
|
5490
|
-
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.');
|
|
5491
5471
|
}
|
|
5492
5472
|
try {
|
|
5493
5473
|
return await this.apiClient.placeOptionsLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5501,8 +5481,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5501
5481
|
* Place a futures market order (convenience method)
|
|
5502
5482
|
*/
|
|
5503
5483
|
async placeFuturesMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5504
|
-
if (!this.
|
|
5505
|
-
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.');
|
|
5506
5489
|
}
|
|
5507
5490
|
try {
|
|
5508
5491
|
return await this.apiClient.placeFuturesMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5516,8 +5499,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5516
5499
|
* Place a futures limit order (convenience method)
|
|
5517
5500
|
*/
|
|
5518
5501
|
async placeFuturesLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5519
|
-
if (!this.
|
|
5520
|
-
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.');
|
|
5521
5507
|
}
|
|
5522
5508
|
try {
|
|
5523
5509
|
return await this.apiClient.placeFuturesLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5532,8 +5518,8 @@ class FinaticConnect extends EventEmitter {
|
|
|
5532
5518
|
* @returns The current user ID or undefined if not authenticated
|
|
5533
5519
|
* @throws AuthenticationError if user is not authenticated
|
|
5534
5520
|
*/
|
|
5535
|
-
getUserId() {
|
|
5536
|
-
if (!this.
|
|
5521
|
+
async getUserId() {
|
|
5522
|
+
if (!(await this.isAuthenticated())) {
|
|
5537
5523
|
return null;
|
|
5538
5524
|
}
|
|
5539
5525
|
if (!this.userToken?.user_id) {
|
|
@@ -5546,7 +5532,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5546
5532
|
* @returns Promise with array of broker information
|
|
5547
5533
|
*/
|
|
5548
5534
|
async getBrokerList() {
|
|
5549
|
-
// if (!this.
|
|
5535
|
+
// if (!this.isAuthenticated()) {
|
|
5550
5536
|
// throw new AuthenticationError('Not authenticated');
|
|
5551
5537
|
// }
|
|
5552
5538
|
const response = await this.apiClient.getBrokerList();
|
|
@@ -5563,7 +5549,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5563
5549
|
* @throws AuthenticationError if user is not authenticated
|
|
5564
5550
|
*/
|
|
5565
5551
|
async getBrokerConnections() {
|
|
5566
|
-
if (!this.
|
|
5552
|
+
if (!(await this.isAuthenticated())) {
|
|
5567
5553
|
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5568
5554
|
}
|
|
5569
5555
|
if (!this.userToken?.user_id) {
|
|
@@ -5637,118 +5623,22 @@ class FinaticConnect extends EventEmitter {
|
|
|
5637
5623
|
return this.getAllPositions({ broker_id: brokerId });
|
|
5638
5624
|
}
|
|
5639
5625
|
// Pagination methods
|
|
5640
|
-
/**
|
|
5641
|
-
* Get a specific page of orders with pagination metadata
|
|
5642
|
-
* @param page - Page number (default: 1)
|
|
5643
|
-
* @param perPage - Items per page (default: 100)
|
|
5644
|
-
* @param filter - Optional filter parameters
|
|
5645
|
-
* @returns Promise with paginated orders result
|
|
5646
|
-
*/
|
|
5647
|
-
async getOrdersPage(page = 1, perPage = 100, filter) {
|
|
5648
|
-
if (!this.isAuthed()) {
|
|
5649
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5650
|
-
}
|
|
5651
|
-
return this.apiClient.getBrokerOrdersPage(page, perPage, filter);
|
|
5652
|
-
}
|
|
5653
|
-
/**
|
|
5654
|
-
* Get a specific page of positions with pagination metadata
|
|
5655
|
-
* @param page - Page number (default: 1)
|
|
5656
|
-
* @param perPage - Items per page (default: 100)
|
|
5657
|
-
* @param filter - Optional filter parameters
|
|
5658
|
-
* @returns Promise with paginated positions result
|
|
5659
|
-
*/
|
|
5660
|
-
async getPositionsPage(page = 1, perPage = 100, filter) {
|
|
5661
|
-
if (!this.isAuthed()) {
|
|
5662
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5663
|
-
}
|
|
5664
|
-
return this.apiClient.getBrokerPositionsPage(page, perPage, filter);
|
|
5665
|
-
}
|
|
5666
|
-
/**
|
|
5667
|
-
* Get a specific page of accounts with pagination metadata
|
|
5668
|
-
* @param page - Page number (default: 1)
|
|
5669
|
-
* @param perPage - Items per page (default: 100)
|
|
5670
|
-
* @param filter - Optional filter parameters
|
|
5671
|
-
* @returns Promise with paginated accounts result
|
|
5672
|
-
*/
|
|
5673
|
-
async getAccountsPage(page = 1, perPage = 100, filter) {
|
|
5674
|
-
if (!this.isAuthed()) {
|
|
5675
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5676
|
-
}
|
|
5677
|
-
return this.apiClient.getBrokerAccountsPage(page, perPage, filter);
|
|
5678
|
-
}
|
|
5679
|
-
async getBalancesPage(page = 1, perPage = 100, filter) {
|
|
5680
|
-
if (!this.isAuthed()) {
|
|
5681
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5682
|
-
}
|
|
5683
|
-
return this.apiClient.getBrokerBalancesPage(page, perPage, filter);
|
|
5684
|
-
}
|
|
5685
|
-
/**
|
|
5686
|
-
* Get the next page of orders
|
|
5687
|
-
* @param previousResult - The previous paginated result
|
|
5688
|
-
* @returns Promise with next page of orders or null if no more pages
|
|
5689
|
-
*/
|
|
5690
|
-
async getNextOrdersPage(previousResult) {
|
|
5691
|
-
if (!this.isAuthed()) {
|
|
5692
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5693
|
-
}
|
|
5694
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5695
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5696
|
-
return this.apiClient.getBrokerOrdersPage(page, limit);
|
|
5697
|
-
});
|
|
5698
|
-
}
|
|
5699
|
-
/**
|
|
5700
|
-
* Get the next page of positions
|
|
5701
|
-
* @param previousResult - The previous paginated result
|
|
5702
|
-
* @returns Promise with next page of positions or null if no more pages
|
|
5703
|
-
*/
|
|
5704
|
-
async getNextPositionsPage(previousResult) {
|
|
5705
|
-
if (!this.isAuthed()) {
|
|
5706
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5707
|
-
}
|
|
5708
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5709
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5710
|
-
return this.apiClient.getBrokerPositionsPage(page, limit);
|
|
5711
|
-
});
|
|
5712
|
-
}
|
|
5713
|
-
/**
|
|
5714
|
-
* Get the next page of accounts
|
|
5715
|
-
* @param previousResult - The previous paginated result
|
|
5716
|
-
* @returns Promise with next page of accounts or null if no more pages
|
|
5717
|
-
*/
|
|
5718
|
-
async getNextAccountsPage(previousResult) {
|
|
5719
|
-
if (!this.isAuthed()) {
|
|
5720
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5721
|
-
}
|
|
5722
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5723
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5724
|
-
return this.apiClient.getBrokerAccountsPage(page, limit);
|
|
5725
|
-
});
|
|
5726
|
-
}
|
|
5727
|
-
async getNextBalancesPage(previousResult) {
|
|
5728
|
-
if (!this.isAuthed()) {
|
|
5729
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5730
|
-
}
|
|
5731
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5732
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5733
|
-
return this.apiClient.getBrokerBalancesPage(page, limit);
|
|
5734
|
-
});
|
|
5735
|
-
}
|
|
5736
5626
|
/**
|
|
5737
5627
|
* Get all orders across all pages (convenience method)
|
|
5738
5628
|
* @param filter - Optional filter parameters
|
|
5739
5629
|
* @returns Promise with all orders
|
|
5740
5630
|
*/
|
|
5741
5631
|
async getAllOrders(filter) {
|
|
5742
|
-
if (!this.
|
|
5632
|
+
if (!(await this.isAuthenticated())) {
|
|
5743
5633
|
throw new AuthenticationError('User is not authenticated');
|
|
5744
5634
|
}
|
|
5745
5635
|
const allData = [];
|
|
5746
|
-
let currentResult = await this.
|
|
5636
|
+
let currentResult = await this.apiClient.getBrokerOrdersPage(1, 100, filter);
|
|
5747
5637
|
while (currentResult) {
|
|
5748
5638
|
allData.push(...currentResult.data);
|
|
5749
5639
|
if (!currentResult.hasNext)
|
|
5750
5640
|
break;
|
|
5751
|
-
const nextResult = await
|
|
5641
|
+
const nextResult = await currentResult.nextPage();
|
|
5752
5642
|
if (!nextResult)
|
|
5753
5643
|
break;
|
|
5754
5644
|
currentResult = nextResult;
|
|
@@ -5761,16 +5651,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5761
5651
|
* @returns Promise with all positions
|
|
5762
5652
|
*/
|
|
5763
5653
|
async getAllPositions(filter) {
|
|
5764
|
-
if (!this.
|
|
5654
|
+
if (!(await this.isAuthenticated())) {
|
|
5765
5655
|
throw new AuthenticationError('User is not authenticated');
|
|
5766
5656
|
}
|
|
5767
5657
|
const allData = [];
|
|
5768
|
-
let currentResult = await this.
|
|
5658
|
+
let currentResult = await this.apiClient.getBrokerPositionsPage(1, 100, filter);
|
|
5769
5659
|
while (currentResult) {
|
|
5770
5660
|
allData.push(...currentResult.data);
|
|
5771
5661
|
if (!currentResult.hasNext)
|
|
5772
5662
|
break;
|
|
5773
|
-
const nextResult = await
|
|
5663
|
+
const nextResult = await currentResult.nextPage();
|
|
5774
5664
|
if (!nextResult)
|
|
5775
5665
|
break;
|
|
5776
5666
|
currentResult = nextResult;
|
|
@@ -5783,16 +5673,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5783
5673
|
* @returns Promise with all accounts
|
|
5784
5674
|
*/
|
|
5785
5675
|
async getAllAccounts(filter) {
|
|
5786
|
-
if (!this.
|
|
5676
|
+
if (!(await this.isAuthenticated())) {
|
|
5787
5677
|
throw new AuthenticationError('User is not authenticated');
|
|
5788
5678
|
}
|
|
5789
5679
|
const allData = [];
|
|
5790
|
-
let currentResult = await this.
|
|
5680
|
+
let currentResult = await this.apiClient.getBrokerAccountsPage(1, 100, filter);
|
|
5791
5681
|
while (currentResult) {
|
|
5792
5682
|
allData.push(...currentResult.data);
|
|
5793
5683
|
if (!currentResult.hasNext)
|
|
5794
5684
|
break;
|
|
5795
|
-
const nextResult = await
|
|
5685
|
+
const nextResult = await currentResult.nextPage();
|
|
5796
5686
|
if (!nextResult)
|
|
5797
5687
|
break;
|
|
5798
5688
|
currentResult = nextResult;
|
|
@@ -5800,16 +5690,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5800
5690
|
return allData;
|
|
5801
5691
|
}
|
|
5802
5692
|
async getAllBalances(filter) {
|
|
5803
|
-
if (!this.
|
|
5693
|
+
if (!(await this.isAuthenticated())) {
|
|
5804
5694
|
throw new AuthenticationError('User is not authenticated');
|
|
5805
5695
|
}
|
|
5806
5696
|
const allData = [];
|
|
5807
|
-
let currentResult = await this.
|
|
5697
|
+
let currentResult = await this.apiClient.getBrokerBalancesPage(1, 100, filter);
|
|
5808
5698
|
while (currentResult) {
|
|
5809
5699
|
allData.push(...currentResult.data);
|
|
5810
5700
|
if (!currentResult.hasNext)
|
|
5811
5701
|
break;
|
|
5812
|
-
const nextResult = await
|
|
5702
|
+
const nextResult = await currentResult.nextPage();
|
|
5813
5703
|
if (!nextResult)
|
|
5814
5704
|
break;
|
|
5815
5705
|
currentResult = nextResult;
|
|
@@ -5854,7 +5744,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5854
5744
|
* Validate session for keep-alive purposes and handle automatic refresh
|
|
5855
5745
|
*/
|
|
5856
5746
|
async validateSessionKeepAlive() {
|
|
5857
|
-
if (!this.sessionId || !this.
|
|
5747
|
+
if (!this.sessionId || !(await this.isAuthenticated())) {
|
|
5858
5748
|
console.log('[FinaticConnect] Session keep-alive skipped - no active session');
|
|
5859
5749
|
return;
|
|
5860
5750
|
}
|
|
@@ -5965,7 +5855,6 @@ class FinaticConnect extends EventEmitter {
|
|
|
5965
5855
|
const response = await fetch(`${this.baseUrl}/portal/${sessionId}/complete`, {
|
|
5966
5856
|
method: 'POST',
|
|
5967
5857
|
headers: {
|
|
5968
|
-
Authorization: `Bearer ${this.userToken?.accessToken || ''}`,
|
|
5969
5858
|
'Content-Type': 'application/json',
|
|
5970
5859
|
},
|
|
5971
5860
|
});
|
|
@@ -5988,7 +5877,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5988
5877
|
* @throws AuthenticationError if user is not authenticated
|
|
5989
5878
|
*/
|
|
5990
5879
|
async disconnectCompany(connectionId) {
|
|
5991
|
-
if (!this.
|
|
5880
|
+
if (!(await this.isAuthenticated())) {
|
|
5992
5881
|
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5993
5882
|
}
|
|
5994
5883
|
if (!this.userToken?.user_id) {
|
|
@@ -5996,24 +5885,6 @@ class FinaticConnect extends EventEmitter {
|
|
|
5996
5885
|
}
|
|
5997
5886
|
return this.apiClient.disconnectCompany(connectionId);
|
|
5998
5887
|
}
|
|
5999
|
-
/**
|
|
6000
|
-
* Get account balances for the authenticated user
|
|
6001
|
-
* @param filters - Optional filters for balances
|
|
6002
|
-
* @returns Promise with balance data
|
|
6003
|
-
*/
|
|
6004
|
-
async getBalances(filters) {
|
|
6005
|
-
if (!this.isAuthed()) {
|
|
6006
|
-
throw new AuthenticationError('User is not authenticated');
|
|
6007
|
-
}
|
|
6008
|
-
try {
|
|
6009
|
-
const response = await this.apiClient.getBalances(filters);
|
|
6010
|
-
return response.response_data || [];
|
|
6011
|
-
}
|
|
6012
|
-
catch (error) {
|
|
6013
|
-
this.emit('error', error);
|
|
6014
|
-
throw error;
|
|
6015
|
-
}
|
|
6016
|
-
}
|
|
6017
5888
|
}
|
|
6018
5889
|
FinaticConnect.instance = null;
|
|
6019
5890
|
|
|
@@ -6025,7 +5896,6 @@ exports.BaseError = BaseError;
|
|
|
6025
5896
|
exports.CompanyAccessError = CompanyAccessError;
|
|
6026
5897
|
exports.EventEmitter = EventEmitter;
|
|
6027
5898
|
exports.FinaticConnect = FinaticConnect;
|
|
6028
|
-
exports.MockFactory = MockFactory;
|
|
6029
5899
|
exports.NetworkError = NetworkError;
|
|
6030
5900
|
exports.OrderError = OrderError;
|
|
6031
5901
|
exports.OrderValidationError = OrderValidationError;
|