exguard-backend 1.0.6 → 1.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exguard-backend",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -0,0 +1,535 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Automatic ExGuard Module Setup for NestJS
5
+ *
6
+ * Usage:
7
+ * npx exguard-backend
8
+ * npx exguard-backend setup-nestjs
9
+ * OR
10
+ * node node_modules/exguard-backend/scripts/setup-nestjs.js
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const { execSync } = require('child_process');
16
+
17
+ // ANSI colors for better output
18
+ const colors = {
19
+ reset: '\x1b[0m',
20
+ bright: '\x1b[1m',
21
+ red: '\x1b[31m',
22
+ green: '\x1b[32m',
23
+ yellow: '\x1b[33m',
24
+ blue: '\x1b[34m',
25
+ magenta: '\x1b[35m',
26
+ cyan: '\x1b[36m'
27
+ };
28
+
29
+ function log(message, color = 'reset') {
30
+ console.log(`${colors[color]}${message}${colors.reset}`);
31
+ }
32
+
33
+ function logStep(step, message) {
34
+ log(`\nšŸ”§ Step ${step}: ${message}`, 'cyan');
35
+ }
36
+
37
+ function logSuccess(message) {
38
+ log(`āœ… ${message}`, 'green');
39
+ }
40
+
41
+ function logWarning(message) {
42
+ log(`āš ļø ${message}`, 'yellow');
43
+ }
44
+
45
+ function logError(message) {
46
+ log(`āŒ ${message}`, 'red');
47
+ }
48
+
49
+ function logInfo(message) {
50
+ log(`ā„¹ļø ${message}`, 'blue');
51
+ }
52
+
53
+ // Check if we're in a NestJS project
54
+ function checkNestJSProject() {
55
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
56
+
57
+ if (!fs.existsSync(packageJsonPath)) {
58
+ logError('package.json not found. Please run this command in a NestJS project root.');
59
+ process.exit(1);
60
+ }
61
+
62
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
63
+ const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
64
+
65
+ const nestPackages = Object.keys(dependencies).filter(dep =>
66
+ dep.startsWith('@nestjs/') || dep === 'nestjs'
67
+ );
68
+
69
+ if (nestPackages.length === 0) {
70
+ logError('No NestJS packages found. Please run this command in a NestJS project.');
71
+ process.exit(1);
72
+ }
73
+
74
+ logSuccess(`NestJS project detected with packages: ${nestPackages.join(', ')}`);
75
+ return true;
76
+ }
77
+
78
+ // Create exguard directory structure
79
+ function createDirectoryStructure() {
80
+ logStep(1, 'Creating ExGuard directory structure');
81
+
82
+ const directories = [
83
+ 'src/exguard',
84
+ 'src/exguard/guards',
85
+ 'src/exguard/decorators',
86
+ 'src/exguard/interceptors'
87
+ ];
88
+
89
+ directories.forEach(dir => {
90
+ const fullPath = path.join(process.cwd(), dir);
91
+ if (!fs.existsSync(fullPath)) {
92
+ fs.mkdirSync(fullPath, { recursive: true });
93
+ logSuccess(`Created directory: ${dir}`);
94
+ } else {
95
+ logWarning(`Directory already exists: ${dir}`);
96
+ }
97
+ });
98
+ }
99
+
100
+ // Create ExGuard Module
101
+ function createExGuardModule() {
102
+ logStep(2, 'Creating ExGuard Module');
103
+
104
+ const moduleContent = `import { Module, Global } from '@nestjs/common';
105
+ import { Guard } from 'exguard-backend';
106
+
107
+ @Global()
108
+ @Module({
109
+ providers: [
110
+ {
111
+ provide: Guard,
112
+ useFactory: () => new Guard({
113
+ apiUrl: process.env.EXGUARD_API_URL || 'http://localhost:3000',
114
+ cache: {
115
+ enabled: process.env.EXGUARD_CACHE_ENABLED !== 'false',
116
+ ttl: parseInt(process.env.EXGUARD_CACHE_TTL) || 300000, // 5 minutes
117
+ },
118
+ realtime: {
119
+ enabled: process.env.EXGUARD_REALTIME_ENABLED === 'true',
120
+ url: process.env.EXGUARD_REALTIME_URL,
121
+ token: process.env.EXGUARD_SERVICE_TOKEN,
122
+ },
123
+ }),
124
+ },
125
+ ],
126
+ exports: [Guard],
127
+ })
128
+ export class ExGuardModule {}
129
+ `;
130
+
131
+ const modulePath = path.join(process.cwd(), 'src/exguard/exguard.module.ts');
132
+
133
+ if (fs.existsSync(modulePath)) {
134
+ logWarning('ExGuardModule already exists. Skipping creation.');
135
+ return;
136
+ }
137
+
138
+ fs.writeFileSync(modulePath, moduleContent);
139
+ logSuccess('Created ExGuardModule');
140
+ }
141
+
142
+ // Create ExGuard Guards
143
+ function createExGuardGuards() {
144
+ logStep(3, 'Creating ExGuard Guards');
145
+
146
+ const guardContent = `import { Injectable, CanActivate, ExecutionContext, ForbiddenException, UnauthorizedException } from '@nestjs/common';
147
+ import { Guard, GuardContext } from 'exguard-backend';
148
+
149
+ @Injectable()
150
+ export class ExGuardNestGuard implements CanActivate {
151
+ constructor(protected exGuard: Guard) {}
152
+
153
+ async canActivate(context: ExecutionContext): Promise<boolean> {
154
+ const request = context.switchToHttp().getRequest();
155
+ const token = this.extractToken(request);
156
+
157
+ if (!token) {
158
+ throw new UnauthorizedException('No authentication token provided');
159
+ }
160
+
161
+ const guardContext: GuardContext = {
162
+ token,
163
+ request,
164
+ };
165
+
166
+ const result = await this.checkPermissions(guardContext);
167
+
168
+ if (!result.allowed) {
169
+ throw new ForbiddenException(result.error || 'Access denied');
170
+ }
171
+
172
+ request.user = result.user;
173
+ return true;
174
+ }
175
+
176
+ protected async checkPermissions(context: GuardContext) {
177
+ return this.exGuard.authenticate(context);
178
+ }
179
+
180
+ protected extractToken(request: any): string | null {
181
+ const authHeader = request.headers?.authorization;
182
+ if (authHeader?.startsWith('Bearer ')) {
183
+ return authHeader.substring(7);
184
+ }
185
+ return null;
186
+ }
187
+ }
188
+
189
+ @Injectable()
190
+ export class ExGuardPermissionGuard extends ExGuardNestGuard {
191
+ protected async checkPermissions(context: GuardContext) {
192
+ return this.exGuard.requirePermissions(context, ['read']);
193
+ }
194
+ }
195
+
196
+ @Injectable()
197
+ export class ExGuardRoleGuard extends ExGuardNestGuard {
198
+ protected async checkPermissions(context: GuardContext) {
199
+ return this.exGuard.requireRoles(context, ['Admin']);
200
+ }
201
+ }
202
+
203
+ // Factory functions for dynamic guards
204
+ export function createPermissionGuard(permissions: string[], requireAll = false) {
205
+ return class extends ExGuardNestGuard {
206
+ protected async checkPermissions(context: GuardContext) {
207
+ return this.exGuard.requirePermissions(context, permissions, { requireAll });
208
+ }
209
+ };
210
+ }
211
+
212
+ export function createRoleGuard(roles: string[], requireAll = false) {
213
+ return class extends ExGuardNestGuard {
214
+ protected async checkPermissions(context: GuardContext) {
215
+ return this.exGuard.requireRoles(context, roles, { requireAll });
216
+ }
217
+ };
218
+ }
219
+
220
+ export function createModuleGuard(modules: string[], requireAll = false) {
221
+ return class extends ExGuardNestGuard {
222
+ protected async checkPermissions(context: GuardContext) {
223
+ return this.exGuard.requireModules(context, modules, { requireAll });
224
+ }
225
+ };
226
+ }
227
+ `;
228
+
229
+ const guardPath = path.join(process.cwd(), 'src/exguard/exguard.guard.ts');
230
+
231
+ if (fs.existsSync(guardPath)) {
232
+ logWarning('ExGuard guards already exist. Skipping creation.');
233
+ return;
234
+ }
235
+
236
+ fs.writeFileSync(guardPath, guardContent);
237
+ logSuccess('Created ExGuard guards');
238
+ }
239
+
240
+ // Create ExGuard Decorators
241
+ function createExGuardDecorators() {
242
+ logStep(4, 'Creating ExGuard Decorators');
243
+
244
+ const decoratorContent = `import { SetMetadata } from '@nestjs/common';
245
+ import { createPermissionGuard, createRoleGuard, createModuleGuard } from './exguard.guard';
246
+
247
+ // Metadata keys
248
+ export const EXGUARD_PERMISSIONS_KEY = 'exguard_permissions';
249
+ export const EXGUARD_ROLES_KEY = 'exguard_roles';
250
+ export const EXGUARD_MODULES_KEY = 'exguard_modules';
251
+ export const EXGUARD_FIELD_OFFICES_KEY = 'exguard_field_offices';
252
+
253
+ // Permission decorator
254
+ export const RequirePermissions = (permissions: string[], requireAll = false) => {
255
+ return SetMetadata(EXGUARD_PERMISSIONS_KEY, { permissions, requireAll });
256
+ };
257
+
258
+ // Role decorator
259
+ export const RequireRoles = (roles: string[], requireAll = false) => {
260
+ return SetMetadata(EXGUARD_ROLES_KEY, { roles, requireAll });
261
+ };
262
+
263
+ // Module decorator
264
+ export const RequireModules = (modules: string[], requireAll = false) => {
265
+ return SetMetadata(EXGUARD_MODULES_KEY, { modules, requireAll });
266
+ };
267
+
268
+ // Field office decorator
269
+ export const RequireFieldOffices = (fieldOffices: string[], requireAll = false) => {
270
+ return SetMetadata(EXGUARD_FIELD_OFFICES_KEY, { fieldOffices, requireAll });
271
+ };
272
+
273
+ // Combined decorator for complex requirements
274
+ export const Require = (requirements: {
275
+ permissions?: string[];
276
+ roles?: string[];
277
+ modules?: string[];
278
+ fieldOffices?: string[];
279
+ requireAll?: boolean;
280
+ }) => {
281
+ return (target: any) => {
282
+ if (requirements.permissions) {
283
+ SetMetadata(EXGUARD_PERMISSIONS_KEY, {
284
+ permissions: requirements.permissions,
285
+ requireAll: requirements.requireAll || false
286
+ })(target);
287
+ }
288
+ if (requirements.roles) {
289
+ SetMetadata(EXGUARD_ROLES_KEY, {
290
+ roles: requirements.roles,
291
+ requireAll: requirements.requireAll || false
292
+ })(target);
293
+ }
294
+ if (requirements.modules) {
295
+ SetMetadata(EXGUARD_MODULES_KEY, {
296
+ modules: requirements.modules,
297
+ requireAll: requirements.requireAll || false
298
+ })(target);
299
+ }
300
+ if (requirements.fieldOffices) {
301
+ SetMetadata(EXGUARD_FIELD_OFFICES_KEY, {
302
+ fieldOffices: requirements.fieldOffices,
303
+ requireAll: requirements.requireAll || false
304
+ })(target);
305
+ }
306
+ };
307
+ };
308
+ `;
309
+
310
+ const decoratorPath = path.join(process.cwd(), 'src/exguard/exguard.decorators.ts');
311
+
312
+ if (fs.existsSync(decoratorPath)) {
313
+ logWarning('ExGuard decorators already exist. Skipping creation.');
314
+ return;
315
+ }
316
+
317
+ fs.writeFileSync(decoratorPath, decoratorContent);
318
+ logSuccess('Created ExGuard decorators');
319
+ }
320
+
321
+ // Create example controller
322
+ function createExampleController() {
323
+ logStep(5, 'Creating Example Controller');
324
+
325
+ const controllerContent = `import {
326
+ Controller,
327
+ Get,
328
+ Post,
329
+ Body,
330
+ UseGuards,
331
+ Request
332
+ } from '@nestjs/common';
333
+ import {
334
+ RequirePermissions,
335
+ RequireRoles,
336
+ RequireModules
337
+ } from '../exguard/exguard.decorators';
338
+ import {
339
+ ExGuardPermissionGuard,
340
+ createPermissionGuard
341
+ } from '../exguard/exguard.guard';
342
+
343
+ @Controller('events')
344
+ @UseGuards(ExGuardPermissionGuard) // Requires 'read' permission
345
+ export class EventsController {
346
+ @Get()
347
+ async getEvents(@Request() req) {
348
+ console.log('User accessing events:', req.user);
349
+ return { success: true, data: [] };
350
+ }
351
+
352
+ @Post()
353
+ @UseGuards(createPermissionGuard(['events:create']))
354
+ async createEvent(@Body() createEventDto: any, @Request() req) {
355
+ console.log('User creating event:', req.user);
356
+ return { success: true, data: createEventDto };
357
+ }
358
+
359
+ @Get('admin')
360
+ @RequireRoles(['Admin']) // Using decorator
361
+ @UseGuards(createRoleGuard(['Admin']))
362
+ async getAdminEvents(@Request() req) {
363
+ return { success: true, data: [], message: 'Admin events' };
364
+ }
365
+
366
+ @Get('reports')
367
+ @RequireModules(['reporting']) // Using decorator
368
+ @UseGuards(createModuleGuard(['reporting']))
369
+ async getReports(@Request() req) {
370
+ return { success: true, data: [], message: 'Reports data' };
371
+ }
372
+ }
373
+ `;
374
+
375
+ const controllerPath = path.join(process.cwd(), 'src/events/events.controller.ts');
376
+
377
+ // Check if events directory exists
378
+ const eventsDir = path.join(process.cwd(), 'src/events');
379
+ if (!fs.existsSync(eventsDir)) {
380
+ fs.mkdirSync(eventsDir, { recursive: true });
381
+ logSuccess('Created events directory');
382
+ }
383
+
384
+ if (fs.existsSync(controllerPath)) {
385
+ logWarning('Example controller already exists. Skipping creation.');
386
+ return;
387
+ }
388
+
389
+ fs.writeFileSync(controllerPath, controllerContent);
390
+ logSuccess('Created example controller');
391
+ }
392
+
393
+ // Update app module
394
+ function updateAppModule() {
395
+ logStep(6, 'Updating App Module');
396
+
397
+ const appModulePath = path.join(process.cwd(), 'src/app.module.ts');
398
+
399
+ if (!fs.existsSync(appModulePath)) {
400
+ logWarning('app.module.ts not found. Please manually import ExGuardModule.');
401
+ return;
402
+ }
403
+
404
+ let appModuleContent = fs.readFileSync(appModulePath, 'utf8');
405
+
406
+ // Check if ExGuardModule is already imported
407
+ if (appModuleContent.includes('ExGuardModule')) {
408
+ logWarning('ExGuardModule already imported in app.module.ts');
409
+ return;
410
+ }
411
+
412
+ // Add import
413
+ const importMatch = appModuleContent.match(/import\s*\{[^}]*\}\s*from\s*['"][^'"]*['"];?\s*/m);
414
+ if (importMatch) {
415
+ const lastImport = importMatch[0];
416
+ const newImport = lastImport.replace(/;?\s*$/, '') + ',\n ExGuardModule from \'./exguard/exguard.module\';\n';
417
+ appModuleContent = appModuleContent.replace(lastImport, newImport);
418
+ } else {
419
+ // Add import at the top
420
+ appModuleContent = `import { ExGuardModule } from './exguard/exguard.module';\n\n${appModuleContent}`;
421
+ }
422
+
423
+ // Add to imports array
424
+ const importsMatch = appModuleContent.match(/@Module\s*\(\s*\{\s*imports:\s*\[([^\]]*)\]/m);
425
+ if (importsMatch) {
426
+ const importsContent = importsMatch[1];
427
+ const newImportsContent = importsContent.trim() + ',\n ExGuardModule';
428
+ appModuleContent = appModuleContent.replace(importsMatch[0], `@Module({\n imports: [${newImportsContent}]`);
429
+ }
430
+
431
+ fs.writeFileSync(appModulePath, appModuleContent);
432
+ logSuccess('Updated app.module.ts with ExGuardModule');
433
+ }
434
+
435
+ // Create environment variables
436
+ function createEnvironmentFile() {
437
+ logStep(7, 'Creating Environment Variables');
438
+
439
+ const envContent = `# ExGuard Configuration
440
+ EXGUARD_API_URL=http://localhost:3000
441
+ EXGUARD_CACHE_ENABLED=true
442
+ EXGUARD_CACHE_TTL=300000
443
+
444
+ # Optional Realtime Configuration
445
+ EXGUARD_REALTIME_ENABLED=false
446
+ EXGUARD_REALTIME_URL=ws://localhost:3000/realtime
447
+ EXGUARD_SERVICE_TOKEN=your-service-jwt-token
448
+ `;
449
+
450
+ const envPath = path.join(process.cwd(), '.env');
451
+
452
+ if (fs.existsSync(envPath)) {
453
+ // Append if not already present
454
+ const existingEnv = fs.readFileSync(envPath, 'utf8');
455
+ if (!existingEnv.includes('EXGUARD_API_URL')) {
456
+ fs.appendFileSync(envPath, '\n\n# ExGuard Configuration\n' + envContent);
457
+ logSuccess('Appended ExGuard configuration to .env');
458
+ } else {
459
+ logWarning('ExGuard configuration already exists in .env');
460
+ }
461
+ } else {
462
+ fs.writeFileSync(envPath, envContent);
463
+ logSuccess('Created .env with ExGuard configuration');
464
+ }
465
+ }
466
+
467
+ // Update package.json scripts
468
+ function updatePackageScripts() {
469
+ logStep(8, 'Updating Package Scripts');
470
+
471
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
472
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
473
+
474
+ const scriptsToAdd = {
475
+ 'exguard:setup': 'node node_modules/exguard-backend/scripts/setup-nestjs.js',
476
+ 'exguard:example': 'node node_modules/exguard-backend/scripts/create-example.js'
477
+ };
478
+
479
+ if (!packageJson.scripts) {
480
+ packageJson.scripts = {};
481
+ }
482
+
483
+ Object.entries(scriptsToAdd).forEach(([script, command]) => {
484
+ if (!packageJson.scripts[script]) {
485
+ packageJson.scripts[script] = command;
486
+ logSuccess(`Added script: ${script}`);
487
+ } else {
488
+ logWarning(`Script already exists: ${script}`);
489
+ }
490
+ });
491
+
492
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
493
+ logSuccess('Updated package.json scripts');
494
+ }
495
+
496
+ // Main setup function
497
+ async function setupExGuard() {
498
+ log('šŸš€ ExGuard NestJS Automatic Setup', 'bright');
499
+ log('This script will automatically set up ExGuard in your NestJS project.\n');
500
+
501
+ try {
502
+ checkNestJSProject();
503
+ createDirectoryStructure();
504
+ createExGuardModule();
505
+ createExGuardGuards();
506
+ createExGuardDecorators();
507
+ createExampleController();
508
+ updateAppModule();
509
+ createEnvironmentFile();
510
+ updatePackageScripts();
511
+
512
+ log('\nšŸŽ‰ ExGuard setup completed successfully!', 'green');
513
+ log('\nšŸ“‹ Next steps:', 'cyan');
514
+ log('1. Review the generated files in src/exguard/', 'blue');
515
+ log('2. Check the example controller in src/events/', 'blue');
516
+ log('3. Update your .env file with your ExGuard API URL', 'blue');
517
+ log('4. Start your application: npm run start:dev', 'blue');
518
+ log('5. Test the protected endpoints', 'blue');
519
+
520
+ log('\nšŸ“š Documentation:', 'cyan');
521
+ log('- Main README: node_modules/exguard-backend/README.md', 'blue');
522
+ log('- NestJS Guide: node_modules/exguard-backend/examples/NESTJS-SETUP.md', 'blue');
523
+
524
+ } catch (error) {
525
+ logError(`Setup failed: ${error.message}`);
526
+ process.exit(1);
527
+ }
528
+ }
529
+
530
+ // Run setup if called directly
531
+ if (require.main === module) {
532
+ setupExGuard();
533
+ }
534
+
535
+ module.exports = { setupExGuard };
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Automatic ExGuard Module Setup for NestJS
4
+ * Fixed Automatic ExGuard Module Setup for NestJS
5
5
  *
