@elevasis/ui 1.2.0 → 1.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 (54) hide show
  1. package/dist/api/hooks/useApiClient.d.ts +54 -0
  2. package/dist/api/hooks/useApiClient.d.ts.map +1 -0
  3. package/dist/api/hooks/useApiClient.js +185 -0
  4. package/dist/api/index.d.ts +49 -11
  5. package/dist/api/index.js +3 -2
  6. package/dist/auth/index.d.ts +88 -2
  7. package/dist/auth/index.js +6 -2
  8. package/dist/{chunk-5UWFGBFM.js → chunk-4KAG5U7A.js} +18 -4
  9. package/dist/chunk-4VGWQ5AN.js +91 -0
  10. package/dist/{chunk-JKERRYVS.js → chunk-BLO4SISK.js} +7 -3
  11. package/dist/chunk-BWCC6ZJC.js +202 -0
  12. package/dist/{chunk-WNWKOCGJ.js → chunk-BZTA7IIL.js} +1 -1
  13. package/dist/chunk-DD3CCMCZ.js +15 -0
  14. package/dist/{chunk-GEFB5YIR.js → chunk-EZMRFWZQ.js} +1 -1
  15. package/dist/chunk-FDCVFCOQ.js +105 -0
  16. package/dist/chunk-FLJXZ7YC.js +150 -0
  17. package/dist/{chunk-7AI5ZYJ4.js → chunk-JVAZHVNV.js} +2 -94
  18. package/dist/{chunk-ZGHDPDTF.js → chunk-JYSYHVLU.js} +3 -3
  19. package/dist/{chunk-J3FALDQE.js → chunk-NXHL23JW.js} +7 -13
  20. package/dist/{chunk-OUHGHTE7.js → chunk-O3PY6B6E.js} +3 -2
  21. package/dist/chunk-OLD3NQLI.js +91 -0
  22. package/dist/{chunk-XVPEDNIM.js → chunk-PCBXNHKY.js} +325 -152
  23. package/dist/chunk-QQOLC46E.js +75 -0
  24. package/dist/{chunk-KSG4C5DD.js → chunk-QSVZP2NU.js} +2 -1
  25. package/dist/chunk-RNP5R5I3.js +1 -0
  26. package/dist/{chunk-YULUKCS6.js → chunk-SITSZUFW.js} +1 -1
  27. package/dist/chunk-TIRMFDM4.js +33 -0
  28. package/dist/{chunk-PYL4XW6H.js → chunk-TMFCNFLW.js} +1 -1
  29. package/dist/{chunk-S66I2PYB.js → chunk-TN3PU2WK.js} +1 -1
  30. package/dist/components/command-queue/index.js +6 -4
  31. package/dist/components/index.js +9 -7
  32. package/dist/components/notifications/index.js +4 -3
  33. package/dist/display/index.js +3 -2
  34. package/dist/hooks/index.d.ts +1 -1
  35. package/dist/hooks/index.js +5 -4
  36. package/dist/hooks/published.d.ts +1 -1
  37. package/dist/hooks/published.js +4 -3
  38. package/dist/index.d.ts +458 -120
  39. package/dist/index.js +23 -17
  40. package/dist/initialization/index.d.ts +49 -1
  41. package/dist/initialization/index.js +5 -2
  42. package/dist/organization/index.d.ts +61 -2
  43. package/dist/organization/index.js +5 -2
  44. package/dist/profile/index.d.ts +30 -2
  45. package/dist/profile/index.js +2 -1
  46. package/dist/provider/index.d.ts +123 -30
  47. package/dist/provider/index.js +11 -6
  48. package/dist/provider/published.d.ts +96 -16
  49. package/dist/provider/published.js +10 -4
  50. package/dist/utils/index.js +2 -1
  51. package/package.json +17 -4
  52. package/dist/chunk-GDV44UWF.js +0 -138
  53. package/dist/chunk-HBRMWW6V.js +0 -43
  54. package/dist/chunk-QGEFP2EU.js +0 -399
