@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,536 @@
1
+ 'use client';
2
+ import { changeSubscriptionPlan, client, createCheckoutSession, createGraph as createGraphAPI, createRepositorySubscription, getOrgBillingCustomer, } from '@robosystems/client';
3
+ import { useCallback, useEffect, useRef, useState } from 'react';
4
+ import { operationMonitor } from './operationMonitor';
5
+ /**
6
+ * Hook for monitoring operations using SSE
7
+ */
8
+ export function useOperationMonitoring() {
9
+ const [state, setState] = useState({
10
+ isLoading: false,
11
+ isMonitoring: false, // Alias for isLoading
12
+ progress: null,
13
+ currentStep: null,
14
+ error: null,
15
+ operationId: null,
16
+ result: null,
17
+ status: null,
18
+ });
19
+ const currentOperationId = useRef(null);
20
+ const reset = useCallback(() => {
21
+ setState({
22
+ isLoading: false,
23
+ isMonitoring: false, // Alias for isLoading
24
+ progress: null,
25
+ currentStep: null,
26
+ error: null,
27
+ operationId: null,
28
+ result: null,
29
+ status: null,
30
+ });
31
+ currentOperationId.current = null;
32
+ }, []);
33
+ const cancelOperation = useCallback(async () => {
34
+ if (currentOperationId.current) {
35
+ try {
36
+ await operationMonitor.cancelOperation(currentOperationId.current);
37
+ setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, isMonitoring: false, status: 'cancelled', error: 'Operation was cancelled', result: null })));
38
+ }
39
+ catch (error) {
40
+ console.error('Failed to cancel operation:', error);
41
+ setState((prev) => (Object.assign(Object.assign({}, prev), { error: 'Failed to cancel operation', result: null })));
42
+ }
43
+ }
44
+ }, []);
45
+ const startMonitoring = useCallback(async (operationId, options) => {
46
+ currentOperationId.current = operationId;
47
+ setState({
48
+ isLoading: true,
49
+ isMonitoring: true,
50
+ progress: 0,
51
+ currentStep: 'Starting...',
52
+ error: null,
53
+ operationId,
54
+ result: null,
55
+ status: 'pending',
56
+ });
57
+ try {
58
+ const result = await operationMonitor.monitorOperation({
59
+ operationId,
60
+ timeout: options === null || options === void 0 ? void 0 : options.timeout,
61
+ onProgress: (progress) => {
62
+ setState((prev) => (Object.assign(Object.assign({}, prev), { progress: progress.percent, currentStep: progress.message, status: 'running' })));
63
+ },
64
+ onComplete: (result) => {
65
+ setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, isMonitoring: false, progress: 100, currentStep: 'Completed', result: result, status: 'completed' })));
66
+ },
67
+ onError: (errorMsg) => {
68
+ setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, isMonitoring: false, error: errorMsg, result: null, status: 'failed' })));
69
+ },
70
+ });
71
+ return result.result || result;
72
+ }
73
+ catch (error) {
74
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
75
+ setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, isMonitoring: false, error: errorMessage, result: null, status: 'failed' })));
76
+ throw error;
77
+ }
78
+ finally {
79
+ currentOperationId.current = null;
80
+ }
81
+ }, []);
82
+ // Cleanup on unmount
83
+ useEffect(() => {
84
+ return () => {
85
+ if (currentOperationId.current) {
86
+ operationMonitor.cancelOperation(currentOperationId.current);
87
+ }
88
+ };
89
+ }, []);
90
+ return Object.assign(Object.assign({}, state), { startMonitoring,
91
+ cancelOperation, cancelMonitoring: cancelOperation, // Alias for consistency
92
+ reset });
93
+ }
94
+ /**
95
+ * Hook for graph creation using the new unified endpoint
96
+ */
97
+ export function useGraphCreation() {
98
+ const operationMonitoring = useOperationMonitoring();
99
+ const [isCreating, setIsCreating] = useState(false);
100
+ const createGraph = useCallback(async (graphData) => {
101
+ var _a, _b, _c;
102
+ setIsCreating(true);
103
+ try {
104
+ // Check if billing is enabled and user needs to complete checkout
105
+ let billingData = null;
106
+ if (graphData.org_id) {
107
+ const billingResponse = await getOrgBillingCustomer({
108
+ client,
109
+ path: { org_id: graphData.org_id },
110
+ });
111
+ // Only set billingData if we got a successful response
112
+ // If billing disabled, getOrgBillingCustomer will return 404 and we skip checkout
113
+ if (!billingResponse.error) {
114
+ billingData = billingResponse.data;
115
+ }
116
+ }
117
+ if (billingData &&
118
+ !billingData.has_payment_method &&
119
+ !billingData.invoice_billing_enabled) {
120
+ // User needs to add payment method - create checkout session
121
+ const checkoutResponse = await createCheckoutSession({
122
+ client,
123
+ body: {
124
+ resource_type: 'graph',
125
+ plan_name: graphData.instance_tier || 'ladybug-standard',
126
+ resource_config: {
127
+ graph_type: graphData.graph_type,
128
+ graph_name: graphData.graph_name,
129
+ description: graphData.description,
130
+ tags: graphData.tags,
131
+ schema_extensions: graphData.schema_extensions,
132
+ create_entity: graphData.create_entity,
133
+ entity_name: graphData.entity_name,
134
+ entity_identifier: graphData.entity_identifier,
135
+ entity_identifier_type: graphData.entity_identifier_type,
136
+ company_name: graphData.company_name,
137
+ company_identifier: graphData.company_identifier,
138
+ company_identifier_type: graphData.company_identifier_type,
139
+ },
140
+ },
141
+ });
142
+ if (checkoutResponse.error) {
143
+ const errorMsg = typeof checkoutResponse.error === 'object' &&
144
+ 'detail' in checkoutResponse.error
145
+ ? String(checkoutResponse.error.detail)
146
+ : 'Failed to create checkout session';
147
+ throw new Error(errorMsg);
148
+ }
149
+ // Check if billing is disabled on the backend
150
+ // @ts-ignore - billing_disabled field will be in next SDK release
151
+ if ((_a = checkoutResponse.data) === null || _a === void 0 ? void 0 : _a.billing_disabled) {
152
+ // Billing disabled - proceed with normal graph creation without payment
153
+ // Fall through to the graph creation logic below
154
+ }
155
+ else if ((_b = checkoutResponse.data) === null || _b === void 0 ? void 0 : _b.checkout_url) {
156
+ // Redirect to Stripe checkout (leave isCreating=true since we're redirecting)
157
+ window.location.href = checkoutResponse.data.checkout_url;
158
+ // Return a pending state to prevent further processing
159
+ return {
160
+ requires_checkout: true,
161
+ checkout_url: checkoutResponse.data.checkout_url,
162
+ session_id: checkoutResponse.data.session_id,
163
+ subscription_id: checkoutResponse.data.subscription_id,
164
+ };
165
+ }
166
+ }
167
+ // User has payment method or invoice billing - proceed with normal graph creation
168
+ // Prepare the request in the correct format for CreateGraphRequest
169
+ const requestBody = {
170
+ metadata: {
171
+ graph_name: graphData.graph_name,
172
+ description: graphData.description,
173
+ tags: graphData.tags,
174
+ schema_extensions: graphData.schema_extensions || [],
175
+ },
176
+ instance_tier: graphData.instance_tier || 'ladybug-standard',
177
+ create_entity: graphData.graph_type === 'generic'
178
+ ? false
179
+ : ((_c = graphData.create_entity) !== null && _c !== void 0 ? _c : true),
180
+ };
181
+ // Add initial_entity for entity or company graphs
182
+ if (graphData.graph_type === 'entity' && graphData.entity_name) {
183
+ requestBody.initial_entity = {
184
+ name: graphData.entity_name,
185
+ uri: graphData.entity_name.toLowerCase().replace(/\s+/g, '-'),
186
+ ein: graphData.entity_identifier_type === 'ein'
187
+ ? graphData.entity_identifier
188
+ : undefined,
189
+ };
190
+ }
191
+ else if (graphData.graph_type === 'company' &&
192
+ graphData.company_name) {
193
+ // Legacy support for company type
194
+ requestBody.initial_entity = {
195
+ name: graphData.company_name,
196
+ uri: graphData.company_name.toLowerCase().replace(/\s+/g, '-'),
197
+ ein: graphData.company_identifier_type === 'ein'
198
+ ? graphData.company_identifier
199
+ : undefined,
200
+ };
201
+ }
202
+ // Call the new unified graph creation endpoint
203
+ const response = await createGraphAPI({
204
+ client,
205
+ body: requestBody,
206
+ });
207
+ // Check for error in response
208
+ const apiError = response.error;
209
+ if (apiError) {
210
+ setIsCreating(false);
211
+ // Format validation error message
212
+ let errorMessage = 'Graph creation failed';
213
+ if (Array.isArray(apiError.detail)) {
214
+ errorMessage = apiError.detail
215
+ .map((err) => {
216
+ var _a;
217
+ if (typeof err === 'string')
218
+ return err;
219
+ if (err.msg)
220
+ return `${((_a = err.loc) === null || _a === void 0 ? void 0 : _a.join('.')) || 'field'}: ${err.msg}`;
221
+ return JSON.stringify(err);
222
+ })
223
+ .join(', ');
224
+ }
225
+ else if (typeof apiError.detail === 'string') {
226
+ errorMessage = apiError.detail;
227
+ }
228
+ else if (apiError.message) {
229
+ errorMessage = apiError.message;
230
+ }
231
+ throw new Error(errorMessage);
232
+ }
233
+ // Check if response contains operation_id (async) or direct result
234
+ const responseData = response.data;
235
+ if (responseData === null || responseData === void 0 ? void 0 : responseData.operationId) {
236
+ // Async operation - monitor it
237
+ const result = await operationMonitoring.startMonitoring(responseData.operationId);
238
+ setIsCreating(false);
239
+ return result;
240
+ }
241
+ else if ((responseData === null || responseData === void 0 ? void 0 : responseData.graph_id) || (responseData === null || responseData === void 0 ? void 0 : responseData.graphId)) {
242
+ // Synchronous result - return directly
243
+ // Handle both snake_case and camelCase, normalize initial_entity
244
+ setIsCreating(false);
245
+ return Object.assign({ graph_id: responseData.graph_id || responseData.graphId, initial_entity: responseData.initial_entity || responseData.initialEntity }, responseData);
246
+ }
247
+ else {
248
+ setIsCreating(false);
249
+ throw new Error('Invalid response from graph creation');
250
+ }
251
+ }
252
+ catch (error) {
253
+ setIsCreating(false);
254
+ throw error;
255
+ }
256
+ }, [operationMonitoring]);
257
+ const createEntityGraph = useCallback(async (entityData) => {
258
+ return createGraph({
259
+ graph_type: 'entity',
260
+ graph_name: entityData.entity_name,
261
+ entity_name: entityData.entity_name,
262
+ entity_identifier: entityData.entity_identifier,
263
+ entity_identifier_type: entityData.entity_identifier_type,
264
+ instance_tier: entityData.instance_tier,
265
+ schema_extensions: entityData.schema_extensions,
266
+ create_entity: entityData.create_entity,
267
+ description: entityData.description,
268
+ tags: entityData.tags,
269
+ org_id: entityData.org_id,
270
+ });
271
+ }, [createGraph]);
272
+ const createGenericGraph = useCallback(async (graphData) => {
273
+ return createGraph(Object.assign({ graph_type: 'generic' }, graphData));
274
+ }, [createGraph]);
275
+ return Object.assign(Object.assign({}, operationMonitoring), { isLoading: isCreating || operationMonitoring.isLoading, createGraph,
276
+ createEntityGraph,
277
+ createGenericGraph });
278
+ }
279
+ /**
280
+ * Hook for creating repository subscriptions with billing integration
281
+ * Mirrors the graph creation pattern for consistency
282
+ */
283
+ export function useRepositorySubscription() {
284
+ const [isSubscribing, setIsSubscribing] = useState(false);
285
+ const subscribe = useCallback(async (subscriptionData) => {
286
+ var _a, _b;
287
+ setIsSubscribing(true);
288
+ try {
289
+ // Check if billing is enabled and user needs to complete checkout
290
+ const billingResponse = await getOrgBillingCustomer({
291
+ client,
292
+ path: { org_id: subscriptionData.org_id },
293
+ });
294
+ const billingData = billingResponse.data;
295
+ // Only check payment if billing is enabled (response exists without error)
296
+ // If billing disabled, getOrgBillingCustomer will return 404 and we skip checkout
297
+ if (!billingResponse.error &&
298
+ billingData &&
299
+ !billingData.has_payment_method &&
300
+ !billingData.invoice_billing_enabled) {
301
+ // User needs to add payment method - create checkout session
302
+ const checkoutResponse = await createCheckoutSession({
303
+ client,
304
+ body: {
305
+ resource_type: 'repository',
306
+ plan_name: subscriptionData.plan_name,
307
+ resource_config: {
308
+ repository_name: subscriptionData.repository_name,
309
+ },
310
+ },
311
+ });
312
+ if (checkoutResponse.error) {
313
+ const errorMsg = typeof checkoutResponse.error === 'object' &&
314
+ 'detail' in checkoutResponse.error
315
+ ? String(checkoutResponse.error.detail)
316
+ : 'Failed to create checkout session';
317
+ throw new Error(errorMsg);
318
+ }
319
+ // Check if billing is disabled on the backend
320
+ // @ts-ignore - billing_disabled field will be in next SDK release
321
+ if ((_a = checkoutResponse.data) === null || _a === void 0 ? void 0 : _a.billing_disabled) {
322
+ // Billing disabled - proceed with direct subscription creation
323
+ // Fall through to the subscription creation logic below
324
+ }
325
+ else if ((_b = checkoutResponse.data) === null || _b === void 0 ? void 0 : _b.checkout_url) {
326
+ // Redirect to Stripe checkout
327
+ window.location.href = checkoutResponse.data.checkout_url;
328
+ // Return a pending state to prevent further processing
329
+ return {
330
+ requires_checkout: true,
331
+ checkout_url: checkoutResponse.data.checkout_url,
332
+ session_id: checkoutResponse.data.session_id,
333
+ subscription_id: checkoutResponse.data.subscription_id,
334
+ };
335
+ }
336
+ }
337
+ // User has payment method, invoice billing, or billing is disabled
338
+ // Proceed with direct subscription creation
339
+ const response = await createRepositorySubscription({
340
+ client,
341
+ path: { graph_id: subscriptionData.repository_name },
342
+ body: {
343
+ plan_name: subscriptionData.plan_name,
344
+ },
345
+ });
346
+ if (response.error) {
347
+ const errorMsg = typeof response.error === 'object' && 'detail' in response.error
348
+ ? String(response.error.detail)
349
+ : 'Failed to create repository subscription';
350
+ throw new Error(errorMsg);
351
+ }
352
+ return response.data;
353
+ }
354
+ catch (error) {
355
+ console.error('Repository subscription failed:', error);
356
+ throw error;
357
+ }
358
+ finally {
359
+ setIsSubscribing(false);
360
+ }
361
+ }, []);
362
+ const changePlan = useCallback(async (data) => {
363
+ setIsSubscribing(true);
364
+ try {
365
+ const response = await changeSubscriptionPlan({
366
+ client,
367
+ path: { graph_id: data.repository_name },
368
+ body: { new_plan_name: data.new_plan_name },
369
+ });
370
+ if (response.error) {
371
+ const errorMsg = typeof response.error === 'object' && 'detail' in response.error
372
+ ? String(response.error.detail)
373
+ : 'Failed to change plan';
374
+ throw new Error(errorMsg);
375
+ }
376
+ return response.data;
377
+ }
378
+ catch (error) {
379
+ console.error('Plan change failed:', error);
380
+ throw error;
381
+ }
382
+ finally {
383
+ setIsSubscribing(false);
384
+ }
385
+ }, []);
386
+ return {
387
+ isSubscribing,
388
+ subscribe,
389
+ changePlan,
390
+ };
391
+ }
392
+ /**
393
+ * Hook for monitoring multiple operations simultaneously
394
+ */
395
+ export function useMultipleOperations() {
396
+ const [operations, setOperations] = useState(new Map());
397
+ // Keep a ref to the latest operations for cleanup without triggering effect re-runs
398
+ const operationsRef = useRef(operations);
399
+ // Update ref whenever operations change
400
+ useEffect(() => {
401
+ operationsRef.current = operations;
402
+ }, [operations]);
403
+ const addOperation = useCallback(async (operationId, options) => {
404
+ // Initialize state for this operation
405
+ setOperations((prev) => {
406
+ const newMap = new Map(prev);
407
+ newMap.set(operationId, {
408
+ isLoading: true,
409
+ isMonitoring: true,
410
+ progress: 0,
411
+ currentStep: 'Starting...',
412
+ error: null,
413
+ operationId,
414
+ result: null,
415
+ status: 'pending',
416
+ });
417
+ return newMap;
418
+ });
419
+ try {
420
+ const result = await operationMonitor.monitorOperation({
421
+ operationId,
422
+ timeout: options === null || options === void 0 ? void 0 : options.timeout,
423
+ onProgress: (progress) => {
424
+ setOperations((prev) => {
425
+ const newMap = new Map(prev);
426
+ const current = newMap.get(operationId);
427
+ if (current) {
428
+ newMap.set(operationId, Object.assign(Object.assign({}, current), { progress: progress.percent, currentStep: progress.message, status: 'running' }));
429
+ }
430
+ return newMap;
431
+ });
432
+ },
433
+ onComplete: (result) => {
434
+ setOperations((prev) => {
435
+ const newMap = new Map(prev);
436
+ const current = newMap.get(operationId);
437
+ if (current) {
438
+ newMap.set(operationId, Object.assign(Object.assign({}, current), { isLoading: false, isMonitoring: false, progress: 100, currentStep: 'Completed', result: result, status: 'completed' }));
439
+ }
440
+ return newMap;
441
+ });
442
+ },
443
+ onError: (errorMsg) => {
444
+ setOperations((prev) => {
445
+ const newMap = new Map(prev);
446
+ const current = newMap.get(operationId);
447
+ if (current) {
448
+ newMap.set(operationId, Object.assign(Object.assign({}, current), { isLoading: false, isMonitoring: false, error: errorMsg, result: null, status: 'failed' }));
449
+ }
450
+ return newMap;
451
+ });
452
+ },
453
+ });
454
+ return result;
455
+ }
456
+ catch (error) {
457
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
458
+ setOperations((prev) => {
459
+ const newMap = new Map(prev);
460
+ const current = newMap.get(operationId);
461
+ if (current) {
462
+ newMap.set(operationId, Object.assign(Object.assign({}, current), { isLoading: false, isMonitoring: false, error: errorMessage, result: null, status: 'failed' }));
463
+ }
464
+ return newMap;
465
+ });
466
+ throw error;
467
+ }
468
+ }, []);
469
+ const cancelOperation = useCallback(async (operationId) => {
470
+ await operationMonitor.cancelOperation(operationId);
471
+ setOperations((prev) => {
472
+ const newMap = new Map(prev);
473
+ const current = newMap.get(operationId);
474
+ if (current) {
475
+ newMap.set(operationId, Object.assign(Object.assign({}, current), { isLoading: false, isMonitoring: false, status: 'cancelled', error: 'Operation was cancelled' }));
476
+ }
477
+ return newMap;
478
+ });
479
+ }, []);
480
+ const removeOperation = useCallback((operationId) => {
481
+ setOperations((prev) => {
482
+ const newMap = new Map(prev);
483
+ newMap.delete(operationId);
484
+ return newMap;
485
+ });
486
+ }, []);
487
+ const clearAll = useCallback(() => {
488
+ // Cancel all active operations
489
+ for (const [operationId, state] of operations) {
490
+ if (state.isLoading) {
491
+ operationMonitor.cancelOperation(operationId);
492
+ }
493
+ }
494
+ setOperations(new Map());
495
+ }, [operations]);
496
+ // Cleanup on unmount - use ref to avoid stale closures
497
+ useEffect(() => {
498
+ return () => {
499
+ for (const [operationId, state] of operationsRef.current) {
500
+ if (state.isLoading) {
501
+ operationMonitor.cancelOperation(operationId);
502
+ }
503
+ }
504
+ };
505
+ }, []);
506
+ return {
507
+ operations: Array.from(operations.values()),
508
+ addOperation,
509
+ cancelOperation,
510
+ removeOperation,
511
+ clearAll,
512
+ };
513
+ }
514
+ /**
515
+ * Helper to determine if an operation is still active
516
+ */
517
+ export function isOperationActive(status) {
518
+ return status === 'pending' || status === 'running';
519
+ }
520
+ /**
521
+ * Helper to get progress color based on status
522
+ */
523
+ export function getProgressColor(status) {
524
+ switch (status) {
525
+ case 'completed':
526
+ return 'text-green-600';
527
+ case 'failed':
528
+ return 'text-red-600';
529
+ case 'cancelled':
530
+ return 'text-yellow-600';
531
+ case 'running':
532
+ return 'text-blue-600';
533
+ default:
534
+ return 'text-gray-600';
535
+ }
536
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Operation Monitor - SSE-based monitoring for unified backend operations
3
+ * Replaces the polling-based TaskMonitor with EventSource streaming
4
+ *
5
+ * Uses SDK extensions when available (@robosystems/client v0.1.21+)
6
+ * No fallback - fails fast if SDK extensions not available
7
+ */
8
+ export type OperationStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
9
+ export interface OperationEvent {
10
+ event: string;
11
+ data: any;
12
+ timestamp?: string;
13
+ }
14
+ export interface OperationProgress {
15
+ percent: number;
16
+ message?: string;
17
+ current_step?: string;
18
+ total_steps?: number;
19
+ }
20
+ export interface OperationResult {
21
+ operation_id: string;
22
+ status: OperationStatus;
23
+ result?: any;
24
+ error?: string;
25
+ duration_ms?: number;
26
+ events?: OperationEvent[];
27
+ }
28
+ export interface OperationMonitorOptions {
29
+ operationId: string;
30
+ onProgress?: (progress: OperationProgress) => void;
31
+ onComplete?: (result: any) => void;
32
+ onError?: (error: string) => void;
33
+ onEvent?: (event: OperationEvent) => void;
34
+ timeout?: number;
35
+ }
36
+ export declare class OperationMonitor {
37
+ private static instance;
38
+ private activeOperations;
39
+ private operationResults;
40
+ static getInstance(): OperationMonitor;
41
+ /**
42
+ * Monitor an operation using SSE streaming
43
+ */
44
+ monitorOperation({ operationId, onProgress, onComplete, onError, onEvent, timeout, }: OperationMonitorOptions): Promise<OperationResult>;
45
+ /**
46
+ * Cancel operation monitoring (does not cancel the operation itself)
47
+ */
48
+ cancelOperation(operationId: string): boolean;
49
+ /**
50
+ * Get cached operation status/result
51
+ */
52
+ getOperationStatus(operationId: string): OperationResult | null;
53
+ /**
54
+ * Clean up operation monitoring resources
55
+ */
56
+ private cleanupOperation;
57
+ /**
58
+ * Monitor operation using SDK extensions
59
+ */
60
+ private monitorWithSDKExtensions;
61
+ /**
62
+ * Clean up all active operations
63
+ */
64
+ cleanup(): void;
65
+ /**
66
+ * Get list of active operation IDs
67
+ */
68
+ getActiveOperations(): string[];
69
+ /**
70
+ * Clear operation results cache
71
+ */
72
+ clearCache(): void;
73
+ }
74
+ export declare const operationMonitor: OperationMonitor;
75
+ export declare const monitorOperation: (options: OperationMonitorOptions) => Promise<OperationResult>;
76
+ export declare const cancelOperation: (operationId: string) => boolean;
77
+ export declare const getOperationStatus: (operationId: string) => OperationResult;
78
+ export declare const getActiveOperations: () => string[];