@flusys/nestjs-iam 7.1.0 → 8.0.0

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 (175) hide show
  1. package/config/index.d.ts +3 -3
  2. package/config/message-keys.d.ts +2 -0
  3. package/controllers/action.controller.d.ts +4 -4
  4. package/controllers/company-action-permission.controller.d.ts +2 -2
  5. package/controllers/index.d.ts +6 -6
  6. package/controllers/my-permission.controller.d.ts +3 -3
  7. package/controllers/role-permission.controller.d.ts +5 -4
  8. package/controllers/role.controller.d.ts +2 -2
  9. package/controllers/user-action-permission.controller.d.ts +5 -4
  10. package/docs/iam-swagger.config.d.ts +2 -2
  11. package/docs/index.d.ts +1 -1
  12. package/dtos/action.dto.d.ts +2 -2
  13. package/dtos/index.d.ts +3 -3
  14. package/dtos/permission.dto.d.ts +16 -0
  15. package/entities/action.entity.d.ts +2 -2
  16. package/entities/index.d.ts +11 -11
  17. package/entities/permission-with-company.entity.d.ts +1 -1
  18. package/entities/role-with-company.entity.d.ts +1 -1
  19. package/entities/role.entity.d.ts +1 -1
  20. package/entities/user-iam-permission.entity.d.ts +1 -1
  21. package/enums/index.d.ts +4 -4
  22. package/fesm/284.js +1316 -0
  23. package/fesm/867.js +3801 -0
  24. package/fesm/chunks/364.js +86 -0
  25. package/fesm/config/index.js +135 -3
  26. package/fesm/controllers/index.js +18 -7
  27. package/fesm/docs/index.js +240 -1
  28. package/fesm/dtos/index.js +1168 -3
  29. package/fesm/entities/index.js +670 -31
  30. package/fesm/enums/index.js +97 -4
  31. package/fesm/helpers/index.js +125 -2
  32. package/fesm/index.js +818 -11
  33. package/fesm/interfaces/index.js +17 -3
  34. package/fesm/modules/index.js +259 -1
  35. package/fesm/runtime.js +134 -0
  36. package/fesm/services/index.js +43 -6
  37. package/fesm/types/index.js +15 -1
  38. package/helpers/company-access.helper.d.ts +2 -2
  39. package/helpers/index.d.ts +2 -2
  40. package/helpers/permission-mode.helper.d.ts +1 -1
  41. package/index.d.ts +11 -11
  42. package/interfaces/action.interface.d.ts +2 -2
  43. package/interfaces/iam-module-options.interface.d.ts +3 -3
  44. package/interfaces/index.d.ts +3 -3
  45. package/modules/iam.module.d.ts +2 -2
  46. package/modules/index.d.ts +1 -1
  47. package/package.json +30 -37
  48. package/services/action.service.d.ts +9 -9
  49. package/services/iam-config.service.d.ts +4 -4
  50. package/services/iam-datasource.service.d.ts +3 -3
  51. package/services/index.d.ts +6 -6
  52. package/services/permission-cache.service.d.ts +5 -5
  53. package/services/permission.service.d.ts +6 -4
  54. package/services/role.service.d.ts +8 -8
  55. package/types/index.d.ts +1 -1
  56. package/cjs/config/event-actions.js +0 -36
  57. package/cjs/config/iam.constants.js +0 -11
  58. package/cjs/config/index.js +0 -20
  59. package/cjs/config/message-keys.js +0 -71
  60. package/cjs/controllers/action.controller.js +0 -174
  61. package/cjs/controllers/action.controller.spec.js +0 -79
  62. package/cjs/controllers/company-action-permission.controller.js +0 -119
  63. package/cjs/controllers/company-action-permission.controller.spec.js +0 -65
  64. package/cjs/controllers/index.js +0 -23
  65. package/cjs/controllers/my-permission.controller.js +0 -147
  66. package/cjs/controllers/my-permission.controller.spec.js +0 -128
  67. package/cjs/controllers/role-permission.controller.js +0 -191
  68. package/cjs/controllers/role-permission.controller.spec.js +0 -140
  69. package/cjs/controllers/role.controller.js +0 -102
  70. package/cjs/controllers/role.controller.spec.js +0 -86
  71. package/cjs/controllers/user-action-permission.controller.js +0 -129
  72. package/cjs/controllers/user-action-permission.controller.spec.js +0 -68
  73. package/cjs/docs/iam-swagger.config.js +0 -209
  74. package/cjs/docs/iam-swagger.config.spec.js +0 -99
  75. package/cjs/docs/index.js +0 -18
  76. package/cjs/dtos/action.dto.js +0 -282
  77. package/cjs/dtos/index.js +0 -21
  78. package/cjs/dtos/permission.dto.js +0 -637
  79. package/cjs/dtos/role.dto.js +0 -155
  80. package/cjs/entities/action.entity.js +0 -138
  81. package/cjs/entities/index.js +0 -80
  82. package/cjs/entities/index.spec.js +0 -56
  83. package/cjs/entities/permission-base.entity.js +0 -107
  84. package/cjs/entities/permission-with-company.entity.js +0 -100
  85. package/cjs/entities/role-base.entity.js +0 -80
  86. package/cjs/entities/role-with-company.entity.js +0 -55
  87. package/cjs/entities/role.entity.js +0 -25
  88. package/cjs/entities/user-iam-permission.entity.js +0 -43
  89. package/cjs/enums/action-type.enum.js +0 -22
  90. package/cjs/enums/iam-entity-type.enum.js +0 -17
  91. package/cjs/enums/iam-permission-type.enum.js +0 -17
  92. package/cjs/enums/index.js +0 -21
  93. package/cjs/enums/permission-type.enum.js +0 -16
  94. package/cjs/helpers/company-access.helper.js +0 -23
  95. package/cjs/helpers/company-access.helper.spec.js +0 -68
  96. package/cjs/helpers/index.js +0 -19
  97. package/cjs/helpers/permission-mode.helper.js +0 -49
  98. package/cjs/helpers/permission-mode.helper.spec.js +0 -54
  99. package/cjs/index.js +0 -28
  100. package/cjs/interfaces/action.interface.js +0 -4
  101. package/cjs/interfaces/iam-module-options.interface.js +0 -4
  102. package/cjs/interfaces/index.js +0 -20
  103. package/cjs/interfaces/role.interface.js +0 -7
  104. package/cjs/modules/iam.module.js +0 -186
  105. package/cjs/modules/iam.module.spec.js +0 -282
  106. package/cjs/modules/index.js +0 -18
  107. package/cjs/services/action.service.js +0 -337
  108. package/cjs/services/action.service.spec.js +0 -351
  109. package/cjs/services/iam-config.service.js +0 -87
  110. package/cjs/services/iam-config.service.spec.js +0 -110
  111. package/cjs/services/iam-datasource.service.js +0 -129
  112. package/cjs/services/iam-datasource.service.spec.js +0 -110
  113. package/cjs/services/index.js +0 -23
  114. package/cjs/services/permission-cache.service.js +0 -544
  115. package/cjs/services/permission-cache.service.spec.js +0 -718
  116. package/cjs/services/permission.service.js +0 -914
  117. package/cjs/services/permission.service.spec.js +0 -918
  118. package/cjs/services/role.service.js +0 -224
  119. package/cjs/services/role.service.spec.js +0 -347
  120. package/cjs/types/index.js +0 -18
  121. package/cjs/types/logic-node.type.js +0 -30
  122. package/fesm/config/event-actions.js +0 -15
  123. package/fesm/config/iam.constants.js +0 -1
  124. package/fesm/config/message-keys.js +0 -35
  125. package/fesm/controllers/action.controller.js +0 -164
  126. package/fesm/controllers/action.controller.spec.js +0 -75
  127. package/fesm/controllers/company-action-permission.controller.js +0 -109
  128. package/fesm/controllers/company-action-permission.controller.spec.js +0 -61
  129. package/fesm/controllers/my-permission.controller.js +0 -137
  130. package/fesm/controllers/my-permission.controller.spec.js +0 -124
  131. package/fesm/controllers/role-permission.controller.js +0 -181
  132. package/fesm/controllers/role-permission.controller.spec.js +0 -136
  133. package/fesm/controllers/role.controller.js +0 -92
  134. package/fesm/controllers/role.controller.spec.js +0 -82
  135. package/fesm/controllers/user-action-permission.controller.js +0 -119
  136. package/fesm/controllers/user-action-permission.controller.spec.js +0 -64
  137. package/fesm/docs/iam-swagger.config.js +0 -199
  138. package/fesm/docs/iam-swagger.config.spec.js +0 -95
  139. package/fesm/dtos/action.dto.js +0 -252
  140. package/fesm/dtos/permission.dto.js +0 -571
  141. package/fesm/dtos/role.dto.js +0 -134
  142. package/fesm/entities/action.entity.js +0 -128
  143. package/fesm/entities/index.spec.js +0 -52
  144. package/fesm/entities/permission-base.entity.js +0 -100
  145. package/fesm/entities/permission-with-company.entity.js +0 -90
  146. package/fesm/entities/role-base.entity.js +0 -70
  147. package/fesm/entities/role-with-company.entity.js +0 -45
  148. package/fesm/entities/role.entity.js +0 -15
  149. package/fesm/entities/user-iam-permission.entity.js +0 -33
  150. package/fesm/enums/action-type.enum.js +0 -12
  151. package/fesm/enums/iam-entity-type.enum.js +0 -7
  152. package/fesm/enums/iam-permission-type.enum.js +0 -7
  153. package/fesm/enums/permission-type.enum.js +0 -6
  154. package/fesm/helpers/company-access.helper.js +0 -18
  155. package/fesm/helpers/company-access.helper.spec.js +0 -64
  156. package/fesm/helpers/permission-mode.helper.js +0 -49
  157. package/fesm/helpers/permission-mode.helper.spec.js +0 -50
  158. package/fesm/interfaces/action.interface.js +0 -3
  159. package/fesm/interfaces/iam-module-options.interface.js +0 -3
  160. package/fesm/interfaces/role.interface.js +0 -4
  161. package/fesm/modules/iam.module.js +0 -176
  162. package/fesm/modules/iam.module.spec.js +0 -278
  163. package/fesm/services/action.service.js +0 -327
  164. package/fesm/services/action.service.spec.js +0 -347
  165. package/fesm/services/iam-config.service.js +0 -77
  166. package/fesm/services/iam-config.service.spec.js +0 -106
  167. package/fesm/services/iam-datasource.service.js +0 -78
  168. package/fesm/services/iam-datasource.service.spec.js +0 -106
  169. package/fesm/services/permission-cache.service.js +0 -527
  170. package/fesm/services/permission-cache.service.spec.js +0 -714
  171. package/fesm/services/permission.service.js +0 -904
  172. package/fesm/services/permission.service.spec.js +0 -914
  173. package/fesm/services/role.service.js +0 -214
  174. package/fesm/services/role.service.spec.js +0 -343
  175. package/fesm/types/logic-node.type.js +0 -27
