@finatic/client 0.0.142 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +39 -0
  3. package/README.md +54 -425
  4. package/dist/index.d.ts +7329 -1579
  5. package/dist/index.js +8110 -6114
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +8047 -6085
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +77 -33
  10. package/dist/types/core/client/ApiClient.d.ts +0 -270
  11. package/dist/types/core/client/FinaticConnect.d.ts +0 -332
  12. package/dist/types/core/portal/PortalUI.d.ts +0 -37
  13. package/dist/types/index.d.ts +0 -12
  14. package/dist/types/lib/logger/index.d.ts +0 -2
  15. package/dist/types/lib/logger/logger.d.ts +0 -4
  16. package/dist/types/lib/logger/logger.types.d.ts +0 -28
  17. package/dist/types/mocks/MockApiClient.d.ts +0 -171
  18. package/dist/types/mocks/MockDataProvider.d.ts +0 -139
  19. package/dist/types/mocks/MockFactory.d.ts +0 -53
  20. package/dist/types/mocks/utils.d.ts +0 -24
  21. package/dist/types/themes/portalPresets.d.ts +0 -9
  22. package/dist/types/types/api/auth.d.ts +0 -93
  23. package/dist/types/types/api/broker.d.ts +0 -421
  24. package/dist/types/types/api/core.d.ts +0 -46
  25. package/dist/types/types/api/errors.d.ts +0 -31
  26. package/dist/types/types/api/orders.d.ts +0 -39
  27. package/dist/types/types/api/portfolio.d.ts +0 -55
  28. package/dist/types/types/common/pagination.d.ts +0 -33
  29. package/dist/types/types/connect.d.ts +0 -58
  30. package/dist/types/types/index.d.ts +0 -13
  31. package/dist/types/types/portal.d.ts +0 -204
  32. package/dist/types/types/ui/theme.d.ts +0 -104
  33. package/dist/types/utils/brokerUtils.d.ts +0 -30
  34. package/dist/types/utils/errors.d.ts +0 -45
  35. package/dist/types/utils/events.d.ts +0 -12
  36. package/dist/types/utils/themeUtils.d.ts +0 -34
  37. package/src/core/client/ApiClient.ts +0 -2004
  38. package/src/core/client/FinaticConnect.ts +0 -1606
  39. package/src/core/portal/PortalUI.ts +0 -335
  40. package/src/index.d.ts +0 -23
  41. package/src/index.ts +0 -100
  42. package/src/lib/logger/index.ts +0 -3
  43. package/src/lib/logger/logger.ts +0 -332
  44. package/src/lib/logger/logger.types.ts +0 -34
  45. package/src/mocks/MockApiClient.ts +0 -1058
  46. package/src/mocks/MockDataProvider.ts +0 -986
  47. package/src/mocks/MockFactory.ts +0 -97
  48. package/src/mocks/utils.ts +0 -133
  49. package/src/themes/portalPresets.ts +0 -1307
  50. package/src/types/api/auth.ts +0 -112
  51. package/src/types/api/broker.ts +0 -461
  52. package/src/types/api/core.ts +0 -53
  53. package/src/types/api/errors.ts +0 -35
  54. package/src/types/api/orders.ts +0 -45
  55. package/src/types/api/portfolio.ts +0 -59
  56. package/src/types/common/pagination.ts +0 -164
  57. package/src/types/connect.ts +0 -56
  58. package/src/types/index.ts +0 -25
  59. package/src/types/portal.ts +0 -214
  60. package/src/types/ui/theme.ts +0 -105
  61. package/src/utils/brokerUtils.ts +0 -104
  62. package/src/utils/errors.ts +0 -104
  63. package/src/utils/events.ts +0 -66
  64. package/src/utils/themeUtils.ts +0 -165
