@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.
- package/LICENSE +21 -0
- package/README.md +252 -0
- package/actions/entity-actions.d.ts +8 -0
- package/actions/entity-actions.js +16 -0
- package/actions/graph-actions.d.ts +3 -0
- package/actions/graph-actions.js +13 -0
- package/auth-components/AppSwitcher.d.ts +6 -0
- package/auth-components/AppSwitcher.js +28 -0
- package/auth-components/AuthGuard.d.ts +7 -0
- package/auth-components/AuthGuard.js +31 -0
- package/auth-components/AuthProvider.d.ts +9 -0
- package/auth-components/AuthProvider.js +565 -0
- package/auth-components/SessionWarningDialog.d.ts +1 -0
- package/auth-components/SessionWarningDialog.js +51 -0
- package/auth-components/SignInForm.d.ts +20 -0
- package/auth-components/SignInForm.js +139 -0
- package/auth-components/SignUpForm.d.ts +15 -0
- package/auth-components/SignUpForm.js +167 -0
- package/auth-components/TurnstileWidget.d.ts +99 -0
- package/auth-components/TurnstileWidget.js +224 -0
- package/auth-components/index.d.ts +6 -0
- package/auth-components/index.js +6 -0
- package/auth-core/cleanup.d.ts +44 -0
- package/auth-core/cleanup.js +157 -0
- package/auth-core/client.d.ts +121 -0
- package/auth-core/client.js +767 -0
- package/auth-core/config.d.ts +19 -0
- package/auth-core/config.js +56 -0
- package/auth-core/hooks.d.ts +19 -0
- package/auth-core/hooks.js +63 -0
- package/auth-core/index.d.ts +6 -0
- package/auth-core/index.js +6 -0
- package/auth-core/sso.d.ts +42 -0
- package/auth-core/sso.js +281 -0
- package/auth-core/token-storage.d.ts +58 -0
- package/auth-core/token-storage.js +177 -0
- package/auth-core/types.d.ts +145 -0
- package/auth-core/types.js +1 -0
- package/components/EntitySelector.d.ts +44 -0
- package/components/EntitySelector.js +64 -0
- package/components/EntitySelectorCore.d.ts +45 -0
- package/components/EntitySelectorCore.js +67 -0
- package/components/GraphSelectorCore.d.ts +21 -0
- package/components/GraphSelectorCore.js +39 -0
- package/components/PageLayout.d.ts +8 -0
- package/components/PageLayout.js +5 -0
- package/components/RepositoryGuard.d.ts +68 -0
- package/components/RepositoryGuard.js +91 -0
- package/components/console/ConsoleContent.d.ts +4 -0
- package/components/console/ConsoleContent.js +612 -0
- package/components/console/ConsoleMarkdown.d.ts +11 -0
- package/components/console/ConsoleMarkdown.js +49 -0
- package/components/console/ProgressiveText.d.ts +6 -0
- package/components/console/ProgressiveText.js +21 -0
- package/components/console/graphAwareConfig.d.ts +70 -0
- package/components/console/graphAwareConfig.js +411 -0
- package/components/console/index.d.ts +6 -0
- package/components/console/index.js +4 -0
- package/components/console/types.d.ts +84 -0
- package/components/console/types.js +1 -0
- package/components/graph-filters.d.ts +75 -0
- package/components/graph-filters.js +111 -0
- package/components/index.d.ts +10 -0
- package/components/index.js +9 -0
- package/components/repositories/ActiveSubscriptions.d.ts +26 -0
- package/components/repositories/ActiveSubscriptions.js +103 -0
- package/components/repositories/BrowseRepositories.d.ts +11 -0
- package/components/repositories/BrowseRepositories.js +184 -0
- package/components/repositories/index.d.ts +2 -0
- package/components/repositories/index.js +2 -0
- package/components/search/SearchContent.d.ts +4 -0
- package/components/search/SearchContent.js +168 -0
- package/components/search/index.d.ts +2 -0
- package/components/search/index.js +1 -0
- package/components/search/types.d.ts +15 -0
- package/components/search/types.js +1 -0
- package/contexts/entity-context.d.ts +28 -0
- package/contexts/entity-context.js +89 -0
- package/contexts/graph-context.d.ts +27 -0
- package/contexts/graph-context.js +128 -0
- package/contexts/index.d.ts +5 -0
- package/contexts/index.js +5 -0
- package/contexts/org-context.d.ts +25 -0
- package/contexts/org-context.js +64 -0
- package/contexts/service-offerings-context.d.ts +45 -0
- package/contexts/service-offerings-context.js +98 -0
- package/contexts/sidebar-context.d.ts +18 -0
- package/contexts/sidebar-context.js +44 -0
- package/hooks/index.d.ts +6 -0
- package/hooks/index.js +6 -0
- package/hooks/use-api-error.d.ts +3 -0
- package/hooks/use-api-error.js +24 -0
- package/hooks/use-media-query.d.ts +1 -0
- package/hooks/use-media-query.js +21 -0
- package/hooks/use-streaming-query.d.ts +22 -0
- package/hooks/use-streaming-query.js +142 -0
- package/hooks/use-toast.d.ts +37 -0
- package/hooks/use-toast.js +117 -0
- package/hooks/use-user-limits.d.ts +12 -0
- package/hooks/use-user-limits.js +73 -0
- package/hooks/use-user.d.ts +11 -0
- package/hooks/use-user.js +39 -0
- package/index.d.ts +29 -0
- package/index.js +77 -0
- package/lib/entity-cookie.d.ts +10 -0
- package/lib/entity-cookie.js +38 -0
- package/lib/graph-cookie.d.ts +11 -0
- package/lib/graph-cookie.js +62 -0
- package/lib/graph-tiers.d.ts +41 -0
- package/lib/graph-tiers.js +107 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/sidebar-cookie.d.ts +11 -0
- package/lib/sidebar-cookie.js +42 -0
- package/library/colors.d.ts +4 -0
- package/library/colors.js +41 -0
- package/library/components/ClassificationPicker.d.ts +8 -0
- package/library/components/ClassificationPicker.js +55 -0
- package/library/components/ElementBrowser.d.ts +11 -0
- package/library/components/ElementBrowser.js +106 -0
- package/library/components/ElementDetail.d.ts +7 -0
- package/library/components/ElementDetail.js +97 -0
- package/library/components/LibraryHierarchy.d.ts +13 -0
- package/library/components/LibraryHierarchy.js +380 -0
- package/library/components/TaxonomySidebar.d.ts +6 -0
- package/library/components/TaxonomySidebar.js +45 -0
- package/library/index.d.ts +8 -0
- package/library/index.js +7 -0
- package/package.json +37 -0
- package/research/CoverageCard.d.ts +12 -0
- package/research/CoverageCard.js +15 -0
- package/research/CoverageGrid.d.ts +6 -0
- package/research/CoverageGrid.js +9 -0
- package/research/CoverageHistory.d.ts +5 -0
- package/research/CoverageHistory.js +7 -0
- package/research/ResearchArticle.d.ts +15 -0
- package/research/ResearchArticle.js +26 -0
- package/research/catalog.d.ts +14 -0
- package/research/catalog.js +42 -0
- package/research/index.d.ts +6 -0
- package/research/index.js +9 -0
- package/research/types.d.ts +38 -0
- package/research/types.js +4 -0
- package/task-monitoring/hooks.d.ts +26 -0
- package/task-monitoring/hooks.js +126 -0
- package/task-monitoring/index.d.ts +5 -0
- package/task-monitoring/index.js +7 -0
- package/task-monitoring/operationErrors.d.ts +82 -0
- package/task-monitoring/operationErrors.js +251 -0
- package/task-monitoring/operationHooks.d.ts +117 -0
- package/task-monitoring/operationHooks.js +536 -0
- package/task-monitoring/operationMonitor.d.ts +78 -0
- package/task-monitoring/operationMonitor.js +200 -0
- package/task-monitoring/operationTypes.d.ts +236 -0
- package/task-monitoring/operationTypes.js +60 -0
- package/task-monitoring/taskMonitor.d.ts +14 -0
- package/task-monitoring/taskMonitor.js +132 -0
- package/task-monitoring/types.d.ts +31 -0
- package/task-monitoring/types.js +1 -0
- package/theme/flowbite-theme.d.ts +758 -0
- package/theme/flowbite-theme.js +765 -0
- package/theme/index.d.ts +1 -0
- package/theme/index.js +1 -0
- package/types/entity.d.ts +19 -0
- package/types/index.d.ts +2 -0
- package/types/index.js +1 -0
- package/types/user.d.ts +6 -0
- package/ui-components/ConfirmModal.d.ts +41 -0
- package/ui-components/ConfirmModal.js +19 -0
- package/ui-components/EmptyState.d.ts +22 -0
- package/ui-components/EmptyState.js +10 -0
- package/ui-components/LoadingState.d.ts +27 -0
- package/ui-components/LoadingState.js +12 -0
- package/ui-components/Logo.d.ts +28 -0
- package/ui-components/Logo.js +95 -0
- package/ui-components/Spinner.d.ts +37 -0
- package/ui-components/Spinner.js +48 -0
- package/ui-components/StatCard.d.ts +21 -0
- package/ui-components/StatCard.js +10 -0
- package/ui-components/api-keys/ApiKeyDisplay.d.ts +13 -0
- package/ui-components/api-keys/ApiKeyDisplay.js +7 -0
- package/ui-components/api-keys/ApiKeyTable.d.ts +9 -0
- package/ui-components/api-keys/ApiKeyTable.js +17 -0
- package/ui-components/api-keys/ApiKeysCard.d.ts +6 -0
- package/ui-components/api-keys/ApiKeysCard.js +97 -0
- package/ui-components/api-keys/CreateApiKeyModal.d.ts +11 -0
- package/ui-components/api-keys/CreateApiKeyModal.js +47 -0
- package/ui-components/api-keys/SecureApiKeyField.d.ts +13 -0
- package/ui-components/api-keys/SecureApiKeyField.js +64 -0
- package/ui-components/api-keys/index.d.ts +5 -0
- package/ui-components/api-keys/index.js +5 -0
- package/ui-components/chat/ChatHeader.d.ts +12 -0
- package/ui-components/chat/ChatHeader.js +5 -0
- package/ui-components/chat/ChatInputArea.d.ts +16 -0
- package/ui-components/chat/ChatInputArea.js +9 -0
- package/ui-components/chat/ChatMessage.d.ts +7 -0
- package/ui-components/chat/ChatMessage.js +24 -0
- package/ui-components/chat/DeepResearchToggle.d.ts +8 -0
- package/ui-components/chat/DeepResearchToggle.js +13 -0
- package/ui-components/chat/index.d.ts +9 -0
- package/ui-components/chat/index.js +8 -0
- package/ui-components/chat/types.d.ts +23 -0
- package/ui-components/chat/types.js +51 -0
- package/ui-components/forms/PasswordRequirements.d.ts +10 -0
- package/ui-components/forms/PasswordRequirements.js +15 -0
- package/ui-components/forms/SettingsCard.d.ts +11 -0
- package/ui-components/forms/SettingsCard.js +5 -0
- package/ui-components/forms/SettingsFormField.d.ts +18 -0
- package/ui-components/forms/SettingsFormField.js +17 -0
- package/ui-components/forms/StatusAlert.d.ts +8 -0
- package/ui-components/forms/StatusAlert.js +7 -0
- package/ui-components/forms/index.d.ts +4 -0
- package/ui-components/forms/index.js +4 -0
- package/ui-components/index.d.ts +13 -0
- package/ui-components/index.js +18 -0
- package/ui-components/layout/CoreNavbar.d.ts +14 -0
- package/ui-components/layout/CoreNavbar.js +53 -0
- package/ui-components/layout/CoreSidebar.d.ts +28 -0
- package/ui-components/layout/CoreSidebar.js +62 -0
- package/ui-components/layout/LandingFooter.d.ts +28 -0
- package/ui-components/layout/LandingFooter.js +34 -0
- package/ui-components/layout/PageContainer.d.ts +8 -0
- package/ui-components/layout/PageContainer.js +17 -0
- package/ui-components/layout/PageHeader.d.ts +23 -0
- package/ui-components/layout/PageHeader.js +12 -0
- package/ui-components/layout/SettingsContainer.d.ts +10 -0
- package/ui-components/layout/SettingsContainer.js +9 -0
- package/ui-components/layout/ThemeToggle.d.ts +4 -0
- package/ui-components/layout/ThemeToggle.js +6 -0
- package/ui-components/layout/index.d.ts +7 -0
- package/ui-components/layout/index.js +7 -0
- package/ui-components/settings/GeneralInformationCard.d.ts +12 -0
- package/ui-components/settings/GeneralInformationCard.js +72 -0
- package/ui-components/settings/PasswordInformationCard.d.ts +10 -0
- package/ui-components/settings/PasswordInformationCard.js +167 -0
- package/ui-components/settings/SettingsPageHeader.d.ts +7 -0
- package/ui-components/settings/SettingsPageHeader.js +6 -0
- package/ui-components/settings/index.d.ts +3 -0
- package/ui-components/settings/index.js +3 -0
- package/ui-components/support/SupportModal.d.ts +15 -0
- package/ui-components/support/SupportModal.js +74 -0
- package/ui-components/support/index.d.ts +2 -0
- package/ui-components/support/index.js +1 -0
- package/ui-components/types/index.d.ts +39 -0
- package/ui-components/types/index.js +1 -0
- package/utils/index.d.ts +31 -0
- package/utils/index.js +38 -0
- package/utils/turnstile-config.d.ts +11 -0
- 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
|
+
}
|