@flusys/nestjs-iam 0.1.0-beta.3 → 1.1.0-beta
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 +3 -7
- package/cjs/controllers/action.controller.js +3 -1
- package/cjs/services/action.service.js +11 -42
- package/cjs/services/iam-config.service.js +11 -28
- package/cjs/services/iam-datasource.provider.js +12 -30
- package/cjs/services/permission-cache.service.js +20 -94
- package/cjs/services/permission.service.js +21 -93
- package/cjs/services/role.service.js +23 -64
- package/fesm/controllers/action.controller.js +3 -1
- package/fesm/services/action.service.js +12 -43
- package/fesm/services/iam-config.service.js +11 -28
- package/fesm/services/iam-datasource.provider.js +12 -30
- package/fesm/services/permission-cache.service.js +20 -94
- package/fesm/services/permission.service.js +21 -93
- package/fesm/services/role.service.js +24 -65
- package/package.json +3 -3
- package/services/action.service.d.ts +1 -4
- package/services/role.service.d.ts +2 -5
package/README.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
> **Package:** `@flusys/nestjs-iam`
|
|
4
4
|
> **Purpose:** Identity and Access Management with RBAC, ABAC, and permission logic
|
|
5
|
-
> **Version:** 4.4.0 | **Updated:** 2026-01-24
|
|
6
5
|
|
|
7
6
|
## Table of Contents
|
|
8
7
|
|
|
@@ -648,7 +647,8 @@ nestjs-iam/src/
|
|
|
648
647
|
├── interfaces/
|
|
649
648
|
│ ├── action.interface.ts
|
|
650
649
|
│ ├── role.interface.ts
|
|
651
|
-
│
|
|
650
|
+
│ ├── iam-module-options.interface.ts
|
|
651
|
+
│ └── iam-module-async-options.interface.ts
|
|
652
652
|
├── enums/
|
|
653
653
|
│ ├── action-type.enum.ts
|
|
654
654
|
│ └── permission-type.enum.ts
|
|
@@ -658,8 +658,4 @@ nestjs-iam/src/
|
|
|
658
658
|
|
|
659
659
|
---
|
|
660
660
|
|
|
661
|
-
**Last Updated:** 2026-02-
|
|
662
|
-
|
|
663
|
-
**Recent Changes (2026-02-09):**
|
|
664
|
-
- Added explicit `@Inject()` decorators to all services for esbuild bundling compatibility
|
|
665
|
-
- All services use REQUEST scope with lazy repository initialization via DataSource Provider pattern
|
|
661
|
+
**Last Updated:** 2026-02-16
|
|
@@ -41,7 +41,9 @@ function _ts_param(paramIndex, decorator) {
|
|
|
41
41
|
decorator(target, key, paramIndex);
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
let ActionController = class ActionController extends (0, _nestjsshared.createApiController)(_actiondto.CreateActionDto, _actiondto.UpdateActionDto, _actiondto.ActionResponseDto
|
|
44
|
+
let ActionController = class ActionController extends (0, _nestjsshared.createApiController)(_actiondto.CreateActionDto, _actiondto.UpdateActionDto, _actiondto.ActionResponseDto, {
|
|
45
|
+
security: 'jwt'
|
|
46
|
+
}) {
|
|
45
47
|
async getActionsForPermission(user) {
|
|
46
48
|
const actions = await this.actionService.getActionsForPermission(user);
|
|
47
49
|
return {
|
|
@@ -44,38 +44,15 @@ function _ts_param(paramIndex, decorator) {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
let ActionService = class ActionService extends _classes.RequestScopedApiService {
|
|
47
|
-
|
|
48
|
-
* Resolve entity class for this service
|
|
49
|
-
* @returns Action entity class
|
|
50
|
-
*/ resolveEntity() {
|
|
47
|
+
resolveEntity() {
|
|
51
48
|
return _actionentity.Action;
|
|
52
49
|
}
|
|
53
|
-
|
|
54
|
-
* Get DataSource provider for this service
|
|
55
|
-
* @returns IAMDataSourceProvider instance
|
|
56
|
-
*/ getDataSourceProvider() {
|
|
50
|
+
getDataSourceProvider() {
|
|
57
51
|
return this.dataSourceProvider;
|
|
58
52
|
}
|
|
59
|
-
//
|
|
60
|
-
async convertSingleDtoToEntity(dto, _user) {
|
|
61
|
-
if (!('id' in dto) || !dto.id) {
|
|
62
|
-
return dto;
|
|
63
|
-
}
|
|
64
|
-
const existingAction = await this.repository.findOne({
|
|
65
|
-
where: {
|
|
66
|
-
id: dto.id
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
if (!existingAction) {
|
|
70
|
-
throw new _common.NotFoundException(`Action with ID ${dto.id} not found`);
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
...existingAction,
|
|
74
|
-
...dto
|
|
75
|
-
};
|
|
76
|
-
}
|
|
53
|
+
// Query Customization
|
|
77
54
|
async getSelectQuery(query, _user, select) {
|
|
78
|
-
if (!select
|
|
55
|
+
if (!select?.length) {
|
|
79
56
|
select = [
|
|
80
57
|
'id',
|
|
81
58
|
'name',
|
|
@@ -89,14 +66,13 @@ let ActionService = class ActionService extends _classes.RequestScopedApiService
|
|
|
89
66
|
'createdAt'
|
|
90
67
|
];
|
|
91
68
|
}
|
|
92
|
-
|
|
93
|
-
query.select(selectFields);
|
|
69
|
+
query.select(select.map((f)=>`${this.entityName}.${f}`));
|
|
94
70
|
return {
|
|
95
71
|
query,
|
|
96
72
|
isRaw: false
|
|
97
73
|
};
|
|
98
74
|
}
|
|
99
|
-
async getGlobalSearchQuery(query, search
|
|
75
|
+
async getGlobalSearchQuery(query, search) {
|
|
100
76
|
query.andWhere('(action.name LIKE :search OR action.code LIKE :search OR action.description LIKE :search)', {
|
|
101
77
|
search: `%${search}%`
|
|
102
78
|
});
|
|
@@ -105,9 +81,8 @@ let ActionService = class ActionService extends _classes.RequestScopedApiService
|
|
|
105
81
|
isRaw: false
|
|
106
82
|
};
|
|
107
83
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
*/ convertEntityToResponseDto(entity, _isRaw) {
|
|
84
|
+
// Response Conversion
|
|
85
|
+
convertEntityToResponseDto(entity, _isRaw) {
|
|
111
86
|
return {
|
|
112
87
|
id: entity.id,
|
|
113
88
|
readOnly: entity.readOnly,
|
|
@@ -128,12 +103,8 @@ let ActionService = class ActionService extends _classes.RequestScopedApiService
|
|
|
128
103
|
deletedById: entity.deletedById
|
|
129
104
|
};
|
|
130
105
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
*
|
|
134
|
-
* @param user - Logged in user info
|
|
135
|
-
* @returns Array of actions with id, code, and name fields
|
|
136
|
-
*/ async getActionsForPermission(user) {
|
|
106
|
+
// Custom Methods
|
|
107
|
+
/** Get actions available for permission assignment (filtered by company whitelist) */ async getActionsForPermission(user) {
|
|
137
108
|
await this.ensureRepositoryInitialized();
|
|
138
109
|
if (!user) {
|
|
139
110
|
throw new Error('User is required for getActionsForPermission');
|
|
@@ -227,10 +198,8 @@ let ActionService = class ActionService extends _classes.RequestScopedApiService
|
|
|
227
198
|
}
|
|
228
199
|
return rootNodes;
|
|
229
200
|
}
|
|
230
|
-
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
231
201
|
constructor(cacheManager, utilsService, iamConfigService, dataSourceProvider, permissionService){
|
|
232
|
-
|
|
233
|
-
super('action', null, cacheManager, utilsService, ActionService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "permissionService", void 0), _define_property(this, "logger", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.dataSourceProvider = dataSourceProvider, this.permissionService = permissionService, this.logger = new _common.Logger(ActionService.name);
|
|
202
|
+
super('action', null, cacheManager, utilsService, ActionService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "permissionService", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.dataSourceProvider = dataSourceProvider, this.permissionService = permissionService;
|
|
234
203
|
}
|
|
235
204
|
};
|
|
236
205
|
ActionService = _ts_decorate([
|
|
@@ -41,50 +41,33 @@ function _ts_param(paramIndex, decorator) {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
let IAMConfigService = class IAMConfigService {
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
* Get database mode (single or multi-tenant)
|
|
47
|
-
*/ getDatabaseMode() {
|
|
44
|
+
// Database Mode
|
|
45
|
+
getDatabaseMode() {
|
|
48
46
|
return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
|
|
49
47
|
}
|
|
50
|
-
|
|
51
|
-
* Check if running in multi-tenant mode
|
|
52
|
-
*/ isMultiTenant() {
|
|
48
|
+
isMultiTenant() {
|
|
53
49
|
return this.getDatabaseMode() === 'multi-tenant';
|
|
54
50
|
}
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
* Get enable company feature flag
|
|
58
|
-
*/ getEnableCompanyFeature() {
|
|
51
|
+
// Company Feature
|
|
52
|
+
getEnableCompanyFeature() {
|
|
59
53
|
return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
60
54
|
}
|
|
61
|
-
|
|
62
|
-
* Check if company feature is enabled (alias for getEnableCompanyFeature)
|
|
63
|
-
*/ isCompanyFeatureEnabled() {
|
|
55
|
+
isCompanyFeatureEnabled() {
|
|
64
56
|
return this.getEnableCompanyFeature();
|
|
65
57
|
}
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
* Get permission mode from bootstrap config
|
|
69
|
-
*
|
|
70
|
-
* **Note:** Reads from bootstrapAppConfig (not runtime config)
|
|
71
|
-
* because permissionMode affects entity/controller registration.
|
|
72
|
-
*/ getPermissionMode() {
|
|
58
|
+
// Permission Mode
|
|
59
|
+
getPermissionMode() {
|
|
73
60
|
return _helpers.PermissionModeHelper.fromString(this.options.bootstrapAppConfig?.permissionMode);
|
|
74
61
|
}
|
|
75
|
-
|
|
76
|
-
* Check if RBAC (role-based) permissions are enabled
|
|
77
|
-
*/ isRbacEnabled() {
|
|
62
|
+
isRbacEnabled() {
|
|
78
63
|
const mode = this.getPermissionMode();
|
|
79
64
|
return mode === _permissiontypeenum.IAMPermissionMode.RBAC || mode === _permissiontypeenum.IAMPermissionMode.FULL;
|
|
80
65
|
}
|
|
81
|
-
|
|
82
|
-
* Check if direct (user-level) permissions are enabled
|
|
83
|
-
*/ isDirectPermissionEnabled() {
|
|
66
|
+
isDirectPermissionEnabled() {
|
|
84
67
|
const mode = this.getPermissionMode();
|
|
85
68
|
return mode === _permissiontypeenum.IAMPermissionMode.DIRECT || mode === _permissiontypeenum.IAMPermissionMode.FULL;
|
|
86
69
|
}
|
|
87
|
-
//
|
|
70
|
+
// Options
|
|
88
71
|
getOptions() {
|
|
89
72
|
return this.options;
|
|
90
73
|
}
|
|
@@ -83,10 +83,8 @@ function _ts_param(paramIndex, decorator) {
|
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
85
|
let IAMDataSourceProvider = class IAMDataSourceProvider extends _modules.MultiTenantDataSourceService {
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
* Build parent options from IAMModuleOptions
|
|
89
|
-
*/ static buildParentOptions(options) {
|
|
86
|
+
// Factory Methods
|
|
87
|
+
static buildParentOptions(options) {
|
|
90
88
|
return {
|
|
91
89
|
bootstrapAppConfig: options.bootstrapAppConfig,
|
|
92
90
|
defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
|
|
@@ -94,43 +92,29 @@ let IAMDataSourceProvider = class IAMDataSourceProvider extends _modules.MultiTe
|
|
|
94
92
|
tenants: options.config?.tenants
|
|
95
93
|
};
|
|
96
94
|
}
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
* Get global enable company feature flag
|
|
100
|
-
*/ getEnableCompanyFeature() {
|
|
95
|
+
// Feature Flags
|
|
96
|
+
getEnableCompanyFeature() {
|
|
101
97
|
return this.iamOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
102
98
|
}
|
|
103
|
-
|
|
104
|
-
* Get enable company feature for specific tenant
|
|
105
|
-
* Falls back to global setting if not specified per-tenant
|
|
106
|
-
*/ getEnableCompanyFeatureForTenant(tenant) {
|
|
99
|
+
getEnableCompanyFeatureForTenant(tenant) {
|
|
107
100
|
return tenant?.enableCompanyFeature ?? this.getEnableCompanyFeature();
|
|
108
101
|
}
|
|
109
|
-
|
|
110
|
-
* Get enable company feature for current request context
|
|
111
|
-
*/ getEnableCompanyFeatureForCurrentTenant() {
|
|
102
|
+
getEnableCompanyFeatureForCurrentTenant() {
|
|
112
103
|
return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant() ?? undefined);
|
|
113
104
|
}
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
* Get IAM entities dynamically based on configuration
|
|
117
|
-
* Returns appropriate entities based on company feature and permission mode
|
|
118
|
-
*/ async getIAMEntities() {
|
|
105
|
+
// Entity Management
|
|
106
|
+
async getIAMEntities() {
|
|
119
107
|
const { Action, Role, RoleWithCompany, UserIamPermission, UserIamPermissionWithCompany, getIAMEntitiesByConfig } = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
|
|
120
108
|
const enableCompanyFeature = this.getEnableCompanyFeatureForCurrentTenant();
|
|
121
109
|
const permissionMode = this.iamOptions.bootstrapAppConfig?.permissionMode || 'FULL';
|
|
122
110
|
return getIAMEntitiesByConfig(enableCompanyFeature, permissionMode);
|
|
123
111
|
}
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
* Override to dynamically set entities based on tenant config
|
|
127
|
-
*/ async createDataSourceFromConfig(config) {
|
|
112
|
+
// Overrides
|
|
113
|
+
async createDataSourceFromConfig(config) {
|
|
128
114
|
const entities = await this.getIAMEntities();
|
|
129
115
|
return super.createDataSourceFromConfig(config, entities);
|
|
130
116
|
}
|
|
131
|
-
|
|
132
|
-
* Override to use IAM-specific static cache
|
|
133
|
-
*/ async getSingleDataSource() {
|
|
117
|
+
async getSingleDataSource() {
|
|
134
118
|
if (!IAMDataSourceProvider.singleDataSource) {
|
|
135
119
|
if (IAMDataSourceProvider.singleConnectionLock) {
|
|
136
120
|
return IAMDataSourceProvider.singleConnectionLock;
|
|
@@ -154,9 +138,7 @@ let IAMDataSourceProvider = class IAMDataSourceProvider extends _modules.MultiTe
|
|
|
154
138
|
}
|
|
155
139
|
return IAMDataSourceProvider.singleDataSource;
|
|
156
140
|
}
|
|
157
|
-
|
|
158
|
-
* Override to use IAM-specific static cache for tenant connections
|
|
159
|
-
*/ async getOrCreateTenantConnection(tenant) {
|
|
141
|
+
async getOrCreateTenantConnection(tenant) {
|
|
160
142
|
// Return existing initialized connection from IAM-specific cache
|
|
161
143
|
const existing = IAMDataSourceProvider.tenantConnections.get(tenant.id);
|
|
162
144
|
if (existing?.isInitialized) {
|
|
@@ -38,33 +38,23 @@ function _ts_param(paramIndex, decorator) {
|
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
let PermissionCacheService = class PermissionCacheService {
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
* Generate cache key for user permissions (backend codes for PermissionGuard)
|
|
44
|
-
* Format matches PermissionGuard in nestjs-shared
|
|
45
|
-
*/ generateCacheKey(options) {
|
|
41
|
+
// Cache Key Generation
|
|
42
|
+
generateCacheKey(options) {
|
|
46
43
|
const { userId, companyId, branchId, enableCompanyFeature } = options;
|
|
47
44
|
if (enableCompanyFeature && companyId) {
|
|
48
45
|
return `${this.CACHE_PREFIX}:company:${companyId}:branch:${branchId || 'null'}:user:${userId}`;
|
|
49
46
|
}
|
|
50
47
|
return `${this.CACHE_PREFIX}:user:${userId}`;
|
|
51
48
|
}
|
|
52
|
-
|
|
53
|
-
* Generate cache key for full my-permissions response
|
|
54
|
-
*/ generateMyPermissionsCacheKey(options) {
|
|
49
|
+
generateMyPermissionsCacheKey(options) {
|
|
55
50
|
const { userId, companyId, branchId, enableCompanyFeature } = options;
|
|
56
51
|
if (enableCompanyFeature && companyId) {
|
|
57
52
|
return `${this.MY_PERMISSIONS_PREFIX}:company:${companyId}:branch:${branchId || 'null'}:user:${userId}`;
|
|
58
53
|
}
|
|
59
54
|
return `${this.MY_PERMISSIONS_PREFIX}:user:${userId}`;
|
|
60
55
|
}
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
* Set user permissions in cache
|
|
64
|
-
*
|
|
65
|
-
* @param options - Cache key options
|
|
66
|
-
* @param permissions - Array of permission codes (action codes)
|
|
67
|
-
*/ async setPermissions(options, permissions) {
|
|
56
|
+
// Cache Operations
|
|
57
|
+
async setPermissions(options, permissions) {
|
|
68
58
|
try {
|
|
69
59
|
const key = this.generateCacheKey(options);
|
|
70
60
|
await this.cacheManager.set(key, permissions, this.TTL);
|
|
@@ -74,12 +64,7 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
74
64
|
// Don't throw - cache failure shouldn't break the operation
|
|
75
65
|
}
|
|
76
66
|
}
|
|
77
|
-
|
|
78
|
-
* Get user permissions from cache
|
|
79
|
-
*
|
|
80
|
-
* @param options - Cache key options
|
|
81
|
-
* @returns Array of permission codes or null if not found
|
|
82
|
-
*/ async getPermissions(options) {
|
|
67
|
+
async getPermissions(options) {
|
|
83
68
|
try {
|
|
84
69
|
const key = this.generateCacheKey(options);
|
|
85
70
|
const result = await this.cacheManager.get(key);
|
|
@@ -89,14 +74,8 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
89
74
|
return null;
|
|
90
75
|
}
|
|
91
76
|
}
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
* Set full my-permissions response in cache
|
|
95
|
-
* Caches frontend actions and backend codes for quick retrieval
|
|
96
|
-
*
|
|
97
|
-
* @param options - Cache key options
|
|
98
|
-
* @param data - Full permissions data to cache
|
|
99
|
-
*/ async setMyPermissions(options, data) {
|
|
77
|
+
// My-Permissions Cache Operations
|
|
78
|
+
async setMyPermissions(options, data) {
|
|
100
79
|
try {
|
|
101
80
|
const key = this.generateMyPermissionsCacheKey(options);
|
|
102
81
|
await this.cacheManager.set(key, data, this.TTL);
|
|
@@ -105,12 +84,7 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
105
84
|
this.logger.error(`Failed to cache my-permissions: ${error}`);
|
|
106
85
|
}
|
|
107
86
|
}
|
|
108
|
-
|
|
109
|
-
* Get full my-permissions response from cache
|
|
110
|
-
*
|
|
111
|
-
* @param options - Cache key options
|
|
112
|
-
* @returns Cached permissions data or null if not found
|
|
113
|
-
*/ async getMyPermissions(options) {
|
|
87
|
+
async getMyPermissions(options) {
|
|
114
88
|
try {
|
|
115
89
|
const key = this.generateMyPermissionsCacheKey(options);
|
|
116
90
|
const result = await this.cacheManager.get(key);
|
|
@@ -123,13 +97,8 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
123
97
|
return null;
|
|
124
98
|
}
|
|
125
99
|
}
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
* Cache action codes to IDs mapping
|
|
129
|
-
* Used for parentCodes filter to avoid DB query on cache hit
|
|
130
|
-
*
|
|
131
|
-
* @param codeToIdMap - Map of action code to action ID
|
|
132
|
-
*/ async setActionCodeMap(codeToIdMap) {
|
|
100
|
+
// Action Code Cache Operations
|
|
101
|
+
async setActionCodeMap(codeToIdMap) {
|
|
133
102
|
try {
|
|
134
103
|
const key = `${this.ACTION_CODE_PREFIX}:map`;
|
|
135
104
|
await this.cacheManager.set(key, codeToIdMap, this.ACTION_CODE_TTL);
|
|
@@ -138,12 +107,7 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
138
107
|
this.logger.error(`Failed to cache action code map: ${error}`);
|
|
139
108
|
}
|
|
140
109
|
}
|
|
141
|
-
|
|
142
|
-
* Get action IDs for given codes from cache
|
|
143
|
-
*
|
|
144
|
-
* @param codes - Array of action codes
|
|
145
|
-
* @returns Map of code to ID, or null if not cached
|
|
146
|
-
*/ async getActionIdsByCodes(codes) {
|
|
110
|
+
async getActionIdsByCodes(codes) {
|
|
147
111
|
try {
|
|
148
112
|
const key = `${this.ACTION_CODE_PREFIX}:map`;
|
|
149
113
|
const fullMap = await this.cacheManager.get(key);
|
|
@@ -163,10 +127,7 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
163
127
|
return null;
|
|
164
128
|
}
|
|
165
129
|
}
|
|
166
|
-
|
|
167
|
-
* Invalidate action code cache
|
|
168
|
-
* Call when actions are created, updated, or deleted
|
|
169
|
-
*/ async invalidateActionCodeCache() {
|
|
130
|
+
async invalidateActionCodeCache() {
|
|
170
131
|
try {
|
|
171
132
|
const key = `${this.ACTION_CODE_PREFIX}:map`;
|
|
172
133
|
await this.cacheManager.del(key);
|
|
@@ -175,15 +136,8 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
175
136
|
this.logger.warn(`Failed to invalidate action code cache: ${error}`);
|
|
176
137
|
}
|
|
177
138
|
}
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
* Invalidate cache for specific user
|
|
181
|
-
* Clears both permission codes and my-permissions cache for ALL branches
|
|
182
|
-
*
|
|
183
|
-
* @param userId - User ID
|
|
184
|
-
* @param companyId - Optional company ID
|
|
185
|
-
* @param branchIds - Optional array of branch IDs to invalidate (if not provided, only null branch is cleared)
|
|
186
|
-
*/ async invalidateUser(userId, companyId, branchIds) {
|
|
139
|
+
// Cache Invalidation
|
|
140
|
+
async invalidateUser(userId, companyId, branchIds) {
|
|
187
141
|
try {
|
|
188
142
|
const keysToDelete = [
|
|
189
143
|
// Permission codes cache (for PermissionGuard) - user-based key
|
|
@@ -209,15 +163,7 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
209
163
|
this.logger.warn(`Failed to invalidate user cache for ${userId}: ${error}`);
|
|
210
164
|
}
|
|
211
165
|
}
|
|
212
|
-
|
|
213
|
-
* Invalidate cache for multiple users
|
|
214
|
-
* Useful when role or company permissions change
|
|
215
|
-
*
|
|
216
|
-
* @param userIds - Array of user IDs
|
|
217
|
-
* @param companyId - Optional company ID
|
|
218
|
-
* @param branchIds - Optional array of branch IDs to invalidate for each user
|
|
219
|
-
* @returns Number of users whose cache was invalidated
|
|
220
|
-
*/ async invalidateUsers(userIds, companyId, branchIds) {
|
|
166
|
+
async invalidateUsers(userIds, companyId, branchIds) {
|
|
221
167
|
if (userIds.length === 0) {
|
|
222
168
|
return 0;
|
|
223
169
|
}
|
|
@@ -233,30 +179,14 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
233
179
|
}
|
|
234
180
|
return successCount;
|
|
235
181
|
}
|
|
236
|
-
/**
|
|
237
|
-
* Invalidate cache for all users in company
|
|
238
|
-
* WARNING: Without pattern matching support in HybridCache, this method
|
|
239
|
-
* invalidates individual user caches passed in the userIds array.
|
|
240
|
-
* For true company-wide invalidation, consider upgrading HybridCache with keys() support.
|
|
241
|
-
*
|
|
242
|
-
* @param companyId - Company ID
|
|
243
|
-
* @returns Number of cache entries deleted (always 0 without keys() support)
|
|
244
|
-
*/ async invalidateCompany(companyId) {
|
|
182
|
+
/** Invalidate cache for all users in company (requires userIds via invalidateUsers) */ async invalidateCompany(companyId) {
|
|
245
183
|
// Note: HybridCache doesn't support pattern matching (keys() method)
|
|
246
184
|
// Company-wide invalidation requires passing individual user IDs
|
|
247
185
|
// This is a placeholder that logs a warning
|
|
248
186
|
this.logger.warn(`invalidateCompany called for ${companyId}, but pattern matching is not supported. ` + `Use invalidateUsers() with specific user IDs instead.`);
|
|
249
187
|
return 0;
|
|
250
188
|
}
|
|
251
|
-
|
|
252
|
-
* Invalidate cache for all users with specific role
|
|
253
|
-
*
|
|
254
|
-
* @param roleId - Role ID (for logging)
|
|
255
|
-
* @param userIds - Array of user IDs who have this role
|
|
256
|
-
* @param companyId - Optional company ID
|
|
257
|
-
* @param branchIds - Optional array of branch IDs to invalidate
|
|
258
|
-
* @returns Number of users whose cache was invalidated
|
|
259
|
-
*/ async invalidateRole(roleId, userIds, companyId, branchIds) {
|
|
189
|
+
async invalidateRole(roleId, userIds, companyId, branchIds) {
|
|
260
190
|
if (userIds.length === 0) {
|
|
261
191
|
this.logger.debug(`No users found for role ${roleId}`);
|
|
262
192
|
return 0;
|
|
@@ -267,12 +197,8 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
267
197
|
}
|
|
268
198
|
return count;
|
|
269
199
|
}
|
|
270
|
-
//
|
|
271
|
-
/**
|
|
272
|
-
* Clear all permission caches
|
|
273
|
-
* Uses HybridCache reset methods (memory and redis)
|
|
274
|
-
* WARNING: Use with caution - this affects all caches, not just permissions
|
|
275
|
-
*/ async clearAll() {
|
|
200
|
+
// Administrative Operations
|
|
201
|
+
/** Clear all permission caches (memory and redis) */ async clearAll() {
|
|
276
202
|
try {
|
|
277
203
|
await this.cacheManager.reset(); // Clear memory cache
|
|
278
204
|
await this.cacheManager.resetL2(); // Clear redis cache
|