@finatic/client 0.0.138 → 0.0.140

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 (40) hide show
  1. package/README.md +278 -461
  2. package/dist/index.d.ts +59 -516
  3. package/dist/index.js +337 -456
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +338 -456
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/types/core/client/ApiClient.d.ts +12 -26
  8. package/dist/types/core/client/FinaticConnect.d.ts +20 -103
  9. package/dist/types/index.d.ts +1 -2
  10. package/dist/types/mocks/MockApiClient.d.ts +2 -4
  11. package/dist/types/mocks/utils.d.ts +0 -5
  12. package/dist/types/types/api/auth.d.ts +12 -30
  13. package/dist/types/types/api/broker.d.ts +1 -1
  14. package/dist/types/types/connect.d.ts +4 -1
  15. package/package.json +7 -3
  16. package/src/core/client/ApiClient.ts +1721 -0
  17. package/src/core/client/FinaticConnect.ts +1476 -0
  18. package/src/core/portal/PortalUI.ts +300 -0
  19. package/src/index.d.ts +23 -0
  20. package/src/index.ts +87 -0
  21. package/src/mocks/MockApiClient.ts +1032 -0
  22. package/src/mocks/MockDataProvider.ts +986 -0
  23. package/src/mocks/MockFactory.ts +97 -0
  24. package/src/mocks/utils.ts +133 -0
  25. package/src/themes/portalPresets.ts +1307 -0
  26. package/src/types/api/auth.ts +112 -0
  27. package/src/types/api/broker.ts +330 -0
  28. package/src/types/api/core.ts +53 -0
  29. package/src/types/api/errors.ts +35 -0
  30. package/src/types/api/orders.ts +45 -0
  31. package/src/types/api/portfolio.ts +59 -0
  32. package/src/types/common/pagination.ts +138 -0
  33. package/src/types/connect.ts +56 -0
  34. package/src/types/index.ts +25 -0
  35. package/src/types/portal.ts +214 -0
  36. package/src/types/ui/theme.ts +105 -0
  37. package/src/utils/brokerUtils.ts +85 -0
  38. package/src/utils/errors.ts +104 -0
  39. package/src/utils/events.ts +54 -0
  40. package/src/utils/themeUtils.ts +146 -0
