@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/dist/index.js CHANGED
@@ -2,9 +2,287 @@
2
2
 
3
3
  var uuid = require('uuid');
4
4
 
5
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
6
+ const LOG_LEVEL_ORDER = {
7
+ error: 0,
8
+ warn: 1,
9
+ info: 2,
10
+ debug: 3,
11
+ };
12
+ const LEVEL_TO_CONSOLE = {
13
+ error: 'error',
14
+ warn: 'warn',
15
+ info: 'info',
16
+ debug: 'debug',
17
+ };
18
+ const DEFAULT_LOGGER_NAME = 'FinaticLogger';
19
+ const parseLogLevel = (value, fallback) => {
20
+ if (typeof value !== 'string') {
21
+ return fallback;
22
+ }
23
+ const normalized = value.toLowerCase().trim();
24
+ if (normalized === 'silent' || normalized === 'error' || normalized === 'warn' || normalized === 'info' || normalized === 'debug') {
25
+ return normalized;
26
+ }
27
+ return fallback;
28
+ };
29
+ const parseVerbosity = (value, fallback) => {
30
+ if (typeof value !== 'string' && typeof value !== 'number') {
31
+ return fallback;
32
+ }
33
+ const numeric = typeof value === 'number' ? value : Number.parseInt(value, 10);
34
+ if (Number.isNaN(numeric)) {
35
+ return fallback;
36
+ }
37
+ if (numeric <= 0) {
38
+ return 0;
39
+ }
40
+ if (numeric >= 3) {
41
+ return 3;
42
+ }
43
+ return numeric;
44
+ };
45
+ const resolveEnv = (key) => {
46
+ try {
47
+ if (typeof process !== 'undefined' && process.env && typeof process.env[key] === 'string') {
48
+ return process.env[key];
49
+ }
50
+ }
51
+ catch {
52
+ // ignore
53
+ }
54
+ try {
55
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
+ const metaEnv = typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)) }) !== 'undefined' ? undefined : undefined;
57
+ if (metaEnv && typeof metaEnv[key] === 'string') {
58
+ return metaEnv[key];
59
+ }
60
+ }
61
+ catch {
62
+ // ignore
63
+ }
64
+ try {
65
+ if (typeof globalThis !== 'undefined') {
66
+ const value = globalThis[key];
67
+ if (typeof value === 'string') {
68
+ return value;
69
+ }
70
+ }
71
+ }
72
+ catch {
73
+ // ignore
74
+ }
75
+ return undefined;
76
+ };
77
+ const resolveDefaultLogLevel = (explicitLevel) => {
78
+ if (explicitLevel) {
79
+ return explicitLevel;
80
+ }
81
+ const envLevel = resolveEnv('FINATIC_LOG_LEVEL') ||
82
+ resolveEnv('VITE_FINATIC_LOG_LEVEL') ||
83
+ resolveEnv('NEXT_PUBLIC_FINATIC_LOG_LEVEL') ||
84
+ resolveEnv('NEXT_FINATIC_LOG_LEVEL') ||
85
+ resolveEnv('REACT_APP_FINATIC_LOG_LEVEL') ||
86
+ resolveEnv('NUXT_PUBLIC_FINATIC_LOG_LEVEL') ||
87
+ resolveEnv('NX_FINATIC_LOG_LEVEL');
88
+ if (envLevel) {
89
+ return parseLogLevel(envLevel, 'silent');
90
+ }
91
+ return 'silent';
92
+ };
93
+ const resolveVerbosity = () => {
94
+ const envVerbosity = resolveEnv('FINATIC_LOG_VERBOSITY') ||
95
+ resolveEnv('VITE_FINATIC_LOG_VERBOSITY') ||
96
+ resolveEnv('NEXT_PUBLIC_FINATIC_LOG_VERBOSITY') ||
97
+ resolveEnv('NEXT_FINATIC_LOG_VERBOSITY') ||
98
+ resolveEnv('REACT_APP_FINATIC_LOG_VERBOSITY') ||
99
+ resolveEnv('NUXT_PUBLIC_FINATIC_LOG_VERBOSITY') ||
100
+ resolveEnv('NX_FINATIC_LOG_VERBOSITY');
101
+ if (envVerbosity) {
102
+ return parseVerbosity(envVerbosity, 1);
103
+ }
104
+ return 1;
105
+ };
106
+ const resolveBaseMetadata = () => {
107
+ const base = {
108
+ timestamp: new Date().toISOString(),
109
+ };
110
+ try {
111
+ if (typeof globalThis !== 'undefined') {
112
+ if (typeof globalThis.location !== 'undefined') {
113
+ base.host = globalThis.location.hostname;
114
+ }
115
+ if (typeof globalThis.navigator !== 'undefined') {
116
+ base.user_agent = globalThis.navigator.userAgent;
117
+ }
118
+ }
119
+ }
120
+ catch {
121
+ // ignore
122
+ }
123
+ try {
124
+ if (typeof process !== 'undefined') {
125
+ base.pid = process.pid;
126
+ }
127
+ }
128
+ catch {
129
+ // ignore
130
+ }
131
+ return base;
132
+ };
133
+ const normalizeError = (error) => {
134
+ if (!error) {
135
+ return undefined;
136
+ }
137
+ if (error instanceof Error) {
138
+ return {
139
+ type: error.name,
140
+ message: error.message,
141
+ stacktrace: error.stack,
142
+ };
143
+ }
144
+ if (typeof error === 'object') {
145
+ return { ...error };
146
+ }
147
+ return {
148
+ type: 'Error',
149
+ message: String(error),
150
+ };
151
+ };
152
+ const shouldLog = (requestedLevel, currentLevel) => {
153
+ if (currentLevel === 'silent') {
154
+ return false;
155
+ }
156
+ const currentOrder = LOG_LEVEL_ORDER[currentLevel];
157
+ const requestedOrder = LOG_LEVEL_ORDER[requestedLevel];
158
+ return requestedOrder <= currentOrder;
159
+ };
160
+ const buildPayload = (name, level, message, defaultMetadata, extra, verbosity) => {
161
+ const payload = {
162
+ timestamp: new Date().toISOString(),
163
+ message,
164
+ };
165
+ if (verbosity >= 1 && extra) {
166
+ if (extra.module) {
167
+ payload.module = extra.module;
168
+ }
169
+ if (extra.function) {
170
+ payload.function = extra.function;
171
+ }
172
+ }
173
+ if (verbosity >= 2) {
174
+ if (extra?.duration_ms !== undefined) {
175
+ payload.duration_ms = extra.duration_ms;
176
+ }
177
+ if (extra?.event) {
178
+ payload.event = extra.event;
179
+ }
180
+ if (extra?.error) {
181
+ payload.error = normalizeError(extra.error);
182
+ }
183
+ }
184
+ if (verbosity >= 3) {
185
+ payload.level = level.toUpperCase();
186
+ payload.name = name;
187
+ const baseMetadata = resolveBaseMetadata();
188
+ const mergedMetadata = {
189
+ ...baseMetadata,
190
+ ...(defaultMetadata || {}),
191
+ ...(extra?.metadata || {}),
192
+ };
193
+ if (Object.keys(mergedMetadata).length > 0) {
194
+ payload.metadata = mergedMetadata;
195
+ }
196
+ }
197
+ const restKeys = ['module', 'function', 'event', 'duration_ms', 'error', 'metadata'];
198
+ if (extra) {
199
+ Object.entries(extra).forEach(([key, value]) => {
200
+ if (!restKeys.includes(key) && value !== undefined) {
201
+ payload[key] = value;
202
+ }
203
+ });
204
+ }
205
+ return payload;
206
+ };
207
+ const consoleWrite = (consoleLevel, name, level, message, payload) => {
208
+ if (typeof console === 'undefined' || typeof console[consoleLevel] !== 'function') {
209
+ return;
210
+ }
211
+ const prefix = `${level.toUpperCase()}: ${name} || ${message}`;
212
+ console[consoleLevel](prefix, payload);
213
+ };
214
+ const setupLogger = (nameOrOptions, level, defaultMetadata) => {
215
+ const options = typeof nameOrOptions === 'string'
216
+ ? {
217
+ name: nameOrOptions,
218
+ level,
219
+ defaultMetadata,
220
+ }
221
+ : nameOrOptions;
222
+ const loggerName = options.name || DEFAULT_LOGGER_NAME;
223
+ let currentLevel = resolveDefaultLogLevel(options.level);
224
+ const loggerDefaultMetadata = options.defaultMetadata;
225
+ const verbosity = resolveVerbosity();
226
+ const log = (requestedLevel, message, extra) => {
227
+ if (!shouldLog(requestedLevel, currentLevel)) {
228
+ return;
229
+ }
230
+ const payload = buildPayload(loggerName, requestedLevel, message, loggerDefaultMetadata, extra, verbosity);
231
+ consoleWrite(LEVEL_TO_CONSOLE[requestedLevel], loggerName, requestedLevel, message, payload);
232
+ };
233
+ return {
234
+ getLevel: () => currentLevel,
235
+ setLevel: (nextLevel) => {
236
+ currentLevel = nextLevel;
237
+ },
238
+ debug: (message, extra) => log('debug', message, extra),
239
+ info: (message, extra) => log('info', message, extra),
240
+ warn: (message, extra) => log('warn', message, extra),
241
+ error: (message, extra) => log('error', message, extra),
242
+ exception: (message, error, extra) => {
243
+ log('error', message, {
244
+ ...extra,
245
+ error,
246
+ event: extra?.event || 'exception',
247
+ });
248
+ },
249
+ };
250
+ };
251
+ const buildLoggerExtra = (metadata) => ({
252
+ metadata,
253
+ });
254
+ const logStartEnd = (logger) => (fn) => async (...args) => {
255
+ const start = Date.now();
256
+ const functionName = fn.name || 'anonymous';
257
+ logger.debug('START', { module: 'logStartEnd', function: functionName, event: 'start' });
258
+ try {
259
+ const result = await fn(...args);
260
+ const duration = Date.now() - start;
261
+ logger.info('END', { module: 'logStartEnd', function: functionName, event: 'end', duration_ms: duration });
262
+ return result;
263
+ }
264
+ catch (error) {
265
+ const duration = Date.now() - start;
266
+ logger.exception('EXCEPTION', error, {
267
+ module: 'logStartEnd',
268
+ function: functionName,
269
+ duration_ms: duration,
270
+ });
271
+ throw error;
272
+ }
273
+ };
274
+
5
275
  /**
6
276
  * Pagination-related types and classes
7
277
  */
