@finatic/client 0.0.138 → 0.0.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +278 -461
- package/dist/index.d.ts +59 -516
- package/dist/index.js +337 -456
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +338 -456
- package/dist/index.mjs.map +1 -1
- package/dist/types/core/client/ApiClient.d.ts +12 -26
- package/dist/types/core/client/FinaticConnect.d.ts +20 -103
- package/dist/types/index.d.ts +1 -2
- package/dist/types/mocks/MockApiClient.d.ts +2 -4
- package/dist/types/mocks/utils.d.ts +0 -5
- package/dist/types/types/api/auth.d.ts +12 -30
- package/dist/types/types/api/broker.d.ts +1 -1
- package/dist/types/types/connect.d.ts +4 -1
- package/package.json +7 -3
- package/src/core/client/ApiClient.ts +1721 -0
- package/src/core/client/FinaticConnect.ts +1476 -0
- package/src/core/portal/PortalUI.ts +300 -0
- package/src/index.d.ts +23 -0
- package/src/index.ts +87 -0
- package/src/mocks/MockApiClient.ts +1032 -0
- package/src/mocks/MockDataProvider.ts +986 -0
- package/src/mocks/MockFactory.ts +97 -0
- package/src/mocks/utils.ts +133 -0
- package/src/themes/portalPresets.ts +1307 -0
- package/src/types/api/auth.ts +112 -0
- package/src/types/api/broker.ts +330 -0
- package/src/types/api/core.ts +53 -0
- package/src/types/api/errors.ts +35 -0
- package/src/types/api/orders.ts +45 -0
- package/src/types/api/portfolio.ts +59 -0
- package/src/types/common/pagination.ts +138 -0
- package/src/types/connect.ts +56 -0
- package/src/types/index.ts +25 -0
- package/src/types/portal.ts +214 -0
- package/src/types/ui/theme.ts +105 -0
- package/src/utils/brokerUtils.ts +85 -0
- package/src/utils/errors.ts +104 -0
- package/src/utils/events.ts +54 -0
- package/src/utils/themeUtils.ts +146 -0
package/dist/index.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
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Refresh the access token using the refresh token
|
|
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
|
-
}
|
|
265
|
+
// Supabase refresh method removed - SDK no longer uses Supabase tokens
|
|
309
266
|
/**
|
|
310
|
-
*
|
|
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() {
|
|
@@ -1670,13 +1594,17 @@ class PortalUI {
|
|
|
1670
1594
|
console.warn('[PortalUI] Received message from unauthorized origin:', event.origin, 'Expected:', this.portalOrigin);
|
|
1671
1595
|
return;
|
|
1672
1596
|
}
|
|
1673
|
-
const { type, userId, error, height, data } = event.data;
|
|
1597
|
+
const { type, userId, access_token, refresh_token, error, height, data } = event.data;
|
|
1674
1598
|
console.log('[PortalUI] Received message:', event.data);
|
|
1675
1599
|
switch (type) {
|
|
1676
1600
|
case 'portal-success': {
|
|
1677
1601
|
// Handle both direct userId and data.userId formats
|
|
1678
1602
|
const successUserId = userId || (data && data.userId);
|
|
1679
|
-
|
|
1603
|
+
const tokens = {
|
|
1604
|
+
access_token: access_token || (data && data.access_token),
|
|
1605
|
+
refresh_token: refresh_token || (data && data.refresh_token)
|
|
1606
|
+
};
|
|
1607
|
+
this.handlePortalSuccess(successUserId, tokens);
|
|
1680
1608
|
break;
|
|
1681
1609
|
}
|
|
1682
1610
|
case 'portal-error': {
|
|
@@ -1708,14 +1636,17 @@ class PortalUI {
|
|
|
1708
1636
|
console.warn('[PortalUI] Received unhandled message type:', type);
|
|
1709
1637
|
}
|
|
1710
1638
|
}
|
|
1711
|
-
handlePortalSuccess(userId) {
|
|
1639
|
+
handlePortalSuccess(userId, tokens) {
|
|
1712
1640
|
if (!userId) {
|
|
1713
1641
|
console.error('[PortalUI] Missing userId in portal-success message');
|
|
1714
1642
|
return;
|
|
1715
1643
|
}
|
|
1716
1644
|
console.log('[PortalUI] Portal success - User connected:', userId);
|
|
1645
|
+
if (tokens?.access_token && tokens?.refresh_token) {
|
|
1646
|
+
console.log('[PortalUI] Tokens received for user:', userId);
|
|
1647
|
+
}
|
|
1717
1648
|
// Pass userId to parent (SDK will handle tokens internally)
|
|
1718
|
-
this.options?.onSuccess?.(userId);
|
|
1649
|
+
this.options?.onSuccess?.(userId, tokens);
|
|
1719
1650
|
}
|
|
1720
1651
|
handlePortalError(error) {
|
|
1721
1652
|
console.error('[PortalUI] Portal error:', error);
|
|
@@ -1811,15 +1742,11 @@ class MockDataProvider {
|
|
|
1811
1742
|
* Generate mock tokens
|
|
1812
1743
|
*/
|
|
1813
1744
|
generateTokens(userId) {
|
|
1814
|
-
|
|
1815
|
-
|
|
1745
|
+
`mock_access_${v4().replace(/-/g, '')}`;
|
|
1746
|
+
`mock_refresh_${v4().replace(/-/g, '')}`;
|
|
1816
1747
|
return {
|
|
1817
|
-
accessToken,
|
|
1818
|
-
refreshToken,
|
|
1819
|
-
expiresIn: 3600, // 1 hour
|
|
1820
1748
|
user_id: userId,
|
|
1821
|
-
|
|
1822
|
-
scope: 'read write',
|
|
1749
|
+
// Removed token fields - we no longer use Supabase tokens in the SDK
|
|
1823
1750
|
};
|
|
1824
1751
|
}
|
|
1825
1752
|
// Authentication & Session Management Mocks
|
|
@@ -1839,6 +1766,7 @@ class MockDataProvider {
|
|
|
1839
1766
|
};
|
|
1840
1767
|
this.sessionData.set(sessionId, sessionData);
|
|
1841
1768
|
return {
|
|
1769
|
+
success: true,
|
|
1842
1770
|
data: sessionData,
|
|
1843
1771
|
message: 'Session started successfully',
|
|
1844
1772
|
};
|
|
@@ -1860,12 +1788,12 @@ class MockDataProvider {
|
|
|
1860
1788
|
success: true,
|
|
1861
1789
|
message: 'OTP verified successfully',
|
|
1862
1790
|
data: {
|
|
1863
|
-
access_token: tokens
|
|
1864
|
-
refresh_token: tokens
|
|
1791
|
+
access_token: '', // No longer using Supabase tokens
|
|
1792
|
+
refresh_token: '', // No longer using Supabase tokens
|
|
1865
1793
|
user_id: userId,
|
|
1866
|
-
expires_in:
|
|
1867
|
-
scope:
|
|
1868
|
-
token_type:
|
|
1794
|
+
expires_in: 0, // No token expiration for session-based auth
|
|
1795
|
+
scope: 'api:access',
|
|
1796
|
+
token_type: 'Bearer',
|
|
1869
1797
|
},
|
|
1870
1798
|
};
|
|
1871
1799
|
}
|
|
@@ -1877,8 +1805,8 @@ class MockDataProvider {
|
|
|
1877
1805
|
success: true,
|
|
1878
1806
|
message: 'Authentication successful',
|
|
1879
1807
|
data: {
|
|
1880
|
-
access_token: tokens
|
|
1881
|
-
refresh_token: tokens
|
|
1808
|
+
access_token: '', // No longer using Supabase tokens
|
|
1809
|
+
refresh_token: '', // No longer using Supabase tokens
|
|
1882
1810
|
},
|
|
1883
1811
|
};
|
|
1884
1812
|
}
|
|
@@ -1924,6 +1852,8 @@ class MockDataProvider {
|
|
|
1924
1852
|
valid: true,
|
|
1925
1853
|
company_id: this.generateCompanyId(),
|
|
1926
1854
|
status: 'active',
|
|
1855
|
+
is_sandbox: false,
|
|
1856
|
+
environment: 'production',
|
|
1927
1857
|
};
|
|
1928
1858
|
}
|
|
1929
1859
|
async mockCompletePortalSession(sessionId) {
|
|
@@ -2027,6 +1957,12 @@ class MockDataProvider {
|
|
|
2027
1957
|
created_at: new Date().toISOString(),
|
|
2028
1958
|
updated_at: new Date().toISOString(),
|
|
2029
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
|
|
2030
1966
|
},
|
|
2031
1967
|
{
|
|
2032
1968
|
id: v4(),
|
|
@@ -2041,6 +1977,12 @@ class MockDataProvider {
|
|
|
2041
1977
|
created_at: new Date().toISOString(),
|
|
2042
1978
|
updated_at: new Date().toISOString(),
|
|
2043
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
|
|
2044
1986
|
},
|
|
2045
1987
|
];
|
|
2046
1988
|
return {
|
|
@@ -2526,6 +2468,12 @@ class MockDataProvider {
|
|
|
2526
2468
|
created_at: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(), // Random date within last year
|
|
2527
2469
|
updated_at: new Date().toISOString(),
|
|
2528
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
|
|
2529
2477
|
});
|
|
2530
2478
|
}
|
|
2531
2479
|
return accounts;
|
|
@@ -2862,12 +2810,6 @@ class MockApiClient {
|
|
|
2862
2810
|
this.tradingContext.accountId = accountId;
|
|
2863
2811
|
console.log('MockApiClient.setAccount Debug - Updated context:', this.tradingContext);
|
|
2864
2812
|
}
|
|
2865
|
-
getTradingContext() {
|
|
2866
|
-
return { ...this.tradingContext };
|
|
2867
|
-
}
|
|
2868
|
-
clearTradingContext() {
|
|
2869
|
-
this.tradingContext = {};
|
|
2870
|
-
}
|
|
2871
2813
|
// Stock convenience methods
|
|
2872
2814
|
async placeStockMarketOrder(symbol, orderQty, action, broker, accountNumber, extras = {}) {
|
|
2873
2815
|
return this.placeBrokerOrder({
|
|
@@ -2877,7 +2819,7 @@ class MockApiClient {
|
|
|
2877
2819
|
orderQty,
|
|
2878
2820
|
action,
|
|
2879
2821
|
orderType: 'Market',
|
|
2880
|
-
assetType: '
|
|
2822
|
+
assetType: 'equity',
|
|
2881
2823
|
timeInForce: 'day',
|
|
2882
2824
|
}, extras);
|
|
2883
2825
|
}
|
|
@@ -2889,7 +2831,7 @@ class MockApiClient {
|
|
|
2889
2831
|
orderQty,
|
|
2890
2832
|
action,
|
|
2891
2833
|
orderType: 'Limit',
|
|
2892
|
-
assetType: '
|
|
2834
|
+
assetType: 'equity',
|
|
2893
2835
|
timeInForce,
|
|
2894
2836
|
price,
|
|
2895
2837
|
}, extras);
|
|
@@ -2902,7 +2844,7 @@ class MockApiClient {
|
|
|
2902
2844
|
orderQty,
|
|
2903
2845
|
action,
|
|
2904
2846
|
orderType: 'Stop',
|
|
2905
|
-
assetType: '
|
|
2847
|
+
assetType: 'equity',
|
|
2906
2848
|
timeInForce,
|
|
2907
2849
|
stopPrice,
|
|
2908
2850
|
}, extras);
|
|
@@ -2916,7 +2858,7 @@ class MockApiClient {
|
|
|
2916
2858
|
orderQty: options.quantity || orderQty,
|
|
2917
2859
|
action,
|
|
2918
2860
|
orderType: 'Market',
|
|
2919
|
-
assetType: '
|
|
2861
|
+
assetType: 'crypto',
|
|
2920
2862
|
timeInForce: 'gtc', // Crypto typically uses GTC
|
|
2921
2863
|
};
|
|
2922
2864
|
return this.placeBrokerOrder(orderParams, extras);
|
|
@@ -2929,7 +2871,7 @@ class MockApiClient {
|
|
|
2929
2871
|
orderQty: options.quantity || orderQty,
|
|
2930
2872
|
action,
|
|
2931
2873
|
orderType: 'Limit',
|
|
2932
|
-
assetType: '
|
|
2874
|
+
assetType: 'crypto',
|
|
2933
2875
|
timeInForce,
|
|
2934
2876
|
price,
|
|
2935
2877
|
};
|
|
@@ -2944,7 +2886,7 @@ class MockApiClient {
|
|
|
2944
2886
|
orderQty,
|
|
2945
2887
|
action,
|
|
2946
2888
|
orderType: 'Market',
|
|
2947
|
-
assetType: '
|
|
2889
|
+
assetType: 'equity_option',
|
|
2948
2890
|
timeInForce: 'day',
|
|
2949
2891
|
};
|
|
2950
2892
|
return this.placeBrokerOrder(orderParams, extras);
|
|
@@ -2957,7 +2899,7 @@ class MockApiClient {
|
|
|
2957
2899
|
orderQty,
|
|
2958
2900
|
action,
|
|
2959
2901
|
orderType: 'Limit',
|
|
2960
|
-
assetType: '
|
|
2902
|
+
assetType: 'equity_option',
|
|
2961
2903
|
timeInForce,
|
|
2962
2904
|
price,
|
|
2963
2905
|
};
|
|
@@ -2972,7 +2914,7 @@ class MockApiClient {
|
|
|
2972
2914
|
orderQty,
|
|
2973
2915
|
action,
|
|
2974
2916
|
orderType: 'Market',
|
|
2975
|
-
assetType: '
|
|
2917
|
+
assetType: 'future',
|
|
2976
2918
|
timeInForce: 'day',
|
|
2977
2919
|
}, extras);
|
|
2978
2920
|
}
|
|
@@ -2984,7 +2926,7 @@ class MockApiClient {
|
|
|
2984
2926
|
orderQty,
|
|
2985
2927
|
action,
|
|
2986
2928
|
orderType: 'Limit',
|
|
2987
|
-
assetType: '
|
|
2929
|
+
assetType: 'future',
|
|
2988
2930
|
timeInForce,
|
|
2989
2931
|
price,
|
|
2990
2932
|
}, extras);
|
|
@@ -3198,6 +3140,8 @@ class MockApiClient {
|
|
|
3198
3140
|
/**
|
|
3199
3141
|
* Utility functions for mock system environment detection
|
|
3200
3142
|
*/
|
|
3143
|
+
// Type declarations for Node.js environment
|
|
3144
|
+
// Note: process is already declared globally in Node.js types
|
|
3201
3145
|
/**
|
|
3202
3146
|
* Check if mocks should be used based on environment variables
|
|
3203
3147
|
* Supports both browser and Node.js environments
|
|
@@ -4900,95 +4844,161 @@ class FinaticConnect extends EventEmitter {
|
|
|
4900
4844
|
// Register automatic session cleanup
|
|
4901
4845
|
this.registerSessionCleanup();
|
|
4902
4846
|
}
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
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;
|
|
4906
4871
|
}
|
|
4907
|
-
// Keep existing user_id or use empty string as fallback
|
|
4908
|
-
const userId = this.userToken?.user_id || '';
|
|
4909
|
-
this.userToken = {
|
|
4910
|
-
accessToken: tokens.access_token,
|
|
4911
|
-
refreshToken: tokens.refresh_token,
|
|
4912
|
-
expiresIn: 3600, // Default to 1 hour if not provided
|
|
4913
|
-
user_id: userId,
|
|
4914
|
-
tokenType: 'Bearer',
|
|
4915
|
-
scope: 'api:access',
|
|
4916
|
-
};
|
|
4917
|
-
// Store tokens in ApiClient for automatic refresh
|
|
4918
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
4919
|
-
this.apiClient.setTokens(tokens.access_token, tokens.refresh_token, expiresAt, userId);
|
|
4920
4872
|
}
|
|
4921
4873
|
/**
|
|
4922
|
-
*
|
|
4923
|
-
* @
|
|
4874
|
+
* Store user ID for authentication state persistence
|
|
4875
|
+
* @param userId - The user ID to store
|
|
4924
4876
|
*/
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
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);
|
|
4929
4890
|
}
|
|
4930
4891
|
/**
|
|
4931
|
-
* Check if the
|
|
4932
|
-
* @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
|
|
4933
4894
|
*/
|
|
4934
|
-
|
|
4935
|
-
|
|
4895
|
+
async isAuthenticated() {
|
|
4896
|
+
// Check internal session context only - no localStorage dependency
|
|
4897
|
+
return this.userToken?.user_id !== undefined && this.userToken?.user_id !== null;
|
|
4936
4898
|
}
|
|
4937
4899
|
/**
|
|
4938
4900
|
* Get user's orders with pagination and optional filtering
|
|
4939
4901
|
* @param params - Query parameters including page, perPage, and filters
|
|
4940
4902
|
* @returns Promise with paginated result that supports navigation
|
|
4941
4903
|
*/
|
|
4942
|
-
async getOrders(
|
|
4943
|
-
if (!this.
|
|
4904
|
+
async getOrders(page = 1, perPage = 100, options, filters) {
|
|
4905
|
+
if (!(await this.isAuthenticated())) {
|
|
4944
4906
|
throw new AuthenticationError('User is not authenticated');
|
|
4945
4907
|
}
|
|
4946
|
-
const
|
|
4947
|
-
|
|
4948
|
-
const
|
|
4949
|
-
|
|
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;
|
|
4950
4924
|
}
|
|
4951
4925
|
/**
|
|
4952
4926
|
* Get user's positions with pagination and optional filtering
|
|
4953
4927
|
* @param params - Query parameters including page, perPage, and filters
|
|
4954
4928
|
* @returns Promise with paginated result that supports navigation
|
|
4955
4929
|
*/
|
|
4956
|
-
async getPositions(
|
|
4957
|
-
if (!this.
|
|
4930
|
+
async getPositions(page = 1, perPage = 100, options, filters) {
|
|
4931
|
+
if (!(await this.isAuthenticated())) {
|
|
4958
4932
|
throw new AuthenticationError('User is not authenticated');
|
|
4959
4933
|
}
|
|
4960
|
-
const
|
|
4961
|
-
|
|
4962
|
-
const
|
|
4963
|
-
|
|
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;
|
|
4964
4950
|
}
|
|
4965
4951
|
/**
|
|
4966
4952
|
* Get user's accounts with pagination and optional filtering
|
|
4967
4953
|
* @param params - Query parameters including page, perPage, and filters
|
|
4968
4954
|
* @returns Promise with paginated result that supports navigation
|
|
4969
4955
|
*/
|
|
4970
|
-
async getAccounts(
|
|
4971
|
-
if (!this.
|
|
4956
|
+
async getAccounts(page = 1, perPage = 100, options, filters) {
|
|
4957
|
+
if (!(await this.isAuthenticated())) {
|
|
4972
4958
|
throw new AuthenticationError('User is not authenticated');
|
|
4973
4959
|
}
|
|
4974
|
-
const
|
|
4975
|
-
|
|
4976
|
-
const
|
|
4977
|
-
|
|
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;
|
|
4978
4976
|
}
|
|
4979
4977
|
/**
|
|
4980
4978
|
* Get user's balances with pagination and optional filtering
|
|
4981
4979
|
* @param params - Query parameters including page, perPage, and filters
|
|
4982
4980
|
* @returns Promise with paginated result that supports navigation
|
|
4983
4981
|
*/
|
|
4984
|
-
async getBalances(
|
|
4985
|
-
if (!this.
|
|
4982
|
+
async getBalances(page = 1, perPage = 100, options, filters) {
|
|
4983
|
+
if (!(await this.isAuthenticated())) {
|
|
4986
4984
|
throw new AuthenticationError('User is not authenticated');
|
|
4987
4985
|
}
|
|
4988
|
-
const
|
|
4989
|
-
|
|
4990
|
-
const
|
|
4991
|
-
|
|
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;
|
|
4992
5002
|
}
|
|
4993
5003
|
/**
|
|
4994
5004
|
* Initialize the Finatic Connect SDK
|
|
@@ -5041,26 +5051,20 @@ class FinaticConnect extends EventEmitter {
|
|
|
5041
5051
|
FinaticConnect.instance.apiClient.setSessionContext(FinaticConnect.instance.sessionId, FinaticConnect.instance.companyId, startResponse.data.csrf_token // If available in response
|
|
5042
5052
|
);
|
|
5043
5053
|
}
|
|
5044
|
-
// If userId is provided,
|
|
5054
|
+
// If userId is provided, try to link user to session
|
|
5045
5055
|
if (normalizedUserId) {
|
|
5046
5056
|
try {
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
FinaticConnect.instance.userToken = userToken;
|
|
5059
|
-
// Set tokens in ApiClient for automatic token management
|
|
5060
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
5061
|
-
FinaticConnect.instance.apiClient.setTokens(authResponse.data.access_token, authResponse.data.refresh_token, expiresAt, normalizedUserId);
|
|
5062
|
-
// Emit success event
|
|
5063
|
-
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
|
+
}
|
|
5064
5068
|
}
|
|
5065
5069
|
catch (error) {
|
|
5066
5070
|
FinaticConnect.instance.emit('error', error);
|
|
@@ -5081,38 +5085,25 @@ class FinaticConnect extends EventEmitter {
|
|
|
5081
5085
|
* Get the user and tokens for a completed session
|
|
5082
5086
|
* @returns Promise with user information and tokens
|
|
5083
5087
|
*/
|
|
5084
|
-
async getSessionUser() {
|
|
5085
|
-
if (!this.isAuthed()) {
|
|
5086
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5087
|
-
}
|
|
5088
|
-
if (!this.userToken) {
|
|
5089
|
-
throw new AuthenticationError('No user token available');
|
|
5090
|
-
}
|
|
5091
|
-
return {
|
|
5092
|
-
user_id: this.userToken.userId,
|
|
5093
|
-
access_token: this.userToken.accessToken,
|
|
5094
|
-
refresh_token: this.userToken.refreshToken,
|
|
5095
|
-
expires_in: this.userToken.expiresIn,
|
|
5096
|
-
token_type: this.userToken.tokenType,
|
|
5097
|
-
scope: this.userToken.scope,
|
|
5098
|
-
company_id: this.companyId,
|
|
5099
|
-
};
|
|
5100
|
-
}
|
|
5101
5088
|
async initializeWithUser(userId) {
|
|
5102
5089
|
try {
|
|
5103
5090
|
if (!this.sessionId) {
|
|
5104
5091
|
throw new SessionError('Session not initialized');
|
|
5105
5092
|
}
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
if (
|
|
5109
|
-
|
|
5110
|
-
|
|
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;
|
|
5111
5099
|
}
|
|
5100
|
+
// Store user ID for authentication state
|
|
5101
|
+
this.storeUserId(userId);
|
|
5112
5102
|
this.emit('success', userId);
|
|
5113
5103
|
}
|
|
5114
5104
|
catch (error) {
|
|
5115
5105
|
this.emit('error', error);
|
|
5106
|
+
throw error;
|
|
5116
5107
|
}
|
|
5117
5108
|
}
|
|
5118
5109
|
/**
|
|
@@ -5165,6 +5156,15 @@ class FinaticConnect extends EventEmitter {
|
|
|
5165
5156
|
url.searchParams.set('email', options.email);
|
|
5166
5157
|
themedPortalUrl = url.toString();
|
|
5167
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();
|
|
5168
5168
|
// Create portal UI if not exists
|
|
5169
5169
|
if (!this.portalUI) {
|
|
5170
5170
|
this.portalUI = new PortalUI(this.baseUrl);
|
|
@@ -5176,6 +5176,13 @@ class FinaticConnect extends EventEmitter {
|
|
|
5176
5176
|
if (!this.sessionId) {
|
|
5177
5177
|
throw new SessionError('Session not initialized');
|
|
5178
5178
|
}
|
|
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');
|
|
5185
|
+
}
|
|
5179
5186
|
// Emit portal success event
|
|
5180
5187
|
this.emit('portal:success', userId);
|
|
5181
5188
|
// Emit legacy success event
|
|
@@ -5265,32 +5272,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5265
5272
|
* Place a new order using the broker order API
|
|
5266
5273
|
* @param order - Order details with broker context
|
|
5267
5274
|
*/
|
|
5268
|
-
async placeOrder(order) {
|
|
5269
|
-
if (!this.
|
|
5270
|
-
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.');
|
|
5271
5281
|
}
|
|
5272
5282
|
try {
|
|
5273
|
-
//
|
|
5274
|
-
|
|
5275
|
-
symbol: order.symbol,
|
|
5276
|
-
orderQty: order.quantity,
|
|
5277
|
-
action: order.side === 'buy' ? 'Buy' : 'Sell',
|
|
5278
|
-
orderType: order.orderType === 'market'
|
|
5279
|
-
? 'Market'
|
|
5280
|
-
: order.orderType === 'limit'
|
|
5281
|
-
? 'Limit'
|
|
5282
|
-
: order.orderType === 'stop'
|
|
5283
|
-
? 'Stop'
|
|
5284
|
-
: 'StopLimit',
|
|
5285
|
-
assetType: order.assetType || 'Stock',
|
|
5286
|
-
timeInForce: order.timeInForce,
|
|
5287
|
-
price: order.price,
|
|
5288
|
-
stopPrice: order.stopPrice,
|
|
5289
|
-
broker: order.broker,
|
|
5290
|
-
accountNumber: order.accountNumber,
|
|
5291
|
-
order_id: order.order_id,
|
|
5292
|
-
};
|
|
5293
|
-
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);
|
|
5294
5285
|
}
|
|
5295
5286
|
catch (error) {
|
|
5296
5287
|
this.emit('error', error);
|
|
@@ -5304,8 +5295,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5304
5295
|
* @param connection_id - Optional connection ID for testing bypass
|
|
5305
5296
|
*/
|
|
5306
5297
|
async cancelOrder(orderId, broker, connection_id) {
|
|
5307
|
-
if (!this.
|
|
5308
|
-
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.');
|
|
5309
5303
|
}
|
|
5310
5304
|
try {
|
|
5311
5305
|
return await this.apiClient.cancelBrokerOrder(orderId, broker, {}, connection_id);
|
|
@@ -5323,8 +5317,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5323
5317
|
* @param connection_id - Optional connection ID for testing bypass
|
|
5324
5318
|
*/
|
|
5325
5319
|
async modifyOrder(orderId, modifications, broker, connection_id) {
|
|
5326
|
-
if (!this.
|
|
5327
|
-
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.');
|
|
5328
5325
|
}
|
|
5329
5326
|
try {
|
|
5330
5327
|
// Convert modifications to broker format
|
|
@@ -5352,39 +5349,15 @@ class FinaticConnect extends EventEmitter {
|
|
|
5352
5349
|
throw error;
|
|
5353
5350
|
}
|
|
5354
5351
|
}
|
|
5355
|
-
/**
|
|
5356
|
-
* Set the broker context for trading
|
|
5357
|
-
* @param broker - The broker to use for trading
|
|
5358
|
-
*/
|
|
5359
|
-
setTradingContextBroker(broker) {
|
|
5360
|
-
this.apiClient.setBroker(broker);
|
|
5361
|
-
}
|
|
5362
|
-
/**
|
|
5363
|
-
* Set the account context for trading
|
|
5364
|
-
* @param accountNumber - The account number to use for trading
|
|
5365
|
-
* @param accountId - Optional account ID
|
|
5366
|
-
*/
|
|
5367
|
-
setTradingContextAccount(accountNumber, accountId) {
|
|
5368
|
-
this.apiClient.setAccount(accountNumber, accountId);
|
|
5369
|
-
}
|
|
5370
|
-
/**
|
|
5371
|
-
* Get the current trading context
|
|
5372
|
-
*/
|
|
5373
|
-
getTradingContext() {
|
|
5374
|
-
return this.apiClient.getTradingContext();
|
|
5375
|
-
}
|
|
5376
|
-
/**
|
|
5377
|
-
* Clear the trading context
|
|
5378
|
-
*/
|
|
5379
|
-
clearTradingContext() {
|
|
5380
|
-
this.apiClient.clearTradingContext();
|
|
5381
|
-
}
|
|
5382
5352
|
/**
|
|
5383
5353
|
* Place a stock market order (convenience method)
|
|
5384
5354
|
*/
|
|
5385
5355
|
async placeStockMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5386
|
-
if (!this.
|
|
5387
|
-
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.');
|
|
5388
5361
|
}
|
|
5389
5362
|
try {
|
|
5390
5363
|
return await this.apiClient.placeStockMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5398,8 +5371,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5398
5371
|
* Place a stock limit order (convenience method)
|
|
5399
5372
|
*/
|
|
5400
5373
|
async placeStockLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5401
|
-
if (!this.
|
|
5402
|
-
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.');
|
|
5403
5379
|
}
|
|
5404
5380
|
try {
|
|
5405
5381
|
return await this.apiClient.placeStockLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5413,8 +5389,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5413
5389
|
* Place a stock stop order (convenience method)
|
|
5414
5390
|
*/
|
|
5415
5391
|
async placeStockStopOrder(symbol, quantity, side, stopPrice, timeInForce = 'gtc', broker, accountNumber) {
|
|
5416
|
-
if (!this.
|
|
5417
|
-
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.');
|
|
5418
5397
|
}
|
|
5419
5398
|
try {
|
|
5420
5399
|
return await this.apiClient.placeStockStopOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', stopPrice, timeInForce, broker, accountNumber);
|
|
@@ -5428,8 +5407,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5428
5407
|
* Place a crypto market order (convenience method)
|
|
5429
5408
|
*/
|
|
5430
5409
|
async placeCryptoMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5431
|
-
if (!this.
|
|
5432
|
-
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.');
|
|
5433
5415
|
}
|
|
5434
5416
|
try {
|
|
5435
5417
|
return await this.apiClient.placeCryptoMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5443,8 +5425,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5443
5425
|
* Place a crypto limit order (convenience method)
|
|
5444
5426
|
*/
|
|
5445
5427
|
async placeCryptoLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5446
|
-
if (!this.
|
|
5447
|
-
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.');
|
|
5448
5433
|
}
|
|
5449
5434
|
try {
|
|
5450
5435
|
return await this.apiClient.placeCryptoLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5458,8 +5443,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5458
5443
|
* Place an options market order (convenience method)
|
|
5459
5444
|
*/
|
|
5460
5445
|
async placeOptionsMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5461
|
-
if (!this.
|
|
5462
|
-
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.');
|
|
5463
5451
|
}
|
|
5464
5452
|
try {
|
|
5465
5453
|
return await this.apiClient.placeOptionsMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5473,8 +5461,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5473
5461
|
* Place an options limit order (convenience method)
|
|
5474
5462
|
*/
|
|
5475
5463
|
async placeOptionsLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5476
|
-
if (!this.
|
|
5477
|
-
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.');
|
|
5478
5469
|
}
|
|
5479
5470
|
try {
|
|
5480
5471
|
return await this.apiClient.placeOptionsLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5488,8 +5479,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5488
5479
|
* Place a futures market order (convenience method)
|
|
5489
5480
|
*/
|
|
5490
5481
|
async placeFuturesMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5491
|
-
if (!this.
|
|
5492
|
-
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.');
|
|
5493
5487
|
}
|
|
5494
5488
|
try {
|
|
5495
5489
|
return await this.apiClient.placeFuturesMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
@@ -5503,8 +5497,11 @@ class FinaticConnect extends EventEmitter {
|
|
|
5503
5497
|
* Place a futures limit order (convenience method)
|
|
5504
5498
|
*/
|
|
5505
5499
|
async placeFuturesLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5506
|
-
if (!this.
|
|
5507
|
-
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.');
|
|
5508
5505
|
}
|
|
5509
5506
|
try {
|
|
5510
5507
|
return await this.apiClient.placeFuturesLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
@@ -5519,8 +5516,8 @@ class FinaticConnect extends EventEmitter {
|
|
|
5519
5516
|
* @returns The current user ID or undefined if not authenticated
|
|
5520
5517
|
* @throws AuthenticationError if user is not authenticated
|
|
5521
5518
|
*/
|
|
5522
|
-
getUserId() {
|
|
5523
|
-
if (!this.
|
|
5519
|
+
async getUserId() {
|
|
5520
|
+
if (!(await this.isAuthenticated())) {
|
|
5524
5521
|
return null;
|
|
5525
5522
|
}
|
|
5526
5523
|
if (!this.userToken?.user_id) {
|
|
@@ -5533,7 +5530,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5533
5530
|
* @returns Promise with array of broker information
|
|
5534
5531
|
*/
|
|
5535
5532
|
async getBrokerList() {
|
|
5536
|
-
// if (!this.
|
|
5533
|
+
// if (!this.isAuthenticated()) {
|
|
5537
5534
|
// throw new AuthenticationError('Not authenticated');
|
|
5538
5535
|
// }
|
|
5539
5536
|
const response = await this.apiClient.getBrokerList();
|
|
@@ -5550,7 +5547,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5550
5547
|
* @throws AuthenticationError if user is not authenticated
|
|
5551
5548
|
*/
|
|
5552
5549
|
async getBrokerConnections() {
|
|
5553
|
-
if (!this.
|
|
5550
|
+
if (!(await this.isAuthenticated())) {
|
|
5554
5551
|
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5555
5552
|
}
|
|
5556
5553
|
if (!this.userToken?.user_id) {
|
|
@@ -5624,118 +5621,22 @@ class FinaticConnect extends EventEmitter {
|
|
|
5624
5621
|
return this.getAllPositions({ broker_id: brokerId });
|
|
5625
5622
|
}
|
|
5626
5623
|
// Pagination methods
|
|
5627
|
-
/**
|
|
5628
|
-
* Get a specific page of orders with pagination metadata
|
|
5629
|
-
* @param page - Page number (default: 1)
|
|
5630
|
-
* @param perPage - Items per page (default: 100)
|
|
5631
|
-
* @param filter - Optional filter parameters
|
|
5632
|
-
* @returns Promise with paginated orders result
|
|
5633
|
-
*/
|
|
5634
|
-
async getOrdersPage(page = 1, perPage = 100, filter) {
|
|
5635
|
-
if (!this.isAuthed()) {
|
|
5636
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5637
|
-
}
|
|
5638
|
-
return this.apiClient.getBrokerOrdersPage(page, perPage, filter);
|
|
5639
|
-
}
|
|
5640
|
-
/**
|
|
5641
|
-
* Get a specific page of positions 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 positions result
|
|
5646
|
-
*/
|
|
5647
|
-
async getPositionsPage(page = 1, perPage = 100, filter) {
|
|
5648
|
-
if (!this.isAuthed()) {
|
|
5649
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5650
|
-
}
|
|
5651
|
-
return this.apiClient.getBrokerPositionsPage(page, perPage, filter);
|
|
5652
|
-
}
|
|
5653
|
-
/**
|
|
5654
|
-
* Get a specific page of accounts 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 accounts result
|
|
5659
|
-
*/
|
|
5660
|
-
async getAccountsPage(page = 1, perPage = 100, filter) {
|
|
5661
|
-
if (!this.isAuthed()) {
|
|
5662
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5663
|
-
}
|
|
5664
|
-
return this.apiClient.getBrokerAccountsPage(page, perPage, filter);
|
|
5665
|
-
}
|
|
5666
|
-
async getBalancesPage(page = 1, perPage = 100, filter) {
|
|
5667
|
-
if (!this.isAuthed()) {
|
|
5668
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5669
|
-
}
|
|
5670
|
-
return this.apiClient.getBrokerBalancesPage(page, perPage, filter);
|
|
5671
|
-
}
|
|
5672
|
-
/**
|
|
5673
|
-
* Get the next page of orders
|
|
5674
|
-
* @param previousResult - The previous paginated result
|
|
5675
|
-
* @returns Promise with next page of orders or null if no more pages
|
|
5676
|
-
*/
|
|
5677
|
-
async getNextOrdersPage(previousResult) {
|
|
5678
|
-
if (!this.isAuthed()) {
|
|
5679
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5680
|
-
}
|
|
5681
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5682
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5683
|
-
return this.apiClient.getBrokerOrdersPage(page, limit);
|
|
5684
|
-
});
|
|
5685
|
-
}
|
|
5686
|
-
/**
|
|
5687
|
-
* Get the next page of positions
|
|
5688
|
-
* @param previousResult - The previous paginated result
|
|
5689
|
-
* @returns Promise with next page of positions or null if no more pages
|
|
5690
|
-
*/
|
|
5691
|
-
async getNextPositionsPage(previousResult) {
|
|
5692
|
-
if (!this.isAuthed()) {
|
|
5693
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5694
|
-
}
|
|
5695
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5696
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5697
|
-
return this.apiClient.getBrokerPositionsPage(page, limit);
|
|
5698
|
-
});
|
|
5699
|
-
}
|
|
5700
|
-
/**
|
|
5701
|
-
* Get the next page of accounts
|
|
5702
|
-
* @param previousResult - The previous paginated result
|
|
5703
|
-
* @returns Promise with next page of accounts or null if no more pages
|
|
5704
|
-
*/
|
|
5705
|
-
async getNextAccountsPage(previousResult) {
|
|
5706
|
-
if (!this.isAuthed()) {
|
|
5707
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5708
|
-
}
|
|
5709
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5710
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5711
|
-
return this.apiClient.getBrokerAccountsPage(page, limit);
|
|
5712
|
-
});
|
|
5713
|
-
}
|
|
5714
|
-
async getNextBalancesPage(previousResult) {
|
|
5715
|
-
if (!this.isAuthed()) {
|
|
5716
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5717
|
-
}
|
|
5718
|
-
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5719
|
-
const page = Math.floor(offset / limit) + 1;
|
|
5720
|
-
return this.apiClient.getBrokerBalancesPage(page, limit);
|
|
5721
|
-
});
|
|
5722
|
-
}
|
|
5723
5624
|
/**
|
|
5724
5625
|
* Get all orders across all pages (convenience method)
|
|
5725
5626
|
* @param filter - Optional filter parameters
|
|
5726
5627
|
* @returns Promise with all orders
|
|
5727
5628
|
*/
|
|
5728
5629
|
async getAllOrders(filter) {
|
|
5729
|
-
if (!this.
|
|
5630
|
+
if (!(await this.isAuthenticated())) {
|
|
5730
5631
|
throw new AuthenticationError('User is not authenticated');
|
|
5731
5632
|
}
|
|
5732
5633
|
const allData = [];
|
|
5733
|
-
let currentResult = await this.
|
|
5634
|
+
let currentResult = await this.apiClient.getBrokerOrdersPage(1, 100, filter);
|
|
5734
5635
|
while (currentResult) {
|
|
5735
5636
|
allData.push(...currentResult.data);
|
|
5736
5637
|
if (!currentResult.hasNext)
|
|
5737
5638
|
break;
|
|
5738
|
-
const nextResult = await
|
|
5639
|
+
const nextResult = await currentResult.nextPage();
|
|
5739
5640
|
if (!nextResult)
|
|
5740
5641
|
break;
|
|
5741
5642
|
currentResult = nextResult;
|
|
@@ -5748,16 +5649,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5748
5649
|
* @returns Promise with all positions
|
|
5749
5650
|
*/
|
|
5750
5651
|
async getAllPositions(filter) {
|
|
5751
|
-
if (!this.
|
|
5652
|
+
if (!(await this.isAuthenticated())) {
|
|
5752
5653
|
throw new AuthenticationError('User is not authenticated');
|
|
5753
5654
|
}
|
|
5754
5655
|
const allData = [];
|
|
5755
|
-
let currentResult = await this.
|
|
5656
|
+
let currentResult = await this.apiClient.getBrokerPositionsPage(1, 100, filter);
|
|
5756
5657
|
while (currentResult) {
|
|
5757
5658
|
allData.push(...currentResult.data);
|
|
5758
5659
|
if (!currentResult.hasNext)
|
|
5759
5660
|
break;
|
|
5760
|
-
const nextResult = await
|
|
5661
|
+
const nextResult = await currentResult.nextPage();
|
|
5761
5662
|
if (!nextResult)
|
|
5762
5663
|
break;
|
|
5763
5664
|
currentResult = nextResult;
|
|
@@ -5770,16 +5671,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5770
5671
|
* @returns Promise with all accounts
|
|
5771
5672
|
*/
|
|
5772
5673
|
async getAllAccounts(filter) {
|
|
5773
|
-
if (!this.
|
|
5674
|
+
if (!(await this.isAuthenticated())) {
|
|
5774
5675
|
throw new AuthenticationError('User is not authenticated');
|
|
5775
5676
|
}
|
|
5776
5677
|
const allData = [];
|
|
5777
|
-
let currentResult = await this.
|
|
5678
|
+
let currentResult = await this.apiClient.getBrokerAccountsPage(1, 100, filter);
|
|
5778
5679
|
while (currentResult) {
|
|
5779
5680
|
allData.push(...currentResult.data);
|
|
5780
5681
|
if (!currentResult.hasNext)
|
|
5781
5682
|
break;
|
|
5782
|
-
const nextResult = await
|
|
5683
|
+
const nextResult = await currentResult.nextPage();
|
|
5783
5684
|
if (!nextResult)
|
|
5784
5685
|
break;
|
|
5785
5686
|
currentResult = nextResult;
|
|
@@ -5787,16 +5688,16 @@ class FinaticConnect extends EventEmitter {
|
|
|
5787
5688
|
return allData;
|
|
5788
5689
|
}
|
|
5789
5690
|
async getAllBalances(filter) {
|
|
5790
|
-
if (!this.
|
|
5691
|
+
if (!(await this.isAuthenticated())) {
|
|
5791
5692
|
throw new AuthenticationError('User is not authenticated');
|
|
5792
5693
|
}
|
|
5793
5694
|
const allData = [];
|
|
5794
|
-
let currentResult = await this.
|
|
5695
|
+
let currentResult = await this.apiClient.getBrokerBalancesPage(1, 100, filter);
|
|
5795
5696
|
while (currentResult) {
|
|
5796
5697
|
allData.push(...currentResult.data);
|
|
5797
5698
|
if (!currentResult.hasNext)
|
|
5798
5699
|
break;
|
|
5799
|
-
const nextResult = await
|
|
5700
|
+
const nextResult = await currentResult.nextPage();
|
|
5800
5701
|
if (!nextResult)
|
|
5801
5702
|
break;
|
|
5802
5703
|
currentResult = nextResult;
|
|
@@ -5841,7 +5742,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5841
5742
|
* Validate session for keep-alive purposes and handle automatic refresh
|
|
5842
5743
|
*/
|
|
5843
5744
|
async validateSessionKeepAlive() {
|
|
5844
|
-
if (!this.sessionId || !this.
|
|
5745
|
+
if (!this.sessionId || !(await this.isAuthenticated())) {
|
|
5845
5746
|
console.log('[FinaticConnect] Session keep-alive skipped - no active session');
|
|
5846
5747
|
return;
|
|
5847
5748
|
}
|
|
@@ -5952,7 +5853,6 @@ class FinaticConnect extends EventEmitter {
|
|
|
5952
5853
|
const response = await fetch(`${this.baseUrl}/portal/${sessionId}/complete`, {
|
|
5953
5854
|
method: 'POST',
|
|
5954
5855
|
headers: {
|
|
5955
|
-
Authorization: `Bearer ${this.userToken?.accessToken || ''}`,
|
|
5956
5856
|
'Content-Type': 'application/json',
|
|
5957
5857
|
},
|
|
5958
5858
|
});
|
|
@@ -5975,7 +5875,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
5975
5875
|
* @throws AuthenticationError if user is not authenticated
|
|
5976
5876
|
*/
|
|
5977
5877
|
async disconnectCompany(connectionId) {
|
|
5978
|
-
if (!this.
|
|
5878
|
+
if (!(await this.isAuthenticated())) {
|
|
5979
5879
|
throw new AuthenticationError('User is not authenticated. Please connect a broker first.');
|
|
5980
5880
|
}
|
|
5981
5881
|
if (!this.userToken?.user_id) {
|
|
@@ -5983,26 +5883,8 @@ class FinaticConnect extends EventEmitter {
|
|
|
5983
5883
|
}
|
|
5984
5884
|
return this.apiClient.disconnectCompany(connectionId);
|
|
5985
5885
|
}
|
|
5986
|
-
/**
|
|
5987
|
-
* Get account balances for the authenticated user
|
|
5988
|
-
* @param filters - Optional filters for balances
|
|
5989
|
-
* @returns Promise with balance data
|
|
5990
|
-
*/
|
|
5991
|
-
async getBalances(filters) {
|
|
5992
|
-
if (!this.isAuthed()) {
|
|
5993
|
-
throw new AuthenticationError('User is not authenticated');
|
|
5994
|
-
}
|
|
5995
|
-
try {
|
|
5996
|
-
const response = await this.apiClient.getBalances(filters);
|
|
5997
|
-
return response.response_data || [];
|
|
5998
|
-
}
|
|
5999
|
-
catch (error) {
|
|
6000
|
-
this.emit('error', error);
|
|
6001
|
-
throw error;
|
|
6002
|
-
}
|
|
6003
|
-
}
|
|
6004
5886
|
}
|
|
6005
5887
|
FinaticConnect.instance = null;
|
|
6006
5888
|
|
|
6007
|
-
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 };
|
|
6008
5890
|
//# sourceMappingURL=index.mjs.map
|