6
6
  * Usage:
7
7
  * npx exguard-backend
8
8
  * npx exguard-backend setup-nestjs
9
9
  * OR
10
- * node node_modules/exguard-backend/scripts/setup-nestjs.js
10
+ * node node_modules/exguard-backend/scripts/setup-nestjs-fixed.cjs
11
11
  */
12
12
 
13
13
  const fs = require('fs');
@@ -71,6 +71,18 @@ function checkNestJSProject() {
71
71
  process.exit(1);
72
72
  }
73
73
 
74
+ // Check if exguard-backend is installed
75
+ if (!dependencies['exguard-backend']) {
76
+ logWarning('exguard-backend not found in dependencies. Installing it...');
77
+ try {
78
+ execSync('npm install exguard-backend@latest', { stdio: 'inherit' });
79
+ logSuccess('exguard-backend installed successfully');
80
+ } catch (error) {
81
+ logError('Failed to install exguard-backend. Please install it manually: npm install exguard-backend');
82
+ process.exit(1);
83
+ }
84
+ }
85
+
74
86
  logSuccess(`NestJS project detected with packages: ${nestPackages.join(', ')}`);
75
87
  return true;
76
88
  }
@@ -113,12 +125,12 @@ import { Guard } from 'exguard-backend';
113
125
  apiUrl: process.env.EXGUARD_API_URL || 'http://localhost:3000',
