@elevasis/ui 1.2.1 → 1.3.1

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 (59) hide show
  1. package/dist/CoreAuthKitInner-3J4RVQO6.js +43 -0
  2. package/dist/api/index.d.ts +32 -18
  3. package/dist/api/index.js +4 -2
  4. package/dist/auth/context.d.ts +23 -5
  5. package/dist/auth/index.d.ts +119 -30
  6. package/dist/auth/index.js +6 -3
  7. package/dist/chunk-2JBWPFHF.js +108 -0
  8. package/dist/chunk-4VGWQ5AN.js +91 -0
  9. package/dist/chunk-72HOBFMP.js +87 -0
  10. package/dist/{chunk-WNWKOCGJ.js → chunk-A3MCANC6.js} +296 -2
  11. package/dist/{chunk-JKERRYVS.js → chunk-BLO4SISK.js} +7 -3
  12. package/dist/chunk-DD3CCMCZ.js +15 -0
  13. package/dist/chunk-FWZJH3TL.js +13 -0
  14. package/dist/{chunk-GEFB5YIR.js → chunk-JBFFCZI4.js} +1 -1
  15. package/dist/chunk-JGJSZ3UE.js +47 -0
  16. package/dist/{chunk-7AI5ZYJ4.js → chunk-JVAZHVNV.js} +2 -94
  17. package/dist/{chunk-ZGHDPDTF.js → chunk-JYSYHVLU.js} +3 -3
  18. package/dist/{chunk-5UWFGBFM.js → chunk-L2CM2CUA.js} +16 -4
  19. package/dist/chunk-NEK6JKPW.js +75 -0
  20. package/dist/{chunk-J3FALDQE.js → chunk-NXHL23JW.js} +7 -13
  21. package/dist/{chunk-OUHGHTE7.js → chunk-O3PY6B6E.js} +3 -2
  22. package/dist/{chunk-YULUKCS6.js → chunk-PVVQTENF.js} +1 -1
  23. package/dist/chunk-TIRMFDM4.js +33 -0
  24. package/dist/{chunk-PYL4XW6H.js → chunk-TMFCNFLW.js} +1 -1
  25. package/dist/{chunk-S66I2PYB.js → chunk-TN3PU2WK.js} +1 -1
  26. package/dist/chunk-TYV5NJV2.js +1 -0
  27. package/dist/{chunk-B64YDSAY.js → chunk-TZPAA4RC.js} +54 -97
  28. package/dist/chunk-UMXDDEAG.js +148 -0
  29. package/dist/chunk-XLV6LYN2.js +157 -0
  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 +2630 -3
  35. package/dist/hooks/index.js +9 -5
  36. package/dist/hooks/published.d.ts +2630 -3
  37. package/dist/hooks/published.js +7 -3
  38. package/dist/index.d.ts +759 -164
  39. package/dist/index.js +24 -18
  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 +116 -43
  47. package/dist/provider/index.js +10 -6
  48. package/dist/provider/published.d.ts +88 -28
  49. package/dist/provider/published.js +9 -4
  50. package/dist/supabase/index.js +2 -47
  51. package/dist/utils/index.js +2 -1
  52. package/package.json +15 -2
  53. package/dist/CoreAuthKitInner-KM72EYJS.js +0 -19
  54. package/dist/chunk-GDV44UWF.js +0 -138
  55. package/dist/chunk-HBRMWW6V.js +0 -43
  56. package/dist/chunk-NIAVTSMB.js +0 -21
  57. package/dist/chunk-QSVZP2NU.js +0 -214
  58. package/dist/chunk-ZQVPUAGR.js +0 -89
  59. /package/dist/{chunk-Q47SPRY7.js → chunk-RNP5R5I3.js} +0 -0
