@insforge/react 0.5.4 → 0.5.6

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/README.md CHANGED
@@ -5,7 +5,8 @@
5
5
  ## Why @insforge/react?
6
6
 
7
7
  ✅ **Framework Agnostic** - Works with any React setup (Vite, CRA, or no bundler)
8
- ✅ **Zero Router Dependencies** - Use with any routing solution or none at all
8
+ ✅ **Zero Router Dependencies** - Built-in navigation abstraction works with any routing solution
9
+ ✅ **Route Protection** - Built-in `RouteGuard` for vanilla React apps
9
10
  ✅ **Production Ready** - Complete auth flows with business logic included
10
11
  ✅ **Full TypeScript** - Complete type safety out of the box
11
12
 
@@ -38,21 +39,30 @@ npm install react@^19.0.0 react-dom@^19.0.0
38
39
  VITE_INSFORGE_BASE_URL=https://your-project.insforge.app/
39
40
  ```
40
41
 
41
- ### 2. Setup Provider
42
+ ### 2. Setup Provider & Route Guard
42
43
 
43
- Wrap your app with `InsforgeProvider`:
44
+ Wrap your app with `InsforgeProvider` and `RouteGuard`:
44
45
 
45
46
  ```tsx
46
47
  // src/main.tsx (Vite) or src/index.tsx (CRA)
47
48
  import { StrictMode } from 'react';
48
49
  import { createRoot } from 'react-dom/client';
49
- import { InsforgeProvider } from '@insforge/react';
50
+ import { InsforgeProvider, RouteGuard } from '@insforge/react';
50
51
  import App from './App';
51
52
 
52
53
  createRoot(document.getElementById('root')!).render(
53
54
  <StrictMode>
54
- <InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL} afterSignInUrl="/dashboard">
55
- <App />
55
+ <InsforgeProvider
56
+ baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}
57
+ afterSignInUrl="/dashboard"
58
+ >
59
+ <RouteGuard
60
+ builtInAuth
61
+ publicRoutes={['/', '/about']}
62
+ loadingFallback={<div>Loading...</div>}
63
+ >
64
+ <App />
65
+ </RouteGuard>
56
66
  </InsforgeProvider>
57
67
  </StrictMode>
58
68
  );
@@ -90,7 +100,7 @@ export default function App() {
90
100
  }
91
101
  ```
92
102
 
93
- **That's it!** 🎉 You now have production-ready authentication.
103
+ **That's it!** 🎉 Your app is now protected with authentication.
94
104
 
95
105
  ---
96
106
 
@@ -186,7 +196,8 @@ function CustomAuthForm() {
186
196
  - `<ResetPassword />` - Reset password with token validation
187
197
  - `<VerifyEmail />` - Verify email with automatic token handling
188
198
  - `<UserButton />` - User dropdown with sign-out
189
- - `<Protect />` - Route protection wrapper
199
+ - `<RouteGuard />` - **NEW:** App-level route protection for vanilla React
200
+ - `<Protect />` - Component-level protection wrapper
190
201
  - `<SignedIn>` / `<SignedOut>` - Conditional rendering
191
202
 
192
203
  **Form Components (Pure UI):**
@@ -204,8 +215,24 @@ function CustomAuthForm() {
204
215
  ### Hooks
205
216
 
206
217
  ```tsx
207
- const { signIn, signUp, signOut, isSignedIn, isLoaded } = useAuth();
218
+ // Authentication state and methods
219
+ const {
220
+ signIn,
221
+ signUp,
222
+ signOut,
223
+ isSignedIn,
224
+ isLoaded,
225
+ baseUrl, // From provider
226
+ afterSignInUrl // From provider
227
+ } = useAuth();
228
+
229
+ // Or use useInsforge (same as useAuth)
230
+ const context = useInsforge();
231
+
232
+ // User information
208
233
  const { user, updateUser, isLoaded } = useUser();
234
+
235
+ // Public auth configuration (OAuth providers, password requirements, etc.)
209
236
  const { oauthProviders, authConfig, isLoaded } = usePublicAuthConfig();