@@ -1,544 +0,0 @@
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 PermissionCacheKeyOptions () {
13
- return _nestjsshared.PermissionCacheKeyOptions;
14
- },
15
- get PermissionCacheService () {
16
- return PermissionCacheService;
17
- }
18
- });
19
- const _config = require("@flusys/nestjs-core/config");
20
- const _nestjsshared = require("@flusys/nestjs-shared");
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");
34
- function _define_property(obj, key, value) {
35
- if (key in obj) {
36
- Object.defineProperty(obj, key, {
37
- value: value,
38
- enumerable: true,
39
- configurable: true,
40
- writable: true
41
- });
42
- } else {
43
- obj[key] = value;
44
- }
45
- return obj;
46
- }
47
- function _ts_decorate(decorators, target, key, desc) {
48
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
49
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
50
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
51
- return c > 3 && r && Object.defineProperty(target, key, r), r;
52
- }
53
- function _ts_metadata(k, v) {
54
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
55
- }
56
- function _ts_param(paramIndex, decorator) {
57
- return function(target, key) {
58
- decorator(target, key, paramIndex);
59
- };
60
- }
61
- const NO_COMPANY_SCOPE = 'none';
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
- }
77
- // Cache Key Generation
78
- parseDurationMs(duration) {
79
- const unitMs = {
80
- ms: 1,
81
- s: 1000,
82
- m: 60000,
83
- h: 3600000,
84
- d: 86400000,
85
- w: 604800000
86
- };
87
- const match = /^(\d+)\s*(ms|s|m|h|d|w)?$/i.exec(duration.trim());
88
- if (!match) {
89
- return unitMs.h; // fallback: 1 hour
90
- }
91
- const unit = (match[2] || 'ms').toLowerCase();
92
- return Number(match[1]) * unitMs[unit];
93
- }
94
- buildCacheKey(options) {
95
- return (0, _nestjsshared.buildPermissionCacheKey)(options, this.guardConfig);
96
- }
97
- scopeToken(companyId) {
98
- return companyId || NO_COMPANY_SCOPE;
99
- }
100
- buildTrackedKeysKey(userId, companyId) {
101
- return `${this.TRACKED_KEYS_PREFIX}:user:${userId}:company:${this.scopeToken(companyId)}`;
102
- }
103
- buildTrackedScopesKey(userId) {
104
- return `${this.TRACKED_SCOPES_PREFIX}:user:${userId}`;
105
- }
106
- // Cache Operations
107
- async setMyPermissions(options, data) {
108
- const key = this.buildCacheKey(options);
109
- await this.cacheManager.set(key, data, this.TTL);
110
- await this.trackKey(options.userId, key, options.companyId);
111
- }
112
- async getMyPermissions(options) {
113
- try {
114
- const key = this.buildCacheKey(options);
115
- const result = await this.cacheManager.get(key);
116
- return result || null;
117
- } catch {
118
- return null;
119
- }
120
- }
121
- async trackKey(userId, key, companyId) {
122
- try {
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
- }
131
- }
132
- const scopesKey = this.buildTrackedScopesKey(userId);
133
- const scopes = await this.cacheManager.get(scopesKey) || [];
134
- if (!scopes.includes(scopeKey)) {
135
- scopes.push(scopeKey);
136
- await this.cacheManager.set(scopesKey, scopes, this.TTL);
137
- }
138
- } catch {
139
- // tracking is best-effort; a missed entry only widens invalidation, never narrows it
140
- }
141
- }
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);
153
- }
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
- }
166
- }
167
- return {
168
- frontendActions: frontendActions.map((a)=>({
169
- code: a.code,
170
- name: a.name,
171
- description: a.description
172
- })),
173
- cachedEndpoints: cachedData.backendCodes.length
174
- };
175
- }
176
- /** Resolve action IDs for the given codes */ async getParentIdsByCodesWithCache(codes) {
177
- const actionRepo = await this.getActionRepository();
178
- const actions = await actionRepo.find({
179
- where: {
180
- code: (0, _typeorm.In)(codes)
181
- },
182
- select: [
183
- 'id',
184
- 'code'
185
- ]
186
- });
187
- return new Set(actions.map((action)=>action.id));
188
- }
189
- /** Fetch permissions from DB and cache them (empty permissions are also cached) */ async fetchAndCachePermissions(userId, branchId, companyId) {
190
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
191
- const cacheOptions = {
192
- userId,
193
- companyId: enableCompanyFeature ? companyId : null,
194
- branchId
195
- };
196
- const emptyData = {
197
- frontendActions: [],
198
- backendCodes: []
199
- };
200
- const allActionIds = await this.collectAllActionIds(userId, branchId, companyId);
201
- if (allActionIds.size === 0) {
202
- await this.setMyPermissions(cacheOptions, emptyData);
203
- return emptyData;
204
- }
205
- return this.buildAndCachePermissionData(allActionIds, cacheOptions);
206
- }
207
- /** Collect all action IDs based on permission mode (RBAC, DIRECT, or FULL) */ async collectAllActionIds(userId, branchId, companyId) {
208
- const permissionMode = this.iamConfigService.getPermissionMode();
209
- const allActionIds = new Set();
210
- if (permissionMode === _permissiontypeenum.IAMPermissionMode.RBAC || permissionMode === _permissiontypeenum.IAMPermissionMode.FULL) {
211
- const userRoleIds = await this.getUserRoleIds(userId, branchId, companyId);
212
- if (userRoleIds.length > 0) {
213
- const roleActionIds = await this.getRoleActionIds(userRoleIds);
214
- roleActionIds.forEach((id)=>allActionIds.add(id));
215
- }
216
- }
217
- if (permissionMode === _permissiontypeenum.IAMPermissionMode.DIRECT || permissionMode === _permissiontypeenum.IAMPermissionMode.FULL) {
218
- const userActionIds = await this.getUserActionIds(userId, branchId, companyId);
219
- userActionIds.forEach((id)=>allActionIds.add(id));
220
- }
221
- return allActionIds;
222
- }
223
- /** Fetch actions from DB, separate by type, build cache data, and cache it */ async buildAndCachePermissionData(actionIds, cacheOptions) {
224
- const actionRepo = await this.getActionRepository();
225
- const actions = await actionRepo.find({
226
- where: {
227
- id: (0, _typeorm.In)(Array.from(actionIds)),
228
- isActive: true
229
- }
230
- });
231
- const backendActions = actions.filter((a)=>a.actionType === _actiontypeenum.ActionType.BACKEND || a.actionType === _actiontypeenum.ActionType.BOTH);
232
- const frontendActions = actions.filter((a)=>a.actionType === _actiontypeenum.ActionType.FRONTEND || a.actionType === _actiontypeenum.ActionType.BOTH);
233
- const backendCodes = backendActions.map((a)=>a.code).filter((c)=>!!c);
234
- const cacheData = {
235
- frontendActions: frontendActions.map((a)=>({
236
- id: a.id,
237
- code: a.code ?? '',
238
- name: a.name,
239
- description: a.description,
240
- parentId: a.parentId
241
- })),
242
- backendCodes
243
- };
244
- await this.setMyPermissions(cacheOptions, cacheData);
245
- return cacheData;
246
- }
247
- /** Get role IDs assigned to a user (merges company-wide + branch-specific roles) */ async getUserRoleIds(userId, branchId, companyId) {
248
- const permissionRepo = await this.getPermissionRepository();
249
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
250
- if (!enableCompanyFeature) {
251
- const permissions = await permissionRepo.find({
252
- where: {
253
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
254
- sourceType: _iamentitytypeenum.IamEntityType.USER,
255
- sourceId: userId
256
- }
257
- });
258
- return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
259
- }
260
- const roleIds = new Set();
261
- const baseWhere = {
262
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
263
- sourceType: _iamentitytypeenum.IamEntityType.USER,
264
- sourceId: userId
265
- };
266
- if (companyId) {
267
- baseWhere.companyId = companyId;
268
- }
269
- if (branchId) {
270
- // Get company-wide + branch-specific roles
271
- const companyWidePermissions = await permissionRepo.find({
272
- where: {
273
- ...baseWhere,
274
- branchId: (0, _typeorm.IsNull)()
275
- }
276
- });
277
- companyWidePermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
278
- const branchPermissions = await permissionRepo.find({
279
- where: {
280
- ...baseWhere,
281
- branchId
282
- }
283
- });
284
- branchPermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
285
- } else {
286
- // No branch context: get all roles for this company
287
- const allPermissions = await permissionRepo.find({
288
- where: baseWhere
289
- });
290
- allPermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
291
- }
292
- return Array.from(roleIds);
293
- }
294
- async getRoleActionIds(roleIds) {
295
- const permissionRepo = await this.getPermissionRepository();
296
- const permissions = await permissionRepo.find({
297
- where: {
298
- permissionType: _iampermissiontypeenum.IamPermissionType.ROLE_ACTION,
299
- sourceType: _iamentitytypeenum.IamEntityType.ROLE,
300
- sourceId: (0, _typeorm.In)(roleIds)
301
- }
302
- });
303
- return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
304
- }
305
- /** Get action IDs directly assigned to a user (merges company-wide + branch-specific actions) */ async getUserActionIds(userId, branchId, companyId) {
306
- const permissionRepo = await this.getPermissionRepository();
307
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
308
- if (!enableCompanyFeature) {
309
- const permissions = await permissionRepo.find({
310
- where: {
311
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
312
- sourceType: _iamentitytypeenum.IamEntityType.USER,
313
- sourceId: userId
314
- }
315
- });
316
- return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
317
- }
318
- const actionIds = new Set();
319
- const baseWhere = {
320
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
321
- sourceType: _iamentitytypeenum.IamEntityType.USER,
322
- sourceId: userId
323
- };
324
- if (companyId) {
325
- baseWhere.companyId = companyId;
326
- }
327
- if (branchId) {
328
- // Get company-wide + branch-specific actions
329
- const companyWidePermissions = await permissionRepo.find({
330
- where: {
331
- ...baseWhere,
332
- branchId: (0, _typeorm.IsNull)()
333
- }
334
- });
335
- companyWidePermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
336
- const branchPermissions = await permissionRepo.find({
337
- where: {
338
- ...baseWhere,
339
- branchId
340
- }
341
- });
342
- branchPermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
343
- } else {
344
- // No branch context: get all actions for this company
345
- const allPermissions = await permissionRepo.find({
346
- where: baseWhere
347
- });
348
- allPermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
349
- }
350
- return Array.from(actionIds);
351
- }
352
- // Cache Invalidation
353
- async invalidateUser(userId, companyId, branchIds) {
354
- const keysToDelete = new Set();
355
- /** Drop a scope entry from the tracked-scopes index, or queue the whole index for deletion once nothing remains */ const untrackScope = async (scopeKey)=>{
356
- const scopesKeysKey = this.buildTrackedScopesKey(userId);
357
- let scopesKeys = [];
358
- try {
359
- scopesKeys = await this.cacheManager.get(scopesKeysKey) || [];
360
- } catch {
361
- scopesKeys = [];
362
- }
363
- if (scopeKey) {
364
- const remainingScopes = scopesKeys.filter((scope)=>scope !== scopeKey);
365
- if (remainingScopes.length > 0) {
366
- await this.cacheManager.set(scopesKeysKey, remainingScopes, this.TTL);
367
- } else {
368
- keysToDelete.add(scopesKeysKey);
369
- }
370
- } else {
371
- for (const scope of scopesKeys){
372
- if (scope.startsWith(this.TRACKED_KEYS_PREFIX)) {
373
- let nestedKeys = [];
374
- try {
375
- nestedKeys = await this.cacheManager.get(scope) || [];
376
- } catch {
377
- nestedKeys = [];
378
- }
379
- nestedKeys.forEach((key)=>keysToDelete.add(key));
380
- }
381
- keysToDelete.add(scope);
382
- }
383
- keysToDelete.add(scopesKeysKey);
384
- }
385
- };
386
- if (companyId) {
387
- const trackedKeysKey = this.buildTrackedKeysKey(userId, companyId);
388
- let trackedKeys = [];
389
- try {
390
- trackedKeys = await this.cacheManager.get(trackedKeysKey) || [];
391
- } catch {
392
- trackedKeys = [];
393
- }
394
- const hasCompanyWideScope = branchIds?.some((branchId)=>!branchId);
395
- if (!branchIds?.length || hasCompanyWideScope) {
396
- trackedKeys.forEach((key)=>keysToDelete.add(key));
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
- }
413
- }
414
- } else {
415
- await untrackScope();
416
- }
417
- await Promise.all(Array.from(keysToDelete).map(async (key)=>{
418
- try {
419
- await this.cacheManager.del(key);
420
- } catch {}
421
- }));
422
- }
423
- async invalidateUsers(userIds, companyId, branchIds) {
424
- if (userIds.length === 0) {
425
- return 0;
426
- }
427
- const results = await Promise.allSettled(userIds.map((userId)=>this.invalidateUser(userId, companyId, branchIds)));
428
- return results.filter((r)=>r.status === 'fulfilled').length;
429
- }
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){
474
- _define_property(this, "cacheManager", void 0);
475
- _define_property(this, "iamConfigService", void 0);
476
- _define_property(this, "dataSourceProvider", void 0);
477
- _define_property(this, "guardConfig", void 0);
478
- _define_property(this, "TRACKED_KEYS_PREFIX", void 0);
479
- _define_property(this, "TRACKED_SCOPES_PREFIX", void 0);
480
- _define_property(this, "TTL", void 0);
481
- this.cacheManager = cacheManager;
482
- this.iamConfigService = iamConfigService;
483
- this.dataSourceProvider = dataSourceProvider;
484
- this.guardConfig = guardConfig;
485
- this.TRACKED_KEYS_PREFIX = 'permission-tracked-keys';
486
- this.TRACKED_SCOPES_PREFIX = 'permission-tracked-scopes';
487
- this.TTL = this.parseDurationMs(_config.envConfig.getJwtConfig().refreshExpiration);
488
- }
489
- };
490
- _ts_decorate([
491
- (0, _nestjsshared.LogAction)({
492
- action: 'permissionCache.setMyPermissions',
493
- module: 'iam'
494
- }),
495
- _ts_metadata("design:type", Function),
496
- _ts_metadata("design:paramtypes", [
497
- typeof _nestjsshared.PermissionCacheKeyOptions === "undefined" ? Object : _nestjsshared.PermissionCacheKeyOptions,
498
- typeof CachedMyPermissions === "undefined" ? Object : CachedMyPermissions
499
- ]),
500
- _ts_metadata("design:returntype", Promise)
501
- ], PermissionCacheService.prototype, "setMyPermissions", null);
502
- _ts_decorate([
503
- (0, _nestjsshared.LogAction)({
504
- action: 'permissionCache.invalidateUser',
505
- module: 'iam'
506
- }),
507
- _ts_metadata("design:type", Function),
508
- _ts_metadata("design:paramtypes", [
509
- String,
510
- Object,
511
- Array
512
- ]),
513
- _ts_metadata("design:returntype", Promise)
514
- ], PermissionCacheService.prototype, "invalidateUser", null);
515
- _ts_decorate([
516
- (0, _nestjsshared.LogAction)({
517
- action: 'permissionCache.invalidateUsers',
518
- module: 'iam'
519
- }),
520
- _ts_metadata("design:type", Function),
521
- _ts_metadata("design:paramtypes", [
522
- Array,
523
- Object,
524
- Array
525
- ]),
526
- _ts_metadata("design:returntype", Promise)
527
- ], PermissionCacheService.prototype, "invalidateUsers", null);
528
- PermissionCacheService = _ts_decorate([
529
- (0, _common.Injectable)({
530
- scope: _common.Scope.REQUEST
531
- }),
532
- _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
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)),
537
- _ts_metadata("design:type", Function),
538
- _ts_metadata("design:paramtypes", [
539
- typeof _nestjsshared.HybridCache === "undefined" ? Object : _nestjsshared.HybridCache,
540
- typeof _iamconfigservice.IAMConfigService === "undefined" ? Object : _iamconfigservice.IAMConfigService,
541
- typeof _iamdatasourceservice.IAMDataSourceService === "undefined" ? Object : _iamdatasourceservice.IAMDataSourceService,
542
- typeof _nestjsshared.PermissionGuardConfig === "undefined" ? Object : _nestjsshared.PermissionGuardConfig
543
- ])
544
- ], PermissionCacheService);