@finatic/client 0.0.140 → 0.0.142
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -0
- package/dist/index.d.ts +256 -2
- package/dist/index.js +767 -94
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +764 -95
- package/dist/index.mjs.map +1 -1
- package/dist/types/core/client/ApiClient.d.ts +71 -1
- package/dist/types/core/client/FinaticConnect.d.ts +35 -0
- package/dist/types/core/portal/PortalUI.d.ts +2 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/lib/logger/index.d.ts +2 -0
- package/dist/types/lib/logger/logger.d.ts +4 -0
- package/dist/types/lib/logger/logger.types.d.ts +28 -0
- package/dist/types/mocks/MockApiClient.d.ts +2 -0
- package/dist/types/types/api/broker.d.ts +116 -0
- package/package.json +1 -1
- package/src/core/client/ApiClient.ts +302 -19
- package/src/core/client/FinaticConnect.ts +160 -30
- package/src/core/portal/PortalUI.ts +58 -23
- package/src/index.ts +13 -0
- package/src/lib/logger/index.ts +3 -0
- package/src/lib/logger/logger.ts +332 -0
- package/src/lib/logger/logger.types.ts +34 -0
- package/src/mocks/MockApiClient.ts +43 -17
- package/src/types/api/broker.ts +131 -0
- package/src/types/common/pagination.ts +31 -5
- package/src/utils/brokerUtils.ts +21 -2
- package/src/utils/events.ts +13 -1
- package/src/utils/themeUtils.ts +23 -4
|
@@ -16,11 +16,22 @@ import {
|
|
|
16
16
|
PositionsFilter,
|
|
17
17
|
AccountsFilter,
|
|
18
18
|
BalancesFilter,
|
|
19
|
+
OrderFill,
|
|
20
|
+
OrderEvent,
|
|
21
|
+
OrderGroup,
|
|
22
|
+
PositionLot,
|
|
23
|
+
PositionLotFill,
|
|
24
|
+
OrderFillsFilter,
|
|
25
|
+
OrderEventsFilter,
|
|
26
|
+
OrderGroupsFilter,
|
|
27
|
+
PositionLotsFilter,
|
|
28
|
+
PositionLotFillsFilter,
|
|
19
29
|
} from '../../types/api/broker';
|
|
20
30
|
import { TradingContext } from '../../types/api/orders';
|
|
21
31
|
import { ApiPaginationInfo, PaginatedResult } from '../../types/common/pagination';
|
|
22
32
|
import { ApiResponse } from '../../types/api/core';
|
|
23
33
|
import { PortalUrlResponse } from '../../types/api/core';
|
|
34
|
+
import { setupLogger, buildLoggerExtra, LoggerExtra } from '../../lib/logger';
|
|
24
35
|
import {
|
|
25
36
|
DeviceInfo,
|
|
26
37
|
SessionState,
|
|
@@ -60,6 +71,17 @@ export class ApiClient {
|
|
|
60
71
|
// Session and company context
|
|
61
72
|
private companyId: string | null = null;
|
|
62
73
|
private csrfToken: string | null = null;
|
|
74
|
+
private readonly logger = setupLogger('FinaticClientSDK.ApiClient', undefined, {
|
|
75
|
+
codebase: 'FinaticClientSDK',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
private buildLoggerExtra(functionName: string, metadata?: Record<string, unknown>): LoggerExtra {
|
|
79
|
+
return {
|
|
80
|
+
module: 'ApiClient',
|
|
81
|
+
function: functionName,
|
|
82
|
+
...(metadata ? buildLoggerExtra(metadata) : {}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
63
85
|
|
|
64
86
|
constructor(baseUrl: string, deviceInfo?: DeviceInfo) {
|
|
65
87
|
this.baseUrl = baseUrl;
|
|
@@ -213,15 +235,11 @@ export class ApiClient {
|
|
|
213
235
|
}
|
|
214
236
|
});
|
|
215
237
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
console.log('Session ID:', this.currentSessionId);
|
|
222
|
-
console.log('Company ID:', this.companyId);
|
|
223
|
-
console.log('CSRF Token:', this.csrfToken);
|
|
224
|
-
}
|
|
238
|
+
this.logger.debug('Dispatching API request', this.buildLoggerExtra('request', {
|
|
239
|
+
url: url.toString(),
|
|
240
|
+
method: options.method,
|
|
241
|
+
has_body: Boolean(options.body),
|
|
242
|
+
}));
|
|
225
243
|
|
|
226
244
|
const response = await fetch(url.toString(), {
|
|
227
245
|
method: options.method,
|
|
@@ -229,16 +247,19 @@ export class ApiClient {
|
|
|
229
247
|
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
230
248
|
});
|
|
231
249
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
console.log('Request was made with headers:', safariSafeHeaders);
|
|
237
|
-
}
|
|
250
|
+
this.logger.debug('Received API response', this.buildLoggerExtra('request', {
|
|
251
|
+
url: url.toString(),
|
|
252
|
+
status: response.status,
|
|
253
|
+
}));
|
|
238
254
|
|
|
239
255
|
if (!response.ok) {
|
|
240
256
|
const error = await response.json();
|
|
241
|
-
|
|
257
|
+
const apiError = this.handleError(response.status, error);
|
|
258
|
+
this.logger.exception('API request failed', apiError, this.buildLoggerExtra('request', {
|
|
259
|
+
url: url.toString(),
|
|
260
|
+
status: response.status,
|
|
261
|
+
}));
|
|
262
|
+
throw apiError;
|
|
242
263
|
}
|
|
243
264
|
|
|
244
265
|
const data = await response.json();
|
|
@@ -251,12 +272,22 @@ export class ApiClient {
|
|
|
251
272
|
// Add context that this is an order-related error
|
|
252
273
|
data._isOrderError = true;
|
|
253
274
|
}
|
|
254
|
-
|
|
275
|
+
const apiError = this.handleError(data.status_code || 500, data);
|
|
276
|
+
this.logger.exception('API response indicated failure', apiError, this.buildLoggerExtra('request', {
|
|
277
|
+
url: url.toString(),
|
|
278
|
+
status: data.status_code || 500,
|
|
279
|
+
}));
|
|
280
|
+
throw apiError;
|
|
255
281
|
}
|
|
256
282
|
|
|
257
283
|
// Check if the response has a status_code field indicating an error (4xx or 5xx)
|
|
258
284
|
if (data && typeof data === 'object' && 'status_code' in data && data.status_code >= 400) {
|
|
259
|
-
|
|
285
|
+
const apiError = this.handleError(data.status_code, data);
|
|
286
|
+
this.logger.exception('API status code error', apiError, this.buildLoggerExtra('request', {
|
|
287
|
+
url: url.toString(),
|
|
288
|
+
status: data.status_code,
|
|
289
|
+
}));
|
|
290
|
+
throw apiError;
|
|
260
291
|
}
|
|
261
292
|
|
|
262
293
|
// Check if the response has errors field with content
|
|
@@ -268,7 +299,12 @@ export class ApiClient {
|
|
|
268
299
|
Array.isArray(data.errors) &&
|
|
269
300
|
data.errors.length > 0
|
|
270
301
|
) {
|
|
271
|
-
|
|
302
|
+
const apiError = this.handleError(data.status_code || 500, data);
|
|
303
|
+
this.logger.exception('API response contained errors', apiError, this.buildLoggerExtra('request', {
|
|
304
|
+
url: url.toString(),
|
|
305
|
+
status: data.status_code || 500,
|
|
306
|
+
}));
|
|
307
|
+
throw apiError;
|
|
272
308
|
}
|
|
273
309
|
|
|
274
310
|
return data;
|
|
@@ -1718,4 +1754,251 @@ export class ApiClient {
|
|
|
1718
1754
|
},
|
|
1719
1755
|
});
|
|
1720
1756
|
}
|
|
1757
|
+
|
|
1758
|
+
/**
|
|
1759
|
+
* Get order fills for a specific order
|
|
1760
|
+
* @param orderId - The order ID
|
|
1761
|
+
* @param filter - Optional filter parameters
|
|
1762
|
+
* @returns Promise with order fills response
|
|
1763
|
+
*/
|
|
1764
|
+
async getOrderFills(
|
|
1765
|
+
orderId: string,
|
|
1766
|
+
filter?: OrderFillsFilter
|
|
1767
|
+
): Promise<{
|
|
1768
|
+
_id: string;
|
|
1769
|
+
response_data: OrderFill[];
|
|
1770
|
+
message: string;
|
|
1771
|
+
status_code: number;
|
|
1772
|
+
warnings: null;
|
|
1773
|
+
errors: null;
|
|
1774
|
+
}> {
|
|
1775
|
+
const accessToken = await this.getValidAccessToken();
|
|
1776
|
+
const params: Record<string, string> = {};
|
|
1777
|
+
|
|
1778
|
+
if (filter?.connection_id) {
|
|
1779
|
+
params.connection_id = filter.connection_id;
|
|
1780
|
+
}
|
|
1781
|
+
if (filter?.limit) {
|
|
1782
|
+
params.limit = filter.limit.toString();
|
|
1783
|
+
}
|
|
1784
|
+
if (filter?.offset) {
|
|
1785
|
+
params.offset = filter.offset.toString();
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
return this.request<{
|
|
1789
|
+
_id: string;
|
|
1790
|
+
response_data: OrderFill[];
|
|
1791
|
+
message: string;
|
|
1792
|
+
status_code: number;
|
|
1793
|
+
warnings: null;
|
|
1794
|
+
errors: null;
|
|
1795
|
+
}>(`/brokers/data/orders/${orderId}/fills`, {
|
|
1796
|
+
method: 'GET',
|
|
1797
|
+
headers: {
|
|
1798
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1799
|
+
},
|
|
1800
|
+
params,
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
/**
|
|
1805
|
+
* Get order events for a specific order
|
|
1806
|
+
* @param orderId - The order ID
|
|
1807
|
+
* @param filter - Optional filter parameters
|
|
1808
|
+
* @returns Promise with order events response
|
|
1809
|
+
*/
|
|
1810
|
+
async getOrderEvents(
|
|
1811
|
+
orderId: string,
|
|
1812
|
+
filter?: OrderEventsFilter
|
|
1813
|
+
): Promise<{
|
|
1814
|
+
_id: string;
|
|
1815
|
+
response_data: OrderEvent[];
|
|
1816
|
+
message: string;
|
|
1817
|
+
status_code: number;
|
|
1818
|
+
warnings: null;
|
|
1819
|
+
errors: null;
|
|
1820
|
+
}> {
|
|
1821
|
+
const accessToken = await this.getValidAccessToken();
|
|
1822
|
+
const params: Record<string, string> = {};
|
|
1823
|
+
|
|
1824
|
+
if (filter?.connection_id) {
|
|
1825
|
+
params.connection_id = filter.connection_id;
|
|
1826
|
+
}
|
|
1827
|
+
if (filter?.limit) {
|
|
1828
|
+
params.limit = filter.limit.toString();
|
|
1829
|
+
}
|
|
1830
|
+
if (filter?.offset) {
|
|
1831
|
+
params.offset = filter.offset.toString();
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
return this.request<{
|
|
1835
|
+
_id: string;
|
|
1836
|
+
response_data: OrderEvent[];
|
|
1837
|
+
message: string;
|
|
1838
|
+
status_code: number;
|
|
1839
|
+
warnings: null;
|
|
1840
|
+
errors: null;
|
|
1841
|
+
}>(`/brokers/data/orders/${orderId}/events`, {
|
|
1842
|
+
method: 'GET',
|
|
1843
|
+
headers: {
|
|
1844
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1845
|
+
},
|
|
1846
|
+
params,
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
/**
|
|
1851
|
+
* Get order groups
|
|
1852
|
+
* @param filter - Optional filter parameters
|
|
1853
|
+
* @returns Promise with order groups response
|
|
1854
|
+
*/
|
|
1855
|
+
async getOrderGroups(
|
|
1856
|
+
filter?: OrderGroupsFilter
|
|
1857
|
+
): Promise<{
|
|
1858
|
+
_id: string;
|
|
1859
|
+
response_data: OrderGroup[];
|
|
1860
|
+
message: string;
|
|
1861
|
+
status_code: number;
|
|
1862
|
+
warnings: null;
|
|
1863
|
+
errors: null;
|
|
1864
|
+
}> {
|
|
1865
|
+
const accessToken = await this.getValidAccessToken();
|
|
1866
|
+
const params: Record<string, string> = {};
|
|
1867
|
+
|
|
1868
|
+
if (filter?.broker_id) {
|
|
1869
|
+
params.broker_id = filter.broker_id;
|
|
1870
|
+
}
|
|
1871
|
+
if (filter?.connection_id) {
|
|
1872
|
+
params.connection_id = filter.connection_id;
|
|
1873
|
+
}
|
|
1874
|
+
if (filter?.limit) {
|
|
1875
|
+
params.limit = filter.limit.toString();
|
|
1876
|
+
}
|
|
1877
|
+
if (filter?.offset) {
|
|
1878
|
+
params.offset = filter.offset.toString();
|
|
1879
|
+
}
|
|
1880
|
+
if (filter?.created_after) {
|
|
1881
|
+
params.created_after = filter.created_after;
|
|
1882
|
+
}
|
|
1883
|
+
if (filter?.created_before) {
|
|
1884
|
+
params.created_before = filter.created_before;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
return this.request<{
|
|
1888
|
+
_id: string;
|
|
1889
|
+
response_data: OrderGroup[];
|
|
1890
|
+
message: string;
|
|
1891
|
+
status_code: number;
|
|
1892
|
+
warnings: null;
|
|
1893
|
+
errors: null;
|
|
1894
|
+
}>('/brokers/data/orders/groups', {
|
|
1895
|
+
method: 'GET',
|
|
1896
|
+
headers: {
|
|
1897
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1898
|
+
},
|
|
1899
|
+
params,
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
/**
|
|
1904
|
+
* Get position lots (tax lots for positions)
|
|
1905
|
+
* @param filter - Optional filter parameters
|
|
1906
|
+
* @returns Promise with position lots response
|
|
1907
|
+
*/
|
|
1908
|
+
async getPositionLots(
|
|
1909
|
+
filter?: PositionLotsFilter
|
|
1910
|
+
): Promise<{
|
|
1911
|
+
_id: string;
|
|
1912
|
+
response_data: PositionLot[];
|
|
1913
|
+
message: string;
|
|
1914
|
+
status_code: number;
|
|
1915
|
+
warnings: null;
|
|
1916
|
+
errors: null;
|
|
1917
|
+
}> {
|
|
1918
|
+
const accessToken = await this.getValidAccessToken();
|
|
1919
|
+
const params: Record<string, string> = {};
|
|
1920
|
+
|
|
1921
|
+
if (filter?.broker_id) {
|
|
1922
|
+
params.broker_id = filter.broker_id;
|
|
1923
|
+
}
|
|
1924
|
+
if (filter?.connection_id) {
|
|
1925
|
+
params.connection_id = filter.connection_id;
|
|
1926
|
+
}
|
|
1927
|
+
if (filter?.account_id) {
|
|
1928
|
+
params.account_id = filter.account_id;
|
|
1929
|
+
}
|
|
1930
|
+
if (filter?.symbol) {
|
|
1931
|
+
params.symbol = filter.symbol;
|
|
1932
|
+
}
|
|
1933
|
+
if (filter?.position_id) {
|
|
1934
|
+
params.position_id = filter.position_id;
|
|
1935
|
+
}
|
|
1936
|
+
if (filter?.limit) {
|
|
1937
|
+
params.limit = filter.limit.toString();
|
|
1938
|
+
}
|
|
1939
|
+
if (filter?.offset) {
|
|
1940
|
+
params.offset = filter.offset.toString();
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
return this.request<{
|
|
1944
|
+
_id: string;
|
|
1945
|
+
response_data: PositionLot[];
|
|
1946
|
+
message: string;
|
|
1947
|
+
status_code: number;
|
|
1948
|
+
warnings: null;
|
|
1949
|
+
errors: null;
|
|
1950
|
+
}>('/brokers/data/positions/lots', {
|
|
1951
|
+
method: 'GET',
|
|
1952
|
+
headers: {
|
|
1953
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1954
|
+
},
|
|
1955
|
+
params,
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
/**
|
|
1960
|
+
* Get position lot fills for a specific lot
|
|
1961
|
+
* @param lotId - The position lot ID
|
|
1962
|
+
* @param filter - Optional filter parameters
|
|
1963
|
+
* @returns Promise with position lot fills response
|
|
1964
|
+
*/
|
|
1965
|
+
async getPositionLotFills(
|
|
1966
|
+
lotId: string,
|
|
1967
|
+
filter?: PositionLotFillsFilter
|
|
1968
|
+
): Promise<{
|
|
1969
|
+
_id: string;
|
|
1970
|
+
response_data: PositionLotFill[];
|
|
1971
|
+
message: string;
|
|
1972
|
+
status_code: number;
|
|
1973
|
+
warnings: null;
|
|
1974
|
+
errors: null;
|
|
1975
|
+
}> {
|
|
1976
|
+
const accessToken = await this.getValidAccessToken();
|
|
1977
|
+
const params: Record<string, string> = {};
|
|
1978
|
+
|
|
1979
|
+
if (filter?.connection_id) {
|
|
1980
|
+
params.connection_id = filter.connection_id;
|
|
1981
|
+
}
|
|
1982
|
+
if (filter?.limit) {
|
|
1983
|
+
params.limit = filter.limit.toString();
|
|
1984
|
+
}
|
|
1985
|
+
if (filter?.offset) {
|
|
1986
|
+
params.offset = filter.offset.toString();
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
return this.request<{
|
|
1990
|
+
_id: string;
|
|
1991
|
+
response_data: PositionLotFill[];
|
|
1992
|
+
message: string;
|
|
1993
|
+
status_code: number;
|
|
1994
|
+
warnings: null;
|
|
1995
|
+
errors: null;
|
|
1996
|
+
}>(`/brokers/data/positions/lots/${lotId}/fills`, {
|
|
1997
|
+
method: 'GET',
|
|
1998
|
+
headers: {
|
|
1999
|
+
Authorization: `Bearer ${accessToken}`,
|
|
2000
|
+
},
|
|
2001
|
+
params,
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
1721
2004
|
}
|