@elevasis/ui 1.2.1 → 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 (52) 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 +5 -1
  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-ZQVPUAGR.js → chunk-OLD3NQLI.js} +33 -31
  22. package/dist/{chunk-B64YDSAY.js → chunk-PCBXNHKY.js} +53 -97
  23. package/dist/chunk-QQOLC46E.js +75 -0
  24. package/dist/chunk-RNP5R5I3.js +1 -0
  25. package/dist/{chunk-YULUKCS6.js → chunk-SITSZUFW.js} +1 -1
  26. package/dist/chunk-TIRMFDM4.js +33 -0
  27. package/dist/{chunk-PYL4XW6H.js → chunk-TMFCNFLW.js} +1 -1
  28. package/dist/{chunk-S66I2PYB.js → chunk-TN3PU2WK.js} +1 -1
  29. package/dist/components/command-queue/index.js +6 -4
  30. package/dist/components/index.js +9 -7
  31. package/dist/components/notifications/index.js +4 -3
  32. package/dist/display/index.js +3 -2
  33. package/dist/hooks/index.d.ts +1 -1
  34. package/dist/hooks/index.js +5 -4
  35. package/dist/hooks/published.d.ts +1 -1
  36. package/dist/hooks/published.js +4 -3
  37. package/dist/index.d.ts +447 -117
  38. package/dist/index.js +22 -16
  39. package/dist/initialization/index.d.ts +49 -1
  40. package/dist/initialization/index.js +5 -2
  41. package/dist/organization/index.d.ts +61 -2
  42. package/dist/organization/index.js +5 -2
  43. package/dist/profile/index.d.ts +30 -2
  44. package/dist/profile/index.js +2 -1
  45. package/dist/provider/index.d.ts +112 -27
  46. package/dist/provider/index.js +11 -6
  47. package/dist/provider/published.d.ts +85 -13
  48. package/dist/provider/published.js +10 -4
  49. package/dist/utils/index.js +2 -1
  50. package/package.json +17 -4
  51. package/dist/chunk-GDV44UWF.js +0 -138
  52. package/dist/chunk-HBRMWW6V.js +0 -43
@@ -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;
@@ -99,16 +146,18 @@ interface ElevasisCoreProviderProps {
99
146
  */
100
147
  theme?: ElevasisCoreThemeConfig;
101
148
  /**
102
- * Override organization ID resolution.
103
- * Command-center passes Zustand-managed org ID here.
104
- * 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).
105
152
  */
106
153
  organizationId?: string | null;
107
154
  /** Custom QueryClient. If omitted, a default is created internally. */
108
155
  queryClient?: QueryClient;
109
156
  /**
110
157
  * API base URL (e.g., 'https://api.elevasis.com' or 'http://localhost:5170').
111
- * When provided, ElevasisCoreProvider composes ApiClientProvider + ElevasisServiceProvider internally.
158
+ * When provided, ElevasisCoreProvider composes the full provider stack:
159
+ * ApiClientProvider + ElevasisServiceProvider + ProfileProvider +
160
+ * OrganizationProvider + NotificationProvider + InitializationProvider.
112
161
  * When omitted, no service context is provided (theme-only mode).
113
162
  */
114
163
  apiUrl?: string;
@@ -118,11 +167,19 @@ interface ElevasisCoreProviderProps {
118
167
  */
119
168
  onError?: (endpoint: string, error: Error, details?: ApiErrorDetails) => void;
120
169
  /**
121
- * Override organization readiness check.
122
- * Defaults to `!!organizationId` if not provided.
123
- * 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.
124
172
  */
125
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;
126
183
  /**
127
184
  * Whether to inject CSS variables, `data-elevasis-scheme` attribute, and font links.
128
185
  * Set to `false` when the consumer has its own complete design system and only
@@ -157,21 +214,36 @@ interface ElevasisServiceProviderProps {
157
214
  * variables, set `data-elevasis-scheme`, or load fonts. Consumers that need
158
215
  * Elevasis theming should use `ElevasisProvider` (Mantine) instead.
159
216
  *
160
- * Composes: QueryClientProvider + auth provider + auth bridge.
161
- * 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.
162
224
  *
163
225
  * @example Headless SDK consumer
164
226
  * ```tsx
165
227
  * <ElevasisCoreProvider
166
228
  * auth={{ mode: 'authkit', clientId: '...', redirectUri: '/' }}
167
- * theme={{ colorScheme: 'dark', preset: 'default' }}
168
229
  * apiUrl="https://api.elevasis.com"
169
230
  * >
170
231
  * <Dashboard />
171
232
  * </ElevasisCoreProvider>
172
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
+ * ```
173
245
  */
174
- declare function ElevasisCoreProvider({ auth, 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;
175
247
 
176
248
  /**
177
249
  * Hook to access the ElevasisServiceProvider context.
@@ -202,5 +274,5 @@ declare function useElevasisServices(): ElevasisServiceContextValue;
202
274
  */
203
275
  declare function ElevasisServiceProvider({ apiRequest, organizationId, isReady, children }: ElevasisServiceProviderProps): react_jsx_runtime.JSX.Element;
204
276
 
205
- export { ElevasisCoreProvider, ElevasisServiceProvider, useElevasisServices };
206
- 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-ZQVPUAGR.js';
2
- import '../chunk-GDV44UWF.js';
3
- export { ElevasisServiceProvider, useElevasisServices } from '../chunk-KA7LO7U5.js';
4
- import '../chunk-7AI5ZYJ4.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';
5
7
  import '../chunk-QSVZP2NU.js';
8
+ import '../chunk-QQOLC46E.js';
9
+ import '../chunk-DD3CCMCZ.js';
10
+ import '../chunk-4KAG5U7A.js';
11
+ export { ElevasisServiceProvider, useElevasisServices } from '../chunk-KA7LO7U5.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.1",
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 };