@robosystems/core 0.3.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 (249) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +252 -0
  3. package/actions/entity-actions.d.ts +8 -0
  4. package/actions/entity-actions.js +16 -0
  5. package/actions/graph-actions.d.ts +3 -0
  6. package/actions/graph-actions.js +13 -0
  7. package/auth-components/AppSwitcher.d.ts +6 -0
  8. package/auth-components/AppSwitcher.js +28 -0
  9. package/auth-components/AuthGuard.d.ts +7 -0
  10. package/auth-components/AuthGuard.js +31 -0
  11. package/auth-components/AuthProvider.d.ts +9 -0
  12. package/auth-components/AuthProvider.js +565 -0
  13. package/auth-components/SessionWarningDialog.d.ts +1 -0
  14. package/auth-components/SessionWarningDialog.js +51 -0
  15. package/auth-components/SignInForm.d.ts +20 -0
  16. package/auth-components/SignInForm.js +139 -0
  17. package/auth-components/SignUpForm.d.ts +15 -0
  18. package/auth-components/SignUpForm.js +167 -0
  19. package/auth-components/TurnstileWidget.d.ts +99 -0
  20. package/auth-components/TurnstileWidget.js +224 -0
  21. package/auth-components/index.d.ts +6 -0
  22. package/auth-components/index.js +6 -0
  23. package/auth-core/cleanup.d.ts +44 -0
  24. package/auth-core/cleanup.js +157 -0
  25. package/auth-core/client.d.ts +121 -0
  26. package/auth-core/client.js +767 -0
  27. package/auth-core/config.d.ts +19 -0
  28. package/auth-core/config.js +56 -0
  29. package/auth-core/hooks.d.ts +19 -0
  30. package/auth-core/hooks.js +63 -0
  31. package/auth-core/index.d.ts +6 -0
  32. package/auth-core/index.js +6 -0
  33. package/auth-core/sso.d.ts +42 -0
  34. package/auth-core/sso.js +281 -0
  35. package/auth-core/token-storage.d.ts +58 -0
  36. package/auth-core/token-storage.js +177 -0
  37. package/auth-core/types.d.ts +145 -0
  38. package/auth-core/types.js +1 -0
  39. package/components/EntitySelector.d.ts +44 -0
  40. package/components/EntitySelector.js +64 -0
  41. package/components/EntitySelectorCore.d.ts +45 -0
  42. package/components/EntitySelectorCore.js +67 -0
  43. package/components/GraphSelectorCore.d.ts +21 -0
  44. package/components/GraphSelectorCore.js +39 -0
  45. package/components/PageLayout.d.ts +8 -0
  46. package/components/PageLayout.js +5 -0
  47. package/components/RepositoryGuard.d.ts +68 -0
  48. package/components/RepositoryGuard.js +91 -0
  49. package/components/console/ConsoleContent.d.ts +4 -0
  50. package/components/console/ConsoleContent.js +612 -0
  51. package/components/console/ConsoleMarkdown.d.ts +11 -0
  52. package/components/console/ConsoleMarkdown.js +49 -0
  53. package/components/console/ProgressiveText.d.ts +6 -0
  54. package/components/console/ProgressiveText.js +21 -0
  55. package/components/console/graphAwareConfig.d.ts +70 -0
  56. package/components/console/graphAwareConfig.js +411 -0
  57. package/components/console/index.d.ts +6 -0
  58. package/components/console/index.js +4 -0
  59. package/components/console/types.d.ts +84 -0
  60. package/components/console/types.js +1 -0
  61. package/components/graph-filters.d.ts +75 -0
  62. package/components/graph-filters.js +111 -0
  63. package/components/index.d.ts +10 -0
  64. package/components/index.js +9 -0
  65. package/components/repositories/ActiveSubscriptions.d.ts +26 -0
  66. package/components/repositories/ActiveSubscriptions.js +103 -0
  67. package/components/repositories/BrowseRepositories.d.ts +11 -0
  68. package/components/repositories/BrowseRepositories.js +184 -0
  69. package/components/repositories/index.d.ts +2 -0
  70. package/components/repositories/index.js +2 -0
  71. package/components/search/SearchContent.d.ts +4 -0
  72. package/components/search/SearchContent.js +168 -0
  73. package/components/search/index.d.ts +2 -0
  74. package/components/search/index.js +1 -0
  75. package/components/search/types.d.ts +15 -0
  76. package/components/search/types.js +1 -0
  77. package/contexts/entity-context.d.ts +28 -0
  78. package/contexts/entity-context.js +89 -0
  79. package/contexts/graph-context.d.ts +27 -0
  80. package/contexts/graph-context.js +128 -0
  81. package/contexts/index.d.ts +5 -0
  82. package/contexts/index.js +5 -0
  83. package/contexts/org-context.d.ts +25 -0
  84. package/contexts/org-context.js +64 -0
  85. package/contexts/service-offerings-context.d.ts +45 -0
  86. package/contexts/service-offerings-context.js +98 -0
  87. package/contexts/sidebar-context.d.ts +18 -0
  88. package/contexts/sidebar-context.js +44 -0
  89. package/hooks/index.d.ts +6 -0
  90. package/hooks/index.js +6 -0
  91. package/hooks/use-api-error.d.ts +3 -0
  92. package/hooks/use-api-error.js +24 -0
  93. package/hooks/use-media-query.d.ts +1 -0
  94. package/hooks/use-media-query.js +21 -0
  95. package/hooks/use-streaming-query.d.ts +22 -0
  96. package/hooks/use-streaming-query.js +142 -0
  97. package/hooks/use-toast.d.ts +37 -0
  98. package/hooks/use-toast.js +117 -0
  99. package/hooks/use-user-limits.d.ts +12 -0
  100. package/hooks/use-user-limits.js +73 -0
  101. package/hooks/use-user.d.ts +11 -0
  102. package/hooks/use-user.js +39 -0
  103. package/index.d.ts +29 -0
  104. package/index.js +77 -0
  105. package/lib/entity-cookie.d.ts +10 -0
  106. package/lib/entity-cookie.js +38 -0
  107. package/lib/graph-cookie.d.ts +11 -0
  108. package/lib/graph-cookie.js +62 -0
  109. package/lib/graph-tiers.d.ts +41 -0
  110. package/lib/graph-tiers.js +107 -0
  111. package/lib/index.d.ts +3 -0
  112. package/lib/index.js +3 -0
  113. package/lib/sidebar-cookie.d.ts +11 -0
  114. package/lib/sidebar-cookie.js +42 -0
  115. package/library/colors.d.ts +4 -0
  116. package/library/colors.js +41 -0
  117. package/library/components/ClassificationPicker.d.ts +8 -0
  118. package/library/components/ClassificationPicker.js +55 -0
  119. package/library/components/ElementBrowser.d.ts +11 -0
  120. package/library/components/ElementBrowser.js +106 -0
  121. package/library/components/ElementDetail.d.ts +7 -0
  122. package/library/components/ElementDetail.js +97 -0
  123. package/library/components/LibraryHierarchy.d.ts +13 -0
  124. package/library/components/LibraryHierarchy.js +380 -0
  125. package/library/components/TaxonomySidebar.d.ts +6 -0
  126. package/library/components/TaxonomySidebar.js +45 -0
  127. package/library/index.d.ts +8 -0
  128. package/library/index.js +7 -0
  129. package/package.json +37 -0
  130. package/research/CoverageCard.d.ts +12 -0
  131. package/research/CoverageCard.js +15 -0
  132. package/research/CoverageGrid.d.ts +6 -0
  133. package/research/CoverageGrid.js +9 -0
  134. package/research/CoverageHistory.d.ts +5 -0
  135. package/research/CoverageHistory.js +7 -0
  136. package/research/ResearchArticle.d.ts +15 -0
  137. package/research/ResearchArticle.js +26 -0
  138. package/research/catalog.d.ts +14 -0
  139. package/research/catalog.js +42 -0
  140. package/research/index.d.ts +6 -0
  141. package/research/index.js +9 -0
  142. package/research/types.d.ts +38 -0
  143. package/research/types.js +4 -0
  144. package/task-monitoring/hooks.d.ts +26 -0
  145. package/task-monitoring/hooks.js +126 -0
  146. package/task-monitoring/index.d.ts +5 -0
  147. package/task-monitoring/index.js +7 -0
  148. package/task-monitoring/operationErrors.d.ts +82 -0
  149. package/task-monitoring/operationErrors.js +251 -0
  150. package/task-monitoring/operationHooks.d.ts +117 -0
  151. package/task-monitoring/operationHooks.js +536 -0
  152. package/task-monitoring/operationMonitor.d.ts +78 -0
  153. package/task-monitoring/operationMonitor.js +200 -0
  154. package/task-monitoring/operationTypes.d.ts +236 -0
  155. package/task-monitoring/operationTypes.js +60 -0
  156. package/task-monitoring/taskMonitor.d.ts +14 -0
  157. package/task-monitoring/taskMonitor.js +132 -0
  158. package/task-monitoring/types.d.ts +31 -0
  159. package/task-monitoring/types.js +1 -0
  160. package/theme/flowbite-theme.d.ts +758 -0
  161. package/theme/flowbite-theme.js +765 -0
  162. package/theme/index.d.ts +1 -0
  163. package/theme/index.js +1 -0
  164. package/types/entity.d.ts +19 -0
  165. package/types/index.d.ts +2 -0
  166. package/types/index.js +1 -0
  167. package/types/user.d.ts +6 -0
  168. package/ui-components/ConfirmModal.d.ts +41 -0
  169. package/ui-components/ConfirmModal.js +19 -0
  170. package/ui-components/EmptyState.d.ts +22 -0
  171. package/ui-components/EmptyState.js +10 -0
  172. package/ui-components/LoadingState.d.ts +27 -0
  173. package/ui-components/LoadingState.js +12 -0
  174. package/ui-components/Logo.d.ts +28 -0
  175. package/ui-components/Logo.js +95 -0
  176. package/ui-components/Spinner.d.ts +37 -0
  177. package/ui-components/Spinner.js +48 -0
  178. package/ui-components/StatCard.d.ts +21 -0
  179. package/ui-components/StatCard.js +10 -0
  180. package/ui-components/api-keys/ApiKeyDisplay.d.ts +13 -0
  181. package/ui-components/api-keys/ApiKeyDisplay.js +7 -0
  182. package/ui-components/api-keys/ApiKeyTable.d.ts +9 -0
  183. package/ui-components/api-keys/ApiKeyTable.js +17 -0
  184. package/ui-components/api-keys/ApiKeysCard.d.ts +6 -0
  185. package/ui-components/api-keys/ApiKeysCard.js +97 -0
  186. package/ui-components/api-keys/CreateApiKeyModal.d.ts +11 -0
  187. package/ui-components/api-keys/CreateApiKeyModal.js +47 -0
  188. package/ui-components/api-keys/SecureApiKeyField.d.ts +13 -0
  189. package/ui-components/api-keys/SecureApiKeyField.js +64 -0
  190. package/ui-components/api-keys/index.d.ts +5 -0
  191. package/ui-components/api-keys/index.js +5 -0
  192. package/ui-components/chat/ChatHeader.d.ts +12 -0
  193. package/ui-components/chat/ChatHeader.js +5 -0
  194. package/ui-components/chat/ChatInputArea.d.ts +16 -0
  195. package/ui-components/chat/ChatInputArea.js +9 -0
  196. package/ui-components/chat/ChatMessage.d.ts +7 -0
  197. package/ui-components/chat/ChatMessage.js +24 -0
  198. package/ui-components/chat/DeepResearchToggle.d.ts +8 -0
  199. package/ui-components/chat/DeepResearchToggle.js +13 -0
  200. package/ui-components/chat/index.d.ts +9 -0
  201. package/ui-components/chat/index.js +8 -0
  202. package/ui-components/chat/types.d.ts +23 -0
  203. package/ui-components/chat/types.js +51 -0
  204. package/ui-components/forms/PasswordRequirements.d.ts +10 -0
  205. package/ui-components/forms/PasswordRequirements.js +15 -0
  206. package/ui-components/forms/SettingsCard.d.ts +11 -0
  207. package/ui-components/forms/SettingsCard.js +5 -0
  208. package/ui-components/forms/SettingsFormField.d.ts +18 -0
  209. package/ui-components/forms/SettingsFormField.js +17 -0
  210. package/ui-components/forms/StatusAlert.d.ts +8 -0
  211. package/ui-components/forms/StatusAlert.js +7 -0
  212. package/ui-components/forms/index.d.ts +4 -0
  213. package/ui-components/forms/index.js +4 -0
  214. package/ui-components/index.d.ts +13 -0
  215. package/ui-components/index.js +18 -0
  216. package/ui-components/layout/CoreNavbar.d.ts +14 -0
  217. package/ui-components/layout/CoreNavbar.js +53 -0
  218. package/ui-components/layout/CoreSidebar.d.ts +28 -0
  219. package/ui-components/layout/CoreSidebar.js +62 -0
  220. package/ui-components/layout/LandingFooter.d.ts +28 -0
  221. package/ui-components/layout/LandingFooter.js +34 -0
  222. package/ui-components/layout/PageContainer.d.ts +8 -0
  223. package/ui-components/layout/PageContainer.js +17 -0
  224. package/ui-components/layout/PageHeader.d.ts +23 -0
  225. package/ui-components/layout/PageHeader.js +12 -0
  226. package/ui-components/layout/SettingsContainer.d.ts +10 -0
  227. package/ui-components/layout/SettingsContainer.js +9 -0
  228. package/ui-components/layout/ThemeToggle.d.ts +4 -0
  229. package/ui-components/layout/ThemeToggle.js +6 -0
  230. package/ui-components/layout/index.d.ts +7 -0
  231. package/ui-components/layout/index.js +7 -0
  232. package/ui-components/settings/GeneralInformationCard.d.ts +12 -0
  233. package/ui-components/settings/GeneralInformationCard.js +72 -0
  234. package/ui-components/settings/PasswordInformationCard.d.ts +10 -0
  235. package/ui-components/settings/PasswordInformationCard.js +167 -0
  236. package/ui-components/settings/SettingsPageHeader.d.ts +7 -0
  237. package/ui-components/settings/SettingsPageHeader.js +6 -0
  238. package/ui-components/settings/index.d.ts +3 -0
  239. package/ui-components/settings/index.js +3 -0
  240. package/ui-components/support/SupportModal.d.ts +15 -0
  241. package/ui-components/support/SupportModal.js +74 -0
  242. package/ui-components/support/index.d.ts +2 -0
  243. package/ui-components/support/index.js +1 -0
  244. package/ui-components/types/index.d.ts +39 -0
  245. package/ui-components/types/index.js +1 -0
  246. package/utils/index.d.ts +31 -0
  247. package/utils/index.js +38 -0
  248. package/utils/turnstile-config.d.ts +11 -0
  249. package/utils/turnstile-config.js +19 -0