@@ -0,0 +1,104 @@
1
+ export class BaseError extends Error {
2
+ constructor(
3
+ message: string,
4
+ public readonly code: string = 'UNKNOWN_ERROR'
5
+ ) {
6
+ super(message);
7
+ this.name = this.constructor.name;
8
+ }
9
+ }
10
+
11
+ export class ApiError extends BaseError {
12
+ constructor(
13
+ public readonly status: number,
14
+ message: string,
15
+ public readonly details?: Record<string, any>
16
+ ) {
17
+ super(message, `API_ERROR_${status}`);
18
+ this.name = 'ApiError';
19
+ }
20
+ }
21
+
22
+ export class SessionError extends ApiError {
23
+ constructor(message: string, details?: Record<string, any>) {
24
+ super(400, message, details);
25
+ this.name = 'SessionError';
26
+ }
27
+ }
28
+
29
+ export class AuthenticationError extends ApiError {
30
+ constructor(message: string, details?: Record<string, any>) {
31
+ super(401, message, details);
32
+ this.name = 'AuthenticationError';
33
+ }
34
+ }
35
+
36
+ export class AuthorizationError extends ApiError {
37
+ constructor(message: string, details?: Record<string, any>) {
38
+ super(403, message, details);
39
+ this.name = 'AuthorizationError';
40
+ }
41
+ }
42
+
43
+ export class RateLimitError extends ApiError {
44
+ constructor(message: string, details?: Record<string, any>) {
45
+ super(429, message, details);
46
+ this.name = 'RateLimitError';
47
+ }
48
+ }
49
+
50
+ export class TokenError extends BaseError {
51
+ constructor(message: string) {
52
+ super(message, 'TOKEN_ERROR');
53
+ this.name = 'TokenError';
54
+ }
55
+ }
56
+
57
+ export class ValidationError extends BaseError {
58
+ constructor(message: string) {
59
+ super(message, 'VALIDATION_ERROR');
60
+ this.name = 'ValidationError';
61
+ }
62
+ }
63
+
64
+ export class NetworkError extends BaseError {
65
+ constructor(message: string) {
66
+ super(message, 'NETWORK_ERROR');
67
+ this.name = 'NetworkError';
68
+ }
69
+ }
70
+
71
+ export class SecurityError extends BaseError {
72
+ constructor(message: string) {
73
+ super(message, 'SECURITY_ERROR');
74
+ this.name = 'SecurityError';
75
+ }
76
+ }
77
+
78
+ export class CompanyAccessError extends ApiError {
79
+ constructor(message: string, details?: Record<string, any>) {
80
+ super(403, message, details);
81
+ this.name = 'CompanyAccessError';
82
+ }
83
+ }
84
+
85
+ export class OrderError extends ApiError {
86
+ constructor(message: string, details?: Record<string, any>) {
87
+ super(500, message, details);
88
+ this.name = 'OrderError';
89
+ }
90
+ }
91
+
92
+ export class OrderValidationError extends ApiError {
93
+ constructor(message: string, details?: Record<string, any>) {
94
+ super(400, message, details);
95
+ this.name = 'OrderValidationError';
96
+ }
97
+ }
98
+
99
+ export class TradingNotEnabledError extends ApiError {
100
+ constructor(message: string, details?: Record<string, any>) {
101
+ super(403, message, details);
102
+ this.name = 'TradingNotEnabledError';
103
+ }
104
+ }
@@ -0,0 +1,54 @@
1
+ type EventCallback = (...args: any[]) => void;
2
+
3
+ export class EventEmitter {
4
+ private events: Map<string, Set<EventCallback>> = new Map();
5
+
6
+ public on(event: string, callback: EventCallback): void {
7
+ if (!this.events.has(event)) {
8
+ this.events.set(event, new Set());
9
+ }
10
+ this.events.get(event)!.add(callback);
11
+ }
12
+
13
+ public off(event: string, callback: EventCallback): void {
14
+ if (this.events.has(event)) {
15
+ this.events.get(event)!.delete(callback);
16
+ }
17
+ }
18
+
19
+ public once(event: string, callback: EventCallback): void {
20
+ const onceCallback = (...args: any[]) => {
21
+ callback(...args);
22
+ this.off(event, onceCallback);
23
+ };
24
+ this.on(event, onceCallback);
25
+ }
26
+
27
+ public emit(event: string, ...args: any[]): void {
28
+ if (this.events.has(event)) {
29
+ this.events.get(event)!.forEach(callback => {
30
+ try {
31
+ callback(...args);
32
+ } catch (error) {
33
+ console.error(`Error in event handler for ${event}:`, error);
34
+ }
35
+ });
36
+ }
37
+ }
38
+
39
+ public removeAllListeners(event?: string): void {
40
+ if (event) {
41
+ this.events.delete(event);
42
+ } else {
43
+ this.events.clear();
44
+ }
45
+ }
46
+
47
+ public listenerCount(event: string): number {
48
+ return this.events.get(event)?.size || 0;
49
+ }
50
+
51
+ public listeners(event: string): EventCallback[] {
52
+ return Array.from(this.events.get(event) || []);
53
+ }
54
+ }
@@ -0,0 +1,146 @@
1
+ import { PortalTheme, PortalThemeConfig } from '../types/portal';
2
+ import { portalThemePresets } from '../themes/portalPresets';
3
+
4
+ /**
5
+ * Generate a portal URL with theme parameters
6
+ * @param baseUrl The base portal URL
7
+ * @param theme The theme configuration
8
+ * @returns The portal URL with theme parameters
9
+ */
10
+ export function generatePortalThemeURL(baseUrl: string, theme?: PortalTheme): string {
11
+ if (!theme) {
12
+ return baseUrl;
13
+ }
14
+
15
+ try {
16
+ const url = new URL(baseUrl);
17
+
18
+ if (theme.preset) {
19
+ // Use preset theme
20
+ url.searchParams.set('theme', theme.preset);
21
+ } else if (theme.custom) {
22
+ // Use custom theme
23
+ const encodedTheme = btoa(JSON.stringify(theme.custom));
24
+ url.searchParams.set('theme', 'custom');
25
+ url.searchParams.set('themeObject', encodedTheme);
26
+ }
27
+
28
+ return url.toString();
29
+ } catch (error) {
30
+ console.error('Failed to generate theme URL:', error);
31
+ return baseUrl;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Generate a portal URL with theme parameters, appending to existing query params
37
+ * @param baseUrl The base portal URL (may already have query parameters)
38
+ * @param theme The theme configuration
39
+ * @returns The portal URL with theme parameters appended
40
+ */
41
+ export function appendThemeToURL(baseUrl: string, theme?: PortalTheme): string {
42
+ if (!theme) {
43
+ return baseUrl;
44
+ }
45
+
46
+ try {
47
+ const url = new URL(baseUrl);
48
+
49
+ if (theme.preset) {
50
+ // Use preset theme
51
+ url.searchParams.set('theme', theme.preset);
52
+ } else if (theme.custom) {
53
+ // Use custom theme
54
+ const encodedTheme = btoa(JSON.stringify(theme.custom));
55
+ url.searchParams.set('theme', 'custom');
56
+ url.searchParams.set('themeObject', encodedTheme);
57
+ }
58
+
59
+ return url.toString();
60
+ } catch (error) {
61
+ console.error('Failed to append theme to URL:', error);
62
+ return baseUrl;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Get a theme configuration by preset name
68
+ * @param preset The preset theme name
69
+ * @returns The theme configuration or undefined if not found
70
+ */
71
+ export function getThemePreset(preset: string): PortalThemeConfig | undefined {
72
+ return portalThemePresets[preset];
73
+ }
74
+
75
+ /**
76
+ * Validate a custom theme configuration
77
+ * @param theme The theme configuration to validate
78
+ * @returns True if valid, false otherwise
79
+ */
80
+ export function validateCustomTheme(theme: PortalThemeConfig): boolean {
81
+ try {
82
+ // Only validate what's provided - everything else gets defaults
83
+ if (theme.mode && !['dark', 'light', 'auto'].includes(theme.mode)) {
84
+ return false;
85
+ }
86
+
87
+ // If colors are provided, validate the structure
88
+ if (theme.colors) {
89
+ // Check that any provided color sections have valid structure
90
+ const colorSections = ['background', 'status', 'text', 'border', 'input', 'button'];
91
+ for (const section of colorSections) {
92
+ const colorSection = theme.colors[section as keyof typeof theme.colors];
93
+ if (colorSection && typeof colorSection !== 'object') {
94
+ return false;
95
+ }
96
+ }
97
+ }
98
+
99
+ // If typography is provided, validate structure
100
+ if (theme.typography) {
101
+ if (theme.typography.fontSize && typeof theme.typography.fontSize !== 'object') {
102
+ return false;
103
+ }
104
+ if (theme.typography.fontWeight && typeof theme.typography.fontWeight !== 'object') {
105
+ return false;
106
+ }
107
+ }
108
+
109
+ // If effects are provided, validate structure
110
+ if (theme.effects) {
111
+ if (theme.effects.animations && typeof theme.effects.animations !== 'object') {
112
+ return false;
113
+ }
114
+ if (theme.effects.shadows && typeof theme.effects.shadows !== 'object') {
115
+ return false;
116
+ }
117
+ }
118
+
119
+ return true;
120
+ } catch (error) {
121
+ console.error('Theme validation error:', error);
122
+ return false;
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Create a custom theme from a preset with modifications
128
+ * @param preset The base preset theme
129
+ * @param modifications Partial theme modifications
130
+ * @returns The modified theme configuration
131
+ */
132
+ export function createCustomThemeFromPreset(
133
+ preset: string,
134
+ modifications: Partial<PortalThemeConfig>
135
+ ): PortalThemeConfig | null {
136
+ const baseTheme = getThemePreset(preset);
137
+ if (!baseTheme) {
138
+ console.error(`Preset theme '${preset}' not found`);
139
+ return null;
140
+ }
141
+
142
+ return {
143
+ ...baseTheme,
144
+ ...modifications,
145
+ };
146
+ }