exguard-client 1.0.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.
@@ -0,0 +1,609 @@
1
+ # ExGuard Client Implementation Guide
2
+
3
+ Complete step-by-step guide to implement @empowerx/exguard-client in your React application.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Prerequisites](#prerequisites)
8
+ - [Installation](#installation)
9
+ - [Project Setup](#project-setup)
10
+ - [Configuration](#configuration)
11
+ - [Basic Usage](#basic-usage)
12
+ - [Advanced Features](#advanced-features)
13
+ - [Best Practices](#best-practices)
14
+ - [Troubleshooting](#troubleshooting)
15
+
16
+ ## Prerequisites
17
+
18
+ Before installing ExGuard client, ensure you have:
19
+
20
+ 1. **Node.js** >= 18.0.0
21
+ 2. **React** >= 18.0.0 or >= 19.0.0
22
+ 3. **TypeScript** (recommended for type safety)
23
+ 4. **ExGuard Backend API** running and accessible
24
+
25
+ ### Required Peer Dependencies
26
+
27
+ ```json
28
+ {
29
+ "react": "^18.0.0 || ^19.0.0",
30
+ "react-dom": "^18.0.0 || ^19.0.0",
31
+ "react-router": "^7.0.0",
32
+ "axios": "^1.0.0",
33
+ "socket.io-client": "^4.0.0"
34
+ }
35
+ ```
36
+
37
+ ## Installation
38
+
39
+ ### Step 1: Install the Package
40
+
41
+ Using pnpm (recommended):
42
+ ```bash
43
+ pnpm add @empowerx/exguard-client
44
+ ```
45
+
46
+ Using npm:
47
+ ```bash
48
+ npm install @empowerx/exguard-client
49
+ ```
50
+
51
+ Using yarn:
52
+ ```bash
53
+ yarn add @empowerx/exguard-client
54
+ ```
55
+
56
+ ### Step 2: Install Peer Dependencies
57
+
58
+ If not already installed:
59
+
60
+ ```bash
61
+ # Using pnpm
62
+ pnpm add react react-dom react-router axios socket.io-client
63
+
64
+ # Using npm
65
+ npm install react react-dom react-router axios socket.io-client
66
+ ```
67
+
68
+ ## Project Setup
69
+
70
+ ### Option 1: Using the Setup Script (Recommended)
71
+
72
+ The package includes a setup script that creates a clean module structure in your project:
73
+
74
+ ```bash
75
+ npx exguard-setup
76
+ # or
77
+ pnpm exguard-setup
78
+ ```
79
+
80
+ This creates:
81
+ ```
82
+ src/features/exguard/
83
+ ├── index.ts # Re-exports from @empowerx/exguard-client
84
+ ├── README.md # Module-specific documentation
85
+ └── config/
86
+ └── exguard.config.ts # Optional configuration file
87
+ ```
88
+
89
+ **Benefits:**
90
+ - Clean separation between package and application code
91
+ - Easy to customize or extend ExGuard functionality
92
+ - Consistent import paths across your application
93
+ - Type-safe re-exports
94
+
95
+ ### Option 2: Direct Package Imports
96
+
97
+ You can also import directly from the package without the setup script:
98
+
99
+ ```tsx
100
+ import { PermissionGuard, useUserAccess } from '@empowerx/exguard-client';
101
+ ```
102
+
103
+ ## Configuration
104
+
105
+ ### Step 1: Configure ExGuard API URL
106
+
107
+ In your application entry point (`main.tsx` or `App.tsx`):
108
+
109
+ ```tsx
110
+ // src/main.tsx
111
+ import { StrictMode } from 'react';
112
+ import { createRoot } from 'react-dom/client';
113
+ import { ExGuardRealtimeProvider, setExGuardConfig } from '@/features/exguard';
114
+ import App from './App';
115
+
116
+ // Configure ExGuard API URL
117
+ setExGuardConfig({
118
+ apiUrl: import.meta.env.VITE_GUARD_APP_URL as string,
119
+ });
120
+
121
+ createRoot(document.getElementById('root')!).render(
122
+ <StrictMode>
123
+ <ExGuardRealtimeProvider>
124
+ <App />
125
+ </ExGuardRealtimeProvider>
126
+ </StrictMode>
127
+ );
128
+ ```
129
+
130
+ ### Step 2: Environment Variables
131
+
132
+ Create or update your `.env` file:
133
+
134
+ **For Vite:**
135
+ ```env
136
+ VITE_GUARD_APP_URL=https://your-exguard-api.com
137
+ ```
138
+
139
+ **For Next.js:**
140
+ ```env
141
+ NEXT_PUBLIC_GUARD_APP_URL=https://your-exguard-api.com
142
+ ```
143
+
144
+ **For Create React App:**
145
+ ```env
146
+ REACT_APP_GUARD_APP_URL=https://your-exguard-api.com
147
+ ```
148
+
149
+ ### Step 3: Wrap Your Application
150
+
151
+ Ensure your app is wrapped with `ExGuardRealtimeProvider`:
152
+
153
+ ```tsx
154
+ // src/App.tsx
155
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
156
+ import { RouterProvider } from 'react-router';
157
+ import { ExGuardRealtimeProvider, setExGuardConfig } from '@/features/exguard';
158
+ import router from './router';
159
+
160
+ const queryClient = new QueryClient();
161
+
162
+ // Configure before rendering
163
+ setExGuardConfig({
164
+ apiUrl: import.meta.env.VITE_GUARD_APP_URL as string,
165
+ });
166
+
167
+ function App() {
168
+ return (
169
+ <QueryClientProvider client={queryClient}>
170
+ <ExGuardRealtimeProvider>
171
+ <RouterProvider router={router} />
172
+ </ExGuardRealtimeProvider>
173
+ </QueryClientProvider>
174
+ );
175
+ }
176
+
177
+ export default App;
178
+ ```
179
+
180
+ ## Basic Usage
181
+
182
+ ### 1. Route Protection with PermissionGuard
183
+
184
+ Protect entire routes or components based on module access:
185
+
186
+ ```tsx
187
+ // src/features/profiles/pages/ProfilesPage.tsx
188
+ import { PermissionGuard } from '@/features/exguard';
189
+ import { ProfilesList } from '../components/ProfilesList';
190
+
191
+ export function ProfilesPage() {
192
+ return (
193
+ <PermissionGuard
194
+ module="EXID"
195
+ fallbackPath="/unauthorized"
196
+ >
197
+ <ProfilesList />
198
+ </PermissionGuard>
199
+ );
200
+ }
201
+ ```
202
+
203
+ ### 2. Permission-Based Feature Access
204
+
205
+ Protect specific features or actions:
206
+
207
+ ```tsx
208
+ // src/features/profiles/pages/ProfileDetailPage.tsx
209
+ import { PermissionGuard } from '@/features/exguard';
210
+
211
+ export function ProfileDetailPage() {
212
+ return (
213
+ <div>
214
+ <h1>Profile Details</h1>
215
+
216
+ {/* Only users with profile:update permission can see this */}
217
+ <PermissionGuard
218
+ module="EXID"
219
+ permission="profile:update"
220
+ requirePermission={true}
221
+ >
222
+ <button>Edit Profile</button>
223
+ </PermissionGuard>
224
+
225
+ {/* Only users with profile:delete permission can see this */}
226
+ <PermissionGuard
227
+ module="EXID"
228
+ permission="profile:delete"
229
+ requirePermission={true}
230
+ >
231
+ <button>Delete Profile</button>
232
+ </PermissionGuard>
233
+ </div>
234
+ );
235
+ }
236
+ ```
237
+
238
+ ### 3. Using useUserAccess Hook
239
+
240
+ Access user permissions programmatically:
241
+
242
+ ```tsx
243
+ // src/features/profiles/components/ProfileActions.tsx
244
+ import { useUserAccess } from '@/features/exguard';
245
+
246
+ export function ProfileActions({ profileId }: { profileId: string }) {
247
+ const { hasModuleAccess, hasPermission, isLoading } = useUserAccess();
248
+
249
+ if (isLoading) {
250
+ return <div>Loading permissions...</div>;
251
+ }
252
+
253
+ // Check module access
254
+ if (!hasModuleAccess('EXID')) {
255
+ return <div>Access denied to EXID module</div>;
256
+ }
257
+
258
+ return (
259
+ <div className="flex gap-2">
260
+ {/* Show edit button only if user has permission */}
261
+ {hasPermission('EXID', 'profile:update') && (
262
+ <button onClick={() => handleEdit(profileId)}>
263
+ Edit
264
+ </button>
265
+ )}
266
+
267
+ {/* Show delete button only if user has permission */}
268
+ {hasPermission('EXID', 'profile:delete') && (
269
+ <button onClick={() => handleDelete(profileId)}>
270
+ Delete
271
+ </button>
272
+ )}
273
+
274
+ {/* View is always available if user has module access */}
275
+ <button onClick={() => handleView(profileId)}>
276
+ View
277
+ </button>
278
+ </div>
279
+ );
280
+ }
281
+ ```
282
+
283
+ ### 4. API Functions
284
+
285
+ Verify tokens and get user access data:
286
+
287
+ ```tsx
288
+ // src/features/auth/hooks/useAuth.ts
289
+ import { verifyToken, getUserAccess } from '@/features/exguard';
290
+
291
+ export function useAuth() {
292
+ const checkAuthentication = async () => {
293
+ try {
294
+ const result = await verifyToken();
295
+
296
+ if (!result.isValid) {
297
+ // Token is invalid, redirect to login
298
+ window.location.href = '/login';
299
+ return;
300
+ }
301
+
302
+ // Get user's access data
303
+ const userAccess = await getUserAccess();
304
+ console.log('User modules:', userAccess.modules);
305
+ console.log('User roles:', userAccess.roles);
306
+
307
+ return userAccess;
308
+ } catch (error) {
309
+ console.error('Authentication failed:', error);
310
+ throw error;
311
+ }
312
+ };
313
+
314
+ return { checkAuthentication };
315
+ }
316
+ ```
317
+
318
+ ## Advanced Features
319
+
320
+ ### 1. Realtime RBAC Updates
321
+
322
+ Listen to real-time permission changes:
323
+
324
+ ```tsx
325
+ // src/features/admin/pages/UsersPage.tsx
326
+ import { useEffect, useState } from 'react';
327
+ import {
328
+ useExGuardRealtime,
329
+ useExGuardRealtimeSubscription,
330
+ EXGUARD_RBAC_EVENTS
331
+ } from '@/features/exguard';
332
+
333
+ export function UsersPage() {
334
+ const [users, setUsers] = useState([]);
335
+ const { isConnected } = useExGuardRealtime();
336
+
337
+ // Subscribe to user RBAC updates
338
+ useExGuardRealtimeSubscription(
339
+ EXGUARD_RBAC_EVENTS.USER_ROLES_UPDATED,
340
+ (payload) => {
341
+ console.log('User roles updated:', payload);
342
+ // Refresh user list or update specific user
343
+ refreshUsers();
344
+ }
345
+ );
346
+
347
+ // Subscribe to permission changes
348
+ useExGuardRealtimeSubscription(
349
+ EXGUARD_RBAC_EVENTS.RBAC_PERMISSIONS_UPDATED,
350
+ (payload) => {
351
+ console.log('Permissions updated:', payload);
352
+ // Refresh current user's access data
353
+ window.location.reload(); // or use a more elegant refresh
354
+ }
355
+ );
356
+
357
+ return (
358
+ <div>
359
+ <div>WebSocket: {isConnected ? '✅ Connected' : '❌ Disconnected'}</div>
360
+ {/* User list */}
361
+ </div>
362
+ );
363
+ }
364
+ ```
365
+
366
+ ### 2. Custom RBAC Refresh Logic
367
+
368
+ Register callbacks for when RBAC data needs to be refreshed:
369
+
370
+ ```tsx
371
+ // src/providers/AppProvider.tsx
372
+ import { useEffect } from 'react';
373
+ import { useExGuardRealtime, getUserAccess } from '@/features/exguard';
374
+ import { useQueryClient } from '@tanstack/react-query';
375
+
376
+ export function AppProvider({ children }) {
377
+ const { registerRbacRefreshCallback } = useExGuardRealtime();
378
+ const queryClient = useQueryClient();
379
+
380
+ useEffect(() => {
381
+ // Register callback to refresh user data when RBAC changes
382
+ const unregister = registerRbacRefreshCallback(async () => {
383
+ console.log('RBAC data changed, refreshing...');
384
+
385
+ // Refetch user access data
386
+ const newAccess = await getUserAccess();
387
+
388
+ // Update React Query cache
389
+ queryClient.setQueryData(['userAccess'], newAccess);
390
+
391
+ // Invalidate related queries
392
+ queryClient.invalidateQueries({ queryKey: ['permissions'] });
393
+ queryClient.invalidateQueries({ queryKey: ['modules'] });
394
+ });
395
+
396
+ return unregister; // Cleanup on unmount
397
+ }, [registerRbacRefreshCallback, queryClient]);
398
+
399
+ return <>{children}</>;
400
+ }
401
+ ```
402
+
403
+ ### 3. Token Management
404
+
405
+ Access and manage authentication tokens:
406
+
407
+ ```tsx
408
+ // src/utils/auth.ts
409
+ import { EXGUARD_STORAGE_KEYS } from '@/features/exguard';
410
+
411
+ export function getAccessToken(): string | null {
412
+ return localStorage.getItem(EXGUARD_STORAGE_KEYS.ACCESS_TOKEN);
413
+ }
414
+
415
+ export function getIdToken(): string | null {
416
+ return localStorage.getItem(EXGUARD_STORAGE_KEYS.ID_TOKEN);
417
+ }
418
+
419
+ export function clearTokens(): void {
420
+ localStorage.removeItem(EXGUARD_STORAGE_KEYS.ACCESS_TOKEN);
421
+ localStorage.removeItem(EXGUARD_STORAGE_KEYS.ID_TOKEN);
422
+ localStorage.removeItem(EXGUARD_STORAGE_KEYS.REFRESH_TOKEN);
423
+ }
424
+
425
+ // Use in axios interceptor
426
+ import axios from 'axios';
427
+
428
+ axios.interceptors.request.use((config) => {
429
+ const token = getAccessToken();
430
+ if (token) {
431
+ config.headers.Authorization = `Bearer ${token}`;
432
+ }
433
+ return config;
434
+ });
435
+ ```
436
+
437
+ ## Best Practices
438
+
439
+ ### 1. Import Pattern
440
+
441
+ **✅ DO:** Use the generated exguard module for imports
442
+ ```tsx
443
+ import { PermissionGuard, useUserAccess } from '@/features/exguard';
444
+ ```
445
+
446
+ **❌ DON'T:** Mix package and module imports
447
+ ```tsx
448
+ // Avoid this - choose one pattern
449
+ import { PermissionGuard } from '@empowerx/exguard-client';
450
+ import { useUserAccess } from '@/features/exguard';
451
+ ```
452
+
453
+ ### 2. Permission Guard Placement
454
+
455
+ **✅ DO:** Place PermissionGuard at route level
456
+ ```tsx
457
+ <Route
458
+ path="/profiles"
459
+ element={
460
+ <PermissionGuard module="EXID">
461
+ <ProfilesPage />
462
+ </PermissionGuard>
463
+ }
464
+ />
465
+ ```
466
+
467
+ **✅ DO:** Use for feature-level protection
468
+ ```tsx
469
+ <PermissionGuard module="EXID" permission="profile:delete">
470
+ <DeleteButton />
471
+ </PermissionGuard>
472
+ ```
473
+
474
+ ### 3. Error Handling
475
+
476
+ Always handle permission errors gracefully:
477
+
478
+ ```tsx
479
+ import { useUserAccess } from '@/features/exguard';
480
+
481
+ export function MyComponent() {
482
+ const { hasModuleAccess, error, isLoading } = useUserAccess();
483
+
484
+ if (isLoading) {
485
+ return <LoadingSpinner />;
486
+ }
487
+
488
+ if (error) {
489
+ return <ErrorMessage message="Failed to load permissions" />;
490
+ }
491
+
492
+ if (!hasModuleAccess('EXID')) {
493
+ return <AccessDenied />;
494
+ }
495
+
496
+ return <ProtectedContent />;
497
+ }
498
+ ```
499
+
500
+ ### 4. Performance
501
+
502
+ Use `enabled` option to control when to fetch permissions:
503
+
504
+ ```tsx
505
+ const { hasModuleAccess } = useUserAccess({
506
+ enabled: isAuthenticated, // Only fetch when authenticated
507
+ refetchInterval: 60000, // Refetch every minute
508
+ });
509
+ ```
510
+
511
+ ### 5. TypeScript Usage
512
+
513
+ Leverage full type safety:
514
+
515
+ ```tsx
516
+ import type {
517
+ UserAccessData,
518
+ ModulePermissions,
519
+ RealtimeEventPayload
520
+ } from '@/features/exguard';
521
+
522
+ interface MyComponentProps {
523
+ userAccess: UserAccessData;
524
+ onPermissionChange: (payload: RealtimeEventPayload) => void;
525
+ }
526
+ ```
527
+
528
+ ## Troubleshooting
529
+
530
+ ### Issue: "Cannot find module '@/features/exguard'"
531
+
532
+ **Solution:** Ensure you've run the setup script and your tsconfig paths are configured:
533
+
534
+ ```json
535
+ // tsconfig.json
536
+ {
537
+ "compilerOptions": {
538
+ "baseUrl": ".",
539
+ "paths": {
540
+ "@/*": ["./src/*"]
541
+ }
542
+ }
543
+ }
544
+ ```
545
+
546
+ ### Issue: WebSocket not connecting
547
+
548
+ **Solution:** Check that:
549
+ 1. ExGuard API URL is correct
550
+ 2. User is authenticated (has valid tokens)
551
+ 3. CORS is properly configured on the backend
552
+ 4. ExGuardRealtimeProvider is wrapping your app
553
+
554
+ ```tsx
555
+ // Debug connection
556
+ const { isConnected } = useExGuardRealtime();
557
+ console.log('WebSocket connected:', isConnected);
558
+ ```
559
+
560
+ ### Issue: Permissions not updating in real-time
561
+
562
+ **Solution:** Ensure you're listening to the correct events:
563
+
564
+ ```tsx
565
+ import { EXGUARD_RBAC_EVENTS } from '@/features/exguard';
566
+
567
+ // Listen to general RBAC updates
568
+ useExGuardRealtimeSubscription(
569
+ EXGUARD_RBAC_EVENTS.RBAC_PERMISSIONS_UPDATED,
570
+ (payload) => {
571
+ // Refresh user access data
572
+ window.location.reload();
573
+ }
574
+ );
575
+ ```
576
+
577
+ ### Issue: TypeScript errors after installation
578
+
579
+ **Solution:** Rebuild the package and clear TypeScript cache:
580
+
581
+ ```bash
582
+ cd packages/exguard-client
583
+ pnpm build
584
+
585
+ # In your app
586
+ rm -rf node_modules/.cache
587
+ pnpm install
588
+ ```
589
+
590
+ ### Issue: Module not found errors for old imports
591
+
592
+ **Solution:** Old realtime provider files need to be deleted. Remove:
593
+ - `src/app/providers/realtime-*.ts*`
594
+ - `src/shared/hooks/use-realtime.ts`
595
+ - `src/shared/lib/realtime*.ts`
596
+
597
+ Then update all imports to use `@/features/exguard`.
598
+
599
+ ## Support
600
+
601
+ For additional help:
602
+
603
+ 1. Check the [README.md](./README.md) for API reference
604
+ 2. Review example implementations in the test applications
605
+ 3. Contact the EmpowerX development team
606
+
607
+ ## License
608
+
609
+ MIT