@flusys/nestjs-shared 6.0.1 → 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.
@@ -60,5 +60,5 @@ const PERMISSION_GUARD_CONFIG = 'PERMISSION_GUARD_CONFIG';
60
60
  const IDEMPOTENCY_KEY_HEADER = 'x-idempotency-key';
61
61
  const REQUEST_ID_HEADER = 'x-request-id';
62
62
  const CLIENT_TYPE_HEADER = 'x-client-type';
63
- const PERMISSIONS_CACHE_PREFIX = 'permissions';
63
+ const PERMISSIONS_CACHE_PREFIX = 'my-permissions';
64
64
  const IDEMPOTENCY_CACHE_PREFIX = 'idempotency';
@@ -14,6 +14,7 @@ const _hybridcacheclass = require("../classes/hybrid-cache.class");
14
14
  const _constants = require("../constants");
15
15
  const _permissionexception = require("../exceptions/permission.exception");
16
16
  const _permissioninterface = require("../interfaces/permission.interface");
17
+ const _permissioncachekeyutil = require("../utils/permission-cache-key.util");
17
18
  function _define_property(obj, key, value) {
18
19
  if (key in obj) {
19
20
  Object.defineProperty(obj, key, {
@@ -157,14 +158,14 @@ let PermissionGuard = class PermissionGuard {
157
158
  }
158
159
  async getUserPermissions(user) {
159
160
  if (!this.cache) throw new _permissionexception.PermissionSystemUnavailableException();
160
- const cacheKey = this.buildPermissionCacheKey(user);
161
- return await this.cache.get(cacheKey) || [];
162
- }
163
- buildPermissionCacheKey(user) {
164
- if (this.config.enableCompanyFeature && user.companyId) {
165
- return (this.config.companyPermissionKeyFormat || `${_constants.PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`).replace('{userId}', user.id).replace('{companyId}', user.companyId).replace('{branchId}', user.branchId || 'null');
166
- }
167
- return (this.config.userPermissionKeyFormat || `${_constants.PERMISSIONS_CACHE_PREFIX}:user:{userId}`).replace('{userId}', user.id);
161
+ const cacheKey = (0, _permissioncachekeyutil.buildPermissionCacheKey)({
162
+ userId: user.id,
163
+ companyId: user.companyId,
164
+ branchId: user.branchId
165
+ }, this.config);
166
+ const cached = await this.cache.get(cacheKey);
167
+ if (!cached) return [];
168
+ return Array.isArray(cached) ? cached : cached.backendCodes || [];
168
169
  }
169
170
  hasPermission(userPermissions, requiredPermission) {
170
171
  if (userPermissions.includes(requiredPermission)) return true;
@@ -184,8 +185,8 @@ let PermissionGuard = class PermissionGuard {
184
185
  this.cache = cache;
185
186
  this.config = {
186
187
  enableCompanyFeature: false,
187
- userPermissionKeyFormat: `${_constants.PERMISSIONS_CACHE_PREFIX}:user:{userId}`,
188
- companyPermissionKeyFormat: `${_constants.PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`,
188
+ userPermissionKeyFormat: _permissioncachekeyutil.DEFAULT_USER_PERMISSION_KEY_FORMAT,
189
+ companyPermissionKeyFormat: _permissioncachekeyutil.DEFAULT_COMPANY_PERMISSION_KEY_FORMAT,
189
190
  ...config
190
191
  };
191
192
  }
@@ -11,6 +11,7 @@ _export_star(require("./logged-user-info.interface"), exports);
11
11
  _export_star(require("./module-config.interface"), exports);
12
12
  _export_star(require("./notification-adapter.interface"), exports);
13
13
  _export_star(require("./permission.interface"), exports);
14
+ _export_star(require("./permission-sync-adapter.interface"), exports);
14
15
  function _export_star(from, to) {
15
16
  Object.keys(from).forEach(function(k) {
16
17
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "PERMISSION_SYNC_ADAPTER", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return PERMISSION_SYNC_ADAPTER;
9
+ }
10
+ });
11
+ const PERMISSION_SYNC_ADAPTER = 'PERMISSION_SYNC_ADAPTER';
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  _export_star(require("./date-time.util"), exports);
6
6
  _export_star(require("./html-sanitizer.util"), exports);
7
+ _export_star(require("./permission-cache-key.util"), exports);
7
8
  _export_star(require("./query-helpers.util"), exports);
8
9
  _export_star(require("./request.util"), exports);
9
10
  _export_star(require("./string.util"), exports);
@@ -0,0 +1,31 @@
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 DEFAULT_COMPANY_PERMISSION_KEY_FORMAT () {
13
+ return DEFAULT_COMPANY_PERMISSION_KEY_FORMAT;
14
+ },
15
+ get DEFAULT_USER_PERMISSION_KEY_FORMAT () {
16
+ return DEFAULT_USER_PERMISSION_KEY_FORMAT;
17
+ },
18
+ get buildPermissionCacheKey () {
19
+ return buildPermissionCacheKey;
20
+ }
21
+ });
22
+ const _constants = require("../constants");
23
+ const DEFAULT_USER_PERMISSION_KEY_FORMAT = `${_constants.PERMISSIONS_CACHE_PREFIX}:user:{userId}`;
24
+ const DEFAULT_COMPANY_PERMISSION_KEY_FORMAT = `${_constants.PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`;
25
+ function buildPermissionCacheKey(options, config) {
26
+ const isCompanyScope = Boolean(config?.enableCompanyFeature && options.companyId);
27
+ if (isCompanyScope) {
28
+ return (config?.companyPermissionKeyFormat || DEFAULT_COMPANY_PERMISSION_KEY_FORMAT).replace('{userId}', options.userId).replace('{companyId}', options.companyId).replace('{branchId}', options.branchId || 'null');
29
+ }
30
+ return (config?.userPermissionKeyFormat || DEFAULT_USER_PERMISSION_KEY_FORMAT).replace('{userId}', options.userId);
31
+ }
@@ -5,7 +5,7 @@ export declare const PERMISSION_GUARD_CONFIG = "PERMISSION_GUARD_CONFIG";
5
5
  export declare const IDEMPOTENCY_KEY_HEADER = "x-idempotency-key";
6
6
  export declare const REQUEST_ID_HEADER = "x-request-id";
7
7
  export declare const CLIENT_TYPE_HEADER = "x-client-type";
8
- export declare const PERMISSIONS_CACHE_PREFIX = "permissions";
8
+ export declare const PERMISSIONS_CACHE_PREFIX = "my-permissions";
9
9
  export declare const IDEMPOTENCY_CACHE_PREFIX = "idempotency";
10
10
  export * from './permissions';
11
11
  export * from './message-keys';
@@ -9,7 +9,7 @@ export const IDEMPOTENCY_KEY_HEADER = 'x-idempotency-key';
9
9
  export const REQUEST_ID_HEADER = 'x-request-id';
10
10
  export const CLIENT_TYPE_HEADER = 'x-client-type';
11
11
  // Cache key prefixes
12
- export const PERMISSIONS_CACHE_PREFIX = 'permissions';
12
+ export const PERMISSIONS_CACHE_PREFIX = 'my-permissions';
13
13
  export const IDEMPOTENCY_CACHE_PREFIX = 'idempotency';
14
14
  // Permission codes
15
15
  export * from './permissions';
@@ -28,9 +28,10 @@ function _ts_param(paramIndex, decorator) {
28
28
  import { Inject, Injectable, Optional, UnauthorizedException } from '@nestjs/common';
29
29
  import { Reflector } from '@nestjs/core';
30
30
  import { HybridCache } from '../classes/hybrid-cache.class';
31
- import { AUTH_MESSAGES, CACHE_INSTANCE, IS_PUBLIC_KEY, PERMISSION_GUARD_CONFIG, PERMISSIONS_CACHE_PREFIX, PERMISSIONS_KEY } from '../constants';
31
+ import { AUTH_MESSAGES, CACHE_INSTANCE, IS_PUBLIC_KEY, PERMISSION_GUARD_CONFIG, PERMISSIONS_KEY } from '../constants';
32
32
  import { InsufficientPermissionsException, NoPermissionsFoundException, PermissionSystemUnavailableException } from '../exceptions/permission.exception';
33
33
  import { PermissionGuardConfig } from '../interfaces/permission.interface';
34
+ import { buildPermissionCacheKey, DEFAULT_COMPANY_PERMISSION_KEY_FORMAT, DEFAULT_USER_PERMISSION_KEY_FORMAT } from '../utils/permission-cache-key.util';
34
35
  export class PermissionGuard {
35
36
  async canActivate(context) {
36
37
  const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [
@@ -147,14 +148,14 @@ export class PermissionGuard {
147
148
  }
148
149
  async getUserPermissions(user) {
149
150
  if (!this.cache) throw new PermissionSystemUnavailableException();
150
- const cacheKey = this.buildPermissionCacheKey(user);
151
- return await this.cache.get(cacheKey) || [];
152
- }
153
- buildPermissionCacheKey(user) {
154
- if (this.config.enableCompanyFeature && user.companyId) {
155
- return (this.config.companyPermissionKeyFormat || `${PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`).replace('{userId}', user.id).replace('{companyId}', user.companyId).replace('{branchId}', user.branchId || 'null');
156
- }
157
- return (this.config.userPermissionKeyFormat || `${PERMISSIONS_CACHE_PREFIX}:user:{userId}`).replace('{userId}', user.id);
151
+ const cacheKey = buildPermissionCacheKey({
152
+ userId: user.id,
153
+ companyId: user.companyId,
154
+ branchId: user.branchId
155
+ }, this.config);
156
+ const cached = await this.cache.get(cacheKey);
157
+ if (!cached) return [];
158
+ return Array.isArray(cached) ? cached : cached.backendCodes || [];
158
159
  }
159
160
  hasPermission(userPermissions, requiredPermission) {
160
161
  if (userPermissions.includes(requiredPermission)) return true;
@@ -174,8 +175,8 @@ export class PermissionGuard {
174
175
  this.cache = cache;
175
176
  this.config = {
176
177
  enableCompanyFeature: false,
177
- userPermissionKeyFormat: `${PERMISSIONS_CACHE_PREFIX}:user:{userId}`,
178
- companyPermissionKeyFormat: `${PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`,
178
+ userPermissionKeyFormat: DEFAULT_USER_PERMISSION_KEY_FORMAT,
179
+ companyPermissionKeyFormat: DEFAULT_COMPANY_PERMISSION_KEY_FORMAT,
179
180
  ...config
180
181
  };
181
182
  }
@@ -7,3 +7,4 @@ export * from './logged-user-info.interface';
7
7
  export * from './module-config.interface';
8
8
  export * from './notification-adapter.interface';
9
9
  export * from './permission.interface';
10
+ export * from './permission-sync-adapter.interface';
@@ -0,0 +1 @@
1
+ export const PERMISSION_SYNC_ADAPTER = 'PERMISSION_SYNC_ADAPTER';
@@ -1,5 +1,6 @@
1
1
  export * from './date-time.util';
2
2
  export * from './html-sanitizer.util';
3
+ export * from './permission-cache-key.util';
3
4
  export * from './query-helpers.util';
4
5
  export * from './request.util';
5
6
  export * from './string.util';
@@ -0,0 +1,10 @@
1
+ import { PERMISSIONS_CACHE_PREFIX } from '../constants';
2
+ export const DEFAULT_USER_PERMISSION_KEY_FORMAT = `${PERMISSIONS_CACHE_PREFIX}:user:{userId}`;
3
+ export const DEFAULT_COMPANY_PERMISSION_KEY_FORMAT = `${PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`;
4
+ /** Single source of truth for permission cache keys, shared by the guard (reader) and cache service (writer) so a config override can't desync them; company scope requires enableCompanyFeature, not just a companyId */ export function buildPermissionCacheKey(options, config) {
5
+ const isCompanyScope = Boolean(config?.enableCompanyFeature && options.companyId);
6
+ if (isCompanyScope) {
7
+ return (config?.companyPermissionKeyFormat || DEFAULT_COMPANY_PERMISSION_KEY_FORMAT).replace('{userId}', options.userId).replace('{companyId}', options.companyId).replace('{branchId}', options.branchId || 'null');
8
+ }
9
+ return (config?.userPermissionKeyFormat || DEFAULT_USER_PERMISSION_KEY_FORMAT).replace('{userId}', options.userId);
10
+ }
@@ -11,6 +11,5 @@ export declare class PermissionGuard implements CanActivate {
11
11
  private normalizeToLogicNode;
12
12
  private evaluateLogicNode;
13
13
  private getUserPermissions;
14
- private buildPermissionCacheKey;
15
14
  private hasPermission;
16
15
  }
@@ -7,3 +7,4 @@ export * from './logged-user-info.interface';
7
7
  export * from './module-config.interface';
8
8
  export * from './notification-adapter.interface';
9
9
  export * from './permission.interface';
10
+ export * from './permission-sync-adapter.interface';
@@ -0,0 +1,7 @@
1
+ export interface IPermissionSyncAdapter {
2
+ onCompanyDeleted?(companyId: string): Promise<void>;
3
+ onBranchDeleted?(branchId: string, companyId: string): Promise<void>;
4
+ onUserCompanyAccessRevoked?(userId: string, companyId: string): Promise<void>;
5
+ onUserBranchAccessRevoked?(userId: string, branchId: string, companyId: string): Promise<void>;
6
+ }
7
+ export declare const PERMISSION_SYNC_ADAPTER = "PERMISSION_SYNC_ADAPTER";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-shared",
3
- "version": "6.0.1",
3
+ "version": "6.0.2",
4
4
  "description": "Common shared utilities for Flusys NestJS applications",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -112,6 +112,6 @@
112
112
  "rxjs": "^7.8.0"
113
113
  },
114
114
  "dependencies": {
115
- "@flusys/nestjs-core": "6.0.1"
115
+ "@flusys/nestjs-core": "6.0.2"
116
116
  }
117
117
  }
package/utils/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './date-time.util';
2
2
  export * from './html-sanitizer.util';
3
+ export * from './permission-cache-key.util';
3
4
  export * from './query-helpers.util';
4
5
  export * from './request.util';
5
6
  export * from './string.util';
@@ -0,0 +1,9 @@
1
+ import { PermissionGuardConfig } from '../interfaces/permission.interface';
2
+ export interface PermissionCacheKeyOptions {
3
+ userId: string;
4
+ companyId?: string | null;
5
+ branchId?: string | null;
6
+ }
7
+ export declare const DEFAULT_USER_PERMISSION_KEY_FORMAT = "my-permissions:user:{userId}";
8
+ export declare const DEFAULT_COMPANY_PERMISSION_KEY_FORMAT = "my-permissions:company:{companyId}:branch:{branchId}:user:{userId}";
9
+ export declare function buildPermissionCacheKey(options: PermissionCacheKeyOptions, config?: PermissionGuardConfig): string;