@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,767 @@
1
+ var _a;
2
+ import { checkPasswordStrength, client, completeSsoAuth, createUserApiKey, forgotPassword, generateSsoToken, getCurrentAuthUser, getPasswordPolicy, listUserApiKeys, loginUser, logoutUser, refreshAuthSession, registerUser, resendVerificationEmail, resetPassword, revokeUserApiKey, ssoTokenExchange, validateResetToken, verifyEmail, } from '@robosystems/client';
3
+ import * as sdkClientsModule from '@robosystems/client/clients';
4
+ import { getToken, getValidToken } from './token-storage';
5
+ // Global config hook for the clients package's lazy default singleton
6
+ // (`import { clients } from '@robosystems/client/clients'`). We must
7
+ // set this BEFORE the singleton is first accessed — the singleton reads the
8
+ // token at construction time and never re-reads it. Without this, the
9
+ // GraphQL client inside LedgerClient/InvestorClient has no credentials and
10
+ // every resolver call returns UNAUTHENTICATED.
11
+ //
12
+ // Statically imported: the `@robosystems/client >=0.3.2` peer range
13
+ // guarantees the clients surface (the root barrel imports it statically
14
+ // too), and `require()` does not exist in this package's compiled ESM.
15
+ // A missing *export* still falls through to a no-op, which just means the
16
+ // extensions singleton is unconfigured but the core REST auth path works.
17
+ const setSDKClientConfig = (_a = sdkClientsModule.setSDKClientConfig) !== null && _a !== void 0 ? _a : null;
18
+ // Configuration constants
19
+ const CACHE_TTL_MS = 30 * 1000; // 30 seconds - optimized for performance
20
+ const ERROR_CACHE_TTL_MS = 5 * 1000; // 5 seconds - allow reasonable retry delay
21
+ // Custom error class for token expiry
22
+ export class TokenExpiredError extends Error {
23
+ constructor(message = 'Token expired') {
24
+ super(message);
25
+ this.name = 'TokenExpiredError';
26
+ }
27
+ }
28
+ export class RoboSystemsAuthClient {
29
+ constructor(baseUrl) {
30
+ this.authCheckPromise = null;
31
+ this.lastAuthCheck = null;
32
+ this.lastError = null;
33
+ this.refreshRetryCount = 0;
34
+ this.MAX_REFRESH_RETRIES = 3;
35
+ this.INITIAL_RETRY_DELAY = 1000; // 1 second
36
+ // Configure the SDK client with the provided base URL and credentials
37
+ this.client = client;
38
+ // Configure client with JWT authentication
39
+ this.configureClientWithAuth(baseUrl);
40
+ }
41
+ /**
42
+ * Configure the client with JWT authentication for all requests
43
+ */
44
+ configureClientWithAuth(baseUrl) {
45
+ var _a, _b, _c, _d, _e, _f;
46
+ // Get JWT token for authorization with auto-refresh
47
+ const getAuthToken = async () => {
48
+ const { getValidToken } = await import('./token-storage');
49
+ return await getValidToken(); // This will auto-refresh if needed
50
+ };
51
+ // Set base configuration
52
+ this.client.setConfig({
53
+ baseUrl: baseUrl.replace(/\/$/, ''), // Remove trailing slash
54
+ credentials: 'include', // Essential for cookie-based authentication
55
+ headers: {},
56
+ });
57
+ // Wire the SDK extensions singleton to pull a fresh JWT on every
58
+ // GraphQL request. The `extensions` singleton at
59
+ // `@robosystems/client/clients` lazy-builds on first access; if we
60
+ // seeded a static `token` it would get captured there and go stale the
61
+ // moment the JWT rotates (~every 30 min). Instead we register a
62
+ // `tokenProvider` callback that reads the latest token from storage on
63
+ // each request, so refresh flows through without any cache clearing.
64
+ //
65
+ // On the REST side this isn't necessary because the main SDK client's
66
+ // methods are wrapped below to inject `Authorization: Bearer` per-call
67
+ // — this block is only about the GraphQL read path that runs inside
68
+ // LedgerClient / InvestorClient / ReportClient via graphql-request.
69
+ if (setSDKClientConfig && typeof window !== 'undefined') {
70
+ try {
71
+ // token-storage is imported statically (its functions are all
72
+ // window-guarded, so it is server-safe); `require()` is not
73
+ // available in this package's compiled ESM output.
74
+ setSDKClientConfig({
75
+ baseUrl: baseUrl.replace(/\/$/, ''),
76
+ // Priming `token` with the current storage value isn't required
77
+ // since the provider always wins, but it gives the singleton a
78
+ // sensible initial value before the first async refresh.
79
+ token: (_a = getToken()) !== null && _a !== void 0 ? _a : undefined,
80
+ // Async provider — `getValidToken` auto-refreshes expired tokens
81
+ // against the backend before returning. Every GraphQL request
82
+ // consults this callback, so a token rotation between requests
83
+ // is picked up automatically.
84
+ tokenProvider: async () => {
85
+ try {
86
+ return await getValidToken();
87
+ }
88
+ catch (_a) {
89
+ // If refresh fails (offline, backend down, token-storage
90
+ // corrupted) let the request go out unauthenticated; the
91
+ // backend's 401 will trigger the normal session-expired
92
+ // handling instead of crashing the request at middleware.
93
+ return null;
94
+ }
95
+ },
96
+ });
97
+ }
98
+ catch (err) {
99
+ console.warn('[AuthClient] Failed to seed SDK extensions config:', err);
100
+ }
101
+ }
102
+ // Wrap the client methods to add JWT token to requests
103
+ const originalPost = (_b = this.client.post) === null || _b === void 0 ? void 0 : _b.bind(this.client);
104
+ const originalPut = (_c = this.client.put) === null || _c === void 0 ? void 0 : _c.bind(this.client);
105
+ const originalPatch = (_d = this.client.patch) === null || _d === void 0 ? void 0 : _d.bind(this.client);
106
+ const originalDelete = (_e = this.client.delete) === null || _e === void 0 ? void 0 : _e.bind(this.client);
107
+ // Helper to add JWT token to headers and handle 401 responses
108
+ const wrapWithAuthAndErrorHandling = (originalMethod, methodName) => {
109
+ if (!originalMethod)
110
+ return undefined;
111
+ return async (options) => {
112
+ var _a, _b, _c;
113
+ try {
114
+ const authToken = await getAuthToken();
115
+ const headers = Object.assign({}, options.headers);
116
+ if (authToken) {
117
+ headers['Authorization'] = `Bearer ${authToken}`;
118
+ }
119
+ const enhancedOptions = Object.assign(Object.assign({}, options), { headers });
120
+ const result = await originalMethod(enhancedOptions);
121
+ return result;
122
+ }
123
+ catch (error) {
124
+ // Check for 401 Unauthorized errors
125
+ if ((error === null || error === void 0 ? void 0 : error.status) === 401 ||
126
+ ((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) === 401 ||
127
+ ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes('unauthorized')) ||
128
+ ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes('401'))) {
129
+ // Clear cached auth data
130
+ this.clearAuthCache();
131
+ // Clear token from storage
132
+ const { clearToken } = await import('./token-storage');
133
+ clearToken();
134
+ // Throw custom error that can be caught by UI
135
+ throw new TokenExpiredError('Your session has expired. Please log in again.');
136
+ }
137
+ // Re-throw other errors
138
+ throw error;
139
+ }
140
+ };
141
+ };
142
+ // Also wrap GET requests to add JWT token
143
+ const originalGet = (_f = this.client.get) === null || _f === void 0 ? void 0 : _f.bind(this.client);
144
+ // Override all methods with auth headers and error handling
145
+ this.client.get = wrapWithAuthAndErrorHandling(originalGet, 'GET');
146
+ this.client.post = wrapWithAuthAndErrorHandling(originalPost, 'POST');
147
+ this.client.put = wrapWithAuthAndErrorHandling(originalPut, 'PUT');
148
+ this.client.patch = wrapWithAuthAndErrorHandling(originalPatch, 'PATCH');
149
+ this.client.delete = wrapWithAuthAndErrorHandling(originalDelete, 'DELETE');
150
+ }
151
+ /**
152
+ * Push the latest auth token into the SDK extensions global config.
153
+ *
154
+ * Called from every auth success path (`login` / `register` / SSO
155
+ * token exchange / verify-email) so the SDK extensions singleton
156
+ * stays in sync with the current credential.
157
+ *
158
+ * The GraphQL read path already has refresh via `tokenProvider`
159
+ * (wired in `configureClientWithAuth`) and does not depend on this
160
+ * static field. But the SDK's React hooks (`useQuery`, `useOperation`,
161
+ * `useStreamingQuery`, …) still read `getSDKClientConfig().token`
162
+ * via `extractTokenFromSDKClient` to seed their inner `QueryClient`
163
+ * / `OperationClient` instances. Keeping the static field updated
164
+ * after every auth success keeps those hook-owned clients
165
+ * authenticated across login/register/SSO transitions.
166
+ *
167
+ * No-op when the SDK extensions module isn't installed.
168
+ */
169
+ syncClientConfigToken(token) {
170
+ if (!setSDKClientConfig)
171
+ return;
172
+ setSDKClientConfig({
173
+ baseUrl: this.client.getConfig().baseUrl,
174
+ token,
175
+ });
176
+ }
177
+ async login(email, password) {
178
+ const response = await loginUser({
179
+ client: this.client,
180
+ body: { email, password },
181
+ });
182
+ const sdkResponse = this.validateSDKAuthResponse(response.data);
183
+ // Store JWT token with expiry information if present in response
184
+ if (sdkResponse.token) {
185
+ const { storeToken } = await import('./token-storage');
186
+ storeToken(sdkResponse.token, sdkResponse.expires_in || 1800, sdkResponse.refresh_threshold || 300);
187
+ // Keep the SDK extensions singleton's static `token` field in
188
+ // sync. The GraphQL read path refreshes via `tokenProvider`
189
+ // independently, but the React hooks surface still reads the
190
+ // static field at hook-init time — see `syncClientConfigToken`
191
+ // for the full rationale.
192
+ this.syncClientConfigToken(sdkResponse.token);
193
+ }
194
+ return {
195
+ user: sdkResponse.user,
196
+ success: true,
197
+ message: sdkResponse.message,
198
+ token: sdkResponse.token,
199
+ expires_in: sdkResponse.expires_in,
200
+ refresh_threshold: sdkResponse.refresh_threshold,
201
+ };
202
+ }
203
+ async register(email, password, name, captchaToken) {
204
+ const response = await registerUser({
205
+ client: this.client,
206
+ body: {
207
+ email,
208
+ password,
209
+ name: name || '',
210
+ captcha_token: captchaToken || undefined,
211
+ },
212
+ });
213
+ // Check for error responses (4xx/5xx)
214
+ if (response.error) {
215
+ const errorData = response.error;
216
+ throw new Error((errorData === null || errorData === void 0 ? void 0 : errorData.detail) || 'Registration failed');
217
+ }
218
+ const sdkResponse = this.validateSDKAuthResponse(response.data);
219
+ // Store JWT token with expiry information if present in response
220
+ if (sdkResponse.token) {
221
+ const { storeToken } = await import('./token-storage');
222
+ storeToken(sdkResponse.token, sdkResponse.expires_in || 1800, sdkResponse.refresh_threshold || 300);
223
+ // Keep the SDK extensions singleton's static `token` field in
224
+ // sync. The GraphQL read path refreshes via `tokenProvider`
225
+ // independently, but the React hooks surface still reads the
226
+ // static field at hook-init time — see `syncClientConfigToken`
227
+ // for the full rationale.
228
+ this.syncClientConfigToken(sdkResponse.token);
229
+ }
230
+ return {
231
+ user: sdkResponse.user,
232
+ success: true,
233
+ message: sdkResponse.message,
234
+ token: sdkResponse.token,
235
+ expires_in: sdkResponse.expires_in,
236
+ refresh_threshold: sdkResponse.refresh_threshold,
237
+ };
238
+ }
239
+ async logout() {
240
+ try {
241
+ // Add timeout to prevent hanging
242
+ const logoutPromise = logoutUser({
243
+ client: this.client,
244
+ });
245
+ const timeoutPromise = new Promise((_, reject) => {
246
+ setTimeout(() => reject(new Error('Logout timeout after 10 seconds')), 10000);
247
+ });
248
+ await Promise.race([logoutPromise, timeoutPromise]);
249
+ }
250
+ catch (error) {
251
+ // Don't throw - continue with local cleanup even if backend fails
252
+ }
253
+ // Clear stored JWT token
254
+ const { clearToken } = await import('./token-storage');
255
+ clearToken();
256
+ // Verify logout by checking current user session
257
+ try {
258
+ // Clear any cached auth state to force fresh API call
259
+ this.clearAuthCache();
260
+ // Try to get current user - this should fail if logout worked
261
+ await this.getCurrentUser();
262
+ }
263
+ catch (verifyError) {
264
+ // This is expected - getCurrentUser should throw an error after logout
265
+ }
266
+ }
267
+ async getCurrentUser() {
268
+ var _a;
269
+ // Return cached result if fresh
270
+ if (this.lastAuthCheck &&
271
+ Date.now() - this.lastAuthCheck.timestamp < CACHE_TTL_MS) {
272
+ if (this.lastAuthCheck.result) {
273
+ return this.lastAuthCheck.result;
274
+ }
275
+ }
276
+ // Return cached error if fresh
277
+ if (this.lastError &&
278
+ Date.now() - this.lastError.timestamp < ERROR_CACHE_TTL_MS) {
279
+ throw this.lastError.error;
280
+ }
281
+ // If request already in progress, wait for it
282
+ if (this.authCheckPromise) {
283
+ return await this.authCheckPromise;
284
+ }
285
+ // Create new auth check promise
286
+ this.authCheckPromise = this.performAuthCheck();
287
+ try {
288
+ const result = await this.authCheckPromise;
289
+ // Clear any previous error on success
290
+ this.lastError = null;
291
+ return result;
292
+ }
293
+ catch (error) {
294
+ // Don't cache 403 errors - they indicate a permanent state change
295
+ const is403 = (error === null || error === void 0 ? void 0 : error.status) === 403 ||
296
+ ((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) === 403;
297
+ if (!is403) {
298
+ // Cache non-403 errors for consistent responses
299
+ this.lastError = {
300
+ timestamp: Date.now(),
301
+ error: error instanceof Error ? error : new Error(String(error)),
302
+ };
303
+ }
304
+ else {
305
+ // Clear cached error for 403s to force fresh checks
306
+ this.lastError = null;
307
+ }
308
+ throw error;
309
+ }
310
+ finally {
311
+ this.authCheckPromise = null;
312
+ }
313
+ }
314
+ async performAuthCheck() {
315
+ try {
316
+ const response = await getCurrentAuthUser({
317
+ client: this.client,
318
+ });
319
+ const data = this.validateSDKCurrentUserResponse(response.data);
320
+ const user = data.user;
321
+ this.lastAuthCheck = { timestamp: Date.now(), result: user };
322
+ return user;
323
+ }
324
+ catch (error) {
325
+ this.lastAuthCheck = { timestamp: Date.now(), result: null };
326
+ // Error caching is handled in getCurrentUser()
327
+ throw error;
328
+ }
329
+ }
330
+ async refreshSession() {
331
+ const response = await this.refreshSessionWithRetry();
332
+ // Check if response has data property or if it IS the data
333
+ const responseData = (response === null || response === void 0 ? void 0 : response.data) !== undefined ? response.data : response;
334
+ const sdkResponse = this.validateSDKAuthResponse(responseData);
335
+ // Store new JWT token with expiry information if present in response
336
+ if (sdkResponse.token) {
337
+ const { storeToken } = await import('./token-storage');
338
+ storeToken(sdkResponse.token, sdkResponse.expires_in || 1800, sdkResponse.refresh_threshold || 300);
339
+ // Keep the SDK extensions singleton's static `token` field in
340
+ // sync. The GraphQL read path refreshes via `tokenProvider`
341
+ // independently, but the React hooks surface still reads the
342
+ // static field at hook-init time — see `syncClientConfigToken`
343
+ // for the full rationale.
344
+ this.syncClientConfigToken(sdkResponse.token);
345
+ }
346
+ // Reset retry count on success
347
+ this.refreshRetryCount = 0;
348
+ return {
349
+ user: sdkResponse.user,
350
+ success: true,
351
+ message: sdkResponse.message,
352
+ token: sdkResponse.token,
353
+ expires_in: sdkResponse.expires_in,
354
+ refresh_threshold: sdkResponse.refresh_threshold,
355
+ };
356
+ }
357
+ /**
358
+ * Refresh session with exponential backoff retry logic
359
+ */
360
+ async refreshSessionWithRetry() {
361
+ let lastError = null;
362
+ for (let attempt = 0; attempt <= this.MAX_REFRESH_RETRIES; attempt++) {
363
+ try {
364
+ // Attempt to refresh the session
365
+ const response = await refreshAuthSession({
366
+ client: this.client,
367
+ });
368
+ // Success - return the response
369
+ return response;
370
+ }
371
+ catch (error) {
372
+ lastError = error;
373
+ // If this is the last attempt, throw the error
374
+ if (attempt === this.MAX_REFRESH_RETRIES) {
375
+ break;
376
+ }
377
+ // Calculate delay with exponential backoff
378
+ const delay = this.INITIAL_RETRY_DELAY * Math.pow(2, attempt);
379
+ // Add jitter to prevent thundering herd
380
+ const jitter = Math.random() * 0.3 * delay;
381
+ const totalDelay = delay + jitter;
382
+ console.warn(`Session refresh attempt ${attempt + 1} failed, retrying in ${Math.round(totalDelay)}ms...`);
383
+ // Wait before retrying
384
+ await new Promise((resolve) => setTimeout(resolve, totalDelay));
385
+ }
386
+ }
387
+ // All attempts failed - throw the last error
388
+ throw lastError || new Error('Failed to refresh session after all retries');
389
+ }
390
+ async createAPIKey(request) {
391
+ const response = await createUserApiKey({
392
+ client: this.client,
393
+ body: {
394
+ name: request.name,
395
+ description: request.permissions.join(', '), // Map permissions to description for now
396
+ },
397
+ });
398
+ const sdkResponse = response.data;
399
+ return {
400
+ id: sdkResponse.api_key.id,
401
+ name: sdkResponse.api_key.name,
402
+ key: sdkResponse.key,
403
+ permissions: request.permissions,
404
+ graphId: request.graphId,
405
+ createdAt: sdkResponse.api_key.created_at,
406
+ isActive: sdkResponse.api_key.is_active,
407
+ lastUsedAt: sdkResponse.api_key.last_used_at,
408
+ expiresAt: request.expiresAt,
409
+ };
410
+ }
411
+ async getAPIKeys() {
412
+ const response = await listUserApiKeys({
413
+ client: this.client,
414
+ });
415
+ const sdkResponse = response.data;
416
+ return sdkResponse.api_keys.map((apiKey) => ({
417
+ id: apiKey.id,
418
+ name: apiKey.name,
419
+ key: apiKey.prefix + '...', // Only prefix is available in list
420
+ permissions: [], // Not available in the SDK response
421
+ createdAt: apiKey.created_at,
422
+ isActive: apiKey.is_active,
423
+ lastUsedAt: apiKey.last_used_at,
424
+ }));
425
+ }
426
+ async revokeAPIKey(keyId) {
427
+ await revokeUserApiKey({
428
+ client: this.client,
429
+ path: { api_key_id: keyId },
430
+ });
431
+ }
432
+ async generateSSOToken() {
433
+ const response = await generateSsoToken({
434
+ client: this.client,
435
+ });
436
+ const data = response.data;
437
+ return data;
438
+ }
439
+ async ssoExchange(token, targetApp) {
440
+ const response = await ssoTokenExchange({
441
+ client: this.client,
442
+ body: { token, target_app: targetApp },
443
+ });
444
+ const data = response.data;
445
+ return {
446
+ session_id: data.session_id,
447
+ };
448
+ }
449
+ async ssoComplete(sessionId) {
450
+ const response = await completeSsoAuth({
451
+ client: this.client,
452
+ body: { session_id: sessionId },
453
+ });
454
+ const sdkResponse = this.validateSDKAuthResponse(response.data);
455
+ // Store JWT token with expiry information if present in response
456
+ if (sdkResponse.token) {
457
+ const { storeToken } = await import('./token-storage');
458
+ storeToken(sdkResponse.token, sdkResponse.expires_in || 1800, sdkResponse.refresh_threshold || 300);
459
+ // Keep the SDK extensions singleton's static `token` field in
460
+ // sync. The GraphQL read path refreshes via `tokenProvider`
461
+ // independently, but the React hooks surface still reads the
462
+ // static field at hook-init time — see `syncClientConfigToken`
463
+ // for the full rationale.
464
+ this.syncClientConfigToken(sdkResponse.token);
465
+ }
466
+ return {
467
+ user: sdkResponse.user,
468
+ success: true,
469
+ message: sdkResponse.message,
470
+ token: sdkResponse.token,
471
+ expires_in: sdkResponse.expires_in,
472
+ refresh_threshold: sdkResponse.refresh_threshold,
473
+ };
474
+ }
475
+ async checkAuthentication() {
476
+ try {
477
+ return await this.getCurrentUser();
478
+ }
479
+ catch (_a) {
480
+ return null;
481
+ }
482
+ }
483
+ // Clear request deduplication cache (useful after login/logout)
484
+ clearAuthCache() {
485
+ this.lastAuthCheck = null;
486
+ this.lastError = null;
487
+ this.authCheckPromise = null;
488
+ }
489
+ /**
490
+ * Send password reset email
491
+ */
492
+ async forgotPassword(email) {
493
+ try {
494
+ await forgotPassword({
495
+ client: this.client,
496
+ body: { email },
497
+ });
498
+ return {
499
+ success: true,
500
+ message: 'Password reset email sent if the account exists',
501
+ };
502
+ }
503
+ catch (error) {
504
+ console.error('Forgot password error:', error);
505
+ return {
506
+ success: false,
507
+ message: 'Failed to send password reset email',
508
+ };
509
+ }
510
+ }
511
+ /**
512
+ * Reset password using token
513
+ */
514
+ async resetPassword(token, newPassword) {
515
+ try {
516
+ const response = await resetPassword({
517
+ client: this.client,
518
+ body: {
519
+ token,
520
+ new_password: newPassword,
521
+ },
522
+ });
523
+ // Check for error responses (4xx/5xx)
524
+ if (response.error) {
525
+ const errorData = response.error;
526
+ return {
527
+ success: false,
528
+ message: (errorData === null || errorData === void 0 ? void 0 : errorData.detail) || 'Failed to reset password',
529
+ };
530
+ }
531
+ // Handle the auth response if login is automatic after reset
532
+ const data = response.data;
533
+ if ((data === null || data === void 0 ? void 0 : data.token) &&
534
+ typeof data.token === 'string' &&
535
+ data.token.length > 0) {
536
+ const { storeToken } = await import('./token-storage');
537
+ storeToken(data.token);
538
+ }
539
+ return {
540
+ success: true,
541
+ message: 'Password reset successfully',
542
+ };
543
+ }
544
+ catch (error) {
545
+ console.error('Reset password error:', error);
546
+ return {
547
+ success: false,
548
+ message: 'Failed to reset password',
549
+ };
550
+ }
551
+ }
552
+ /**
553
+ * Validate password reset token
554
+ */
555
+ async validateResetToken(token) {
556
+ try {
557
+ const response = await validateResetToken({
558
+ client: this.client,
559
+ query: { token },
560
+ });
561
+ const data = response.data;
562
+ return {
563
+ valid: (data === null || data === void 0 ? void 0 : data.valid) === true,
564
+ email: data === null || data === void 0 ? void 0 : data.email,
565
+ message: data === null || data === void 0 ? void 0 : data.message,
566
+ };
567
+ }
568
+ catch (error) {
569
+ console.error('Validate reset token error:', error);
570
+ return {
571
+ valid: false,
572
+ message: 'Invalid or expired reset token',
573
+ };
574
+ }
575
+ }
576
+ /**
577
+ * Verify email with token
578
+ */
579
+ async verifyEmail(token) {
580
+ try {
581
+ const response = await verifyEmail({
582
+ client: this.client,
583
+ body: { token },
584
+ });
585
+ // Check for error responses (4xx/5xx)
586
+ if (response.error) {
587
+ const errorData = response.error;
588
+ return {
589
+ success: false,
590
+ message: (errorData === null || errorData === void 0 ? void 0 : errorData.detail) || 'Failed to verify email',
591
+ };
592
+ }
593
+ const data = response.data;
594
+ // Handle the auth response if login is automatic after verification
595
+ if ((data === null || data === void 0 ? void 0 : data.token) &&
596
+ typeof data.token === 'string' &&
597
+ data.token.length > 0) {
598
+ const { storeToken } = await import('./token-storage');
599
+ storeToken(data.token);
600
+ }
601
+ return {
602
+ success: true,
603
+ message: 'Email verified successfully',
604
+ user: data === null || data === void 0 ? void 0 : data.user,
605
+ };
606
+ }
607
+ catch (error) {
608
+ console.error('Verify email error:', error);
609
+ return {
610
+ success: false,
611
+ message: 'Failed to verify email',
612
+ };
613
+ }
614
+ }
615
+ /**
616
+ * Resend verification email
617
+ */
618
+ async resendVerificationEmail(email) {
619
+ try {
620
+ await resendVerificationEmail({
621
+ client: this.client,
622
+ body: { email },
623
+ });
624
+ return {
625
+ success: true,
626
+ message: 'Verification email sent if the account exists',
627
+ };
628
+ }
629
+ catch (error) {
630
+ console.error('Resend verification email error:', error);
631
+ return {
632
+ success: false,
633
+ message: 'Failed to send verification email',
634
+ };
635
+ }
636
+ }
637
+ /**
638
+ * Get password policy requirements
639
+ */
640
+ async getPasswordPolicy() {
641
+ try {
642
+ const response = await getPasswordPolicy({
643
+ client: this.client,
644
+ });
645
+ const data = response.data;
646
+ return {
647
+ minLength: (data === null || data === void 0 ? void 0 : data.min_length) || 8,
648
+ requireUppercase: (data === null || data === void 0 ? void 0 : data.require_uppercase) || false,
649
+ requireLowercase: (data === null || data === void 0 ? void 0 : data.require_lowercase) || false,
650
+ requireNumbers: (data === null || data === void 0 ? void 0 : data.require_numbers) || false,
651
+ requireSpecial: (data === null || data === void 0 ? void 0 : data.require_special) || false,
652
+ specialCharacters: (data === null || data === void 0 ? void 0 : data.special_characters) || '!@#$%^&*()_+-=[]{}|;:,.<>?',
653
+ };
654
+ }
655
+ catch (error) {
656
+ console.error('Get password policy error:', error);
657
+ // Return default policy
658
+ return {
659
+ minLength: 8,
660
+ requireUppercase: true,
661
+ requireLowercase: true,
662
+ requireNumbers: true,
663
+ requireSpecial: true,
664
+ specialCharacters: '!@#$%^&*()_+-=[]{}|;:,.<>?',
665
+ };
666
+ }
667
+ }
668
+ /**
669
+ * Check password strength
670
+ */
671
+ async checkPasswordStrength(password, email) {
672
+ try {
673
+ const response = await checkPasswordStrength({
674
+ client: this.client,
675
+ body: { password, email },
676
+ });
677
+ const data = response.data;
678
+ return {
679
+ score: (data === null || data === void 0 ? void 0 : data.score) || 0,
680
+ strength: (data === null || data === void 0 ? void 0 : data.strength) || 'very-weak',
681
+ errors: (data === null || data === void 0 ? void 0 : data.errors) || [],
682
+ suggestions: (data === null || data === void 0 ? void 0 : data.suggestions) || [],
683
+ is_valid: (data === null || data === void 0 ? void 0 : data.is_valid) || false,
684
+ };
685
+ }
686
+ catch (error) {
687
+ console.error('Check password strength error:', error);
688
+ // Return basic strength calculation
689
+ let score = 0;
690
+ if (password.length >= 8)
691
+ score += 20;
692
+ if (password.length >= 12)
693
+ score += 20;
694
+ if (/[a-z]/.test(password))
695
+ score += 20;
696
+ if (/[A-Z]/.test(password))
697
+ score += 20;
698
+ if (/[0-9]/.test(password))
699
+ score += 10;
700
+ if (/[^a-zA-Z0-9]/.test(password))
701
+ score += 10;
702
+ return {
703
+ score,
704
+ strength: score < 20
705
+ ? 'very-weak'
706
+ : score < 40
707
+ ? 'weak'
708
+ : score < 60
709
+ ? 'fair'
710
+ : score < 80
711
+ ? 'good'
712
+ : 'strong',
713
+ errors: [],
714
+ suggestions: [],
715
+ is_valid: score >= 60,
716
+ };
717
+ }
718
+ }
719
+ /**
720
+ * Validate and safely cast SDK response data
721
+ */
722
+ normalizeUser(raw) {
723
+ var _a, _b, _c, _d, _e;
724
+ return {
725
+ id: raw.id,
726
+ email: raw.email,
727
+ name: raw.name,
728
+ emailVerified: (_a = raw.email_verified) !== null && _a !== void 0 ? _a : raw.emailVerified,
729
+ createdAt: (_c = (_b = raw.createdAt) !== null && _b !== void 0 ? _b : raw.created_at) !== null && _c !== void 0 ? _c : '',
730
+ updatedAt: (_e = (_d = raw.updatedAt) !== null && _d !== void 0 ? _d : raw.updated_at) !== null && _e !== void 0 ? _e : '',
731
+ };
732
+ }
733
+ validateSDKAuthResponse(data) {
734
+ if (!data || typeof data !== 'object') {
735
+ throw new Error('Invalid SDK response: expected object');
736
+ }
737
+ const response = data;
738
+ if (!response.user || typeof response.user !== 'object') {
739
+ throw new Error('Invalid SDK response: missing or invalid user');
740
+ }
741
+ const user = response.user;
742
+ if (!user.id || typeof user.id !== 'string') {
743
+ throw new Error('Invalid SDK response: user missing required id');
744
+ }
745
+ if (!user.email || typeof user.email !== 'string') {
746
+ throw new Error('Invalid SDK response: user missing required email');
747
+ }
748
+ response.user = this.normalizeUser(response.user);
749
+ return response;
750
+ }
751
+ validateSDKCurrentUserResponse(data) {
752
+ if (!data || typeof data !== 'object') {
753
+ throw new Error('Invalid SDK response: expected object');
754
+ }
755
+ const response = data;
756
+ // Check if the response is the user object directly (not nested under 'user' property)
757
+ if (response.id && response.email) {
758
+ return { user: this.normalizeUser(response) };
759
+ }
760
+ // Check if it's nested under 'user' property
761
+ if (!response.user || typeof response.user !== 'object') {
762
+ throw new Error('Invalid SDK response: missing or invalid user');
763
+ }
764
+ response.user = this.normalizeUser(response.user);
765
+ return response;
766
+ }
767
+ }