114
126
  cache: {
115
127
  enabled: process.env.EXGUARD_CACHE_ENABLED !== 'false',
116
- ttl: parseInt(process.env.EXGUARD_CACHE_TTL) || 300000, // 5 minutes
128
+ ttl: parseInt(process.env.EXGUARD_CACHE_TTL || '300000'), // 5 minutes
117
129
  },
118
130
  realtime: {
119
131
  enabled: process.env.EXGUARD_REALTIME_ENABLED === 'true',
120
- url: process.env.EXGUARD_REALTIME_URL,
121
- token: process.env.EXGUARD_SERVICE_TOKEN,
132
+ url: process.env.EXGUARD_REALTIME_URL || undefined,
133
+ token: process.env.EXGUARD_SERVICE_TOKEN || undefined,
122
134
  },
123
135
  }),
124
136
  },
@@ -148,7 +160,7 @@ import { Guard, GuardContext } from 'exguard-backend';
148
160
 
149
161
  @Injectable()
150
162
  export class ExGuardNestGuard implements CanActivate {
151
- constructor(protected exGuard: Guard) {}
163
+ constructor(public exGuard: Guard) {}
152
164
 
153
165
  async canActivate(context: ExecutionContext): Promise<boolean> {
154
166
  const request = context.switchToHttp().getRequest();
@@ -173,11 +185,11 @@ export class ExGuardNestGuard implements CanActivate {
173
185
  return true;
174
186
  }
175
187
 
176
- protected async checkPermissions(context: GuardContext) {
188
+ public async checkPermissions(context: GuardContext) {
177
189
  return this.exGuard.authenticate(context);
178
190
  }
179
191
 
180
- protected extractToken(request: any): string | null {
192
+ public extractToken(request: any): string | null {
181
193
  const authHeader = request.headers?.authorization;
182
194
  if (authHeader?.startsWith('Bearer ')) {
183
195
  return authHeader.substring(7);
@@ -188,14 +200,14 @@ export class ExGuardNestGuard implements CanActivate {
188
200
 
189
201
  @Injectable()
190
202
  export class ExGuardPermissionGuard extends ExGuardNestGuard {
191
- protected async checkPermissions(context: GuardContext) {
203
+ public async checkPermissions(context: GuardContext) {
192
204
  return this.exGuard.requirePermissions(context, ['read']);
193
205
  }
194
206
  }
195
207
 
196
208
  @Injectable()
197
209
  export class ExGuardRoleGuard extends ExGuardNestGuard {
198
- protected async checkPermissions(context: GuardContext) {
210
+ public async checkPermissions(context: GuardContext) {
199
211
  return this.exGuard.requireRoles(context, ['Admin']);
200
212
  }
201
213
  }
@@ -203,7 +215,7 @@ export class ExGuardRoleGuard extends ExGuardNestGuard {
203
215
  // Factory functions for dynamic guards
204
216
  export function createPermissionGuard(permissions: string[], requireAll = false) {
205
217
  return class extends ExGuardNestGuard {
206
- protected async checkPermissions(context: GuardContext) {
218
+ public async checkPermissions(context: GuardContext) {
207
219
  return this.exGuard.requirePermissions(context, permissions, { requireAll });
208
220
  }
209
221
  };
@@ -211,7 +223,7 @@ export function createPermissionGuard(permissions: string[], requireAll = false)
211
223
 
212
224
  export function createRoleGuard(roles: string[], requireAll = false) {
213
225
  return class extends ExGuardNestGuard {
214
- protected async checkPermissions(context: GuardContext) {
226
+ public async checkPermissions(context: GuardContext) {
215
227
  return this.exGuard.requireRoles(context, roles, { requireAll });
216
228
  }
217
229
  };
@@ -219,7 +231,7 @@ export function createRoleGuard(roles: string[], requireAll = false) {
219
231
 
220
232
  export function createModuleGuard(modules: string[], requireAll = false) {
221
233
  return class extends ExGuardNestGuard {
222
- protected async checkPermissions(context: GuardContext) {
234
+ public async checkPermissions(context: GuardContext) {
223
235
  return this.exGuard.requireModules(context, modules, { requireAll });
224
236
  }
225
237
  };
@@ -409,23 +421,51 @@ function updateAppModule() {
409
421
  return;
410
422
  }
411
423
 
412
- // Add import
413
- const importMatch = appModuleContent.match(/import\s*\{[^}]*\}\s*from\s*['"][^'"]*['"];?\s*/m);
414
- if (importMatch) {
415
- const lastImport = importMatch[0];
416
- const newImport = lastImport.replace(/;?\s*$/, '') + ',\n ExGuardModule from \'./exguard/exguard.module\';\n';
417
- appModuleContent = appModuleContent.replace(lastImport, newImport);
424
+ // Add import at the top - find the last import statement
425
+ const importRegex = /import\s+.*\s+from\s+['"][^'"]*['"];?\s*/g;
426
+ const imports = appModuleContent.match(importRegex);
427
+
428
+ if (imports && imports.length > 0) {
429
+ // Add after the last import
430
+ const lastImport = imports[imports.length - 1];
431
+ const lastImportIndex = appModuleContent.lastIndexOf(lastImport);
432
+ const afterLastImport = appModuleContent.substring(lastImportIndex + lastImport.length);
433
+
434
+ appModuleContent = appModuleContent.substring(0, lastImportIndex + lastImport.length) +
435
+ `import { ExGuardModule } from './exguard/exguard.module';\n` +
436
+ afterLastImport;
418
437
  } else {
419
- // Add import at the top
420
- appModuleContent = `import { ExGuardModule } from './exguard/exguard.module';\n\n${appModuleContent}`;
438
+ // Add at the very top
439
+ appModuleContent = `import { ExGuardModule } from './exguard/exguard.module';\n${appModuleContent}`;
421
440
  }
422
441
 
423
- // Add to imports array
424
- const importsMatch = appModuleContent.match(/@Module\s*\(\s*\{\s*imports:\s*\[([^\]]*)\]/m);
425
- if (importsMatch) {
426
- const importsContent = importsMatch[1];
427
- const newImportsContent = importsContent.trim() + ',\n ExGuardModule';
428
- appModuleContent = appModuleContent.replace(importsMatch[0], `@Module({\n imports: [${newImportsContent}]`);
442
+ // Find and update the @Module decorator
443
+ const moduleDecoratorMatch = appModuleContent.match(/@Module\s*\(\s*\{([^}]*)\}/s);
444
+ if (moduleDecoratorMatch) {
445
+ const moduleContent = moduleDecoratorMatch[1];
446
+
447
+ // Check if imports array exists
448
+ const importsArrayMatch = moduleContent.match(/imports:\s*\[([^\]]*)\]/s);
449
+ if (importsArrayMatch) {
450
+ // Add to existing imports array
451
+ const importsContent = importsArrayMatch[1];
452
+ const newImportsContent = importsContent.trim() + ',\n ExGuardModule';
453
+ appModuleContent = appModuleContent.replace(
454
+ importsArrayMatch[0],
455
+ `imports: [${newImportsContent}]`
456
+ );
457
+ } else {
458
+ // Add imports array after @Module({
459
+ const moduleStartMatch = appModuleContent.match(/@Module\s*\(\s*\{/);
460
+ if (moduleStartMatch) {
461
+ const moduleStartIndex = appModuleContent.indexOf(moduleStartMatch[0]);
462
+ const afterModuleStart = appModuleContent.substring(moduleStartIndex + moduleStartMatch[0].length);
463
+
464
+ appModuleContent = appModuleContent.substring(0, moduleStartIndex + moduleStartMatch[0].length) +
465
+ `\n imports: [ExGuardModule],` +
466
+ afterModuleStart;
467
+ }
468
+ }
429
469
  }
430
470
 
431
471
  fs.writeFileSync(appModulePath, appModuleContent);
@@ -464,7 +504,7 @@ EXGUARD_SERVICE_TOKEN=your-service-jwt-token
464
504
  }
465
505
  }
466
506
 
467
- // Update package.json scripts
507
+ // Update package scripts
468
508
  function updatePackageScripts() {
469
509
  logStep(8, 'Updating Package Scripts');
470
510
 
@@ -472,8 +512,8 @@ function updatePackageScripts() {
472
512
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
473
513
 
474
514
  const scriptsToAdd = {
475
- 'exguard:setup': 'node node_modules/exguard-backend/scripts/setup-nestjs.js',
476
- 'exguard:example': 'node node_modules/exguard-backend/scripts/create-example.js'
515
+ 'exguard:setup': 'node node_modules/exguard-backend/scripts/setup-nestjs-fixed.cjs',
516
+ 'exguard:example': 'node node_modules/exguard-backend/scripts/create-example.cjs'
477
517
  };
478
518
 
479
519
  if (!packageJson.scripts) {
@@ -495,7 +535,7 @@ function updatePackageScripts() {
495
535
 
496
536
  // Main setup function
497
537
  async function setupExGuard() {
498
- log('šŸš€ ExGuard NestJS Automatic Setup', 'bright');
538
+ log('šŸš€ ExGuard NestJS Automatic Setup (Fixed)', 'bright');
499
539
  log('This script will automatically set up ExGuard in your NestJS project.\n');
500
540
 
501
541
  try {