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