@flusys/nestjs-iam 6.0.0 → 6.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,9 +35,9 @@ import { UserIamPermissionWithCompany } from '../entities/permission-with-compan
35
35
  import { RoleWithCompany } from '../entities/role-with-company.entity';
36
36
  import { Role } from '../entities/role.entity';
37
37
  import { UserIamPermission } from '../entities/user-iam-permission.entity';
38
+ import { ActionType } from '../enums/action-type.enum';
38
39
  import { IamEntityType } from '../enums/iam-entity-type.enum';
39
40
  import { IamPermissionType } from '../enums/iam-permission-type.enum';
40
- import { ActionType } from '../enums/action-type.enum';
41
41
  import { IAMPermissionMode } from '../enums/permission-type.enum';
42
42
  import { IAMConfigService } from './iam-config.service';
43
43
  import { IAMDataSourceService } from './iam-datasource.service';
@@ -57,6 +57,18 @@ export class PermissionService {
57
57
  const entity = enableCompanyFeature ? RoleWithCompany : Role;
58
58
  return this.dataSourceProvider.getRepository(entity);
59
59
  }
60
+ async getActionsMap(actionIds) {
61
+ const actionRepo = await this.getActionRepository();
62
+ const actions = await actionRepo.find({
63
+ where: {
64
+ id: In(actionIds)
65
+ }
66
+ });
67
+ return new Map(actions.map((a)=>[
68
+ a.id,
69
+ a
70
+ ]));
71
+ }
60
72
  // User-Action Permissions