@@ -0,0 +1,177 @@
1
+ /**
2
+ * JWT Token Storage Management
3
+ *
4
+ * Provides secure storage for JWT tokens using localStorage
5
+ * for cross-domain authentication support and persistent sessions.
6
+ */
7
+ const TOKEN_KEY = 'robosystems_jwt_token';
8
+ const TOKEN_EXPIRY_KEY = 'robosystems_jwt_expiry';
9
+ const TOKEN_THRESHOLD_KEY = 'robosystems_jwt_threshold';
10
+ /**
11
+ * Store JWT token in localStorage
12
+ * @param token - The JWT token from login response
13
+ * @param expiresIn - Optional expiry time in seconds (default 30 minutes)
14
+ * @param refreshThreshold - Optional refresh threshold in seconds (default 5 minutes)
15
+ */
16
+ export function storeToken(token, expiresIn = 1800, refreshThreshold = 300) {
17
+ // 30 minutes default to match backend token lifetime
18
+ if (typeof window === 'undefined')
19
+ return;
20
+ try {
21
+ const expiresAt = Date.now() + expiresIn * 1000;
22
+ localStorage.setItem(TOKEN_KEY, token);
23
+ localStorage.setItem(TOKEN_EXPIRY_KEY, expiresAt.toString());
24
+ localStorage.setItem(TOKEN_THRESHOLD_KEY, (refreshThreshold * 1000).toString());
25
+ // Log token storage for security monitoring
26
+ console.debug('[TokenStorage] Token stored with expiry:', new Date(expiresAt).toISOString(), 'Refresh threshold:', refreshThreshold, 'seconds');
27
+ }
28
+ catch (error) {
29
+ console.error('[TokenStorage] Failed to store token:', error);
30
+ }
31
+ }
32
+ /**
33
+ * Retrieve JWT token from localStorage
34
+ * @returns The stored token or null if not found/expired
35
+ */
36
+ export function getToken() {
37
+ if (typeof window === 'undefined')
38
+ return null;
39
+ try {
40
+ const token = localStorage.getItem(TOKEN_KEY);
41
+ const expiryStr = localStorage.getItem(TOKEN_EXPIRY_KEY);
42
+ if (!token)
43
+ return null;
44
+ // Check if token is expired
45
+ if (expiryStr) {
46
+ const expiry = parseInt(expiryStr, 10);
47
+ if (Date.now() > expiry) {
48
+ clearToken();
49
+ return null;
50
+ }
51
+ }
52
+ return token;
53
+ }
54
+ catch (error) {
55
+ console.error('[TokenStorage] Failed to retrieve token:', error);
56
+ return null;
57
+ }
58
+ }
59
+ /**
60
+ * Clear JWT token from storage
61
+ */
62
+ export function clearToken() {
63
+ if (typeof window === 'undefined')
64
+ return;
65
+ try {
66
+ const hadToken = !!localStorage.getItem(TOKEN_KEY);
67
+ localStorage.removeItem(TOKEN_KEY);
68
+ localStorage.removeItem(TOKEN_EXPIRY_KEY);
69
+ localStorage.removeItem(TOKEN_THRESHOLD_KEY);
70
+ if (hadToken) {
71
+ logSecurityEvent('token_cleared', {
72
+ timestamp: new Date().toISOString(),
73
+ url: window.location.href,
74
+ });
75
+ }
76
+ }
77
+ catch (error) {
78
+ console.error('[TokenStorage] Failed to clear token:', error);
79
+ }
80
+ }
81
+ /**
82
+ * Get current token status
83
+ * @returns 'valid' if token is fresh, 'warning' if approaching expiry, 'expired' if expired
84
+ */
85
+ export function getTokenStatus() {
86
+ if (typeof window === 'undefined')
87
+ return 'expired';
88
+ try {
89
+ const expiryStr = localStorage.getItem(TOKEN_EXPIRY_KEY);
90
+ const thresholdStr = localStorage.getItem(TOKEN_THRESHOLD_KEY);
91
+ if (!expiryStr)
92
+ return 'expired';
93
+ const expiry = parseInt(expiryStr, 10);
94
+ const threshold = thresholdStr ? parseInt(thresholdStr, 10) : 300000; // Default 5 min
95
+ const now = Date.now();
96
+ if (now > expiry)
97
+ return 'expired';
98
+ if (now > expiry - threshold)
99
+ return 'warning';
100
+ return 'valid';
101
+ }
102
+ catch (error) {
103
+ console.error('[TokenStorage] Failed to get token status:', error);
104
+ return 'expired';
105
+ }
106
+ }
107
+ /**
108
+ * Get time until token expiry in milliseconds
109
+ * @returns Time until expiry in ms, or 0 if expired
110
+ */
111
+ export function getTimeUntilExpiry() {
112
+ if (typeof window === 'undefined')
113
+ return 0;
114
+ try {
115
+ const expiryStr = localStorage.getItem(TOKEN_EXPIRY_KEY);
116
+ if (!expiryStr)
117
+ return 0;
118
+ const expiry = parseInt(expiryStr, 10);
119
+ return Math.max(0, expiry - Date.now());
120
+ }
121
+ catch (error) {
122
+ console.error('[TokenStorage] Failed to get time until expiry:', error);
123
+ return 0;
124
+ }
125
+ }
126
+ /**
127
+ * Check if a valid token exists
128
+ * @returns True if a non-expired token exists
129
+ */
130
+ export function hasValidToken() {
131
+ return getToken() !== null;
132
+ }
133
+ /**
134
+ * Get the Authorization header value for API requests
135
+ * @returns Bearer token header or null
136
+ */
137
+ export function getAuthHeader() {
138
+ const token = getToken();
139
+ return token ? `Bearer ${token}` : null;
140
+ }
141
+ /**
142
+ * Extract token from login response and store it
143
+ * @param response - The auth response from login/refresh
144
+ */
145
+ export function handleAuthResponse(response) {
146
+ if (response === null || response === void 0 ? void 0 : response.token) {
147
+ storeToken(response.token, response.expires_in || 1800, response.refresh_threshold || 300);
148
+ }
149
+ }
150
+ /**
151
+ * Get valid token (backend handles refresh via grace period)
152
+ * @returns Valid token or null if expired
153
+ */
154
+ export async function getValidToken() {
155
+ const token = getToken();
156
+ if (!token)
157
+ return null;
158
+ // Just check if token is expired - let backend handle refresh
159
+ const expiryStr = localStorage.getItem(TOKEN_EXPIRY_KEY);
160
+ if (expiryStr) {
161
+ const expiry = parseInt(expiryStr, 10);
162
+ if (Date.now() > expiry) {
163
+ // Token is expired, clear it and let AuthProvider handle re-auth
164
+ clearToken();
165
+ return null;
166
+ }
167
+ }
168
+ return token;
169
+ }
170
+ /**
171
+ * Security event logging (for monitoring)
172
+ */
173
+ function logSecurityEvent(event, details = {}) {
174
+ if (process.env.NODE_ENV === 'development') {
175
+ console.log(`[Security] ${event}:`, details);
176
+ }
177
+ }
@@ -0,0 +1,145 @@
1
+ export interface AuthUser {
2
+ id: string;
3
+ email: string;
4
+ name?: string;
5
+ emailVerified?: boolean;
6
+ createdAt: string;
7
+ updatedAt: string;
8
+ }
9
+ export interface AuthResponse {
10
+ user: AuthUser;
11
+ success: boolean;
12
+ message?: string;
13
+ token?: string;
14
+ expires_in?: number;
15
+ refresh_threshold?: number;
16
+ }
17
+ export interface LoginRequest {
18
+ email: string;
19
+ password: string;
20
+ }
21
+ export interface RegisterRequest {
22
+ email: string;
23
+ password: string;
24
+ name?: string;
25
+ }
26
+ export interface APIKey {
27
+ id: string;
28
+ name: string;
29
+ key: string;
30
+ permissions: string[];
31
+ graphId?: string;
32
+ createdAt: string;
33
+ expiresAt?: string;
34
+ lastUsedAt?: string;
35
+ isActive: boolean;
36
+ }
37
+ export interface CreateAPIKeyRequest {
38
+ name: string;
39
+ permissions: string[];
40
+ graphId?: string;
41
+ expiresAt?: string;
42
+ }
43
+ export interface SSOTokenResponse {
44
+ token: string;
45
+ expires_at: string;
46
+ apps: string[];
47
+ }
48
+ export type AppName = 'robosystems' | 'roboledger' | 'roboinvestor';
49
+ export interface AppConfig {
50
+ name: string;
51
+ displayName: string;
52
+ url: string;
53
+ description: string;
54
+ initials: string;
55
+ /**
56
+ * Literal Tailwind palette class for the app's brand (e.g. `bg-violet-600`).
57
+ * Uses literal palette colors — NOT `primary`/`secondary` tokens — so it
58
+ * renders the correct brand for any app even from inside another app.
59
+ */
60
+ colorClass: string;
61
+ /** The app's fixed brand hex — cross-app safe; drives the colored AnimatedLogo. */
62
+ brandColor: string;
63
+ }
64
+ export interface AuthContextType {
65
+ user: AuthUser | null;
66
+ isLoading: boolean;
67
+ isAuthenticated: boolean;
68
+ sessionWarning: {
69
+ show: boolean;
70
+ timeLeft: number;
71
+ };
72
+ login: (email: string, password: string) => Promise<AuthUser>;
73
+ register: (email: string, password: string, name?: string) => Promise<AuthUser>;
74
+ logout: () => Promise<void>;
75
+ refreshUser: () => Promise<AuthUser | null>;
76
+ refreshSession: (force?: boolean) => Promise<void>;
77
+ forgotPassword: (email: string) => Promise<{
78
+ success: boolean;
79
+ message?: string;
80
+ }>;
81
+ resetPassword: (token: string, newPassword: string) => Promise<{
82
+ success: boolean;
83
+ message?: string;
84
+ }>;
85
+ validateResetToken: (token: string) => Promise<{
86
+ valid: boolean;
87
+ email?: string;
88
+ message?: string;
89
+ }>;
90
+ verifyEmail: (token: string) => Promise<{
91
+ success: boolean;
92
+ message?: string;
93
+ user?: AuthUser;
94
+ }>;
95
+ resendVerificationEmail: (email: string) => Promise<{
96
+ success: boolean;
97
+ message?: string;
98
+ }>;
99
+ }
100
+ export interface UseUserHook {
101
+ /**
102
+ * Refresh the current user's data from the server
103
+ */
104
+ refreshUser: () => Promise<AuthUser | null>;
105
+ /**
106
+ * Update the current user's profile information
107
+ */
108
+ updateProfile: (data: {
109
+ name?: string;
110
+ email?: string;
111
+ }) => Promise<AuthUser>;
112
+ }
113
+ export interface SDKAuthResponse {
114
+ user: AuthUser;
115
+ message?: string;
116
+ token?: string;
117
+ expires_in?: number | null;
118
+ refresh_threshold?: number | null;
119
+ }
120
+ export interface SDKCurrentUserResponse {
121
+ user: AuthUser;
122
+ }
123
+ export interface SDKApiKeyResponse {
124
+ api_key: {
125
+ id: string;
126
+ name: string;
127
+ created_at: string;
128
+ is_active: boolean;
129
+ last_used_at: string | null;
130
+ };
131
+ key: string;
132
+ }
133
+ export interface SDKApiKeysListResponse {
134
+ api_keys: Array<{
135
+ id: string;
136
+ name: string;
137
+ prefix: string;
138
+ created_at: string;
139
+ is_active: boolean;
140
+ last_used_at: string | null;
141
+ }>;
142
+ }
143
+ export interface SDKSsoExchangeResponse {
144
+ session_id: string;
145
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ export interface SelectableEntity {
3
+ id: string;
4
+ name: string;
5
+ subtitle?: string;
6
+ icon?: React.ComponentType<{
7
+ className?: string;
8
+ }>;
9
+ metadata?: Record<string, any>;
10
+ }
11
+ export interface EntityGroup {
12
+ id: string;
13
+ name: string;
14
+ entities: SelectableEntity[];
15
+ }
16
+ export interface EntitySelectorProps<T extends SelectableEntity> {
17
+ entities: T[];
18
+ currentEntity?: T | null;
19
+ onEntityChange: (entity: T) => Promise<void>;
20
+ title: string;
21
+ placeholder?: string;
22
+ emptyStateMessage?: string;
23
+ emptyStateAction?: {
24
+ label: string;
25
+ href: string;
26
+ };
27
+ filter?: (entity: T) => boolean;
28
+ groupBy?: (entities: T[]) => EntityGroup[];
29
+ isLoading?: boolean;
30
+ isChanging?: boolean;
31
+ className?: string;
32
+ triggerClassName?: string;
33
+ defaultIcon?: React.ComponentType<{
34
+ className?: string;
35
+ }>;
36
+ additionalActions?: Array<{
37
+ label: string;
38
+ href: string;
39
+ icon?: React.ComponentType<{
40
+ className?: string;
41
+ }>;
42
+ }>;
43
+ }
44
+ export declare function EntitySelector<T extends SelectableEntity>({ entities, currentEntity, onEntityChange, title, placeholder, emptyStateMessage, emptyStateAction, filter, groupBy, isLoading, isChanging, className, triggerClassName, defaultIcon: DefaultIcon, additionalActions, }: EntitySelectorProps<T>): React.JSX.Element;
@@ -0,0 +1,64 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Dropdown, DropdownItem, Spinner } from 'flowbite-react';
4
+ import { useRouter } from 'next/navigation';
5
+ import { useCallback, useState } from 'react';
6
+ import { HiChevronDown } from 'react-icons/hi';
7
+ import { useApiError, useToast } from '../hooks';
8
+ export function EntitySelector({ entities, currentEntity, onEntityChange, title, placeholder = 'Select item', emptyStateMessage = 'No items available', emptyStateAction, filter, groupBy, isLoading = false, isChanging = false, className = '', triggerClassName = '', defaultIcon: DefaultIcon, additionalActions = [], }) {
9
+ const router = useRouter();
10
+ const { handleApiError } = useApiError();
11
+ const { showSuccess } = useToast();
12
+ const [switching, setSwitching] = useState(false);
13
+ // Filter entities if filter function is provided
14
+ const filteredEntities = filter ? entities.filter(filter) : entities;
15
+ // Group entities if groupBy function is provided
16
+ const entityGroups = groupBy ? groupBy(filteredEntities) : null;
17
+ const handleEntityChange = useCallback(async (entity) => {
18
+ if (entity.id === (currentEntity === null || currentEntity === void 0 ? void 0 : currentEntity.id) || switching)
19
+ return;
20
+ try {
21
+ setSwitching(true);
22
+ await onEntityChange(entity);
23
+ showSuccess(`Switched to ${entity.name}`);
24
+ router.refresh();
25
+ }
26
+ catch (error) {
27
+ handleApiError(error, `Failed to switch to ${entity.name}`);
28
+ }
29
+ finally {
30
+ setSwitching(false);
31
+ }
32
+ }, [
33
+ currentEntity,
34
+ switching,
35
+ onEntityChange,
36
+ showSuccess,
37
+ router,
38
+ handleApiError,
39
+ ]);
40
+ const isLoadingState = isLoading || isChanging || switching;
41
+ if (isLoadingState && !currentEntity && filteredEntities.length === 0) {
42
+ return (_jsxs("div", { className: "flex items-center gap-2 rounded-lg bg-gray-100 px-3 py-2 dark:bg-zinc-800", children: [_jsx(Spinner, { size: "sm" }), _jsxs("span", { className: "text-sm text-gray-500", children: ["Loading ", title.toLowerCase(), "..."] })] }));
43
+ }
44
+ // Empty state
45
+ if (!currentEntity && filteredEntities.length === 0) {
46
+ const EmptyIcon = emptyStateAction ? 'a' : 'div';
47
+ const emptyProps = emptyStateAction ? { href: emptyStateAction.href } : {};
48
+ return (_jsxs(EmptyIcon, Object.assign({}, emptyProps, { className: `flex items-center gap-2 rounded-lg bg-gray-100 px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-200 dark:bg-zinc-800 dark:text-gray-300 dark:hover:bg-gray-700 ${emptyStateAction ? 'cursor-pointer' : ''}`, children: [DefaultIcon && _jsx(DefaultIcon, { className: "h-4 w-4" }), _jsx("span", { children: (emptyStateAction === null || emptyStateAction === void 0 ? void 0 : emptyStateAction.label) || emptyStateMessage })] })));
49
+ }
50
+ const displayEntity = currentEntity || filteredEntities[0];
51
+ const EntityIcon = (displayEntity === null || displayEntity === void 0 ? void 0 : displayEntity.icon) || DefaultIcon;
52
+ return (_jsx("div", { className: className, children: _jsx(Dropdown, { label: "", renderTrigger: () => (_jsxs("button", { className: `flex items-center gap-2 rounded-lg bg-gray-100 px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-200 dark:bg-zinc-800 dark:text-white dark:hover:bg-zinc-700 ${triggerClassName}`, disabled: isLoadingState, children: [EntityIcon && _jsx(EntityIcon, { className: "h-4 w-4" }), _jsx("span", { className: "max-w-[150px] truncate", children: (displayEntity === null || displayEntity === void 0 ? void 0 : displayEntity.name) || placeholder }), isLoadingState ? (_jsx(Spinner, { size: "sm" })) : (_jsx(HiChevronDown, { className: `h-4 w-4 transition-transform` }))] })), children: filteredEntities.length === 0 ? (_jsx(_Fragment, { children: emptyStateAction && (_jsx(DropdownItem, { href: emptyStateAction.href, children: _jsxs("div", { className: "flex items-center gap-2", children: [DefaultIcon && _jsx(DefaultIcon, { className: "h-4 w-4" }), _jsx("span", { children: emptyStateAction.label })] }) })) })) : (_jsxs(_Fragment, { children: [entityGroups
53
+ ? // Grouped entities
54
+ entityGroups.map((group, groupIndex) => (_jsxs("div", { children: [groupIndex > 0 && (_jsx("div", { className: "border-t border-gray-200 dark:border-gray-600" })), _jsx("div", { className: "px-4 py-2 text-xs font-medium text-gray-500 uppercase dark:text-gray-400", children: group.name }), group.entities.map((entity) => (_jsx(EntityDropdownItem, { entity: entity, currentEntity: currentEntity, onEntityChange: handleEntityChange, isDisabled: isLoadingState }, entity.id)))] }, group.id)))
55
+ : // Ungrouped entities
56
+ filteredEntities.map((entity) => (_jsx(EntityDropdownItem, { entity: entity, currentEntity: currentEntity, onEntityChange: handleEntityChange, isDisabled: isLoadingState }, entity.id))), additionalActions.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "border-t border-gray-200 dark:border-gray-600" }), additionalActions.map((action, index) => (_jsx(DropdownItem, { href: action.href, children: _jsxs("div", { className: "flex items-center gap-2", children: [action.icon && _jsx(action.icon, { className: "h-4 w-4" }), _jsx("span", { children: action.label })] }) }, index)))] }))] })) }) }));
57
+ }
58
+ function EntityDropdownItem({ entity, currentEntity, onEntityChange, isDisabled, }) {
59
+ var _a;
60
+ const EntityIcon = entity.icon;
61
+ const isSelected = (currentEntity === null || currentEntity === void 0 ? void 0 : currentEntity.id) === entity.id;
62
+ const isRepository = ((_a = entity.metadata) === null || _a === void 0 ? void 0 : _a.isRepository) || false;
63
+ return (_jsx(DropdownItem, { onClick: () => onEntityChange(entity), disabled: isDisabled, className: `text-left ${isSelected ? 'bg-gray-200 dark:bg-gray-700/50' : ''}`, children: _jsxs("div", { className: "flex w-full items-center gap-3", children: [_jsx("div", { className: `flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${isRepository ? 'bg-secondary-600/20' : 'bg-primary-600/20'}`, children: EntityIcon && (_jsx(EntityIcon, { className: `h-4 w-4 ${isRepository ? 'text-secondary-400' : 'text-primary-400'}` })) }), _jsxs("div", { className: "min-w-0 flex-1 text-left", children: [_jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-white", children: entity.name }), _jsx("div", { className: "truncate text-xs text-gray-500 dark:text-gray-400", children: entity.id.slice(0, 10) })] })] }) }));
64
+ }
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { type SelectableEntity } from './EntitySelector';
3
+ export interface EntityLike {
4
+ identifier: string;
5
+ name: string;
6
+ [key: string]: any;
7
+ }
8
+ export interface GraphWithEntities {
9
+ graphId: string;
10
+ graphName: string;
11
+ entities: EntityLike[];
12
+ [key: string]: any;
13
+ }
14
+ export interface EntityRecord extends SelectableEntity {
15
+ entity: EntityLike;
16
+ graphId: string;
17
+ graphName: string;
18
+ }
19
+ export interface EntitySelectorProps {
20
+ graphsWithEntities: GraphWithEntities[];
21
+ currentEntity?: EntityLike | null;
22
+ currentGraphId?: string | null;
23
+ onEntityChange: (entity: EntityLike, graphId: string, graphName: string) => Promise<void>;
24
+ filter?: (entity: EntityLike, graphId: string) => boolean;
25
+ graphFilter?: (graph: GraphWithEntities) => boolean;
26
+ title?: string;
27
+ placeholder?: string;
28
+ emptyStateMessage?: string;
29
+ emptyStateAction?: {
30
+ label: string;
31
+ href: string;
32
+ };
33
+ groupByGraph?: boolean;
34
+ isLoading?: boolean;
35
+ isChanging?: boolean;
36
+ className?: string;
37
+ additionalActions?: Array<{
38
+ label: string;
39
+ href: string;
40
+ icon?: React.ComponentType<{
41
+ className?: string;
42
+ }>;
43
+ }>;
44
+ }
45
+ export declare function EntitySelectorCore({ graphsWithEntities, currentEntity, currentGraphId, onEntityChange, filter, graphFilter, title, placeholder, emptyStateMessage, emptyStateAction, groupByGraph, isLoading, isChanging, className, additionalActions, }: EntitySelectorProps): React.JSX.Element;
@@ -0,0 +1,67 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React from 'react';
4
+ import { HiOfficeBuilding } from 'react-icons/hi';
5
+ import { EntitySelector, } from './EntitySelector';
6
+ // Transform entity to entity
7
+ function entityToEntity(entity, graphId, graphName) {
8
+ return {
9
+ id: `${graphId}-${entity.identifier}`,
10
+ name: entity.name,
11
+ subtitle: graphName,
12
+ icon: HiOfficeBuilding,
13
+ metadata: { entity, graphId, graphName },
14
+ entity,
15
+ graphId,
16
+ graphName,
17
+ };
18
+ }
19
+ export function EntitySelectorCore({ graphsWithEntities, currentEntity, currentGraphId, onEntityChange, filter, graphFilter, title = 'Entity', placeholder = 'Select Entity', emptyStateMessage = 'No entities available', emptyStateAction, groupByGraph = false, isLoading = false, isChanging = false, className = '', additionalActions = [], }) {
20
+ // Transform entities to entities
21
+ const entities = React.useMemo(() => {
22
+ const filteredGraphs = graphFilter
23
+ ? graphsWithEntities.filter(graphFilter)
24
+ : graphsWithEntities;
25
+ const allEntities = [];
26
+ for (const graph of filteredGraphs) {
27
+ const filteredEntities = filter
28
+ ? graph.entities.filter((entity) => filter(entity, graph.graphId))
29
+ : graph.entities;
30
+ for (const entity of filteredEntities) {
31
+ allEntities.push(entityToEntity(entity, graph.graphId, graph.graphName));
32
+ }
33
+ }
34
+ return allEntities;
35
+ }, [graphsWithEntities, filter, graphFilter]);
36
+ // Get current entity record
37
+ const currentEntityRecord = React.useMemo(() => {
38
+ if (!currentEntity || !currentGraphId)
39
+ return null;
40
+ return (entities.find((e) => e.entity.identifier === currentEntity.identifier &&
41
+ e.graphId === currentGraphId) || null);
42
+ }, [currentEntity, currentGraphId, entities]);
43
+ // Handle entity change
44
+ const handleEntityChange = React.useCallback(async (entity) => {
45
+ await onEntityChange(entity.entity, entity.graphId, entity.graphName);
46
+ }, [onEntityChange]);
47
+ // Group entities by graph if requested
48
+ const groupBy = React.useMemo(() => {
49
+ if (!groupByGraph)
50
+ return undefined;
51
+ return (entities) => {
52
+ const groups = new Map();
53
+ for (const entity of entities) {
54
+ if (!groups.has(entity.graphId)) {
55
+ groups.set(entity.graphId, {
56
+ id: entity.graphId,
57
+ name: entity.graphName,
58
+ entities: [],
59
+ });
60
+ }
61
+ groups.get(entity.graphId).entities.push(entity);
62
+ }
63
+ return Array.from(groups.values());
64
+ };
65
+ }, [groupByGraph]);
66
+ return (_jsx(EntitySelector, { entities: entities, currentEntity: currentEntityRecord, onEntityChange: handleEntityChange, title: title, placeholder: placeholder, emptyStateMessage: emptyStateMessage, emptyStateAction: emptyStateAction, groupBy: groupBy, isLoading: isLoading, isChanging: isChanging, className: className, defaultIcon: HiOfficeBuilding, additionalActions: additionalActions }));
67
+ }
@@ -0,0 +1,21 @@
1
+ import type { GraphInfo } from '@robosystems/client';
2
+ import React from 'react';
3
+ export interface GraphSelectorProps {
4
+ filter?: (graph: GraphInfo) => boolean;
5
+ title?: string;
6
+ placeholder?: string;
7
+ emptyStateMessage?: string;
8
+ emptyStateAction?: {
9
+ label: string;
10
+ href: string;
11
+ };
12
+ className?: string;
13
+ additionalActions?: Array<{
14
+ label: string;
15
+ href: string;
16
+ icon?: React.ComponentType<{
17
+ className?: string;
18
+ }>;
19
+ }>;
20
+ }
21
+ export declare function GraphSelectorCore({ filter, title, placeholder, emptyStateMessage, emptyStateAction, className, additionalActions, }: GraphSelectorProps): React.JSX.Element;
@@ -0,0 +1,39 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React from 'react';
4
+ import { HiDatabase } from 'react-icons/hi';
5
+ import { useGraphContext } from '../contexts/graph-context';
6
+ import { EntitySelector } from './EntitySelector';
7
+ function graphToEntity(graph) {
8
+ return {
9
+ id: graph.graphId,
10
+ name: graph.graphName,
11
+ subtitle: graph.isRepository
12
+ ? `Shared Repository • ${graph.role}`
13
+ : graph.role,
14
+ icon: HiDatabase,
15
+ metadata: Object.assign(Object.assign({}, graph), { isRepository: graph.isRepository }),
16
+ graphInfo: graph,
17
+ };
18
+ }
19
+ export function GraphSelectorCore({ filter, title = 'Graph', placeholder = 'Select Graph', emptyStateMessage = 'No graphs available', emptyStateAction, className = '', additionalActions = [], }) {
20
+ const { state, setCurrentGraph } = useGraphContext();
21
+ // Transform graphs to entities
22
+ const entities = React.useMemo(() => {
23
+ const filteredGraphs = filter ? state.graphs.filter(filter) : state.graphs;
24
+ return filteredGraphs.map(graphToEntity);
25
+ }, [state.graphs, filter]);
26
+ // Get current entity
27
+ const currentEntity = React.useMemo(() => {
28
+ if (!state.currentGraphId)
29
+ return null;
30
+ const currentGraph = state.graphs.find((g) => g.graphId === state.currentGraphId);
31
+ return currentGraph ? graphToEntity(currentGraph) : null;
32
+ }, [state.currentGraphId, state.graphs]);
33
+ // Handle entity change
34
+ const handleEntityChange = React.useCallback(async (entity) => {
35
+ // Update graph context (handles backend update and persistence)
36
+ await setCurrentGraph(entity.id);
37
+ }, [setCurrentGraph]);
38
+ return (_jsx(EntitySelector, { entities: entities, currentEntity: currentEntity, onEntityChange: handleEntityChange, title: title, placeholder: placeholder, emptyStateMessage: emptyStateMessage, emptyStateAction: emptyStateAction, isLoading: state.isLoading, className: className, defaultIcon: HiDatabase, additionalActions: additionalActions }));
39
+ }
@@ -0,0 +1,8 @@
1
+ import type { ReactNode } from 'react';
2
+ interface PageLayoutProps {
3
+ children: ReactNode;
4
+ variant?: 'constrained' | 'full-width';
5
+ className?: string;
6
+ }
7
+ export declare function PageLayout({ children, variant, className, }: PageLayoutProps): import("react").JSX.Element;
8
+ export {};
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { twMerge } from 'tailwind-merge';
3
+ export function PageLayout({ children, variant = 'constrained', className, }) {
4
+ return (_jsx("div", { className: twMerge('space-y-6 p-6', variant === 'constrained' && 'mx-auto max-w-7xl', className), children: children }));
5
+ }