@@ -0,0 +1,43 @@
1
+ import { AuthProvider } from './chunk-7PLEQFHO.js';
2
+ import { AuthKitProvider, useAuth } from '@workos-inc/authkit-react';
3
+ import { useMemo } from 'react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ function CoreAuthKitInner({ auth, children }) {
7
+ return /* @__PURE__ */ jsx(
8
+ AuthKitProvider,
9
+ {
10
+ clientId: auth.clientId,
11
+ apiHostname: auth.apiHostname ?? "api.workos.com",
12
+ redirectUri: auth.redirectUri,
13
+ devMode: auth.devMode ?? false,
14
+ children: /* @__PURE__ */ jsx(WorkOSAuthAdapter, { children })
15
+ }
16
+ );
17
+ }
18
+ var WORKOS_REFRESH_TOKEN_KEY = "workos:refresh-token";
19
+ function hasWorkOSRefreshToken() {
20
+ try {
21
+ return !!localStorage.getItem(WORKOS_REFRESH_TOKEN_KEY);
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+ function WorkOSAuthAdapter({ children }) {
27
+ const { user, isLoading, getAccessToken, organizationId, signIn } = useAuth();
28
+ const adaptedUser = useMemo(() => user ? { id: user.id } : null, [user?.id]);
29
+ const value = useMemo(
30
+ () => ({
31
+ user: adaptedUser,
32
+ isLoading,
33
+ getAccessToken,
34
+ organizationId: organizationId ?? null,
35
+ signIn,
36
+ canRecover: hasWorkOSRefreshToken
37
+ }),
38
+ [adaptedUser, isLoading, getAccessToken, organizationId, signIn]
39
+ );
40
+ return /* @__PURE__ */ jsx(AuthProvider, { value, children });
41
+ }
42
+
43
+ export { CoreAuthKitInner };
@@ -5,8 +5,10 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  */
6
6
  interface ApiClientContextValue {
7
7
  getAccessToken: () => Promise<string | undefined>;
8
+ /** @deprecated Read via getOrganizationId() instead. Kept for downstream context consumers during migration. */
8
9
  organizationId: string | null;
9
10
  isOrganizationReady: boolean;
11
+ getOrganizationId: () => string | null;
10
12
  onError?: (endpoint: string, error: Error, details?: ApiErrorDetails) => void;
11
13
  }
12
14
  interface ApiErrorDetails {
@@ -17,7 +19,19 @@ interface ApiErrorDetails {
17
19
  interface ApiClientProviderProps {
18
20
  children: React.ReactNode;
19
21
  getAccessToken: () => Promise<string | undefined>;
20
- organizationId: string | null;
22
+ /**
23
+ * Static org ID. Used when org ID is stable at render time.
24
+ * Cannot reflect org switches without re-rendering the provider.
25
+ * Prefer getOrganizationId for dynamic org context.
26
+ * @deprecated Pass getOrganizationId instead for dynamic org resolution.
27
+ */
28
+ organizationId?: string | null;
29
+ /**
30
+ * Callback invoked on every request to read the current org ID.
31
+ * Takes precedence over organizationId when provided.
32
+ * Allows org switching without re-rendering the provider tree.
33
+ */
34
+ getOrganizationId?: () => string | null;
21
35
  isOrganizationReady: boolean;
22
36
  onError?: (endpoint: string, error: Error, details?: ApiErrorDetails) => void;
23
37
  }
@@ -52,36 +66,36 @@ declare function useApiClientContext(): ApiClientContextValue;
52
66
  * }
53
67
  * ```
54
68
  */
55
- declare function ApiClientProvider({ children, getAccessToken, organizationId, isOrganizationReady, onError }: ApiClientProviderProps): react_jsx_runtime.JSX.Element;
69
+ declare function ApiClientProvider({ children, getAccessToken, organizationId, getOrganizationId: getOrganizationIdProp, isOrganizationReady, onError }: ApiClientProviderProps): react_jsx_runtime.JSX.Element;
56
70
 
57
71
  /**
58
- * Return type of useOrganizations hook (subset needed by useApiClient)
59
- */
60
- interface UseOrganizationsReturn {
61
- isInitializing: boolean;
62
- isOrgRefreshing: boolean;
63
- }
64
- /**
65
- * Factory function to create a useApiClient hook for your app.
72
+ * Hook that returns apiRequest and deferredApiRequest bound to the current
73
+ * ApiClientContext. apiUrl is the only parameter because org ID is resolved
74
+ * at call time via getOrganizationId() from context.
66
75
  *
67
- * This pattern allows the shared package to provide the hook logic
68
- * while each app provides its own useOrganizations hook and API URL.
76
+ * When OrganizationProvider is present in the tree, isOrganizationReady and
77
+ * isInitializing reflect the live org state (currentWorkOSOrganizationId,
78
+ * isInitializing, isOrgRefreshing). When OrganizationProvider is absent
79
+ * (e.g. theme-only mode, testing), the hook falls back to the values from
80
+ * ApiClientContext.
69
81
  *
70
- * Usage in app:
82
+ * Usage:
71
83
  * ```typescript
72
- * import { createUseApiClient } from '@repo/ui/api'
73
- * import { useOrganizations } from './organization/hooks/useOrganizations'
84
+ * import { useApiClient } from '@repo/ui/api'
74
85
  *
75
86
  * const API_URL = import.meta.env.VITE_API_SERVER || 'http://localhost:5170'
76
- * export const useApiClient = createUseApiClient(useOrganizations, API_URL)
87
+ *
88
+ * function useMyClient() {
89
+ * return useApiClient(API_URL)
90
+ * }
77
91
  * ```
78
92
  */
79
- declare function createUseApiClient(useOrganizations: () => UseOrganizationsReturn, apiUrl: string): () => {
93
+ declare function useApiClient(apiUrl: string): {
80
94
  apiRequest: <T>(endpoint: string, options?: RequestInit) => Promise<T>;
81
95
  deferredApiRequest: <T>(endpoint: string, options?: RequestInit) => Promise<T>;
82
96
  isOrganizationReady: boolean;
83
97
  isInitializing: boolean;
84
98
  };
85
99
 
86
- export { ApiClientProvider, createUseApiClient, useApiClientContext };
100
+ export { ApiClientProvider, useApiClient, useApiClientContext };
87
101
  export type { ApiClientContextValue, ApiClientProviderProps, ApiErrorDetails };
package/dist/api/index.js CHANGED
@@ -1,3 +1,5 @@
1
1
  import '../chunk-XCYKC6OZ.js';
2
- export { ApiClientProvider, createUseApiClient, useApiClientContext } from '../chunk-GDV44UWF.js';
3
- import '../chunk-7AI5ZYJ4.js';
2
+ export { ApiClientProvider, useApiClient, useApiClientContext } from '../chunk-XLV6LYN2.js';
3
+ import '../chunk-JVAZHVNV.js';
4
+ import '../chunk-4VGWQ5AN.js';
5
+ import '../chunk-DD3CCMCZ.js';
@@ -1,19 +1,37 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
 
4
- interface AuthAdapter {
4
+ interface AuthContextValue {
5
5
  user: {
6
6
  id: string;
7
7
  } | null;
8
8
  isLoading: boolean;
9
9
  getAccessToken: () => Promise<string>;
10
10
  organizationId?: string | null;
11
+ /**
12
+ * Trigger WorkOS AuthKit's sign-in flow (redirect to WorkOS hosted auth page).
13
+ * Used by ProtectedRoute for auto-recovery when `canRecover()` returns true.
14
+ */
15
+ signIn: (options?: {
16
+ state?: {
17
+ returnTo?: string;
18
+ };
19
+ }) => void;
20
+ /**
21
+ * Returns true when a previous session can be recovered (refresh token
22
+ * exists in storage). ProtectedRoute calls `signIn()` only when this returns
23
+ * true; otherwise it navigates to the login page.
24
+ *
25
+ * Explicit logout clears the stored token, so canRecover() returns false
26
+ * and the user sees the login page as expected.
27
+ */
28
+ canRecover: () => boolean;
11
29
  }
12
- declare function useAuthContext(): AuthAdapter;
30
+ declare function useAuthContext(): AuthContextValue;
13
31
  declare function AuthProvider({ value, children }: {
14
- value: AuthAdapter;
32
+ value: AuthContextValue;
15
33
  children: ReactNode;
16
- }): react.FunctionComponentElement<react.ProviderProps<AuthAdapter | null>>;
34
+ }): react.FunctionComponentElement<react.ProviderProps<AuthContextValue | null>>;
17
35
 
18
36
  export { AuthProvider, useAuthContext };
19
- export type { AuthAdapter };
37
+ export type { AuthContextValue };
@@ -2,43 +2,37 @@ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
 
5
- interface AuthAdapter {
5
+ interface AuthContextValue {
6
6
  user: {
7
7
  id: string;
8
8
  } | null;
9
9
  isLoading: boolean;
10
10
  getAccessToken: () => Promise<string>;
11
11
  organizationId?: string | null;
12
+ /**
13
+ * Trigger WorkOS AuthKit's sign-in flow (redirect to WorkOS hosted auth page).
14
+ * Used by ProtectedRoute for auto-recovery when `canRecover()` returns true.
15
+ */
16
+ signIn: (options?: {
17
+ state?: {
18
+ returnTo?: string;
19
+ };
20
+ }) => void;
21
+ /**
22
+ * Returns true when a previous session can be recovered (refresh token
23
+ * exists in storage). ProtectedRoute calls `signIn()` only when this returns
24
+ * true; otherwise it navigates to the login page.
25
+ *
26
+ * Explicit logout clears the stored token, so canRecover() returns false
27
+ * and the user sees the login page as expected.
28
+ */
29
+ canRecover: () => boolean;
12
30
  }
13
- declare function useAuthContext(): AuthAdapter;
31
+ declare function useAuthContext(): AuthContextValue;
14
32
  declare function AuthProvider({ value, children }: {
15
- value: AuthAdapter;
33
+ value: AuthContextValue;
16
34
  children: ReactNode;
17
- }): react.FunctionComponentElement<react.ProviderProps<AuthAdapter | null>>;
18
-
19
- /**
20
- * Bridge component that reads WorkOS AuthKit state and provides it
21
- * via the generic AuthContext. Place inside AuthKitProvider.
22
- *
23
- * Narrows WorkOS User to { id: string } -- @repo/ui hooks only need the ID.
24
- * Uses useMemo to stabilize the user object and prevent unnecessary
25
- * useEffect re-runs in downstream hooks.
26
- */
27
- declare function WorkOSAuthBridge({ children }: {
28
- children: ReactNode;
29
- }): react_jsx_runtime.JSX.Element;
30
-
31
- interface OAuthContextValue {
32
- user: {
33
- id: string;
34
- } | null;
35
- isLoading: boolean;
36
- organizationId: string | null;
37
- getAccessToken: () => Promise<string>;
38
- error: string | null;
39
- initiateOAuthFlow: () => void;
40
- }
41
- declare function useOAuthContext(): OAuthContextValue;
35
+ }): react.FunctionComponentElement<react.ProviderProps<AuthContextValue | null>>;
42
36
 
43
37
  /**
44
38
  * Returns a stable reference to getAccessToken that won't change between renders
@@ -83,5 +77,100 @@ declare function useStableAccessToken(): () => Promise<string>;
83
77
  */
84
78
  declare function useSessionCheck(): void;
85
79
 
86
- export { AuthProvider, WorkOSAuthBridge, useAuthContext, useOAuthContext, useSessionCheck as useRefocusSessionCheck, useSessionCheck, useStableAccessToken };
87
- export type { AuthAdapter, OAuthContextValue };
80
+ interface InitializationError {
81
+ layer: 'auth' | 'profile' | 'organization';
82
+ message: string;
83
+ originalError?: Error;
84
+ }
85
+
86
+ interface ProtectedRouteProps {
87
+ children: ReactNode;
88
+ /**
89
+ * Path to redirect to when user is unauthenticated and the auth adapter
90
+ * does not provide a `signIn` function.
91
+ * @default '/login'
92
+ */
93
+ redirectTo?: string;
94
+ /**
95
+ * Rendered while initialization is in progress.
96
+ * When not provided, nothing is rendered during initialization.
97
+ */
98
+ fallback?: ReactNode;
99
+ /**
100
+ * Rendered when initialization fails with a non-organization error.
101
+ * Receives the error and a retry callback.
102
+ * When not provided, the error is silently swallowed (children not rendered).
103
+ */
104
+ errorFallback?: (error: InitializationError, retry: () => void) => ReactNode;
105
+ /**
106
+ * When true (default), waits for both user AND organization to be ready
107
+ * before rendering children. When false, only waits for user readiness.
108
+ * @default true
109
+ */
110
+ waitForOrganization?: boolean;
111
+ }
112
+ /**
113
+ * Headless route guard for authenticated pages.
114
+ *
115
+ * Reads initialization state from the nearest InitializationProvider.
116
+ *
117
+ * When `canRecover()` returns true (refresh token exists), unauthenticated users
118
+ * are sent directly to WorkOS AuthKit via `signIn()`. WorkOS checks its
119
+ * server-side session and either signs the user in immediately (page-reload case)
120
+ * or shows a login form (logged-out case). Explicit logout destroys the
121
+ * server-side session, so the next auto-signIn correctly presents a login form
122
+ * rather than looping.
123
+ *
124
+ * When `canRecover()` returns false, falls back to navigating to `redirectTo`
125
+ * (default: '/login') with a `returnTo` search param.
126
+ *
127
+ * Organization-layer errors are allowed through -- routes like /invitations
128
+ * must be accessible even when the user has no org membership.
129
+ *
130
+ * @example
131
+ * // With custom fallback (your Mantine loader):
132
+ * <ProtectedRoute fallback={<AppShellLoader />}>
133
+ * <DashboardPage />
134
+ * </ProtectedRoute>
135
+ *
136
+ * @example
137
+ * // Wait only for user, not org (e.g. /invitations route):
138
+ * <ProtectedRoute waitForOrganization={false}>
139
+ * <InvitationsPage />
140
+ * </ProtectedRoute>
141
+ */
142
+ declare function ProtectedRoute({ children, redirectTo, fallback, errorFallback, waitForOrganization }: ProtectedRouteProps): react_jsx_runtime.JSX.Element | null;
143
+
144
+ interface AdminGuardProps {
145
+ children: ReactNode;
146
+ /**
147
+ * Path to redirect non-admin users to.
148
+ * @default '/'
149
+ */
150
+ redirectTo?: string;
151
+ /**
152
+ * Rendered while user readiness is being determined.
153
+ * When not provided, nothing is rendered during initialization.
154
+ */
155
+ fallback?: ReactNode;
156
+ }
157
+ /**
158
+ * Headless route guard for platform admin pages.
159
+ *
160
+ * Reads `profile.is_platform_admin` from the nearest InitializationProvider.
161
+ * Non-admin users are redirected to `redirectTo` (default: '/').
162
+ *
163
+ * Must be nested inside a ProtectedRoute (or equivalent) so that
164
+ * `userReady` is guaranteed to be true when this guard runs.
165
+ *
166
+ * @example
167
+ * <ProtectedRoute>
168
+ * <AdminGuard fallback={<AppShellLoader />}>
169
+ * <AdminDashboard />
170
+ * </AdminGuard>
171
+ * </ProtectedRoute>
172
+ */
173
+ declare function AdminGuard({ children, redirectTo, fallback }: AdminGuardProps): react_jsx_runtime.JSX.Element | null;
174
+
175
+ export { AdminGuard, AuthProvider, ProtectedRoute, useAuthContext, useSessionCheck as useRefocusSessionCheck, useSessionCheck, useStableAccessToken };
176
+ export type { AdminGuardProps, AuthContextValue, ProtectedRouteProps };
@@ -1,4 +1,7 @@
1
- export { useSessionCheck as useRefocusSessionCheck, useSessionCheck, useStableAccessToken } from '../chunk-HBRMWW6V.js';
2
- export { WorkOSAuthBridge } from '../chunk-NIAVTSMB.js';
3
- export { useOAuthContext } from '../chunk-QSVZP2NU.js';
1
+ export { AdminGuard, ProtectedRoute, useSessionCheck as useRefocusSessionCheck, useSessionCheck } from '../chunk-2JBWPFHF.js';
2
+ export { useStableAccessToken } from '../chunk-FWZJH3TL.js';
3
+ import '../chunk-NEK6JKPW.js';
4
+ import '../chunk-L2CM2CUA.js';
5
+ import '../chunk-DD3CCMCZ.js';
6
+ import '../chunk-KA7LO7U5.js';
4
7
  export { AuthProvider, useAuthContext } from '../chunk-7PLEQFHO.js';
@@ -0,0 +1,108 @@
1
+ import { useInitialization } from './chunk-NEK6JKPW.js';
2
+ import { useAuthContext } from './chunk-7PLEQFHO.js';
3
+ import { useRef, useEffect } from 'react';
4
+ import { useQueryClient } from '@tanstack/react-query';
5
+ import { useNavigate, useLocation } from '@tanstack/react-router';
6
+ import { jsx, Fragment } from 'react/jsx-runtime';
7
+
8
+ function useSessionCheck() {
9
+ const { user } = useAuthContext();
10
+ const queryClient = useQueryClient();
11
+ const isCheckingRef = useRef(false);
12
+ const hadUserRef = useRef(false);
13
+ if (user) {
14
+ hadUserRef.current = true;
15
+ }
16
+ useEffect(() => {
17
+ const handleVisibilityChange = async () => {
18
+ if (isCheckingRef.current || document.visibilityState !== "visible") {
19
+ return;
20
+ }
21
+ isCheckingRef.current = true;
22
+ try {
23
+ if (!user && hadUserRef.current) {
24
+ window.location.replace("/login");
25
+ return;
26
+ }
27
+ if (user) {
28
+ await queryClient.cancelQueries();
29
+ queryClient.invalidateQueries();
30
+ }
31
+ } finally {
32
+ isCheckingRef.current = false;
33
+ }
34
+ };
35
+ document.addEventListener("visibilitychange", handleVisibilityChange);
36
+ window.addEventListener("focus", handleVisibilityChange);
37
+ return () => {
38
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
39
+ window.removeEventListener("focus", handleVisibilityChange);
40
+ };
41
+ }, [user, queryClient]);
42
+ }
43
+ function ProtectedRoute({
44
+ children,
45
+ redirectTo = "/login",
46
+ fallback = null,
47
+ errorFallback,
48
+ waitForOrganization = true
49
+ }) {
50
+ const { userReady, allReady, isInitializing, error, retry } = useInitialization();
51
+ const { signIn, canRecover } = useAuthContext();
52
+ const navigate = useNavigate();
53
+ const location = useLocation();
54
+ const hasRedirected = useRef(false);
55
+ const unauthenticated = !isInitializing && !userReady && error?.layer !== "profile";
56
+ useEffect(() => {
57
+ if (unauthenticated && !hasRedirected.current) {
58
+ hasRedirected.current = true;
59
+ const searchStr = location.searchStr ?? "";
60
+ const returnTo = location.pathname + searchStr;
61
+ if (canRecover()) {
62
+ signIn({ state: { returnTo: returnTo !== "/" ? returnTo : void 0 } });
63
+ } else {
64
+ navigate({
65
+ to: redirectTo,
66
+ search: returnTo !== "/" ? { returnTo } : {}
67
+ });
68
+ }
69
+ }
70
+ }, [unauthenticated, signIn, canRecover, navigate, redirectTo, location]);
71
+ if (isInitializing) {
72
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
73
+ }
74
+ if (error && error.layer !== "organization") {
75
+ if (errorFallback) {
76
+ return /* @__PURE__ */ jsx(Fragment, { children: errorFallback(error, retry) });
77
+ }
78
+ return null;
79
+ }
80
+ if (unauthenticated) {
81
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
82
+ }
83
+ if (waitForOrganization && !allReady && error?.layer !== "organization") {
84
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
85
+ }
86
+ return /* @__PURE__ */ jsx(Fragment, { children });
87
+ }
88
+ function AdminGuard({ children, redirectTo = "/", fallback = null }) {
89
+ const { userReady, profile } = useInitialization();
90
+ const navigate = useNavigate();
91
+ useEffect(() => {
92
+ if (!userReady || !profile) {
93
+ return;
94
+ }
95
+ if (!profile.is_platform_admin) {
96
+ navigate({ to: redirectTo });
97
+ }
98
+ }, [userReady, profile, navigate, redirectTo]);
99
+ if (!userReady) {
100
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
101
+ }
102
+ if (!profile?.is_platform_admin) {
103
+ return null;
104
+ }
105
+ return /* @__PURE__ */ jsx(Fragment, { children });
106
+ }
107
+
108
+ export { AdminGuard, ProtectedRoute, useSessionCheck };
@@ -0,0 +1,91 @@
1
+ // src/utils/error-utils.ts
2
+ var APIClientError = class extends Error {
3
+ statusCode;
4
+ code;
5
+ requestId;
6
+ fields;
7
+ retryAfter;
8
+ constructor(message, code, statusCode, requestId, fields, retryAfter) {
9
+ super(message);
10
+ this.name = "APIClientError";
11
+ this.code = code;
12
+ this.statusCode = statusCode;
13
+ this.requestId = requestId;
14
+ this.fields = fields;
15
+ this.retryAfter = retryAfter;
16
+ }
17
+ };
18
+ function isAPIClientError(error) {
19
+ return error instanceof APIClientError;
20
+ }
21
+ function getErrorInfo(error) {
22
+ if (isAPIClientError(error)) {
23
+ return {
24
+ message: error.message,
25
+ code: error.code,
26
+ requestId: error.requestId,
27
+ statusCode: error.statusCode,
28
+ fields: error.fields,
29
+ retryAfter: error.retryAfter
30
+ };
31
+ }
32
+ if (error instanceof Error) {
33
+ return {
34
+ message: error.message
35
+ };
36
+ }
37
+ return {
38
+ message: String(error)
39
+ };
40
+ }
41
+ function getErrorTitle(code) {
42
+ if (!code) return "Error";
43
+ switch (code) {
44
+ case "VALIDATION_ERROR":
45
+ return "Validation Error";
46
+ case "AUTHENTICATION_FAILED":
47
+ return "Authentication Required";
48
+ case "FORBIDDEN":
49
+ return "Access Denied";
50
+ case "NOT_FOUND":
51
+ return "Not Found";
52
+ case "CONFLICT":
53
+ return "Conflict";
54
+ case "RATE_LIMIT_EXCEEDED":
55
+ return "Rate Limit Exceeded";
56
+ case "INTERNAL_SERVER_ERROR":
57
+ return "Server Error";
58
+ case "SERVICE_UNAVAILABLE":
59
+ return "Service Temporarily Unavailable";
60
+ default:
61
+ return "Error";
62
+ }
63
+ }
64
+ function formatErrorMessage(message, requestId, fields, retryAfter) {
65
+ let formatted = message;
66
+ if (fields && Object.keys(fields).length > 0) {
67
+ const fieldErrors = [];
68
+ for (const [field, errors] of Object.entries(fields)) {
69
+ const fieldName = field === "root" || field === "_root" ? "Request" : field;
70
+ errors.forEach((error) => {
71
+ fieldErrors.push(`\u2022 ${fieldName}: ${error}`);
72
+ });
73
+ }
74
+ if (fieldErrors.length > 0) {
75
+ formatted = fieldErrors.join("\n");
76
+ }
77
+ }
78
+ if (retryAfter) {
79
+ formatted += `
80
+
81
+ Please wait ${retryAfter} seconds before retrying.`;
82
+ }
83
+ if (requestId) {
84
+ formatted += `
85
+
86
+ Request ID: ${requestId}`;
87
+ }
88
+ return formatted;
89
+ }
90
+
91
+ export { APIClientError, formatErrorMessage, getErrorInfo, getErrorTitle, isAPIClientError };
@@ -0,0 +1,87 @@
1
+ import { OrganizationProvider } from './chunk-UMXDDEAG.js';
2
+ import { ApiClientProvider, useApiClient } from './chunk-XLV6LYN2.js';
3
+ import { NotificationProvider } from './chunk-TIRMFDM4.js';
4
+ import { InitializationProvider } from './chunk-NEK6JKPW.js';
5
+ import { ProfileProvider } from './chunk-L2CM2CUA.js';
6
+ import { useOrganization } from './chunk-DD3CCMCZ.js';
7
+ import { ElevasisServiceProvider, useElevasisServices } from './chunk-KA7LO7U5.js';
8
+ import { useAuthContext } from './chunk-7PLEQFHO.js';
9
+ import { lazy, Suspense, useRef } from 'react';
10
+ import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
11
+ import { jsx, Fragment } from 'react/jsx-runtime';
12
+
13
+ var LazyCoreAuthKitInner = lazy(() => import('./CoreAuthKitInner-3J4RVQO6.js').then((m) => ({ default: m.CoreAuthKitInner })));
14
+ var defaultQueryClient = null;
15
+ function getDefaultQueryClient() {
16
+ if (!defaultQueryClient) {
17
+ defaultQueryClient = new QueryClient({
18
+ defaultOptions: { queries: { retry: 1 } }
19
+ });
20
+ }
21
+ return defaultQueryClient;
22
+ }
23
+ function ElevasisCoreProvider({
24
+ auth,
25
+ queryClient,
26
+ apiUrl,
27
+ onError,
28
+ notifications,
29
+ children
30
+ }) {
31
+ if (auth.mode === "apiKey") {
32
+ throw new Error(
33
+ `ElevasisCoreProvider: auth mode 'apiKey' is not yet implemented. Only 'authkit' mode is supported.`
34
+ );
35
+ }
36
+ const resolvedQueryClient = queryClient ?? getDefaultQueryClient();
37
+ const content = apiUrl ? /* @__PURE__ */ jsx(CoreServiceBridge, { apiUrl, onError, notifications, children }) : children;
38
+ const AuthInner = /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(LazyCoreAuthKitInner, { auth, children: content }) });
39
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: resolvedQueryClient, children: AuthInner });
40
+ }
41
+ function CoreServiceBridge({
42
+ apiUrl,
43
+ onError,
44
+ notifications,
45
+ children
46
+ }) {
47
+ const { getAccessToken } = useAuthContext();
48
+ const orgIdRef = useRef(null);
49
+ const getOrganizationId = useRef(() => orgIdRef.current).current;
50
+ return /* @__PURE__ */ jsx(
51
+ ApiClientProvider,
52
+ {
53
+ getAccessToken,
54
+ getOrganizationId,
55
+ isOrganizationReady: false,
56
+ onError,
57
+ children: /* @__PURE__ */ jsx(CoreServiceBridgeInner, { apiUrl, orgIdRef, notifications, children })
58
+ }
59
+ );
60
+ }
61
+ function CoreServiceBridgeInner({
62
+ apiUrl,
63
+ orgIdRef,
64
+ notifications,
65
+ children
66
+ }) {
67
+ const { apiRequest } = useApiClient(apiUrl);
68
+ return /* @__PURE__ */ jsx(ElevasisServiceProvider, { apiRequest, organizationId: null, isReady: false, children: /* @__PURE__ */ jsx(ProfileProvider, { children: /* @__PURE__ */ jsx(OrganizationProvider, { children: /* @__PURE__ */ jsx(OrgIdBridge, { orgIdRef, children: /* @__PURE__ */ jsx(CoreNotificationLayer, { notifications, children: /* @__PURE__ */ jsx(InitializationProvider, { children }) }) }) }) }) });
69
+ }
70
+ function OrgIdBridge({ orgIdRef, children }) {
71
+ const { currentWorkOSOrganizationId, isInitializing, isOrgRefreshing } = useOrganization();
72
+ const { apiRequest } = useElevasisServices();
73
+ orgIdRef.current = currentWorkOSOrganizationId;
74
+ const isReady = !!currentWorkOSOrganizationId && !isInitializing && !isOrgRefreshing;
75
+ return /* @__PURE__ */ jsx(ElevasisServiceProvider, { apiRequest, organizationId: currentWorkOSOrganizationId, isReady, children });
76
+ }
77
+ function CoreNotificationLayer({
78
+ notifications,
79
+ children
80
+ }) {
81
+ if (notifications) {
82
+ return /* @__PURE__ */ jsx(NotificationProvider, { adapter: notifications, children });
83
+ }
84
+ return /* @__PURE__ */ jsx(Fragment, { children });
85
+ }
86
+
87
+ export { ElevasisCoreProvider };