61
73
  async assignUserActions(dto) {
62
74
  if (!this.iamConfigService.isDirectPermissionEnabled()) {
@@ -133,12 +145,13 @@ export class PermissionService {
133
145
  const result = await permissionRepo.delete(whereDelete);
134
146
  removed = result.affected || 0;
135
147
  }
136
- await this.invalidateUserPermissionCache(dto.userId, branchId, companyId);
148
+ await this.permissionCacheService.invalidateUser(dto.userId, enableCompanyFeature ? companyId : null, [
149
+ branchId
150
+ ]);
137
151
  return this.buildOperationResult(dto.items.length, added, removed);
138
152
  }
139
153
  async getUserActions(userId, branchId, companyId) {
140
154
  const permissionRepo = await this.getPermissionRepository();
141
- const actionRepo = await this.getActionRepository();
142
155
  const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
143
156
  const where = {
144
157
  permissionType: IamPermissionType.USER_ACTION,
@@ -156,16 +169,7 @@ export class PermissionService {
156
169
  return [];
157
170
  }
158
171
  const actionIds = permissions.map((p)=>p.targetId);
159
- const actionWhere = {
160
- id: In(actionIds)
161
- };
162
- const actions = await actionRepo.find({
163
- where: actionWhere
164
- });
165
- const actionMap = new Map(actions.map((a)=>[
166
- a.id,
167
- a
168
- ]));
172
+ const actionMap = await this.getActionsMap(actionIds);
169
173
  return permissions.filter((p)=>actionMap.has(p.targetId)).map((p)=>{
170
174
  const action = actionMap.get(p.targetId);
171
175
  return {
@@ -262,7 +266,6 @@ export class PermissionService {
262
266
  }
263
267
  async getRoleActions(roleId) {
264
268
  const permissionRepo = await this.getPermissionRepository();
265
- const actionRepo = await this.getActionRepository();
266
269
  const permissions = await permissionRepo.find({
267
270
  where: {
268
271
  permissionType: IamPermissionType.ROLE_ACTION,
@@ -274,16 +277,7 @@ export class PermissionService {
274
277
  return [];
275
278
  }
276
279
  const actionIds = permissions.map((p)=>p.targetId);
277
- const actionWhere = {
278
- id: In(actionIds)
279
- };
280
- const actions = await actionRepo.find({
281
- where: actionWhere
282
- });
283
- const actionMap = new Map(actions.map((a)=>[
284
- a.id,
285
- a
286
- ]));
280
+ const actionMap = await this.getActionsMap(actionIds);
287
281
  return permissions.filter((p)=>actionMap.has(p.targetId)).map((p)=>{
288
282
  const action = actionMap.get(p.targetId);
289
283
  return {
@@ -310,8 +304,7 @@ export class PermissionService {
310
304
  }
311
305
  if (itemsToRemove.length > 0) {
312
306
  const actionIdsToRemove = itemsToRemove.map((item)=>item.id);
313
- const cascadeResult = await this.removeCompanyActionsWithCascade(manager, dto.companyId, actionIdsToRemove);
314
- removed = cascadeResult.removedCompanyActions;
307
+ removed = await this.removeCompanyActionsWithCascade(manager, dto.companyId, actionIdsToRemove);
315
308
  }
316
309
  });
317
310
  await this.invalidateCompanyMembersCache(dto.companyId);
@@ -367,37 +360,28 @@ export class PermissionService {
367
360
  'id'
368
361
  ]
369
362
  });
370
- let removedRoleActions = 0;
371
- let removedUserActions = 0;
372
363
  if (companyRoles.length > 0) {
373
364
  const roleIds = companyRoles.map((role)=>role.id);
374
- const roleResult = await permissionRepo.delete({
365
+ await permissionRepo.delete({
375
366
  permissionType: IamPermissionType.ROLE_ACTION,
376
367
  sourceType: IamEntityType.ROLE,
377
368
  sourceId: In(roleIds),
378
369
  targetType: IamEntityType.ACTION,
379
370
  targetId: In(actionIds)
380
371
  });
381
- removedRoleActions = roleResult.affected || 0;
382
372
  }
383
373
  if (this.iamConfigService.isCompanyFeatureEnabled()) {
384
- const userResult = await permissionRepo.delete({
374
+ await permissionRepo.delete({
385
375
  permissionType: IamPermissionType.USER_ACTION,
386
376
  companyId,
387
377
  targetType: IamEntityType.ACTION,
388
378
  targetId: In(actionIds)
389
379
  });
390
- removedUserActions = userResult.affected || 0;
391
380
  }
392
- return {
393
- removedCompanyActions: companyResult.affected || 0,
394
- removedRoleActions,
395
- removedUserActions
396
- };
381
+ return companyResult.affected || 0;
397
382
  }
398
383
  /** Get all actions assigned to a company (whitelist) */ async getCompanyActions(companyId) {
399
384
  const permissionRepo = await this.getPermissionRepository();
400
- const actionRepo = await this.getActionRepository();
401
385
  const permissions = await permissionRepo.find({
402
386
  where: {
403
387
  permissionType: IamPermissionType.COMPANY_ACTION,
@@ -409,15 +393,7 @@ export class PermissionService {
409
393
  return [];
410
394
  }
411
395
  const actionIds = permissions.map((p)=>p.targetId);
412
- const actions = await actionRepo.find({
413
- where: {
414
- id: In(actionIds)
415
- }
416
- });
417
- const actionMap = new Map(actions.map((a)=>[
418
- a.id,
419
- a
420
- ]));
396
+ const actionMap = await this.getActionsMap(actionIds);
421
397
  return permissions.filter((p)=>actionMap.has(p.targetId)).map((p)=>{
422
398
  const action = actionMap.get(p.targetId);
423
399
  return {
@@ -520,7 +496,9 @@ export class PermissionService {
520
496
  const result = await permissionRepo.delete(whereDelete);
521
497
  removed = result.affected || 0;
522
498
  }
523
- await this.invalidateUserPermissionCache(dto.userId, branchId, companyId);
499
+ await this.permissionCacheService.invalidateUser(dto.userId, enableCompanyFeature ? companyId : null, [
500
+ branchId
501
+ ]);
524
502
  return this.buildOperationResult(dto.items.length, added, removed);
525
503
  }
526
504
  /** Get user's roles (branch-scoped, filtered by companyId and branchId if provided) */ async getUserRoles(userId, branchId, companyId) {
@@ -571,9 +549,8 @@ export class PermissionService {
571
549
  const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
572
550
  const cacheOptions = {
573
551
  userId,
574
- companyId,
575
- branchId,
576
- enableCompanyFeature
552
+ companyId: enableCompanyFeature ? companyId : null,
553
+ branchId
577
554
  };
578
555
  const cachedData = await this.permissionCacheService.getMyPermissions(cacheOptions);
579
556
  if (cachedData) {
@@ -602,42 +579,25 @@ export class PermissionService {
602
579
  cachedEndpoints: cachedData.backendCodes.length
603
580
  };
604
581
  }
605
- /** Get current tenant ID for multi-tenant cache keys */ getCurrentTenantId() {
606
- if (!this.iamConfigService.isMultiTenant()) {
607
- return undefined;
608
- }
609
- const tenant = this.dataSourceProvider.getCurrentTenant();
610
- return tenant?.id;
611
- }
612
- /** Get parent IDs by codes, using cache first (tenant-aware) */ async getParentIdsByCodesWithCache(codes) {
613
- const tenantId = this.getCurrentTenantId();
614
- const cachedMap = await this.permissionCacheService.getActionIdsByCodes(codes, tenantId);
615
- if (cachedMap) {
616
- return new Set(Object.values(cachedMap));
617
- }
582
+ /** Resolve action IDs for the given codes */ async getParentIdsByCodesWithCache(codes) {
618
583
  const actionRepo = await this.getActionRepository();
619
- const allActions = await actionRepo.find({
584
+ const actions = await actionRepo.find({
585
+ where: {
586
+ code: In(codes)
587
+ },
620
588
  select: [
621
589
  'id',
622
590
  'code'
623
591
  ]
624
592
  });
625
- const fullMap = {};
626
- for (const action of allActions){
627
- if (action.code) {
628
- fullMap[action.code] = action.id;
629
- }
630
- }
631
- await this.permissionCacheService.setActionCodeMap(fullMap, tenantId);
632
- return new Set(codes.map((code)=>fullMap[code]).filter(Boolean));
593
+ return new Set(actions.map((action)=>action.id));
633
594
  }
634
595
  /** Fetch permissions from DB and cache them (empty permissions are also cached) */ async fetchAndCachePermissions(userId, branchId, companyId) {
635
596
  const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
636
597
  const cacheOptions = {
637
598
  userId,
638
- companyId,
639
- branchId,
640
- enableCompanyFeature
599
+ companyId: enableCompanyFeature ? companyId : null,
600
+ branchId
641
601
  };
642
602
  const emptyData = {
643
603
  frontendActions: [],
@@ -690,7 +650,8 @@ export class PermissionService {
690
650
  const actionRepo = await this.getActionRepository();
691
651
  const actions = await actionRepo.find({
692
652
  where: {
693
- id: In(Array.from(actionIds))
653
+ id: In(Array.from(actionIds)),
654
+ isActive: true
694
655
  }
695
656
  });
696
657
  const backendActions = actions.filter((a)=>a.actionType === ActionType.BACKEND || a.actionType === ActionType.BOTH);
@@ -706,10 +667,7 @@ export class PermissionService {
706
667
  })),
707
668
  backendCodes
708
669
  };
709
- await Promise.all([
710
- this.permissionCacheService.setMyPermissions(cacheOptions, cacheData),
711
- this.permissionCacheService.setPermissions(cacheOptions, backendCodes)
712
- ]);
670
+ await this.permissionCacheService.setMyPermissions(cacheOptions, cacheData);
713
671
  return cacheData;
714
672
  }
715
673
  // Helper Methods
@@ -743,9 +701,11 @@ export class PermissionService {
743
701
  const baseWhere = {
744
702
  permissionType: IamPermissionType.USER_ROLE,
745
703
  sourceType: IamEntityType.USER,
746
- sourceId: userId,
747
- companyId: companyId
704
+ sourceId: userId
748
705
  };
706
+ if (companyId) {
707
+ baseWhere.companyId = companyId;
708
+ }
749
709
  if (branchId) {
750
710
  // Get company-wide + branch-specific roles
751
711
  const companyWidePermissions = await permissionRepo.find({
@@ -829,14 +789,6 @@ export class PermissionService {
829
789
  }
830
790
  return Array.from(actionIds);
831
791
  }
832
- /** Invalidate permission cache for a user */ async invalidateUserPermissionCache(userId, branchId, companyId) {
833
- const branchIds = branchId !== undefined ? [
834
- branchId
835
- ] : [
836
- null
837
- ];
838
- await this.permissionCacheService.invalidateUser(userId, companyId, branchIds);
839
- }
840
792
  async invalidateRoleMembersCache(roleId) {
841
793
  const permissionRepo = await this.getPermissionRepository();
842
794
  const roleRepo = await this.getRoleRepository();
@@ -874,7 +826,7 @@ export class PermissionService {
874
826
  ...new Set(userBranches.map((p)=>p.branchId))
875
827
  ];
876
828
  }
877
- return this.permissionCacheService.invalidateRole(roleId, userIds, companyId, branchIds);
829
+ return this.permissionCacheService.invalidateUsers(userIds, companyId, branchIds);
878
830
  }
879
831
  /** Invalidate permission cache for all users in a company */ async invalidateCompanyMembersCache(companyId) {
880
832
  if (!this.iamConfigService.isCompanyFeatureEnabled()) {
@@ -895,6 +847,127 @@ export class PermissionService {
895
847
  }
896
848
  return await this.permissionCacheService.invalidateUsers(userIds, companyId, branchIds);
897
849
  }
850
+ async revokeCompanyPermissions(companyId) {
851
+ if (!this.iamConfigService.isCompanyFeatureEnabled()) {
852
+ return;
853
+ }
854
+ const permissionRepo = await this.getPermissionRepository();
855
+ const roleRepo = await this.getRoleRepository();
856
+ const dataSource = permissionRepo.manager.connection;
857
+ const companyRoles = await roleRepo.find({
858
+ where: {
859
+ companyId,
860
+ deletedAt: IsNull()
861
+ },
862
+ select: [
863
+ 'id'
864
+ ]
865
+ });
866
+ const roleIds = companyRoles.map((role)=>role.id);
867
+ const affectedUserRows = await permissionRepo.find({
868
+ where: {
869
+ permissionType: In([
870
+ IamPermissionType.USER_ROLE,
871
+ IamPermissionType.USER_ACTION
872
+ ]),
873
+ companyId
874
+ },
875
+ select: [
876
+ 'userId'
877
+ ]
878
+ });
879
+ const affectedUserIds = [
880
+ ...new Set(affectedUserRows.map((row)=>row.userId).filter((id)=>!!id))
881
+ ];
882
+ await dataSource.transaction(async (manager)=>{
883
+ const txRepo = manager.getRepository(permissionRepo.target);
884
+ await txRepo.delete({
885
+ permissionType: IamPermissionType.COMPANY_ACTION,
886
+ sourceType: IamEntityType.COMPANY,
887
+ sourceId: companyId
888
+ });
889
+ if (roleIds.length > 0) {
890
+ await txRepo.delete({
891
+ permissionType: IamPermissionType.ROLE_ACTION,
892
+ sourceType: IamEntityType.ROLE,
893
+ sourceId: In(roleIds)
894
+ });
895
+ }
896
+ await txRepo.delete({
897
+ permissionType: In([
898
+ IamPermissionType.USER_ROLE,
899
+ IamPermissionType.USER_ACTION
900
+ ]),
901
+ companyId
902
+ });
903
+ if (roleIds.length > 0) {
904
+ const txRoleRepo = manager.getRepository(roleRepo.target);
905
+ await txRoleRepo.delete(roleIds);
906
+ }
907
+ });
908
+ if (affectedUserIds.length > 0) {
909
+ await this.permissionCacheService.invalidateUsers(affectedUserIds, companyId);
910
+ }
911
+ }
912
+ async revokeBranchPermissions(branchId, companyId) {
913
+ if (!this.iamConfigService.isCompanyFeatureEnabled()) {
914
+ return;
915
+ }
916
+ const permissionRepo = await this.getPermissionRepository();
917
+ const where = {
918
+ permissionType: In([
919
+ IamPermissionType.USER_ROLE,
920
+ IamPermissionType.USER_ACTION
921
+ ]),
922
+ branchId,
923
+ companyId
924
+ };
925
+ const affectedUserRows = await permissionRepo.find({
926
+ where,
927
+ select: [
928
+ 'userId'
929
+ ]
930
+ });
931
+ const affectedUserIds = [
932
+ ...new Set(affectedUserRows.map((row)=>row.userId).filter((id)=>!!id))
933
+ ];
934
+ await permissionRepo.delete(where);
935
+ if (affectedUserIds.length > 0) {
936
+ await this.permissionCacheService.invalidateUsers(affectedUserIds, companyId, [
937
+ branchId
938
+ ]);
939
+ }
940
+ }
941
+ async revokeUserCompanyAccess(userId, companyId) {
942
+ const permissionRepo = await this.getPermissionRepository();
943
+ await permissionRepo.delete({
944
+ permissionType: In([
945
+ IamPermissionType.USER_ROLE,
946
+ IamPermissionType.USER_ACTION
947
+ ]),
948
+ sourceType: IamEntityType.USER,
949
+ sourceId: userId,
950
+ companyId
951
+ });
952
+ await this.permissionCacheService.invalidateUser(userId, companyId);
953
+ }
954
+ async revokeUserBranchAccess(userId, branchId, companyId) {
955
+ const permissionRepo = await this.getPermissionRepository();
956
+ const where = {
957
+ permissionType: In([
958
+ IamPermissionType.USER_ROLE,
959
+ IamPermissionType.USER_ACTION
960
+ ]),
961
+ sourceType: IamEntityType.USER,
962
+ sourceId: userId,
963
+ branchId,
964
+ companyId
965
+ };
966
+ await permissionRepo.delete(where);
967
+ await this.permissionCacheService.invalidateUser(userId, companyId, [
968
+ branchId
969
+ ]);
970
+ }
898
971
  // NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
899
972
  constructor(permissionCacheService, iamConfigService, dataSourceProvider){
900
973
  _define_property(this, "permissionCacheService", void 0);
@@ -949,6 +1022,54 @@ _ts_decorate([
949
1022
  ]),
950
1023
  _ts_metadata("design:returntype", Promise)
951
1024
  ], PermissionService.prototype, "assignUserRoles", null);
1025
+ _ts_decorate([
1026
+ LogAction({
1027
+ action: 'iam.revokeCompanyPermissions',
1028
+ module: 'iam'
1029
+ }),
1030
+ _ts_metadata("design:type", Function),
1031
+ _ts_metadata("design:paramtypes", [
1032
+ String
1033
+ ]),
1034
+ _ts_metadata("design:returntype", Promise)
1035
+ ], PermissionService.prototype, "revokeCompanyPermissions", null);
1036
+ _ts_decorate([
1037
+ LogAction({
1038
+ action: 'iam.revokeBranchPermissions',
1039
+ module: 'iam'
1040
+ }),
1041
+ _ts_metadata("design:type", Function),
1042
+ _ts_metadata("design:paramtypes", [
1043
+ String,
1044
+ String
1045
+ ]),
1046
+ _ts_metadata("design:returntype", Promise)
1047
+ ], PermissionService.prototype, "revokeBranchPermissions", null);
1048
+ _ts_decorate([
1049
+ LogAction({
1050
+ action: 'iam.revokeUserCompanyAccess',
1051
+ module: 'iam'
1052
+ }),
1053
+ _ts_metadata("design:type", Function),
1054
+ _ts_metadata("design:paramtypes", [
1055
+ String,
1056
+ String
1057
+ ]),
1058
+ _ts_metadata("design:returntype", Promise)
1059
+ ], PermissionService.prototype, "revokeUserCompanyAccess", null);
1060
+ _ts_decorate([
1061
+ LogAction({
1062
+ action: 'iam.revokeUserBranchAccess',
1063
+ module: 'iam'
1064
+ }),
1065
+ _ts_metadata("design:type", Function),
1066
+ _ts_metadata("design:paramtypes", [
1067
+ String,
1068
+ String,
1069
+ String
1070
+ ]),
1071
+ _ts_metadata("design:returntype", Promise)
1072
+ ], PermissionService.prototype, "revokeUserBranchAccess", null);
952
1073
  PermissionService = _ts_decorate([
953
1074
  Injectable({
954
1075
  scope: Scope.REQUEST
@@ -25,15 +25,57 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
- import { HybridCache, ApiService } from '@flusys/nestjs-shared/classes';
28
+ import { ApiService, HybridCache } from '@flusys/nestjs-shared/classes';
29
29
  import { UtilsService } from '@flusys/nestjs-shared/modules';
30
30
  import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
31
31
  import { Inject, Injectable, Scope } from '@nestjs/common';
32
+ import { In } from 'typeorm';
33
+ import { UserIamPermissionWithCompany } from '../entities/permission-with-company.entity';
32
34
  import { RoleWithCompany } from '../entities/role-with-company.entity';
33
35
  import { Role } from '../entities/role.entity';
36
+ import { UserIamPermission } from '../entities/user-iam-permission.entity';
37
+ import { IamEntityType } from '../enums/iam-entity-type.enum';
38
+ import { IamPermissionType } from '../enums/iam-permission-type.enum';
34
39
  import { IAMConfigService } from './iam-config.service';
35
40
  import { IAMDataSourceService } from './iam-datasource.service';
41
+ import { PermissionCacheService } from './permission-cache.service';
36
42
  export class RoleService extends ApiService {
43
+ async beforeDeleteOperation(dto, user, queryRunner) {
44
+ await super.beforeDeleteOperation(dto, user, queryRunner);
45
+ const roleIds = Array.isArray(dto.id) ? dto.id : [
46
+ dto.id
47
+ ];
48
+ if (roleIds.length === 0) {
49
+ return;
50
+ }
51
+ const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
52
+ const permissionEntity = enableCompanyFeature ? UserIamPermissionWithCompany : UserIamPermission;
53
+ const permissionRepo = queryRunner.manager.getRepository(permissionEntity);
54
+ const userRoleRows = await permissionRepo.find({
55
+ where: {
56
+ permissionType: IamPermissionType.USER_ROLE,
57
+ sourceType: IamEntityType.USER,
58
+ targetType: IamEntityType.ROLE,
59
+ targetId: In(roleIds)
60
+ }
61
+ });
62
+ const affectedUserIds = [
63
+ ...new Set(userRoleRows.map((row)=>row.userId).filter((id)=>!!id))
64
+ ];
65
+ await permissionRepo.delete({
66
+ permissionType: IamPermissionType.ROLE_ACTION,
67
+ sourceType: IamEntityType.ROLE,
68
+ sourceId: In(roleIds)
69
+ });
70
+ await permissionRepo.delete({
71
+ permissionType: IamPermissionType.USER_ROLE,
72
+ targetType: IamEntityType.ROLE,
73
+ targetId: In(roleIds)
74
+ });
75
+ if (affectedUserIds.length > 0) {
76
+ await this.permissionCacheService.invalidateUsers(affectedUserIds);
77
+ }
78
+ }
37
79
  resolveEntity() {
38
80
  return this.iamConfigService.isCompanyFeatureEnabled() ? RoleWithCompany : Role;
39
81
  }
@@ -107,8 +149,8 @@ export class RoleService extends ApiService {
107
149
  deletedById: entity.deletedById
108
150
  };
109
151
  }
110
- constructor(cacheManager, utilsService, iamConfigService, dataSourceProvider){
111
- super('role', cacheManager, utilsService, RoleService.name, true, 'iam', undefined, dataSourceProvider), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService;
152
+ constructor(cacheManager, utilsService, iamConfigService, dataSourceProvider, permissionCacheService){
153
+ super('role', cacheManager, utilsService, RoleService.name, true, 'iam', undefined, dataSourceProvider), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "permissionCacheService", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.permissionCacheService = permissionCacheService;
112
154
  }
113
155
  }
114
156
  RoleService = _ts_decorate([
@@ -119,11 +161,13 @@ RoleService = _ts_decorate([
119
161
  _ts_param(1, Inject(UtilsService)),
120
162
  _ts_param(2, Inject(IAMConfigService)),
121
163
  _ts_param(3, Inject(IAMDataSourceService)),
164
+ _ts_param(4, Inject(PermissionCacheService)),
122
165
  _ts_metadata("design:type", Function),
123
166
  _ts_metadata("design:paramtypes", [
124
167
  typeof HybridCache === "undefined" ? Object : HybridCache,
125
168
  typeof UtilsService === "undefined" ? Object : UtilsService,
126
169
  typeof IAMConfigService === "undefined" ? Object : IAMConfigService,
127
- typeof IAMDataSourceService === "undefined" ? Object : IAMDataSourceService
170
+ typeof IAMDataSourceService === "undefined" ? Object : IAMDataSourceService,
171
+ typeof PermissionCacheService === "undefined" ? Object : PermissionCacheService
128
172
  ])
129
173
  ], RoleService);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-iam",
3
- "version": "6.0.0",
3
+ "version": "6.0.2",
4
4
  "description": "Identity and Access Management (IAM) module for NestJS applications",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -90,7 +90,7 @@
90
90
  "express": "^5.0.0"
91
91
  },
92
92
  "dependencies": {
93
- "@flusys/nestjs-core": "6.0.0",
94
- "@flusys/nestjs-shared": "6.0.0"
93
+ "@flusys/nestjs-core": "6.0.2",
94
+ "@flusys/nestjs-shared": "6.0.2"
95
95
  }
96
96
  }
@@ -1,19 +1,23 @@
1
1
  import { ApiService, HybridCache } from '@flusys/nestjs-shared/classes';
2
+ import { DeleteDto } from '@flusys/nestjs-shared/dtos';
2
3
  import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
3
4
  import { UtilsService } from '@flusys/nestjs-shared/modules';
4
- import { SelectQueryBuilder } from 'typeorm';
5
+ import { QueryRunner, SelectQueryBuilder } from 'typeorm';
5
6
  import { CreateActionDto, UpdateActionDto } from '../dtos/action.dto';
6
7
  import { Action } from '../entities/action.entity';
7
8
  import { IAction, IActionTree } from '../interfaces/action.interface';
8
9
  import { IAMConfigService } from './iam-config.service';
9
10
  import { IAMDataSourceService } from './iam-datasource.service';
11
+ import { PermissionCacheService } from './permission-cache.service';
10
12
  import { PermissionService } from './permission.service';
11
13
  export declare class ActionService extends ApiService<CreateActionDto, UpdateActionDto, IAction, Action> {
12
14
  protected cacheManager: HybridCache;
13
15
  protected utilsService: UtilsService;
14
16
  private readonly iamConfigService;
15
17
  private readonly permissionService;
16
- constructor(cacheManager: HybridCache, utilsService: UtilsService, iamConfigService: IAMConfigService, dataSourceProvider: IAMDataSourceService, permissionService: PermissionService);
18
+ private readonly permissionCacheService;
19
+ constructor(cacheManager: HybridCache, utilsService: UtilsService, iamConfigService: IAMConfigService, dataSourceProvider: IAMDataSourceService, permissionService: PermissionService, permissionCacheService: PermissionCacheService);
20
+ protected beforeDeleteOperation(dto: DeleteDto, user: ILoggedUserInfo | null, queryRunner: QueryRunner): Promise<void>;
17
21
  getSelectQuery(query: SelectQueryBuilder<Action>, _user: ILoggedUserInfo | null, select?: string[]): Promise<{
18
22
  query: SelectQueryBuilder<Action>;
19
23
  isRaw: boolean;
@@ -25,7 +29,7 @@ export declare class ActionService extends ApiService<CreateActionDto, UpdateAct
25
29
  protected convertEntityToResponseDto(entity: Action, _isRaw: boolean): IAction;
26
30
  private readonly actionSelectFields;
27
31
  private requireUser;
28
- getActionsForPermission(user: ILoggedUserInfo): Promise<IAction[]>;
32
+ getActionsForPermission(user: ILoggedUserInfo, companyId?: string): Promise<IAction[]>;
29
33
  getActionTree(user: ILoggedUserInfo, search?: string, isActive?: boolean, withDeleted?: boolean): Promise<IActionTree[]>;
30
34
  private buildActionTree;
31
35
  }
@@ -1,10 +1,5 @@
1
- import { HybridCache } from '@flusys/nestjs-shared';
2
- export interface PermissionCacheKeyOptions {
3
- userId: string;
4
- companyId?: string | null;
5
- branchId?: string | null;
6
- enableCompanyFeature: boolean;
7
- }
1
+ import { HybridCache, PermissionCacheKeyOptions, PermissionGuardConfig } from '@flusys/nestjs-shared';
2
+ export { PermissionCacheKeyOptions } from '@flusys/nestjs-shared';
8
3
  export interface CachedMyPermissions {
9
4
  frontendActions: Array<{
10
5
  id: string;
@@ -15,24 +10,23 @@ export interface CachedMyPermissions {
15
10
  }>;
16
11
  backendCodes: string[];
17
12
  }
13
+ export declare const MY_PERMISSIONS_CACHE_PREFIX = "my-permissions";
18
14
  export declare class PermissionCacheService {
19
15
  private readonly cacheManager;
16
+ private readonly guardConfig?;
17
+ private readonly TRACKED_KEYS_PREFIX;
18
+ private readonly TRACKED_SCOPES_PREFIX;
20
19
  private readonly TTL;
21
- private readonly ACTION_CODE_TTL;
22
- private readonly CACHE_PREFIX;
23
- private readonly MY_PERMISSIONS_PREFIX;
24
- private readonly ACTION_CODE_PREFIX;
25
- constructor(cacheManager: HybridCache);
26
- generateCacheKey(options: PermissionCacheKeyOptions): string;
27
- generateMyPermissionsCacheKey(options: PermissionCacheKeyOptions): string;
20
+ constructor(cacheManager: HybridCache, guardConfig?: PermissionGuardConfig | undefined);
21
+ private parseDurationMs;
28
22
  private buildCacheKey;
29
- setPermissions(options: PermissionCacheKeyOptions, permissions: string[]): Promise<void>;
23
+ private scopeToken;
24
+ private buildTrackedKeysKey;
25
+ private buildTrackedScopesKey;
30
26
  setMyPermissions(options: PermissionCacheKeyOptions, data: CachedMyPermissions): Promise<void>;
31
27
  getMyPermissions(options: PermissionCacheKeyOptions): Promise<CachedMyPermissions | null>;
32
- private generateActionCodeCacheKey;
33
- setActionCodeMap(codeToIdMap: Record<string, string>, tenantId?: string): Promise<void>;
34
- getActionIdsByCodes(codes: string[], tenantId?: string): Promise<Record<string, string> | null>;
28
+ private trackKey;
35
29
  invalidateUser(userId: string, companyId?: string | null, branchIds?: (string | null)[]): Promise<void>;
30
+ private invalidateScope;
36
31
  invalidateUsers(userIds: string[], companyId?: string | null, branchIds?: (string | null)[]): Promise<number>;
37
- invalidateRole(_roleId: string, userIds: string[], companyId?: string | null, branchIds?: (string | null)[]): Promise<number>;
38
32
  }