@cranberry-money/shared-services 1.0.0

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 (50) hide show
  1. package/README.md +288 -0
  2. package/dist/adapters/MobileApiClient.d.ts +68 -0
  3. package/dist/adapters/MobileApiClient.d.ts.map +1 -0
  4. package/dist/adapters/MobileApiClient.js +240 -0
  5. package/dist/adapters/MobileTokenStorage.d.ts +43 -0
  6. package/dist/adapters/MobileTokenStorage.d.ts.map +1 -0
  7. package/dist/adapters/MobileTokenStorage.js +128 -0
  8. package/dist/adapters/WebApiClient.d.ts +28 -0
  9. package/dist/adapters/WebApiClient.d.ts.map +1 -0
  10. package/dist/adapters/WebApiClient.js +119 -0
  11. package/dist/adapters/WebTokenStorage.d.ts +38 -0
  12. package/dist/adapters/WebTokenStorage.d.ts.map +1 -0
  13. package/dist/adapters/WebTokenStorage.js +86 -0
  14. package/dist/auth/AuthManager.d.ts +81 -0
  15. package/dist/auth/AuthManager.d.ts.map +1 -0
  16. package/dist/auth/AuthManager.js +223 -0
  17. package/dist/auth/createAuthManager.d.ts +63 -0
  18. package/dist/auth/createAuthManager.d.ts.map +1 -0
  19. package/dist/auth/createAuthManager.js +103 -0
  20. package/dist/auth/useAuthManager.d.ts +66 -0
  21. package/dist/auth/useAuthManager.d.ts.map +1 -0
  22. package/dist/auth/useAuthManager.js +133 -0
  23. package/dist/core/BaseApiClient.d.ts +82 -0
  24. package/dist/core/BaseApiClient.d.ts.map +1 -0
  25. package/dist/core/BaseApiClient.js +89 -0
  26. package/dist/core/TokenStorage.d.ts +45 -0
  27. package/dist/core/TokenStorage.d.ts.map +1 -0
  28. package/dist/core/TokenStorage.js +23 -0
  29. package/dist/index.d.ts +19 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +23 -0
  32. package/dist/query/QueryClient.d.ts +82 -0
  33. package/dist/query/QueryClient.d.ts.map +1 -0
  34. package/dist/query/QueryClient.js +136 -0
  35. package/dist/query/useAuth.d.ts +64 -0
  36. package/dist/query/useAuth.d.ts.map +1 -0
  37. package/dist/query/useAuth.js +144 -0
  38. package/dist/query/usePortfolios.d.ts +79 -0
  39. package/dist/query/usePortfolios.d.ts.map +1 -0
  40. package/dist/query/usePortfolios.js +172 -0
  41. package/dist/services/AuthService.d.ts +75 -0
  42. package/dist/services/AuthService.d.ts.map +1 -0
  43. package/dist/services/AuthService.js +83 -0
  44. package/dist/services/BaseService.d.ts +48 -0
  45. package/dist/services/BaseService.d.ts.map +1 -0
  46. package/dist/services/BaseService.js +51 -0
  47. package/dist/services/PortfolioService.d.ts +100 -0
  48. package/dist/services/PortfolioService.d.ts.map +1 -0
  49. package/dist/services/PortfolioService.js +68 -0
  50. package/package.json +56 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Mobile-specific token storage using secure storage
