@flusys/nestjs-iam 6.0.2 → 6.1.1

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.
Files changed (61) hide show
  1. package/cjs/controllers/action.controller.spec.js +79 -0
  2. package/cjs/controllers/company-action-permission.controller.js +1 -1
  3. package/cjs/controllers/company-action-permission.controller.spec.js +65 -0
  4. package/cjs/controllers/my-permission.controller.spec.js +56 -0
  5. package/cjs/controllers/role-permission.controller.spec.js +140 -0
  6. package/cjs/controllers/role.controller.spec.js +86 -0
  7. package/cjs/controllers/user-action-permission.controller.js +1 -1
  8. package/cjs/controllers/user-action-permission.controller.spec.js +68 -0
  9. package/cjs/docs/iam-swagger.config.spec.js +99 -0
  10. package/cjs/dtos/permission.dto.js +7 -0
  11. package/cjs/entities/index.spec.js +56 -0
  12. package/cjs/entities/permission-base.entity.js +1 -10
  13. package/cjs/entities/permission-with-company.entity.js +0 -3
  14. package/cjs/entities/user-iam-permission.entity.js +0 -3
  15. package/cjs/helpers/company-access.helper.spec.js +68 -0
  16. package/cjs/helpers/permission-mode.helper.spec.js +54 -0
  17. package/cjs/modules/iam.module.js +2 -2
  18. package/cjs/modules/iam.module.spec.js +293 -0
  19. package/cjs/services/action.service.js +4 -4
  20. package/cjs/services/action.service.spec.js +314 -0
  21. package/cjs/services/iam-config.service.spec.js +110 -0
  22. package/cjs/services/iam-datasource.service.spec.js +117 -0
  23. package/cjs/services/permission-cache.service.js +363 -52
  24. package/cjs/services/permission-cache.service.spec.js +699 -0
  25. package/cjs/services/permission.service.js +92 -396
  26. package/cjs/services/permission.service.spec.js +692 -0
  27. package/cjs/services/role.service.js +1 -1
  28. package/cjs/services/role.service.spec.js +309 -0
  29. package/dtos/permission.dto.d.ts +1 -0
  30. package/entities/permission-base.entity.d.ts +0 -1
  31. package/fesm/controllers/action.controller.spec.js +75 -0
  32. package/fesm/controllers/company-action-permission.controller.js +1 -1
  33. package/fesm/controllers/company-action-permission.controller.spec.js +61 -0
  34. package/fesm/controllers/my-permission.controller.spec.js +52 -0
  35. package/fesm/controllers/role-permission.controller.spec.js +136 -0
  36. package/fesm/controllers/role.controller.spec.js +82 -0
  37. package/fesm/controllers/user-action-permission.controller.js +1 -1
  38. package/fesm/controllers/user-action-permission.controller.spec.js +64 -0
  39. package/fesm/docs/iam-swagger.config.spec.js +95 -0
  40. package/fesm/dtos/permission.dto.js +7 -0
  41. package/fesm/entities/index.spec.js +52 -0
  42. package/fesm/entities/permission-base.entity.js +1 -10
  43. package/fesm/entities/permission-with-company.entity.js +0 -3
  44. package/fesm/entities/user-iam-permission.entity.js +0 -3
  45. package/fesm/helpers/company-access.helper.spec.js +64 -0
  46. package/fesm/helpers/permission-mode.helper.spec.js +50 -0
  47. package/fesm/modules/iam.module.js +4 -4
  48. package/fesm/modules/iam.module.spec.js +289 -0
  49. package/fesm/services/action.service.js +4 -4
  50. package/fesm/services/action.service.spec.js +310 -0
  51. package/fesm/services/iam-config.service.spec.js +106 -0
  52. package/fesm/services/iam-datasource.service.spec.js +113 -0
  53. package/fesm/services/permission-cache.service.js +365 -51
  54. package/fesm/services/permission-cache.service.spec.js +695 -0
  55. package/fesm/services/permission.service.js +92 -396
  56. package/fesm/services/permission.service.spec.js +688 -0
  57. package/fesm/services/role.service.js +1 -1
  58. package/fesm/services/role.service.spec.js +305 -0
  59. package/package.json +3 -3
  60. package/services/permission-cache.service.d.ts +20 -3
  61. package/services/permission.service.d.ts +2 -16
