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