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