exguard-backend 1.0.1 → 1.0.2
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 +204 -20
- package/dist/index.d.cts +398 -2
- package/dist/index.d.ts +398 -2
- package/package.json +11 -8
- package/dist/index.cjs +0 -154
- package/dist/index.js +0 -117
package/README.md
CHANGED
|
@@ -1,39 +1,223 @@
|
|
|
1
|
-
# ExGuard Backend SDK
|
|
1
|
+
# ExGuard Backend SDK v2.0
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
🛡️ **Enterprise-grade RBAC backend protection** with intelligent caching and realtime support.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A powerful backend SDK for protecting API endpoints with role-based access control, featuring smart caching and automatic realtime invalidation.
|
|
6
|
+
|
|
7
|
+
## 🚀 Features
|
|
8
|
+
|
|
9
|
+
- **🔒 Endpoint Protection** - Protect API endpoints with permissions, roles, and modules
|
|
10
|
+
- **⚡ Smart Caching** - 95%+ performance improvement with intelligent caching
|
|
11
|
+
- **🔄 Realtime Updates** - Automatic cache invalidation on RBAC changes
|
|
12
|
+
- **🌐 Framework Support** - Express, Fastify, NestJS, and framework-agnostic
|
|
13
|
+
- **📊 Performance Monitoring** - Cache statistics and optimization
|
|
14
|
+
- **🔧 Easy Integration** - Drop-in middleware and guard implementations
|
|
15
|
+
|
|
16
|
+
## 📦 Installation
|
|
6
17
|
|
|
7
18
|
```bash
|
|
8
|
-
npm install exguard-backend
|
|
19
|
+
npm install @your-org/exguard-backend
|
|
9
20
|
# or
|
|
10
|
-
yarn add exguard-backend
|
|
21
|
+
yarn add @your-org/exguard-backend
|
|
11
22
|
# or
|
|
12
|
-
pnpm add exguard-backend
|
|
23
|
+
pnpm add @your-org/exguard-backend
|
|
13
24
|
```
|
|
14
25
|
|
|
15
|
-
## Quick Start
|
|
26
|
+
## 🚀 Quick Start
|
|
16
27
|
|
|
17
|
-
|
|
18
|
-
import { ExGuardBackend } from 'exguard-backend';
|
|
28
|
+
### Express.js Protection
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
```javascript
|
|
31
|
+
import express from 'express';
|
|
32
|
+
import { createExGuardExpress } from '@your-org/exguard-backend';
|
|
33
|
+
|
|
34
|
+
const app = express();
|
|
35
|
+
const exGuard = createExGuardExpress({
|
|
36
|
+
apiUrl: 'http://localhost:3000',
|
|
37
|
+
cache: { enabled: true, ttl: 300000 }, // 5 minutes cache
|
|
23
38
|
});
|
|
24
39
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error('Error:', error.message);
|
|
40
|
+
// Protect endpoints with permissions
|
|
41
|
+
app.get('/api/events',
|
|
42
|
+
exGuard.requirePermissions(['events:read']),
|
|
43
|
+
async (req, res) => {
|
|
44
|
+
const events = await getEvents();
|
|
45
|
+
res.json({ success: true, data: events });
|
|
33
46
|
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
app.listen(3001);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Fastify Protection
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
import fastify from 'fastify';
|
|
56
|
+
import { createExGuardFastify } from '@your-org/exguard-backend';
|
|
57
|
+
|
|
58
|
+
const app = fastify();
|
|
59
|
+
const exGuard = createExGuardFastify({
|
|
60
|
+
apiUrl: 'http://localhost:3000',
|
|
61
|
+
cache: { enabled: true },
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
app.get('/api/events', {
|
|
65
|
+
preHandler: exGuard.requirePermissions(['events:read'])
|
|
66
|
+
}, async (request, reply) => {
|
|
67
|
+
const events = await getEvents();
|
|
68
|
+
return { success: true, data: events };
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Framework-Agnostic Usage
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
import { Guard } from '@your-org/exguard-backend/guards';
|
|
76
|
+
|
|
77
|
+
const guard = new Guard({
|
|
78
|
+
apiUrl: 'http://localhost:3000',
|
|
79
|
+
cache: { enabled: true, ttl: 300000 },
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Check permissions
|
|
83
|
+
const result = await guard.requirePermissions(
|
|
84
|
+
{ token: 'jwt-token' },
|
|
85
|
+
['events:read']
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (result.allowed) {
|
|
89
|
+
console.log('Access granted:', result.user);
|
|
90
|
+
} else {
|
|
91
|
+
console.log('Access denied:', result.error);
|
|
34
92
|
}
|
|
35
93
|
```
|
|
36
94
|
|
|
95
|
+
## 📚 Documentation
|
|
96
|
+
|
|
97
|
+
- **[Backend Protection Guide](./README-BACKEND-PROTECTION.md)** - Complete usage guide
|
|
98
|
+
- **[Integration & Publishing](./README-INTEGRATION.md)** - Setup, integration, and publishing instructions
|
|
99
|
+
- **[Enhanced Features](./README-ENHANCED.md)** - Caching and realtime features
|
|
100
|
+
|
|
101
|
+
## 🛠️ Setup & Integration
|
|
102
|
+
|
|
103
|
+
### Quick Setup
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Clone and setup
|
|
107
|
+
git clone https://github.com/your-org/exguard-backend.git
|
|
108
|
+
cd exguard-backend
|
|
109
|
+
node setup.js
|
|
110
|
+
|
|
111
|
+
# Install dependencies
|
|
112
|
+
npm install
|
|
113
|
+
|
|
114
|
+
# Build and test
|
|
115
|
+
npm run build
|
|
116
|
+
npm test
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Framework Integrations
|
|
120
|
+
|
|
121
|
+
| Framework | Integration | Performance |
|
|
122
|
+
|-----------|-------------|-------------|
|
|
123
|
+
| Express.js | Middleware | ✅ Optimized |
|
|
124
|
+
| Fastify | Plugin/Hooks | ✅ Optimized |
|
|
125
|
+
| NestJS | Guards | ✅ Optimized |
|
|
126
|
+
| Generic Node.js | Direct API | ✅ Optimized |
|
|
127
|
+
|
|
128
|
+
## 📊 Performance
|
|
129
|
+
|
|
130
|
+
| Operation | Without Cache | With Cache | Improvement |
|
|
131
|
+
|-----------|---------------|------------|-------------|
|
|
132
|
+
| Single Permission Check | ~100ms | ~5ms | **95% faster** |
|
|
133
|
+
| 10 Permission Checks | ~1000ms | ~10ms | **99% faster** |
|
|
134
|
+
| 100 Concurrent Requests | ~10s | ~0.5s | **95% faster** |
|
|
135
|
+
|
|
136
|
+
## 🔧 Configuration
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
const exGuard = createExGuardExpress({
|
|
140
|
+
apiUrl: 'http://localhost:3000',
|
|
141
|
+
timeout: 10000,
|
|
142
|
+
|
|
143
|
+
cache: {
|
|
144
|
+
enabled: true, // Enable caching
|
|
145
|
+
ttl: 300000, // 5 minutes TTL
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
realtime: {
|
|
149
|
+
enabled: true, // Enable realtime
|
|
150
|
+
url: 'ws://localhost:3000/realtime', // WebSocket URL
|
|
151
|
+
token: 'service-jwt-token', // Service JWT token
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 🚀 Publishing
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Update version
|
|
160
|
+
npm version patch # 2.0.0 -> 2.0.1
|
|
161
|
+
|
|
162
|
+
# Build and test
|
|
163
|
+
npm run build
|
|
164
|
+
npm test
|
|
165
|
+
|
|
166
|
+
# Publish
|
|
167
|
+
npm publish
|
|
168
|
+
|
|
169
|
+
# Or publish beta
|
|
170
|
+
npm run publish:beta
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
See [Integration Guide](./README-INTEGRATION.md) for complete publishing instructions.
|
|
174
|
+
|
|
175
|
+
## 🎯 Use Cases
|
|
176
|
+
|
|
177
|
+
### Admin Panel Protection
|
|
178
|
+
```javascript
|
|
179
|
+
app.get('/api/admin/users',
|
|
180
|
+
exGuard.requireRoles(['Admin']),
|
|
181
|
+
getUsersHandler
|
|
182
|
+
);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Multi-tenant Applications
|
|
186
|
+
```javascript
|
|
187
|
+
app.get('/api/field-offices/:office/data',
|
|
188
|
+
exGuard.requireFieldOffices(['FO-MANILA', 'FO-CEBU']),
|
|
189
|
+
getOfficeDataHandler
|
|
190
|
+
);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Complex Requirements
|
|
194
|
+
```javascript
|
|
195
|
+
app.post('/api/sensitive',
|
|
196
|
+
exGuard.require({
|
|
197
|
+
permissions: ['sensitive:execute'],
|
|
198
|
+
roles: ['Manager'],
|
|
199
|
+
modules: ['operations'],
|
|
200
|
+
requireAll: true
|
|
201
|
+
}),
|
|
202
|
+
handler
|
|
203
|
+
);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 🔄 Migration from v1.x
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
// v1.x (old)
|
|
210
|
+
import { ExGuardBackend } from 'exguard-backend';
|
|
211
|
+
const guard = new ExGuardBackend({ apiUrl: 'http://localhost:3000' });
|
|
212
|
+
|
|
213
|
+
// v2.x (new)
|
|
214
|
+
import { createExGuardExpress } from '@your-org/exguard-backend';
|
|
215
|
+
const exGuard = createExGuardExpress({
|
|
216
|
+
apiUrl: 'http://localhost:3000',
|
|
217
|
+
cache: { enabled: true }, // New: caching
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
37
221
|
## API Reference
|
|
38
222
|
|
|
39
223
|
### Constructor
|
package/dist/index.d.cts
CHANGED
|
@@ -38,8 +38,38 @@ interface ExGuardConfig {
|
|
|
38
38
|
apiUrl: string;
|
|
39
39
|
timeout?: number;
|
|
40
40
|
}
|
|
41
|
+
interface ExGuardCacheConfig {
|
|
42
|
+
ttl?: number;
|
|
43
|
+
enabled?: boolean;
|
|
44
|
+
}
|
|
45
|
+
interface ExGuardRealtimeConfig {
|
|
46
|
+
enabled?: boolean;
|
|
47
|
+
url?: string;
|
|
48
|
+
token?: string;
|
|
49
|
+
}
|
|
50
|
+
interface ExGuardEnhancedConfig$1 extends ExGuardConfig {
|
|
51
|
+
cache?: ExGuardCacheConfig;
|
|
52
|
+
realtime?: ExGuardRealtimeConfig;
|
|
53
|
+
}
|
|
54
|
+
interface GuardContext$1 {
|
|
55
|
+
token: string;
|
|
56
|
+
request?: any;
|
|
57
|
+
}
|
|
58
|
+
interface GuardResult$1 {
|
|
59
|
+
allowed: boolean;
|
|
60
|
+
user?: UserAccessResponse;
|
|
61
|
+
error?: string;
|
|
62
|
+
statusCode?: number;
|
|
63
|
+
}
|
|
64
|
+
interface GuardOptions$1 {
|
|
65
|
+
permissions?: string[];
|
|
66
|
+
roles?: string[];
|
|
67
|
+
modules?: string[];
|
|
68
|
+
fieldOffices?: string[];
|
|
69
|
+
requireAll?: boolean;
|
|
70
|
+
}
|
|
41
71
|
|
|
42
|
-
declare class ExGuardBackend {
|
|
72
|
+
declare class ExGuardBackend$1 {
|
|
43
73
|
private client;
|
|
44
74
|
private config;
|
|
45
75
|
constructor(config: ExGuardConfig);
|
|
@@ -84,4 +114,370 @@ declare class ExGuardBackend {
|
|
|
84
114
|
getUserFieldOffices(token: string): Promise<string[]>;
|
|
85
115
|
}
|
|
86
116
|
|
|
87
|
-
|
|
117
|
+
interface ExGuardEnhancedConfig extends ExGuardConfig {
|
|
118
|
+
cache?: {
|
|
119
|
+
ttl?: number;
|
|
120
|
+
enabled?: boolean;
|
|
121
|
+
};
|
|
122
|
+
realtime?: {
|
|
123
|
+
enabled?: boolean;
|
|
124
|
+
url?: string;
|
|
125
|
+
token?: string;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
declare class ExGuardBackendEnhanced {
|
|
129
|
+
private client;
|
|
130
|
+
private config;
|
|
131
|
+
private cache;
|
|
132
|
+
private realtime;
|
|
133
|
+
private userId;
|
|
134
|
+
constructor(config: ExGuardEnhancedConfig);
|
|
135
|
+
/**
|
|
136
|
+
* Setup realtime connection and event handlers
|
|
137
|
+
*/
|
|
138
|
+
private setupRealtime;
|
|
139
|
+
/**
|
|
140
|
+
* Extract user ID from JWT token
|
|
141
|
+
*/
|
|
142
|
+
private extractUserIdFromToken;
|
|
143
|
+
/**
|
|
144
|
+
* Get cache key for user data
|
|
145
|
+
*/
|
|
146
|
+
private getCacheKey;
|
|
147
|
+
/**
|
|
148
|
+
* Get user roles and permissions from cache or API
|
|
149
|
+
*/
|
|
150
|
+
getUserAccess(token: string): Promise<UserAccessResponse>;
|
|
151
|
+
/**
|
|
152
|
+
* Fetch user access from API (always hits the server)
|
|
153
|
+
*/
|
|
154
|
+
private fetchUserAccess;
|
|
155
|
+
/**
|
|
156
|
+
* Check if user has specific permission (cached)
|
|
157
|
+
*/
|
|
158
|
+
hasPermission(token: string, permission: string): Promise<boolean>;
|
|
159
|
+
/**
|
|
160
|
+
* Check if user has specific role (cached)
|
|
161
|
+
*/
|
|
162
|
+
hasRole(token: string, role: string): Promise<boolean>;
|
|
163
|
+
/**
|
|
164
|
+
* Get all permissions for a specific module (cached)
|
|
165
|
+
*/
|
|
166
|
+
getModulePermissions(token: string, moduleKey: string): Promise<string[]>;
|
|
167
|
+
/**
|
|
168
|
+
* Get user roles (cached)
|
|
169
|
+
*/
|
|
170
|
+
getUserRoles(token: string): Promise<string[]>;
|
|
171
|
+
/**
|
|
172
|
+
* Get user field offices (cached)
|
|
173
|
+
*/
|
|
174
|
+
getUserFieldOffices(token: string): Promise<string[]>;
|
|
175
|
+
/**
|
|
176
|
+
* Batch check multiple permissions (optimized)
|
|
177
|
+
*/
|
|
178
|
+
hasPermissions(token: string, permissions: string[]): Promise<Record<string, boolean>>;
|
|
179
|
+
/**
|
|
180
|
+
* Batch check multiple roles (optimized)
|
|
181
|
+
*/
|
|
182
|
+
hasRoles(token: string, roles: string[]): Promise<Record<string, boolean>>;
|
|
183
|
+
/**
|
|
184
|
+
* Clear cache for a specific user
|
|
185
|
+
*/
|
|
186
|
+
clearUserCache(token: string): void;
|
|
187
|
+
/**
|
|
188
|
+
* Get cache statistics
|
|
189
|
+
*/
|
|
190
|
+
getCacheStats(): {
|
|
191
|
+
size: number;
|
|
192
|
+
keys: string[];
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Disconnect from realtime server
|
|
196
|
+
*/
|
|
197
|
+
disconnect(): void;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
declare class ExGuardCache {
|
|
201
|
+
private cache;
|
|
202
|
+
private subscribers;
|
|
203
|
+
private defaultTTL;
|
|
204
|
+
/**
|
|
205
|
+
* Get cached data
|
|
206
|
+
*/
|
|
207
|
+
get<T>(key: string): T | null;
|
|
208
|
+
/**
|
|
209
|
+
* Set cached data with TTL
|
|
210
|
+
*/
|
|
211
|
+
set<T>(key: string, data: T, ttl?: number): void;
|
|
212
|
+
/**
|
|
213
|
+
* Delete cached data
|
|
214
|
+
*/
|
|
215
|
+
delete(key: string): boolean;
|
|
216
|
+
/**
|
|
217
|
+
* Clear all cache
|
|
218
|
+
*/
|
|
219
|
+
clear(): void;
|
|
220
|
+
/**
|
|
221
|
+
* Clear cache for a specific user
|
|
222
|
+
*/
|
|
223
|
+
clearUserCache(userId: string): void;
|
|
224
|
+
/**
|
|
225
|
+
* Subscribe to cache changes
|
|
226
|
+
*/
|
|
227
|
+
subscribe(key: string, callback: () => void): () => void;
|
|
228
|
+
/**
|
|
229
|
+
* Notify subscribers of cache changes
|
|
230
|
+
*/
|
|
231
|
+
private notifySubscribers;
|
|
232
|
+
/**
|
|
233
|
+
* Get cache statistics
|
|
234
|
+
*/
|
|
235
|
+
getStats(): {
|
|
236
|
+
size: number;
|
|
237
|
+
keys: string[];
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Clean up expired entries
|
|
241
|
+
*/
|
|
242
|
+
cleanup(): void;
|
|
243
|
+
}
|
|
244
|
+
declare const cache: ExGuardCache;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Realtime event handling for cache invalidation
|
|
248
|
+
*/
|
|
249
|
+
interface RealtimeEvent {
|
|
250
|
+
type: 'rbac_update' | 'user_update' | 'role_update' | 'permission_update';
|
|
251
|
+
userId?: string;
|
|
252
|
+
data?: any;
|
|
253
|
+
timestamp: number;
|
|
254
|
+
}
|
|
255
|
+
interface RealtimeEventHandler {
|
|
256
|
+
(event: RealtimeEvent): void;
|
|
257
|
+
}
|
|
258
|
+
declare class ExGuardRealtime {
|
|
259
|
+
private handlers;
|
|
260
|
+
private websocket;
|
|
261
|
+
private reconnectAttempts;
|
|
262
|
+
private maxReconnectAttempts;
|
|
263
|
+
private reconnectDelay;
|
|
264
|
+
/**
|
|
265
|
+
* Connect to realtime server
|
|
266
|
+
*/
|
|
267
|
+
connect(url: string, token: string): Promise<void>;
|
|
268
|
+
/**
|
|
269
|
+
* Disconnect from realtime server
|
|
270
|
+
*/
|
|
271
|
+
disconnect(): void;
|
|
272
|
+
/**
|
|
273
|
+
* Subscribe to realtime events
|
|
274
|
+
*/
|
|
275
|
+
subscribe(eventType: string, handler: RealtimeEventHandler): () => void;
|
|
276
|
+
/**
|
|
277
|
+
* Handle incoming realtime events
|
|
278
|
+
*/
|
|
279
|
+
private handleEvent;
|
|
280
|
+
/**
|
|
281
|
+
* Handle reconnection logic
|
|
282
|
+
*/
|
|
283
|
+
private handleReconnect;
|
|
284
|
+
/**
|
|
285
|
+
* Check if connected
|
|
286
|
+
*/
|
|
287
|
+
isConnected(): boolean;
|
|
288
|
+
}
|
|
289
|
+
declare const realtime: ExGuardRealtime;
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Framework-agnostic guards for protecting backend endpoints
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
interface GuardContext {
|
|
296
|
+
token: string;
|
|
297
|
+
request?: any;
|
|
298
|
+
}
|
|
299
|
+
interface GuardResult {
|
|
300
|
+
allowed: boolean;
|
|
301
|
+
user?: UserAccessResponse;
|
|
302
|
+
error?: string;
|
|
303
|
+
statusCode?: number;
|
|
304
|
+
}
|
|
305
|
+
interface GuardOptions {
|
|
306
|
+
permissions?: string[];
|
|
307
|
+
roles?: string[];
|
|
308
|
+
modules?: string[];
|
|
309
|
+
fieldOffices?: string[];
|
|
310
|
+
requireAll?: boolean;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Framework-agnostic guard class for endpoint protection
|
|
314
|
+
*/
|
|
315
|
+
declare class ExGuardBackend {
|
|
316
|
+
private exGuard;
|
|
317
|
+
constructor(config: ExGuardEnhancedConfig$1);
|
|
318
|
+
/**
|
|
319
|
+
* Check if user has specific permissions
|
|
320
|
+
*/
|
|
321
|
+
requirePermissions(context: GuardContext, permissions: string[], options?: {
|
|
322
|
+
requireAll?: boolean;
|
|
323
|
+
}): Promise<GuardResult>;
|
|
324
|
+
/**
|
|
325
|
+
* Check if user has specific roles
|
|
326
|
+
*/
|
|
327
|
+
requireRoles(context: GuardContext, roles: string[], options?: {
|
|
328
|
+
requireAll?: boolean;
|
|
329
|
+
}): Promise<GuardResult>;
|
|
330
|
+
/**
|
|
331
|
+
* Check if user has access to specific modules
|
|
332
|
+
*/
|
|
333
|
+
requireModules(context: GuardContext, modules: string[], options?: {
|
|
334
|
+
requireAll?: boolean;
|
|
335
|
+
}): Promise<GuardResult>;
|
|
336
|
+
/**
|
|
337
|
+
* Check if user has access to specific field offices
|
|
338
|
+
*/
|
|
339
|
+
requireFieldOffices(context: GuardContext, fieldOffices: string[], options?: {
|
|
340
|
+
requireAll?: boolean;
|
|
341
|
+
}): Promise<GuardResult>;
|
|
342
|
+
/**
|
|
343
|
+
* Flexible guard with multiple requirements
|
|
344
|
+
*/
|
|
345
|
+
require(context: GuardContext, options: GuardOptions): Promise<GuardResult>;
|
|
346
|
+
/**
|
|
347
|
+
* Simple authentication (just validates token)
|
|
348
|
+
*/
|
|
349
|
+
authenticate(context: GuardContext): Promise<GuardResult>;
|
|
350
|
+
/**
|
|
351
|
+
* Get the underlying ExGuardBackendEnhanced instance
|
|
352
|
+
*/
|
|
353
|
+
getExGuard(): ExGuardBackendEnhanced;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Express.js middleware for ExGuard endpoint protection
|
|
358
|
+
*/
|
|
359
|
+
|
|
360
|
+
type Request = any;
|
|
361
|
+
type Response = any;
|
|
362
|
+
type NextFunction = any;
|
|
363
|
+
interface AuthenticatedRequest$1 extends Request {
|
|
364
|
+
user?: {
|
|
365
|
+
id: string;
|
|
366
|
+
cognitoSubId: string;
|
|
367
|
+
username: string;
|
|
368
|
+
email: string;
|
|
369
|
+
roles: string[];
|
|
370
|
+
permissions: string[];
|
|
371
|
+
modules: Array<{
|
|
372
|
+
key: string;
|
|
373
|
+
permissions: string[];
|
|
374
|
+
}>;
|
|
375
|
+
fieldOffices: string[];
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Express middleware factory
|
|
380
|
+
*/
|
|
381
|
+
declare function createExGuardExpress(config: any): {
|
|
382
|
+
/**
|
|
383
|
+
* Require specific permissions
|
|
384
|
+
*/
|
|
385
|
+
requirePermissions(permissions: string[], options?: {
|
|
386
|
+
requireAll?: boolean;
|
|
387
|
+
}): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
388
|
+
/**
|
|
389
|
+
* Require specific roles
|
|
390
|
+
*/
|
|
391
|
+
requireRoles(roles: string[], options?: {
|
|
392
|
+
requireAll?: boolean;
|
|
393
|
+
}): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
394
|
+
/**
|
|
395
|
+
* Require module access
|
|
396
|
+
*/
|
|
397
|
+
requireModules(modules: string[], options?: {
|
|
398
|
+
requireAll?: boolean;
|
|
399
|
+
}): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
400
|
+
/**
|
|
401
|
+
* Require field office access
|
|
402
|
+
*/
|
|
403
|
+
requireFieldOffices(fieldOffices: string[], options?: {
|
|
404
|
+
requireAll?: boolean;
|
|
405
|
+
}): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
406
|
+
/**
|
|
407
|
+
* Flexible guard with multiple requirements
|
|
408
|
+
*/
|
|
409
|
+
require(options: GuardOptions): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
410
|
+
/**
|
|
411
|
+
* Simple authentication middleware
|
|
412
|
+
*/
|
|
413
|
+
authenticate(): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
414
|
+
/**
|
|
415
|
+
* Get the underlying guard instance
|
|
416
|
+
*/
|
|
417
|
+
getGuard(): ExGuardBackend;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Fastify plugin for ExGuard endpoint protection
|
|
422
|
+
*/
|
|
423
|
+
|
|
424
|
+
type FastifyRequest = any;
|
|
425
|
+
type FastifyReply = any;
|
|
426
|
+
interface AuthenticatedRequest extends FastifyRequest {
|
|
427
|
+
user?: {
|
|
428
|
+
id: string;
|
|
429
|
+
cognitoSubId: string;
|
|
430
|
+
username: string;
|
|
431
|
+
email: string;
|
|
432
|
+
roles: string[];
|
|
433
|
+
permissions: string[];
|
|
434
|
+
modules: Array<{
|
|
435
|
+
key: string;
|
|
436
|
+
permissions: string[];
|
|
437
|
+
}>;
|
|
438
|
+
fieldOffices: string[];
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Fastify plugin factory
|
|
443
|
+
*/
|
|
444
|
+
declare function createExGuardFastify(config: any): {
|
|
445
|
+
/**
|
|
446
|
+
* Require specific permissions
|
|
447
|
+
*/
|
|
448
|
+
requirePermissions(permissions: string[], options?: {
|
|
449
|
+
requireAll?: boolean;
|
|
450
|
+
}): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
451
|
+
/**
|
|
452
|
+
* Require specific roles
|
|
453
|
+
*/
|
|
454
|
+
requireRoles(roles: string[], options?: {
|
|
455
|
+
requireAll?: boolean;
|
|
456
|
+
}): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
457
|
+
/**
|
|
458
|
+
* Require module access
|
|
459
|
+
*/
|
|
460
|
+
requireModules(modules: string[], options?: {
|
|
461
|
+
requireAll?: boolean;
|
|
462
|
+
}): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
463
|
+
/**
|
|
464
|
+
* Require field office access
|
|
465
|
+
*/
|
|
466
|
+
requireFieldOffices(fieldOffices: string[], options?: {
|
|
467
|
+
requireAll?: boolean;
|
|
468
|
+
}): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
469
|
+
/**
|
|
470
|
+
* Flexible guard with multiple requirements
|
|
471
|
+
*/
|
|
472
|
+
require(options: GuardOptions): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
473
|
+
/**
|
|
474
|
+
* Simple authentication hook
|
|
475
|
+
*/
|
|
476
|
+
authenticate(): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
477
|
+
/**
|
|
478
|
+
* Get the underlying guard instance
|
|
479
|
+
*/
|
|
480
|
+
getGuard(): ExGuardBackend;
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
export { type ApiResponse, ExGuardBackend$1 as ExGuardBackend, ExGuardBackendEnhanced, ExGuardCache, type ExGuardCacheConfig, type ExGuardConfig, type ExGuardEnhancedConfig$1 as ExGuardEnhancedConfig, ExGuardRealtime, type ExGuardRealtimeConfig, ExGuardBackend as Guard, type GuardContext$1 as GuardContext, type GuardOptions$1 as GuardOptions, type GuardResult$1 as GuardResult, type UserAccessResponse, cache, createExGuardExpress, createExGuardFastify, realtime };
|
package/dist/index.d.ts
CHANGED
|
@@ -38,8 +38,38 @@ interface ExGuardConfig {
|
|
|
38
38
|
apiUrl: string;
|
|
39
39
|
timeout?: number;
|
|
40
40
|
}
|
|
41
|
+
interface ExGuardCacheConfig {
|
|
42
|
+
ttl?: number;
|
|
43
|
+
enabled?: boolean;
|
|
44
|
+
}
|
|
45
|
+
interface ExGuardRealtimeConfig {
|
|
46
|
+
enabled?: boolean;
|
|
47
|
+
url?: string;
|
|
48
|
+
token?: string;
|
|
49
|
+
}
|
|
50
|
+
interface ExGuardEnhancedConfig$1 extends ExGuardConfig {
|
|
51
|
+
cache?: ExGuardCacheConfig;
|
|
52
|
+
realtime?: ExGuardRealtimeConfig;
|
|
53
|
+
}
|
|
54
|
+
interface GuardContext$1 {
|
|
55
|
+
token: string;
|
|
56
|
+
request?: any;
|
|
57
|
+
}
|
|
58
|
+
interface GuardResult$1 {
|
|
59
|
+
allowed: boolean;
|
|
60
|
+
user?: UserAccessResponse;
|
|
61
|
+
error?: string;
|
|
62
|
+
statusCode?: number;
|
|
63
|
+
}
|
|
64
|
+
interface GuardOptions$1 {
|
|
65
|
+
permissions?: string[];
|
|
66
|
+
roles?: string[];
|
|
67
|
+
modules?: string[];
|
|
68
|
+
fieldOffices?: string[];
|
|
69
|
+
requireAll?: boolean;
|
|
70
|
+
}
|
|
41
71
|
|
|
42
|
-
declare class ExGuardBackend {
|
|
72
|
+
declare class ExGuardBackend$1 {
|
|
43
73
|
private client;
|
|
44
74
|
private config;
|
|
45
75
|
constructor(config: ExGuardConfig);
|
|
@@ -84,4 +114,370 @@ declare class ExGuardBackend {
|
|
|
84
114
|
getUserFieldOffices(token: string): Promise<string[]>;
|
|
85
115
|
}
|
|
86
116
|
|
|
87
|
-
|
|
117
|
+
interface ExGuardEnhancedConfig extends ExGuardConfig {
|
|
118
|
+
cache?: {
|
|
119
|
+
ttl?: number;
|
|
120
|
+
enabled?: boolean;
|
|
121
|
+
};
|
|
122
|
+
realtime?: {
|
|
123
|
+
enabled?: boolean;
|
|
124
|
+
url?: string;
|
|
125
|
+
token?: string;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
declare class ExGuardBackendEnhanced {
|
|
129
|
+
private client;
|
|
130
|
+
private config;
|
|
131
|
+
private cache;
|
|
132
|
+
private realtime;
|
|
133
|
+
private userId;
|
|
134
|
+
constructor(config: ExGuardEnhancedConfig);
|
|
135
|
+
/**
|
|
136
|
+
* Setup realtime connection and event handlers
|
|
137
|
+
*/
|
|
138
|
+
private setupRealtime;
|
|
139
|
+
/**
|
|
140
|
+
* Extract user ID from JWT token
|
|
141
|
+
*/
|
|
142
|
+
private extractUserIdFromToken;
|
|
143
|
+
/**
|
|
144
|
+
* Get cache key for user data
|
|
145
|
+
*/
|
|
146
|
+
private getCacheKey;
|
|
147
|
+
/**
|
|
148
|
+
* Get user roles and permissions from cache or API
|
|
149
|
+
*/
|
|
150
|
+
getUserAccess(token: string): Promise<UserAccessResponse>;
|
|
151
|
+
/**
|
|
152
|
+
* Fetch user access from API (always hits the server)
|
|
153
|
+
*/
|
|
154
|
+
private fetchUserAccess;
|
|
155
|
+
/**
|
|
156
|
+
* Check if user has specific permission (cached)
|
|
157
|
+
*/
|
|
158
|
+
hasPermission(token: string, permission: string): Promise<boolean>;
|
|
159
|
+
/**
|
|
160
|
+
* Check if user has specific role (cached)
|
|
161
|
+
*/
|
|
162
|
+
hasRole(token: string, role: string): Promise<boolean>;
|
|
163
|
+
/**
|
|
164
|
+
* Get all permissions for a specific module (cached)
|
|
165
|
+
*/
|
|
166
|
+
getModulePermissions(token: string, moduleKey: string): Promise<string[]>;
|
|
167
|
+
/**
|
|
168
|
+
* Get user roles (cached)
|
|
169
|
+
*/
|
|
170
|
+
getUserRoles(token: string): Promise<string[]>;
|
|
171
|
+
/**
|
|
172
|
+
* Get user field offices (cached)
|
|
173
|
+
*/
|
|
174
|
+
getUserFieldOffices(token: string): Promise<string[]>;
|
|
175
|
+
/**
|
|
176
|
+
* Batch check multiple permissions (optimized)
|
|
177
|
+
*/
|
|
178
|
+
hasPermissions(token: string, permissions: string[]): Promise<Record<string, boolean>>;
|
|
179
|
+
/**
|
|
180
|
+
* Batch check multiple roles (optimized)
|
|
181
|
+
*/
|
|
182
|
+
hasRoles(token: string, roles: string[]): Promise<Record<string, boolean>>;
|
|
183
|
+
/**
|
|
184
|
+
* Clear cache for a specific user
|
|
185
|
+
*/
|
|
186
|
+
clearUserCache(token: string): void;
|
|
187
|
+
/**
|
|
188
|
+
* Get cache statistics
|
|
189
|
+
*/
|
|
190
|
+
getCacheStats(): {
|
|
191
|
+
size: number;
|
|
192
|
+
keys: string[];
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Disconnect from realtime server
|
|
196
|
+
*/
|
|
197
|
+
disconnect(): void;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
declare class ExGuardCache {
|
|
201
|
+
private cache;
|
|
202
|
+
private subscribers;
|
|
203
|
+
private defaultTTL;
|
|
204
|
+
/**
|
|
205
|
+
* Get cached data
|
|
206
|
+
*/
|
|
207
|
+
get<T>(key: string): T | null;
|
|
208
|
+
/**
|
|
209
|
+
* Set cached data with TTL
|
|
210
|
+
*/
|
|
211
|
+
set<T>(key: string, data: T, ttl?: number): void;
|
|
212
|
+
/**
|
|
213
|
+
* Delete cached data
|
|
214
|
+
*/
|
|
215
|
+
delete(key: string): boolean;
|
|
216
|
+
/**
|
|
217
|
+
* Clear all cache
|
|
218
|
+
*/
|
|
219
|
+
clear(): void;
|
|
220
|
+
/**
|
|
221
|
+
* Clear cache for a specific user
|
|
222
|
+
*/
|
|
223
|
+
clearUserCache(userId: string): void;
|
|
224
|
+
/**
|
|
225
|
+
* Subscribe to cache changes
|
|
226
|
+
*/
|
|
227
|
+
subscribe(key: string, callback: () => void): () => void;
|
|
228
|
+
/**
|
|
229
|
+
* Notify subscribers of cache changes
|
|
230
|
+
*/
|
|
231
|
+
private notifySubscribers;
|
|
232
|
+
/**
|
|
233
|
+
* Get cache statistics
|
|
234
|
+
*/
|
|
235
|
+
getStats(): {
|
|
236
|
+
size: number;
|
|
237
|
+
keys: string[];
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Clean up expired entries
|
|
241
|
+
*/
|
|
242
|
+
cleanup(): void;
|
|
243
|
+
}
|
|
244
|
+
declare const cache: ExGuardCache;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Realtime event handling for cache invalidation
|
|
248
|
+
*/
|
|
249
|
+
interface RealtimeEvent {
|
|
250
|
+
type: 'rbac_update' | 'user_update' | 'role_update' | 'permission_update';
|
|
251
|
+
userId?: string;
|
|
252
|
+
data?: any;
|
|
253
|
+
timestamp: number;
|
|
254
|
+
}
|
|
255
|
+
interface RealtimeEventHandler {
|
|
256
|
+
(event: RealtimeEvent): void;
|
|
257
|
+
}
|
|
258
|
+
declare class ExGuardRealtime {
|
|
259
|
+
private handlers;
|
|
260
|
+
private websocket;
|
|
261
|
+
private reconnectAttempts;
|
|
262
|
+
private maxReconnectAttempts;
|
|
263
|
+
private reconnectDelay;
|
|
264
|
+
/**
|
|
265
|
+
* Connect to realtime server
|
|
266
|
+
*/
|
|
267
|
+
connect(url: string, token: string): Promise<void>;
|
|
268
|
+
/**
|
|
269
|
+
* Disconnect from realtime server
|
|
270
|
+
*/
|
|
271
|
+
disconnect(): void;
|
|
272
|
+
/**
|
|
273
|
+
* Subscribe to realtime events
|
|
274
|
+
*/
|
|
275
|
+
subscribe(eventType: string, handler: RealtimeEventHandler): () => void;
|
|
276
|
+
/**
|
|
277
|
+
* Handle incoming realtime events
|
|
278
|
+
*/
|
|
279
|
+
private handleEvent;
|
|
280
|
+
/**
|
|
281
|
+
* Handle reconnection logic
|
|
282
|
+
*/
|
|
283
|
+
private handleReconnect;
|
|
284
|
+
/**
|
|
285
|
+
* Check if connected
|
|
286
|
+
*/
|
|
287
|
+
isConnected(): boolean;
|
|
288
|
+
}
|
|
289
|
+
declare const realtime: ExGuardRealtime;
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Framework-agnostic guards for protecting backend endpoints
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
interface GuardContext {
|
|
296
|
+
token: string;
|
|
297
|
+
request?: any;
|
|
298
|
+
}
|
|
299
|
+
interface GuardResult {
|
|
300
|
+
allowed: boolean;
|
|
301
|
+
user?: UserAccessResponse;
|
|
302
|
+
error?: string;
|
|
303
|
+
statusCode?: number;
|
|
304
|
+
}
|
|
305
|
+
interface GuardOptions {
|
|
306
|
+
permissions?: string[];
|
|
307
|
+
roles?: string[];
|
|
308
|
+
modules?: string[];
|
|
309
|
+
fieldOffices?: string[];
|
|
310
|
+
requireAll?: boolean;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Framework-agnostic guard class for endpoint protection
|
|
314
|
+
*/
|
|
315
|
+
declare class ExGuardBackend {
|
|
316
|
+
private exGuard;
|
|
317
|
+
constructor(config: ExGuardEnhancedConfig$1);
|
|
318
|
+
/**
|
|
319
|
+
* Check if user has specific permissions
|
|
320
|
+
*/
|
|
321
|
+
requirePermissions(context: GuardContext, permissions: string[], options?: {
|
|
322
|
+
requireAll?: boolean;
|
|
323
|
+
}): Promise<GuardResult>;
|
|
324
|
+
/**
|
|
325
|
+
* Check if user has specific roles
|
|
326
|
+
*/
|
|
327
|
+
requireRoles(context: GuardContext, roles: string[], options?: {
|
|
328
|
+
requireAll?: boolean;
|
|
329
|
+
}): Promise<GuardResult>;
|
|
330
|
+
/**
|
|
331
|
+
* Check if user has access to specific modules
|
|
332
|
+
*/
|
|
333
|
+
requireModules(context: GuardContext, modules: string[], options?: {
|
|
334
|
+
requireAll?: boolean;
|
|
335
|
+
}): Promise<GuardResult>;
|
|
336
|
+
/**
|
|
337
|
+
* Check if user has access to specific field offices
|
|
338
|
+
*/
|
|
339
|
+
requireFieldOffices(context: GuardContext, fieldOffices: string[], options?: {
|
|
340
|
+
requireAll?: boolean;
|
|
341
|
+
}): Promise<GuardResult>;
|
|
342
|
+
/**
|
|
343
|
+
* Flexible guard with multiple requirements
|
|
344
|
+
*/
|
|
345
|
+
require(context: GuardContext, options: GuardOptions): Promise<GuardResult>;
|
|
346
|
+
/**
|
|
347
|
+
* Simple authentication (just validates token)
|
|
348
|
+
*/
|
|
349
|
+
authenticate(context: GuardContext): Promise<GuardResult>;
|
|
350
|
+
/**
|
|
351
|
+
* Get the underlying ExGuardBackendEnhanced instance
|
|
352
|
+
*/
|
|
353
|
+
getExGuard(): ExGuardBackendEnhanced;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Express.js middleware for ExGuard endpoint protection
|
|
358
|
+
*/
|
|
359
|
+
|
|
360
|
+
type Request = any;
|
|
361
|
+
type Response = any;
|
|
362
|
+
type NextFunction = any;
|
|
363
|
+
interface AuthenticatedRequest$1 extends Request {
|
|
364
|
+
user?: {
|
|
365
|
+
id: string;
|
|
366
|
+
cognitoSubId: string;
|
|
367
|
+
username: string;
|
|
368
|
+
email: string;
|
|
369
|
+
roles: string[];
|
|
370
|
+
permissions: string[];
|
|
371
|
+
modules: Array<{
|
|
372
|
+
key: string;
|
|
373
|
+
permissions: string[];
|
|
374
|
+
}>;
|
|
375
|
+
fieldOffices: string[];
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Express middleware factory
|
|
380
|
+
*/
|
|
381
|
+
declare function createExGuardExpress(config: any): {
|
|
382
|
+
/**
|
|
383
|
+
* Require specific permissions
|
|
384
|
+
*/
|
|
385
|
+
requirePermissions(permissions: string[], options?: {
|
|
386
|
+
requireAll?: boolean;
|
|
387
|
+
}): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
388
|
+
/**
|
|
389
|
+
* Require specific roles
|
|
390
|
+
*/
|
|
391
|
+
requireRoles(roles: string[], options?: {
|
|
392
|
+
requireAll?: boolean;
|
|
393
|
+
}): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
394
|
+
/**
|
|
395
|
+
* Require module access
|
|
396
|
+
*/
|
|
397
|
+
requireModules(modules: string[], options?: {
|
|
398
|
+
requireAll?: boolean;
|
|
399
|
+
}): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
400
|
+
/**
|
|
401
|
+
* Require field office access
|
|
402
|
+
*/
|
|
403
|
+
requireFieldOffices(fieldOffices: string[], options?: {
|
|
404
|
+
requireAll?: boolean;
|
|
405
|
+
}): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
406
|
+
/**
|
|
407
|
+
* Flexible guard with multiple requirements
|
|
408
|
+
*/
|
|
409
|
+
require(options: GuardOptions): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
410
|
+
/**
|
|
411
|
+
* Simple authentication middleware
|
|
412
|
+
*/
|
|
413
|
+
authenticate(): (req: AuthenticatedRequest$1, res: Response, next: NextFunction) => Promise<any>;
|
|
414
|
+
/**
|
|
415
|
+
* Get the underlying guard instance
|
|
416
|
+
*/
|
|
417
|
+
getGuard(): ExGuardBackend;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Fastify plugin for ExGuard endpoint protection
|
|
422
|
+
*/
|
|
423
|
+
|
|
424
|
+
type FastifyRequest = any;
|
|
425
|
+
type FastifyReply = any;
|
|
426
|
+
interface AuthenticatedRequest extends FastifyRequest {
|
|
427
|
+
user?: {
|
|
428
|
+
id: string;
|
|
429
|
+
cognitoSubId: string;
|
|
430
|
+
username: string;
|
|
431
|
+
email: string;
|
|
432
|
+
roles: string[];
|
|
433
|
+
permissions: string[];
|
|
434
|
+
modules: Array<{
|
|
435
|
+
key: string;
|
|
436
|
+
permissions: string[];
|
|
437
|
+
}>;
|
|
438
|
+
fieldOffices: string[];
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Fastify plugin factory
|
|
443
|
+
*/
|
|
444
|
+
declare function createExGuardFastify(config: any): {
|
|
445
|
+
/**
|
|
446
|
+
* Require specific permissions
|
|
447
|
+
*/
|
|
448
|
+
requirePermissions(permissions: string[], options?: {
|
|
449
|
+
requireAll?: boolean;
|
|
450
|
+
}): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
451
|
+
/**
|
|
452
|
+
* Require specific roles
|
|
453
|
+
*/
|
|
454
|
+
requireRoles(roles: string[], options?: {
|
|
455
|
+
requireAll?: boolean;
|
|
456
|
+
}): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
457
|
+
/**
|
|
458
|
+
* Require module access
|
|
459
|
+
*/
|
|
460
|
+
requireModules(modules: string[], options?: {
|
|
461
|
+
requireAll?: boolean;
|
|
462
|
+
}): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
463
|
+
/**
|
|
464
|
+
* Require field office access
|
|
465
|
+
*/
|
|
466
|
+
requireFieldOffices(fieldOffices: string[], options?: {
|
|
467
|
+
requireAll?: boolean;
|
|
468
|
+
}): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
469
|
+
/**
|
|
470
|
+
* Flexible guard with multiple requirements
|
|
471
|
+
*/
|
|
472
|
+
require(options: GuardOptions): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
473
|
+
/**
|
|
474
|
+
* Simple authentication hook
|
|
475
|
+
*/
|
|
476
|
+
authenticate(): (req: AuthenticatedRequest, reply: FastifyReply) => Promise<any>;
|
|
477
|
+
/**
|
|
478
|
+
* Get the underlying guard instance
|
|
479
|
+
*/
|
|
480
|
+
getGuard(): ExGuardBackend;
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
export { type ApiResponse, ExGuardBackend$1 as ExGuardBackend, ExGuardBackendEnhanced, ExGuardCache, type ExGuardCacheConfig, type ExGuardConfig, type ExGuardEnhancedConfig$1 as ExGuardEnhancedConfig, ExGuardRealtime, type ExGuardRealtimeConfig, ExGuardBackend as Guard, type GuardContext$1 as GuardContext, type GuardOptions$1 as GuardOptions, type GuardResult$1 as GuardResult, type UserAccessResponse, cache, createExGuardExpress, createExGuardFastify, realtime };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exguard-backend",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -21,12 +21,6 @@
|
|
|
21
21
|
"dist",
|
|
22
22
|
"README.md"
|
|
23
23
|
],
|
|
24
|
-
"scripts": {
|
|
25
|
-
"build": "tsup",
|
|
26
|
-
"dev": "tsup --watch",
|
|
27
|
-
"type-check": "tsc --noEmit",
|
|
28
|
-
"prepublishOnly": "pnpm build"
|
|
29
|
-
},
|
|
30
24
|
"keywords": [
|
|
31
25
|
"exguard",
|
|
32
26
|
"rbac",
|
|
@@ -44,5 +38,14 @@
|
|
|
44
38
|
"@types/node": "^22.10.5",
|
|
45
39
|
"tsup": "^8.3.5",
|
|
46
40
|
"typescript": "^5.7.3"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup",
|
|
44
|
+
"dev": "tsup --watch",
|
|
45
|
+
"type-check": "tsc --noEmit",
|
|
46
|
+
"test": "node --test",
|
|
47
|
+
"test:watch": "node --test --watch",
|
|
48
|
+
"clean": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\"",
|
|
49
|
+
"prebuild": "npm run clean"
|
|
47
50
|
}
|
|
48
|
-
}
|
|
51
|
+
}
|
package/dist/index.cjs
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
ExGuardBackend: () => ExGuardBackend
|
|
34
|
-
});
|
|
35
|
-
module.exports = __toCommonJS(index_exports);
|
|
36
|
-
|
|
37
|
-
// src/exguard-backend.ts
|
|
38
|
-
var import_axios = __toESM(require("axios"), 1);
|
|
39
|
-
var ExGuardBackend = class {
|
|
40
|
-
constructor(config) {
|
|
41
|
-
this.config = {
|
|
42
|
-
timeout: 1e4,
|
|
43
|
-
...config
|
|
44
|
-
};
|
|
45
|
-
this.client = import_axios.default.create({
|
|
46
|
-
baseURL: this.config.apiUrl,
|
|
47
|
-
timeout: this.config.timeout,
|
|
48
|
-
headers: {
|
|
49
|
-
"Content-Type": "application/json"
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Get user roles and permissions from the /guard/me endpoint
|
|
55
|
-
* @param token - JWT access token
|
|
56
|
-
* @returns Promise<UserAccessResponse>
|
|
57
|
-
*/
|
|
58
|
-
async getUserAccess(token) {
|
|
59
|
-
try {
|
|
60
|
-
const response = await this.client.get("/guard/me", {
|
|
61
|
-
headers: {
|
|
62
|
-
"Authorization": `Bearer ${token}`
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
if (!response.data.success) {
|
|
66
|
-
throw new Error("Failed to fetch user access information");
|
|
67
|
-
}
|
|
68
|
-
return response.data.data;
|
|
69
|
-
} catch (error) {
|
|
70
|
-
if (import_axios.default.isAxiosError(error)) {
|
|
71
|
-
if (error.response?.status === 401) {
|
|
72
|
-
throw new Error("Unauthorized: Invalid or expired token");
|
|
73
|
-
}
|
|
74
|
-
throw new Error(`API Error: ${error.response?.data?.message || error.message}`);
|
|
75
|
-
}
|
|
76
|
-
throw error;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Check if user has specific permission
|
|
81
|
-
* @param token - JWT access token
|
|
82
|
-
* @param permission - Permission to check (e.g., 'events:create')
|
|
83
|
-
* @returns Promise<boolean>
|
|
84
|
-
*/
|
|
85
|
-
async hasPermission(token, permission) {
|
|
86
|
-
try {
|
|
87
|
-
const userAccess = await this.getUserAccess(token);
|
|
88
|
-
return userAccess.modules.some(
|
|
89
|
-
(module2) => module2.permissions.includes(permission)
|
|
90
|
-
);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Check if user has specific role
|
|
97
|
-
* @param token - JWT access token
|
|
98
|
-
* @param role - Role to check (e.g., 'Event Manager')
|
|
99
|
-
* @returns Promise<boolean>
|
|
100
|
-
*/
|
|
101
|
-
async hasRole(token, role) {
|
|
102
|
-
try {
|
|
103
|
-
const userAccess = await this.getUserAccess(token);
|
|
104
|
-
return userAccess.roles.includes(role);
|
|
105
|
-
} catch (error) {
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Get all permissions for a specific module
|
|
111
|
-
* @param token - JWT access token
|
|
112
|
-
* @param moduleKey - Module key (e.g., 'events')
|
|
113
|
-
* @returns Promise<string[]>
|
|
114
|
-
*/
|
|
115
|
-
async getModulePermissions(token, moduleKey) {
|
|
116
|
-
try {
|
|
117
|
-
const userAccess = await this.getUserAccess(token);
|
|
118
|
-
const module2 = userAccess.modules.find((m) => m.key === moduleKey);
|
|
119
|
-
return module2?.permissions || [];
|
|
120
|
-
} catch (error) {
|
|
121
|
-
return [];
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Get user roles
|
|
126
|
-
* @param token - JWT access token
|
|
127
|
-
* @returns Promise<string[]>
|
|
128
|
-
*/
|
|
129
|
-
async getUserRoles(token) {
|
|
130
|
-
try {
|
|
131
|
-
const userAccess = await this.getUserAccess(token);
|
|
132
|
-
return userAccess.roles;
|
|
133
|
-
} catch (error) {
|
|
134
|
-
return [];
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Get user field offices
|
|
139
|
-
* @param token - JWT access token
|
|
140
|
-
* @returns Promise<string[]>
|
|
141
|
-
*/
|
|
142
|
-
async getUserFieldOffices(token) {
|
|
143
|
-
try {
|
|
144
|
-
const userAccess = await this.getUserAccess(token);
|
|
145
|
-
return userAccess.fieldOffices;
|
|
146
|
-
} catch (error) {
|
|
147
|
-
return [];
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
152
|
-
0 && (module.exports = {
|
|
153
|
-
ExGuardBackend
|
|
154
|
-
});
|
package/dist/index.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
// src/exguard-backend.ts
|
|
2
|
-
import axios from "axios";
|
|
3
|
-
var ExGuardBackend = class {
|
|
4
|
-
constructor(config) {
|
|
5
|
-
this.config = {
|
|
6
|
-
timeout: 1e4,
|
|
7
|
-
...config
|
|
8
|
-
};
|
|
9
|
-
this.client = axios.create({
|
|
10
|
-
baseURL: this.config.apiUrl,
|
|
11
|
-
timeout: this.config.timeout,
|
|
12
|
-
headers: {
|
|
13
|
-
"Content-Type": "application/json"
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Get user roles and permissions from the /guard/me endpoint
|
|
19
|
-
* @param token - JWT access token
|
|
20
|
-
* @returns Promise<UserAccessResponse>
|
|
21
|
-
*/
|
|
22
|
-
async getUserAccess(token) {
|
|
23
|
-
try {
|
|
24
|
-
const response = await this.client.get("/guard/me", {
|
|
25
|
-
headers: {
|
|
26
|
-
"Authorization": `Bearer ${token}`
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
if (!response.data.success) {
|
|
30
|
-
throw new Error("Failed to fetch user access information");
|
|
31
|
-
}
|
|
32
|
-
return response.data.data;
|
|
33
|
-
} catch (error) {
|
|
34
|
-
if (axios.isAxiosError(error)) {
|
|
35
|
-
if (error.response?.status === 401) {
|
|
36
|
-
throw new Error("Unauthorized: Invalid or expired token");
|
|
37
|
-
}
|
|
38
|
-
throw new Error(`API Error: ${error.response?.data?.message || error.message}`);
|
|
39
|
-
}
|
|
40
|
-
throw error;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Check if user has specific permission
|
|
45
|
-
* @param token - JWT access token
|
|
46
|
-
* @param permission - Permission to check (e.g., 'events:create')
|
|
47
|
-
* @returns Promise<boolean>
|
|
48
|
-
*/
|
|
49
|
-
async hasPermission(token, permission) {
|
|
50
|
-
try {
|
|
51
|
-
const userAccess = await this.getUserAccess(token);
|
|
52
|
-
return userAccess.modules.some(
|
|
53
|
-
(module) => module.permissions.includes(permission)
|
|
54
|
-
);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Check if user has specific role
|
|
61
|
-
* @param token - JWT access token
|
|
62
|
-
* @param role - Role to check (e.g., 'Event Manager')
|
|
63
|
-
* @returns Promise<boolean>
|
|
64
|
-
*/
|
|
65
|
-
async hasRole(token, role) {
|
|
66
|
-
try {
|
|
67
|
-
const userAccess = await this.getUserAccess(token);
|
|
68
|
-
return userAccess.roles.includes(role);
|
|
69
|
-
} catch (error) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Get all permissions for a specific module
|
|
75
|
-
* @param token - JWT access token
|
|
76
|
-
* @param moduleKey - Module key (e.g., 'events')
|
|
77
|
-
* @returns Promise<string[]>
|
|
78
|
-
*/
|
|
79
|
-
async getModulePermissions(token, moduleKey) {
|
|
80
|
-
try {
|
|
81
|
-
const userAccess = await this.getUserAccess(token);
|
|
82
|
-
const module = userAccess.modules.find((m) => m.key === moduleKey);
|
|
83
|
-
return module?.permissions || [];
|
|
84
|
-
} catch (error) {
|
|
85
|
-
return [];
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Get user roles
|
|
90
|
-
* @param token - JWT access token
|
|
91
|
-
* @returns Promise<string[]>
|
|
92
|
-
*/
|
|
93
|
-
async getUserRoles(token) {
|
|
94
|
-
try {
|
|
95
|
-
const userAccess = await this.getUserAccess(token);
|
|
96
|
-
return userAccess.roles;
|
|
97
|
-
} catch (error) {
|
|
98
|
-
return [];
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Get user field offices
|
|
103
|
-
* @param token - JWT access token
|
|
104
|
-
* @returns Promise<string[]>
|
|
105
|
-
*/
|
|
106
|
-
async getUserFieldOffices(token) {
|
|
107
|
-
try {
|
|
108
|
-
const userAccess = await this.getUserAccess(token);
|
|
109
|
-
return userAccess.fieldOffices;
|
|
110
|
-
} catch (error) {
|
|
111
|
-
return [];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
export {
|
|
116
|
-
ExGuardBackend
|
|
117
|
-
};
|