278
+ const paginationLogger = setupLogger('FinaticClientSDK.Pagination', undefined, {
279
+ codebase: 'FinaticClientSDK',
280
+ });
281
+ const buildPaginationExtra = (functionName, metadata) => ({
282
+ module: 'PaginatedResult',
283
+ function: functionName,
284
+ ...(metadata ? buildLoggerExtra(metadata) : {}),
285
+ });
8
286
  class PaginatedResult {
9
287
  constructor(data, paginationInfo, navigationCallback) {
10
288
  this.data = data;
@@ -36,7 +314,10 @@ class PaginatedResult {
36
314
  return await this.navigationCallback(this.metadata.nextOffset, this.metadata.limit);
37
315
  }
38
316
  catch (error) {
39
- console.error('Error fetching next page:', error);
317
+ paginationLogger.exception('Error fetching next page', error, buildPaginationExtra('nextPage', {
318
+ next_offset: this.metadata.nextOffset,
319
+ limit: this.metadata.limit,
320
+ }));
40
321
  return null;
41
322
  }
42
323
  }
@@ -49,7 +330,10 @@ class PaginatedResult {
49
330
  return await this.navigationCallback(previousOffset, this.metadata.limit);
50
331
  }
51
332
  catch (error) {
52
- console.error('Error fetching previous page:', error);
333
+ paginationLogger.exception('Error fetching previous page', error, buildPaginationExtra('previousPage', {
334
+ previous_offset: previousOffset,
335
+ limit: this.metadata.limit,
336
+ }));
53
337
  return null;
54
338
  }
55
339
  }
@@ -62,7 +346,11 @@ class PaginatedResult {
62
346
  return await this.navigationCallback(offset, this.metadata.limit);
63
347
  }
64
348
  catch (error) {
65
- console.error('Error fetching page:', pageNumber, error);
349
+ paginationLogger.exception('Error fetching page', error, buildPaginationExtra('goToPage', {
350
+ page_number: pageNumber,
351
+ offset,
352
+ limit: this.metadata.limit,
353
+ }));
66
354
  return null;
67
355
  }
68
356
  }
@@ -74,7 +362,9 @@ class PaginatedResult {
74
362
  return await this.navigationCallback(0, this.metadata.limit);
75
363
  }
76
364
  catch (error) {
77
- console.error('Error fetching first page:', error);
365
+ paginationLogger.exception('Error fetching first page', error, buildPaginationExtra('firstPage', {
366
+ limit: this.metadata.limit,
367
+ }));
78
368
  return null;
79
369
  }
80
370
  }
@@ -96,7 +386,9 @@ class PaginatedResult {
96
386
  return await findLast(this);
97
387
  }
98
388
  catch (error) {
99
- console.error('Error fetching last page:', error);
389
+ paginationLogger.exception('Error fetching last page', error, buildPaginationExtra('lastPage', {
390
+ limit: this.metadata.limit,
391
+ }));
100
392
  return null;
101
393
  }
102
394
  }