3
+ *
4
+ * This implementation uses platform-secure storage mechanisms
5
+ * like iOS Keychain and Android Keystore via React Native libraries.
6
+ *
7
+ * For Expo: Uses Expo SecureStore
8
+ * For bare React Native: Would use @react-native-async-storage/async-storage
9
+ * with encryption or react-native-keychain
10
+ */
11
+ import { BaseTokenStorage } from '../core/TokenStorage';
12
+ // Keys for secure storage
13
+ const STORAGE_KEYS = {
14
+ ACCESS_TOKEN: 'myportfolio_access_token',
15
+ REFRESH_TOKEN: 'myportfolio_refresh_token',
16
+ };
17
+ export class MobileTokenStorage extends BaseTokenStorage {
18
+ constructor(secureStore) {
19
+ super();
20
+ this.secureStore = secureStore;
21
+ }
22
+ async storeTokens(tokens) {
23
+ if (!this.validateTokens(tokens)) {
24
+ throw new Error('Invalid token format');
25
+ }
26
+ try {
27
+ await Promise.all([
28
+ this.secureStore.setItemAsync(STORAGE_KEYS.ACCESS_TOKEN, tokens.access),
29
+ this.secureStore.setItemAsync(STORAGE_KEYS.REFRESH_TOKEN, tokens.refresh),
30
+ ]);
31
+ }
32
+ catch (error) {
33
+ throw new Error(`Failed to store tokens: ${error instanceof Error ? error.message : 'Unknown error'}`);
34
+ }
35
+ }
36
+ async retrieveTokens() {
37
+ try {
38
+ const [access, refresh] = await Promise.all([
39
+ this.secureStore.getItemAsync(STORAGE_KEYS.ACCESS_TOKEN),
40
+ this.secureStore.getItemAsync(STORAGE_KEYS.REFRESH_TOKEN),
41
+ ]);
42
+ if (!access || !refresh) {
43
+ return null;
44
+ }
45
+ const tokens = { access, refresh };
46
+ if (!this.validateTokens(tokens)) {
47
+ // Clear invalid tokens
48
+ await this.clearTokens();
49
+ return null;
50
+ }
51
+ return tokens;
52
+ }
53
+ catch (error) {
54
+ console.error('Failed to retrieve tokens:', error);
55
+ return null;
56
+ }
57
+ }
58
+ async clearTokens() {
59
+ try {
60
+ await Promise.all([
61
+ this.secureStore.deleteItemAsync(STORAGE_KEYS.ACCESS_TOKEN),
62
+ this.secureStore.deleteItemAsync(STORAGE_KEYS.REFRESH_TOKEN),
63
+ ]);
64
+ }
65
+ catch (error) {
66
+ console.error('Failed to clear tokens:', error);
67
+ // Don't throw - clearing should be idempotent
68
+ }
69
+ }
70
+ async hasTokens() {
71
+ try {
72
+ const [access, refresh] = await Promise.all([
73
+ this.secureStore.getItemAsync(STORAGE_KEYS.ACCESS_TOKEN),
74
+ this.secureStore.getItemAsync(STORAGE_KEYS.REFRESH_TOKEN),
75
+ ]);
76
+ return !!(access && refresh);
77
+ }
78
+ catch {
79
+ return false;
80
+ }
81
+ }
82
+ /**
83
+ * Check if secure storage is available
84
+ */
85
+ async isAvailable() {
86
+ try {
87
+ // Try to perform a simple operation to check availability
88
+ await this.secureStore.isAvailableAsync?.();
89
+ return true;
90
+ }
91
+ catch {
92
+ return false;
93
+ }
94
+ }
95
+ }
96
+ /**
97
+ * Factory function to create MobileTokenStorage with different backends
98
+ */
99
+ export const createMobileTokenStorage = (secureStore) => {
100
+ return new MobileTokenStorage(secureStore);
101
+ };
102
+ /**
103
+ * Expo SecureStore adapter
104
+ * Usage: createMobileTokenStorage(createExpoSecureStoreAdapter())
105
+ */
106
+ export const createExpoSecureStoreAdapter = () => {
107
+ // This would be implemented when actually using Expo
108
+ // For now, return a mock implementation for type checking
109
+ return {
110
+ async setItemAsync(key, value) {
111
+ // In real implementation: await ExpoSecureStore.setItemAsync(key, value);
112
+ console.log(`Mock: Storing ${key} = ${value}`);
113
+ },
114
+ async getItemAsync(key) {
115
+ // In real implementation: return await ExpoSecureStore.getItemAsync(key);
116
+ console.log(`Mock: Retrieving ${key}`);
117
+ return null;
118
+ },
119
+ async deleteItemAsync(key) {
120
+ // In real implementation: await ExpoSecureStore.deleteItemAsync(key);
121
+ console.log(`Mock: Deleting ${key}`);
122
+ },
123
+ async isAvailableAsync() {
124
+ // In real implementation: return await ExpoSecureStore.isAvailableAsync();
125
+ return true;
126
+ },
127
+ };
128
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Web-specific API client implementation using fetch or axios
3
+ *
4
+ * This implementation is designed for web browsers and supports
5
+ * cookie-based authentication with proper CORS handling.
6
+ */
7
+ import { BaseApiClient, type RequestConfig, type ApiResponse, type ApiClientConfig } from '../core/BaseApiClient';
8
+ export declare class WebApiClient extends BaseApiClient {
9
+ constructor(config: ApiClientConfig);
10
+ request<T = unknown>(config: RequestConfig): Promise<ApiResponse<T>>;
11
+ /**
12
+ * Parse response data based on content type
13
+ */
14
+ private parseResponseData;
15
+ /**
16
+ * Convert Headers to plain object
17
+ */
18
+ private parseResponseHeaders;
19
+ /**
20
+ * Check if error is an API error
21
+ */
22
+ private isApiError;
23
+ /**
24
+ * Handle token refresh for web (cookie-based)
25
+ */
26
+ protected handleTokenRefresh(): Promise<boolean>;
27
+ }
28
+ //# sourceMappingURL=WebApiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebApiClient.d.ts","sourceRoot":"","sources":["../../src/adapters/WebApiClient.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAElH,qBAAa,YAAa,SAAQ,aAAa;gBACjC,MAAM,EAAE,eAAe;IAU7B,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAoE1E;;OAEG;YACW,iBAAiB;IAe/B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;cACa,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;CAcvD"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Web-specific API client implementation using fetch or axios
3
+ *
4
+ * This implementation is designed for web browsers and supports
5
+ * cookie-based authentication with proper CORS handling.
6
+ */
7
+ import { HTTP_HEADER_CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON } from '@myportfolio/shared-constants';
8
+ import { BaseApiClient } from '../core/BaseApiClient';
9
+ export class WebApiClient extends BaseApiClient {
10
+ constructor(config) {
11
+ super({
12
+ ...config,
13
+ defaultHeaders: {
14
+ [HTTP_HEADER_CONTENT_TYPE]: CONTENT_TYPE_APPLICATION_JSON,
15
+ ...config.defaultHeaders,
16
+ },
17
+ });
18
+ }
19
+ async request(config) {
20
+ const url = this.buildUrl(config.url);
21
+ const headers = await this.buildHeaders(config.headers);
22
+ // Build fetch options
23
+ const fetchOptions = {
24
+ method: config.method || 'GET',
25
+ headers,
26
+ credentials: this.withCredentials ? 'include' : 'omit',
27
+ };
28
+ // Add body for non-GET requests
29
+ if (config.data && config.method !== 'GET') {
30
+ if (headers[HTTP_HEADER_CONTENT_TYPE] === CONTENT_TYPE_APPLICATION_JSON) {
31
+ fetchOptions.body = JSON.stringify(config.data);
32
+ }
33
+ else {
34
+ fetchOptions.body = config.data;
35
+ }
36
+ }
37
+ // Add query parameters for GET requests
38
+ const requestUrl = config.params && config.method === 'GET'
39
+ ? `${url}?${new URLSearchParams(config.params).toString()}`
40
+ : url;
41
+ try {
42
+ const response = await fetch(requestUrl, fetchOptions);
43
+ // Handle non-2xx responses
44
+ if (!response.ok) {
45
+ const errorData = await this.parseResponseData(response);
46
+ throw this.createError(response.statusText || 'Request failed', response.status, 'HTTP_ERROR', errorData);
47
+ }
48
+ const data = await this.parseResponseData(response);
49
+ return {
50
+ data,
51
+ status: response.status,
52
+ statusText: response.statusText,
53
+ headers: this.parseResponseHeaders(response.headers),
54
+ };
55
+ }
56
+ catch (error) {
57
+ // Handle network errors
58
+ if (error instanceof TypeError && error.message.includes('fetch')) {
59
+ throw this.createError('Network error', 0, 'NETWORK_ERROR');
60
+ }
61
+ // Re-throw API errors
62
+ if (this.isApiError(error)) {
63
+ throw error;
64
+ }
65
+ // Handle unexpected errors
66
+ throw this.createError(error instanceof Error ? error.message : 'Unknown error', 0, 'UNEXPECTED_ERROR');
67
+ }
68
+ }
69
+ /**
70
+ * Parse response data based on content type
71
+ */
72
+ async parseResponseData(response) {
73
+ const contentType = response.headers.get('content-type') || '';
74
+ if (contentType.includes('application/json')) {
75
+ return response.json();
76
+ }
77
+ if (contentType.includes('text/')) {
78
+ return response.text();
79
+ }
80
+ // For other content types, return as blob
81
+ return response.blob();
82
+ }
83
+ /**
84
+ * Convert Headers to plain object
85
+ */
86
+ parseResponseHeaders(headers) {
87
+ const headerObj = {};
88
+ headers.forEach((value, key) => {
89
+ headerObj[key] = value;
90
+ });
91
+ return headerObj;
92
+ }
93
+ /**
94
+ * Check if error is an API error
95
+ */
96
+ isApiError(error) {
97
+ return typeof error === 'object' &&
98
+ error !== null &&
99
+ 'message' in error &&
100
+ 'status' in error;
101
+ }
102
+ /**
103
+ * Handle token refresh for web (cookie-based)
104
+ */
105
+ async handleTokenRefresh() {
106
+ try {
107
+ // For cookie-based auth, make a request to refresh endpoint
108
+ // The server will set new cookies automatically
109
+ const response = await this.request({
110
+ url: '/auth/refresh',
111
+ method: 'POST',
112
+ });
113
+ return response.status === 200;
114
+ }
115
+ catch {
116
+ return false;
117
+ }
118
+ }
119
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Web-specific token storage using HTTP-only cookies
3
+ *
4
+ * This implementation relies on the backend to set HTTP-only cookies
5
+ * and doesn't directly manage tokens on the client side for security.
6
+ *
7
+ * For web applications using cookie-based authentication, the tokens
8
+ * are automatically included in requests via browser cookie handling.
9
+ */
10
+ import { BaseTokenStorage, type TokenPair } from '../core/TokenStorage';
11
+ export declare class WebTokenStorage extends BaseTokenStorage {
12
+ /**
13
+ * For cookie-based auth, tokens are managed by the browser/server
14
+ * This method would typically not store anything client-side
15
+ */
16
+ storeTokens(tokens: TokenPair): Promise<void>;
17
+ /**
18
+ * For cookie-based auth, we can't directly access HTTP-only cookies
19
+ * This method checks if authentication cookies likely exist
20
+ */
21
+ retrieveTokens(): Promise<TokenPair | null>;
22
+ /**
23
+ * Clear authentication state
24
+ * In cookie systems, this would typically call a logout endpoint
25
+ */
26
+ clearTokens(): Promise<void>;
27
+ /**
28
+ * Check authentication status
29
+ * In cookie systems, this would check if auth cookies exist
30
+ */
31
+ hasTokens(): Promise<boolean>;
32
+ /**
33
+ * Check if authentication cookies exist
34
+ * This is a web-specific method for cookie-based auth
35
+ */
36
+ hasCookies(): boolean;
37
+ }
38
+ //# sourceMappingURL=WebTokenStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebTokenStorage.d.ts","sourceRoot":"","sources":["../../src/adapters/WebTokenStorage.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAExE,qBAAa,eAAgB,SAAQ,gBAAgB;IACnD;;;OAGG;IACG,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAWnD;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAuBjD;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAUlC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAYnC;;;OAGG;IACH,UAAU,IAAI,OAAO;CAOtB"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Web-specific token storage using HTTP-only cookies
3
+ *
4
+ * This implementation relies on the backend to set HTTP-only cookies
5
+ * and doesn't directly manage tokens on the client side for security.
6
+ *
7
+ * For web applications using cookie-based authentication, the tokens
8
+ * are automatically included in requests via browser cookie handling.
9
+ */
10
+ import { BaseTokenStorage } from '../core/TokenStorage';
11
+ export class WebTokenStorage extends BaseTokenStorage {
12
+ /**
13
+ * For cookie-based auth, tokens are managed by the browser/server
14
+ * This method would typically not store anything client-side
15
+ */
16
+ async storeTokens(tokens) {
17
+ // In cookie-based systems, tokens are set by the server as HTTP-only cookies
18
+ // The client doesn't need to manually store them
19
+ // For development/testing, we could store in sessionStorage
20
+ // but in production, this would be handled by server-set cookies
21
+ if (typeof window !== 'undefined' && window.sessionStorage) {
22
+ sessionStorage.setItem('auth_tokens', JSON.stringify(tokens));
23
+ }
24
+ }
25
+ /**
26
+ * For cookie-based auth, we can't directly access HTTP-only cookies
27
+ * This method checks if authentication cookies likely exist
28
+ */
29
+ async retrieveTokens() {
30
+ // In a real cookie-based system, we can't access HTTP-only cookies from JS
31
+ // This would typically make a request to a /auth/status endpoint
32
+ // For development/testing, check sessionStorage
33
+ if (typeof window !== 'undefined' && window.sessionStorage) {
34
+ const stored = sessionStorage.getItem('auth_tokens');
35
+ if (stored) {
36
+ try {
37
+ const tokens = JSON.parse(stored);
38
+ if (this.validateTokens(tokens)) {
39
+ return tokens;
40
+ }
41
+ }
42
+ catch {
43
+ // Invalid stored data, clear it
44
+ sessionStorage.removeItem('auth_tokens');
45
+ }
46
+ }
47
+ }
48
+ return null;
49
+ }
50
+ /**
51
+ * Clear authentication state
52
+ * In cookie systems, this would typically call a logout endpoint
53
+ */
54
+ async clearTokens() {
55
+ // Clear any client-side storage
56
+ if (typeof window !== 'undefined' && window.sessionStorage) {
57
+ sessionStorage.removeItem('auth_tokens');
58
+ }
59
+ // In a real implementation, this would make a POST to /auth/signout
60
+ // to clear the HTTP-only cookies on the server side
61
+ }
62
+ /**
63
+ * Check authentication status
64
+ * In cookie systems, this would check if auth cookies exist
65
+ */
66
+ async hasTokens() {
67
+ // For cookie-based systems, we'd typically check document.cookie
68
+ // or make a request to an auth status endpoint
69
+ // For development, check sessionStorage
70
+ if (typeof window !== 'undefined' && window.sessionStorage) {
71
+ return sessionStorage.getItem('auth_tokens') !== null;
72
+ }
73
+ return false;
74
+ }
75
+ /**
76
+ * Check if authentication cookies exist
77
+ * This is a web-specific method for cookie-based auth
78
+ */
79
+ hasCookies() {
80
+ if (typeof document === 'undefined')
81
+ return false;
82
+ // Check for common auth cookie names
83
+ const cookies = document.cookie;
84
+ return cookies.includes('access') || cookies.includes('sessionid') || cookies.includes('auth');
85
+ }
86
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Cross-platform Authentication Manager
3
+ *
4
+ * Centralizes authentication logic and state management across web and mobile platforms.
5
+ * Handles token storage, automatic refresh, and authentication state persistence.
6
+ */
7
+ import type { TokenStorage } from '../core/TokenStorage';
8
+ import type { BaseApiClient } from '../core/BaseApiClient';
9
+ import { type SigninPayload, type SignupPayload, type UserProfile } from '../services/AuthService';
10
+ export interface AuthState {
11
+ isAuthenticated: boolean;
12
+ isLoading: boolean;
13
+ user: UserProfile | null;
14
+ error: string | null;
15
+ }
16
+ export interface AuthManagerConfig {
17
+ apiClient: BaseApiClient;
18
+ tokenStorage: TokenStorage;
19
+ onAuthStateChange?: (state: AuthState) => void;
20
+ autoRefreshEnabled?: boolean;
21
+ refreshThreshold?: number;
22
+ }
23
+ export declare class AuthManager {
24
+ private apiClient;
25
+ private tokenStorage;
26
+ private authService;
27
+ private onAuthStateChange?;
28
+ private autoRefreshEnabled;
29
+ private refreshTimer?;
30
+ private currentState;
31
+ constructor(config: AuthManagerConfig);
32
+ /**
33
+ * Get current authentication state
34
+ */
35
+ getState(): AuthState;
36
+ /**
37
+ * Initialize authentication manager
38
+ * Checks for existing tokens and validates authentication state
39
+ */
40
+ initialize(): Promise<AuthState>;
41
+ /**
42
+ * Sign in user with credentials
43
+ */
44
+ signin(credentials: SigninPayload): Promise<AuthState>;
45
+ /**
46
+ * Sign out user
47
+ */
48
+ signout(): Promise<AuthState>;
49
+ /**
50
+ * Sign up new user
51
+ */
52
+ signup(userData: SignupPayload): Promise<{
53
+ success: boolean;
54
+ error?: string;
55
+ }>;
56
+ /**
57
+ * Refresh authentication tokens
58
+ */
59
+ refreshTokens(): Promise<boolean>;
60
+ /**
61
+ * Update user profile in state
62
+ */
63
+ refreshProfile(): Promise<void>;
64
+ /**
65
+ * Start automatic token refresh
66
+ */
67
+ private startAutoRefresh;
68
+ /**
69
+ * Stop automatic token refresh
70
+ */
71
+ private stopAutoRefresh;
72
+ /**
73
+ * Update authentication state and notify listeners
74
+ */
75
+ private updateState;
76
+ /**
77
+ * Clean up resources
78
+ */
79
+ dispose(): void;
80
+ }
81
+ //# sourceMappingURL=AuthManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthManager.d.ts","sourceRoot":"","sources":["../../src/auth/AuthManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAe,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEhH,MAAM,WAAW,SAAS;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,aAAa,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;IAC3B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,iBAAiB,CAAC,CAA6B;IACvD,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,YAAY,CAAC,CAAiB;IAEtC,OAAO,CAAC,YAAY,CAKlB;gBAEU,MAAM,EAAE,iBAAiB;IAWrC;;OAEG;IACH,QAAQ,IAAI,SAAS;IAIrB;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC;IA6CtC;;OAEG;IACG,MAAM,CAAC,WAAW,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC;IAsC5D;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;IAyBnC;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAsBpF;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IA2BvC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAWrC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB"}