@tailor-platform/app-shell 0.24.0 → 0.26.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/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { AuthState } from '@tailor-platform/auth-browser-client';
1
+ import { AuthClient } from '@tailor-platform/auth-public-client';
2
2
  import { ClassProp } from 'class-variance-authority/types';
3
- import { DocumentNode } from 'graphql';
4
3
  import { JSX } from 'react/jsx-runtime';
5
4
  import { Link } from 'react-router';
6
5
  import { LoaderFunctionArgs } from 'react-router';
7
6
  import { Params } from 'react-router';
8
7
  import * as React_2 from 'react';
9
8
  import { ReactNode } from 'react';
9
+ import { toast } from 'sonner';
10
10
  import { useLocation } from 'react-router';
11
11
  import { useNavigate } from 'react-router';
12
12
  import { useParams } from 'react-router';
@@ -146,37 +146,19 @@ export declare type AppShellProps = React.PropsWithChildren<{
146
146
  export declare interface AppShellRegister {
147
147
  }
148
148
 
149
- declare type AuthContextType = {
150
- /**
151
- * Current authentication state.
152
- */
153
- authState: AuthState<User>;
154
- /**
155
- * Initiates the login process.
156
- *
157
- * This redirects the user to the Tailor Platform authentication page.
158
- */
159
- login: () => Promise<void>;
160
- /**
161
- * Logs out the current user.
162
- *
163
- * This clears the authentication tokens and user session.
164
- */
165
- logout: () => Promise<void>;
166
- /**
167
- * Checks the current authentication status.
168
- *
169
- * Remember that this method always makes a network request to verify the auth status.
170
- * If the user is authenticated, returns the user information and updates `authState` in the context.
171
- *
172
- * This also attempts to refresh tokens internally if they are expired.
173
- */
174
- checkAuthStatus: () => Promise<AuthState<User>>;
175
- /**
176
- * OAuth callback handler.
177
- */
178
- handleCallback: () => Promise<void>;
179
- };
149
+ export { AuthClient }
150
+
151
+ /**
152
+ * Configuration for creating an enhanced auth client
153
+ */
154
+ export declare interface AuthClientConfig {
155
+ /** OAuth client ID */
156
+ clientId: string;
157
+ /** Authorization server base URL (e.g., https://your-app.erp.dev) */
158
+ appUri: string;
159
+ /** Redirect URI after authorization (default: window.location.origin) */
160
+ redirectUri?: string;
161
+ }
180
162
 
181
163
  /**
182
164
  * Authentication provider component.
@@ -185,14 +167,17 @@ declare type AuthContextType = {
185
167
  *
186
168
  * @example
187
169
  * ```tsx
188
- * import { AuthProvider } from "@tailor-platform/app-shell";
170
+ * import { createAuthClient, AuthProvider } from "@tailor-platform/app-shell";
171
+ *
172
+ * // Create the auth client outside of the component
173
+ * const authClient = createAuthClient({
174
+ * clientId: "your-client-id",
175
+ * appUri: "https://xyz.erp.dev",
176
+ * });
189
177
  *
190
178
  * function App() {
191
179
  * return (
192
- * <AuthProvider
193
- * apiEndpoint="https://xyz.erp.dev"
194
- * clientId="your-client-id"
195
- * >
180
+ * <AuthProvider client={authClient}>
196
181
  * <YourAppComponents />
197
182
  * </AuthProvider>
198
183
  * );
@@ -203,39 +188,10 @@ export declare const AuthProvider: (props: React.PropsWithChildren<AuthProviderP
203
188
 
204
189
  declare type AuthProviderProps = {
205
190
  /**
206
- * API endpoint of your Tailor Platform application. No `/query` suffix needed.
207
- *
208
- * @example https://xyz.erp.dev
191
+ * The EnhancedAuthClient instance created with createAuthClient from @tailor-platform/app-shell.
192
+ * This allows you to initialize the client outside the component.
209
193
  */
210
- apiEndpoint: string;
211
- /**
212
- * OAuth2 Client ID of your Tailor Platform application.
213
- */
214
- clientId: string;
215
- /**
216
- * GraphQL query to fetch the current authenticated user.
217
- *
218
- * The result of this query should return the user object.
219
- * If you override `AuthRegister["user"]`, make sure to have the fields match your custom user type.
220
- *
221
- * @defaults
222
- * ```graphql
223
- * query {
224
- * me {
225
- * id
226
- * email
227
- * name
228
- * }
229
- * }
230
- * ```
231
- */
232
- meQuery?: string | DocumentNode;
233
- /**
234
- * Redirect URI after login is successful.
235
- *
236
- * @defaults `window.location.origin`
237
- */
238
- redirectUri?: string;
194
+ client: EnhancedAuthClient;
239
195
  /**
240
196
  * Enable automatic login on initialization.
241
197
  */
@@ -249,24 +205,24 @@ declare type AuthProviderProps = {
249
205
  };
250
206
 
251
207
  /**
252
- * Registerable interface for type extension via module augmentation.
208
+ * Authentication state.
253
209
  *
254
- * @example
255
- * // In your project's TypeScript file (e.g., app-shell.d.ts, App.tsx, etc.)
256
- * declare module "@tailor-platform/app-shell" {
257
- * interface AuthRegister {
258
- * user: {
259
- * id: string;
260
- * email: string;
261
- * name?: string;
262
- * role: "admin" | "user";
263
- * organizationId: string;
264
- * }
265
- * }
266
- * }
210
+ * This type matches the AuthState from @tailor-platform/auth-public-client.
267
211
  */
268
- export declare interface AuthRegister {
269
- }
212
+ export declare type AuthState = {
213
+ /**
214
+ * Whether the user is authenticated.
215
+ */
216
+ isAuthenticated: boolean;
217
+ /**
218
+ * Error message if authentication failed.
219
+ */
220
+ error: string | null;
221
+ /**
222
+ * Whether the initial authentication check has completed.
223
+ */
224
+ isReady: boolean;
225
+ };
270
226
 
271
227
  export declare function Badge({ className, variant, children, ...props }: BadgeProps): JSX.Element;
272
228
 
@@ -363,6 +319,8 @@ export declare type ContextData = AppShellRegister extends {
363
319
  contextData: infer T;
364
320
  } ? T : Record<string, unknown>;
365
321
 
322
+ export declare function createAuthClient(config: AuthClientConfig): EnhancedAuthClient;
323
+
366
324
  /**
367
325
  * Date format options
368
326
  */
@@ -375,26 +333,6 @@ declare type DefaultSidebarProps = {
375
333
  footer?: React.ReactNode;
376
334
  };
377
335
 
378
- /**
379
- * Default user type when no custom user type is registered.
380
- *
381
- * You can extend this type via module augmentation:
382
- * @example
383
- * declare module "@tailor-platform/app-shell" {
384
- * interface Register {
385
- * user: DefaultUser & {
386
- * role: "admin" | "user";
387
- * organizationId: string;
388
- * }
389
- * }
390
- * }
391
- */
392
- export declare type DefaultUser = {
393
- id: string;
394
- email: string;
395
- name?: string;
396
- };
397
-
398
336
  /**
399
337
  * Defines internationalization labels for multiple locales.
400
338
  *
@@ -627,6 +565,27 @@ declare type DynamicLocales<Def extends Record<string, LabelValue>> = {
627
565
  */
628
566
  declare type EmptyBehavior = "dash" | "hide";
629
567
 
568
+ /**
569
+ * Enhanced auth client with additional helper methods
570
+ */
571
+ export declare interface EnhancedAuthClient extends AuthClient {
572
+ /**
573
+ * Get the appUri used to create this client
574
+ */
575
+ getAppUri(): string;
576
+ /**
577
+ * Get Authorization and DPoP headers for protected resource requests.
578
+ * This version automatically uses the appUri for the /query endpoint.
579
+ *
580
+ * @param path - Optional path to append to appUri (default: "/query")
581
+ * @param method - HTTP method (default: "POST")
582
+ */
583
+ getAuthHeadersForQuery(path?: string, method?: string): Promise<{
584
+ Authorization: string;
585
+ DPoP: string;
586
+ }>;
587
+ }
588
+
630
589
  /**
631
590
  * Error boundary element type for route error handling.
632
591
  *
@@ -975,7 +934,92 @@ export declare const useAppShellConfig: () => AppShellConfigContextType;
975
934
  */
976
935
  export declare const useAppShellData: () => AppShellDataContextType;
977
936
 
978
- export declare const useAuth: () => AuthContextType;
937
+ /**
938
+ * Authentication hook.
939
+ *
940
+ * Returns authentication state and methods. Use `isReady` to check if
941
+ * the initial authentication check has completed before rendering
942
+ * authenticated content.
943
+ *
944
+ * @example
945
+ * ```tsx
946
+ * function MyComponent() {
947
+ * const { isAuthenticated, isReady, login, logout } = useAuth();
948
+ *
949
+ * if (!isReady) return <Loading />;
950
+ * if (!isAuthenticated) return <button onClick={login}>Log In</button>;
951
+ *
952
+ * return <button onClick={logout}>Log Out</button>;
953
+ * }
954
+ * ```
955
+ */
956
+ export declare const useAuth: () => {
957
+ error: string | null;
958
+ isAuthenticated: boolean;
959
+ isReady: boolean;
960
+ login: () => Promise<void>;
961
+ logout: () => Promise<void>;
962
+ checkAuthStatus: () => Promise<AuthState>;
963
+ };
964
+
965
+ /**
966
+ * Suspense-compatible authentication hook.
967
+ *
968
+ * This hook integrates with React Suspense by throwing a promise while
969
+ * the authentication state is loading. Use this hook when you want to
970
+ * leverage Suspense boundaries for loading states.
971
+ *
972
+ * This uses the `ready()` function from the underlying auth client, which
973
+ * returns a Promise that resolves when the initial authentication check has completed.
974
+ *
975
+ * @throws {Promise} Throws a promise while authentication is loading
976
+ * @throws {Error} Throws an error if used outside AuthProvider
977
+ *
978
+ * @example
979
+ * ```tsx
980
+ * import { Suspense } from 'react';
981
+ * import { createAuthClient, AuthProvider, useAuthSuspense } from '@tailor-platform/app-shell';
982
+ *
983
+ * const authClient = createAuthClient({
984
+ * clientId: 'your-client-id',
985
+ * appUri: 'https://api.example.com',
986
+ * });
987
+ *
988
+ * function App() {
989
+ * return (
990
+ * <AuthProvider client={authClient}>
991
+ * <Suspense fallback={<div>Loading authentication...</div>}>
992
+ * <ProtectedContent />
993
+ * </Suspense>
994
+ * </AuthProvider>
995
+ * );
996
+ * }
997
+ *
998
+ * function ProtectedContent() {
999
+ * const { isAuthenticated, login, logout } = useAuthSuspense();
1000
+ *
1001
+ * // isReady is guaranteed to be true here (Suspense handles loading)
1002
+ *
1003
+ * if (!isAuthenticated) {
1004
+ * return <button onClick={login}>Log In</button>;
1005
+ * }
1006
+ *
1007
+ * return (
1008
+ * <div>
1009
+ * <p>Welcome!</p>
1010
+ * <button onClick={logout}>Log Out</button>
1011
+ * </div>
1012
+ * );
1013
+ * }
1014
+ * ```
1015
+ */
1016
+ export declare const useAuthSuspense: () => {
1017
+ error: string | null;
1018
+ isAuthenticated: boolean;
1019
+ login: () => Promise<void>;
1020
+ logout: () => Promise<void>;
1021
+ checkAuthStatus: () => Promise<AuthState>;
1022
+ };
979
1023
 
980
1024
  export { useLocation }
981
1025
 
@@ -983,20 +1027,12 @@ export { useNavigate }
983
1027
 
984
1028
  export { useParams }
985
1029
 
986
- /**
987
- * User type that can be extended via the AuthRegister interface.
988
- *
989
- * If `AuthRegister["user"]` is defined, it will be used as the User type.
990
- * Otherwise, the DefaultUser type will be used.
991
- */
992
- declare type User = AuthRegister extends {
993
- user: infer TUser;
994
- } ? TUser : DefaultUser;
995
-
996
1030
  export { useRouteError }
997
1031
 
998
1032
  export { useSearchParams }
999
1033
 
1000
1034
  export declare const useTheme: () => ThemeProviderState;
1001
1035
 
1036
+ export declare const useToast: () => typeof toast;
1037
+
1002
1038
  export { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/app-shell",
3
- "version": "0.24.0",
3
+ "version": "0.26.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./styles": "./dist/app-shell.css",
@@ -28,7 +28,7 @@
28
28
  "@radix-ui/react-separator": "^1.1.8",
29
29
  "@radix-ui/react-slot": "^1.2.4",
30
30
  "@radix-ui/react-tooltip": "^1.2.8",
31
- "@tailor-platform/auth-browser-client": "^0.3.0",
31
+ "@tailor-platform/auth-public-client": "^0.4.0",
32
32
  "@tanstack/react-table": "^8.21.2",
33
33
  "change-case": "^5.4.4",
34
34
  "class-variance-authority": "^0.7.1",
@@ -47,7 +47,7 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@tailwindcss/postcss": "^4.1.2",
50
- "@testing-library/react": "^16.3.0",
50
+ "@testing-library/react": "^16.3.2",
51
51
  "@testing-library/user-event": "^14.6.1",
52
52
  "@types/node": "^22",
53
53
  "@types/react": "^19",