@@ -9,9 +9,6 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
- get MY_PERMISSIONS_CACHE_PREFIX () {
13
- return MY_PERMISSIONS_CACHE_PREFIX;
14
- },
15
12
  get PermissionCacheKeyOptions () {
16
13
  return _nestjsshared.PermissionCacheKeyOptions;
17
14
  },
@@ -22,6 +19,18 @@ _export(exports, {
22
19
  const _config = require("@flusys/nestjs-core/config");
23
20
  const _nestjsshared = require("@flusys/nestjs-shared");
24
21
  const _common = require("@nestjs/common");
22
+ const _typeorm = require("typeorm");
23
+ const _actionentity = require("../entities/action.entity");
24
+ const _permissionwithcompanyentity = require("../entities/permission-with-company.entity");
25
+ const _rolewithcompanyentity = require("../entities/role-with-company.entity");
26
+ const _roleentity = require("../entities/role.entity");
27
+ const _useriampermissionentity = require("../entities/user-iam-permission.entity");
28
+ const _actiontypeenum = require("../enums/action-type.enum");
29
+ const _iamentitytypeenum = require("../enums/iam-entity-type.enum");
30
+ const _iampermissiontypeenum = require("../enums/iam-permission-type.enum");
31
+ const _permissiontypeenum = require("../enums/permission-type.enum");
32
+ const _iamconfigservice = require("./iam-config.service");
33
+ const _iamdatasourceservice = require("./iam-datasource.service");
25
34
  function _define_property(obj, key, value) {
26
35
  if (key in obj) {
27
36
  Object.defineProperty(obj, key, {
@@ -49,9 +58,22 @@ function _ts_param(paramIndex, decorator) {
49
58
  decorator(target, key, paramIndex);
50
59
  };
51
60
  }
52
- const MY_PERMISSIONS_CACHE_PREFIX = _nestjsshared.PERMISSIONS_CACHE_PREFIX;
53
61
  const NO_COMPANY_SCOPE = 'none';
54
62
  let PermissionCacheService = class PermissionCacheService {
63
+ // Repository Getters
64
+ async getPermissionRepository() {
65
+ const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
66
+ const entity = enableCompanyFeature ? _permissionwithcompanyentity.UserIamPermissionWithCompany : _useriampermissionentity.UserIamPermission;
67
+ return this.dataSourceProvider.getRepository(entity);
68
+ }
69
+ async getActionRepository() {
70
+ return this.dataSourceProvider.getRepository(_actionentity.Action);
71
+ }
72
+ async getRoleRepository() {
73
+ const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
74
+ const entity = enableCompanyFeature ? _rolewithcompanyentity.RoleWithCompany : _roleentity.Role;
75
+ return this.dataSourceProvider.getRepository(entity);
76
+ }
55
77
  // Cache Key Generation
56
78
  parseDurationMs(duration) {
57
79
  const unitMs = {
@@ -98,69 +120,305 @@ let PermissionCacheService = class PermissionCacheService {
98
120
  }
99
121
  async trackKey(userId, key, companyId) {
100
122
  try {
101
- const trackedKeysKey = this.buildTrackedKeysKey(userId, companyId);
102
- const keys = await this.cacheManager.get(trackedKeysKey) || [];
103
- if (!keys.includes(key)) {
104
- keys.push(key);
105
- await this.cacheManager.set(trackedKeysKey, keys, this.TTL);
123
+ let scopeKey = key;
124
+ if (companyId) {
125
+ scopeKey = this.buildTrackedKeysKey(userId, companyId);
126
+ const keys = await this.cacheManager.get(scopeKey) || [];
127
+ if (!keys.includes(key)) {
128
+ keys.push(key);
129
+ await this.cacheManager.set(scopeKey, keys, this.TTL);
130
+ }
106
131
  }
107
132
  const scopesKey = this.buildTrackedScopesKey(userId);
108
133
  const scopes = await this.cacheManager.get(scopesKey) || [];
109
- const scope = this.scopeToken(companyId);
110
- if (!scopes.includes(scope)) {
111
- scopes.push(scope);
134
+ if (!scopes.includes(scopeKey)) {
135
+ scopes.push(scopeKey);
112
136
  await this.cacheManager.set(scopesKey, scopes, this.TTL);
113
137
  }
114
138
  } catch {
115
139
  // tracking is best-effort; a missed entry only widens invalidation, never narrows it
116
140
  }
117
141
  }
118
- // Cache Invalidation
119
- async invalidateUser(userId, companyId, branchIds) {
120
- if (companyId) {
121
- await this.invalidateScope(userId, companyId, branchIds);
122
- return;
142
+ // My Permissions (cache-first read, DB-backed rebuild)
143
+ /** Get user's effective permissions (cache-first approach) */ async getMyPermissionsResponse(userId, branchId, companyId, parentCodes) {
144
+ const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
145
+ const cacheOptions = {
146
+ userId,
147
+ companyId: enableCompanyFeature ? companyId : null,
148
+ branchId: enableCompanyFeature ? branchId : null
149
+ };
150
+ const cachedData = await this.getMyPermissions(cacheOptions);
151
+ if (cachedData) {
152
+ return this.buildResponseFromCache(cachedData, parentCodes);
123
153
  }
124
- // No company scope given: clear every company/branch scope tracked for this user
125
- const scopesKey = this.buildTrackedScopesKey(userId);
126
- let scopes = [];
127
- try {
128
- scopes = await this.cacheManager.get(scopesKey) || [];
129
- } catch {
130
- scopes = [];
154
+ const freshData = await this.fetchAndCachePermissions(userId, branchId, companyId);
155
+ return this.buildResponseFromCache(freshData, parentCodes);
156
+ }
157
+ /** Build response from cached data, applying optional parentCodes filter */ async buildResponseFromCache(cachedData, parentCodes) {
158
+ let frontendActions = cachedData.frontendActions;
159
+ if (parentCodes?.length) {
160
+ const parentIds = await this.getParentIdsByCodesWithCache(parentCodes);
161
+ if (parentIds.size > 0) {
162
+ frontendActions = frontendActions.filter((a)=>a.parentId && parentIds.has(a.parentId));
163
+ } else {
164
+ frontendActions = [];
165
+ }
131
166
  }
132
- await Promise.all(scopes.map((scope)=>this.invalidateScope(userId, scope === NO_COMPANY_SCOPE ? null : scope, branchIds)));
133
- await this.cacheManager.del(scopesKey);
167
+ return {
168
+ frontendActions: frontendActions.map((a)=>({
169
+ id: a.id,
170
+ code: a.code,
171
+ name: a.name,
172
+ description: a.description
173
+ })),
174
+ cachedEndpoints: cachedData.backendCodes.length
175
+ };
134
176
  }
135
- async invalidateScope(userId, companyId, branchIds) {
136
- const keysToDelete = new Set();
137
- const trackedKeysKey = this.buildTrackedKeysKey(userId, companyId);
138
- let trackedKeys = [];
139
- try {
140
- trackedKeys = await this.cacheManager.get(trackedKeysKey) || [];
141
- } catch {
142
- trackedKeys = [];
177
+ /** Resolve action IDs for the given codes */ async getParentIdsByCodesWithCache(codes) {
178
+ const actionRepo = await this.getActionRepository();
179
+ const actions = await actionRepo.find({
180
+ where: {
181
+ code: (0, _typeorm.In)(codes)
182
+ },
183
+ select: [
184
+ 'id',
185
+ 'code'
186
+ ]
187
+ });
188
+ return new Set(actions.map((action)=>action.id));
189
+ }
190
+ /** Fetch permissions from DB and cache them (empty permissions are also cached) */ async fetchAndCachePermissions(userId, branchId, companyId) {
191
+ const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
192
+ const cacheOptions = {
193
+ userId,
194
+ companyId: enableCompanyFeature ? companyId : null,
195
+ branchId
196
+ };
197
+ const emptyData = {
198
+ frontendActions: [],
199
+ backendCodes: []
200
+ };
201
+ const allActionIds = await this.collectAllActionIds(userId, branchId, companyId);
202
+ if (allActionIds.size === 0) {
203
+ await this.setMyPermissions(cacheOptions, emptyData);
204
+ return emptyData;
205
+ }
206
+ return this.buildAndCachePermissionData(allActionIds, cacheOptions);
207
+ }
208
+ /** Collect all action IDs based on permission mode (RBAC, DIRECT, or FULL) */ async collectAllActionIds(userId, branchId, companyId) {
209
+ const permissionMode = this.iamConfigService.getPermissionMode();
210
+ const allActionIds = new Set();
211
+ if (permissionMode === _permissiontypeenum.IAMPermissionMode.RBAC || permissionMode === _permissiontypeenum.IAMPermissionMode.FULL) {
212
+ const userRoleIds = await this.getUserRoleIds(userId, branchId, companyId);
213
+ if (userRoleIds.length > 0) {
214
+ const roleActionIds = await this.getRoleActionIds(userRoleIds);
215
+ roleActionIds.forEach((id)=>allActionIds.add(id));
216
+ }
217
+ }
218
+ if (permissionMode === _permissiontypeenum.IAMPermissionMode.DIRECT || permissionMode === _permissiontypeenum.IAMPermissionMode.FULL) {
219
+ const userActionIds = await this.getUserActionIds(userId, branchId, companyId);
220
+ userActionIds.forEach((id)=>allActionIds.add(id));
221
+ }
222
+ return allActionIds;
223
+ }
224
+ /** Fetch actions from DB, separate by type, build cache data, and cache it */ async buildAndCachePermissionData(actionIds, cacheOptions) {
225
+ const actionRepo = await this.getActionRepository();
226
+ const actions = await actionRepo.find({
227
+ where: {
228
+ id: (0, _typeorm.In)(Array.from(actionIds)),
229
+ isActive: true
230
+ }
231
+ });
232
+ const backendActions = actions.filter((a)=>a.actionType === _actiontypeenum.ActionType.BACKEND || a.actionType === _actiontypeenum.ActionType.BOTH);
233
+ const frontendActions = actions.filter((a)=>a.actionType === _actiontypeenum.ActionType.FRONTEND || a.actionType === _actiontypeenum.ActionType.BOTH);
234
+ const backendCodes = backendActions.map((a)=>a.code).filter((c)=>!!c);
235
+ const cacheData = {
236
+ frontendActions: frontendActions.map((a)=>({
237
+ id: a.id,
238
+ code: a.code ?? '',
239
+ name: a.name,
240
+ description: a.description,
241
+ parentId: a.parentId
242
+ })),
243
+ backendCodes
244
+ };
245
+ await this.setMyPermissions(cacheOptions, cacheData);
246
+ return cacheData;
247
+ }
248
+ /** Get role IDs assigned to a user (merges company-wide + branch-specific roles) */ async getUserRoleIds(userId, branchId, companyId) {
249
+ const permissionRepo = await this.getPermissionRepository();
250
+ const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
251
+ if (!enableCompanyFeature) {
252
+ const permissions = await permissionRepo.find({
253
+ where: {
254
+ permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
255
+ sourceType: _iamentitytypeenum.IamEntityType.USER,
256
+ sourceId: userId
257
+ }
258
+ });
259
+ return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
143
260
  }
144
- if (!branchIds?.length) {
145
- trackedKeys.forEach((key)=>keysToDelete.add(key));
146
- keysToDelete.add(trackedKeysKey);
261
+ const roleIds = new Set();
262
+ const baseWhere = {
263
+ permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
264
+ sourceType: _iamentitytypeenum.IamEntityType.USER,
265
+ sourceId: userId
266
+ };
267
+ if (companyId) {
268
+ baseWhere.companyId = companyId;
269
+ }
270
+ if (branchId) {
271
+ // Get company-wide + branch-specific roles
272
+ const companyWidePermissions = await permissionRepo.find({
273
+ where: {
274
+ ...baseWhere,
275
+ branchId: (0, _typeorm.IsNull)()
276
+ }
277
+ });
278
+ companyWidePermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
279
+ const branchPermissions = await permissionRepo.find({
280
+ where: {
281
+ ...baseWhere,
282
+ branchId
283
+ }
284
+ });
285
+ branchPermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
147
286
  } else {
148
- // Branch scope given: only invalidate those branches, keep the rest tracked
149
- branchIds.forEach((branchId)=>keysToDelete.add(this.buildCacheKey({
150
- userId,
151
- companyId,
287
+ // No branch context: get all roles for this company
288
+ const allPermissions = await permissionRepo.find({
289
+ where: baseWhere
290
+ });
291
+ allPermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
292
+ }
293
+ return Array.from(roleIds);
294
+ }
295
+ async getRoleActionIds(roleIds) {
296
+ const permissionRepo = await this.getPermissionRepository();
297
+ const permissions = await permissionRepo.find({
298
+ where: {
299
+ permissionType: _iampermissiontypeenum.IamPermissionType.ROLE_ACTION,
300
+ sourceType: _iamentitytypeenum.IamEntityType.ROLE,
301
+ sourceId: (0, _typeorm.In)(roleIds)
302
+ }
303
+ });
304
+ return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
305
+ }
306
+ /** Get action IDs directly assigned to a user (merges company-wide + branch-specific actions) */ async getUserActionIds(userId, branchId, companyId) {
307
+ const permissionRepo = await this.getPermissionRepository();
308
+ const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
309
+ if (!enableCompanyFeature) {
310
+ const permissions = await permissionRepo.find({
311
+ where: {
312
+ permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
313
+ sourceType: _iamentitytypeenum.IamEntityType.USER,
314
+ sourceId: userId
315
+ }
316
+ });
317
+ return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
318
+ }
319
+ const actionIds = new Set();
320
+ const baseWhere = {
321
+ permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
322
+ sourceType: _iamentitytypeenum.IamEntityType.USER,
323
+ sourceId: userId
324
+ };
325
+ if (companyId) {
326
+ baseWhere.companyId = companyId;
327
+ }
328
+ if (branchId) {
329
+ // Get company-wide + branch-specific actions
330
+ const companyWidePermissions = await permissionRepo.find({
331
+ where: {
332
+ ...baseWhere,
333
+ branchId: (0, _typeorm.IsNull)()
334
+ }
335
+ });
336
+ companyWidePermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
337
+ const branchPermissions = await permissionRepo.find({
338
+ where: {
339
+ ...baseWhere,
152
340
  branchId
153
- })));
154
- const remainingKeys = trackedKeys.filter((key)=>!keysToDelete.has(key));
155
- if (remainingKeys.length) {
156
- await this.cacheManager.set(trackedKeysKey, remainingKeys, this.TTL);
341
+ }
342
+ });
343
+ branchPermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
344
+ } else {
345
+ // No branch context: get all actions for this company
346
+ const allPermissions = await permissionRepo.find({
347
+ where: baseWhere
348
+ });
349
+ allPermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
350
+ }
351
+ return Array.from(actionIds);
352
+ }
353
+ // Cache Invalidation
354
+ async invalidateUser(userId, companyId, branchIds) {
355
+ const keysToDelete = new Set();
356
+ /** Drop a scope entry from the tracked-scopes index, or queue the whole index for deletion once nothing remains */ const untrackScope = async (scopeKey)=>{
357
+ const scopesKeysKey = this.buildTrackedScopesKey(userId);
358
+ let scopesKeys = [];
359
+ try {
360
+ scopesKeys = await this.cacheManager.get(scopesKeysKey) || [];
361
+ } catch {
362
+ scopesKeys = [];
363
+ }
364
+ if (scopeKey) {
365
+ const remainingScopes = scopesKeys.filter((scope)=>scope !== scopeKey);
366
+ if (remainingScopes.length > 0) {
367
+ await this.cacheManager.set(scopesKeysKey, remainingScopes, this.TTL);
368
+ } else {
369
+ keysToDelete.add(scopesKeysKey);
370
+ }
157
371
  } else {
372
+ for (const scope of scopesKeys){
373
+ if (scope.startsWith(this.TRACKED_KEYS_PREFIX)) {
374
+ let nestedKeys = [];
375
+ try {
376
+ nestedKeys = await this.cacheManager.get(scope) || [];
377
+ } catch {
378
+ nestedKeys = [];
379
+ }
380
+ nestedKeys.forEach((key)=>keysToDelete.add(key));
381
+ }
382
+ keysToDelete.add(scope);
383
+ }
384
+ keysToDelete.add(scopesKeysKey);
385
+ }
386
+ };
387
+ if (companyId) {
388
+ const trackedKeysKey = this.buildTrackedKeysKey(userId, companyId);
389
+ let trackedKeys = [];
390
+ try {
391
+ trackedKeys = await this.cacheManager.get(trackedKeysKey) || [];
392
+ } catch {
393
+ trackedKeys = [];
394
+ }
395
+ if (!branchIds?.length) {
396
+ trackedKeys.forEach((key)=>keysToDelete.add(key));
158
397
  keysToDelete.add(trackedKeysKey);
398
+ await untrackScope(trackedKeysKey);
399
+ } else {
400
+ // Branch scope given: only invalidate those branches, keep the rest tracked
401
+ branchIds.forEach((branchId)=>keysToDelete.add(this.buildCacheKey({
402
+ userId,
403
+ companyId,
404
+ branchId
405
+ })));
406
+ const remainingKeys = trackedKeys.filter((key)=>!keysToDelete.has(key));
407
+ if (remainingKeys.length) {
408
+ await this.cacheManager.set(trackedKeysKey, remainingKeys, this.TTL);
409
+ } else {
410
+ keysToDelete.add(trackedKeysKey);
411
+ await untrackScope(trackedKeysKey);
412
+ }
159
413
  }
414
+ } else {
415
+ await untrackScope();
160
416
  }
161
- await Promise.all([
162
- ...keysToDelete
163
- ].map((key)=>this.cacheManager.del(key)));
417
+ await Promise.all(Array.from(keysToDelete).map(async (key)=>{
418
+ try {
419
+ await this.cacheManager.del(key);
420
+ } catch {}
421
+ }));
164
422
  }
165
423
  async invalidateUsers(userIds, companyId, branchIds) {
166
424
  if (userIds.length === 0) {
@@ -169,13 +427,60 @@ let PermissionCacheService = class PermissionCacheService {
169
427
  const results = await Promise.allSettled(userIds.map((userId)=>this.invalidateUser(userId, companyId, branchIds)));
170
428
  return results.filter((r)=>r.status === 'fulfilled').length;
171
429
  }
172
- constructor(cacheManager, guardConfig){
430
+ /** Invalidate permission cache for all users holding a given role */ async invalidateRoleMembersCache(roleId) {
431
+ const permissionRepo = await this.getPermissionRepository();
432
+ const roleRepo = await this.getRoleRepository();
433
+ const userRoles = await permissionRepo.find({
434
+ where: {
435
+ permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
436
+ sourceType: _iamentitytypeenum.IamEntityType.USER,
437
+ targetType: _iamentitytypeenum.IamEntityType.ROLE,
438
+ targetId: roleId
439
+ }
440
+ });
441
+ const userIds = [
442
+ ...new Set(userRoles.map((ur)=>ur.sourceId))
443
+ ];
444
+ if (userIds.length === 0) {
445
+ return 0;
446
+ }
447
+ const role = await roleRepo.findOne({
448
+ where: {
449
+ id: roleId
450
+ }
451
+ });
452
+ const companyId = role?.companyId || null;
453
+ return this.invalidateUsers(userIds, companyId);
454
+ }
455
+ /** Invalidate permission cache for all users in a company */ async invalidateCompanyMembersCache(companyId) {
456
+ if (!this.iamConfigService.isCompanyFeatureEnabled()) {
457
+ return 0;
458
+ }
459
+ const permissionRepo = await this.getPermissionRepository();
460
+ const userPermissions = await permissionRepo.createQueryBuilder('p').select('DISTINCT p.source_id', 'userId').where('p.company_id = :companyId', {
461
+ companyId
462
+ }).andWhere('p.source_type = :sourceType', {
463
+ sourceType: _iamentitytypeenum.IamEntityType.USER
464
+ }).getRawMany();
465
+ const userIds = [
466
+ ...new Set(userPermissions.map((p)=>p.userId).filter(Boolean))
467
+ ];
468
+ if (userIds.length === 0) {
469
+ return 0;
470
+ }
471
+ return this.invalidateUsers(userIds, companyId);
472
+ }
473
+ constructor(cacheManager, iamConfigService, dataSourceProvider, guardConfig){
173
474
  _define_property(this, "cacheManager", void 0);
475
+ _define_property(this, "iamConfigService", void 0);
476
+ _define_property(this, "dataSourceProvider", void 0);
174
477
  _define_property(this, "guardConfig", void 0);
175
478
  _define_property(this, "TRACKED_KEYS_PREFIX", void 0);
176
479
  _define_property(this, "TRACKED_SCOPES_PREFIX", void 0);
177
480
  _define_property(this, "TTL", void 0);
178
481
  this.cacheManager = cacheManager;
482
+ this.iamConfigService = iamConfigService;
483
+ this.dataSourceProvider = dataSourceProvider;
179
484
  this.guardConfig = guardConfig;
180
485
  this.TRACKED_KEYS_PREFIX = 'permission-tracked-keys';
181
486
  this.TRACKED_SCOPES_PREFIX = 'permission-tracked-scopes';
@@ -221,13 +526,19 @@ _ts_decorate([
221
526
  _ts_metadata("design:returntype", Promise)
222
527
  ], PermissionCacheService.prototype, "invalidateUsers", null);
223
528
  PermissionCacheService = _ts_decorate([
224
- (0, _common.Injectable)(),
529
+ (0, _common.Injectable)({
530
+ scope: _common.Scope.REQUEST
531
+ }),
225
532
  _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
226
- _ts_param(1, (0, _common.Optional)()),
227
- _ts_param(1, (0, _common.Inject)(_nestjsshared.PERMISSION_GUARD_CONFIG)),
533
+ _ts_param(1, (0, _common.Inject)(_iamconfigservice.IAMConfigService)),
534
+ _ts_param(2, (0, _common.Inject)(_iamdatasourceservice.IAMDataSourceService)),
535
+ _ts_param(3, (0, _common.Optional)()),
536
+ _ts_param(3, (0, _common.Inject)(_nestjsshared.PERMISSION_GUARD_CONFIG)),
228
537
  _ts_metadata("design:type", Function),
229
538
  _ts_metadata("design:paramtypes", [
230
539
  typeof _nestjsshared.HybridCache === "undefined" ? Object : _nestjsshared.HybridCache,
540
+ typeof _iamconfigservice.IAMConfigService === "undefined" ? Object : _iamconfigservice.IAMConfigService,
541
+ typeof _iamdatasourceservice.IAMDataSourceService === "undefined" ? Object : _iamdatasourceservice.IAMDataSourceService,
231
542
  typeof _nestjsshared.PermissionGuardConfig === "undefined" ? Object : _nestjsshared.PermissionGuardConfig
232
543
  ])
233
544
  ], PermissionCacheService);