@@ -10,6 +10,53 @@ interface ApiErrorDetails {
10
10
  requestId?: string;
11
11
  }
12
12
 
13
+ /**
14
+ * Pluggable notification adapter interface.
15
+ *
16
+ * Implement this to connect any notification library (Mantine, react-toastify, etc.)
17
+ * to the Elevasis UI hooks.
18
+ */
19
+ interface NotificationAdapter {
20
+ success(title: string, message: string): void;
21
+ error(title: string, message: string): void;
22
+ info(title: string, message: string): void;
23
+ warning(title: string, message: string): void;
24
+ /** Formats and displays an API error using structured error-utils helpers. */
25
+ apiError(error: unknown): void;
26
+ }
27
+ /**
28
+ * Provides a notification adapter to all descendant components.
29
+ *
30
+ * Pass a `MantineNotificationAdapter` for Command Center, or any custom
31
+ * adapter for other consumers (template, tests, etc.).
32
+ *
33
+ * When omitted, hooks fall back to the console adapter automatically.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * import { NotificationProvider } from '@repo/ui/provider'
38
+ * import { mantineNotificationAdapter } from '@repo/ui/provider'
39
+ *
40
+ * <NotificationProvider adapter={mantineNotificationAdapter}>
41
+ * <App />
42
+ * </NotificationProvider>
43
+ * ```
44
+ */
45
+ declare function NotificationProvider({ adapter, children }: {
46
+ adapter: NotificationAdapter;
47
+ children: ReactNode;
48
+ }): react_jsx_runtime.JSX.Element;
49
+ /**
50
+ * Returns the active notification adapter.
51
+ *
52
+ * Falls back to the console adapter when used outside a NotificationProvider,
53
+ * so hooks remain functional in template environments without Mantine.
54
+ *
55
+ * Named `useNotificationAdapter` to avoid collision with the data-fetching
56
+ * `useNotifications` hook exported from `hooks/monitoring`.
57
+ */
58
+ declare function useNotificationAdapter(): NotificationAdapter;
59
+
13
60
  /** Flat + per-scheme override pattern. Flat values apply to both; `light`/`dark` win over flat. */