@@ -207,6 +499,13 @@ class TradingNotEnabledError extends ApiError {
207
499
 
208
500
  // Supabase import removed - SDK no longer depends on Supabase
209
501
  class ApiClient {
502
+ buildLoggerExtra(functionName, metadata) {
503
+ return {
504
+ module: 'ApiClient',
505
+ function: functionName,
506
+ ...(metadata ? buildLoggerExtra(metadata) : {}),
507
+ };
508
+ }
210
509
  constructor(baseUrl, deviceInfo) {
211
510
  this.currentSessionState = null;
212
511
  this.currentSessionId = null;
@@ -215,6 +514,9 @@ class ApiClient {
215
514
  // Session and company context
216
515
  this.companyId = null;
217
516
  this.csrfToken = null;
517
+ this.logger = setupLogger('FinaticClientSDK.ApiClient', undefined, {
518
+ codebase: 'FinaticClientSDK',
519
+ });
218
520
  this.baseUrl = baseUrl;
219
521
  this.deviceInfo = deviceInfo;
220
522
  // Ensure baseUrl doesn't end with a slash
@@ -335,29 +637,28 @@ class ApiClient {
335
637
  safariSafeHeaders[normalizedKey] = normalizedValue;
336
638
  }
337
639
  });
338
- // Debug logging for development
339
- if (typeof window !== 'undefined' && window.location.hostname === 'localhost') {
340
- console.log('Request to:', url.toString());
341
- console.log('Safari-safe headers:', safariSafeHeaders);
342
- console.log('Browser:', navigator.userAgent);
343
- console.log('Session ID:', this.currentSessionId);
344
- console.log('Company ID:', this.companyId);
345
- console.log('CSRF Token:', this.csrfToken);
346
- }
640
+ this.logger.debug('Dispatching API request', this.buildLoggerExtra('request', {
641
+ url: url.toString(),
642
+ method: options.method,
643
+ has_body: Boolean(options.body),
644
+ }));
347
645
  const response = await fetch(url.toString(), {
348
646
  method: options.method,
349
647
  headers: safariSafeHeaders,
350
648
  body: options.body ? JSON.stringify(options.body) : undefined,
351
649
  });
352
- // Debug logging for response
353
- if (typeof window !== 'undefined' && window.location.hostname === 'localhost') {
354
- console.log('Response status:', response.status);
355
- console.log('Response headers:', Object.fromEntries(response.headers.entries()));
356
- console.log('Request was made with headers:', safariSafeHeaders);
357
- }
650
+ this.logger.debug('Received API response', this.buildLoggerExtra('request', {
651
+ url: url.toString(),
652
+ status: response.status,
653
+ }));
358
654
  if (!response.ok) {
359
655
  const error = await response.json();
360
- throw this.handleError(response.status, error);
656
+ const apiError = this.handleError(response.status, error);
657
+ this.logger.exception('API request failed', apiError, this.buildLoggerExtra('request', {
658
+ url: url.toString(),
659
+ status: response.status,
660
+ }));
661
+ throw apiError;
361
662
  }
362
663
  const data = await response.json();
363
664
  // Check if the response has a success field and it's false
@@ -368,11 +669,21 @@ class ApiClient {
368
669
  // Add context that this is an order-related error
369
670
  data._isOrderError = true;
370
671
  }
371
- throw this.handleError(data.status_code || 500, data);
672
+ const apiError = this.handleError(data.status_code || 500, data);
673
+ this.logger.exception('API response indicated failure', apiError, this.buildLoggerExtra('request', {
674
+ url: url.toString(),
675
+ status: data.status_code || 500,
676
+ }));
677
+ throw apiError;
372
678
  }
373
679
  // Check if the response has a status_code field indicating an error (4xx or 5xx)
374
680
  if (data && typeof data === 'object' && 'status_code' in data && data.status_code >= 400) {
375
- throw this.handleError(data.status_code, data);
681
+ const apiError = this.handleError(data.status_code, data);
682
+ this.logger.exception('API status code error', apiError, this.buildLoggerExtra('request', {
683
+ url: url.toString(),
684
+ status: data.status_code,
685
+ }));
686
+ throw apiError;
376
687
  }
377
688
  // Check if the response has errors field with content
378
689
  if (data &&
@@ -381,7 +692,12 @@ class ApiClient {
381
692
  data.errors &&
382
693
  Array.isArray(data.errors) &&
383
694
  data.errors.length > 0) {
384
- throw this.handleError(data.status_code || 500, data);
695
+ const apiError = this.handleError(data.status_code || 500, data);
696
+ this.logger.exception('API response contained errors', apiError, this.buildLoggerExtra('request', {
697
+ url: url.toString(),
698
+ status: data.status_code || 500,
699
+ }));
700
+ throw apiError;
385
701
  }
386
702
  return data;
387
703
  }
@@ -1411,8 +1727,160 @@ class ApiClient {
1411
1727
  },
1412
1728
  });
1413
1729
  }
1730
+ /**
1731
+ * Get order fills for a specific order
1732
+ * @param orderId - The order ID
1733
+ * @param filter - Optional filter parameters
1734
+ * @returns Promise with order fills response
1735
+ */
1736
+ async getOrderFills(orderId, filter) {
1737
+ const accessToken = await this.getValidAccessToken();
1738
+ const params = {};
1739
+ if (filter?.connection_id) {
1740
+ params.connection_id = filter.connection_id;
1741
+ }
1742
+ if (filter?.limit) {
1743
+ params.limit = filter.limit.toString();
1744
+ }
1745
+ if (filter?.offset) {
1746
+ params.offset = filter.offset.toString();
1747
+ }
1748
+ return this.request(`/brokers/data/orders/${orderId}/fills`, {
1749
+ method: 'GET',
1750
+ headers: {
1751
+ Authorization: `Bearer ${accessToken}`,
1752
+ },
1753
+ params,
1754
+ });
1755
+ }
1756
+ /**
1757
+ * Get order events for a specific order
1758
+ * @param orderId - The order ID
1759
+ * @param filter - Optional filter parameters
1760
+ * @returns Promise with order events response
1761
+ */
1762
+ async getOrderEvents(orderId, filter) {
1763
+ const accessToken = await this.getValidAccessToken();
1764
+ const params = {};
1765
+ if (filter?.connection_id) {
1766
+ params.connection_id = filter.connection_id;
1767
+ }
1768
+ if (filter?.limit) {
1769
+ params.limit = filter.limit.toString();
1770
+ }
1771
+ if (filter?.offset) {
1772
+ params.offset = filter.offset.toString();
1773
+ }
1774
+ return this.request(`/brokers/data/orders/${orderId}/events`, {
1775
+ method: 'GET',
1776
+ headers: {
1777
+ Authorization: `Bearer ${accessToken}`,
1778
+ },
1779
+ params,
1780
+ });
1781
+ }
1782
+ /**
1783
+ * Get order groups
1784
+ * @param filter - Optional filter parameters
1785
+ * @returns Promise with order groups response
1786
+ */
1787
+ async getOrderGroups(filter) {
1788
+ const accessToken = await this.getValidAccessToken();
1789
+ const params = {};
1790
+ if (filter?.broker_id) {
1791
+ params.broker_id = filter.broker_id;
1792
+ }
1793
+ if (filter?.connection_id) {
1794
+ params.connection_id = filter.connection_id;
1795
+ }
1796
+ if (filter?.limit) {
1797
+ params.limit = filter.limit.toString();
1798
+ }
1799
+ if (filter?.offset) {
1800
+ params.offset = filter.offset.toString();
1801
+ }
1802
+ if (filter?.created_after) {
1803
+ params.created_after = filter.created_after;
1804
+ }
1805
+ if (filter?.created_before) {
1806
+ params.created_before = filter.created_before;
1807
+ }
1808
+ return this.request('/brokers/data/orders/groups', {
1809
+ method: 'GET',
1810
+ headers: {
1811
+ Authorization: `Bearer ${accessToken}`,
1812
+ },
1813
+ params,
1814
+ });
1815
+ }
1816
+ /**
1817
+ * Get position lots (tax lots for positions)
1818
+ * @param filter - Optional filter parameters
1819
+ * @returns Promise with position lots response
1820
+ */
1821
+ async getPositionLots(filter) {
1822
+ const accessToken = await this.getValidAccessToken();
1823
+ const params = {};
1824
+ if (filter?.broker_id) {
1825
+ params.broker_id = filter.broker_id;
1826
+ }
1827
+ if (filter?.connection_id) {
1828
+ params.connection_id = filter.connection_id;
1829
+ }
1830
+ if (filter?.account_id) {
1831
+ params.account_id = filter.account_id;
1832
+ }
1833
+ if (filter?.symbol) {
1834
+ params.symbol = filter.symbol;
1835
+ }
1836
+ if (filter?.position_id) {
1837
+ params.position_id = filter.position_id;
1838
+ }
1839
+ if (filter?.limit) {
1840
+ params.limit = filter.limit.toString();
1841
+ }
1842
+ if (filter?.offset) {
1843
+ params.offset = filter.offset.toString();
1844
+ }
1845
+ return this.request('/brokers/data/positions/lots', {
1846
+ method: 'GET',
1847
+ headers: {
1848
+ Authorization: `Bearer ${accessToken}`,
1849
+ },
1850
+ params,
1851
+ });
1852
+ }
1853
+ /**
1854
+ * Get position lot fills for a specific lot
1855
+ * @param lotId - The position lot ID
1856
+ * @param filter - Optional filter parameters
1857
+ * @returns Promise with position lot fills response
1858
+ */
1859
+ async getPositionLotFills(lotId, filter) {
1860
+ const accessToken = await this.getValidAccessToken();
1861
+ const params = {};
1862
+ if (filter?.connection_id) {
1863
+ params.connection_id = filter.connection_id;
1864
+ }
1865
+ if (filter?.limit) {
1866
+ params.limit = filter.limit.toString();
1867
+ }
1868
+ if (filter?.offset) {
1869
+ params.offset = filter.offset.toString();
1870
+ }
1871
+ return this.request(`/brokers/data/positions/lots/${lotId}/fills`, {
1872
+ method: 'GET',
1873
+ headers: {
1874
+ Authorization: `Bearer ${accessToken}`,
1875
+ },
1876
+ params,
1877
+ });
1878
+ }
1414
1879
  }
