@finatic/client 0.0.136 → 0.0.137

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -652,23 +652,6 @@ class ApiClient {
652
652
  },
653
653
  });
654
654
  }
655
- async validatePortalSession(sessionId, signature) {
656
- return this.request('/portal/validate', {
657
- method: 'GET',
658
- headers: {
659
- 'Content-Type': 'application/json',
660
- 'X-Session-ID': sessionId,
661
- 'X-Device-Info': JSON.stringify({
662
- ip_address: this.deviceInfo?.ip_address || '',
663
- user_agent: this.deviceInfo?.user_agent || '',
664
- fingerprint: this.deviceInfo?.fingerprint || '',
665
- }),
666
- },
667
- params: {
668
- signature,
669
- },
670
- });
671
- }
672
655
  async completePortalSession(sessionId) {
673
656
  return this.request(`/portal/${sessionId}/complete`, {
674
657
  method: 'POST',
@@ -678,34 +661,14 @@ class ApiClient {
678
661
  });
679
662
  }
680
663
  // Portfolio Management
681
- async getHoldings() {
682
- const accessToken = await this.getValidAccessToken();
683
- return this.request('/portfolio/holdings', {
684
- method: 'GET',
685
- headers: {
686
- 'Authorization': `Bearer ${accessToken}`,
687
- },
688
- });
689
- }
690
664
  async getOrders() {
691
665
  const accessToken = await this.getValidAccessToken();
692
- return this.request('/data/orders', {
693
- method: 'GET',
694
- headers: {
695
- 'Authorization': `Bearer ${accessToken}`,
696
- },
697
- });
698
- }
699
- async getPortfolio() {
700
- const accessToken = await this.getValidAccessToken();
701
- const response = await this.request('/portfolio/', {
666
+ return this.request('/brokers/data/orders', {
702
667
  method: 'GET',
703
668
  headers: {
704
669
  'Authorization': `Bearer ${accessToken}`,
705
- 'Content-Type': 'application/json',
706
670
  },
707
671
  });
708
- return response;
709
672
  }
710
673
  // Enhanced Trading Methods with Session Management
711
674
  async placeBrokerOrder(params, extras = {}, connection_id) {
@@ -768,10 +731,7 @@ class ApiClient {
768
731
  }
769
732
  const accountNumber = this.tradingContext.accountNumber;
770
733
  // Build query parameters as required by API documentation
771
- const queryParams = {
772
- broker: selectedBroker,
773
- order_id: orderId,
774
- };
734
+ const queryParams = {};
775
735
  // Add optional parameters if available
776
736
  if (accountNumber) {
777
737
  queryParams.account_number = accountNumber.toString();
@@ -791,7 +751,7 @@ class ApiClient {
791
751
  }
792
752
  };
793
753
  }
794
- return this.request('/brokers/orders', {
754
+ return this.request(`/brokers/orders/${orderId}`, {
795
755
  method: 'DELETE',
796
756
  headers: {
797
757
  'Content-Type': 'application/json',
@@ -1061,19 +1021,9 @@ class ApiClient {
1061
1021
  return extras;
1062
1022
  }
1063
1023
  }
1064
- async revokeToken() {
1065
- const accessToken = await this.getValidAccessToken();
1066
- await this.request('/auth/token/revoke', {
1067
- method: 'POST',
1068
- headers: {
1069
- 'Authorization': `Bearer ${accessToken}`,
1070
- },
1071
- });
1072
- this.clearTokens();
1073
- }
1074
- async getUserToken(userId) {
1024
+ async getUserToken(sessionId) {
1075
1025
  const accessToken = await this.getValidAccessToken();
1076
- return this.request(`/auth/token/user/${userId}`, {
1026
+ return this.request(`/auth/session/${sessionId}/user`, {
1077
1027
  method: 'GET',
1078
1028
  headers: {
1079
1029
  'Authorization': `Bearer ${accessToken}`,
@@ -1104,7 +1054,7 @@ class ApiClient {
1104
1054
  // Broker Data Management
1105
1055
  async getBrokerList() {
1106
1056
  const accessToken = await this.getValidAccessToken();
1107
- return this.request('/brokers/list', {
1057
+ return this.request('/brokers/', {
1108
1058
  method: 'GET',
1109
1059
  headers: {
1110
1060
  'Authorization': `Bearer ${accessToken}`,
@@ -1171,6 +1121,26 @@ class ApiClient {
1171
1121
  params,
1172
1122
  });
1173
1123
  }
1124
+ async getBrokerBalances(options) {
1125
+ const accessToken = await this.getValidAccessToken();
1126
+ const params = {};
1127
+ if (options?.broker_name) {
1128
+ params.broker_id = options.broker_name;
1129
+ }
1130
+ if (options?.account_id) {
1131
+ params.account_id = options.account_id;
1132
+ }
1133
+ if (options?.symbol) {
1134
+ params.symbol = options.symbol;
1135
+ }
1136
+ return this.request('/brokers/data/balances', {
1137
+ method: 'GET',
1138
+ headers: {
1139
+ 'Authorization': `Bearer ${accessToken}`,
1140
+ },
1141
+ params,
1142
+ });
1143
+ }
1174
1144
  async getBrokerConnections() {
1175
1145
  const accessToken = await this.getValidAccessToken();
1176
1146
  return this.request('/brokers/connections', {
@@ -1180,6 +1150,25 @@ class ApiClient {
1180
1150
  },
1181
1151
  });
1182
1152
  }
1153
+ async getBalances(filters) {
1154
+ const accessToken = await this.getValidAccessToken();
1155
+ const params = new URLSearchParams();
1156
+ if (filters) {
1157
+ Object.entries(filters).forEach(([key, value]) => {
1158
+ if (value !== undefined && value !== null) {
1159
+ params.append(key, String(value));
1160
+ }
1161
+ });
1162
+ }
1163
+ const queryString = params.toString();
1164
+ const url = queryString ? `/brokers/data/balances?${queryString}` : '/brokers/data/balances';
1165
+ return this.request(url, {
1166
+ method: 'GET',
1167
+ headers: {
1168
+ 'Authorization': `Bearer ${accessToken}`,
1169
+ },
1170
+ });
1171
+ }
1183
1172
  // Page-based pagination methods
1184
1173
  async getBrokerOrdersPage(page = 1, perPage = 100, filters) {
1185
1174
  const accessToken = await this.getValidAccessToken();
@@ -1398,6 +1387,81 @@ class ApiClient {
1398
1387
  limit: perPage,
1399
1388
  }, navigationCallback);
1400
1389
  }
1390
+ async getBrokerBalancesPage(page = 1, perPage = 100, filters) {
1391
+ const accessToken = await this.getValidAccessToken();
1392
+ const offset = (page - 1) * perPage;
1393
+ const params = {
1394
+ limit: perPage.toString(),
1395
+ offset: offset.toString(),
1396
+ };
1397
+ // Add filter parameters
1398
+ if (filters) {
1399
+ if (filters.broker_id)
1400
+ params.broker_id = filters.broker_id;
1401
+ if (filters.connection_id)
1402
+ params.connection_id = filters.connection_id;
1403
+ if (filters.account_id)
1404
+ params.account_id = filters.account_id;
1405
+ if (filters.is_end_of_day_snapshot !== undefined)
1406
+ params.is_end_of_day_snapshot = filters.is_end_of_day_snapshot.toString();
1407
+ if (filters.balance_created_after)
1408
+ params.balance_created_after = filters.balance_created_after;
1409
+ if (filters.balance_created_before)
1410
+ params.balance_created_before = filters.balance_created_before;
1411
+ if (filters.with_metadata !== undefined)
1412
+ params.with_metadata = filters.with_metadata.toString();
1413
+ }
1414
+ const response = await this.request('/brokers/data/balances', {
1415
+ method: 'GET',
1416
+ headers: {
1417
+ Authorization: `Bearer ${accessToken}`,
1418
+ },
1419
+ params,
1420
+ });
1421
+ // Create navigation callback for pagination
1422
+ const navigationCallback = async (newOffset, newLimit) => {
1423
+ const newParams = {
1424
+ limit: newLimit.toString(),
1425
+ offset: newOffset.toString(),
1426
+ };
1427
+ // Add filter parameters
1428
+ if (filters) {
1429
+ if (filters.broker_id)
1430
+ newParams.broker_id = filters.broker_id;
1431
+ if (filters.connection_id)
1432
+ newParams.connection_id = filters.connection_id;
1433
+ if (filters.account_id)
1434
+ newParams.account_id = filters.account_id;
1435
+ if (filters.is_end_of_day_snapshot !== undefined)
1436
+ newParams.is_end_of_day_snapshot = filters.is_end_of_day_snapshot.toString();
1437
+ if (filters.balance_created_after)
1438
+ newParams.balance_created_after = filters.balance_created_after;
1439
+ if (filters.balance_created_before)
1440
+ newParams.balance_created_before = filters.balance_created_before;
1441
+ if (filters.with_metadata !== undefined)
1442
+ newParams.with_metadata = filters.with_metadata.toString();
1443
+ }
1444
+ const newResponse = await this.request('/brokers/data/balances', {
1445
+ method: 'GET',
1446
+ headers: {
1447
+ Authorization: `Bearer ${accessToken}`,
1448
+ },
1449
+ params: newParams,
1450
+ });
1451
+ return new PaginatedResult(newResponse.response_data, newResponse.pagination || {
1452
+ has_more: false,
1453
+ next_offset: newOffset,
1454
+ current_offset: newOffset,
1455
+ limit: newLimit,
1456
+ }, navigationCallback);
1457
+ };
1458
+ return new PaginatedResult(response.response_data, response.pagination || {
1459
+ has_more: false,
1460
+ next_offset: offset,
1461
+ current_offset: offset,
1462
+ limit: perPage,
1463
+ }, navigationCallback);
1464
+ }
1401
1465
  // Navigation methods
1402
1466
  async getNextPage(previousResult, fetchFunction) {
1403
1467
  if (!previousResult.hasNext) {
@@ -1419,7 +1483,7 @@ class ApiClient {
1419
1483
  */
1420
1484
  async disconnectCompany(connectionId) {
1421
1485
  const accessToken = await this.getValidAccessToken();
1422
- return this.request(`/brokers/disconnect-company/${connectionId}`, {
1486
+ return this.request(`/brokers/disconnect/${connectionId}`, {
1423
1487
  method: 'DELETE',
1424
1488
  headers: {
1425
1489
  'Authorization': `Bearer ${accessToken}`,
@@ -2074,109 +2138,6 @@ class MockDataProvider {
2074
2138
  };
2075
2139
  }
2076
2140
  // Portfolio & Trading Mocks
2077
- async mockGetHoldings() {
2078
- await this.simulateDelay();
2079
- const holdings = [
2080
- {
2081
- symbol: 'AAPL',
2082
- quantity: 100,
2083
- averagePrice: 150.25,
2084
- currentPrice: 175.5,
2085
- marketValue: 17550.0,
2086
- unrealizedPnL: 2525.0,
2087
- realizedPnL: 0,
2088
- costBasis: 15025.0,
2089
- currency: 'USD',
2090
- },
2091
- {
2092
- symbol: 'TSLA',
2093
- quantity: 50,
2094
- averagePrice: 200.0,
2095
- currentPrice: 220.75,
2096
- marketValue: 11037.5,
2097
- unrealizedPnL: 1037.5,
2098
- realizedPnL: 0,
2099
- costBasis: 10000.0,
2100
- currency: 'USD',
2101
- },
2102
- {
2103
- symbol: 'MSFT',
2104
- quantity: 75,
2105
- averagePrice: 300.0,
2106
- currentPrice: 325.25,
2107
- marketValue: 24393.75,
2108
- unrealizedPnL: 1893.75,
2109
- realizedPnL: 0,
2110
- costBasis: 22500.0,
2111
- currency: 'USD',
2112
- },
2113
- ];
2114
- return { data: holdings };
2115
- }
2116
- async mockGetPortfolio() {
2117
- await this.simulateDelay();
2118
- const portfolio = {
2119
- id: uuid.v4(),
2120
- name: 'Main Portfolio',
2121
- type: 'individual',
2122
- status: 'active',
2123
- cash: 15000.5,
2124
- buyingPower: 45000.0,
2125
- equity: 52981.25,
2126
- longMarketValue: 37981.25,
2127
- shortMarketValue: 0,
2128
- initialMargin: 0,
2129
- maintenanceMargin: 0,
2130
- lastEquity: 52000.0,
2131
- positions: [
2132
- {
2133
- symbol: 'AAPL',
2134
- quantity: 100,
2135
- averagePrice: 150.25,
2136
- currentPrice: 175.5,
2137
- marketValue: 17550.0,
2138
- unrealizedPnL: 2525.0,
2139
- realizedPnL: 0,
2140
- costBasis: 15025.0,
2141
- currency: 'USD',
2142
- },
2143
- {
2144
- symbol: 'TSLA',
2145
- quantity: 50,
2146
- averagePrice: 200.0,
2147
- currentPrice: 220.75,
2148
- marketValue: 11037.5,
2149
- unrealizedPnL: 1037.5,
2150
- realizedPnL: 0,
2151
- costBasis: 10000.0,
2152
- currency: 'USD',
2153
- },
2154
- {
2155
- symbol: 'MSFT',
2156
- quantity: 75,
2157
- averagePrice: 300.0,
2158
- currentPrice: 325.25,
2159
- marketValue: 24393.75,
2160
- unrealizedPnL: 1893.75,
2161
- realizedPnL: 0,
2162
- costBasis: 22500.0,
2163
- currency: 'USD',
2164
- },
2165
- ],
2166
- performance: {
2167
- totalReturn: 0.089,
2168
- dailyReturn: 0.002,
2169
- weeklyReturn: 0.015,
2170
- monthlyReturn: 0.045,
2171
- yearlyReturn: 0.089,
2172
- maxDrawdown: -0.05,
2173
- sharpeRatio: 1.2,
2174
- beta: 0.95,
2175
- alpha: 0.02,
2176
- },
2177
- };
2178
- return { data: portfolio };
2179
- }
2180
2141
  async mockGetOrders(filter) {
2181
2142
  await this.simulateDelay();
2182
2143
  const mockOrders = [
@@ -2237,6 +2198,52 @@ class MockDataProvider {
2237
2198
  data: filteredPositions,
2238
2199
  };
2239
2200
  }
2201
+ async mockGetBrokerBalances(filter) {
2202
+ await this.simulateDelay();
2203
+ // Determine how many balances to generate based on limit parameter
2204
+ const limit = filter?.limit || 100;
2205
+ const maxLimit = Math.min(limit, 1000); // Cap at 1000
2206
+ const mockBalances = [];
2207
+ for (let i = 0; i < maxLimit; i++) {
2208
+ const totalCashValue = Math.random() * 100000 + 10000; // $10k - $110k
2209
+ const netLiquidationValue = totalCashValue * (0.8 + Math.random() * 0.4); // ±20% variation
2210
+ const initialMargin = netLiquidationValue * 0.1; // 10% of net liquidation
2211
+ const maintenanceMargin = initialMargin * 0.8; // 80% of initial margin
2212
+ const availableToWithdraw = totalCashValue * 0.9; // 90% of cash available
2213
+ const totalRealizedPnl = (Math.random() - 0.5) * 10000; // -$5k to +$5k
2214
+ const balance = {
2215
+ id: `balance_${i + 1}`,
2216
+ account_id: `account_${Math.floor(Math.random() * 3) + 1}`,
2217
+ total_cash_value: totalCashValue,
2218
+ net_liquidation_value: netLiquidationValue,
2219
+ initial_margin: initialMargin,
2220
+ maintenance_margin: maintenanceMargin,
2221
+ available_to_withdraw: availableToWithdraw,
2222
+ total_realized_pnl: totalRealizedPnl,
2223
+ balance_created_at: new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000).toISOString(),
2224
+ balance_updated_at: new Date().toISOString(),
2225
+ is_end_of_day_snapshot: Math.random() > 0.7, // 30% chance of being EOD snapshot
2226
+ raw_payload: {
2227
+ broker_specific_data: {
2228
+ margin_ratio: netLiquidationValue / initialMargin,
2229
+ day_trading_buying_power: availableToWithdraw * 4,
2230
+ overnight_buying_power: availableToWithdraw * 2,
2231
+ },
2232
+ },
2233
+ created_at: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000).toISOString(),
2234
+ updated_at: new Date().toISOString(),
2235
+ };
2236
+ mockBalances.push(balance);
2237
+ }
2238
+ // Apply filters if provided
2239
+ let filteredBalances = mockBalances;
2240
+ if (filter) {
2241
+ filteredBalances = this.applyBrokerBalanceFilters(mockBalances, filter);
2242
+ }
2243
+ return {
2244
+ data: filteredBalances,
2245
+ };
2246
+ }
2240
2247
  async mockGetBrokerDataAccounts(filter) {
2241
2248
  await this.simulateDelay();
2242
2249
  // Determine how many accounts to generate based on limit parameter
@@ -2289,8 +2296,8 @@ class MockDataProvider {
2289
2296
  /**
2290
2297
  * Get stored user token
2291
2298
  */
2292
- getUserToken(userId) {
2293
- return this.userTokens.get(userId);
2299
+ getUserToken(sessionId) {
2300
+ return this.userTokens.get(sessionId);
2294
2301
  }
2295
2302
  /**
2296
2303
  * Clear all stored data
@@ -2382,6 +2389,19 @@ class MockDataProvider {
2382
2389
  return true;
2383
2390
  });
2384
2391
  }
2392
+ applyBrokerBalanceFilters(balances, filter) {
2393
+ return balances.filter(balance => {
2394
+ if (filter.account_id && balance.account_id !== filter.account_id)
2395
+ return false;
2396
+ if (filter.is_end_of_day_snapshot !== undefined && balance.is_end_of_day_snapshot !== filter.is_end_of_day_snapshot)
2397
+ return false;
2398
+ if (filter.balance_created_after && balance.balance_created_at && new Date(balance.balance_created_at) < new Date(filter.balance_created_after))
2399
+ return false;
2400
+ if (filter.balance_created_before && balance.balance_created_at && new Date(balance.balance_created_at) > new Date(filter.balance_created_before))
2401
+ return false;
2402
+ return true;
2403
+ });
2404
+ }
2385
2405
  /**
2386
2406
  * Generate mock orders with diverse data
2387
2407
  */
@@ -2793,18 +2813,10 @@ class MockApiClient {
2793
2813
  return this.mockDataProvider.mockCompletePortalSession(sessionId);
2794
2814
  }
2795
2815
  // Portfolio Management
2796
- async getHoldings(filter) {
2797
- await this.getValidAccessToken();
2798
- return this.mockDataProvider.mockGetHoldings();
2799
- }
2800
2816
  async getOrders(filter) {
2801
2817
  await this.getValidAccessToken();
2802
2818
  return this.mockDataProvider.mockGetOrders(filter);
2803
2819
  }
2804
- async getPortfolio() {
2805
- await this.getValidAccessToken();
2806
- return this.mockDataProvider.mockGetPortfolio();
2807
- }
2808
2820
  async placeOrder(order) {
2809
2821
  await this.getValidAccessToken();
2810
2822
  await this.mockDataProvider.mockPlaceOrder(order);
@@ -3015,12 +3027,8 @@ class MockApiClient {
3015
3027
  price,
3016
3028
  }, extras);
3017
3029
  }
3018
- async revokeToken(accessToken) {
3019
- // Clear tokens on revoke
3020
- this.clearTokens();
3021
- }
3022
- async getUserToken(userId) {
3023
- const token = this.mockDataProvider.getUserToken(userId);
3030
+ async getUserToken(sessionId) {
3031
+ const token = this.mockDataProvider.getUserToken(sessionId);
3024
3032
  if (!token) {
3025
3033
  throw new AuthenticationError('User token not found');
3026
3034
  }
@@ -3069,6 +3077,9 @@ class MockApiClient {
3069
3077
  async getBrokerPositionsWithFilter(filter) {
3070
3078
  return this.mockDataProvider.mockGetBrokerPositions(filter);
3071
3079
  }
3080
+ async getBrokerBalancesWithFilter(filter) {
3081
+ return this.mockDataProvider.mockGetBrokerBalances(filter);
3082
+ }
3072
3083
  async getBrokerDataAccountsWithFilter(filter) {
3073
3084
  return this.mockDataProvider.mockGetBrokerDataAccounts(filter);
3074
3085
  }
@@ -3163,6 +3174,36 @@ class MockApiClient {
3163
3174
  limit: perPage,
3164
3175
  }, navigationCallback);
3165
3176
  }
3177
+ async getBrokerBalancesPage(page = 1, perPage = 100, filters) {
3178
+ const mockBalances = await this.mockDataProvider.mockGetBrokerBalances(filters);
3179
+ const balances = mockBalances.data;
3180
+ // Simulate pagination
3181
+ const startIndex = (page - 1) * perPage;
3182
+ const endIndex = startIndex + perPage;
3183
+ const paginatedBalances = balances.slice(startIndex, endIndex);
3184
+ const hasMore = endIndex < balances.length;
3185
+ const nextOffset = hasMore ? endIndex : startIndex;
3186
+ // Create navigation callback for mock pagination
3187
+ const navigationCallback = async (newOffset, newLimit) => {
3188
+ const newStartIndex = newOffset;
3189
+ const newEndIndex = newStartIndex + newLimit;
3190
+ const newPaginatedBalances = balances.slice(newStartIndex, newEndIndex);
3191
+ const newHasMore = newEndIndex < balances.length;
3192
+ const newNextOffset = newHasMore ? newEndIndex : newStartIndex;
3193
+ return new PaginatedResult(newPaginatedBalances, {
3194
+ has_more: newHasMore,
3195
+ next_offset: newNextOffset,
3196
+ current_offset: newStartIndex,
3197
+ limit: newLimit,
3198
+ }, navigationCallback);
3199
+ };
3200
+ return new PaginatedResult(paginatedBalances, {
3201
+ has_more: hasMore,
3202
+ next_offset: nextOffset,
3203
+ current_offset: startIndex,
3204
+ limit: perPage,
3205
+ }, navigationCallback);
3206
+ }
3166
3207
  async getBrokerConnections() {
3167
3208
  await this.getValidAccessToken();
3168
3209
  return this.mockDataProvider.mockGetBrokerConnections();
@@ -3401,9 +3442,135 @@ const darkTheme = {
3401
3442
  },
3402
3443
  },
3403
3444
  },
3445
+ typography: {
3446
+ fontFamily: {
3447
+ primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
3448
+ secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
3449
+ },
3450
+ fontSize: {
3451
+ xs: '0.75rem',
3452
+ sm: '0.875rem',
3453
+ base: '1rem',
3454
+ lg: '1.125rem',
3455
+ xl: '1.25rem',
3456
+ '2xl': '1.5rem',
3457
+ '3xl': '1.875rem',
3458
+ '4xl': '2.25rem',
3459
+ },
3460
+ fontWeight: {
3461
+ normal: 400,
3462
+ medium: 500,
3463
+ semibold: 600,
3464
+ bold: 700,
3465
+ extrabold: 800,
3466
+ },
3467
+ lineHeight: {
3468
+ tight: '1.25',
3469
+ normal: '1.5',
3470
+ relaxed: '1.75',
3471
+ },
3472
+ },
3473
+ spacing: {
3474
+ xs: '0.25rem',
3475
+ sm: '0.5rem',
3476
+ md: '1rem',
3477
+ lg: '1.5rem',
3478
+ xl: '2rem',
3479
+ '2xl': '3rem',
3480
+ '3xl': '4rem',
3481
+ },
3482
+ layout: {
3483
+ containerMaxWidth: '1440px',
3484
+ gridGap: '1rem',
3485
+ cardPadding: '1.5rem',
3486
+ borderRadius: {
3487
+ sm: '0.25rem',
3488
+ md: '0.5rem',
3489
+ lg: '0.75rem',
3490
+ xl: '1rem',
3491
+ '2xl': '1.5rem',
3492
+ full: '9999px',
3493
+ },
3494
+ },
3495
+ components: {
3496
+ brokerCard: {
3497
+ width: '100%',
3498
+ height: '180px',
3499
+ logoSize: '64px',
3500
+ padding: '1.5rem',
3501
+ },
3502
+ statusIndicator: {
3503
+ size: '22px',
3504
+ glowIntensity: 0.9,
3505
+ },
3506
+ modal: {
3507
+ background: 'rgba(0, 0, 0, 0.95)',
3508
+ backdrop: 'rgba(0, 0, 0, 0.8)',
3509
+ },
3510
+ brokerCardModern: {
3511
+ width: '150px',
3512
+ height: '150px',
3513
+ padding: '16px',
3514
+ logoSize: '48px',
3515
+ statusSize: '22px',
3516
+ },
3517
+ connectButton: {
3518
+ width: '120px',
3519
+ height: '120px',
3520
+ },
3521
+ themeSwitcher: {
3522
+ indicatorSize: '24px',
3523
+ },
3524
+ },
3525
+ effects: {
3526
+ glassmorphism: {
3527
+ enabled: true,
3528
+ blur: '12px',
3529
+ opacity: 0.15,
3530
+ border: 'rgba(0, 255, 255, 0.3)',
3531
+ },
3532
+ animations: {
3533
+ enabled: true,
3534
+ duration: {
3535
+ fast: '150ms',
3536
+ normal: '300ms',
3537
+ slow: '500ms',
3538
+ },
3539
+ easing: {
3540
+ default: 'cubic-bezier(0.4, 0, 0.2, 1)',
3541
+ smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
3542
+ bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
3543
+ },
3544
+ },
3545
+ shadows: {
3546
+ sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
3547
+ md: '0 4px 6px rgba(0, 0, 0, 0.6)',
3548
+ lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
3549
+ xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
3550
+ card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(0, 255, 255, 0.2)',
3551
+ cardHover: '0px 4px 24px rgba(0, 255, 255, 0.3), 0 0 30px rgba(0, 255, 255, 0.25)',
3552
+ glow: '0 0 20px rgba(0, 255, 255, 0.8)',
3553
+ focus: '0 0 0 2px #00FFFF, 0 0 8px 2px rgba(0, 255, 255, 0.8)',
3554
+ },
3555
+ },
3404
3556
  branding: {
3405
3557
  primaryColor: '#00FFFF',
3406
3558
  },
3559
+ glow: {
3560
+ primary: 'rgba(0, 255, 255, 0.4)',
3561
+ secondary: 'rgba(0, 255, 255, 0.6)',
3562
+ card: 'rgba(0, 255, 255, 0.2)',
3563
+ cardHover: 'rgba(0, 255, 255, 0.3)',
3564
+ button: 'rgba(0, 255, 255, 0.6)',
3565
+ focus: 'rgba(0, 255, 255, 0.8)',
3566
+ scrollbar: 'rgba(0, 255, 255, 0.4)',
3567
+ },
3568
+ gradients: {
3569
+ start: 'rgba(0, 255, 255, 0.08)',
3570
+ end: 'rgba(0, 255, 255, 0.03)',
3571
+ hoverStart: 'rgba(0, 255, 255, 0.15)',
3572
+ hoverEnd: 'rgba(0, 255, 255, 0.08)',
3573
+ },
3407
3574
  };
3408
3575
  // Light theme with cyan accents
3409
3576
  const lightTheme = {
@@ -3460,9 +3627,121 @@ const lightTheme = {
3460
3627
  },
3461
3628
  },
3462
3629
  },
3630
+ typography: {
3631
+ fontFamily: {
3632
+ primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
3633
+ secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
3634
+ },
3635
+ fontSize: {
3636
+ xs: '0.75rem',
3637
+ sm: '0.875rem',
3638
+ base: '1rem',
3639
+ lg: '1.125rem',
3640
+ xl: '1.25rem',
3641
+ '2xl': '1.5rem',
3642
+ '3xl': '1.875rem',
3643
+ '4xl': '2.25rem',
3644
+ },
3645
+ fontWeight: {
3646
+ normal: 400,
3647
+ medium: 500,
3648
+ semibold: 600,
3649
+ bold: 700,
3650
+ extrabold: 800,
3651
+ },
3652
+ lineHeight: {
3653
+ tight: '1.25',
3654
+ normal: '1.5',
3655
+ relaxed: '1.75',
3656
+ },
3657
+ },
3658
+ spacing: {
3659
+ xs: '0.25rem',
3660
+ sm: '0.5rem',
3661
+ md: '1rem',
3662
+ lg: '1.5rem',
3663
+ xl: '2rem',
3664
+ '2xl': '3rem',
3665
+ '3xl': '4rem',
3666
+ },
3667
+ layout: {
3668
+ containerMaxWidth: '1440px',
3669
+ gridGap: '1rem',
3670
+ cardPadding: '1.5rem',
3671
+ borderRadius: {
3672
+ sm: '0.25rem',
3673
+ md: '0.5rem',
3674
+ lg: '0.75rem',
3675
+ xl: '1rem',
3676
+ '2xl': '1.5rem',
3677
+ full: '9999px',
3678
+ },
3679
+ },
3680
+ components: {
3681
+ brokerCard: {
3682
+ width: '100%',
3683
+ height: '180px',
3684
+ logoSize: '64px',
3685
+ padding: '1.5rem',
3686
+ },
3687
+ statusIndicator: {
3688
+ size: '22px',
3689
+ glowIntensity: 0.9,
3690
+ },
3691
+ modal: {
3692
+ background: 'rgba(255, 255, 255, 0.95)',
3693
+ backdrop: 'rgba(0, 0, 0, 0.5)',
3694
+ },
3695
+ },
3696
+ effects: {
3697
+ glassmorphism: {
3698
+ enabled: true,
3699
+ blur: '12px',
3700
+ opacity: 0.15,
3701
+ border: 'rgba(0, 255, 255, 0.3)',
3702
+ },
3703
+ animations: {
3704
+ enabled: true,
3705
+ duration: {
3706
+ fast: '150ms',
3707
+ normal: '300ms',
3708
+ slow: '500ms',
3709
+ },
3710
+ easing: {
3711
+ default: 'cubic-bezier(0.4, 0, 0.2, 1)',
3712
+ smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
3713
+ bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
3714
+ },
3715
+ },
3716
+ shadows: {
3717
+ sm: '0 1px 2px rgba(0, 0, 0, 0.1)',
3718
+ md: '0 4px 6px rgba(0, 0, 0, 0.1)',
3719
+ lg: '0 10px 15px rgba(0, 0, 0, 0.1)',
3720
+ xl: '0 20px 25px rgba(0, 0, 0, 0.1)',
3721
+ card: '0px 4px 12px rgba(0, 0, 0, 0.1), 0 0 20px rgba(0, 255, 255, 0.2)',
3722
+ cardHover: '0px 4px 24px rgba(0, 255, 255, 0.3), 0 0 30px rgba(0, 255, 255, 0.25)',
3723
+ glow: '0 0 20px rgba(0, 255, 255, 0.8)',
3724
+ focus: '0 0 0 2px #00FFFF, 0 0 8px 2px rgba(0, 255, 255, 0.8)',
3725
+ },
3726
+ },
3463
3727
  branding: {
3464
3728
  primaryColor: '#00FFFF',
3465
3729
  },
3730
+ glow: {
3731
+ primary: 'rgba(0, 255, 255, 0.4)',
3732
+ secondary: 'rgba(0, 255, 255, 0.6)',
3733
+ card: 'rgba(0, 255, 255, 0.2)',
3734
+ cardHover: 'rgba(0, 255, 255, 0.3)',
3735
+ button: 'rgba(0, 255, 255, 0.6)',
3736
+ focus: 'rgba(0, 255, 255, 0.8)',
3737
+ scrollbar: 'rgba(0, 255, 255, 0.4)',
3738
+ },
3739
+ gradients: {
3740
+ start: 'rgba(0, 255, 255, 0.08)',
3741
+ end: 'rgba(0, 255, 255, 0.03)',
3742
+ hoverStart: 'rgba(0, 255, 255, 0.15)',
3743
+ hoverEnd: 'rgba(0, 255, 255, 0.08)',
3744
+ },
3466
3745
  };
3467
3746
  // Corporate blue theme
3468
3747
  const corporateBlueTheme = {
@@ -3519,23 +3798,149 @@ const corporateBlueTheme = {
3519
3798
  },
3520
3799
  },
3521
3800
  },
3522
- branding: {
3523
- primaryColor: '#3B82F6',
3524
- },
3525
- };
3526
- // Purple theme
3527
- const purpleTheme = {
3528
- mode: 'dark',
3529
- colors: {
3530
- background: {
3531
- primary: '#1a1a1a',
3532
- secondary: '#2a2a2a',
3533
- tertiary: '#3a3a3a',
3534
- accent: 'rgba(168, 85, 247, 0.1)',
3535
- glass: 'rgba(255, 255, 255, 0.05)',
3801
+ typography: {
3802
+ fontFamily: {
3803
+ primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
3804
+ secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
3536
3805
  },
3537
- status: {
3538
- connected: '#A855F7',
3806
+ fontSize: {
3807
+ xs: '0.75rem',
3808
+ sm: '0.875rem',
3809
+ base: '1rem',
3810
+ lg: '1.125rem',
3811
+ xl: '1.25rem',
3812
+ '2xl': '1.5rem',
3813
+ '3xl': '1.875rem',
3814
+ '4xl': '2.25rem',
3815
+ },
3816
+ fontWeight: {
3817
+ normal: 400,
3818
+ medium: 500,
3819
+ semibold: 600,
3820
+ bold: 700,
3821
+ extrabold: 800,
3822
+ },
3823
+ lineHeight: {
3824
+ tight: '1.25',
3825
+ normal: '1.5',
3826
+ relaxed: '1.75',
3827
+ },
3828
+ },
3829
+ spacing: {
3830
+ xs: '0.25rem',
3831
+ sm: '0.5rem',
3832
+ md: '1rem',
3833
+ lg: '1.5rem',
3834
+ xl: '2rem',
3835
+ '2xl': '3rem',
3836
+ '3xl': '4rem',
3837
+ },
3838
+ layout: {
3839
+ containerMaxWidth: '1440px',
3840
+ gridGap: '1rem',
3841
+ cardPadding: '1.5rem',
3842
+ borderRadius: {
3843
+ sm: '0.25rem',
3844
+ md: '0.5rem',
3845
+ lg: '0.75rem',
3846
+ xl: '1rem',
3847
+ '2xl': '1.5rem',
3848
+ full: '9999px',
3849
+ },
3850
+ },
3851
+ components: {
3852
+ brokerCard: {
3853
+ width: '100%',
3854
+ height: '180px',
3855
+ logoSize: '64px',
3856
+ padding: '1.5rem',
3857
+ },
3858
+ statusIndicator: {
3859
+ size: '22px',
3860
+ glowIntensity: 0.9,
3861
+ },
3862
+ modal: {
3863
+ background: 'rgba(0, 0, 0, 0.95)',
3864
+ backdrop: 'rgba(0, 0, 0, 0.8)',
3865
+ },
3866
+ brokerCardModern: {
3867
+ width: '150px',
3868
+ height: '150px',
3869
+ padding: '16px',
3870
+ logoSize: '48px',
3871
+ statusSize: '22px',
3872
+ },
3873
+ connectButton: {
3874
+ width: '120px',
3875
+ height: '120px',
3876
+ },
3877
+ themeSwitcher: {
3878
+ indicatorSize: '24px',
3879
+ },
3880
+ },
3881
+ effects: {
3882
+ glassmorphism: {
3883
+ enabled: true,
3884
+ blur: '12px',
3885
+ opacity: 0.15,
3886
+ border: 'rgba(59, 130, 246, 0.3)',
3887
+ },
3888
+ animations: {
3889
+ enabled: true,
3890
+ duration: {
3891
+ fast: '150ms',
3892
+ normal: '300ms',
3893
+ slow: '500ms',
3894
+ },
3895
+ easing: {
3896
+ default: 'cubic-bezier(0.4, 0, 0.2, 1)',
3897
+ smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
3898
+ bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
3899
+ },
3900
+ },
3901
+ shadows: {
3902
+ sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
3903
+ md: '0 4px 6px rgba(0, 0, 0, 0.6)',
3904
+ lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
3905
+ xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
3906
+ card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(59, 130, 246, 0.2)',
3907
+ cardHover: '0px 4px 24px rgba(59, 130, 246, 0.3), 0 0 30px rgba(59, 130, 246, 0.25)',
3908
+ glow: '0 0 20px rgba(59, 130, 246, 0.8)',
3909
+ focus: '0 0 0 2px #3B82F6, 0 0 8px 2px rgba(59, 130, 246, 0.8)',
3910
+ },
3911
+ },
3912
+ branding: {
3913
+ primaryColor: '#3B82F6',
3914
+ },
3915
+ glow: {
3916
+ primary: 'rgba(59, 130, 246, 0.4)',
3917
+ secondary: 'rgba(59, 130, 246, 0.6)',
3918
+ card: 'rgba(59, 130, 246, 0.2)',
3919
+ cardHover: 'rgba(59, 130, 246, 0.3)',
3920
+ button: 'rgba(59, 130, 246, 0.6)',
3921
+ focus: 'rgba(59, 130, 246, 0.8)',
3922
+ scrollbar: 'rgba(59, 130, 246, 0.4)',
3923
+ },
3924
+ gradients: {
3925
+ start: 'rgba(59, 130, 246, 0.08)',
3926
+ end: 'rgba(59, 130, 246, 0.03)',
3927
+ hoverStart: 'rgba(59, 130, 246, 0.15)',
3928
+ hoverEnd: 'rgba(59, 130, 246, 0.08)',
3929
+ },
3930
+ };
3931
+ // Purple theme
3932
+ const purpleTheme = {
3933
+ mode: 'dark',
3934
+ colors: {
3935
+ background: {
3936
+ primary: '#1a1a1a',
3937
+ secondary: '#2a2a2a',
3938
+ tertiary: '#3a3a3a',
3939
+ accent: 'rgba(168, 85, 247, 0.1)',
3940
+ glass: 'rgba(255, 255, 255, 0.05)',
3941
+ },
3942
+ status: {
3943
+ connected: '#A855F7',
3539
3944
  disconnected: '#EF4444',
3540
3945
  warning: '#F59E0B',
3541
3946
  pending: '#8B5CF6',
@@ -3578,9 +3983,135 @@ const purpleTheme = {
3578
3983
  },
3579
3984
  },
3580
3985
  },
3986
+ typography: {
3987
+ fontFamily: {
3988
+ primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
3989
+ secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
3990
+ },
3991
+ fontSize: {
3992
+ xs: '0.75rem',
3993
+ sm: '0.875rem',
3994
+ base: '1rem',
3995
+ lg: '1.125rem',
3996
+ xl: '1.25rem',
3997
+ '2xl': '1.5rem',
3998
+ '3xl': '1.875rem',
3999
+ '4xl': '2.25rem',
4000
+ },
4001
+ fontWeight: {
4002
+ normal: 400,
4003
+ medium: 500,
4004
+ semibold: 600,
4005
+ bold: 700,
4006
+ extrabold: 800,
4007
+ },
4008
+ lineHeight: {
4009
+ tight: '1.25',
4010
+ normal: '1.5',
4011
+ relaxed: '1.75',
4012
+ },
4013
+ },
4014
+ spacing: {
4015
+ xs: '0.25rem',
4016
+ sm: '0.5rem',
4017
+ md: '1rem',
4018
+ lg: '1.5rem',
4019
+ xl: '2rem',
4020
+ '2xl': '3rem',
4021
+ '3xl': '4rem',
4022
+ },
4023
+ layout: {
4024
+ containerMaxWidth: '1440px',
4025
+ gridGap: '1rem',
4026
+ cardPadding: '1.5rem',
4027
+ borderRadius: {
4028
+ sm: '0.25rem',
4029
+ md: '0.5rem',
4030
+ lg: '0.75rem',
4031
+ xl: '1rem',
4032
+ '2xl': '1.5rem',
4033
+ full: '9999px',
4034
+ },
4035
+ },
4036
+ components: {
4037
+ brokerCard: {
4038
+ width: '100%',
4039
+ height: '180px',
4040
+ logoSize: '64px',
4041
+ padding: '1.5rem',
4042
+ },
4043
+ statusIndicator: {
4044
+ size: '22px',
4045
+ glowIntensity: 0.9,
4046
+ },
4047
+ modal: {
4048
+ background: 'rgba(0, 0, 0, 0.95)',
4049
+ backdrop: 'rgba(0, 0, 0, 0.8)',
4050
+ },
4051
+ brokerCardModern: {
4052
+ width: '150px',
4053
+ height: '150px',
4054
+ padding: '16px',
4055
+ logoSize: '48px',
4056
+ statusSize: '22px',
4057
+ },
4058
+ connectButton: {
4059
+ width: '120px',
4060
+ height: '120px',
4061
+ },
4062
+ themeSwitcher: {
4063
+ indicatorSize: '24px',
4064
+ },
4065
+ },
4066
+ effects: {
4067
+ glassmorphism: {
4068
+ enabled: true,
4069
+ blur: '12px',
4070
+ opacity: 0.15,
4071
+ border: 'rgba(168, 85, 247, 0.3)',
4072
+ },
4073
+ animations: {
4074
+ enabled: true,
4075
+ duration: {
4076
+ fast: '150ms',
4077
+ normal: '300ms',
4078
+ slow: '500ms',
4079
+ },
4080
+ easing: {
4081
+ default: 'cubic-bezier(0.4, 0, 0.2, 1)',
4082
+ smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
4083
+ bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
4084
+ },
4085
+ },
4086
+ shadows: {
4087
+ sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
4088
+ md: '0 4px 6px rgba(0, 0, 0, 0.6)',
4089
+ lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
4090
+ xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
4091
+ card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(168, 85, 247, 0.2)',
4092
+ cardHover: '0px 4px 24px rgba(168, 85, 247, 0.3), 0 0 30px rgba(168, 85, 247, 0.25)',
4093
+ glow: '0 0 20px rgba(168, 85, 247, 0.8)',
4094
+ focus: '0 0 0 2px #A855F7, 0 0 8px 2px rgba(168, 85, 247, 0.8)',
4095
+ },
4096
+ },
3581
4097
  branding: {
3582
4098
  primaryColor: '#A855F7',
3583
4099
  },
4100
+ glow: {
4101
+ primary: 'rgba(168, 85, 247, 0.4)',
4102
+ secondary: 'rgba(168, 85, 247, 0.6)',
4103
+ card: 'rgba(168, 85, 247, 0.2)',
4104
+ cardHover: 'rgba(168, 85, 247, 0.3)',
4105
+ button: 'rgba(168, 85, 247, 0.6)',
4106
+ focus: 'rgba(168, 85, 247, 0.8)',
4107
+ scrollbar: 'rgba(168, 85, 247, 0.4)',
4108
+ },
4109
+ gradients: {
4110
+ start: 'rgba(168, 85, 247, 0.08)',
4111
+ end: 'rgba(168, 85, 247, 0.03)',
4112
+ hoverStart: 'rgba(168, 85, 247, 0.15)',
4113
+ hoverEnd: 'rgba(168, 85, 247, 0.08)',
4114
+ },
3584
4115
  };
3585
4116
  // Green theme
3586
4117
  const greenTheme = {
@@ -3637,9 +4168,135 @@ const greenTheme = {
3637
4168
  },
3638
4169
  },
3639
4170
  },
4171
+ typography: {
4172
+ fontFamily: {
4173
+ primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
4174
+ secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
4175
+ },
4176
+ fontSize: {
4177
+ xs: '0.75rem',
4178
+ sm: '0.875rem',
4179
+ base: '1rem',
4180
+ lg: '1.125rem',
4181
+ xl: '1.25rem',
4182
+ '2xl': '1.5rem',
4183
+ '3xl': '1.875rem',
4184
+ '4xl': '2.25rem',
4185
+ },
4186
+ fontWeight: {
4187
+ normal: 400,
4188
+ medium: 500,
4189
+ semibold: 600,
4190
+ bold: 700,
4191
+ extrabold: 800,
4192
+ },
4193
+ lineHeight: {
4194
+ tight: '1.25',
4195
+ normal: '1.5',
4196
+ relaxed: '1.75',
4197
+ },
4198
+ },
4199
+ spacing: {
4200
+ xs: '0.25rem',
4201
+ sm: '0.5rem',
4202
+ md: '1rem',
4203
+ lg: '1.5rem',
4204
+ xl: '2rem',
4205
+ '2xl': '3rem',
4206
+ '3xl': '4rem',
4207
+ },
4208
+ layout: {
4209
+ containerMaxWidth: '1440px',
4210
+ gridGap: '1rem',
4211
+ cardPadding: '1.5rem',
4212
+ borderRadius: {
4213
+ sm: '0.25rem',
4214
+ md: '0.5rem',
4215
+ lg: '0.75rem',
4216
+ xl: '1rem',
4217
+ '2xl': '1.5rem',
4218
+ full: '9999px',
4219
+ },
4220
+ },
4221
+ components: {
4222
+ brokerCard: {
4223
+ width: '100%',
4224
+ height: '180px',
4225
+ logoSize: '64px',
4226
+ padding: '1.5rem',
4227
+ },
4228
+ statusIndicator: {
4229
+ size: '22px',
4230
+ glowIntensity: 0.9,
4231
+ },
4232
+ modal: {
4233
+ background: 'rgba(0, 0, 0, 0.95)',
4234
+ backdrop: 'rgba(0, 0, 0, 0.8)',
4235
+ },
4236
+ brokerCardModern: {
4237
+ width: '150px',
4238
+ height: '150px',
4239
+ padding: '16px',
4240
+ logoSize: '48px',
4241
+ statusSize: '22px',
4242
+ },
4243
+ connectButton: {
4244
+ width: '120px',
4245
+ height: '120px',
4246
+ },
4247
+ themeSwitcher: {
4248
+ indicatorSize: '24px',
4249
+ },
4250
+ },
4251
+ effects: {
4252
+ glassmorphism: {
4253
+ enabled: true,
4254
+ blur: '12px',
4255
+ opacity: 0.15,
4256
+ border: 'rgba(34, 197, 94, 0.3)',
4257
+ },
4258
+ animations: {
4259
+ enabled: true,
4260
+ duration: {
4261
+ fast: '150ms',
4262
+ normal: '300ms',
4263
+ slow: '500ms',
4264
+ },
4265
+ easing: {
4266
+ default: 'cubic-bezier(0.4, 0, 0.2, 1)',
4267
+ smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
4268
+ bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
4269
+ },
4270
+ },
4271
+ shadows: {
4272
+ sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
4273
+ md: '0 4px 6px rgba(0, 0, 0, 0.6)',
4274
+ lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
4275
+ xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
4276
+ card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(34, 197, 94, 0.2)',
4277
+ cardHover: '0px 4px 24px rgba(34, 197, 94, 0.3), 0 0 30px rgba(34, 197, 94, 0.25)',
4278
+ glow: '0 0 20px rgba(34, 197, 94, 0.8)',
4279
+ focus: '0 0 0 2px #22C55E, 0 0 8px 2px rgba(34, 197, 94, 0.8)',
4280
+ },
4281
+ },
3640
4282
  branding: {
3641
4283
  primaryColor: '#22C55E',
3642
4284
  },
4285
+ glow: {
4286
+ primary: 'rgba(34, 197, 94, 0.4)',
4287
+ secondary: 'rgba(34, 197, 94, 0.6)',
4288
+ card: 'rgba(34, 197, 94, 0.2)',
4289
+ cardHover: 'rgba(34, 197, 94, 0.3)',
4290
+ button: 'rgba(34, 197, 94, 0.6)',
4291
+ focus: 'rgba(34, 197, 94, 0.8)',
4292
+ scrollbar: 'rgba(34, 197, 94, 0.4)',
4293
+ },
4294
+ gradients: {
4295
+ start: 'rgba(34, 197, 94, 0.08)',
4296
+ end: 'rgba(34, 197, 94, 0.03)',
4297
+ hoverStart: 'rgba(34, 197, 94, 0.15)',
4298
+ hoverEnd: 'rgba(34, 197, 94, 0.08)',
4299
+ },
3643
4300
  };
3644
4301
  // Orange theme
3645
4302
  const orangeTheme = {
@@ -3696,9 +4353,135 @@ const orangeTheme = {
3696
4353
  },
3697
4354
  },
3698
4355
  },
4356
+ typography: {
4357
+ fontFamily: {
4358
+ primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
4359
+ secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
4360
+ },
4361
+ fontSize: {
4362
+ xs: '0.75rem',
4363
+ sm: '0.875rem',
4364
+ base: '1rem',
4365
+ lg: '1.125rem',
4366
+ xl: '1.25rem',
4367
+ '2xl': '1.5rem',
4368
+ '3xl': '1.875rem',
4369
+ '4xl': '2.25rem',
4370
+ },
4371
+ fontWeight: {
4372
+ normal: 400,
4373
+ medium: 500,
4374
+ semibold: 600,
4375
+ bold: 700,
4376
+ extrabold: 800,
4377
+ },
4378
+ lineHeight: {
4379
+ tight: '1.25',
4380
+ normal: '1.5',
4381
+ relaxed: '1.75',
4382
+ },
4383
+ },
4384
+ spacing: {
4385
+ xs: '0.25rem',
4386
+ sm: '0.5rem',
4387
+ md: '1rem',
4388
+ lg: '1.5rem',
4389
+ xl: '2rem',
4390
+ '2xl': '3rem',
4391
+ '3xl': '4rem',
4392
+ },
4393
+ layout: {
4394
+ containerMaxWidth: '1440px',
4395
+ gridGap: '1rem',
4396
+ cardPadding: '1.5rem',
4397
+ borderRadius: {
4398
+ sm: '0.25rem',
4399
+ md: '0.5rem',
4400
+ lg: '0.75rem',
4401
+ xl: '1rem',
4402
+ '2xl': '1.5rem',
4403
+ full: '9999px',
4404
+ },
4405
+ },
4406
+ components: {
4407
+ brokerCard: {
4408
+ width: '100%',
4409
+ height: '180px',
4410
+ logoSize: '64px',
4411
+ padding: '1.5rem',
4412
+ },
4413
+ statusIndicator: {
4414
+ size: '22px',
4415
+ glowIntensity: 0.9,
4416
+ },
4417
+ modal: {
4418
+ background: 'rgba(0, 0, 0, 0.95)',
4419
+ backdrop: 'rgba(0, 0, 0, 0.8)',
4420
+ },
4421
+ brokerCardModern: {
4422
+ width: '150px',
4423
+ height: '150px',
4424
+ padding: '16px',
4425
+ logoSize: '48px',
4426
+ statusSize: '22px',
4427
+ },
4428
+ connectButton: {
4429
+ width: '120px',
4430
+ height: '120px',
4431
+ },
4432
+ themeSwitcher: {
4433
+ indicatorSize: '24px',
4434
+ },
4435
+ },
4436
+ effects: {
4437
+ glassmorphism: {
4438
+ enabled: true,
4439
+ blur: '12px',
4440
+ opacity: 0.15,
4441
+ border: 'rgba(249, 115, 22, 0.3)',
4442
+ },
4443
+ animations: {
4444
+ enabled: true,
4445
+ duration: {
4446
+ fast: '150ms',
4447
+ normal: '300ms',
4448
+ slow: '500ms',
4449
+ },
4450
+ easing: {
4451
+ default: 'cubic-bezier(0.4, 0, 0.2, 1)',
4452
+ smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
4453
+ bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
4454
+ },
4455
+ },
4456
+ shadows: {
4457
+ sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
4458
+ md: '0 4px 6px rgba(0, 0, 0, 0.6)',
4459
+ lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
4460
+ xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
4461
+ card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(249, 115, 22, 0.2)',
4462
+ cardHover: '0px 4px 24px rgba(249, 115, 22, 0.3), 0 0 30px rgba(249, 115, 22, 0.25)',
4463
+ glow: '0 0 20px rgba(249, 115, 22, 0.8)',
4464
+ focus: '0 0 0 2px #F97316, 0 0 8px 2px rgba(249, 115, 22, 0.8)',
4465
+ },
4466
+ },
3699
4467
  branding: {
3700
4468
  primaryColor: '#F97316',
3701
4469
  },
4470
+ glow: {
4471
+ primary: 'rgba(249, 115, 22, 0.4)',
4472
+ secondary: 'rgba(249, 115, 22, 0.6)',
4473
+ card: 'rgba(249, 115, 22, 0.2)',
4474
+ cardHover: 'rgba(249, 115, 22, 0.3)',
4475
+ button: 'rgba(249, 115, 22, 0.6)',
4476
+ focus: 'rgba(249, 115, 22, 0.8)',
4477
+ scrollbar: 'rgba(249, 115, 22, 0.4)',
4478
+ },
4479
+ gradients: {
4480
+ start: 'rgba(249, 115, 22, 0.08)',
4481
+ end: 'rgba(249, 115, 22, 0.03)',
4482
+ hoverStart: 'rgba(249, 115, 22, 0.15)',
4483
+ hoverEnd: 'rgba(249, 115, 22, 0.08)',
4484
+ },
3702
4485
  };
3703
4486
  // Theme preset mapping
3704
4487
  const portalThemePresets = {
@@ -3783,17 +4566,36 @@ function getThemePreset(preset) {
3783
4566
  */
3784
4567
  function validateCustomTheme(theme) {
3785
4568
  try {
3786
- // Check required properties
3787
- if (!theme.mode || !['dark', 'light', 'auto'].includes(theme.mode)) {
4569
+ // Only validate what's provided - everything else gets defaults
4570
+ if (theme.mode && !['dark', 'light', 'auto'].includes(theme.mode)) {
3788
4571
  return false;
3789
4572
  }
3790
- if (!theme.colors) {
3791
- return false;
4573
+ // If colors are provided, validate the structure
4574
+ if (theme.colors) {
4575
+ // Check that any provided color sections have valid structure
4576
+ const colorSections = ['background', 'status', 'text', 'border', 'input', 'button'];
4577
+ for (const section of colorSections) {
4578
+ const colorSection = theme.colors[section];
4579
+ if (colorSection && typeof colorSection !== 'object') {
4580
+ return false;
4581
+ }
4582
+ }
3792
4583
  }
3793
- // Check required color sections
3794
- const requiredSections = ['background', 'status', 'text', 'border', 'input', 'button'];
3795
- for (const section of requiredSections) {
3796
- if (!theme.colors[section]) {
4584
+ // If typography is provided, validate structure
4585
+ if (theme.typography) {
4586
+ if (theme.typography.fontSize && typeof theme.typography.fontSize !== 'object') {
4587
+ return false;
4588
+ }
4589
+ if (theme.typography.fontWeight && typeof theme.typography.fontWeight !== 'object') {
4590
+ return false;
4591
+ }
4592
+ }
4593
+ // If effects are provided, validate structure
4594
+ if (theme.effects) {
4595
+ if (theme.effects.animations && typeof theme.effects.animations !== 'object') {
4596
+ return false;
4597
+ }
4598
+ if (theme.effects.shadows && typeof theme.effects.shadows !== 'object') {
3797
4599
  return false;
3798
4600
  }
3799
4601
  }
@@ -3825,12 +4627,14 @@ function createCustomThemeFromPreset(preset, modifications) {
3825
4627
  /**
3826
4628
  * Broker filtering utility functions
3827
4629
  */
3828
- // Supported broker names and their corresponding IDs
4630
+ // Supported broker names and their corresponding IDs (including aliases)
3829
4631
  const SUPPORTED_BROKERS = {
3830
4632
  'alpaca': 'alpaca',
3831
4633
  'robinhood': 'robinhood',
3832
4634
  'tasty_trade': 'tasty_trade',
3833
- 'ninja_trader': 'ninja_trader'
4635
+ 'ninja_trader': 'ninja_trader',
4636
+ 'tradovate': 'tradovate', // Alias for ninja_trader
4637
+ 'interactive_brokers': 'interactive_brokers',
3834
4638
  };
3835
4639
  /**
3836
4640
  * Convert broker names to broker IDs, filtering out unsupported ones
@@ -3970,6 +4774,13 @@ class FinaticConnect extends EventEmitter {
3970
4774
  this.userToken?.refreshToken &&
3971
4775
  this.userToken?.user_id);
3972
4776
  }
4777
+ /**
4778
+ * Check if the client is authenticated (alias for isAuthed for consistency)
4779
+ * @returns True if authenticated, false otherwise
4780
+ */
4781
+ is_authenticated() {
4782
+ return this.isAuthed();
4783
+ }
3973
4784
  /**
3974
4785
  * Get user's orders with pagination and optional filtering
3975
4786
  * @param params - Query parameters including page, perPage, and filters
@@ -4013,20 +4824,18 @@ class FinaticConnect extends EventEmitter {
4013
4824
  return this.getAccountsPage(page, perPage, filter);
4014
4825
  }
4015
4826
  /**
4016
- * Revoke the current user's access
4827
+ * Get user's balances with pagination and optional filtering
4828
+ * @param params - Query parameters including page, perPage, and filters
4829
+ * @returns Promise with paginated result that supports navigation
4017
4830
  */
4018
- async revokeToken() {
4019
- if (!this.userToken) {
4020
- return;
4021
- }
4022
- try {
4023
- await this.apiClient.revokeToken(this.userToken.accessToken);
4024
- this.userToken = null;
4025
- }
4026
- catch (error) {
4027
- this.emit('error', error);
4028
- throw error;
4831
+ async getBalances(params) {
4832
+ if (!this.isAuthed()) {
4833
+ throw new AuthenticationError('User is not authenticated');
4029
4834
  }
4835
+ const page = params?.page || 1;
4836
+ const perPage = params?.perPage || 100;
4837
+ const filter = params?.filter;
4838
+ return this.getBalancesPage(page, perPage, filter);
4030
4839
  }
4031
4840
  /**
4032
4841
  * Initialize the Finatic Connect SDK
@@ -4115,9 +4924,33 @@ class FinaticConnect extends EventEmitter {
4115
4924
  async setUserId(userId) {
4116
4925
  await this.initializeWithUser(userId);
4117
4926
  }
4927
+ /**
4928
+ * Get the user and tokens for a completed session
4929
+ * @returns Promise with user information and tokens
4930
+ */
4931
+ async getSessionUser() {
4932
+ if (!this.isAuthed()) {
4933
+ throw new AuthenticationError('User is not authenticated');
4934
+ }
4935
+ if (!this.userToken) {
4936
+ throw new AuthenticationError('No user token available');
4937
+ }
4938
+ return {
4939
+ user_id: this.userToken.userId,
4940
+ access_token: this.userToken.accessToken,
4941
+ refresh_token: this.userToken.refreshToken,
4942
+ expires_in: this.userToken.expiresIn,
4943
+ token_type: this.userToken.tokenType,
4944
+ scope: this.userToken.scope,
4945
+ company_id: this.companyId
4946
+ };
4947
+ }
4118
4948
  async initializeWithUser(userId) {
4119
4949
  try {
4120
- this.userToken = await this.apiClient.getUserToken(userId);
4950
+ if (!this.sessionId) {
4951
+ throw new SessionError('Session not initialized');
4952
+ }
4953
+ this.userToken = await this.apiClient.getUserToken(this.sessionId);
4121
4954
  // Set tokens in ApiClient for automatic token management
4122
4955
  if (this.userToken) {
4123
4956
  const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
@@ -4161,20 +4994,8 @@ class FinaticConnect extends EventEmitter {
4161
4994
  this.apiClient.setSessionContext(this.sessionId, this.companyId, startResponse.data.csrf_token // If available in response
4162
4995
  );
4163
4996
  }
4164
- // Wait for session to become active
4165
- const maxAttempts = 5;
4166
- let attempts = 0;
4167
- while (attempts < maxAttempts) {
4168
- const sessionResponse = await this.apiClient.validatePortalSession(this.sessionId, '');
4169
- if (sessionResponse.status === 'active') {
4170
- break;
4171
- }
4172
- await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second between attempts
4173
- attempts++;
4174
- }
4175
- if (attempts === maxAttempts) {
4176
- throw new SessionError('Session failed to become active');
4177
- }
4997
+ // Session is now active
4998
+ this.currentSessionState = SessionState.ACTIVE;
4178
4999
  }
4179
5000
  // Get portal URL
4180
5001
  const portalResponse = await this.apiClient.getPortalUrl(this.sessionId);
@@ -4185,6 +5006,12 @@ class FinaticConnect extends EventEmitter {
4185
5006
  let themedPortalUrl = appendThemeToURL(portalResponse.data.portal_url, options?.theme);
4186
5007
  // Apply broker filter to portal URL if provided
4187
5008
  themedPortalUrl = appendBrokerFilterToURL(themedPortalUrl, options?.brokers);
5009
+ // Apply email parameter to portal URL if provided
5010
+ if (options?.email) {
5011
+ const url = new URL(themedPortalUrl);
5012
+ url.searchParams.set('email', options.email);
5013
+ themedPortalUrl = url.toString();
5014
+ }
4188
5015
  // Create portal UI if not exists
4189
5016
  if (!this.portalUI) {
4190
5017
  this.portalUI = new PortalUI(this.baseUrl);
@@ -4280,21 +5107,8 @@ class FinaticConnect extends EventEmitter {
4280
5107
  }
4281
5108
  // For non-direct auth, we need to wait for the session to be ACTIVE
4282
5109
  if (response.data.state === SessionState.PENDING) {
4283
- // Wait for session to become active
4284
- const maxAttempts = 5;
4285
- let attempts = 0;
4286
- while (attempts < maxAttempts) {
4287
- const sessionResponse = await this.apiClient.validatePortalSession(this.sessionId, '');
4288
- if (sessionResponse.status === 'active') {
4289
- this.currentSessionState = SessionState.ACTIVE;
4290
- break;
4291
- }
4292
- await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second between attempts
4293
- attempts++;
4294
- }
4295
- if (attempts === maxAttempts) {
4296
- throw new SessionError('Session failed to become active');
4297
- }
5110
+ // Session is now active
5111
+ this.currentSessionState = SessionState.ACTIVE;
4298
5112
  }
4299
5113
  }
4300
5114
  catch (error) {
@@ -4452,6 +5266,138 @@ class FinaticConnect extends EventEmitter {
4452
5266
  throw error;
4453
5267
  }
4454
5268
  }
5269
+ /**
5270
+ * Place a stock stop order (convenience method)
5271
+ */
5272
+ async placeStockStopOrder(symbol, quantity, side, stopPrice, timeInForce = 'gtc', broker, accountNumber) {
5273
+ if (!this.userToken) {
5274
+ throw new Error('Not initialized with user');
5275
+ }
5276
+ try {
5277
+ return await this.apiClient.placeStockStopOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', stopPrice, timeInForce, broker, accountNumber);
5278
+ }
5279
+ catch (error) {
5280
+ this.emit('error', error);
5281
+ throw error;
5282
+ }
5283
+ }
5284
+ /**
5285
+ * Place a crypto market order (convenience method)
5286
+ */
5287
+ async placeCryptoMarketOrder(symbol, quantity, side, broker, accountNumber) {
5288
+ if (!this.userToken) {
5289
+ throw new Error('Not initialized with user');
5290
+ }
5291
+ try {
5292
+ return await this.apiClient.placeCryptoMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
5293
+ }
5294
+ catch (error) {
5295
+ this.emit('error', error);
5296
+ throw error;
5297
+ }
5298
+ }
5299
+ /**
5300
+ * Place a crypto limit order (convenience method)
5301
+ */
5302
+ async placeCryptoLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
5303
+ if (!this.userToken) {
5304
+ throw new Error('Not initialized with user');
5305
+ }
5306
+ try {
5307
+ return await this.apiClient.placeCryptoLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
5308
+ }
5309
+ catch (error) {
5310
+ this.emit('error', error);
5311
+ throw error;
5312
+ }
5313
+ }
5314
+ /**
5315
+ * Place an options market order (convenience method)
5316
+ */
5317
+ async placeOptionsMarketOrder(symbol, quantity, side, broker, accountNumber) {
5318
+ if (!this.userToken) {
5319
+ throw new Error('Not initialized with user');
5320
+ }
5321
+ try {
5322
+ return await this.apiClient.placeOptionsMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
5323
+ }
5324
+ catch (error) {
5325
+ this.emit('error', error);
5326
+ throw error;
5327
+ }
5328
+ }
5329
+ /**
5330
+ * Place an options limit order (convenience method)
5331
+ */
5332
+ async placeOptionsLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
5333
+ if (!this.userToken) {
5334
+ throw new Error('Not initialized with user');
5335
+ }
5336
+ try {
5337
+ return await this.apiClient.placeOptionsLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
5338
+ }
5339
+ catch (error) {
5340
+ this.emit('error', error);
5341
+ throw error;
5342
+ }
5343
+ }
5344
+ /**
5345
+ * Place a futures market order (convenience method)
5346
+ */
5347
+ async placeFuturesMarketOrder(symbol, quantity, side, broker, accountNumber) {
5348
+ if (!this.userToken) {
5349
+ throw new Error('Not initialized with user');
5350
+ }
5351
+ try {
5352
+ return await this.apiClient.placeFuturesMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
5353
+ }
5354
+ catch (error) {
5355
+ this.emit('error', error);
5356
+ throw error;
5357
+ }
5358
+ }
5359
+ /**
5360
+ * Place a futures limit order (convenience method)
5361
+ */
5362
+ async placeFuturesLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
5363
+ if (!this.userToken) {
5364
+ throw new Error('Not initialized with user');
5365
+ }
5366
+ try {
5367
+ return await this.apiClient.placeFuturesLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
5368
+ }
5369
+ catch (error) {
5370
+ this.emit('error', error);
5371
+ throw error;
5372
+ }
5373
+ }
5374
+ /**
5375
+ * Set the broker context for trading operations
5376
+ * @param broker - The broker to set as context
5377
+ */
5378
+ setBroker(broker) {
5379
+ this.apiClient.setBroker(broker);
5380
+ }
5381
+ /**
5382
+ * Set the account context for trading operations
5383
+ * @param accountNumber - The account number to set as context
5384
+ */
5385
+ setAccount(accountNumber) {
5386
+ this.apiClient.setAccount(accountNumber);
5387
+ }
5388
+ /**
5389
+ * Get the current trading context
5390
+ * @returns Object with current broker and account context
5391
+ */
5392
+ getTradingContext() {
5393
+ return this.apiClient.getTradingContext();
5394
+ }
5395
+ /**
5396
+ * Clear the trading context
5397
+ */
5398
+ clearTradingContext() {
5399
+ this.apiClient.clearTradingContext();
5400
+ }
4455
5401
  /**
4456
5402
  * Get the current user ID
4457
5403
  * @returns The current user ID or undefined if not authenticated
@@ -4601,6 +5547,12 @@ class FinaticConnect extends EventEmitter {
4601
5547
  }
4602
5548
  return this.apiClient.getBrokerAccountsPage(page, perPage, filter);
4603
5549
  }
5550
+ async getBalancesPage(page = 1, perPage = 100, filter) {
5551
+ if (!this.isAuthed()) {
5552
+ throw new AuthenticationError('User is not authenticated');
5553
+ }
5554
+ return this.apiClient.getBrokerBalancesPage(page, perPage, filter);
5555
+ }
4604
5556
  /**
4605
5557
  * Get the next page of orders
4606
5558
  * @param previousResult - The previous paginated result
@@ -4643,6 +5595,15 @@ class FinaticConnect extends EventEmitter {
4643
5595
  return this.apiClient.getBrokerAccountsPage(page, limit);
4644
5596
  });
4645
5597
  }
5598
+ async getNextBalancesPage(previousResult) {
5599
+ if (!this.isAuthed()) {
5600
+ throw new AuthenticationError('User is not authenticated');
5601
+ }
5602
+ return this.apiClient.getNextPage(previousResult, (offset, limit) => {
5603
+ const page = Math.floor(offset / limit) + 1;
5604
+ return this.apiClient.getBrokerBalancesPage(page, limit);
5605
+ });
5606
+ }
4646
5607
  /**
4647
5608
  * Get all orders across all pages (convenience method)
4648
5609
  * @param filter - Optional filter parameters
@@ -4709,6 +5670,23 @@ class FinaticConnect extends EventEmitter {
4709
5670
  }
4710
5671
  return allData;
4711
5672
  }
5673
+ async getAllBalances(filter) {
5674
+ if (!this.isAuthed()) {
5675
+ throw new AuthenticationError('User is not authenticated');
5676
+ }
5677
+ const allData = [];
5678
+ let currentResult = await this.getBalancesPage(1, 100, filter);
5679
+ while (currentResult) {
5680
+ allData.push(...currentResult.data);
5681
+ if (!currentResult.hasNext)
5682
+ break;
5683
+ const nextResult = await this.getNextBalancesPage(currentResult);
5684
+ if (!nextResult)
5685
+ break;
5686
+ currentResult = nextResult;
5687
+ }
5688
+ return allData;
5689
+ }
4712
5690
  /**
4713
5691
  * Register session management (but don't auto-cleanup for 24-hour sessions)
4714
5692
  */
@@ -4758,20 +5736,9 @@ class FinaticConnect extends EventEmitter {
4758
5736
  await this.refreshSessionAutomatically();
4759
5737
  return;
4760
5738
  }
4761
- // Use a timeout to prevent hanging requests
4762
- const timeoutPromise = new Promise((_, reject) => {
4763
- setTimeout(() => reject(new Error('Session validation timeout')), this.SESSION_VALIDATION_TIMEOUT);
4764
- });
4765
- const validationPromise = this.apiClient.validatePortalSession(this.sessionId, '');
4766
- const response = await Promise.race([validationPromise, timeoutPromise]);
4767
- if (response && response.status === 'active') {
4768
- console.log('[FinaticConnect] Session keep-alive successful');
4769
- this.currentSessionState = 'active';
4770
- }
4771
- else {
4772
- console.warn('[FinaticConnect] Session keep-alive failed - session not active');
4773
- this.currentSessionState = response?.status || 'unknown';
4774
- }
5739
+ // Session keep-alive - assume session is active if we have a session ID
5740
+ console.log('[FinaticConnect] Session keep-alive successful');
5741
+ this.currentSessionState = 'active';
4775
5742
  }
4776
5743
  catch (error) {
4777
5744
  console.warn('[FinaticConnect] Session keep-alive error:', error);
@@ -4900,6 +5867,24 @@ class FinaticConnect extends EventEmitter {
4900
5867
  }
4901
5868
  return this.apiClient.disconnectCompany(connectionId);
4902
5869
  }
5870
+ /**
5871
+ * Get account balances for the authenticated user
5872
+ * @param filters - Optional filters for balances
5873
+ * @returns Promise with balance data
5874
+ */
5875
+ async getBalances(filters) {
5876
+ if (!this.isAuthed()) {
5877
+ throw new AuthenticationError('User is not authenticated');
5878
+ }
5879
+ try {
5880
+ const response = await this.apiClient.getBalances(filters);
5881
+ return response.response_data || [];
5882
+ }
5883
+ catch (error) {
5884
+ this.emit('error', error);
5885
+ throw error;
5886
+ }
5887
+ }
4903
5888
  }
4904
5889
  FinaticConnect.instance = null;
4905
5890