14
61
  type WithSchemes<T> = T & {
15
62
  light?: T;
@@ -81,6 +128,8 @@ interface OAuthConfig {
81
128
  tokenStorage?: 'session';
82
129
  /** Pre-select organization in WorkOS flow. */
83
130
  organizationId?: string;
131
+ /** Auth provider for the authorize request. Defaults to 'authkit' (hosted login UI). */
132
+ provider?: 'authkit' | 'GoogleOAuth' | 'MicrosoftOAuth' | 'GitHubOAuth' | 'AppleOAuth';
84
133
  }
85
134
  /** Deferred -- will throw at runtime. */
86
135
  interface ApiKeyConfig {
@@ -97,16 +146,18 @@ interface ElevasisCoreProviderProps {
97
146
  */
98
147
  theme?: ElevasisCoreThemeConfig;
99
148
  /**
100
- * Override organization ID resolution.
101
- * Command-center passes Zustand-managed org ID here.
102
- * SDK consumers typically omit this (auto-resolved from JWT/API key).
149
+ * @deprecated Organization ID is now resolved automatically via OrganizationProvider.
150
+ * This prop is accepted for backwards compatibility during migration but is no longer
151
+ * used when the full provider stack is active (apiUrl provided).
103
152
  */
104
153
  organizationId?: string | null;
105
154
  /** Custom QueryClient. If omitted, a default is created internally. */
106
155
  queryClient?: QueryClient;
107
156
  /**
108
157
  * API base URL (e.g., 'https://api.elevasis.com' or 'http://localhost:5170').
109
- * When provided, ElevasisCoreProvider composes ApiClientProvider + ElevasisServiceProvider internally.
158
+ * When provided, ElevasisCoreProvider composes the full provider stack:
159
+ * ApiClientProvider + ElevasisServiceProvider + ProfileProvider +
160
+ * OrganizationProvider + NotificationProvider + InitializationProvider.
110
161
  * When omitted, no service context is provided (theme-only mode).
111
162
  */
112
163
  apiUrl?: string;
@@ -116,11 +167,25 @@ interface ElevasisCoreProviderProps {
116
167
  */
117
168
  onError?: (endpoint: string, error: Error, details?: ApiErrorDetails) => void;
118
169
  /**
119
- * Override organization readiness check.
120
- * Defaults to `!!organizationId` if not provided.
121
- * Command-center passes `!!currentMembership` for its stricter readiness requirement.
170
+ * @deprecated Organization readiness is now managed internally by OrganizationProvider.
171
+ * Accepted for backwards compatibility but ignored when apiUrl is provided.
122
172
  */
123
173
  isOrganizationReady?: boolean;
174
+ /**
175
+ * Notification adapter for displaying success/error/info messages.
176
+ * When provided, wraps the subtree in a NotificationProvider with this adapter.
177
+ * When omitted, the console fallback adapter is used automatically.
178
+ *
179
+ * ElevasisUIProvider (Mantine variant) passes mantineNotificationAdapter here automatically.
180
+ * Headless/SDK consumers can pass a custom adapter or omit for console output.
181
+ */
182
+ notifications?: NotificationAdapter;
183
+ /**
184
+ * Whether to inject CSS variables, `data-elevasis-scheme` attribute, and font links.
185
+ * Set to `false` when the consumer has its own complete design system and only
186
+ * needs auth + API from this provider. Defaults to `true`.
187
+ */
188
+ injectStyles?: boolean;
124
189
  children: ReactNode;
125
190
  }
126
191
  /**
@@ -145,25 +210,40 @@ interface ElevasisServiceProviderProps {
145
210
  /**
146
211
  * Headless root provider for Elevasis-powered applications.
147
212
  *
148
- * Same capabilities as ElevasisUIProvider but without any Mantine dependency.
149
- * Injects CSS variables via a `<style>` tag and sets `data-elevasis-scheme`
150
- * on the `<html>` element.
213
+ * Pure auth + API provider with no style side-effects. Does not inject CSS
214
+ * variables, set `data-elevasis-scheme`, or load fonts. Consumers that need
215
+ * Elevasis theming should use `ElevasisProvider` (Mantine) instead.
151
216
  *
152
- * Composes: QueryClientProvider + auth provider + auth bridge.
153
- * When apiUrl is provided, also composes ApiClientProvider + ElevasisServiceProvider.
217
+ * When `apiUrl` is provided, composes the full provider stack:
218
+ * QueryClientProvider -> AuthProvider -> ApiClientProvider ->
219
+ * ElevasisServiceProvider -> ProfileProvider -> OrganizationProvider ->
220
+ * NotificationProvider -> InitializationProvider
221
+ *
222
+ * The `notifications` prop wires a custom adapter (e.g. mantineNotificationAdapter)
223
+ * into the NotificationProvider. When omitted, the console fallback is used.
154
224
  *
155
225
  * @example Headless SDK consumer
156
226
  * ```tsx
157
227
  * <ElevasisCoreProvider
158
228
  * auth={{ mode: 'authkit', clientId: '...', redirectUri: '/' }}
159
- * theme={{ colorScheme: 'dark', preset: 'default' }}
160
229
  * apiUrl="https://api.elevasis.com"
161
230
  * >
162
231
  * <Dashboard />
163
232
  * </ElevasisCoreProvider>
164
233
  * ```
234
+ *
235
+ * @example With custom notification adapter
236
+ * ```tsx
237
+ * <ElevasisCoreProvider
238
+ * auth={{ mode: 'authkit', clientId: '...', redirectUri: '/' }}
239
+ * apiUrl="https://api.elevasis.com"
240
+ * notifications={myNotificationAdapter}
241
+ * >
242
+ * <Dashboard />
243
+ * </ElevasisCoreProvider>
244
+ * ```
165
245
  */
166
- declare function ElevasisCoreProvider({ auth, theme, organizationId, queryClient, apiUrl, onError, isOrganizationReady, children }: ElevasisCoreProviderProps): react_jsx_runtime.JSX.Element;
246
+ declare function ElevasisCoreProvider({ auth, queryClient, apiUrl, onError, notifications, children }: ElevasisCoreProviderProps): react_jsx_runtime.JSX.Element;
167
247
 
168
248
  /**
169
249
  * Hook to access the ElevasisServiceProvider context.
@@ -194,5 +274,5 @@ declare function useElevasisServices(): ElevasisServiceContextValue;
194
274
  */
195
275
  declare function ElevasisServiceProvider({ apiRequest, organizationId, isReady, children }: ElevasisServiceProviderProps): react_jsx_runtime.JSX.Element;
196
276
 
197
- export { ElevasisCoreProvider, ElevasisServiceProvider, useElevasisServices };
198
- export type { ApiKeyConfig, AuthConfig, AuthKitConfig, ElevasisCoreProviderProps, ElevasisCoreThemeConfig, ElevasisServiceContextValue, ElevasisServiceProviderProps, ElevasisTokenOverrides, OAuthConfig, WithSchemes };
277
+ export { ElevasisCoreProvider, ElevasisServiceProvider, NotificationProvider, useElevasisServices, useNotificationAdapter };
278
+ export type { ApiKeyConfig, AuthConfig, AuthKitConfig, ElevasisCoreProviderProps, ElevasisCoreThemeConfig, ElevasisServiceContextValue, ElevasisServiceProviderProps, ElevasisTokenOverrides, NotificationAdapter, OAuthConfig, WithSchemes };
@@ -1,6 +1,12 @@
1
- export { ElevasisCoreProvider } from '../chunk-XVPEDNIM.js';
2
- import '../chunk-GDV44UWF.js';
1
+ export { ElevasisCoreProvider } from '../chunk-OLD3NQLI.js';
2
+ import '../chunk-FLJXZ7YC.js';
3
+ import '../chunk-BWCC6ZJC.js';
4
+ export { NotificationProvider, useNotificationAdapter } from '../chunk-TIRMFDM4.js';
5
+ import '../chunk-JVAZHVNV.js';
6
+ import '../chunk-4VGWQ5AN.js';
7
+ import '../chunk-QSVZP2NU.js';
8
+ import '../chunk-QQOLC46E.js';
9
+ import '../chunk-DD3CCMCZ.js';
10
+ import '../chunk-4KAG5U7A.js';
3
11
  export { ElevasisServiceProvider, useElevasisServices } from '../chunk-KA7LO7U5.js';
4
- import '../chunk-7AI5ZYJ4.js';
5
- import '../chunk-KSG4C5DD.js';
6
12
  import '../chunk-7PLEQFHO.js';
@@ -1 +1,2 @@
1
- export { APIClientError, formatDate, formatErrorMessage, getErrorInfo, getErrorTitle, getResourceColor, getResourceIcon, isAPIClientError, showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification, validateEmail } from '../chunk-7AI5ZYJ4.js';
1
+ export { formatDate, getResourceColor, getResourceIcon, showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification, validateEmail } from '../chunk-JVAZHVNV.js';
2
+ export { APIClientError, formatErrorMessage, getErrorInfo, getErrorTitle, isAPIClientError } from '../chunk-4VGWQ5AN.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/ui",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "UI components and platform-aware hooks for building custom frontends on the Elevasis platform",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,6 +26,18 @@
26
26
  "./sse": {
27
27
  "types": "./dist/sse/index.d.ts",
28
28
  "import": "./dist/sse/index.js"
29
+ },
30
+ "./initialization": {
31
+ "types": "./dist/initialization/index.d.ts",
32
+ "import": "./dist/initialization/index.js"
33
+ },
34
+ "./profile": {
35
+ "types": "./dist/profile/index.d.ts",
36
+ "import": "./dist/profile/index.js"
37
+ },
38
+ "./organization": {
39
+ "types": "./dist/organization/index.d.ts",
40
+ "import": "./dist/organization/index.js"
29
41
  }
30
42
  },
31
43
  "publishConfig": {
@@ -33,7 +45,8 @@
33
45
  "peerDependencies": {
34
46
  "react": "^19.2.0",
35
47
  "react-dom": "^19.2.0",
36
- "@tanstack/react-query": "^5.76.2"
48
+ "@tanstack/react-query": "^5.76.2",
49
+ "@tanstack/react-router": "^1.131.28"
37
50
  }
38
51
  },
39
52
  "peerDependencies": {
@@ -67,8 +80,8 @@
67
80
  "typescript": "5.9.2",
68
81
  "vite": "^7.0.0",
69
82
  "@repo/core": "0.0.0",
70
- "@repo/eslint-config": "0.0.0",
71
- "@repo/typescript-config": "0.0.0"
83
+ "@repo/typescript-config": "0.0.0",
84
+ "@repo/eslint-config": "0.0.0"
72
85
  },
73
86
  "dependencies": {
74
87
  "@dagrejs/dagre": "^1.1.4",
@@ -1,138 +0,0 @@
1
- import { APIClientError } from './chunk-7AI5ZYJ4.js';
2
- import { createContext, useContext, useMemo, useCallback } from 'react';
3
- import { jsx } from 'react/jsx-runtime';
4
-
5
- var ApiClientContext = createContext(null);
6
- function useApiClientContext() {
7
- const context = useContext(ApiClientContext);
8
- if (!context) {
9
- throw new Error("useApiClient must be used within ApiClientProvider");
10
- }
11
- return context;
12
- }
13
- function ApiClientProvider({
14
- children,
15
- getAccessToken,
16
- organizationId,
17
- isOrganizationReady,
18
- onError
19
- }) {
20
- const value = useMemo(
21
- () => ({
22
- getAccessToken,
23
- organizationId,
24
- isOrganizationReady,
25
- onError
26
- }),
27
- [getAccessToken, organizationId, isOrganizationReady, onError]
28
- );
29
- return /* @__PURE__ */ jsx(ApiClientContext.Provider, { value, children });
30
- }
31
-
32
- // ../core/src/platform/constants/http.ts
33
- var HTTP_HEADERS = {
34
- /**
35
- * Organization context header
36
- * Note: Node.js normalizes all headers to lowercase, so we use lowercase consistently
37
- */
38
- WORKOS_ORGANIZATION_ID: "workos-organization-id",
39
- AGENT_ORGANIZATION: "x-agent-organization",
40
- AGENT_MODE: "x-agent-mode"
41
- };
42
-
43
- // src/api/hooks/useApiClient.ts
44
- var DEFAULT_TIMEOUT_MS = 6e4;
45
- function createUseApiClient(useOrganizations, apiUrl) {
46
- return function useApiClient() {
47
- const { getAccessToken, organizationId, isOrganizationReady, onError } = useApiClientContext();
48
- const { isInitializing, isOrgRefreshing } = useOrganizations();
49
- const handleResponseError = useCallback(
50
- async (endpoint, response, options) => {
51
- const errorData = await response.json().catch(() => ({
52
- error: `HTTP ${response.status}`,
53
- code: "INTERNAL_SERVER_ERROR"
54
- }));
55
- if (response.status >= 500 && onError) {
56
- onError(endpoint, new Error(errorData.error), {
57
- method: options.method || "GET",
58
- statusCode: response.status,
59
- requestId: errorData.requestId
60
- });
61
- }
62
- throw new APIClientError(errorData.error, errorData.code, response.status, errorData.requestId, errorData.fields, errorData.retryAfter);
63
- },
64
- [onError]
65
- );
66
- const apiRequest = useCallback(
67
- async (endpoint, options = {}) => {
68
- try {
69
- const token = await getAccessToken();
70
- const headers = {
71
- ...options.body ? { "Content-Type": "application/json" } : {},
72
- ...token ? { Authorization: `Bearer ${token}` } : {},
73
- ...organizationId && { [HTTP_HEADERS.WORKOS_ORGANIZATION_ID]: organizationId },
74
- ...options.headers
75
- };
76
- const timeoutSignal = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
77
- const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
78
- const response = await fetch(`${apiUrl}/api${endpoint}`, {
79
- ...options,
80
- headers,
81
- signal
82
- });
83
- if (!response.ok) {
84
- await handleResponseError(endpoint, response, options);
85
- }
86
- if (response.status === 204) {
87
- return void 0;
88
- }
89
- const responseData = await response.json();
90
- return responseData;
91
- } catch (error) {
92
- if (error instanceof Error && error.message.includes("No access token")) {
93
- const headers = {
94
- ...options.body ? { "Content-Type": "application/json" } : {},
95
- ...options.headers
96
- };
97
- const fallbackTimeoutSignal = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
98
- const fallbackSignal = options.signal ? AbortSignal.any([options.signal, fallbackTimeoutSignal]) : fallbackTimeoutSignal;
99
- const response = await fetch(`${apiUrl}/api${endpoint}`, {
100
- ...options,
101
- headers,
102
- signal: fallbackSignal
103
- });
104
- if (!response.ok) {
105
- await handleResponseError(endpoint, response, options);
106
- }
107
- if (response.status === 204) {
108
- return void 0;
109
- }
110
- return response.json();
111
- }
112
- throw error;
113
- }
114
- },
115
- [getAccessToken, organizationId, handleResponseError, apiUrl]
116
- );
117
- const deferredApiRequest = useCallback(
118
- async (endpoint, options = {}) => {
119
- if (isInitializing || isOrgRefreshing) {
120
- throw new Error("Organization context is still initializing. Please wait.");
121
- }
122
- if (!isOrganizationReady) {
123
- throw new Error("No organization selected. Please select an organization.");
124
- }
125
- return apiRequest(endpoint, options);
126
- },
127
- [apiRequest, isInitializing, isOrgRefreshing, isOrganizationReady]
128
- );
129
- return {
130
- apiRequest,
131
- deferredApiRequest,
132
- isOrganizationReady,
133
- isInitializing: isInitializing || isOrgRefreshing
134
- };
135
- };
136
- }
137
-
138
- export { ApiClientProvider, createUseApiClient, useApiClientContext };
@@ -1,43 +0,0 @@
1
- import { useAuthContext } from './chunk-7PLEQFHO.js';
2
- import { useRef, useCallback, useEffect } from 'react';
3
- import { useQueryClient } from '@tanstack/react-query';
4
-
5
- function useStableAccessToken() {
6
- const { getAccessToken } = useAuthContext();
7
- const getAccessTokenRef = useRef(getAccessToken);
8
- getAccessTokenRef.current = getAccessToken;
9
- return useCallback(() => {
10
- return getAccessTokenRef.current();
11
- }, []);
12
- }
13
- function useSessionCheck() {
14
- const { user } = useAuthContext();
15
- const queryClient = useQueryClient();
16
- const isCheckingRef = useRef(false);
17
- useEffect(() => {
18
- const handleVisibilityChange = async () => {
19
- if (isCheckingRef.current || document.visibilityState !== "visible") {
20
- return;
21
- }
22
- isCheckingRef.current = true;
23
- try {
24
- if (!user) {
25
- window.location.replace("/login");
26
- return;
27
- }
28
- await queryClient.cancelQueries();
29
- queryClient.invalidateQueries();
30
- } finally {
31
- isCheckingRef.current = false;
32
- }
33
- };
34
- document.addEventListener("visibilitychange", handleVisibilityChange);
35
- window.addEventListener("focus", handleVisibilityChange);
36
- return () => {
37
- document.removeEventListener("visibilitychange", handleVisibilityChange);
38
- window.removeEventListener("focus", handleVisibilityChange);
39
- };
40
- }, [user, queryClient]);
41
- }
42
-
43
- export { useSessionCheck, useStableAccessToken };