@flusys/nestjs-shared 1.0.0-beta → 1.0.0-rc
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 +56 -110
- package/cjs/classes/api-controller.class.js +9 -24
- package/cjs/classes/index.js +1 -0
- package/cjs/constants/index.js +14 -0
- package/cjs/constants/permissions.js +174 -0
- package/cjs/decorators/api-response.decorator.js +1 -1
- package/cjs/decorators/index.js +1 -0
- package/cjs/decorators/sanitize-html.decorator.js +36 -0
- package/cjs/dtos/filter-and-pagination.dto.js +24 -34
- package/cjs/dtos/pagination.dto.js +4 -8
- package/cjs/dtos/response-payload.dto.js +0 -41
- package/cjs/entities/identity.js +4 -4
- package/cjs/entities/user-root.js +13 -14
- package/cjs/guards/permission.guard.js +39 -94
- package/cjs/interceptors/index.js +1 -0
- package/cjs/interceptors/set-create-by-on-body.interceptor.js +2 -30
- package/cjs/interceptors/set-delete-by-on-body.interceptor.js +2 -30
- package/cjs/interceptors/set-update-by-on-body.interceptor.js +2 -30
- package/cjs/interceptors/set-user-field-on-body.interceptor.js +43 -0
- package/cjs/interceptors/slug.interceptor.js +30 -9
- package/cjs/interfaces/datasource.interface.js +4 -0
- package/cjs/interfaces/index.js +2 -1
- package/cjs/interfaces/module-config.interface.js +4 -0
- package/cjs/modules/cache/cache.module.js +3 -3
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +30 -110
- package/cjs/modules/utils/utils.service.js +63 -145
- package/cjs/utils/error-handler.util.js +91 -13
- package/cjs/utils/html-sanitizer.util.js +74 -0
- package/cjs/utils/index.js +2 -0
- package/cjs/utils/query-helpers.util.js +53 -0
- package/classes/api-controller.class.d.ts +5 -5
- package/classes/api-service.class.d.ts +5 -5
- package/classes/index.d.ts +1 -0
- package/classes/request-scoped-api.service.d.ts +3 -2
- package/constants/index.d.ts +1 -0
- package/constants/permissions.d.ts +167 -0
- package/decorators/index.d.ts +1 -0
- package/decorators/sanitize-html.decorator.d.ts +2 -0
- package/dtos/filter-and-pagination.dto.d.ts +0 -2
- package/dtos/response-payload.dto.d.ts +0 -7
- package/fesm/classes/api-controller.class.js +9 -24
- package/fesm/classes/index.js +2 -0
- package/fesm/constants/index.js +2 -0
- package/fesm/constants/permissions.js +121 -0
- package/fesm/decorators/api-response.decorator.js +1 -1
- package/fesm/decorators/index.js +1 -0
- package/fesm/decorators/sanitize-html.decorator.js +45 -0
- package/fesm/dtos/filter-and-pagination.dto.js +26 -47
- package/fesm/dtos/pagination.dto.js +4 -8
- package/fesm/dtos/response-payload.dto.js +0 -38
- package/fesm/entities/identity.js +4 -4
- package/fesm/entities/user-root.js +13 -14
- package/fesm/guards/permission.guard.js +39 -94
- package/fesm/interceptors/index.js +1 -0
- package/fesm/interceptors/set-create-by-on-body.interceptor.js +4 -30
- package/fesm/interceptors/set-delete-by-on-body.interceptor.js +4 -30
- package/fesm/interceptors/set-update-by-on-body.interceptor.js +4 -30
- package/fesm/interceptors/set-user-field-on-body.interceptor.js +36 -0
- package/fesm/interceptors/slug.interceptor.js +31 -10
- package/fesm/interfaces/datasource.interface.js +20 -0
- package/fesm/interfaces/index.js +2 -1
- package/fesm/interfaces/module-config.interface.js +5 -0
- package/fesm/modules/cache/cache.module.js +2 -2
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +30 -110
- package/fesm/modules/utils/utils.service.js +50 -143
- package/fesm/utils/error-handler.util.js +93 -14
- package/fesm/utils/html-sanitizer.util.js +82 -0
- package/fesm/utils/index.js +2 -0
- package/fesm/utils/query-helpers.util.js +78 -0
- package/interceptors/index.d.ts +1 -0
- package/interceptors/set-create-by-on-body.interceptor.d.ts +1 -5
- package/interceptors/set-delete-by-on-body.interceptor.d.ts +1 -5
- package/interceptors/set-update-by-on-body.interceptor.d.ts +1 -5
- package/interceptors/set-user-field-on-body.interceptor.d.ts +2 -0
- package/interceptors/slug.interceptor.d.ts +2 -1
- package/interfaces/api.interface.d.ts +2 -2
- package/interfaces/datasource.interface.d.ts +5 -0
- package/interfaces/identity.interface.d.ts +4 -4
- package/interfaces/index.d.ts +2 -1
- package/interfaces/module-config.interface.d.ts +6 -0
- package/interfaces/permission.interface.d.ts +0 -1
- package/modules/utils/utils.service.d.ts +10 -4
- package/package.json +4 -4
- package/utils/error-handler.util.d.ts +23 -13
- package/utils/html-sanitizer.util.d.ts +3 -0
- package/utils/index.d.ts +2 -0
- package/utils/query-helpers.util.d.ts +16 -0
- package/cjs/interfaces/base-query.interface.js +0 -6
- package/fesm/interfaces/base-query.interface.js +0 -3
- package/interfaces/base-query.interface.d.ts +0 -7
package/README.md
CHANGED
|
@@ -121,7 +121,6 @@ nestjs-shared/
|
|
|
121
121
|
│ │
|
|
122
122
|
│ ├── interfaces/ # TypeScript interfaces
|
|
123
123
|
│ │ ├── api.interface.ts
|
|
124
|
-
│ │ ├── base-query.interface.ts
|
|
125
124
|
│ │ ├── identity.interface.ts
|
|
126
125
|
│ │ ├── logged-user-info.interface.ts
|
|
127
126
|
│ │ ├── logger.interface.ts
|
|
@@ -298,7 +297,7 @@ override async getExtraManipulateQuery(
|
|
|
298
297
|
|
|
299
298
|
## ApiController - Generic CRUD Controller
|
|
300
299
|
|
|
301
|
-
The `createApiController` factory creates standardized
|
|
300
|
+
The `createApiController` factory creates standardized POST-only RPC controllers.
|
|
302
301
|
|
|
303
302
|
### Basic Usage
|
|
304
303
|
|
|
@@ -516,100 +515,56 @@ The shared package provides two guards for authentication and authorization:
|
|
|
516
515
|
|
|
517
516
|
### JwtAuthGuard
|
|
518
517
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
The `JwtAuthGuard` validates JWT tokens for protected routes. It extends Passport's `AuthGuard('jwt')` and respects the `@Public()` decorator.
|
|
522
|
-
|
|
523
|
-
**Why in shared module:**
|
|
524
|
-
- All feature modules (auth, iam, storage) need JWT authentication
|
|
525
|
-
- Keeps feature modules independent (no cross-dependencies)
|
|
526
|
-
- JwtStrategy registration remains in auth module
|
|
527
|
-
- This guard just validates tokens using the registered strategy
|
|
528
|
-
|
|
529
|
-
**Usage:**
|
|
518
|
+
Validates JWT tokens for protected routes. Extends Passport's `AuthGuard('jwt')` and respects `@Public()` decorator.
|
|
530
519
|
|
|
531
520
|
```typescript
|
|
532
521
|
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
533
|
-
import { UseGuards } from '@nestjs/common';
|
|
534
522
|
|
|
535
|
-
//
|
|
523
|
+
// Apply globally
|
|
524
|
+
@Module({
|
|
525
|
+
providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }],
|
|
526
|
+
})
|
|
527
|
+
export class AppModule {}
|
|
528
|
+
|
|
529
|
+
// Or per controller
|
|
536
530
|
@Controller('users')
|
|
537
531
|
@UseGuards(JwtAuthGuard)
|
|
538
532
|
export class UserController {
|
|
539
|
-
// All routes protected
|
|
540
|
-
|
|
541
533
|
@Post('login')
|
|
542
|
-
@Public() // Skip JWT check
|
|
534
|
+
@Public() // Skip JWT check
|
|
543
535
|
async login() { }
|
|
544
536
|
}
|
|
545
|
-
|
|
546
|
-
// Or apply globally
|
|
547
|
-
@Module({
|
|
548
|
-
providers: [
|
|
549
|
-
{
|
|
550
|
-
provide: APP_GUARD,
|
|
551
|
-
useClass: JwtAuthGuard,
|
|
552
|
-
},
|
|
553
|
-
],
|
|
554
|
-
})
|
|
555
|
-
export class AppModule {}
|
|
556
537
|
```
|
|
557
538
|
|
|
558
|
-
**Features:**
|
|
559
|
-
- Validates JWT tokens from `Authorization: Bearer <token>` header
|
|
560
|
-
- Respects `@Public()` decorator to skip authentication
|
|
561
|
-
- Throws `UnauthorizedException` for invalid/expired tokens
|
|
562
|
-
- Works with JwtStrategy registered in auth module
|
|
563
|
-
|
|
564
|
-
**Note:** The JwtStrategy (which registers the JWT validation logic with Passport) is still in the auth module at `@flusys/nestjs-auth/strategies/jwt.strategy.ts`. This guard uses that registered strategy.
|
|
565
|
-
|
|
566
539
|
### PermissionGuard
|
|
567
540
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
The `PermissionGuard` handles permission-based access control.
|
|
541
|
+
Checks user permissions from cache with AND/OR/nested logic support.
|
|
571
542
|
|
|
572
543
|
```typescript
|
|
573
|
-
import { Module } from '@nestjs/common';
|
|
574
|
-
import { APP_GUARD } from '@nestjs/core';
|
|
575
544
|
import { PermissionGuard } from '@flusys/nestjs-shared/guards';
|
|
576
545
|
|
|
546
|
+
// Apply globally
|
|
577
547
|
@Module({
|
|
578
|
-
providers: [
|
|
579
|
-
{
|
|
580
|
-
provide: APP_GUARD,
|
|
581
|
-
useClass: PermissionGuard,
|
|
582
|
-
},
|
|
583
|
-
],
|
|
548
|
+
providers: [{ provide: APP_GUARD, useClass: PermissionGuard }],
|
|
584
549
|
})
|
|
585
550
|
export class AppModule {}
|
|
586
551
|
```
|
|
587
552
|
|
|
588
|
-
|
|
553
|
+
**Cache Key Formats:**
|
|
589
554
|
|
|
590
555
|
```typescript
|
|
591
556
|
// Without company feature
|
|
592
557
|
`permissions:user:{userId}`
|
|
593
558
|
|
|
594
|
-
// With company feature
|
|
559
|
+
// With company feature
|
|
595
560
|
`permissions:company:{companyId}:branch:{branchId}:user:{userId}`
|
|
596
561
|
```
|
|
597
562
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
// Cache TTL in seconds
|
|
604
|
-
cacheTtl: 3600,
|
|
605
|
-
|
|
606
|
-
// Permission check mode
|
|
607
|
-
mode: 'RBAC' | 'DIRECT' | 'FULL',
|
|
608
|
-
|
|
609
|
-
// Custom permission resolver
|
|
610
|
-
resolver: CustomPermissionResolver,
|
|
611
|
-
});
|
|
612
|
-
```
|
|
563
|
+
**Features:**
|
|
564
|
+
- Supports AND/OR operators via `@RequirePermission` and `@RequireAnyPermission`
|
|
565
|
+
- Nested conditions via `@RequirePermissionCondition`
|
|
566
|
+
- Wildcard support (`*` and `*.suffix`)
|
|
567
|
+
- Company/branch scoped permissions
|
|
613
568
|
|
|
614
569
|
---
|
|
615
570
|
|
|
@@ -906,7 +861,7 @@ export class PostController {
|
|
|
906
861
|
|
|
907
862
|
### Slug Interceptor
|
|
908
863
|
|
|
909
|
-
Auto-generate slugs from name field:
|
|
864
|
+
Auto-generate slugs from name field using UtilsService (injected via DI):
|
|
910
865
|
|
|
911
866
|
```typescript
|
|
912
867
|
import { Slug } from '@flusys/nestjs-shared/interceptors';
|
|
@@ -922,6 +877,8 @@ export class ProductController {
|
|
|
922
877
|
}
|
|
923
878
|
```
|
|
924
879
|
|
|
880
|
+
**Note:** Requires `UtilsModule` to be imported in your module for dependency injection.
|
|
881
|
+
|
|
925
882
|
---
|
|
926
883
|
|
|
927
884
|
## Caching System
|
|
@@ -1005,7 +962,7 @@ export class AppModule {}
|
|
|
1005
962
|
|
|
1006
963
|
## Multi-Tenant DataSource
|
|
1007
964
|
|
|
1008
|
-
Dynamic database connection management
|
|
965
|
+
Dynamic database connection management with connection pooling and request-scoped tenant resolution.
|
|
1009
966
|
|
|
1010
967
|
### Setup
|
|
1011
968
|
|
|
@@ -1015,7 +972,7 @@ import { DataSourceModule } from '@flusys/nestjs-shared/modules';
|
|
|
1015
972
|
@Module({
|
|
1016
973
|
imports: [
|
|
1017
974
|
DataSourceModule.forRoot({
|
|
1018
|
-
|
|
975
|
+
bootstrapAppConfig: { databaseMode: 'multi-tenant' },
|
|
1019
976
|
defaultDatabaseConfig: {
|
|
1020
977
|
type: 'mysql',
|
|
1021
978
|
host: 'localhost',
|
|
@@ -1023,11 +980,9 @@ import { DataSourceModule } from '@flusys/nestjs-shared/modules';
|
|
|
1023
980
|
username: 'root',
|
|
1024
981
|
password: 'password',
|
|
1025
982
|
},
|
|
1026
|
-
|
|
1027
|
-
// Tenant configurations
|
|
1028
983
|
tenants: [
|
|
1029
|
-
{ id: 'tenant1', database: 'tenant1_db'
|
|
1030
|
-
{ id: 'tenant2', database: 'tenant2_db'
|
|
984
|
+
{ id: 'tenant1', database: 'tenant1_db' },
|
|
985
|
+
{ id: 'tenant2', database: 'tenant2_db' },
|
|
1031
986
|
],
|
|
1032
987
|
}),
|
|
1033
988
|
],
|
|
@@ -1035,41 +990,35 @@ import { DataSourceModule } from '@flusys/nestjs-shared/modules';
|
|
|
1035
990
|
export class AppModule {}
|
|
1036
991
|
```
|
|
1037
992
|
|
|
1038
|
-
###
|
|
993
|
+
### Key Methods
|
|
1039
994
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
995
|
+
| Method | Description |
|
|
996
|
+
|--------|-------------|
|
|
997
|
+
| `getDataSource()` | Get DataSource for current tenant (from header) |
|
|
998
|
+
| `getDataSourceForTenant(id)` | Get DataSource for specific tenant |
|
|
999
|
+
| `getRepository(entity)` | Get repository for current tenant |
|
|
1000
|
+
| `withTenant(id, callback)` | Execute callback with specific tenant DataSource |
|
|
1001
|
+
| `forAllTenants(callback)` | Execute callback for all active tenants |
|
|
1002
|
+
| `registerTenant(config)` | Register new tenant at runtime |
|
|
1003
|
+
| `removeTenant(id)` | Remove tenant and close connection |
|
|
1004
|
+
|
|
1005
|
+
### Usage
|
|
1043
1006
|
|
|
1007
|
+
```typescript
|
|
1044
1008
|
@Injectable()
|
|
1045
1009
|
export class TenantService {
|
|
1046
|
-
constructor(
|
|
1047
|
-
@Inject('DATASOURCE_PROVIDER')
|
|
1048
|
-
private dataSourceProvider: MultiTenantDataSourceService,
|
|
1049
|
-
) {}
|
|
1010
|
+
constructor(private dataSource: MultiTenantDataSourceService) {}
|
|
1050
1011
|
|
|
1051
|
-
async
|
|
1052
|
-
|
|
1012
|
+
async getUsers() {
|
|
1013
|
+
// Auto-resolves tenant from X-Tenant-ID header
|
|
1014
|
+
const repo = await this.dataSource.getRepository(User);
|
|
1015
|
+
return repo.find();
|
|
1053
1016
|
}
|
|
1054
|
-
}
|
|
1055
|
-
```
|
|
1056
|
-
|
|
1057
|
-
### Tenant Resolution
|
|
1058
1017
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
// Automatically uses tenant-specific database
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
// Manual tenant specification
|
|
1067
|
-
@Injectable()
|
|
1068
|
-
export class CrossTenantService {
|
|
1069
|
-
async copyData(fromTenant: string, toTenant: string) {
|
|
1070
|
-
const fromConn = await this.dataSourceProvider.getConnection(fromTenant);
|
|
1071
|
-
const toConn = await this.dataSourceProvider.getConnection(toTenant);
|
|
1072
|
-
// ...
|
|
1018
|
+
async crossTenantCopy(fromId: string, toId: string) {
|
|
1019
|
+
const fromDs = await this.dataSource.getDataSourceForTenant(fromId);
|
|
1020
|
+
const toDs = await this.dataSource.getDataSourceForTenant(toId);
|
|
1021
|
+
// Copy data between tenants
|
|
1073
1022
|
}
|
|
1074
1023
|
}
|
|
1075
1024
|
```
|
|
@@ -1092,18 +1041,15 @@ import { FilterAndPaginationDto } from '@flusys/nestjs-shared/dtos';
|
|
|
1092
1041
|
"category": "electronics"
|
|
1093
1042
|
},
|
|
1094
1043
|
"pagination": {
|
|
1095
|
-
"
|
|
1096
|
-
"
|
|
1044
|
+
"currentPage": 0,
|
|
1045
|
+
"pageSize": 10
|
|
1097
1046
|
},
|
|
1098
1047
|
"sort": {
|
|
1099
|
-
"
|
|
1100
|
-
"
|
|
1101
|
-
},
|
|
1102
|
-
"search": {
|
|
1103
|
-
"fields": ["name", "description"],
|
|
1104
|
-
"value": "laptop"
|
|
1048
|
+
"createdAt": "DESC",
|
|
1049
|
+
"name": "ASC"
|
|
1105
1050
|
},
|
|
1106
|
-
"select": ["id", "name", "price"]
|
|
1051
|
+
"select": ["id", "name", "price"],
|
|
1052
|
+
"withDeleted": false
|
|
1107
1053
|
}
|
|
1108
1054
|
```
|
|
1109
1055
|
|
|
@@ -1418,4 +1364,4 @@ This is the shared infrastructure layer used by all other Flusys packages.
|
|
|
1418
1364
|
|
|
1419
1365
|
---
|
|
1420
1366
|
|
|
1421
|
-
**Last Updated:** 2026-02-
|
|
1367
|
+
**Last Updated:** 2026-02-18
|
|
@@ -8,10 +8,10 @@ Object.defineProperty(exports, "createApiController", {
|
|
|
8
8
|
return createApiController;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const _decorators = require("
|
|
12
|
-
const _dtos = require("
|
|
13
|
-
const _guards = require("
|
|
14
|
-
const _interceptors = require("
|
|
11
|
+
const _decorators = require("../decorators");
|
|
12
|
+
const _dtos = require("../dtos");
|
|
13
|
+
const _guards = require("../guards");
|
|
14
|
+
const _interceptors = require("../interceptors");
|
|
15
15
|
const _common = require("@nestjs/common");
|
|
16
16
|
const _swagger = require("@nestjs/swagger");
|
|
17
17
|
const _classtransformer = require("class-transformer");
|
|
@@ -104,8 +104,10 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
104
104
|
// 2. It's an object with 'level' property but no endpoint keys
|
|
105
105
|
const isGlobalSecurity = typeof securityConfig === 'string' || securityConfig && typeof securityConfig === 'object' && 'level' in securityConfig && !endpointKeys.some((key)=>key in securityConfig);
|
|
106
106
|
// Normalize security config for each endpoint
|
|
107
|
+
// IMPORTANT: When per-endpoint security is specified, default to 'jwt' for unconfigured endpoints
|
|
108
|
+
// to prevent accidentally exposing endpoints without authentication
|
|
107
109
|
const defaultSecurity = isGlobalSecurity ? normalizeSecurity(securityConfig) : {
|
|
108
|
-
level: '
|
|
110
|
+
level: 'jwt'
|
|
109
111
|
};
|
|
110
112
|
const security = {
|
|
111
113
|
insert: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.insert),
|
|
@@ -347,16 +349,7 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
347
349
|
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
348
350
|
(0, _swagger.ApiOperation)({
|
|
349
351
|
summary: 'Get all items with filters and pagination',
|
|
350
|
-
description:
|
|
351
|
-
Retrieves items with support for:
|
|
352
|
-
- **filter**: Apply field-based filters (e.g., \`{ "isActive": true }\`)
|
|
353
|
-
- **pagination**: Control page and page size
|
|
354
|
-
- **sort**: Order by any field (e.g., \`{ "createdAt": "DESC" }\`)
|
|
355
|
-
- **select**: Choose specific fields to return
|
|
356
|
-
- **withDeleted**: Include soft-deleted items
|
|
357
|
-
- **extraKey**: Include additional relations
|
|
358
|
-
- **q** (query param): Global text search
|
|
359
|
-
`
|
|
352
|
+
description: 'Supports filter, pagination, sort, select, withDeleted, and q (search) params'
|
|
360
353
|
}),
|
|
361
354
|
(0, _swagger.ApiQuery)({
|
|
362
355
|
name: 'q',
|
|
@@ -385,15 +378,7 @@ Retrieves items with support for:
|
|
|
385
378
|
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
386
379
|
(0, _swagger.ApiOperation)({
|
|
387
380
|
summary: 'Delete, restore, or permanently remove items',
|
|
388
|
-
description:
|
|
389
|
-
Performs one of three actions:
|
|
390
|
-
|
|
391
|
-
- **"delete"** (soft delete): Marks items as deleted but keeps in database
|
|
392
|
-
- **"restore"**: Reverts soft-deleted items to active
|
|
393
|
-
- **"permanent"**: Completely removes items from database
|
|
394
|
-
|
|
395
|
-
Supports single ID or array of IDs for batch operations.
|
|
396
|
-
`
|
|
381
|
+
description: 'Types: delete (soft), restore, permanent. Supports batch IDs.'
|
|
397
382
|
}),
|
|
398
383
|
(0, _swagger.ApiResponse)({
|
|
399
384
|
status: 200,
|
package/cjs/classes/index.js
CHANGED
|
@@ -8,6 +8,7 @@ _export_star(require("./request-scoped-api.service"), exports);
|
|
|
8
8
|
_export_star(require("./hybrid-cache.class"), exports);
|
|
9
9
|
_export_star(require("./winston-logger-adapter.class"), exports);
|
|
10
10
|
_export_star(require("./winston.logger.class"), exports);
|
|
11
|
+
_export_star(require("../constants/permissions"), exports);
|
|
11
12
|
function _export_star(from, to) {
|
|
12
13
|
Object.keys(from).forEach(function(k) {
|
|
13
14
|
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
package/cjs/constants/index.js
CHANGED
|
@@ -41,6 +41,20 @@ _export(exports, {
|
|
|
41
41
|
return REQUEST_ID_HEADER;
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
|
+
_export_star(require("./permissions"), exports);
|
|
45
|
+
function _export_star(from, to) {
|
|
46
|
+
Object.keys(from).forEach(function(k) {
|
|
47
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
48
|
+
Object.defineProperty(to, k, {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function() {
|
|
51
|
+
return from[k];
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return from;
|
|
57
|
+
}
|
|
44
58
|
const IS_PUBLIC_KEY = 'isPublic';
|
|
45
59
|
const PERMISSIONS_KEY = 'permissions';
|
|
46
60
|
const CACHE_INSTANCE = 'CACHE_INSTANCE';
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Permission Codes
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for all permission codes used across the application.
|
|
5
|
+
* Use these constants instead of hardcoded strings to prevent typos and enable easy refactoring.
|
|
6
|
+
*
|
|
7
|
+
* Naming Convention: <entity>.<action>
|
|
8
|
+
* - entity: The resource being accessed (e.g., user, role, company)
|
|
9
|
+
* - action: The operation being performed (create, read, update, delete, assign)
|
|
10
|
+
*/ // ==================== AUTH MODULE ====================
|
|
11
|
+
"use strict";
|
|
12
|
+
Object.defineProperty(exports, "__esModule", {
|
|
13
|
+
value: true
|
|
14
|
+
});
|
|
15
|
+
function _export(target, all) {
|
|
16
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
_export(exports, {
|
|
22
|
+
get ACTION_PERMISSIONS () {
|
|
23
|
+
return ACTION_PERMISSIONS;
|
|
24
|
+
},
|
|
25
|
+
get BRANCH_PERMISSIONS () {
|
|
26
|
+
return BRANCH_PERMISSIONS;
|
|
27
|
+
},
|
|
28
|
+
get COMPANY_ACTION_PERMISSIONS () {
|
|
29
|
+
return COMPANY_ACTION_PERMISSIONS;
|
|
30
|
+
},
|
|
31
|
+
get COMPANY_PERMISSIONS () {
|
|
32
|
+
return COMPANY_PERMISSIONS;
|
|
33
|
+
},
|
|
34
|
+
get EMAIL_CONFIG_PERMISSIONS () {
|
|
35
|
+
return EMAIL_CONFIG_PERMISSIONS;
|
|
36
|
+
},
|
|
37
|
+
get EMAIL_TEMPLATE_PERMISSIONS () {
|
|
38
|
+
return EMAIL_TEMPLATE_PERMISSIONS;
|
|
39
|
+
},
|
|
40
|
+
get FILE_PERMISSIONS () {
|
|
41
|
+
return FILE_PERMISSIONS;
|
|
42
|
+
},
|
|
43
|
+
get FOLDER_PERMISSIONS () {
|
|
44
|
+
return FOLDER_PERMISSIONS;
|
|
45
|
+
},
|
|
46
|
+
get FORM_PERMISSIONS () {
|
|
47
|
+
return FORM_PERMISSIONS;
|
|
48
|
+
},
|
|
49
|
+
get PERMISSIONS () {
|
|
50
|
+
return PERMISSIONS;
|
|
51
|
+
},
|
|
52
|
+
get ROLE_ACTION_PERMISSIONS () {
|
|
53
|
+
return ROLE_ACTION_PERMISSIONS;
|
|
54
|
+
},
|
|
55
|
+
get ROLE_PERMISSIONS () {
|
|
56
|
+
return ROLE_PERMISSIONS;
|
|
57
|
+
},
|
|
58
|
+
get STORAGE_CONFIG_PERMISSIONS () {
|
|
59
|
+
return STORAGE_CONFIG_PERMISSIONS;
|
|
60
|
+
},
|
|
61
|
+
get USER_ACTION_PERMISSIONS () {
|
|
62
|
+
return USER_ACTION_PERMISSIONS;
|
|
63
|
+
},
|
|
64
|
+
get USER_PERMISSIONS () {
|
|
65
|
+
return USER_PERMISSIONS;
|
|
66
|
+
},
|
|
67
|
+
get USER_ROLE_PERMISSIONS () {
|
|
68
|
+
return USER_ROLE_PERMISSIONS;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
const USER_PERMISSIONS = {
|
|
72
|
+
CREATE: 'user.create',
|
|
73
|
+
READ: 'user.read',
|
|
74
|
+
UPDATE: 'user.update',
|
|
75
|
+
DELETE: 'user.delete'
|
|
76
|
+
};
|
|
77
|
+
const COMPANY_PERMISSIONS = {
|
|
78
|
+
CREATE: 'company.create',
|
|
79
|
+
READ: 'company.read',
|
|
80
|
+
UPDATE: 'company.update',
|
|
81
|
+
DELETE: 'company.delete'
|
|
82
|
+
};
|
|
83
|
+
const BRANCH_PERMISSIONS = {
|
|
84
|
+
CREATE: 'branch.create',
|
|
85
|
+
READ: 'branch.read',
|
|
86
|
+
UPDATE: 'branch.update',
|
|
87
|
+
DELETE: 'branch.delete'
|
|
88
|
+
};
|
|
89
|
+
const ACTION_PERMISSIONS = {
|
|
90
|
+
CREATE: 'action.create',
|
|
91
|
+
READ: 'action.read',
|
|
92
|
+
UPDATE: 'action.update',
|
|
93
|
+
DELETE: 'action.delete'
|
|
94
|
+
};
|
|
95
|
+
const ROLE_PERMISSIONS = {
|
|
96
|
+
CREATE: 'role.create',
|
|
97
|
+
READ: 'role.read',
|
|
98
|
+
UPDATE: 'role.update',
|
|
99
|
+
DELETE: 'role.delete'
|
|
100
|
+
};
|
|
101
|
+
const ROLE_ACTION_PERMISSIONS = {
|
|
102
|
+
READ: 'role-action.read',
|
|
103
|
+
ASSIGN: 'role-action.assign'
|
|
104
|
+
};
|
|
105
|
+
const USER_ROLE_PERMISSIONS = {
|
|
106
|
+
READ: 'user-role.read',
|
|
107
|
+
ASSIGN: 'user-role.assign'
|
|
108
|
+
};
|
|
109
|
+
const USER_ACTION_PERMISSIONS = {
|
|
110
|
+
READ: 'user-action.read',
|
|
111
|
+
ASSIGN: 'user-action.assign'
|
|
112
|
+
};
|
|
113
|
+
const COMPANY_ACTION_PERMISSIONS = {
|
|
114
|
+
READ: 'company-action.read',
|
|
115
|
+
ASSIGN: 'company-action.assign'
|
|
116
|
+
};
|
|
117
|
+
const FILE_PERMISSIONS = {
|
|
118
|
+
CREATE: 'file.create',
|
|
119
|
+
READ: 'file.read',
|
|
120
|
+
UPDATE: 'file.update',
|
|
121
|
+
DELETE: 'file.delete'
|
|
122
|
+
};
|
|
123
|
+
const FOLDER_PERMISSIONS = {
|
|
124
|
+
CREATE: 'folder.create',
|
|
125
|
+
READ: 'folder.read',
|
|
126
|
+
UPDATE: 'folder.update',
|
|
127
|
+
DELETE: 'folder.delete'
|
|
128
|
+
};
|
|
129
|
+
const STORAGE_CONFIG_PERMISSIONS = {
|
|
130
|
+
CREATE: 'storage-config.create',
|
|
131
|
+
READ: 'storage-config.read',
|
|
132
|
+
UPDATE: 'storage-config.update',
|
|
133
|
+
DELETE: 'storage-config.delete'
|
|
134
|
+
};
|
|
135
|
+
const EMAIL_CONFIG_PERMISSIONS = {
|
|
136
|
+
CREATE: 'email-config.create',
|
|
137
|
+
READ: 'email-config.read',
|
|
138
|
+
UPDATE: 'email-config.update',
|
|
139
|
+
DELETE: 'email-config.delete'
|
|
140
|
+
};
|
|
141
|
+
const EMAIL_TEMPLATE_PERMISSIONS = {
|
|
142
|
+
CREATE: 'email-template.create',
|
|
143
|
+
READ: 'email-template.read',
|
|
144
|
+
UPDATE: 'email-template.update',
|
|
145
|
+
DELETE: 'email-template.delete'
|
|
146
|
+
};
|
|
147
|
+
const FORM_PERMISSIONS = {
|
|
148
|
+
CREATE: 'form.create',
|
|
149
|
+
READ: 'form.read',
|
|
150
|
+
UPDATE: 'form.update',
|
|
151
|
+
DELETE: 'form.delete'
|
|
152
|
+
};
|
|
153
|
+
const PERMISSIONS = {
|
|
154
|
+
// Auth
|
|
155
|
+
USER: USER_PERMISSIONS,
|
|
156
|
+
COMPANY: COMPANY_PERMISSIONS,
|
|
157
|
+
BRANCH: BRANCH_PERMISSIONS,
|
|
158
|
+
// IAM
|
|
159
|
+
ACTION: ACTION_PERMISSIONS,
|
|
160
|
+
ROLE: ROLE_PERMISSIONS,
|
|
161
|
+
ROLE_ACTION: ROLE_ACTION_PERMISSIONS,
|
|
162
|
+
USER_ROLE: USER_ROLE_PERMISSIONS,
|
|
163
|
+
USER_ACTION: USER_ACTION_PERMISSIONS,
|
|
164
|
+
COMPANY_ACTION: COMPANY_ACTION_PERMISSIONS,
|
|
165
|
+
// Storage
|
|
166
|
+
FILE: FILE_PERMISSIONS,
|
|
167
|
+
FOLDER: FOLDER_PERMISSIONS,
|
|
168
|
+
STORAGE_CONFIG: STORAGE_CONFIG_PERMISSIONS,
|
|
169
|
+
// Email
|
|
170
|
+
EMAIL_CONFIG: EMAIL_CONFIG_PERMISSIONS,
|
|
171
|
+
EMAIL_TEMPLATE: EMAIL_TEMPLATE_PERMISSIONS,
|
|
172
|
+
// Form Builder
|
|
173
|
+
FORM: FORM_PERMISSIONS
|
|
174
|
+
};
|
|
@@ -8,7 +8,7 @@ Object.defineProperty(exports, "ApiResponseDto", {
|
|
|
8
8
|
return ApiResponseDto;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const _dtos = require("
|
|
11
|
+
const _dtos = require("../dtos");
|
|
12
12
|
const _common = require("@nestjs/common");
|
|
13
13
|
const _swagger = require("@nestjs/swagger");
|
|
14
14
|
const ApiResponseDto = (dto, isArray = false, arrayType = 'list')=>{
|
package/cjs/decorators/index.js
CHANGED
|
@@ -6,6 +6,7 @@ _export_star(require("./api-response.decorator"), exports);
|
|
|
6
6
|
_export_star(require("./current-user.decorator"), exports);
|
|
7
7
|
_export_star(require("./public.decorator"), exports);
|
|
8
8
|
_export_star(require("./require-permission.decorator"), exports);
|
|
9
|
+
_export_star(require("./sanitize-html.decorator"), exports);
|
|
9
10
|
function _export_star(from, to) {
|
|
10
11
|
Object.keys(from).forEach(function(k) {
|
|
11
12
|
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get SanitizeAndTrim () {
|
|
13
|
+
return SanitizeAndTrim;
|
|
14
|
+
},
|
|
15
|
+
get SanitizeHtml () {
|
|
16
|
+
return SanitizeHtml;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _classtransformer = require("class-transformer");
|
|
20
|
+
const _htmlsanitizerutil = require("../utils/html-sanitizer.util");
|
|
21
|
+
function SanitizeHtml() {
|
|
22
|
+
return (0, _classtransformer.Transform)(({ value })=>{
|
|
23
|
+
if (typeof value === 'string') {
|
|
24
|
+
return (0, _htmlsanitizerutil.escapeHtml)(value);
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function SanitizeAndTrim() {
|
|
30
|
+
return (0, _classtransformer.Transform)(({ value })=>{
|
|
31
|
+
if (typeof value === 'string') {
|
|
32
|
+
return (0, _htmlsanitizerutil.escapeHtml)(value.trim());
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
});
|
|
36
|
+
}
|