1415
1880
 
1881
+ const eventsLogger = setupLogger('FinaticClientSDK.Events', undefined, {
1882
+ codebase: 'FinaticClientSDK',
1883
+ });
1416
1884
  class EventEmitter {
1417
1885
  constructor() {
1418
1886
  this.events = new Map();
@@ -1442,7 +1910,13 @@ class EventEmitter {
1442
1910
  callback(...args);
1443
1911
  }
1444
1912
  catch (error) {
1445
- console.error(`Error in event handler for ${event}:`, error);
1913
+ eventsLogger.exception('Error in event handler', error, {
1914
+ module: 'EventEmitter',
1915
+ function: 'emit',
1916
+ ...buildLoggerExtra({
1917
+ event_name: event,
1918
+ }),
1919
+ });
1446
1920
  }
1447
1921
  });
1448
1922
  }
@@ -1463,6 +1937,9 @@ class EventEmitter {
1463
1937
  }
1464
1938
  }
1465
1939
 
1940
+ const portalLogger = setupLogger('FinaticClientSDK.PortalUI', undefined, {
1941
+ codebase: 'FinaticClientSDK',
1942
+ });
1466
1943
  class PortalUI {
1467
1944
  constructor(portalUrl) {
1468
1945
  this.iframe = null;
@@ -1471,10 +1948,18 @@ class PortalUI {
1471
1948
  this.sessionId = null;
1472
1949
  this.portalOrigin = null;
1473
1950
  this.originalBodyStyle = null;
1951
+ this.logger = portalLogger;
1474
1952
  this.createContainer();
1475
1953
  }
1954
+ buildLoggerExtra(functionName, metadata) {
1955
+ return {
1956
+ module: 'PortalUI',
1957
+ function: functionName,
1958
+ ...(metadata ? buildLoggerExtra(metadata) : {}),
1959
+ };
1960
+ }
1476
1961
  createContainer() {
1477
- console.debug('[PortalUI] Creating container and iframe');
1962
+ this.logger.debug('Creating portal container and iframe', this.buildLoggerExtra('createContainer'));
1478
1963
  this.container = document.createElement('div');
1479
1964
  this.container.style.cssText = `
1480
1965
  position: fixed;
@@ -1521,7 +2006,7 @@ class PortalUI {
1521
2006
  this.iframe.contentDocument?.head.appendChild(meta);
1522
2007
  this.container.appendChild(this.iframe);
1523
2008
  document.body.appendChild(this.container);
1524
- console.debug('[PortalUI] Container and iframe created successfully');
2009
+ this.logger.debug('Portal container and iframe created successfully', this.buildLoggerExtra('createContainer'));
1525
2010
  }
1526
2011
  /**
1527
2012
  * Lock background scrolling by setting overflow: hidden on body
@@ -1535,7 +2020,7 @@ class PortalUI {
1535
2020
  document.body.style.position = 'fixed';
1536
2021
  document.body.style.width = '100%';
1537
2022
  document.body.style.top = `-${window.scrollY}px`;
1538
- console.debug('[PortalUI] Background scroll locked');
2023
+ this.logger.debug('Background scroll locked', this.buildLoggerExtra('lockScroll'));
1539
2024
  }
1540
2025
  }
1541
2026
  /**
@@ -1551,7 +2036,7 @@ class PortalUI {
1551
2036
  document.body.style.top = '';
1552
2037
  window.scrollTo(0, parseInt(scrollY || '0') * -1);
1553
2038
  this.originalBodyStyle = null;
1554
- console.debug('[PortalUI] Background scroll unlocked');
2039
+ this.logger.debug('Background scroll unlocked', this.buildLoggerExtra('unlockScroll'));
1555
2040
  }
1556
2041
  }
1557
2042
  show(url, sessionId, options = {}) {
@@ -1593,11 +2078,17 @@ class PortalUI {
1593
2078
  handleMessage(event) {
1594
2079
  // Verify origin matches the portal URL
1595
2080
  if (!this.portalOrigin || event.origin !== this.portalOrigin) {
1596
- console.warn('[PortalUI] Received message from unauthorized origin:', event.origin, 'Expected:', this.portalOrigin);
2081
+ this.logger.warn('Received message from unauthorized origin', this.buildLoggerExtra('handleMessage', {
2082
+ received_origin: event.origin,
2083
+ expected_origin: this.portalOrigin || 'unknown',
2084
+ }));
1597
2085
  return;
1598
2086
  }
1599
2087
  const { type, userId, access_token, refresh_token, error, height, data } = event.data;
1600
- console.log('[PortalUI] Received message:', event.data);
2088
+ this.logger.debug('Received portal message', this.buildLoggerExtra('handleMessage', {
2089
+ message_type: type,
2090
+ has_data: Boolean(data),
2091
+ }));
1601
2092
  switch (type) {
1602
2093
  case 'portal-success': {
1603
2094
  // Handle both direct userId and data.userId formats
@@ -1635,36 +2126,50 @@ class PortalUI {
1635
2126
  this.handleClose();
1636
2127
  break;
1637
2128
  default:
1638
- console.warn('[PortalUI] Received unhandled message type:', type);
2129
+ this.logger.warn('Received unhandled message type', this.buildLoggerExtra('handleMessage', {
2130
+ message_type: type,
2131
+ }));
1639
2132
  }
1640
2133
  }
1641
2134
  handlePortalSuccess(userId, tokens) {
1642
2135
  if (!userId) {
1643
- console.error('[PortalUI] Missing userId in portal-success message');
2136
+ this.logger.error('Missing userId in portal-success message', this.buildLoggerExtra('handlePortalSuccess'));
1644
2137
  return;
1645
2138
  }
1646
- console.log('[PortalUI] Portal success - User connected:', userId);
2139
+ this.logger.info('Portal success - user connected', this.buildLoggerExtra('handlePortalSuccess', {
2140
+ user_id_present: Boolean(userId),
2141
+ tokens_provided: Boolean(tokens?.access_token && tokens?.refresh_token),
2142
+ }));
1647
2143
  if (tokens?.access_token && tokens?.refresh_token) {
1648
- console.log('[PortalUI] Tokens received for user:', userId);
2144
+ this.logger.debug('Tokens received for user', this.buildLoggerExtra('handlePortalSuccess', {
2145
+ tokens_provided: true,
2146
+ }));
1649
2147
  }
1650
2148
  // Pass userId to parent (SDK will handle tokens internally)
1651
2149
  this.options?.onSuccess?.(userId, tokens);
1652
2150
  }
1653
2151
  handlePortalError(error) {
1654
- console.error('[PortalUI] Portal error:', error);
2152
+ this.logger.error('Portal error received', this.buildLoggerExtra('handlePortalError', {
2153
+ error_message: error,
2154
+ }));
1655
2155
  this.options?.onError?.(new Error(error || 'Unknown portal error'));
1656
2156
  }
1657
2157
  handlePortalClose() {
1658
- console.log('[PortalUI] Portal closed by user');
2158
+ this.logger.info('Portal closed by user', this.buildLoggerExtra('handlePortalClose'));
1659
2159
  this.options?.onClose?.();
1660
2160
  this.hide();
1661
2161
  }
1662
2162
  handleGenericEvent(data) {
1663
2163
  if (!data || !data.type) {
1664
- console.warn('[PortalUI] Invalid event data:', data);
2164
+ this.logger.warn('Invalid event data received', this.buildLoggerExtra('handleGenericEvent', {
2165
+ has_type: Boolean(data?.type),
2166
+ }));
1665
2167
  return;
1666
2168
  }
1667
- console.log('[PortalUI] Generic event received:', data.type, data.data);
2169
+ this.logger.debug('Generic event received', this.buildLoggerExtra('handleGenericEvent', {
2170
+ event_type: data.type,
2171
+ payload_present: Boolean(data.data),
2172
+ }));
1668
2173
  // Emit the event to be handled by the SDK
1669
2174
  // This will be implemented in FinaticConnect
1670
2175
  if (this.options?.onEvent) {
@@ -1673,24 +2178,28 @@ class PortalUI {
1673
2178
  }
1674
2179
  handleSuccess(userId) {
1675
2180
  if (!userId) {
1676
- console.error('[PortalUI] Missing required fields in success message');
2181
+ this.logger.error('Missing required fields in success message', this.buildLoggerExtra('handleSuccess'));
1677
2182
  return;
1678
2183
  }
1679
2184
  // Pass userId to parent
1680
2185
  this.options?.onSuccess?.(userId);
1681
2186
  }
1682
2187
  handleError(error) {
1683
- console.error('[PortalUI] Received error:', error);
2188
+ this.logger.error('Received portal error message', this.buildLoggerExtra('handleError', {
2189
+ error_message: error,
2190
+ }));
1684
2191
  this.options?.onError?.(new Error(error || 'Unknown error'));
1685
2192
  }
1686
2193
  handleClose() {
1687
- console.log('[PortalUI] Received close message');
2194
+ this.logger.debug('Received close message', this.buildLoggerExtra('handleClose'));
1688
2195
  this.options?.onClose?.();
1689
2196
  this.hide();
1690
2197
  }
1691
2198
  handleResize(height) {
1692
2199
  if (height && this.iframe) {
1693
- console.log('[PortalUI] Received resize message:', height);
2200
+ this.logger.debug('Received resize message', this.buildLoggerExtra('handleResize', {
2201
+ height,
2202
+ }));
1694
2203
  this.iframe.style.height = `${height}px`;
1695
2204
  }
1696
2205
  }
@@ -2518,11 +3027,21 @@ class MockDataProvider {
2518
3027
  }
2519
3028
  }
2520
3029
 
3030
+ const mockApiLogger = setupLogger('FinaticClientSDK.MockApiClient', undefined, {
3031
+ codebase: 'FinaticClientSDK',
3032
+ });
2521
3033
  /**
2522
3034
  * Mock API Client that implements the same interface as the real ApiClient
2523
3035
  * but returns mock data instead of making HTTP requests
2524
3036
  */
2525
3037
  class MockApiClient {
3038
+ buildLoggerExtra(functionName, metadata) {
3039
+ return {
3040
+ module: 'MockApiClient',
3041
+ function: functionName,
3042
+ ...(metadata ? buildLoggerExtra(metadata) : {}),
3043
+ };
3044
+ }
2526
3045
  constructor(baseUrl, deviceInfo, mockConfig) {
2527
3046
  this.currentSessionState = null;
2528
3047
  this.currentSessionId = null;
@@ -2534,16 +3053,21 @@ class MockApiClient {
2534
3053
  // Session and company context
2535
3054
  this.companyId = null;
2536
3055
  this.csrfToken = null;
3056
+ this.logger = mockApiLogger;
2537
3057
  this.baseUrl = baseUrl;
2538
3058
  this.deviceInfo = deviceInfo;
2539
3059
  this.mockApiOnly = mockConfig?.mockApiOnly || false;
2540
3060
  this.mockDataProvider = new MockDataProvider(mockConfig);
2541
3061
  // Log that mocks are being used
2542
3062
  if (this.mockApiOnly) {
2543
- console.log('🔧 Finatic SDK: Using MOCK API Client (API only - real portal)');
3063
+ this.logger.info('Using mock API client (API only, real portal)', this.buildLoggerExtra('constructor', {
3064
+ mock_api_only: true,
3065
+ }));
2544
3066
  }
2545
3067
  else {
2546
- console.log('🔧 Finatic SDK: Using MOCK API Client');
3068
+ this.logger.info('Using mock API client', this.buildLoggerExtra('constructor', {
3069
+ mock_api_only: false,
3070
+ }));
2547
3071
  }
2548
3072
  }
2549
3073
  /**
@@ -2737,14 +3261,12 @@ class MockApiClient {
2737
3261
  async placeBrokerOrder(params, extras = {}, connection_id) {
2738
3262
  await this.getValidAccessToken();
2739
3263
  // Debug logging
2740
- console.log('MockApiClient.placeBrokerOrder Debug:', {
2741
- params,
2742
- tradingContext: this.tradingContext,
2743
- paramsBroker: params.broker,
2744
- contextBroker: this.tradingContext.broker,
2745
- paramsAccountNumber: params.accountNumber,
2746
- contextAccountNumber: this.tradingContext.accountNumber,
2747
- });
3264
+ this.logger.debug('placeBrokerOrder parameters', this.buildLoggerExtra('placeBrokerOrder', {
3265
+ has_params_broker: Boolean(params.broker),
3266
+ has_context_broker: Boolean(this.tradingContext.broker),
3267
+ has_params_account: Boolean(params.accountNumber),
3268
+ has_context_account: Boolean(this.tradingContext.accountNumber),
3269
+ }));
2748
3270
  const fullParams = {
2749
3271
  broker: (params.broker || this.tradingContext.broker) ||
2750
3272
  (() => {
@@ -2765,7 +3287,13 @@ class MockApiClient {
2765
3287
  stopPrice: params.stopPrice,
2766
3288
  order_id: params.order_id,
2767
3289
  };
2768
- console.log('MockApiClient.placeBrokerOrder Debug - Final params:', fullParams);
3290
+ this.logger.debug('placeBrokerOrder normalized parameters', this.buildLoggerExtra('placeBrokerOrder', {
3291
+ broker: fullParams.broker,
3292
+ account_number_present: Boolean(fullParams.accountNumber),
3293
+ symbol: fullParams.symbol,
3294
+ order_type: fullParams.orderType,
3295
+ asset_type: fullParams.assetType,
3296
+ }));
2769
3297
  return this.mockDataProvider.mockPlaceOrder(fullParams);
2770
3298
  }
2771
3299
  async cancelBrokerOrder(orderId, broker, extras = {}, connection_id) {
@@ -2803,14 +3331,18 @@ class MockApiClient {
2803
3331
  this.tradingContext.accountId = undefined;
2804
3332
  }
2805
3333
  setAccount(accountNumber, accountId) {
2806
- console.log('MockApiClient.setAccount Debug:', {
2807
- accountNumber,
2808
- accountId,
2809
- previousContext: { ...this.tradingContext },
2810
- });
3334
+ this.logger.debug('setAccount invoked', this.buildLoggerExtra('setAccount', {
3335
+ account_number: accountNumber,
3336
+ account_id_present: Boolean(accountId),
3337
+ had_existing_account: Boolean(this.tradingContext.accountNumber),
3338
+ }));
2811
3339
  this.tradingContext.accountNumber = accountNumber;
2812
3340
  this.tradingContext.accountId = accountId;
2813
- console.log('MockApiClient.setAccount Debug - Updated context:', this.tradingContext);
3341
+ this.logger.debug('setAccount updated context', this.buildLoggerExtra('setAccount', {
3342
+ broker: this.tradingContext.broker,
3343
+ account_number_present: Boolean(this.tradingContext.accountNumber),
3344
+ account_id_present: Boolean(this.tradingContext.accountId),
3345
+ }));
2814
3346
  }
2815
3347
  // Stock convenience methods
2816
3348
  async placeStockMarketOrder(symbol, orderQty, action, broker, accountNumber, extras = {}) {
@@ -4592,6 +5124,14 @@ const portalThemePresets = {
4592
5124
  stockAlgos: stockAlgosTheme,
4593
5125
  };
4594
5126
 
5127
+ const themeLogger = setupLogger('FinaticClientSDK.ThemeUtils', undefined, {
5128
+ codebase: 'FinaticClientSDK',
5129
+ });
5130
+ const buildThemeExtra = (functionName, metadata) => ({
5131
+ module: 'ThemeUtils',
5132
+ function: functionName,
5133
+ ...(metadata ? buildLoggerExtra(metadata) : {}),
5134
+ });
4595
5135
  /**
4596
5136
  * Generate a portal URL with theme parameters
4597
5137
  * @param baseUrl The base portal URL
@@ -4617,7 +5157,10 @@ function generatePortalThemeURL(baseUrl, theme) {
4617
5157
  return url.toString();
4618
5158
  }
4619
5159
  catch (error) {
4620
- console.error('Failed to generate theme URL:', error);
5160
+ themeLogger.exception('Failed to generate theme URL', error, buildThemeExtra('generatePortalThemeURL', {
5161
+ base_url: baseUrl,
5162
+ has_theme: Boolean(theme),
5163
+ }));
4621
5164
  return baseUrl;
4622
5165
  }
4623
5166
  }
@@ -4646,7 +5189,10 @@ function appendThemeToURL(baseUrl, theme) {
4646
5189
  return url.toString();
4647
5190
  }
4648
5191
  catch (error) {
4649
- console.error('Failed to append theme to URL:', error);
5192
+ themeLogger.exception('Failed to append theme to URL', error, buildThemeExtra('appendThemeToURL', {
5193
+ base_url: baseUrl,
5194
+ has_theme: Boolean(theme),
5195
+ }));
4650
5196
  return baseUrl;
4651
5197
  }
4652
5198
  }
@@ -4701,7 +5247,7 @@ function validateCustomTheme(theme) {
4701
5247
  return true;
4702
5248
  }
4703
5249
  catch (error) {
4704
- console.error('Theme validation error:', error);
5250
+ themeLogger.exception('Theme validation error', error, buildThemeExtra('validateCustomTheme'));
4705
5251
  return false;
4706
5252
  }
4707
5253
  }
@@ -4714,7 +5260,9 @@ function validateCustomTheme(theme) {
4714
5260
  function createCustomThemeFromPreset(preset, modifications) {
4715
5261
  const baseTheme = getThemePreset(preset);
4716
5262
  if (!baseTheme) {
4717
- console.error(`Preset theme '${preset}' not found`);
5263
+ themeLogger.warn('Preset theme not found', buildThemeExtra('createCustomThemeFromPreset', {
5264
+ preset,
5265
+ }));
4718
5266
  return null;
4719
5267
  }
4720
5268
  return {
@@ -4726,6 +5274,14 @@ function createCustomThemeFromPreset(preset, modifications) {
4726
5274
  /**
4727
5275
  * Broker filtering utility functions
4728
5276
  */
5277
+ const brokerLogger = setupLogger('FinaticClientSDK.BrokerUtils', undefined, {
5278
+ codebase: 'FinaticClientSDK',
5279
+ });
5280
+ const buildBrokerExtra = (functionName, metadata) => ({
5281
+ module: 'BrokerUtils',
5282
+ function: functionName,
5283
+ ...(metadata ? buildLoggerExtra(metadata) : {}),
5284
+ });
4729
5285
  // Supported broker names and their corresponding IDs (including aliases)
4730
5286
  const SUPPORTED_BROKERS = {
4731
5287
  'alpaca': 'alpaca',
@@ -4768,7 +5324,9 @@ function appendBrokerFilterToURL(baseUrl, brokerNames) {
4768
5324
  const url = new URL(baseUrl);
4769
5325
  const { brokerIds, warnings } = convertBrokerNamesToIds(brokerNames);
4770
5326
  // Log warnings for unsupported broker names
4771
- warnings.forEach(warning => console.warn(`[FinaticConnect] ${warning}`));
5327
+ warnings.forEach(warning => brokerLogger.warn('Unsupported broker name provided', buildBrokerExtra('appendBrokerFilterToURL', {
5328
+ warning,
5329
+ })));
4772
5330
  // Only add broker filter if we have valid broker IDs
4773
5331
  if (brokerIds.length > 0) {
4774
5332
  const encodedBrokers = btoa(JSON.stringify(brokerIds));
@@ -4777,12 +5335,30 @@ function appendBrokerFilterToURL(baseUrl, brokerNames) {
4777
5335
  return url.toString();
4778
5336
  }
4779
5337
  catch (error) {
4780
- console.error('Failed to append broker filter to URL:', error);
5338
+ brokerLogger.exception('Failed to append broker filter to URL', error, buildBrokerExtra('appendBrokerFilterToURL', {
5339
+ base_url: baseUrl,
5340
+ brokers_count: brokerNames?.length ?? 0,
5341
+ }));
4781
5342
  return baseUrl;
4782
5343
  }
4783
5344
  }
4784
5345
 
5346
+ const finaticConnectLogger = setupLogger('FinaticClientSDK.FinaticConnect', undefined, {
5347
+ codebase: 'FinaticClientSDK',
5348
+ });
5349
+ const makeFinaticConnectExtra = (functionName, metadata) => ({
5350
+ module: 'FinaticConnect',
5351
+ function: functionName,
5352
+ ...(metadata ? buildLoggerExtra(metadata) : {}),
5353
+ });
4785
5354
  class FinaticConnect extends EventEmitter {
5355
+ buildLoggerExtra(functionName, metadata) {
5356
+ return {
5357
+ module: 'FinaticConnect',
5358
+ function: functionName,
5359
+ ...(metadata ? buildLoggerExtra(metadata) : {}),
5360
+ };
5361
+ }
4786
5362
  constructor(options, deviceInfo) {
4787
5363
  super();
4788
5364
  this.userToken = null;
@@ -4797,6 +5373,7 @@ class FinaticConnect extends EventEmitter {
4797
5373
  this.SESSION_VALIDATION_TIMEOUT = 1000 * 30; // 30 seconds
4798
5374
  this.SESSION_REFRESH_BUFFER_HOURS = 16; // Refresh session at 16 hours
4799
5375
  this.sessionStartTime = null;
5376
+ this.logger = finaticConnectLogger;
4800
5377
  this.options = options;
4801
5378
  this.baseUrl = options.baseUrl || 'https://api.finatic.dev';
4802
5379
  this.apiClient = MockFactory.createApiClient(this.baseUrl, deviceInfo);
@@ -4849,7 +5426,7 @@ class FinaticConnect extends EventEmitter {
4849
5426
  async linkUserToSession(userId) {
4850
5427
  try {
4851
5428
  if (!this.sessionId) {
4852
- console.error('No session ID available for user linking');
5429
+ this.logger.error('No session ID available for user linking', this.buildLoggerExtra('linkUserToSession'));
4853
5430
  return false;
4854
5431
  }
4855
5432
  // Call API endpoint to authenticate user with session
@@ -4861,14 +5438,20 @@ class FinaticConnect extends EventEmitter {
4861
5438
  },
4862
5439
  });
4863
5440
  if (response.error) {
4864
- console.error('Failed to link user to session:', response.error);
5441
+ this.logger.error('Failed to link user to session', {
5442
+ ...this.buildLoggerExtra('linkUserToSession', {
5443
+ session_id: this.sessionId,
5444
+ user_id: userId,
5445
+ }),
5446
+ error: response.error,
5447
+ });
4865
5448
  return false;
4866
5449
  }
4867
- console.log('User linked to session successfully');
5450
+ this.logger.info('User linked to session successfully', this.buildLoggerExtra('linkUserToSession', { session_id: this.sessionId, user_id: userId }));
4868
5451
  return true;
4869
5452
  }
4870
5453
  catch (error) {
4871
- console.error('Error linking user to session:', error);
5454
+ this.logger.exception('Error linking user to session', error, this.buildLoggerExtra('linkUserToSession', { session_id: this.sessionId, user_id: userId }));
4872
5455
  return false;
4873
5456
  }
4874
5457
  }
@@ -5013,7 +5596,7 @@ class FinaticConnect extends EventEmitter {
5013
5596
  // Safari-specific fix: Clear instance if it exists but has no valid session
5014
5597
  // This prevents stale instances from interfering with new requests
5015
5598
  if (FinaticConnect.instance && !FinaticConnect.instance.sessionId) {
5016
- console.log('[FinaticConnect] Clearing stale instance for Safari compatibility');
5599
+ finaticConnectLogger.debug('Clearing stale instance for Safari compatibility', makeFinaticConnectExtra('init'));
5017
5600
  FinaticConnect.instance = null;
5018
5601
  }
5019
5602
  if (!FinaticConnect.instance) {
@@ -5065,7 +5648,7 @@ class FinaticConnect extends EventEmitter {
5065
5648
  FinaticConnect.instance.emit('success', normalizedUserId);
5066
5649
  }
5067
5650
  else {
5068
- console.warn('Failed to link user to session during initialization');
5651
+ finaticConnectLogger.warn('Failed to link user to session during initialization', makeFinaticConnectExtra('init', { user_id: normalizedUserId }));
5069
5652
  }
5070
5653
  }
5071
5654
  catch (error) {
@@ -5095,7 +5678,7 @@ class FinaticConnect extends EventEmitter {
5095
5678
  // Try to link user to session
5096
5679
  const linked = await this.linkUserToSession(userId);
5097
5680
  if (!linked) {
5098
- console.warn('Failed to link user to session during initialization');
5681
+ this.logger.warn('Failed to link user to session during initialization', this.buildLoggerExtra('initializeWithUser', { user_id: userId }));
5099
5682
  // Don't throw error, just continue without authentication
5100
5683
  return;
5101
5684
  }
@@ -5183,7 +5766,7 @@ class FinaticConnect extends EventEmitter {
5183
5766
  // Try to link user to session via API
5184
5767
  const linked = await this.linkUserToSession(userId);
5185
5768
  if (!linked) {
5186
- console.warn('Failed to link user to session, but continuing with authentication');
5769
+ this.logger.warn('Failed to link user to session, continuing with authentication', this.buildLoggerExtra('openPortal.onSuccess', { user_id: userId }));
5187
5770
  }
5188
5771
  // Emit portal success event
5189
5772
  this.emit('portal:success', userId);
@@ -5217,7 +5800,13 @@ class FinaticConnect extends EventEmitter {
5217
5800
  options?.onClose?.();
5218
5801
  },
5219
5802
  onEvent: (type, data) => {
5220
- console.log('[FinaticConnect] Portal event received:', type, data);
5803
+ this.logger.debug('Portal event received', {
5804
+ ...this.buildLoggerExtra('openPortal.onEvent', {
5805
+ event_type: type,
5806
+ payload_present: Boolean(data),
5807
+ }),
5808
+ event: 'portal-event',
5809
+ });
5221
5810
  // Emit generic event
5222
5811
  this.emit('event', type, data);
5223
5812
  // Call the event callback
@@ -5728,7 +6317,7 @@ class FinaticConnect extends EventEmitter {
5728
6317
  this.sessionKeepAliveInterval = setInterval(() => {
5729
6318
  this.validateSessionKeepAlive();
5730
6319
  }, this.SESSION_KEEP_ALIVE_INTERVAL);
5731
- console.log('[FinaticConnect] Session keep-alive started (5-minute intervals)');
6320
+ this.logger.debug('Session keep-alive started', this.buildLoggerExtra('startSessionKeepAlive', { interval_ms: this.SESSION_KEEP_ALIVE_INTERVAL }));
5732
6321
  }
5733
6322
  /**
5734
6323
  * Stop the session keep-alive mechanism
@@ -5737,7 +6326,7 @@ class FinaticConnect extends EventEmitter {
5737
6326
  if (this.sessionKeepAliveInterval) {
5738
6327
  clearInterval(this.sessionKeepAliveInterval);
5739
6328
  this.sessionKeepAliveInterval = null;
5740
- console.log('[FinaticConnect] Session keep-alive stopped');
6329
+ this.logger.debug('Session keep-alive stopped', this.buildLoggerExtra('stopSessionKeepAlive'));
5741
6330
  }
5742
6331
  }
5743
6332
  /**
@@ -5745,22 +6334,22 @@ class FinaticConnect extends EventEmitter {
5745
6334
  */
5746
6335
  async validateSessionKeepAlive() {
5747
6336
  if (!this.sessionId || !(await this.isAuthenticated())) {
5748
- console.log('[FinaticConnect] Session keep-alive skipped - no active session');
6337
+ this.logger.debug('Session keep-alive skipped - no active session', this.buildLoggerExtra('validateSessionKeepAlive'));
5749
6338
  return;
5750
6339
  }
5751
6340
  try {
5752
- console.log('[FinaticConnect] Validating session for keep-alive...');
6341
+ this.logger.debug('Validating session for keep-alive', this.buildLoggerExtra('validateSessionKeepAlive', { session_id: this.sessionId }));
5753
6342
  // Check if we need to refresh the session (at 16 hours)
5754
6343
  if (this.shouldRefreshSession()) {
5755
6344
  await this.refreshSessionAutomatically();
5756
6345
  return;
5757
6346
  }
5758
6347
  // Session keep-alive - assume session is active if we have a session ID
5759
- console.log('[FinaticConnect] Session keep-alive successful');
6348
+ this.logger.debug('Session keep-alive successful', this.buildLoggerExtra('validateSessionKeepAlive', { session_id: this.sessionId }));
5760
6349
  this.currentSessionState = 'active';
5761
6350
  }
5762
6351
  catch (error) {
5763
- console.warn('[FinaticConnect] Session keep-alive error:', error);
6352
+ this.logger.exception('Session keep-alive error', error, this.buildLoggerExtra('validateSessionKeepAlive', { session_id: this.sessionId }));
5764
6353
  // Don't throw errors during keep-alive - just log them
5765
6354
  }
5766
6355
  }
@@ -5774,12 +6363,16 @@ class FinaticConnect extends EventEmitter {
5774
6363
  const sessionAgeHours = (Date.now() - this.sessionStartTime) / (1000 * 60 * 60);
5775
6364
  const hoursUntilRefresh = this.SESSION_REFRESH_BUFFER_HOURS - sessionAgeHours;
5776
6365
  if (hoursUntilRefresh <= 0) {
5777
- console.log(`[FinaticConnect] Session is ${sessionAgeHours.toFixed(1)} hours old - triggering refresh`);
6366
+ this.logger.info('Session age threshold exceeded - triggering refresh', this.buildLoggerExtra('shouldRefreshSession', {
6367
+ session_age_hours: Number(sessionAgeHours.toFixed(1)),
6368
+ }));
5778
6369
  return true;
5779
6370
  }
5780
6371
  // Log when refresh will occur (every 5 minutes during keep-alive)
5781
6372
  if (hoursUntilRefresh <= 1) {
5782
- console.log(`[FinaticConnect] Session will refresh in ${hoursUntilRefresh.toFixed(1)} hours`);
6373
+ this.logger.debug('Session refresh scheduled', this.buildLoggerExtra('shouldRefreshSession', {
6374
+ hours_until_refresh: Number(hoursUntilRefresh.toFixed(1)),
6375
+ }));
5783
6376
  }
5784
6377
  return false;
5785
6378
  }
@@ -5788,25 +6381,34 @@ class FinaticConnect extends EventEmitter {
5788
6381
  */
5789
6382
  async refreshSessionAutomatically() {
5790
6383
  if (!this.sessionId) {
5791
- console.warn('[FinaticConnect] Cannot refresh session - no session ID');
6384
+ this.logger.warn('Cannot refresh session - missing session ID', this.buildLoggerExtra('refreshSessionAutomatically'));
5792
6385
  return;
5793
6386
  }
5794
6387
  try {
5795
- console.log('[FinaticConnect] Automatically refreshing session (16+ hours old)...');
6388
+ this.logger.info('Automatically refreshing session', this.buildLoggerExtra('refreshSessionAutomatically', {
6389
+ session_id: this.sessionId,
6390
+ }));
5796
6391
  const response = await this.apiClient.refreshSession();
5797
6392
  if (response.success) {
5798
- console.log('[FinaticConnect] Session automatically refreshed successfully');
5799
- console.log('[FinaticConnect] New session expires at:', response.response_data.expires_at);
6393
+ this.logger.info('Session automatically refreshed successfully', this.buildLoggerExtra('refreshSessionAutomatically', {
6394
+ session_id: this.sessionId,
6395
+ status: response.response_data.status,
6396
+ expires_at: response.response_data.expires_at,
6397
+ }));
5800
6398
  this.currentSessionState = response.response_data.status;
5801
6399
  // Update session start time to prevent immediate re-refresh
5802
6400
  this.sessionStartTime = Date.now();
5803
6401
  }
5804
6402
  else {
5805
- console.warn('[FinaticConnect] Automatic session refresh failed');
6403
+ this.logger.warn('Automatic session refresh failed', this.buildLoggerExtra('refreshSessionAutomatically', {
6404
+ session_id: this.sessionId,
6405
+ }));
5806
6406
  }
5807
6407
  }
5808
6408
  catch (error) {
5809
- console.warn('[FinaticConnect] Automatic session refresh error:', error);
6409
+ this.logger.exception('Automatic session refresh error', error, this.buildLoggerExtra('refreshSessionAutomatically', {
6410
+ session_id: this.sessionId,
6411
+ }));
5810
6412
  // Don't throw errors during automatic refresh - just log them
5811
6413
  }
5812
6414
  }
@@ -5826,7 +6428,9 @@ class FinaticConnect extends EventEmitter {
5826
6428
  async handleVisibilityChange() {
5827
6429
  // For 24-hour sessions, we don't want to complete sessions on visibility changes
5828
6430
  // This prevents sessions from being closed when users switch tabs or apps
5829
- console.log('[FinaticConnect] Page visibility changed to:', document.visibilityState);
6431
+ this.logger.debug('Page visibility changed', this.buildLoggerExtra('handleVisibilityChange', {
6432
+ visibility_state: document.visibilityState,
6433
+ }));
5830
6434
  // Only pause keep-alive when hidden, but don't complete the session
5831
6435
  if (document.visibilityState === 'hidden') {
5832
6436
  this.stopSessionKeepAlive();
@@ -5848,7 +6452,7 @@ class FinaticConnect extends EventEmitter {
5848
6452
  this.apiClient.isMockClient();
5849
6453
  if (isMockMode) {
5850
6454
  // Mock the completion response
5851
- console.log('[FinaticConnect] Mock session completion for session:', sessionId);
6455
+ this.logger.debug('Mock session completion', this.buildLoggerExtra('completeSession', { session_id: sessionId }));
5852
6456
  return;
5853
6457
  }
5854
6458
  // Real API call
@@ -5859,15 +6463,18 @@ class FinaticConnect extends EventEmitter {
5859
6463
  },
5860
6464
  });
5861
6465
  if (response.ok) {
5862
- console.log('[FinaticConnect] Session completed successfully');
6466
+ this.logger.info('Session completed successfully', this.buildLoggerExtra('completeSession', { session_id: sessionId }));
5863
6467
  }
5864
6468
  else {
5865
- console.warn('[FinaticConnect] Failed to complete session:', response.status);
6469
+ this.logger.warn('Failed to complete session', this.buildLoggerExtra('completeSession', {
6470
+ session_id: sessionId,
6471
+ response_status: response.status,
6472
+ }));
5866
6473
  }
5867
6474
  }
5868
6475
  catch (error) {
5869
6476
  // Silent failure - don't throw errors during cleanup
5870
- console.warn('[FinaticConnect] Session cleanup failed:', error);
6477
+ this.logger.exception('Session cleanup failed', error, this.buildLoggerExtra('completeSession', { session_id: sessionId }));
5871
6478
  }
5872
6479
  }
5873
6480
  /**
@@ -5885,6 +6492,69 @@ class FinaticConnect extends EventEmitter {
5885
6492
  }
5886
6493
  return this.apiClient.disconnectCompany(connectionId);
5887
6494
  }
6495
+ /**
6496
+ * Get order fills for a specific order
6497
+ * @param orderId - The order ID
6498
+ * @param filter - Optional filter parameters
6499
+ * @returns Promise with order fills response
6500
+ */
6501
+ async getOrderFills(orderId, filter) {
6502
+ if (!(await this.isAuthenticated())) {
6503
+ throw new AuthenticationError('User is not authenticated');
6504
+ }
6505
+ const response = await this.apiClient.getOrderFills(orderId, filter);
6506
+ return response.response_data;
6507
+ }
6508
+ /**
6509
+ * Get order events for a specific order
6510
+ * @param orderId - The order ID
6511
+ * @param filter - Optional filter parameters
6512
+ * @returns Promise with order events response
6513
+ */
6514
+ async getOrderEvents(orderId, filter) {
6515
+ if (!(await this.isAuthenticated())) {
6516
+ throw new AuthenticationError('User is not authenticated');
6517
+ }
6518
+ const response = await this.apiClient.getOrderEvents(orderId, filter);
6519
+ return response.response_data;
6520
+ }
6521
+ /**
6522
+ * Get order groups
6523
+ * @param filter - Optional filter parameters
6524
+ * @returns Promise with order groups response
6525
+ */
6526
+ async getOrderGroups(filter) {
6527
+ if (!(await this.isAuthenticated())) {
6528
+ throw new AuthenticationError('User is not authenticated');
6529
+ }
6530
+ const response = await this.apiClient.getOrderGroups(filter);
6531
+ return response.response_data;
6532
+ }
6533
+ /**
6534
+ * Get position lots (tax lots for positions)
6535
+ * @param filter - Optional filter parameters
6536
+ * @returns Promise with position lots response
6537
+ */
6538
+ async getPositionLots(filter) {
6539
+ if (!(await this.isAuthenticated())) {
6540
+ throw new AuthenticationError('User is not authenticated');
6541
+ }
6542
+ const response = await this.apiClient.getPositionLots(filter);
6543
+ return response.response_data;
6544
+ }
6545
+ /**
6546
+ * Get position lot fills for a specific lot
6547
+ * @param lotId - The position lot ID
6548
+ * @param filter - Optional filter parameters
6549
+ * @returns Promise with position lot fills response
6550
+ */
6551
+ async getPositionLotFills(lotId, filter) {
6552
+ if (!(await this.isAuthenticated())) {
6553
+ throw new AuthenticationError('User is not authenticated');
6554
+ }
6555
+ const response = await this.apiClient.getPositionLotFills(lotId, filter);
6556
+ return response.response_data;
6557
+ }
5888
6558
  }
5889
6559
  FinaticConnect.instance = null;
5890
6560
 
@@ -5907,9 +6577,12 @@ exports.TokenError = TokenError;
5907
6577
  exports.TradingNotEnabledError = TradingNotEnabledError;
5908
6578
  exports.ValidationError = ValidationError;
5909
6579
  exports.appendThemeToURL = appendThemeToURL;
6580
+ exports.buildLoggerExtra = buildLoggerExtra;
5910
6581
  exports.createCustomThemeFromPreset = createCustomThemeFromPreset;
5911
6582
  exports.generatePortalThemeURL = generatePortalThemeURL;
5912
6583
  exports.getThemePreset = getThemePreset;
6584
+ exports.logStartEnd = logStartEnd;
5913
6585
  exports.portalThemePresets = portalThemePresets;
6586
+ exports.setupLogger = setupLogger;
5914
6587
  exports.validateCustomTheme = validateCustomTheme;
5915
6588
  //# sourceMappingURL=index.js.map