210
237
  ```
211
238
 
@@ -347,8 +374,16 @@ function Dashboard() {
347
374
  <UserContent />
348
375
  </Protect>
349
376
 
377
+ {/* With redirect */}
378
+ <Protect redirectTo="/sign-in">
379
+ <UserContent />
380
+ </Protect>
381
+
350
382
  {/* Custom condition - e.g., role-based */}
351
- <Protect condition={(user) => user.email.endsWith('@admin.com')}>
383
+ <Protect
384
+ condition={(user) => user.email.endsWith('@admin.com')}
385
+ redirectTo="/unauthorized"
386
+ >
352
387
  <AdminPanel />
353
388
  </Protect>
354
389
  </div>
@@ -356,7 +391,185 @@ function Dashboard() {
356
391
  }
357
392
  ```
358
393
 
359
- > **Note:** `<Protect>` is for conditional rendering only. For route-level protection, use your router's authentication guards with `useAuth()` hook.
394
+ > **Note:** `<Protect>` is for component-level conditional rendering. For app-level route protection, use `<RouteGuard>`
395
+
396
+ ---
397
+
398
+ ## Route Protection (Detailed)
399
+
400
+ ### RouteGuard for Vanilla React
401
+
402
+ `RouteGuard` provides app-level authentication protection without requiring any routing library.
403
+
404
+ #### Option 1: External Built-in Auth (Simplest)
405
+
406
+ Redirects to your deployed Insforge Auth pages:
407
+
408
+ ```tsx
409
+ import { InsforgeProvider, RouteGuard } from '@insforge/react';
410
+
411
+ createRoot(document.getElementById('root')!).render(
412
+ <InsforgeProvider
413
+ baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}
414
+ afterSignInUrl="/dashboard"
415
+ >
416
+ <RouteGuard
417
+ builtInAuth
418
+ publicRoutes={['/', '/about', '/pricing']}
419
+ loadingFallback={<div>Loading...</div>}
420
+ >
421
+ <App />
422
+ </RouteGuard>
423
+ </InsforgeProvider>
424
+ );
425
+ ```
426
+
427
+ **Behavior:**
428
+ - User visits `/sign-in` → Redirects to `baseUrl/auth/sign-in`
429
+ - User visits `/sign-up` → Redirects to `baseUrl/auth/sign-up`
430
+ - User visits `/dashboard` (protected) → Redirects to `baseUrl/auth/sign-in`
431
+ - User visits `/` (public) → ✅ Renders normally
432
+
433
+ #### Option 2: Custom Auth Pages
434
+
435
+ Use @insforge/react components in your own app:
436
+
437
+ ```tsx
438
+ import { InsforgeProvider, RouteGuard, SignIn, SignUp } from '@insforge/react';
439
+
440
+ // Simple hash-based routing
441
+ function App() {
442
+ const path = window.location.hash.slice(1) || '/';
443
+
444
+ return (
445
+ <>
446
+ {path === '/login' && <SignIn />}
447
+ {path === '/register' && <SignUp />}
448
+ {path === '/dashboard' && <Dashboard />}
449
+ {path === '/' && <HomePage />}
450
+ </>
451
+ );
452
+ }
453
+
454
+ createRoot(document.getElementById('root')!).render(
455
+ <InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
456
+ <RouteGuard
457
+ builtInAuth={false}
458
+ publicRoutes={['/login', '/register', '/forgot-password', '/']}
459
+ paths={{ signIn: '/login', signUp: '/register' }}
460
+ loadingFallback={<div>Loading...</div>}
461
+ >
462
+ <App />
463
+ </RouteGuard>
464
+ </InsforgeProvider>
465
+ );
466
+ ```
467
+
468
+ **Behavior:**
469
+ - User visits `/login` → ✅ Renders `<SignIn />` (in publicRoutes)
470
+ - User visits `/dashboard` (protected) → Redirects to `/login?redirect=/dashboard`
471
+ - After login → Redirects to `/dashboard`
472
+
473
+ #### RouteGuard Props Reference
474
+
475
+ | Prop | Type | Required | Default | Description |
476
+ |------|------|----------|---------|-------------|
477
+ | `builtInAuth` | `boolean` | No | `true` | Use external auth pages (`true`) or custom pages (`false`) |
478
+ | `publicRoutes` | `string[]` | No | `[]` | Routes accessible without authentication |
479
+ | `paths` | `object` | No | `{ signIn: '/sign-in', ... }` | Custom auth page paths (when `builtInAuth=false`) |
480
+ | `paths.signIn` | `string` | No | `'/sign-in'` | Custom sign-in page path |
481
+ | `paths.signUp` | `string` | No | `'/sign-up'` | Custom sign-up page path |
482
+ | `paths.forgotPassword` | `string` | No | `'/forgot-password'` | Custom forgot password page path |
483
+ | `loadingFallback` | `ReactNode` | **Yes** | - | Loading UI displayed while checking authentication |
484
+
485
+ **Public Routes with Wildcards:**
486
+
487
+ ```tsx
488
+ <RouteGuard
489
+ publicRoutes={[
490
+ '/', // Home page
491
+ '/about', // About page
492
+ '/blog/*', // All blog routes
493
+ '/docs/*', // All documentation routes
494
+ ]}
495
+ >
496
+ <App />
497
+ </RouteGuard>
498
+ ```
499
+
500
+ > **Note:** When `builtInAuth=true`, auth paths (`/sign-in`, `/sign-up`, `/forgot-password`) are automatically redirected. Don't include them in `publicRoutes`.
501
+
502
+ ### React Router Integration
503
+
504
+ For React Router apps, use the dedicated adapter:
505
+
506
+ ```bash
507
+ npm install @insforge/react-router
508
+ ```
509
+
510
+ ```tsx
511
+ import { InsforgeProvider } from '@insforge/react-router';
512
+ import { getInsforgeRoutes } from '@insforge/react-router/router';
513
+ import { createBrowserRouter, RouterProvider } from 'react-router-dom';
514
+
515
+ const router = createBrowserRouter([
516
+ { path: '/', element: <Home /> },
517
+ { path: '/dashboard', element: <Dashboard /> },
518
+ ...getInsforgeRoutes({
519
+ baseUrl: import.meta.env.VITE_INSFORGE_BASE_URL,
520
+ builtInAuth: true
521
+ })
522
+ ]);
523
+
524
+ function App() {
525
+ return (
526
+ <InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
527
+ <RouterProvider router={router} />
528
+ </InsforgeProvider>
529
+ );
530
+ }
531
+ ```
532
+
533
+ **Features:**
534
+ - Pre-configured routes for authentication flows
535
+ - React Router's `Link` and `useSearchParams` integration
536
+ - Optimized navigation with client-side routing
537
+
538
+ **Docs:** [@insforge/react-router](https://github.com/InsForge/InsForge/tree/main/packages/react-router)
539
+
540
+ ### Next.js Integration
541
+
542
+ For Next.js App Router with SSR:
543
+
544
+ ```bash
545
+ npm install @insforge/nextjs
546
+ ```
547
+
548
+ ```tsx
549
+ // app/layout.tsx
550
+ import { InsforgeProvider } from '@insforge/nextjs';
551
+
552
+ export default function RootLayout({ children }) {
553
+ return (
554
+ <html>
555
+ <body>
556
+ <InsforgeProvider baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL}>
557
+ {children}
558
+ </InsforgeProvider>
559
+ </body>
560
+ </html>
561
+ );
562
+ }
563
+ ```
564
+
565
+ **Features:**
566
+ - Server-side rendering (SSR) support
567
+ - Middleware-based route protection
568
+ - Next.js `Link` and `useSearchParams` integration
569
+ - Cookie-based session management
570
+ - Automatic token refresh
571
+
572
+ **Docs:** [@insforge/nextjs](https://github.com/InsForge/InsForge/tree/main/packages/nextjs)
360
573
 
361
574
  ---
362
575
 
@@ -401,17 +614,117 @@ Low-level building blocks for complete customization:
401
614
 
402
615
  ---
403
616
 
404
- ## Framework Integration
405
617
 
406
- ### Next.js
618
+ ## API Reference
407
619
 
408
- For Next.js App Router with full SSR support:
620
+ ### InsforgeProvider
409
621
 
410
- ```bash
411
- npm install @insforge/nextjs
622
+ The root provider component that manages authentication state.
623
+
624
+ **Props:**
625
+
626
+ | Prop | Type | Required | Default | Description |
627
+ |------|------|----------|---------|-------------|
628
+ | `baseUrl` | `string` | **Yes** | - | Your Insforge backend URL |
629
+ | `afterSignInUrl` | `string` | No | `'/'` | Redirect URL after successful sign-in |
630
+ | `onAuthChange` | `(user: InsforgeUser \| null) => void` | No | - | Callback when auth state changes |
631
+ | `onSignIn` | `(authToken: string) => Promise<void>` | No | - | Custom handler after sign-in (e.g., cookie sync) |
632
+ | `onSignOut` | `() => Promise<void>` | No | - | Custom handler after sign-out (e.g., clear cookies) |
633
+
634
+ **Example:**
635
+
636
+ ```tsx
637
+ <InsforgeProvider
638
+ baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}
639
+ afterSignInUrl="/dashboard"
640
+ onAuthChange={(user) => {
641
+ console.log('Auth changed:', user);
642
+ }}
643
+ >
644
+ {children}
645
+ </InsforgeProvider>
646
+ ```
647
+
648
+ ### RouteGuard
649
+
650
+ App-level route protection for vanilla React apps (no router library needed).
651
+
652
+ See [Route Protection (Detailed)](#route-protection-detailed) for full documentation.
653
+
654
+ **Quick Props:**
655
+
656
+ - `builtInAuth` (default: `true`) - Use external auth or custom pages
657
+ - `publicRoutes` - Array of paths accessible without auth
658
+ - `paths` - Custom auth page paths (when `builtInAuth=false`)
659
+ - `loadingFallback` (required) - Loading UI
660
+
661
+ ### useAuth() / useInsforge()
662
+
663
+ Primary hook for authentication. Both are aliases for the same hook.
664
+
665
+ **Returns:**
666
+
667
+ ```tsx
668
+ {
669
+ // Auth state
670
+ user: InsforgeUser | null;
671
+ isLoaded: boolean;
672
+ isSignedIn: boolean;
673
+
674
+ // Auth methods
675
+ signIn: (email: string, password: string) => Promise<...>;
676
+ signUp: (email: string, password: string) => Promise<...>;
677
+ signOut: () => Promise<void>;
678
+ updateUser: (data: Partial<InsforgeUser>) => Promise<...>;
679
+ reloadAuth: () => Promise<...>;
680
+
681
+ // Email verification
682
+ sendVerificationEmail: (email: string) => Promise<...>;
683
+ verifyEmail: (otp: string, email?: string) => Promise<...>;
684
+
685
+ // Password reset
686
+ sendResetPasswordEmail: (email: string) => Promise<...>;
687
+ resetPassword: (token: string, newPassword: string) => Promise<...>;
688
+ exchangeResetPasswordToken: (email: string, code: string) => Promise<...>;
689
+
690
+ // OAuth
691
+ loginWithOAuth: (provider: OAuthProvider, redirectTo: string) => Promise<void>;
692
+
693
+ // Config (from provider)
694
+ baseUrl: string;
695
+ afterSignInUrl: string;
696
+
697
+ // Public config
698
+ getPublicAuthConfig: () => Promise<...>;
699
+ }
412
700
  ```
413
701
 
414
- See [@insforge/nextjs documentation](https://github.com/InsForge/InsForge/tree/main/packages/nextjs)
702
+ ### useUser()
703
+
704
+ Simplified hook for user data only.
705
+
706
+ **Returns:**
707
+
708
+ ```tsx
709
+ {
710
+ user: InsforgeUser | null;
711
+ isLoaded: boolean;
712
+ }
713
+ ```
714
+
715
+ ### usePublicAuthConfig()
716
+
717
+ Hook for fetching public auth configuration (OAuth providers, password requirements, etc.).
718
+
719
+ **Returns:**
720
+
721
+ ```tsx
722
+ {
723
+ oauthProviders: OAuthProviderConfig[];
724
+ authConfig: AuthConfig;
725
+ isLoaded: boolean;
726
+ }
727
+ ```
415
728
 
416
729
  ---
417
730
 
package/dist/atoms.cjs CHANGED
@@ -107,7 +107,10 @@ var NavigationContext = react.createContext(null);
107
107
  function useNavigationAdapter() {
108
108
  const adapter = react.useContext(NavigationContext);
109
109
  if (!adapter) {
110
- throw new Error("useNavigationAdapter must be used within NavigationProvider");
110
+ return {
111
+ useSearchParams: () => new URLSearchParams(),
112
+ Link: ({ href, children }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href, children })
113
+ };
111
114
  }
112
115
  return adapter;
113
116
  }
@@ -646,7 +649,8 @@ function useInsforge() {
646
649
  loginWithOAuth: async () => {
647
650
  },
648
651
  getPublicAuthConfig: async () => null,
649
- baseUrl: ""
652
+ baseUrl: "",
653
+ afterSignInUrl: "/"
650
654
  };
651
655
  }
652
656
  return context;