@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 +330 -17
- package/dist/atoms.cjs +6 -2
- package/dist/atoms.cjs.map +1 -1
- package/dist/atoms.js +6 -2
- package/dist/atoms.js.map +1 -1
- package/dist/components.cjs +6 -2
- package/dist/components.cjs.map +1 -1
- package/dist/components.js +6 -2
- package/dist/components.js.map +1 -1
- package/dist/forms.cjs +6 -2
- package/dist/forms.cjs.map +1 -1
- package/dist/forms.js +6 -2
- package/dist/forms.js.map +1 -1
- package/dist/hooks.cjs +2 -1
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.js +2 -1
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +100 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +100 -5
- package/dist/index.js.map +1 -1
- package/dist/navigation.cjs +4 -1
- package/dist/navigation.cjs.map +1 -1
- package/dist/navigation.js +4 -1
- package/dist/navigation.js.map +1 -1
- package/dist/routes.cjs +132 -0
- package/dist/routes.cjs.map +1 -0
- package/dist/routes.d.cts +78 -0
- package/dist/routes.d.ts +78 -0
- package/dist/routes.js +130 -0
- package/dist/routes.js.map +1 -0
- package/package.json +7 -2
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** -
|
|
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
|
|
55
|
-
|
|
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!** 🎉
|
|
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
|
-
- `<
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
618
|
+
## API Reference
|
|
407
619
|
|
|
408
|
-
|
|
620
|
+
### InsforgeProvider
|
|
409
621
|
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|