@@ -1,335 +0,0 @@
1
- import { setupLogger, buildLoggerExtra, LoggerExtra } from '../../lib/logger';
2
-
3
- const portalLogger = setupLogger('FinaticClientSDK.PortalUI', undefined, {
4
- codebase: 'FinaticClientSDK',
5
- });
6
-
7
- export class PortalUI {
8
- private iframe: HTMLIFrameElement | null = null;
9
- private container: HTMLDivElement | null = null;
10
- private messageHandler: ((event: MessageEvent) => void) | null = null;
11
- private sessionId: string | null = null;
12
- private portalOrigin: string | null = null;
13
- private options?: {
14
- onSuccess?: (userId: string, tokens?: { access_token?: string; refresh_token?: string }) => void;
15
- onError?: (error: Error) => void;
16
- onClose?: () => void;
17
- onEvent?: (type: string, data: any) => void;
18
- };
19
- private originalBodyStyle: string | null = null;
20
-
21
- private readonly logger = portalLogger;
22
-
23
- constructor(portalUrl: string) {
24
- this.createContainer();
25
- }
26
-
27
- private buildLoggerExtra(functionName: string, metadata?: Record<string, unknown>): LoggerExtra {
28
- return {
29
- module: 'PortalUI',
30
- function: functionName,
31
- ...(metadata ? buildLoggerExtra(metadata) : {}),
32
- };
33
- }
34
-
35
- private createContainer(): void {
36
- this.logger.debug('Creating portal container and iframe', this.buildLoggerExtra('createContainer'));
37
- this.container = document.createElement('div');
38
- this.container.style.cssText = `
39
- position: fixed;
40
- top: 0;
41
- left: 0;
42
- width: 100%;
43
- height: 100%;
44
- background: rgba(0, 0, 0, 0.5);
45
- display: none;
46
- z-index: 9999;
47
- `;
48
-
49
- this.iframe = document.createElement('iframe');
50
- // Let the portal handle its own styling - only set essential attributes
51
- this.iframe.style.cssText = `
52
- position: absolute;
53
- top: 50%;
54
- left: 50%;
55
- transform: translate(-50%, -50%);
56
- width: 90%;
57
- max-width: 500px;
58
- height: 90%;
59
- max-height: 600px;
60
- border: none;
61
- border-radius: 24px;
62
- `;
63
-
64
- // Set security headers
65
- this.iframe.setAttribute('sandbox', 'allow-scripts allow-forms allow-popups allow-same-origin');
66
- this.iframe.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');
67
- this.iframe.setAttribute(
68
- 'allow',
69
- 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'
70
- );
71
-
72
- // Add CSP meta tag to allow Google Fonts and other required resources
73
- const meta = document.createElement('meta');
74
- meta.setAttribute('http-equiv', 'Content-Security-Policy');
75
- meta.setAttribute(
76
- 'content',
77
- `
78
- default-src 'self' https:;
79
- style-src 'self' 'unsafe-inline' https: https://fonts.googleapis.com https://fonts.gstatic.com https://cdn.jsdelivr.net;
80
- font-src 'self' https://fonts.gstatic.com;
81
- img-src 'self' data: https:;
82
- script-src 'self' 'unsafe-inline' 'unsafe-eval' https:;
83
- connect-src 'self' https:;
84
- frame-src 'self' https:;
85
- `
86
- .replace(/\s+/g, ' ')
87
- .trim()
88
- );
89
- this.iframe.contentDocument?.head.appendChild(meta);
90
-
91
- this.container.appendChild(this.iframe);
92
- document.body.appendChild(this.container);
93
- this.logger.debug('Portal container and iframe created successfully', this.buildLoggerExtra('createContainer'));
94
- }
95
-
96
- /**
97
- * Lock background scrolling by setting overflow: hidden on body
98
- */
99
- private lockScroll(): void {
100
- if (typeof document !== 'undefined' && document.body) {
101
- // Store original body style to restore later
102
- this.originalBodyStyle = document.body.style.cssText;
103
-
104
- // Add overflow: hidden to prevent scrolling
105
- document.body.style.overflow = 'hidden';
106
- document.body.style.position = 'fixed';
107
- document.body.style.width = '100%';
108
- document.body.style.top = `-${window.scrollY}px`;
109
-
110
- this.logger.debug('Background scroll locked', this.buildLoggerExtra('lockScroll'));
111
- }
112
- }
113
-
114
- /**
115
- * Unlock background scrolling by restoring original body style
116
- */
117
- private unlockScroll(): void {
118
- if (typeof document !== 'undefined' && document.body && this.originalBodyStyle !== null) {
119
- // Restore original body style
120
- document.body.style.cssText = this.originalBodyStyle;
121
-
122
- // Restore scroll position
123
- const scrollY = document.body.style.top;
124
- document.body.style.position = '';
125
- document.body.style.top = '';
126
- window.scrollTo(0, parseInt(scrollY || '0') * -1);
127
-
128
- this.originalBodyStyle = null;
129
- this.logger.debug('Background scroll unlocked', this.buildLoggerExtra('unlockScroll'));
130
- }
131
- }
132
-
133
- public show(
134
- url: string,
135
- sessionId: string,
136
- options: {
137
- onSuccess?: (userId: string) => void;
138
- onError?: (error: Error) => void;
139
- onClose?: () => void;
140
- onEvent?: (type: string, data: any) => void;
141
- } = {}
142
- ): void {
143
- if (!this.iframe || !this.container) {
144
- this.createContainer();
145
- }
146
-
147
- // Set portalOrigin to the actual portal URL's origin
148
- try {
149
- this.portalOrigin = new URL(url).origin;
150
- } catch (e) {
151
- this.portalOrigin = null;
152
- }
153
-
154
- this.sessionId = sessionId;
155
- this.options = options;
156
- this.container!.style.display = 'block';
157
- this.iframe!.src = url;
158
-
159
- // Lock background scrolling
160
- this.lockScroll();
161
-
162
- // Set up message handler
163
- this.messageHandler = this.handleMessage.bind(this);
164
- window.addEventListener('message', this.messageHandler);
165
- }
166
-
167
- public hide(): void {
168
- if (this.container) {
169
- this.container.style.display = 'none';
170
- }
171
- if (this.iframe) {
172
- this.iframe.src = '';
173
- }
174
- if (this.messageHandler) {
175
- window.removeEventListener('message', this.messageHandler);
176
- this.messageHandler = null;
177
- }
178
- this.sessionId = null;
179
-
180
- // Unlock background scrolling
181
- this.unlockScroll();
182
- }
183
-
184
- private handleMessage(event: MessageEvent): void {
185
- // Verify origin matches the portal URL
186
- if (!this.portalOrigin || event.origin !== this.portalOrigin) {
187
- this.logger.warn('Received message from unauthorized origin', this.buildLoggerExtra('handleMessage', {
188
- received_origin: event.origin,
189
- expected_origin: this.portalOrigin || 'unknown',
190
- }));
191
- return;
192
- }
193
-
194
- const { type, userId, access_token, refresh_token, error, height, data } = event.data;
195
- this.logger.debug('Received portal message', this.buildLoggerExtra('handleMessage', {
196
- message_type: type,
197
- has_data: Boolean(data),
198
- }));
199
-
200
- switch (type) {
201
- case 'portal-success': {
202
- // Handle both direct userId and data.userId formats
203
- const successUserId = userId || (data && data.userId);
204
- const tokens = {
205
- access_token: access_token || (data && data.access_token),
206
- refresh_token: refresh_token || (data && data.refresh_token)
207
- };
208
- this.handlePortalSuccess(successUserId, tokens);
209
- break;
210
- }
211
-
212
- case 'portal-error': {
213
- // Handle both direct error and data.message formats
214
- const errorMessage = error || (data && data.message);
215
- this.handlePortalError(errorMessage);
216
- break;
217
- }
218
-
219
- case 'portal-close':
220
- this.handlePortalClose();
221
- break;
222
-
223
- case 'event':
224
- this.handleGenericEvent(data);
225
- break;
226
-
227
- case 'resize':
228
- this.handleResize(height);
229
- break;
230
-
231
- // Legacy support for old message types
232
- case 'success':
233
- this.handleSuccess(userId);
234
- break;
235
-
236
- case 'error':
237
- this.handleError(error);
238
- break;
239
-
240
- case 'close':
241
- this.handleClose();
242
- break;
243
-
244
- default:
245
- this.logger.warn('Received unhandled message type', this.buildLoggerExtra('handleMessage', {
246
- message_type: type,
247
- }));
248
- }
249
- }
250
-
251
- private handlePortalSuccess(userId: string, tokens?: { access_token?: string; refresh_token?: string }): void {
252
- if (!userId) {
253
- this.logger.error('Missing userId in portal-success message', this.buildLoggerExtra('handlePortalSuccess'));
254
- return;
255
- }
256
-
257
- this.logger.info('Portal success - user connected', this.buildLoggerExtra('handlePortalSuccess', {
258
- user_id_present: Boolean(userId),
259
- tokens_provided: Boolean(tokens?.access_token && tokens?.refresh_token),
260
- }));
261
- if (tokens?.access_token && tokens?.refresh_token) {
262
- this.logger.debug('Tokens received for user', this.buildLoggerExtra('handlePortalSuccess', {
263
- tokens_provided: true,
264
- }));
265
- }
266
-
267
- // Pass userId to parent (SDK will handle tokens internally)
268
- this.options?.onSuccess?.(userId, tokens);
269
- }
270
-
271
- private handlePortalError(error: string): void {
272
- this.logger.error('Portal error received', this.buildLoggerExtra('handlePortalError', {
273
- error_message: error,
274
- }));
275
- this.options?.onError?.(new Error(error || 'Unknown portal error'));
276
- }
277
-
278
- private handlePortalClose(): void {
279
- this.logger.info('Portal closed by user', this.buildLoggerExtra('handlePortalClose'));
280
- this.options?.onClose?.();
281
- this.hide();
282
- }
283
-
284
- private handleGenericEvent(data: any): void {
285
- if (!data || !data.type) {
286
- this.logger.warn('Invalid event data received', this.buildLoggerExtra('handleGenericEvent', {
287
- has_type: Boolean(data?.type),
288
- }));
289
- return;
290
- }
291
-
292
- this.logger.debug('Generic event received', this.buildLoggerExtra('handleGenericEvent', {
293
- event_type: data.type,
294
- payload_present: Boolean(data.data),
295
- }));
296
-
297
- // Emit the event to be handled by the SDK
298
- // This will be implemented in FinaticConnect
299
- if (this.options?.onEvent) {
300
- this.options.onEvent(data.type, data.data);
301
- }
302
- }
303
-
304
- private handleSuccess(userId: string): void {
305
- if (!userId) {
306
- this.logger.error('Missing required fields in success message', this.buildLoggerExtra('handleSuccess'));
307
- return;
308
- }
309
-
310
- // Pass userId to parent
311
- this.options?.onSuccess?.(userId);
312
- }
313
-
314
- private handleError(error: string): void {
315
- this.logger.error('Received portal error message', this.buildLoggerExtra('handleError', {
316
- error_message: error,
317
- }));
318
- this.options?.onError?.(new Error(error || 'Unknown error'));
319
- }
320
-
321
- private handleClose(): void {
322
- this.logger.debug('Received close message', this.buildLoggerExtra('handleClose'));
323
- this.options?.onClose?.();
324
- this.hide();
325
- }
326
-
327
- private handleResize(height: number): void {
328
- if (height && this.iframe) {
329
- this.logger.debug('Received resize message', this.buildLoggerExtra('handleResize', {
330
- height,
331
- }));
332
- this.iframe.style.height = `${height}px`;
333
- }
334
- }
335
- }
package/src/index.d.ts DELETED
@@ -1,23 +0,0 @@
1
- // Error types
2
- export interface TradeAccessDeniedError {
3
- success: false;
4
- response_data: null;
5
- message: string;
6
- status_code: 403;
7
- category: 'TRADE_ACCESS_DENIED';
8
- }
9
-
10
- export interface OrderNotFoundError {
11
- success: false;
12
- response_data: null;
13
- message: string;
14
- status_code: 404;
15
- category: 'ORDER_NOT_FOUND';
16
- }
17
-
18
- export interface ValidationError {
19
- success: false;
20
- response_data: null;
21
- message: string;
22
- status_code: 400;
23
- }
package/src/index.ts DELETED
@@ -1,100 +0,0 @@
1
- // Types (explicit re-exports to avoid conflicts)
2
- export type {
3
- // Core API types
4
- ApiConfig,
5
- ApiResponse,
6
- Order,
7
- OptionsOrder,
8
- BrokerAccount,
9
- PortfolioSnapshot,
10
- PerformanceMetrics,
11
- UserToken,
12
- Holding,
13
- Portfolio,
14
- PortalResponse,
15
- SessionInitResponse,
16
- SessionResponse,
17
- OtpRequestResponse,
18
- OtpVerifyResponse,
19
- PortalUrlResponse,
20
- SessionValidationResponse,
21
- SessionAuthenticateResponse,
22
- RequestHeaders,
23
- SessionStatus,
24
- BrokerOrderParams,
25
- BrokerExtras,
26
- CryptoOrderOptions,
27
- OptionsOrderOptions,
28
- OrderResponse,
29
- TradingContext,
30
- DeviceInfo,
31
- BrokerOrder,
32
- BrokerPosition,
33
- BrokerBalance,
34
- BrokerDataOptions,
35
- BrokerInfo,
36
- TokenInfo,
37
- RefreshTokenRequest,
38
- RefreshTokenResponse,
39
- AccountsFilter,
40
- OrdersFilter,
41
- PositionsFilter,
42
- BalancesFilter,
43
- BrokerDataOrder,
44
- BrokerDataPosition,
45
- BrokerDataAccount,
46
- FilteredOrdersResponse,
47
- FilteredPositionsResponse,
48
- FilteredAccountsResponse,
49
- FilteredBalancesResponse,
50
- BrokerConnection,
51
- OrderFill,
52
- OrderEvent,
53
- OrderLeg,
54
- OrderGroup,
55
- OrderGroupOrder,
56
- PositionLot,
57
- PositionLotFill,
58
- OrderFillsFilter,
59
- OrderEventsFilter,
60
- OrderGroupsFilter,
61
- PositionLotsFilter,
62
- PositionLotFillsFilter,
63
- } from './types';
64
-
65
- export type { FinaticConnectOptions, FinaticUserToken, PortalMessage } from './types/connect';
66
- export type {
67
- PortalProps,
68
- PortalTheme,
69
- PortalThemeConfig,
70
- PortalThemePreset,
71
- } from './types/portal';
72
-
73
- // Error types
74
- export type {
75
- TradeAccessDeniedError,
76
- OrderNotFoundError,
77
- ValidationError,
78
- } from './types/api/errors';
79
-
80
- // Main SDK classes
81
- export { ApiClient } from './core/client/ApiClient';
82
- export { FinaticConnect } from './core/client/FinaticConnect';
83
-
84
- // Supabase configuration
85
- // Supabase export removed - SDK no longer depends on Supabase
86
-
87
- // Core types and classes
88
- export { PaginatedResult } from './types/common/pagination';
89
-
90
- // Utilities
91
- export * from './utils/errors';
92
- export * from './utils/events';
93
- export * from './utils/themeUtils';
94
- export * from './lib/logger';
95
-
96
- // Theme presets
97
- export { portalThemePresets } from './themes/portalPresets';
98
-
99
- // Mocks (optional, for testing) - removed from main export to reduce bundle size
100
- // export { MockFactory } from './mocks/MockFactory';
@@ -1,3 +0,0 @@
1
- export * from './logger';
2
- export * from './logger.types';
3
-