@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.mjs
CHANGED
|
@@ -203,15 +203,13 @@ class TradingNotEnabledError extends ApiError {
|
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
// Supabase import removed - SDK no longer depends on Supabase
|
|
206
207
|
class ApiClient {
|
|
207
208
|
constructor(baseUrl, deviceInfo) {
|
|
208
209
|
this.currentSessionState = null;
|
|
209
210
|
this.currentSessionId = null;
|
|
210
211
|
this.tradingContext = {};
|
|
211
|
-
//
|
|
212
|
-
this.tokenInfo = null;
|
|
213
|
-
this.refreshPromise = null;
|
|
214
|
-
this.REFRESH_BUFFER_MINUTES = 5; // Refresh token 5 minutes before expiry
|
|
212
|
+
// Session management (no Supabase needed)
|
|
215
213
|
// Session and company context
|
|
216
214
|
this.companyId = null;
|
|
217
215
|
this.csrfToken = null;
|
|
@@ -223,7 +221,9 @@ class ApiClient {
|
|
|
223
221
|
if (!this.baseUrl.includes('/api/v1')) {
|
|
224
222
|
this.baseUrl = `${this.baseUrl}/api/v1`;
|
|
225
223
|
}
|
|
224
|
+
// No Supabase initialization needed - SDK is clean
|
|
226
225
|
}
|
|
226
|
+
// Supabase initialization removed - SDK no longer depends on Supabase
|
|
227
227
|
/**
|
|
228
228
|
* Set session context (session ID, company ID, CSRF token)
|
|
229
229
|
*/
|
|
@@ -251,105 +251,30 @@ class ApiClient {
|
|
|
251
251
|
return this.csrfToken;
|
|
252
252
|
}
|
|
253
253
|
/**
|
|
254
|
-
*
|
|
255
|
-
*/
|
|
256
|
-
setTokens(accessToken, refreshToken, expiresAt, userId) {
|
|
257
|
-
this.tokenInfo = {
|
|
258
|
-
accessToken,
|
|
259
|
-
refreshToken,
|
|
260
|
-
expiresAt,
|
|
261
|
-
userId,
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Get the current access token, refreshing if necessary
|
|
254
|
+
* Get a valid access token (session-based auth - no tokens needed)
|
|
266
255
|
*/
|
|
267
256
|
async getValidAccessToken() {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
// Check if token is expired or about to expire
|
|
272
|
-
if (this.isTokenExpired()) {
|
|
273
|
-
await this.refreshTokens();
|
|
274
|
-
}
|
|
275
|
-
return this.tokenInfo.accessToken;
|
|
257
|
+
// Session-based auth - return empty token as we use session headers
|
|
258
|
+
return '';
|
|
276
259
|
}
|
|
260
|
+
// Token expiration check removed - session-based auth doesn't use expiring tokens
|
|
261
|
+
// Supabase refresh method removed - SDK no longer uses Supabase tokens
|
|
277
262
|
/**
|
|
278
|
-
*
|
|
263
|
+
* Perform the actual Supabase session refresh
|
|
279
264
|
*/
|
|
280
|
-
|
|
281
|
-
if (!this.tokenInfo)
|
|
282
|
-
return true;
|
|
283
|
-
const expiryTime = new Date(this.tokenInfo.expiresAt).getTime();
|
|
284
|
-
const currentTime = Date.now();
|
|
285
|
-
const bufferTime = this.REFRESH_BUFFER_MINUTES * 60 * 1000; // 5 minutes in milliseconds
|
|
286
|
-
return currentTime >= expiryTime - bufferTime;
|
|
287
|
-
}
|
|
265
|
+
// Supabase refresh method removed - SDK no longer uses Supabase tokens
|
|
288
266
|
/**
|
|
289
|
-
*
|
|
290
|
-
*/
|
|
291
|
-
async refreshTokens() {
|
|
292
|
-
if (!this.tokenInfo) {
|
|
293
|
-
throw new AuthenticationError('No refresh token available.');
|
|
294
|
-
}
|
|
295
|
-
// If a refresh is already in progress, wait for it
|
|
296
|
-
if (this.refreshPromise) {
|
|
297
|
-
await this.refreshPromise;
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
// Start a new refresh
|
|
301
|
-
this.refreshPromise = this.performTokenRefresh();
|
|
302
|
-
try {
|
|
303
|
-
await this.refreshPromise;
|
|
304
|
-
}
|
|
305
|
-
finally {
|
|
306
|
-
this.refreshPromise = null;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Perform the actual token refresh request
|
|
311
|
-
*/
|
|
312
|
-
async performTokenRefresh() {
|
|
313
|
-
if (!this.tokenInfo) {
|
|
314
|
-
throw new AuthenticationError('No refresh token available.');
|
|
315
|
-
}
|
|
316
|
-
try {
|
|
317
|
-
const response = await this.request('/company/auth/refresh', {
|
|
318
|
-
method: 'POST',
|
|
319
|
-
headers: {
|
|
320
|
-
'Content-Type': 'application/json',
|
|
321
|
-
},
|
|
322
|
-
body: {
|
|
323
|
-
refresh_token: this.tokenInfo.refreshToken,
|
|
324
|
-
},
|
|
325
|
-
});
|
|
326
|
-
// Update stored tokens
|
|
327
|
-
this.tokenInfo = {
|
|
328
|
-
accessToken: response.response_data.access_token,
|
|
329
|
-
refreshToken: response.response_data.refresh_token,
|
|
330
|
-
expiresAt: response.response_data.expires_at,
|
|
331
|
-
userId: this.tokenInfo.userId,
|
|
332
|
-
};
|
|
333
|
-
return this.tokenInfo;
|
|
334
|
-
}
|
|
335
|
-
catch (error) {
|
|
336
|
-
// Clear tokens on refresh failure
|
|
337
|
-
this.tokenInfo = null;
|
|
338
|
-
throw new AuthenticationError('Token refresh failed. Please re-authenticate.', error);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
/**
|
|
342
|
-
* Clear stored tokens (useful for logout)
|
|
267
|
+
* Clear session tokens (useful for logout)
|
|
343
268
|
*/
|
|
344
269
|
clearTokens() {
|
|
345
|
-
|
|
346
|
-
this.refreshPromise = null;
|
|
270
|
+
// Session-based auth - no tokens to clear
|
|
347
271
|
}
|
|
348
272
|
/**
|
|
349
|
-
* Get current
|
|
273
|
+
* Get current session info (for debugging/testing) - session-based auth
|
|
350
274
|
*/
|
|
351
275
|
getTokenInfo() {
|
|
352
|
-
|
|
276
|
+
// Session-based auth - no tokens to return
|
|
277
|
+
return null;
|
|
353
278
|
}
|
|
354
279
|
/**
|
|
355
280
|
* Make a request to the API.
|
|
@@ -363,9 +288,12 @@ class ApiClient {
|
|
|
363
288
|
url.searchParams.append(key, value);
|
|
364
289
|
});
|
|
365
290
|
}
|
|
291
|
+
// Get Supabase JWT token
|
|
292
|
+
const accessToken = await this.getValidAccessToken();
|
|
366
293
|
// Build comprehensive headers object with all available session data
|
|
367
294
|
const comprehensiveHeaders = {
|
|
368
295
|
'Content-Type': 'application/json',
|
|
296
|
+
Authorization: `Bearer ${accessToken}`,
|
|
369
297
|
};
|
|
370
298
|
// Add device info if available
|
|
371
299
|
if (this.deviceInfo) {
|
|
@@ -533,7 +461,7 @@ class ApiClient {
|
|
|
533
461
|
}
|
|
534
462
|
// Session Management
|
|
535
463
|
async startSession(token, userId) {
|
|
536
|
-
const response = await this.request('/
|
|
464
|
+
const response = await this.request('/session/start', {
|
|
537
465
|
method: 'POST',
|
|
538
466
|
headers: {
|
|
539
467
|
'Content-Type': 'application/json',
|
|
@@ -587,11 +515,8 @@ class ApiClient {
|
|
|
587
515
|
otp,
|
|
588
516
|
},
|
|
589
517
|
});
|
|
590
|
-
//
|
|
591
|
-
if (response.success && response.data)
|
|
592
|
-
const expiresAt = new Date(Date.now() + response.data.expires_in * 1000).toISOString();
|
|
593
|
-
this.setTokens(response.data.access_token, response.data.refresh_token, expiresAt, response.data.user_id);
|
|
594
|
-
}
|
|
518
|
+
// OTP verification successful - tokens are handled by Supabase client
|
|
519
|
+
if (response.success && response.data) ;
|
|
595
520
|
return response;
|
|
596
521
|
}
|
|
597
522
|
// Direct Authentication
|
|
@@ -600,7 +525,7 @@ class ApiClient {
|
|
|
600
525
|
if (this.currentSessionState !== SessionState.ACTIVE) {
|
|
601
526
|
throw new SessionError('Session must be in ACTIVE state to authenticate');
|
|
602
527
|
}
|
|
603
|
-
const response = await this.request('/
|
|
528
|
+
const response = await this.request('/session/authenticate', {
|
|
604
529
|
method: 'POST',
|
|
605
530
|
headers: {
|
|
606
531
|
'Content-Type': 'application/json',
|
|
@@ -618,11 +543,7 @@ class ApiClient {
|
|
|
618
543
|
},
|
|
619
544
|
});
|
|
620
545
|
// Store tokens after successful direct authentication
|
|
621
|
-
if (response.success && response.data)
|
|
622
|
-
// For direct auth, we don't get expires_in, so we'll set a default 1-hour expiry
|
|
623
|
-
const expiresAt = new Date(Date.now() + 60 * 60 * 1000).toISOString(); // 1 hour
|
|
624
|
-
this.setTokens(response.data.access_token, response.data.refresh_token, expiresAt, userId);
|
|
625
|
-
}
|
|
546
|
+
if (response.success && response.data) ;
|
|
626
547
|
return response;
|
|
627
548
|
}
|
|
628
549
|
// Portal Management
|
|
@@ -636,7 +557,7 @@ class ApiClient {
|
|
|
636
557
|
if (this.currentSessionState !== SessionState.ACTIVE) {
|
|
637
558
|
throw new SessionError('Session must be in ACTIVE state to get portal URL');
|
|
638
559
|
}
|
|
639
|
-
return this.request('/
|
|
560
|
+
return this.request('/session/portal', {
|
|
640
561
|
method: 'GET',
|
|
641
562
|
headers: {
|
|
642
563
|
'Content-Type': 'application/json',
|
|
@@ -797,12 +718,6 @@ class ApiClient {
|
|
|
797
718
|
this.tradingContext.accountNumber = accountNumber;
|
|
798
719
|
this.tradingContext.accountId = accountId;
|
|
799
720
|
}
|
|
800
|
-
getTradingContext() {
|
|
801
|
-
return { ...this.tradingContext };
|
|
802
|
-
}
|
|
803
|
-
clearTradingContext() {
|
|
804
|
-
this.tradingContext = {};
|
|
805
|
-
}
|
|
806
721
|
// Stock convenience methods
|
|
807
722
|
async placeStockMarketOrder(symbol, orderQty, action, broker, accountNumber, extras = {}, connection_id) {
|
|
808
723
|
return this.placeBrokerOrder({
|
|
@@ -810,7 +725,7 @@ class ApiClient {
|
|
|
810
725
|
orderQty,
|
|
811
726
|
action,
|
|
812
727
|
orderType: 'Market',
|
|
813
|
-
assetType: '
|
|
728
|
+
assetType: 'equity',
|
|
814
729
|
timeInForce: 'day',
|
|
815
730
|
broker,
|
|
816
731
|
accountNumber,
|
|
@@ -822,7 +737,7 @@ class ApiClient {
|
|
|
822
737
|
orderQty,
|
|
823
738
|
action,
|
|
824
739
|
orderType: 'Limit',
|
|
825
|
-
assetType: '
|
|
740
|
+
assetType: 'equity',
|
|
826
741
|
price,
|
|
827
742
|
timeInForce,
|
|
828
743
|
broker,
|
|
@@ -835,7 +750,7 @@ class ApiClient {
|
|
|
835
750
|
orderQty,
|
|
836
751
|
action,
|
|
837
752
|
orderType: 'Stop',
|
|
838
|
-
assetType: '
|
|
753
|
+
assetType: 'equity',
|
|
839
754
|
stopPrice,
|
|
840
755
|
timeInForce,
|
|
841
756
|
broker,
|
|
@@ -849,7 +764,7 @@ class ApiClient {
|
|
|
849
764
|
orderQty,
|
|
850
765
|
action,
|
|
851
766
|
orderType: 'Market',
|
|
852
|
-
assetType: '
|
|
767
|
+
assetType: 'crypto',
|
|
853
768
|
timeInForce: 'day',
|
|
854
769
|
broker,
|
|
855
770
|
accountNumber,
|
|
@@ -862,7 +777,7 @@ class ApiClient {
|
|
|
862
777
|
orderQty,
|
|
863
778
|
action,
|
|
864
779
|
orderType: 'Limit',
|
|
865
|
-
assetType: '
|
|
780
|
+
assetType: 'crypto',
|
|
866
781
|
price,
|
|
867
782
|
timeInForce,
|
|
868
783
|
broker,
|
|
@@ -877,7 +792,7 @@ class ApiClient {
|
|
|
877
792
|
orderQty,
|
|
878
793
|
action,
|
|
879
794
|
orderType: 'Market',
|
|
880
|
-
assetType: '
|
|
795
|
+
assetType: 'equity_option',
|
|
881
796
|
timeInForce: 'day',
|
|
882
797
|
broker,
|
|
883
798
|
accountNumber,
|
|
@@ -890,7 +805,7 @@ class ApiClient {
|
|
|
890
805
|
orderQty,
|
|
891
806
|
action,
|
|
892
807
|
orderType: 'Limit',
|
|
893
|
-
assetType: '
|
|
808
|
+
assetType: 'equity_option',
|
|
894
809
|
price,
|
|
895
810
|
timeInForce,
|
|
896
811
|
broker,
|
|
@@ -905,7 +820,7 @@ class ApiClient {
|
|
|
905
820
|
orderQty,
|
|
906
821
|
action,
|
|
907
822
|
orderType: 'Market',
|
|
908
|
-
assetType: '
|
|
823
|
+
assetType: 'future',
|
|
909
824
|
timeInForce: 'day',
|
|
910
825
|
broker,
|
|
911
826
|
accountNumber,
|
|
@@ -917,7 +832,7 @@ class ApiClient {
|
|
|
917
832
|
orderQty,
|
|
918
833
|
action,
|
|
919
834
|
orderType: 'Limit',
|
|
920
|
-
assetType: '
|
|
835
|
+
assetType: 'future',
|
|
921
836
|
price,
|
|
922
837
|
timeInForce,
|
|
923
838
|
broker,
|
|
@@ -1021,7 +936,7 @@ class ApiClient {
|
|
|
1021
936
|
}
|
|
1022
937
|
async getUserToken(sessionId) {
|
|
1023
938
|
const accessToken = await this.getValidAccessToken();
|
|
1024
|
-
return this.request(`/
|
|
939
|
+
return this.request(`/session/${sessionId}/user`, {
|
|
1025
940
|
method: 'GET',
|
|
1026
941
|
headers: {
|
|
1027
942
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -1036,18 +951,27 @@ class ApiClient {
|
|
|
1036
951
|
}
|
|
1037
952
|
/**
|
|
1038
953
|
* Refresh the current session to extend its lifetime
|
|
954
|
+
* Note: This now uses Supabase session refresh instead of custom endpoint
|
|
1039
955
|
*/
|
|
1040
956
|
async refreshSession() {
|
|
1041
957
|
if (!this.currentSessionId || !this.companyId) {
|
|
1042
958
|
throw new SessionError('No active session to refresh');
|
|
1043
959
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
960
|
+
// Session-based auth - no token refresh needed
|
|
961
|
+
// Return session info in expected format
|
|
962
|
+
return {
|
|
963
|
+
success: true,
|
|
964
|
+
response_data: {
|
|
965
|
+
session_id: this.currentSessionId,
|
|
966
|
+
company_id: this.companyId,
|
|
967
|
+
status: 'active',
|
|
968
|
+
expires_at: new Date(Date.now() + 60 * 60 * 1000).toISOString(), // 1 hour from now
|
|
969
|
+
user_id: '', // Session-based auth - user_id comes from session
|
|
970
|
+
auto_login: false,
|
|
1049
971
|
},
|
|
1050
|
-
|
|
972
|
+
message: 'Session refreshed successfully',
|
|
973
|
+
status_code: 200,
|
|
974
|
+
};
|
|
1051
975
|
}
|
|
1052
976
|
// Broker Data Management
|
|
1053
977
|
async getBrokerList() {
|
|
@@ -1818,15 +1742,11 @@ class MockDataProvider {
|
|
|
1818
1742
|
* Generate mock tokens
|
|
1819
1743
|
*/
|
|
1820
1744
|
generateTokens(userId) {
|
|
1821
|
-
|
|
1822
|
-
|
|
1745
|
+
`mock_access_${v4().replace(/-/g, '')}`;
|
|
1746
|
+
`mock_refresh_${v4().replace(/-/g, '')}`;
|
|
1823
1747
|
return {
|
|
1824
|
-
accessToken,
|
|
1825
|
-
refreshToken,
|
|
1826
|
-
expiresIn: 3600, // 1 hour
|
|
1827
1748
|
user_id: userId,
|
|
1828
|
-
|
|
1829
|
-
scope: 'read write',
|
|
1749
|
+
// Removed token fields - we no longer use Supabase tokens in the SDK
|
|
1830
1750
|
};
|
|
1831
1751
|
}
|
|
1832
1752
|
// Authentication & Session Management Mocks
|
|
@@ -1846,6 +1766,7 @@ class MockDataProvider {
|
|
|
1846
1766
|
};
|
|
1847
1767
|
this.sessionData.set(sessionId, sessionData);
|
|
1848
1768
|
return {
|
|
1769
|
+
success: true,
|
|
1849
1770
|
data: sessionData,
|
|
1850
1771
|
message: 'Session started successfully',
|
|
1851
1772
|
};
|
|
@@ -1867,12 +1788,12 @@ class MockDataProvider {
|
|
|
1867
1788
|
success: true,
|
|
1868
1789
|
message: 'OTP verified successfully',
|
|
1869
1790
|
data: {
|
|
1870
|
-
access_token: tokens
|
|
1871
|
-
refresh_token: tokens
|
|
1791
|
+
access_token: '', // No longer using Supabase tokens
|
|
1792
|
+
refresh_token: '', // No longer using Supabase tokens
|
|
1872
1793
|
user_id: userId,
|
|
1873
|
-
expires_in:
|
|
1874
|
-
scope:
|
|
1875
|
-
token_type:
|
|
1794
|
+
expires_in: 0, // No token expiration for session-based auth
|
|
1795
|
+
scope: 'api:access',
|
|
1796
|
+
token_type: 'Bearer',
|
|
1876
1797
|
},
|
|
1877
1798
|
};
|
|
1878
1799
|
}
|
|
@@ -1884,8 +1805,8 @@ class MockDataProvider {
|
|
|
1884
1805
|
success: true,
|
|
1885
1806
|
message: 'Authentication successful',
|
|
1886
1807
|
data: {
|
|
1887
|
-
access_token: tokens
|
|
1888
|
-
refresh_token: tokens
|
|
1808
|
+
access_token: '', // No longer using Supabase tokens
|
|
1809
|
+
refresh_token: '', // No longer using Supabase tokens
|
|
1889
1810
|
},
|
|
1890
1811
|
};
|
|
1891
1812
|
}
|
|
@@ -1931,6 +1852,8 @@ class MockDataProvider {
|
|
|
1931
1852
|
valid: true,
|
|
1932
1853
|
company_id: this.generateCompanyId(),
|
|
1933
1854
|
status: 'active',
|
|
1855
|
+
is_sandbox: false,
|
|
1856
|
+
environment: 'production',
|
|
1934
1857
|
};
|
|
1935
1858
|
}
|
|
1936
1859
|
async mockCompletePortalSession(sessionId) {
|
|
@@ -2034,6 +1957,12 @@ class MockDataProvider {
|
|
|
2034
1957
|
created_at: new Date().toISOString(),
|
|
2035
1958
|
updated_at: new Date().toISOString(),
|
|
2036
1959
|
last_synced_at: new Date().toISOString(),
|
|
1960
|
+
positions_synced_at: new Date().toISOString(),
|
|
1961
|
+
orders_synced_at: new Date().toISOString(),
|
|
1962
|
+
balances_synced_at: new Date().toISOString(),
|
|
1963
|
+
account_created_at: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString(), // 1 year ago
|
|
1964
|
+
account_updated_at: new Date().toISOString(),
|
|
1965
|
+
account_first_trade_at: new Date(Date.now() - 300 * 24 * 60 * 60 * 1000).toISOString(), // 300 days ago
|
|
2037
1966
|
},
|
|
2038
1967
|
{
|
|
2039
1968
|
id: v4(),
|
|
@@ -2048,6 +1977,12 @@ class MockDataProvider {
|
|
|
2048
1977
|
created_at: new Date().toISOString(),
|
|
2049
1978
|
updated_at: new Date().toISOString(),
|
|
2050
1979
|
last_synced_at: new Date().toISOString(),
|
|
1980
|
+
positions_synced_at: new Date().toISOString(),
|
|
1981
|
+
orders_synced_at: new Date().toISOString(),
|
|
1982
|
+
balances_synced_at: new Date().toISOString(),
|
|
1983
|
+
account_created_at: new Date(Date.now() - 730 * 24 * 60 * 60 * 1000).toISOString(), // 2 years ago
|
|
1984
|
+
account_updated_at: new Date().toISOString(),
|
|
1985
|
+
account_first_trade_at: new Date(Date.now() - 700 * 24 * 60 * 60 * 1000).toISOString(), // 700 days ago
|
|
2051
1986
|
},
|
|
2052
1987
|
];
|
|
2053
1988
|
return {
|
|
@@ -2533,6 +2468,12 @@ class MockDataProvider {
|
|
|
2533
2468
|
created_at: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(), // Random date within last year
|
|
2534
2469
|
updated_at: new Date().toISOString(),
|
|
2535
2470
|
last_synced_at: new Date().toISOString(),
|
|
2471
|
+
positions_synced_at: new Date().toISOString(),
|
|
2472
|
+
orders_synced_at: new Date().toISOString(),
|
|
2473
|
+
balances_synced_at: new Date().toISOString(),
|
|
2474
|
+
account_created_at: new Date(Date.now() - Math.random() * 730 * 24 * 60 * 60 * 1000).toISOString(), // Random date within last 2 years
|
|
2475
|
+
account_updated_at: new Date().toISOString(),
|
|
2476
|
+
account_first_trade_at: new Date(Date.now() - Math.random() * 500 * 24 * 60 * 60 * 1000).toISOString(), // Random date within last 500 days
|
|
2536
2477
|
});
|
|
2537
2478
|
}
|
|
2538
2479
|
return accounts;
|
|
@@ -2869,12 +2810,6 @@ class MockApiClient {
|
|
|
2869
2810
|
this.tradingContext.accountId = accountId;
|
|
2870
2811
|
console.log('MockApiClient.setAccount Debug - Updated context:', this.tradingContext);
|
|
2871
2812
|
}
|
|
2872
|
-
getTradingContext() {
|
|
2873
|
-
return { ...this.tradingContext };
|
|
2874
|
-
}
|
|
2875
|
-
clearTradingContext() {
|
|
2876
|
-
this.tradingContext = {};
|
|
2877
|
-
}
|
|
2878
2813
|
// Stock convenience methods
|
|
2879
2814
|
async placeStockMarketOrder(symbol, orderQty, action, broker, accountNumber, extras = {}) {
|
|
2880
2815
|
return this.placeBrokerOrder({
|
|
@@ -2884,7 +2819,7 @@ class MockApiClient {
|
|
|
2884
2819
|
orderQty,
|
|
2885
2820
|
action,
|
|
2886
2821
|
orderType: 'Market',
|
|
2887
|
-
assetType: '
|
|
2822
|
+
assetType: 'equity',
|
|
2888
2823
|
timeInForce: 'day',
|
|
2889
2824
|
}, extras);
|
|
2890
2825
|
}
|
|
@@ -2896,7 +2831,7 @@ class MockApiClient {
|
|
|
2896
2831
|
orderQty,
|
|
2897
2832
|
action,
|
|
2898
2833
|
orderType: 'Limit',
|
|
2899
|
-
assetType: '
|
|
2834
|
+
assetType: 'equity',
|
|
2900
2835
|
timeInForce,
|
|
2901
2836
|
price,
|
|
2902
2837
|
}, extras);
|
|
@@ -2909,7 +2844,7 @@ class MockApiClient {
|
|
|
2909
2844
|
orderQty,
|
|
2910
2845
|
action,
|
|
2911
2846
|
orderType: 'Stop',
|
|
2912
|
-
assetType: '
|
|
2847
|
+
assetType: 'equity',
|
|
2913
2848
|
timeInForce,
|
|
2914
2849
|
stopPrice,
|
|
2915
2850
|
}, extras);
|
|
@@ -2923,7 +2858,7 @@ class MockApiClient {
|
|
|
2923
2858
|
orderQty: options.quantity || orderQty,
|
|
2924
2859
|
action,
|
|
2925
2860
|
orderType: 'Market',
|
|
2926
|
-
assetType: '
|
|
2861
|
+
assetType: 'crypto',
|
|
2927
2862
|
timeInForce: 'gtc', // Crypto typically uses GTC
|
|
2928
2863
|
};
|
|
2929
2864
|
return this.placeBrokerOrder(orderParams, extras);
|
|
@@ -2936,7 +2871,7 @@ class MockApiClient {
|
|
|
2936
2871
|
orderQty: options.quantity || orderQty,
|
|
2937
2872
|
action,
|
|
2938
2873
|
orderType: 'Limit',
|
|
2939
|
-
assetType: '
|
|
2874
|
+
assetType: 'crypto',
|
|
2940
2875
|
timeInForce,
|
|
2941
2876
|
price,
|
|
2942
2877
|
};
|
|
@@ -2951,7 +2886,7 @@ class MockApiClient {
|
|
|
2951
2886
|
orderQty,
|
|
2952
2887
|
action,
|
|
2953
2888
|
orderType: 'Market',
|
|
2954
|
-
assetType: '
|
|
2889
|
+
assetType: 'equity_option',
|
|
2955
2890
|
timeInForce: 'day',
|
|
2956
2891
|
};
|
|
2957
2892
|
return this.placeBrokerOrder(orderParams, extras);
|
|
@@ -2964,7 +2899,7 @@ class MockApiClient {
|
|
|
2964
2899
|
orderQty,
|
|
2965
2900
|
action,
|
|
2966
2901
|
orderType: 'Limit',
|
|
2967
|
-
assetType: '
|
|
2902
|
+
assetType: 'equity_option',
|
|
2968
2903
|
timeInForce,
|
|
2969
2904
|
price,
|
|
2970
2905
|
};
|
|
@@ -2979,7 +2914,7 @@ class MockApiClient {
|
|
|
2979
2914
|
orderQty,
|
|
2980
2915
|
action,
|
|
2981
2916
|
orderType: 'Market',
|
|
2982
|
-
assetType: '
|
|
2917
|
+
assetType: 'future',
|
|
2983
2918
|
timeInForce: 'day',
|
|
2984
2919
|
}, extras);
|
|
2985
2920
|
}
|
|
@@ -2991,7 +2926,7 @@ class MockApiClient {
|
|
|
2991
2926
|
orderQty,
|
|
2992
2927
|
action,
|
|
2993
2928
|
orderType: 'Limit',
|
|
2994
|
-
assetType: '
|
|
2929
|
+
assetType: 'future',
|
|
2995
2930
|
timeInForce,
|
|
2996
2931
|
price,
|
|
2997
2932
|
}, extras);
|
|
@@ -3205,6 +3140,8 @@ class MockApiClient {
|
|
|
3205
3140
|
/**
|
|
3206
3141
|
* Utility functions for mock system environment detection
|
|
3207
3142
|
*/
|
|
3143
|
+
// Type declarations for Node.js environment
|
|
3144
|
+
// Note: process is already declared globally in Node.js types
|
|
3208
3145
|
/**
|
|
3209
3146
|
* Check if mocks should be used based on environment variables
|
|
3210
3147
|
* Supports both browser and Node.js environments
|
|
@@ -4907,95 +4844,161 @@ class FinaticConnect extends EventEmitter {
|
|
|
4907
4844
|
// Register automatic session cleanup
|
|
4908
4845
|
this.registerSessionCleanup();
|
|
4909
4846
|
}
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4847
|
+
async linkUserToSession(userId) {
|
|
4848
|
+
try {
|
|
4849
|
+
if (!this.sessionId) {
|
|
4850
|
+
console.error('No session ID available for user linking');
|
|
4851
|
+
return false;
|
|
4852
|
+
}
|
|
4853
|
+
// Call API endpoint to authenticate user with session
|
|
4854
|
+
const response = await this.apiClient.request('/session/authenticate', {
|
|
4855
|
+
method: 'POST',
|
|
4856
|
+
body: {
|
|
4857
|
+
session_id: this.sessionId,
|
|
4858
|
+
user_id: userId,
|
|
4859
|
+
},
|
|
4860
|
+
});
|
|
4861
|
+
if (response.error) {
|
|
4862
|
+
console.error('Failed to link user to session:', response.error);
|
|
4863
|
+
return false;
|
|
4864
|
+
}
|
|
4865
|
+
console.log('User linked to session successfully');
|
|
4866
|
+
return true;
|
|
4867
|
+
}
|
|
4868
|
+
catch (error) {
|
|
4869
|
+
console.error('Error linking user to session:', error);
|
|
4870
|
+
return false;
|
|
4913
4871
|
}
|
|
4914
|
-
// Keep existing user_id or use empty string as fallback
|
|
4915
|
-
const userId = this.userToken?.user_id || '';
|
|
4916
|
-
this.userToken = {
|
|
4917
|
-
accessToken: tokens.access_token,
|
|
4918
|
-
refreshToken: tokens.refresh_token,
|
|
4919
|
-
expiresIn: 3600, // Default to 1 hour if not provided
|
|
4920
|
-
user_id: userId,
|
|
4921
|
-
tokenType: 'Bearer',
|
|
4922
|
-
scope: 'api:access',
|
|
4923
|
-
};
|
|
4924
|
-
// Store tokens in ApiClient for automatic refresh
|
|
4925
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
4926
|
-
this.apiClient.setTokens(tokens.access_token, tokens.refresh_token, expiresAt, userId);
|
|
4927
4872
|
}
|
|
4928
4873
|
/**
|
|
4929
|
-
*
|
|
4930
|
-
* @
|
|
4874
|
+
* Store user ID for authentication state persistence
|
|
4875
|
+
* @param userId - The user ID to store
|
|
4931
4876
|
*/
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
this.userToken
|
|
4877
|
+
storeUserId(userId) {
|
|
4878
|
+
// Initialize userToken if it doesn't exist
|
|
4879
|
+
if (!this.userToken) {
|
|
4880
|
+
this.userToken = {
|
|
4881
|
+
user_id: userId,
|
|
4882
|
+
};
|
|
4883
|
+
}
|
|
4884
|
+
else {
|
|
4885
|
+
// Update existing userToken with new userId
|
|
4886
|
+
this.userToken.user_id = userId;
|
|
4887
|
+
}
|
|
4888
|
+
// Set user ID in ApiClient for session context
|
|
4889
|
+
this.apiClient.setSessionContext(this.sessionId || '', this.companyId, undefined);
|
|
4936
4890
|
}
|
|
4937
4891
|
/**
|
|
4938
|
-
* Check if the
|
|
4939
|
-
* @returns True if authenticated
|
|
4892
|
+
* Check if the user is fully authenticated (has userId in session context)
|
|
4893
|
+
* @returns True if the user is fully authenticated and ready for API calls
|
|
4940
4894
|
*/
|
|
4941
|
-
|
|
4942
|
-
|
|
4895
|
+
async isAuthenticated() {
|
|
4896
|
+
// Check internal session context only - no localStorage dependency
|
|
4897
|
+
return this.userToken?.user_id !== undefined && this.userToken?.user_id !== null;
|
|
4943
4898
|
}
|
|
4944
4899
|
/**
|
|
4945
4900
|
* Get user's orders with pagination and optional filtering
|
|
4946
4901
|
* @param params - Query parameters including page, perPage, and filters
|
|
4947
4902
|
* @returns Promise with paginated result that supports navigation
|
|
4948
4903
|
*/
|
|
4949
|
-
async getOrders(
|
|
4950
|
-
if (!this.
|
|
4904
|
+
async getOrders(page = 1, perPage = 100, options, filters) {
|
|
4905
|
+
if (!(await this.isAuthenticated())) {
|
|
4951
4906
|
throw new AuthenticationError('User is not authenticated');
|
|
4952
4907
|
}
|
|
4953
|
-
const
|
|
4954
|
-
|
|
4955
|
-
const
|
|
4956
|
-
|
|
4908
|
+
const result = await this.apiClient.getBrokerOrdersPage(page, perPage, filters);
|
|
4909
|
+
// Add navigation methods to the result
|
|
4910
|
+
const paginatedResult = result;
|
|
4911
|
+
paginatedResult.next_page = async () => {
|
|
4912
|
+
if (paginatedResult.hasNext) {
|
|
4913
|
+
return this.apiClient.getBrokerOrdersPage(page + 1, perPage, filters);
|
|
4914
|
+
}
|
|
4915
|
+
throw new Error('No next page available');
|
|
4916
|
+
};
|
|
4917
|
+
paginatedResult.previous_page = async () => {
|
|
4918
|
+
if (paginatedResult.has_previous) {
|
|
4919
|
+
return this.apiClient.getBrokerOrdersPage(page - 1, perPage, filters);
|
|
4920
|
+
}
|
|
4921
|
+
throw new Error('No previous page available');
|
|
4922
|
+
};
|
|
4923
|
+
return paginatedResult;
|
|
4957
4924
|
}
|
|
4958
4925
|
/**
|
|
4959
4926
|
* Get user's positions with pagination and optional filtering
|
|
4960
4927
|
* @param params - Query parameters including page, perPage, and filters
|
|
4961
4928
|
* @returns Promise with paginated result that supports navigation
|
|
4962
4929
|
*/
|
|
4963
|
-
async getPositions(
|
|
4964
|
-
if (!this.
|
|
4930
|
+
async getPositions(page = 1, perPage = 100, options, filters) {
|
|
4931
|
+
if (!(await this.isAuthenticated())) {
|
|
4965
4932
|
throw new AuthenticationError('User is not authenticated');
|
|
4966
4933
|
}
|
|
4967
|
-
const
|
|
4968
|
-
|
|
4969
|
-
const
|
|
4970
|
-
|
|
4934
|
+
const result = await this.apiClient.getBrokerPositionsPage(page, perPage, filters);
|
|
4935
|
+
// Add navigation methods to the result
|
|
4936
|
+
const paginatedResult = result;
|
|
4937
|
+
paginatedResult.next_page = async () => {
|
|
4938
|
+
if (paginatedResult.hasNext) {
|
|
4939
|
+
return this.apiClient.getBrokerPositionsPage(page + 1, perPage, filters);
|
|
4940
|
+
}
|
|
4941
|
+
throw new Error('No next page available');
|
|
4942
|
+
};
|
|
4943
|
+
paginatedResult.previous_page = async () => {
|
|
4944
|
+
if (paginatedResult.has_previous) {
|
|
4945
|
+
return this.apiClient.getBrokerPositionsPage(page - 1, perPage, filters);
|
|
4946
|
+
}
|
|
4947
|
+
throw new Error('No previous page available');
|
|
4948
|
+
};
|
|
4949
|
+
return paginatedResult;
|
|
4971
4950
|
}
|
|
4972
4951
|
/**
|
|
4973
4952
|
* Get user's accounts with pagination and optional filtering
|
|
4974
4953
|
* @param params - Query parameters including page, perPage, and filters
|
|
4975
4954
|
* @returns Promise with paginated result that supports navigation
|
|
4976
4955
|
*/
|
|
4977
|
-
async getAccounts(
|
|
4978
|
-
if (!this.
|
|
4956
|
+
async getAccounts(page = 1, perPage = 100, options, filters) {
|
|
4957
|
+
if (!(await this.isAuthenticated())) {
|
|
4979
4958
|
throw new AuthenticationError('User is not authenticated');
|
|
4980
4959
|
}
|
|
4981
|
-
const
|
|
4982
|
-
|
|
4983
|
-
const
|
|
4984
|
-
|
|
4960
|
+
const result = await this.apiClient.getBrokerAccountsPage(page, perPage, filters);
|
|
4961
|
+
// Add navigation methods to the result
|
|
4962
|
+
const paginatedResult = result;
|
|
4963
|
+
paginatedResult.next_page = async () => {
|
|
4964
|
+
if (paginatedResult.hasNext) {
|
|
4965
|
+
return this.apiClient.getBrokerAccountsPage(page + 1, perPage, filters);
|
|
4966
|
+
}
|
|
4967
|
+
throw new Error('No next page available');
|
|
4968
|
+
};
|
|
4969
|
+
paginatedResult.previous_page = async () => {
|
|
4970
|
+
if (paginatedResult.has_previous) {
|
|
4971
|
+
return this.apiClient.getBrokerAccountsPage(page - 1, perPage, filters);
|
|
4972
|
+
}
|
|
4973
|
+
throw new Error('No previous page available');
|
|
4974
|
+
};
|
|
4975
|
+
return paginatedResult;
|
|
4985
4976
|
}
|
|
4986
4977
|
/**
|
|
4987
4978
|
* Get user's balances with pagination and optional filtering
|
|
4988
4979
|
* @param params - Query parameters including page, perPage, and filters
|
|
4989
4980
|
* @returns Promise with paginated result that supports navigation
|
|
4990
4981
|
*/
|
|
4991
|
-
async getBalances(
|
|
4992
|
-
if (!this.
|
|
4982
|
+
async getBalances(page = 1, perPage = 100, options, filters) {
|
|
4983
|
+
if (!(await this.isAuthenticated())) {
|
|
4993
4984
|
throw new AuthenticationError('User is not authenticated');
|
|
4994
4985
|
}
|
|
4995
|
-
const
|
|
4996
|
-
|
|
4997
|
-
const
|
|
4998
|
-
|
|
4986
|
+
const result = await this.apiClient.getBrokerBalancesPage(page, perPage, filters);
|
|
4987
|
+
// Add navigation methods to the result
|
|
4988
|
+
const paginatedResult = result;
|
|
4989
|
+
paginatedResult.next_page = async () => {
|
|
4990
|
+
if (paginatedResult.hasNext) {
|
|
4991
|
+
return this.apiClient.getBrokerBalancesPage(page + 1, perPage, filters);
|
|
4992
|
+
}
|
|
4993
|
+
throw new Error('No next page available');
|
|
4994
|
+
};
|
|
4995
|
+
paginatedResult.previous_page = async () => {
|
|
4996
|
+
if (paginatedResult.has_previous) {
|
|
4997
|
+
return this.apiClient.getBrokerBalancesPage(page - 1, perPage, filters);
|
|
4998
|
+
}
|
|
4999
|
+
throw new Error('No previous page available');
|
|
5000
|
+
};
|
|
5001
|
+
return paginatedResult;
|
|
4999
5002
|
}
|
|
5000
5003
|
/**
|
|
5001
5004
|
* Initialize the Finatic Connect SDK
|
|
@@ -5048,26 +5051,20 @@ class FinaticConnect extends EventEmitter {
|
|
|
5048
5051
|
FinaticConnect.instance.apiClient.setSessionContext(FinaticConnect.instance.sessionId, FinaticConnect.instance.companyId, startResponse.data.csrf_token // If available in response
|
|
5049
5052
|
);
|
|
5050
5053
|
}
|
|
5051
|
-
// If userId is provided,
|
|
5054
|
+
// If userId is provided, try to link user to session
|
|
5052
5055
|
if (normalizedUserId) {
|
|
5053
5056
|
try {
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
FinaticConnect.instance.userToken = userToken;
|
|
5066
|
-
// Set tokens in ApiClient for automatic token management
|
|
5067
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
5068
|
-
FinaticConnect.instance.apiClient.setTokens(authResponse.data.access_token, authResponse.data.refresh_token, expiresAt, normalizedUserId);
|
|
5069
|
-
// Emit success event
|
|
5070
|
-
FinaticConnect.instance.emit('success', normalizedUserId);
|
|
5057
|
+
// Try to link user to session via API
|
|
5058
|
+
const linked = await FinaticConnect.instance.linkUserToSession(normalizedUserId);
|
|
5059
|
+
if (linked) {
|
|
5060
|
+
// Store user ID for authentication state
|
|
5061
|
+
FinaticConnect.instance.storeUserId(normalizedUserId);
|
|
5062
|
+
// Emit success event
|
|
5063
|
+
FinaticConnect.instance.emit('success', normalizedUserId);
|
|
5064
|
+
}
|
|
5065
|
+
else {
|
|
5066
|
+
console.warn('Failed to link user to session during initialization');
|
|
5067
|
+
}
|
|
5071
5068
|
}
|
|
5072
5069
|
catch (error) {
|
|
5073
5070
|
FinaticConnect.instance.emit('error', error);
|
|
@@ -5088,38 +5085,25 @@ class FinaticConnect extends EventEmitter {
|
|
|
5088
5085
|
* Get the user and tokens for a completed session
|
|
5089
5086
|
* @returns Promise with user information and tokens
|
|
5090
5087
|
*/
|
|
5091
|
-
async getSessionUser() {
|
|
5092
|
-
if (!this.isAuthed()) {
|
|
5093
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5094
|
-
}
|
|
5095
|
-
if (!this.userToken) {
|
|
5096
|
-
throw new AuthenticationError('No user token available');
|
|
5097
|
-
}
|
|
5098
|
-
return {
|
|
5099
|
-
user_id: this.userToken.userId,
|
|
5100
|
-
access_token: this.userToken.accessToken,
|
|
5101
|
-
refresh_token: this.userToken.refreshToken,
|
|
5102
|
-
expires_in: this.userToken.expiresIn,
|
|
5103
|
-
token_type: this.userToken.tokenType,
|
|
5104
|
-
scope: this.userToken.scope,
|
|
5105
|
-
company_id: this.companyId,
|
|
5106
|
-
};
|
|
5107
|
-
}
|
|
5108
5088
|
async initializeWithUser(userId) {
|
|
5109
5089
|
try {
|
|
5110
5090
|
if (!this.sessionId) {
|
|
5111
5091
|
throw new SessionError('Session not initialized');
|
|
5112
5092
|
}
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
if (
|
|
5116
|
-
|
|
5117
|
-
|
|
5093
|
+
// Try to link user to session
|
|
5094
|
+
const linked = await this.linkUserToSession(userId);
|
|
5095
|
+
if (!linked) {
|
|
5096
|
+
console.warn('Failed to link user to session during initialization');
|
|
5097
|
+
// Don't throw error, just continue without authentication
|
|
5098
|
+
return;
|
|
5118
5099
|
}
|
|
5100
|
+
// Store user ID for authentication state
|
|
5101
|
+
this.storeUserId(userId);
|
|
5119
5102
|
this.emit('success', userId);
|
|
5120
5103
|
}
|
|
5121
5104
|
catch (error) {
|
|
5122
5105
|
this.emit('error', error);
|
|
5106
|
+
throw error;
|
|
5123
5107
|
}
|
|
5124
5108
|
}
|
|
5125
5109
|
/**
|
|
@@ -5172,20 +5156,32 @@ class FinaticConnect extends EventEmitter {
|
|
|
5172
5156
|
url.searchParams.set('email', options.email);
|
|
5173
5157
|
themedPortalUrl = url.toString();
|
|
5174
5158
|
}
|
|
5159
|
+
// Add session ID to portal URL so the portal can use it
|
|
5160
|
+
const url = new URL(themedPortalUrl);
|
|
5161
|
+
if (this.sessionId) {
|
|
5162
|
+
url.searchParams.set('session_id', this.sessionId);
|
|
5163
|
+
}
|
|
5164
|
+
if (this.companyId) {
|
|
5165
|
+
url.searchParams.set('company_id', this.companyId);
|
|
5166
|
+
}
|
|
5167
|
+
themedPortalUrl = url.toString();
|
|
5175
5168
|
// Create portal UI if not exists
|
|
5176
5169
|
if (!this.portalUI) {
|
|
5177
5170
|
this.portalUI = new PortalUI(this.baseUrl);
|
|
5178
5171
|
}
|
|
5179
5172
|
// Show portal
|
|
5180
5173
|
this.portalUI.show(themedPortalUrl, this.sessionId || '', {
|
|
5181
|
-
onSuccess: async (userId
|
|
5174
|
+
onSuccess: async (userId) => {
|
|
5182
5175
|
try {
|
|
5183
5176
|
if (!this.sessionId) {
|
|
5184
5177
|
throw new SessionError('Session not initialized');
|
|
5185
5178
|
}
|
|
5186
|
-
//
|
|
5187
|
-
|
|
5188
|
-
|
|
5179
|
+
// Store the userId for authentication state
|
|
5180
|
+
this.storeUserId(userId);
|
|
5181
|
+
// Try to link user to session via API
|
|
5182
|
+
const linked = await this.linkUserToSession(userId);
|
|
5183
|
+
if (!linked) {
|
|
5184
|
+
console.warn('Failed to link user to session, but continuing with authentication');
|
|
5189
5185
|
}
|
|
5190
5186
|
// Emit portal success event
|
|
5191
5187
|
this.emit('portal:success', userId);
|
|
@@ -5276,32 +5272,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5276
5272
|
* Place a new order using the broker order API
|
|
5277
5273
|
* @param order - Order details with broker context
|
|
5278
5274
|
*/
|
|
5279
|
-
async placeOrder(order) {
|
|
5280
|
-
if (!this.
|
|
5281
|
-
throw new
|
|
5275
|
+
async placeOrder(order, extras) {
|
|
5276
|
+
if (!(await this.isAuthenticated())) {
|
|
5277
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5278
|
+
}
|
|
5279
|
+
if (!this.userToken?.user_id) {
|
|
5280
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5282
5281
|
}
|
|
5283
5282
|
try {
|
|
5284
|
-
//
|
|
5285
|
-
|
|
5286
|
-
symbol: order.symbol,
|
|
5287
|
-
orderQty: order.quantity,
|
|
5288
|
-
action: order.side === 'buy' ? 'Buy' : 'Sell',
|
|
5289
|
-
orderType: order.orderType === 'market'
|
|
5290
|
-
? 'Market'
|
|
5291
|
-
: order.orderType === 'limit'
|
|
5292
|
-
? 'Limit'
|
|
5293
|
-
: order.orderType === 'stop'
|
|
5294
|
-
? 'Stop'
|
|
5295
|
-
: 'StopLimit',
|
|
5296
|
-
assetType: order.assetType || 'Stock',
|
|
5297
|
-
timeInForce: order.timeInForce,
|
|
5298
|
-
price: order.price,
|
|
5299
|
-
stopPrice: order.stopPrice,
|
|
5300
|
-
broker: order.broker,
|
|
5301
|
-
accountNumber: order.accountNumber,
|
|
5302
|
-
order_id: order.order_id,
|
|
5303
|
-
};
|
|
5304
|
-
return await this.apiClient.placeBrokerOrder(this.userToken.accessToken, brokerOrder, {}, order.connection_id);
|
|
5283
|
+
// Use the order parameter directly since it's already BrokerOrderParams
|
|
5284
|
+
return await this.apiClient.placeBrokerOrder(order, extras || {}, order.connection_id);
|
|
5305
5285
|
}
|
|
5306
5286
|
catch (error) {
|
|
5307
5287
|
this.emit('error', error);
|
|
@@ -5315,8 +5295,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5315
5295
|
* @param connection_id - Optional connection ID for testing bypass
|
|
5316
5296
|
*/
|
|
5317
5297
|
async cancelOrder(orderId, broker, connection_id) {
|
|
5318
|
-
if (!this.
|
|
5319
|
-
throw new
|
|
5298
|
+
if (!(await this.isAuthenticated())) {
|
|
5299
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5300
|
+
}
|
|
5301
|
+
if (!this.userToken?.user_id) {
|
|
5302
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5320
5303
|
}
|
|
5321
5304
|
try {
|
|
5322
5305
|
return await this.apiClient.cancelBrokerOrder(orderId, broker, {}, connection_id);
|
|
@@ -5334,8 +5317,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5334
5317
|
* @param connection_id - Optional connection ID for testing bypass
|
|
5335
5318
|
*/
|
|
5336
5319
|
async modifyOrder(orderId, modifications, broker, connection_id) {
|
|
5337
|
-
if (!this.
|
|
5338
|
-
throw new
|
|
5320
|
+
if (!(await this.isAuthenticated())) {
|
|
5321
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5322
|
+
}
|
|
5323
|
+
if (!this.userToken?.user_id) {
|
|
5324
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5339
5325
|
}
|
|
5340
5326
|
try {
|
|
5341
5327
|
// Convert modifications to broker format
|
|
@@ -5363,39 +5349,15 @@ class FinaticConnect extends EventEmitter {
|
|
|
5363
5349
|
throw error;
|
|
5364
5350
|
}
|
|
5365
5351
|
}
|
|
5366
|
-
/**
|
|
5367
|
-
* Set the broker context for trading
|
|
5368
|
-
* @param broker - The broker to use for trading
|
|
5369
|
-
*/
|
|
5370
|
-
setTradingContextBroker(broker) {
|
|
5371
|
-
this.apiClient.setBroker(broker);
|
|
5372
|
-
}
|
|
5373
|
-
/**
|
|
5374
|
-
* Set the account context for trading
|
|
5375
|
-
* @param accountNumber - The account number to use for trading
|
|
5376
|
-
* @param accountId - Optional account ID
|
|
5377
|
-
*/
|
|
5378
|
-
setTradingContextAccount(accountNumber, accountId) {
|
|
5379
|
-
this.apiClient.setAccount(accountNumber, accountId);
|
|
5380
|
-
}
|
|
5381
|
-
/**
|
|
5382
|
-
* Get the current trading context
|
|
5383
|
-
*/
|
|
5384
|
-
getTradingContext() {
|
|
5385
|
-
return this.apiClient.getTradingContext();
|
|
5386
|
-
}
|
|
5387
|
-
/**
|
|
5388
|
-
* Clear the trading context
|
|
5389
|
-
*/
|
|
5390
|
-
clearTradingContext() {
|
|
5391
|
-
this.apiClient.clearTradingContext();
|
|
5392
|
-
}
|
|
5393
5352
|
/**
|
|
5394
5353
|
* Place a stock market order (convenience method)
|
|
5395
5354
|
*/
|
|
5396
5355
|
async placeStockMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5397
|
-
if (!this.
|
|
5398
|
-
throw new
|
|
5356
|
+
if (!(await this.isAuthenticated())) {
|
|
5357
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5358
|
+
}
|
|
5359
|
+
if (!this.userToken?.user_id) {
|
|
5360
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5399
5361
|
}
|
|
5400
5362
|
try {
|
|
5401
5363
|
return await this.apiClient.placeStockMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5409,8 +5371,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5409
5371
|
* Place a stock limit order (convenience method)
|
|
5410
5372
|
*/
|
|
5411
5373
|
async placeStockLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5412
|
-
if (!this.
|
|
5413
|
-
throw new
|
|
5374
|
+
if (!(await this.isAuthenticated())) {
|
|
5375
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5376
|
+
}
|
|
5377
|
+
if (!this.userToken?.user_id) {
|
|
5378
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5414
5379
|
}
|
|
5415
5380
|
try {
|
|
5416
5381
|
return await this.apiClient.placeStockLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5424,8 +5389,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5424
5389
|
* Place a stock stop order (convenience method)
|
|
5425
5390
|
*/
|
|
5426
5391
|
async placeStockStopOrder(symbol, quantity, side, stopPrice, timeInForce = 'gtc', broker, accountNumber) {
|
|
5427
|
-
if (!this.
|
|
5428
|
-
throw new
|
|
5392
|
+
if (!(await this.isAuthenticated())) {
|
|
5393
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5394
|
+
}
|
|
5395
|
+
if (!this.userToken?.user_id) {
|
|
5396
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5429
5397
|
}
|
|
5430
5398
|
try {
|
|
5431
5399
|
return await this.apiClient.placeStockStopOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', stopPrice, timeInForce, broker, accountNumber);
|
|
@@ -5439,8 +5407,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5439
5407
|
* Place a crypto market order (convenience method)
|
|
5440
5408
|
*/
|
|
5441
5409
|
async placeCryptoMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5442
|
-
if (!this.
|
|
5443
|
-
throw new
|
|
5410
|
+
if (!(await this.isAuthenticated())) {
|
|
5411
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5412
|
+
}
|
|
5413
|
+
if (!this.userToken?.user_id) {
|
|
5414
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5444
5415
|
}
|
|
5445
5416
|
try {
|
|
5446
5417
|
return await this.apiClient.placeCryptoMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5454,8 +5425,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5454
5425
|
* Place a crypto limit order (convenience method)
|
|
5455
5426
|
*/
|
|
5456
5427
|
async placeCryptoLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5457
|
-
if (!this.
|
|
5458
|
-
throw new
|
|
5428
|
+
if (!(await this.isAuthenticated())) {
|
|
5429
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5430
|
+
}
|
|
5431
|
+
if (!this.userToken?.user_id) {
|
|
5432
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5459
5433
|
}
|
|
5460
5434
|
try {
|
|
5461
5435
|
return await this.apiClient.placeCryptoLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5469,8 +5443,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5469
5443
|
* Place an options market order (convenience method)
|
|
5470
5444
|
*/
|
|
5471
5445
|
async placeOptionsMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5472
|
-
if (!this.
|
|
5473
|
-
throw new
|
|
5446
|
+
if (!(await this.isAuthenticated())) {
|
|
5447
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5448
|
+
}
|
|
5449
|
+
if (!this.userToken?.user_id) {
|
|
5450
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5474
5451
|
}
|
|
5475
5452
|
try {
|
|
5476
5453
|
return await this.apiClient.placeOptionsMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5484,8 +5461,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5484
5461
|
* Place an options limit order (convenience method)
|
|
5485
5462
|
*/
|
|
5486
5463
|
async placeOptionsLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5487
|
-
if (!this.
|
|
5488
|
-
throw new
|
|
5464
|
+
if (!(await this.isAuthenticated())) {
|
|
5465
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5466
|
+
}
|
|
5467
|
+
if (!this.userToken?.user_id) {
|
|
5468
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5489
5469
|
}
|
|
5490
5470
|
try {
|
|
5491
5471
|
return await this.apiClient.placeOptionsLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5499,8 +5479,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5499
5479
|
* Place a futures market order (convenience method)
|
|
5500
5480
|
*/
|
|
5501
5481
|
async placeFuturesMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5502
|
-
if (!this.
|
|
5503
|
-
throw new
|
|
5482
|
+
if (!(await this.isAuthenticated())) {
|
|
5483
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5484
|
+
}
|
|
5485
|
+
if (!this.userToken?.user_id) {
|
|
5486
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5504
5487
|
}
|
|
5505
5488
|
try {
|
|
5506
5489
|
return await this.apiClient.placeFuturesMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5514,8 +5497,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5514
5497
|
* Place a futures limit order (convenience method)
|
|
5515
5498
|
*/
|
|
5516
5499
|
async placeFuturesLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5517
|
-
if (!this.
|
|
5518
|
-
throw new
|
|
5500
|
+
if (!(await this.isAuthenticated())) {
|
|
5501
|
+
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5502
|
+
}
|
|
5503
|
+
if (!this.userToken?.user_id) {
|
|
5504
|
+
throw new AuthenticationError('No user ID available. Please connect a broker first.');
|
|
5519
5505
|
}
|
|
5520
5506
|
try {
|
|
5521
5507
|
return await this.apiClient.placeFuturesLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5530,8 +5516,8 @@ class FinaticConnect extends EventEmitter {
|
|
|
5530
5516
|
* @returns The current user ID or undefined if not authenticated
|
|
5531
5517
|
* @throws AuthenticationError if user is not authenticated
|
|
5532
5518
|
*/
|
|
5533
|
-
getUserId() {
|
|
5534
|
-
if (!this.
|
|
5519
|
+
async getUserId() {
|
|
5520
|
+
if (!(await this.isAuthenticated())) {
|
|
5535
5521
|
return null;
|
|
5536
5522
|
}
|
|
5537
5523
|
if (!this.userToken?.user_id) {
|
|
@@ -5544,7 +5530,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5544
5530
|
* @returns Promise with array of broker information
|
|
5545
5531
|
*/
|
|
5546
5532
|
async getBrokerList() {
|
|
5547
|
-
// if (!this.
|
|
5533
|
+
// if (!this.isAuthenticated()) {
|
|
5548
5534
|
// throw new AuthenticationError('Not authenticated');
|
|
5549
5535
|
// }
|
|
5550
5536
|
const response = await this.apiClient.getBrokerList();
|
|
@@ -5561,7 +5547,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5561
5547
|
* @throws AuthenticationError if user is not authenticated
|
|
5562
5548
|
*/
|
|
5563
5549
|
async getBrokerConnections() {
|
|
5564
|
-
if (!this.
|
|
5550
|
+
if (!(await this.isAuthenticated())) {
|
|
5565
5551
|
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5566
5552
|
}
|
|
5567
5553
|
if (!this.userToken?.user_id) {
|
|
@@ -5635,118 +5621,22 @@ class FinaticConnect extends EventEmitter {
|
|
|
5635
5621
|
return this.getAllPositions({ broker_id: brokerId });
|
|
5636
5622
|
}
|
|
5637
5623
|
// Pagination methods
|
|
5638
|
-
/**
|
|
5639
|
-
* Get a specific page of orders with pagination metadata
|
|
5640
|
-
* @param page - Page number (default: 1)
|
|
5641
|
-
* @param perPage - Items per page (default: 100)
|
|
5642
|
-
* @param filter - Optional filter parameters
|
|
5643
|
-
* @returns Promise with paginated orders result
|
|
5644
|
-
*/
|
|
5645
|
-
async getOrdersPage(page = 1, perPage = 100, filter) {
|
|
5646
|
-
if (!this.isAuthed()) {
|
|
5647
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5648
|
-
}
|
|
5649
|
-
return this.apiClient.getBrokerOrdersPage(page, perPage, filter);
|
|
5650
|
-
}
|
|
5651
|
-
/**
|
|
5652
|
-
* Get a specific page of positions with pagination metadata
|
|
5653
|
-
* @param page - Page number (default: 1)
|
|
5654
|
-
* @param perPage - Items per page (default: 100)
|
|
5655
|
-
* @param filter - Optional filter parameters
|
|
5656
|
-
* @returns Promise with paginated positions result
|
|
5657
|
-
*/
|
|
5658
|
-
async getPositionsPage(page = 1, perPage = 100, filter) {
|
|
5659
|
-
if (!this.isAuthed()) {
|
|
5660
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5661
|
-
}
|
|
5662
|
-
return this.apiClient.getBrokerPositionsPage(page, perPage, filter);
|
|
5663
|
-
}
|
|
5664
|
-
/**
|
|
5665
|
-
* Get a specific page of accounts with pagination metadata
|
|
5666
|
-
* @param page - Page number (default: 1)
|
|
5667
|
-
* @param perPage - Items per page (default: 100)
|
|
5668
|
-
* @param filter - Optional filter parameters
|
|
5669
|
-
* @returns Promise with paginated accounts result
|
|
5670
|
-
*/
|
|
5671
|
-
async getAccountsPage(page = 1, perPage = 100, filter) {
|
|
5672
|
-
if (!this.isAuthed()) {
|
|
5673
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5674
|
-
}
|
|
5675
|
-
return this.apiClient.getBrokerAccountsPage(page, perPage, filter);
|
|
5676
|
-
}
|
|
5677
|
-
async getBalancesPage(page = 1, perPage = 100, filter) {
|
|
5678
|
-
if (!this.isAuthed()) {
|
|
5679
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5680
|
-
}
|
|
5681
|
-
return this.apiClient.getBrokerBalancesPage(page, perPage, filter);
|
|
5682
|
-
}
|
|
5683
|
-
/**
|
|
5684
|
-
* Get the next page of orders
|
|
5685
|
-
* @param previousResult - The previous paginated result
|
|
5686
|
-
* @returns Promise with next page of orders or null if no more pages
|
|
5687
|
-
*/
|
|
5688
|
-
async getNextOrdersPage(previousResult) {
|
|
5689
|
-
if (!this.isAuthed()) {
|
|
5690
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5691
|
-
}
|
|
5692
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5693
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5694
|
-
return this.apiClient.getBrokerOrdersPage(page, limit);
|
|
5695
|
-
});
|
|
5696
|
-
}
|
|
5697
|
-
/**
|
|
5698
|
-
* Get the next page of positions
|
|
5699
|
-
* @param previousResult - The previous paginated result
|
|
5700
|
-
* @returns Promise with next page of positions or null if no more pages
|
|
5701
|
-
*/
|
|
5702
|
-
async getNextPositionsPage(previousResult) {
|
|
5703
|
-
if (!this.isAuthed()) {
|
|
5704
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5705
|
-
}
|
|
5706
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5707
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5708
|
-
return this.apiClient.getBrokerPositionsPage(page, limit);
|
|
5709
|
-
});
|
|
5710
|
-
}
|
|
5711
|
-
/**
|
|
5712
|
-
* Get the next page of accounts
|
|
5713
|
-
* @param previousResult - The previous paginated result
|
|
5714
|
-
* @returns Promise with next page of accounts or null if no more pages
|
|
5715
|
-
*/
|
|
5716
|
-
async getNextAccountsPage(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.getBrokerAccountsPage(page, limit);
|
|
5723
|
-
});
|
|
5724
|
-
}
|
|
5725
|
-
async getNextBalancesPage(previousResult) {
|
|
5726
|
-
if (!this.isAuthed()) {
|
|
5727
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5728
|
-
}
|
|
5729
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5730
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5731
|
-
return this.apiClient.getBrokerBalancesPage(page, limit);
|
|
5732
|
-
});
|
|
5733
|
-
}
|
|
5734
5624
|
/**
|
|
5735
5625
|
* Get all orders across all pages (convenience method)
|
|
5736
5626
|
* @param filter - Optional filter parameters
|
|
5737
5627
|
* @returns Promise with all orders
|
|
5738
5628
|
*/
|
|
5739
5629
|
async getAllOrders(filter) {
|
|
5740
|
-
if (!this.
|
|
5630
|
+
if (!(await this.isAuthenticated())) {
|
|
5741
5631
|
throw new AuthenticationError('User is not authenticated');
|
|
5742
5632
|
}
|
|
5743
5633
|
const allData = [];
|
|
5744
|
-
let currentResult = await this.
|
|
5634
|
+
let currentResult = await this.apiClient.getBrokerOrdersPage(1, 100, filter);
|
|
5745
5635
|
while (currentResult) {
|
|
5746
5636
|
allData.push(...currentResult.data);
|
|
5747
5637
|
if (!currentResult.hasNext)
|
|
5748
5638
|
break;
|
|
5749
|
-
const nextResult = await
|
|
5639
|
+
const nextResult = await currentResult.nextPage();
|
|
5750
5640
|
if (!nextResult)
|
|
5751
5641
|
break;
|
|
5752
5642
|
currentResult = nextResult;
|
|
@@ -5759,16 +5649,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5759
5649
|
* @returns Promise with all positions
|
|
5760
5650
|
*/
|
|
5761
5651
|
async getAllPositions(filter) {
|
|
5762
|
-
if (!this.
|
|
5652
|
+
if (!(await this.isAuthenticated())) {
|
|
5763
5653
|
throw new AuthenticationError('User is not authenticated');
|
|
5764
5654
|
}
|
|
5765
5655
|
const allData = [];
|
|
5766
|
-
let currentResult = await this.
|
|
5656
|
+
let currentResult = await this.apiClient.getBrokerPositionsPage(1, 100, filter);
|
|
5767
5657
|
while (currentResult) {
|
|
5768
5658
|
allData.push(...currentResult.data);
|
|
5769
5659
|
if (!currentResult.hasNext)
|
|
5770
5660
|
break;
|
|
5771
|
-
const nextResult = await
|
|
5661
|
+
const nextResult = await currentResult.nextPage();
|
|
5772
5662
|
if (!nextResult)
|
|
5773
5663
|
break;
|
|
5774
5664
|
currentResult = nextResult;
|
|
@@ -5781,16 +5671,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5781
5671
|
* @returns Promise with all accounts
|
|
5782
5672
|
*/
|
|
5783
5673
|
async getAllAccounts(filter) {
|
|
5784
|
-
if (!this.
|
|
5674
|
+
if (!(await this.isAuthenticated())) {
|
|
5785
5675
|
throw new AuthenticationError('User is not authenticated');
|
|
5786
5676
|
}
|
|
5787
5677
|
const allData = [];
|
|
5788
|
-
let currentResult = await this.
|
|
5678
|
+
let currentResult = await this.apiClient.getBrokerAccountsPage(1, 100, filter);
|
|
5789
5679
|
while (currentResult) {
|
|
5790
5680
|
allData.push(...currentResult.data);
|
|
5791
5681
|
if (!currentResult.hasNext)
|
|
5792
5682
|
break;
|
|
5793
|
-
const nextResult = await
|
|
5683
|
+
const nextResult = await currentResult.nextPage();
|
|
5794
5684
|
if (!nextResult)
|
|
5795
5685
|
break;
|
|
5796
5686
|
currentResult = nextResult;
|
|
@@ -5798,16 +5688,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5798
5688
|
return allData;
|
|
5799
5689
|
}
|
|
5800
5690
|
async getAllBalances(filter) {
|
|
5801
|
-
if (!this.
|
|
5691
|
+
if (!(await this.isAuthenticated())) {
|
|
5802
5692
|
throw new AuthenticationError('User is not authenticated');
|
|
5803
5693
|
}
|
|
5804
5694
|
const allData = [];
|
|
5805
|
-
let currentResult = await this.
|
|
5695
|
+
let currentResult = await this.apiClient.getBrokerBalancesPage(1, 100, filter);
|
|
5806
5696
|
while (currentResult) {
|
|
5807
5697
|
allData.push(...currentResult.data);
|
|
5808
5698
|
if (!currentResult.hasNext)
|
|
5809
5699
|
break;
|
|
5810
|
-
const nextResult = await
|
|
5700
|
+
const nextResult = await currentResult.nextPage();
|
|
5811
5701
|
if (!nextResult)
|
|
5812
5702
|
break;
|
|
5813
5703
|
currentResult = nextResult;
|
|
@@ -5852,7 +5742,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5852
5742
|
* Validate session for keep-alive purposes and handle automatic refresh
|
|
5853
5743
|
*/
|
|
5854
5744
|
async validateSessionKeepAlive() {
|
|
5855
|
-
if (!this.sessionId || !this.
|
|
5745
|
+
if (!this.sessionId || !(await this.isAuthenticated())) {
|
|
5856
5746
|
console.log('[FinaticConnect] Session keep-alive skipped - no active session');
|
|
5857
5747
|
return;
|
|
5858
5748
|
}
|
|
@@ -5963,7 +5853,6 @@ class FinaticConnect extends EventEmitter {
|
|
|
5963
5853
|
const response = await fetch(`${this.baseUrl}/portal/${sessionId}/complete`, {
|
|
5964
5854
|
method: 'POST',
|
|
5965
5855
|
headers: {
|
|
5966
|
-
Authorization: `Bearer ${this.userToken?.accessToken || ''}`,
|
|
5967
5856
|
'Content-Type': 'application/json',
|
|
5968
5857
|
},
|
|
5969
5858
|
});
|
|
@@ -5986,7 +5875,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5986
5875
|
* @throws AuthenticationError if user is not authenticated
|
|
5987
5876
|
*/
|
|
5988
5877
|
async disconnectCompany(connectionId) {
|
|
5989
|
-
if (!this.
|
|
5878
|
+
if (!(await this.isAuthenticated())) {
|
|
5990
5879
|
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5991
5880
|
}
|
|
5992
5881
|
if (!this.userToken?.user_id) {
|
|
@@ -5994,26 +5883,8 @@ class FinaticConnect extends EventEmitter {
|
|
|
5994
5883
|
}
|
|
5995
5884
|
return this.apiClient.disconnectCompany(connectionId);
|
|
5996
5885
|
}
|
|
5997
|
-
/**
|
|
5998
|
-
* Get account balances for the authenticated user
|
|
5999
|
-
* @param filters - Optional filters for balances
|
|
6000
|
-
* @returns Promise with balance data
|
|
6001
|
-
*/
|
|
6002
|
-
async getBalances(filters) {
|
|
6003
|
-
if (!this.isAuthed()) {
|
|
6004
|
-
throw new AuthenticationError('User is not authenticated');
|
|
6005
|
-
}
|
|
6006
|
-
try {
|
|
6007
|
-
const response = await this.apiClient.getBalances(filters);
|
|
6008
|
-
return response.response_data || [];
|
|
6009
|
-
}
|
|
6010
|
-
catch (error) {
|
|
6011
|
-
this.emit('error', error);
|
|
6012
|
-
throw error;
|
|
6013
|
-
}
|
|
6014
|
-
}
|
|
6015
5886
|
}
|
|
6016
5887
|
FinaticConnect.instance = null;
|
|
6017
5888
|
|
|
6018
|
-
export { ApiClient, ApiError, AuthenticationError, AuthorizationError, BaseError, CompanyAccessError, EventEmitter, FinaticConnect,
|
|
5889
|
+
export { ApiClient, ApiError, AuthenticationError, AuthorizationError, BaseError, CompanyAccessError, EventEmitter, FinaticConnect, NetworkError, OrderError, OrderValidationError, PaginatedResult, RateLimitError, SecurityError, SessionError, TokenError, TradingNotEnabledError, ValidationError, appendThemeToURL, createCustomThemeFromPreset, generatePortalThemeURL, getThemePreset, portalThemePresets, validateCustomTheme };
|
|
6019
5890
|
//# sourceMappingURL=index.mjs.map
|