@finatic/client 0.0.139 → 0.0.141
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 +335 -446
- package/dist/index.d.ts +272 -515
- package/dist/index.js +531 -449
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +532 -449
- package/dist/index.mjs.map +1 -1
- package/dist/types/core/client/ApiClient.d.ts +81 -27
- package/dist/types/core/client/FinaticConnect.d.ts +53 -103
- package/dist/types/index.d.ts +1 -2
- package/dist/types/mocks/MockApiClient.d.ts +2 -4
- package/dist/types/mocks/utils.d.ts +0 -5
- package/dist/types/types/api/auth.d.ts +12 -30
- package/dist/types/types/api/broker.d.ts +117 -1
- package/package.json +7 -3
- package/src/core/client/ApiClient.ts +1978 -0
- package/src/core/client/FinaticConnect.ts +1557 -0
- package/src/core/portal/PortalUI.ts +300 -0
- package/src/index.d.ts +23 -0
- package/src/index.ts +99 -0
- package/src/mocks/MockApiClient.ts +1032 -0
- package/src/mocks/MockDataProvider.ts +986 -0
- package/src/mocks/MockFactory.ts +97 -0
- package/src/mocks/utils.ts +133 -0
- package/src/themes/portalPresets.ts +1307 -0
- package/src/types/api/auth.ts +112 -0
- package/src/types/api/broker.ts +461 -0
- package/src/types/api/core.ts +53 -0
- package/src/types/api/errors.ts +35 -0
- package/src/types/api/orders.ts +45 -0
- package/src/types/api/portfolio.ts +59 -0
- package/src/types/common/pagination.ts +138 -0
- package/src/types/connect.ts +56 -0
- package/src/types/index.ts +25 -0
- package/src/types/portal.ts +214 -0
- package/src/types/ui/theme.ts +105 -0
- package/src/utils/brokerUtils.ts +85 -0
- package/src/utils/errors.ts +104 -0
- package/src/utils/events.ts +54 -0
- package/src/utils/themeUtils.ts +146 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portfolio-related types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface PortfolioSnapshot {
|
|
6
|
+
timestamp: string;
|
|
7
|
+
totalValue: number;
|
|
8
|
+
cash: number;
|
|
9
|
+
equity: number;
|
|
10
|
+
positions: {
|
|
11
|
+
symbol: string;
|
|
12
|
+
quantity: number;
|
|
13
|
+
averagePrice: number;
|
|
14
|
+
currentPrice: number;
|
|
15
|
+
marketValue: number;
|
|
16
|
+
unrealizedPnL: number;
|
|
17
|
+
}[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PerformanceMetrics {
|
|
21
|
+
totalReturn: number;
|
|
22
|
+
dailyReturn: number;
|
|
23
|
+
weeklyReturn: number;
|
|
24
|
+
monthlyReturn: number;
|
|
25
|
+
yearlyReturn: number;
|
|
26
|
+
maxDrawdown: number;
|
|
27
|
+
sharpeRatio: number;
|
|
28
|
+
beta: number;
|
|
29
|
+
alpha: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface Holding {
|
|
33
|
+
symbol: string;
|
|
34
|
+
quantity: number;
|
|
35
|
+
averagePrice: number;
|
|
36
|
+
currentPrice: number;
|
|
37
|
+
marketValue: number;
|
|
38
|
+
unrealizedPnL: number;
|
|
39
|
+
realizedPnL: number;
|
|
40
|
+
costBasis: number;
|
|
41
|
+
currency: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface Portfolio {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
type: string;
|
|
48
|
+
status: string;
|
|
49
|
+
cash: number;
|
|
50
|
+
buyingPower: number;
|
|
51
|
+
equity: number;
|
|
52
|
+
longMarketValue: number;
|
|
53
|
+
shortMarketValue: number;
|
|
54
|
+
initialMargin: number;
|
|
55
|
+
maintenanceMargin: number;
|
|
56
|
+
lastEquity: number;
|
|
57
|
+
positions: Holding[];
|
|
58
|
+
performance: PerformanceMetrics;
|
|
59
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pagination-related types and classes
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ApiPaginationInfo {
|
|
6
|
+
has_more: boolean;
|
|
7
|
+
next_offset: number;
|
|
8
|
+
current_offset: number;
|
|
9
|
+
limit: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PaginationMetadata {
|
|
13
|
+
hasMore: boolean;
|
|
14
|
+
nextOffset: number;
|
|
15
|
+
currentOffset: number;
|
|
16
|
+
limit: number;
|
|
17
|
+
currentPage: number;
|
|
18
|
+
hasNext: boolean;
|
|
19
|
+
hasPrevious: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class PaginatedResult<T> {
|
|
23
|
+
public readonly data: T;
|
|
24
|
+
public readonly metadata: PaginationMetadata;
|
|
25
|
+
private navigationCallback?: (offset: number, limit: number) => Promise<PaginatedResult<T>>;
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
data: T,
|
|
29
|
+
paginationInfo: ApiPaginationInfo,
|
|
30
|
+
navigationCallback?: (offset: number, limit: number) => Promise<PaginatedResult<T>>
|
|
31
|
+
) {
|
|
32
|
+
this.data = data;
|
|
33
|
+
this.navigationCallback = navigationCallback;
|
|
34
|
+
this.metadata = {
|
|
35
|
+
hasMore: paginationInfo.has_more,
|
|
36
|
+
nextOffset: paginationInfo.next_offset,
|
|
37
|
+
currentOffset: paginationInfo.current_offset,
|
|
38
|
+
limit: paginationInfo.limit,
|
|
39
|
+
currentPage: Math.floor(paginationInfo.current_offset / paginationInfo.limit) + 1,
|
|
40
|
+
hasNext: paginationInfo.has_more,
|
|
41
|
+
hasPrevious: paginationInfo.current_offset > 0,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get hasNext(): boolean {
|
|
46
|
+
return this.metadata.hasNext;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get hasPrevious(): boolean {
|
|
50
|
+
return this.metadata.hasPrevious;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get currentPage(): number {
|
|
54
|
+
return this.metadata.currentPage;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async nextPage(): Promise<PaginatedResult<T> | null> {
|
|
58
|
+
if (!this.hasNext || !this.navigationCallback) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
return await this.navigationCallback(this.metadata.nextOffset, this.metadata.limit);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Error fetching next page:', error);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async previousPage(): Promise<PaginatedResult<T> | null> {
|
|
71
|
+
if (!this.hasPrevious || !this.navigationCallback) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const previousOffset = Math.max(0, this.metadata.currentOffset - this.metadata.limit);
|
|
76
|
+
try {
|
|
77
|
+
return await this.navigationCallback(previousOffset, this.metadata.limit);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error('Error fetching previous page:', error);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async goToPage(pageNumber: number): Promise<PaginatedResult<T> | null> {
|
|
85
|
+
if (!this.navigationCallback || pageNumber < 1) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const offset = (pageNumber - 1) * this.metadata.limit;
|
|
90
|
+
try {
|
|
91
|
+
return await this.navigationCallback(offset, this.metadata.limit);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error('Error fetching page:', pageNumber, error);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async firstPage(): Promise<PaginatedResult<T> | null> {
|
|
99
|
+
if (!this.navigationCallback) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
return await this.navigationCallback(0, this.metadata.limit);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('Error fetching first page:', error);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async lastPage(): Promise<PaginatedResult<T> | null> {
|
|
112
|
+
if (!this.navigationCallback) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const findLast = async (page: PaginatedResult<T>): Promise<PaginatedResult<T>> => {
|
|
117
|
+
if (!page.hasNext) {
|
|
118
|
+
return page;
|
|
119
|
+
}
|
|
120
|
+
const nextPage = await page.nextPage();
|
|
121
|
+
if (!nextPage) {
|
|
122
|
+
return page;
|
|
123
|
+
}
|
|
124
|
+
return findLast(nextPage);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
return await findLast(this);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('Error fetching last page:', error);
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
getPaginationInfo(): string {
|
|
136
|
+
return `Page ${this.currentPage} (${this.metadata.currentOffset + 1}-${this.metadata.currentOffset + this.metadata.limit})`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Theme } from './ui/theme';
|
|
2
|
+
import { UserToken } from './api/auth';
|
|
3
|
+
import { PortalTheme } from './portal';
|
|
4
|
+
|
|
5
|
+
export interface FinaticConnectOptions {
|
|
6
|
+
/** The portal token from your backend */
|
|
7
|
+
token: string;
|
|
8
|
+
/** Optional base URL for API requests */
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
/** Optional origin for the portal */
|
|
11
|
+
origin?: string;
|
|
12
|
+
/** Callback when user successfully connects */
|
|
13
|
+
onSuccess?: (tokens: UserToken) => void;
|
|
14
|
+
/** Callback when an error occurs */
|
|
15
|
+
onError?: (error: Error) => void;
|
|
16
|
+
/** Callback when the portal is closed */
|
|
17
|
+
onClose?: () => void;
|
|
18
|
+
/** Optional theme configuration */
|
|
19
|
+
theme?: Theme;
|
|
20
|
+
/** Callback when tokens are received */
|
|
21
|
+
onTokensReceived?: (tokens: { access_token?: string; refresh_token?: string }) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface FinaticUserToken {
|
|
25
|
+
accessToken: string;
|
|
26
|
+
refreshToken: string;
|
|
27
|
+
userId: string;
|
|
28
|
+
companyId: string;
|
|
29
|
+
expiresAt: Date;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PortalMessage {
|
|
33
|
+
type: 'success' | 'error' | 'close' | 'resize';
|
|
34
|
+
userId?: string;
|
|
35
|
+
error?: string;
|
|
36
|
+
height?: number;
|
|
37
|
+
access_token?: string;
|
|
38
|
+
refresh_token?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface PortalOptions {
|
|
42
|
+
/** Callback when user successfully connects */
|
|
43
|
+
onSuccess?: (userId: string, tokens?: { access_token?: string; refresh_token?: string }) => void;
|
|
44
|
+
/** Callback when an error occurs */
|
|
45
|
+
onError?: (error: Error) => void;
|
|
46
|
+
/** Callback when the portal is closed */
|
|
47
|
+
onClose?: () => void;
|
|
48
|
+
/** Callback when portal events occur */
|
|
49
|
+
onEvent?: (type: string, data: any) => void;
|
|
50
|
+
/** Optional theme configuration for the portal */
|
|
51
|
+
theme?: PortalTheme;
|
|
52
|
+
/** Optional list of broker names to filter by (only these brokers will be shown) */
|
|
53
|
+
brokers?: string[];
|
|
54
|
+
/** Optional email address to prefill in the portal */
|
|
55
|
+
email?: string;
|
|
56
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main types barrel export
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Core API types
|
|
6
|
+
export * from './api/core';
|
|
7
|
+
export * from './api/auth';
|
|
8
|
+
export * from './api/broker';
|
|
9
|
+
export * from './api/orders';
|
|
10
|
+
export * from './api/portfolio';
|
|
11
|
+
|
|
12
|
+
// UI types
|
|
13
|
+
export * from './ui/theme';
|
|
14
|
+
|
|
15
|
+
// Common types
|
|
16
|
+
export * from './common/pagination';
|
|
17
|
+
|
|
18
|
+
// Connect types
|
|
19
|
+
export * from './connect';
|
|
20
|
+
|
|
21
|
+
// Re-export DeviceInfo for backward compatibility
|
|
22
|
+
export type { DeviceInfo } from './api/auth';
|
|
23
|
+
|
|
24
|
+
// Explicit re-export of SessionResponse to ensure it's available
|
|
25
|
+
export type { SessionResponse } from './api/auth';
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { Theme } from './ui/theme';
|
|
2
|
+
|
|
3
|
+
export interface PortalConfig {
|
|
4
|
+
width?: string;
|
|
5
|
+
height?: string;
|
|
6
|
+
position?: 'center' | 'top' | 'bottom';
|
|
7
|
+
zIndex?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface PortalThemeConfig {
|
|
11
|
+
mode?: 'dark' | 'light' | 'auto';
|
|
12
|
+
colors?: {
|
|
13
|
+
background?: {
|
|
14
|
+
primary?: string; // Main background color
|
|
15
|
+
secondary?: string; // Secondary background color
|
|
16
|
+
tertiary?: string; // Tertiary background color
|
|
17
|
+
accent?: string; // Accent background color
|
|
18
|
+
glass?: string; // Glassmorphism background
|
|
19
|
+
};
|
|
20
|
+
status?: {
|
|
21
|
+
connected?: string; // Connected status color
|
|
22
|
+
disconnected?: string; // Disconnected status color
|
|
23
|
+
warning?: string; // Warning status color
|
|
24
|
+
pending?: string; // Pending status color
|
|
25
|
+
error?: string; // Error status color
|
|
26
|
+
success?: string; // Success status color
|
|
27
|
+
};
|
|
28
|
+
text?: {
|
|
29
|
+
primary?: string; // Primary text color
|
|
30
|
+
secondary?: string; // Secondary text color
|
|
31
|
+
muted?: string; // Muted text color
|
|
32
|
+
inverse?: string; // Inverse text color
|
|
33
|
+
};
|
|
34
|
+
border?: {
|
|
35
|
+
primary?: string; // Primary border color
|
|
36
|
+
secondary?: string; // Secondary border color
|
|
37
|
+
hover?: string; // Hover border color
|
|
38
|
+
focus?: string; // Focus border color
|
|
39
|
+
accent?: string; // Accent border color
|
|
40
|
+
};
|
|
41
|
+
input?: {
|
|
42
|
+
background?: string; // Input background color
|
|
43
|
+
border?: string; // Input border color
|
|
44
|
+
borderFocus?: string; // Input focus border color
|
|
45
|
+
text?: string; // Input text color
|
|
46
|
+
placeholder?: string; // Input placeholder color
|
|
47
|
+
};
|
|
48
|
+
button?: {
|
|
49
|
+
primary?: {
|
|
50
|
+
background?: string; // Primary button background
|
|
51
|
+
text?: string; // Primary button text
|
|
52
|
+
hover?: string; // Primary button hover
|
|
53
|
+
active?: string; // Primary button active
|
|
54
|
+
};
|
|
55
|
+
secondary?: {
|
|
56
|
+
background?: string; // Secondary button background
|
|
57
|
+
text?: string; // Secondary button text
|
|
58
|
+
border?: string; // Secondary button border
|
|
59
|
+
hover?: string; // Secondary button hover
|
|
60
|
+
active?: string; // Secondary button active
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
typography?: {
|
|
65
|
+
fontFamily?: {
|
|
66
|
+
primary?: string;
|
|
67
|
+
secondary?: string;
|
|
68
|
+
};
|
|
69
|
+
fontSize?: {
|
|
70
|
+
xs?: string;
|
|
71
|
+
sm?: string;
|
|
72
|
+
base?: string;
|
|
73
|
+
lg?: string;
|
|
74
|
+
xl?: string;
|
|
75
|
+
'2xl'?: string;
|
|
76
|
+
'3xl'?: string;
|
|
77
|
+
'4xl'?: string;
|
|
78
|
+
};
|
|
79
|
+
fontWeight?: {
|
|
80
|
+
normal?: number;
|
|
81
|
+
medium?: number;
|
|
82
|
+
semibold?: number;
|
|
83
|
+
bold?: number;
|
|
84
|
+
extrabold?: number;
|
|
85
|
+
};
|
|
86
|
+
lineHeight?: {
|
|
87
|
+
tight?: string;
|
|
88
|
+
normal?: string;
|
|
89
|
+
relaxed?: string;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
spacing?: {
|
|
93
|
+
xs?: string;
|
|
94
|
+
sm?: string;
|
|
95
|
+
md?: string;
|
|
96
|
+
lg?: string;
|
|
97
|
+
xl?: string;
|
|
98
|
+
'2xl'?: string;
|
|
99
|
+
'3xl'?: string;
|
|
100
|
+
};
|
|
101
|
+
layout?: {
|
|
102
|
+
containerMaxWidth?: string;
|
|
103
|
+
gridGap?: string;
|
|
104
|
+
cardPadding?: string;
|
|
105
|
+
borderRadius?: {
|
|
106
|
+
sm?: string;
|
|
107
|
+
md?: string;
|
|
108
|
+
lg?: string;
|
|
109
|
+
xl?: string;
|
|
110
|
+
'2xl'?: string;
|
|
111
|
+
full?: string;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
components?: {
|
|
115
|
+
brokerCard?: {
|
|
116
|
+
width?: string;
|
|
117
|
+
height?: string;
|
|
118
|
+
logoSize?: string;
|
|
119
|
+
padding?: string;
|
|
120
|
+
};
|
|
121
|
+
statusIndicator?: {
|
|
122
|
+
size?: string;
|
|
123
|
+
glowIntensity?: number;
|
|
124
|
+
};
|
|
125
|
+
modal?: {
|
|
126
|
+
background?: string;
|
|
127
|
+
backdrop?: string;
|
|
128
|
+
};
|
|
129
|
+
brokerCardModern?: {
|
|
130
|
+
width?: string;
|
|
131
|
+
height?: string;
|
|
132
|
+
padding?: string;
|
|
133
|
+
logoSize?: string;
|
|
134
|
+
statusSize?: string;
|
|
135
|
+
};
|
|
136
|
+
connectButton?: {
|
|
137
|
+
width?: string;
|
|
138
|
+
height?: string;
|
|
139
|
+
};
|
|
140
|
+
themeSwitcher?: {
|
|
141
|
+
indicatorSize?: string;
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
effects?: {
|
|
145
|
+
glassmorphism?: {
|
|
146
|
+
enabled?: boolean;
|
|
147
|
+
blur?: string;
|
|
148
|
+
opacity?: number;
|
|
149
|
+
border?: string;
|
|
150
|
+
};
|
|
151
|
+
animations?: {
|
|
152
|
+
enabled?: boolean;
|
|
153
|
+
duration?: {
|
|
154
|
+
fast?: string;
|
|
155
|
+
normal?: string;
|
|
156
|
+
slow?: string;
|
|
157
|
+
};
|
|
158
|
+
easing?: {
|
|
159
|
+
default?: string;
|
|
160
|
+
smooth?: string;
|
|
161
|
+
bounce?: string;
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
shadows?: {
|
|
165
|
+
sm?: string;
|
|
166
|
+
md?: string;
|
|
167
|
+
lg?: string;
|
|
168
|
+
xl?: string;
|
|
169
|
+
card?: string;
|
|
170
|
+
cardHover?: string;
|
|
171
|
+
glow?: string;
|
|
172
|
+
focus?: string;
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
branding?: {
|
|
176
|
+
logo?: string;
|
|
177
|
+
companyName?: string;
|
|
178
|
+
favicon?: string;
|
|
179
|
+
primaryColor?: string;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Glow effect customization
|
|
183
|
+
glow?: {
|
|
184
|
+
primary?: string; // Primary glow color
|
|
185
|
+
secondary?: string; // Secondary glow color
|
|
186
|
+
card?: string; // Card glow effect
|
|
187
|
+
cardHover?: string; // Card hover glow
|
|
188
|
+
button?: string; // Button glow effect
|
|
189
|
+
focus?: string; // Focus ring glow
|
|
190
|
+
scrollbar?: string; // Scrollbar glow
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// Gradient customization
|
|
194
|
+
gradients?: {
|
|
195
|
+
start?: string; // Gradient start color
|
|
196
|
+
end?: string; // Gradient end color
|
|
197
|
+
hoverStart?: string; // Hover gradient start
|
|
198
|
+
hoverEnd?: string; // Hover gradient end
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type PortalThemePreset = 'dark' | 'light' | 'corporateBlue' | 'purple' | 'green' | 'orange';
|
|
203
|
+
|
|
204
|
+
export interface PortalTheme {
|
|
205
|
+
preset?: PortalThemePreset;
|
|
206
|
+
custom?: PortalThemeConfig;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface PortalProps {
|
|
210
|
+
config: PortalConfig;
|
|
211
|
+
onClose?: () => void;
|
|
212
|
+
onReady?: () => void;
|
|
213
|
+
onError?: (error: Error) => void;
|
|
214
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme-related types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface Theme {
|
|
6
|
+
mode: 'light' | 'dark';
|
|
7
|
+
primaryColor: string;
|
|
8
|
+
colors: {
|
|
9
|
+
primary: string;
|
|
10
|
+
secondary: string;
|
|
11
|
+
background: {
|
|
12
|
+
primary: string;
|
|
13
|
+
secondary: string;
|
|
14
|
+
tertiary: string;
|
|
15
|
+
};
|
|
16
|
+
text: {
|
|
17
|
+
primary: string;
|
|
18
|
+
secondary: string;
|
|
19
|
+
disabled: string;
|
|
20
|
+
error: string;
|
|
21
|
+
success: string;
|
|
22
|
+
warning: string;
|
|
23
|
+
};
|
|
24
|
+
border: {
|
|
25
|
+
light: string;
|
|
26
|
+
medium: string;
|
|
27
|
+
dark: string;
|
|
28
|
+
};
|
|
29
|
+
status: {
|
|
30
|
+
active: string;
|
|
31
|
+
inactive: string;
|
|
32
|
+
pending: string;
|
|
33
|
+
error: string;
|
|
34
|
+
success: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
typography: {
|
|
38
|
+
fontFamily: string;
|
|
39
|
+
fontSize: {
|
|
40
|
+
xs: string;
|
|
41
|
+
sm: string;
|
|
42
|
+
base: string;
|
|
43
|
+
lg: string;
|
|
44
|
+
xl: string;
|
|
45
|
+
'2xl': string;
|
|
46
|
+
};
|
|
47
|
+
fontWeight: {
|
|
48
|
+
light: number;
|
|
49
|
+
normal: number;
|
|
50
|
+
medium: number;
|
|
51
|
+
semibold: number;
|
|
52
|
+
bold: number;
|
|
53
|
+
};
|
|
54
|
+
lineHeight: {
|
|
55
|
+
none: number;
|
|
56
|
+
tight: number;
|
|
57
|
+
normal: number;
|
|
58
|
+
relaxed: number;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
spacing: {
|
|
62
|
+
xs: string;
|
|
63
|
+
sm: string;
|
|
64
|
+
md: string;
|
|
65
|
+
lg: string;
|
|
66
|
+
xl: string;
|
|
67
|
+
'2xl': string;
|
|
68
|
+
};
|
|
69
|
+
animation: {
|
|
70
|
+
duration: {
|
|
71
|
+
fast: string;
|
|
72
|
+
normal: string;
|
|
73
|
+
slow: string;
|
|
74
|
+
};
|
|
75
|
+
easing: {
|
|
76
|
+
linear: string;
|
|
77
|
+
easeIn: string;
|
|
78
|
+
easeOut: string;
|
|
79
|
+
easeInOut: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
components: {
|
|
83
|
+
button: {
|
|
84
|
+
borderRadius: string;
|
|
85
|
+
padding: string;
|
|
86
|
+
fontSize: string;
|
|
87
|
+
fontWeight: number;
|
|
88
|
+
};
|
|
89
|
+
input: {
|
|
90
|
+
borderRadius: string;
|
|
91
|
+
padding: string;
|
|
92
|
+
fontSize: string;
|
|
93
|
+
};
|
|
94
|
+
card: {
|
|
95
|
+
borderRadius: string;
|
|
96
|
+
padding: string;
|
|
97
|
+
shadow: string;
|
|
98
|
+
};
|
|
99
|
+
modal: {
|
|
100
|
+
borderRadius: string;
|
|
101
|
+
padding: string;
|
|
102
|
+
backdrop: string;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Broker filtering utility functions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Supported broker names and their corresponding IDs (including aliases)
|
|
6
|
+
const SUPPORTED_BROKERS: Record<string, string> = {
|
|
7
|
+
'alpaca': 'alpaca',
|
|
8
|
+
'robinhood': 'robinhood',
|
|
9
|
+
'tasty_trade': 'tasty_trade',
|
|
10
|
+
'ninja_trader': 'ninja_trader',
|
|
11
|
+
'tradovate': 'tradovate', // Alias for ninja_trader
|
|
12
|
+
'interactive_brokers': 'interactive_brokers',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Convert broker names to broker IDs, filtering out unsupported ones
|
|
17
|
+
* @param brokerNames Array of broker names to convert
|
|
18
|
+
* @returns Object containing valid broker IDs and any warnings about unsupported names
|
|
19
|
+
*/
|
|
20
|
+
export function convertBrokerNamesToIds(brokerNames: string[]): {
|
|
21
|
+
brokerIds: string[];
|
|
22
|
+
warnings: string[];
|
|
23
|
+
} {
|
|
24
|
+
const brokerIds: string[] = [];
|
|
25
|
+
const warnings: string[] = [];
|
|
26
|
+
|
|
27
|
+
for (const brokerName of brokerNames) {
|
|
28
|
+
const brokerId = SUPPORTED_BROKERS[brokerName.toLowerCase()];
|
|
29
|
+
if (brokerId) {
|
|
30
|
+
brokerIds.push(brokerId);
|
|
31
|
+
} else {
|
|
32
|
+
warnings.push(`Broker name '${brokerName}' is not supported. Supported brokers: ${Object.keys(SUPPORTED_BROKERS).join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return { brokerIds, warnings };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Append broker filter parameters to a portal URL
|
|
41
|
+
* @param baseUrl The base portal URL (may already have query parameters)
|
|
42
|
+
* @param brokerNames Array of broker names to filter by
|
|
43
|
+
* @returns The portal URL with broker filter parameters appended
|
|
44
|
+
*/
|
|
45
|
+
export function appendBrokerFilterToURL(baseUrl: string, brokerNames?: string[]): string {
|
|
46
|
+
if (!brokerNames || brokerNames.length === 0) {
|
|
47
|
+
return baseUrl;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const url = new URL(baseUrl);
|
|
52
|
+
const { brokerIds, warnings } = convertBrokerNamesToIds(brokerNames);
|
|
53
|
+
|
|
54
|
+
// Log warnings for unsupported broker names
|
|
55
|
+
warnings.forEach(warning => console.warn(`[FinaticConnect] ${warning}`));
|
|
56
|
+
|
|
57
|
+
// Only add broker filter if we have valid broker IDs
|
|
58
|
+
if (brokerIds.length > 0) {
|
|
59
|
+
const encodedBrokers = btoa(JSON.stringify(brokerIds));
|
|
60
|
+
url.searchParams.set('brokers', encodedBrokers);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return url.toString();
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Failed to append broker filter to URL:', error);
|
|
66
|
+
return baseUrl;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get list of supported broker names
|
|
72
|
+
* @returns Array of supported broker names
|
|
73
|
+
*/
|
|
74
|
+
export function getSupportedBrokerNames(): string[] {
|
|
75
|
+
return Object.keys(SUPPORTED_BROKERS);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check if a broker name is supported
|
|
80
|
+
* @param brokerName The broker name to check
|
|
81
|
+
* @returns True if the broker is supported, false otherwise
|
|
82
|
+
*/
|
|
83
|
+
export function isBrokerSupported(brokerName: string): boolean {
|
|
84
|
+
return brokerName.toLowerCase() in SUPPORTED_BROKERS;
|
|
85
|
+
}
|