@flusys/nestjs-shared 3.0.0-rc → 3.0.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 (47) hide show
  1. package/README.md +851 -275
  2. package/cjs/classes/api-controller.class.js +4 -4
  3. package/cjs/constants/permissions.js +34 -11
  4. package/cjs/decorators/require-permission.decorator.js +7 -3
  5. package/cjs/enums/index.js +20 -0
  6. package/cjs/enums/notification-type.enum.js +17 -0
  7. package/cjs/enums/participant-status.enum.js +17 -0
  8. package/cjs/enums/recurrence-type.enum.js +18 -0
  9. package/cjs/exceptions/permission.exception.js +2 -2
  10. package/cjs/guards/permission.guard.js +66 -65
  11. package/cjs/index.js +1 -0
  12. package/cjs/interfaces/event-manager-adapter.interface.js +11 -0
  13. package/cjs/interfaces/index.js +2 -0
  14. package/cjs/interfaces/notification-adapter.interface.js +11 -0
  15. package/cjs/interfaces/permission.interface.js +1 -1
  16. package/cjs/utils/html-sanitizer.util.js +9 -9
  17. package/cjs/utils/request.util.js +2 -1
  18. package/classes/api-controller.class.d.ts +3 -3
  19. package/constants/permissions.d.ts +36 -0
  20. package/decorators/require-permission.decorator.d.ts +3 -2
  21. package/enums/index.d.ts +3 -0
  22. package/enums/notification-type.enum.d.ts +6 -0
  23. package/enums/participant-status.enum.d.ts +6 -0
  24. package/enums/recurrence-type.enum.d.ts +7 -0
  25. package/exceptions/permission.exception.d.ts +1 -1
  26. package/fesm/classes/api-controller.class.js +5 -5
  27. package/fesm/constants/permissions.js +28 -14
  28. package/fesm/decorators/require-permission.decorator.js +18 -65
  29. package/fesm/enums/index.js +3 -0
  30. package/fesm/enums/notification-type.enum.js +7 -0
  31. package/fesm/enums/participant-status.enum.js +7 -0
  32. package/fesm/enums/recurrence-type.enum.js +8 -0
  33. package/fesm/exceptions/permission.exception.js +2 -2
  34. package/fesm/guards/permission.guard.js +66 -65
  35. package/fesm/index.js +1 -0
  36. package/fesm/interfaces/event-manager-adapter.interface.js +1 -0
  37. package/fesm/interfaces/index.js +2 -0
  38. package/fesm/interfaces/notification-adapter.interface.js +1 -0
  39. package/fesm/interfaces/permission.interface.js +1 -3
  40. package/fesm/utils/request.util.js +2 -1
  41. package/guards/permission.guard.d.ts +2 -4
  42. package/index.d.ts +1 -0
  43. package/interfaces/event-manager-adapter.interface.d.ts +43 -0
  44. package/interfaces/index.d.ts +2 -0
  45. package/interfaces/notification-adapter.interface.d.ts +22 -0
  46. package/interfaces/permission.interface.d.ts +13 -8
  47. package/package.json +7 -2
@@ -1,13 +1,4 @@
1
- /**
2
- * Centralized Permission Codes
3
- *
4
- * Single source of truth for all permission codes used across the application.
5
- * Use these constants instead of hardcoded strings to prevent typos and enable easy refactoring.
6
- *
7
- * Naming Convention: <entity>.<action>
8
- * - entity: The resource being accessed (e.g., user, role, company)
9
- * - action: The operation being performed (create, read, update, delete, assign)
10
- */ // ==================== AUTH MODULE ====================
1
+ // ==================== AUTH MODULE ====================
11
2
  export const USER_PERMISSIONS = {
12
3
  CREATE: 'user.create',
13
4
  READ: 'user.read',
@@ -100,10 +91,28 @@ export const FORM_RESULT_PERMISSIONS = {
100
91
  UPDATE: 'form-result.update',
101
92
  DELETE: 'form-result.delete'
102
93
  };
94
+ // ==================== EVENT MANAGER MODULE ====================
95
+ export const EVENT_PERMISSIONS = {
96
+ CREATE: 'event.create',
97
+ READ: 'event.read',
98
+ UPDATE: 'event.update',
99
+ DELETE: 'event.delete'
100
+ };
101
+ export const EVENT_PARTICIPANT_PERMISSIONS = {
102
+ CREATE: 'event-participant.create',
103
+ READ: 'event-participant.read',
104
+ UPDATE: 'event-participant.update',
105
+ DELETE: 'event-participant.delete'
106
+ };
107
+ // ==================== NOTIFICATION MODULE ====================
108
+ export const NOTIFICATION_PERMISSIONS = {
109
+ CREATE: 'notification.create',
110
+ READ: 'notification.read',
111
+ UPDATE: 'notification.update',
112
+ DELETE: 'notification.delete'
113
+ };
103
114
  // ==================== AGGREGATED EXPORTS ====================
104
- /**
105
- * All permission codes grouped by module
106
- */ export const PERMISSIONS = {
115
+ export const PERMISSIONS = {
107
116
  // Auth
108
117
  USER: USER_PERMISSIONS,
109
118
  COMPANY: COMPANY_PERMISSIONS,
@@ -124,5 +133,10 @@ export const FORM_RESULT_PERMISSIONS = {
124
133
  EMAIL_TEMPLATE: EMAIL_TEMPLATE_PERMISSIONS,
125
134
  // Form Builder
126
135
  FORM: FORM_PERMISSIONS,
127
- FORM_RESULT: FORM_RESULT_PERMISSIONS
136
+ FORM_RESULT: FORM_RESULT_PERMISSIONS,
137
+ // Event Manager
138
+ EVENT: EVENT_PERMISSIONS,
139
+ EVENT_PARTICIPANT: EVENT_PARTICIPANT_PERMISSIONS,
140
+ // Notification
141
+ NOTIFICATION: NOTIFICATION_PERMISSIONS
128
142
  };
@@ -1,75 +1,28 @@
1
1
  import { SetMetadata } from '@nestjs/common';
2
2
  import { PERMISSIONS_KEY } from '../constants';
3
- /**
4
- * Decorator to require specific permissions for a route
5
- *
6
- * By default uses AND logic (user must have ALL permissions).
7
- * This is the most common and secure pattern.
8
- *
9
- * @param permissions - One or more permission keys required (AND logic)
10
- *
11
- * @example
12
- * // Require single permission
13
- * @RequirePermission('users.read')
14
- *
15
- * @example
16
- * // Require ALL permissions (AND)
17
- * @RequirePermission('users.read', 'users.write')
18
- *
19
- * @example
20
- * // For OR logic, use RequireAnyPermission instead
21
- * @RequireAnyPermission('admin.access', 'manager.access')
22
- */ export const RequirePermission = (...permissions)=>SetMetadata(PERMISSIONS_KEY, {
3
+ /** Require ALL permissions (AND logic) - most secure pattern */ export const RequirePermission = (...permissions)=>SetMetadata(PERMISSIONS_KEY, {
23
4
  permissions,
24
- operator: 'and'
5
+ operator: 'AND'
25
6
  });
26
- /**
27
- * Decorator to require ANY of the specified permissions (OR logic)
28
- *
29
- * User must have at least ONE of the specified permissions.
30
- * Less secure than RequirePermission (AND), use carefully.
31
- *
32
- * @param permissions - User must have at least ONE of these permissions
33
- *
34
- * @example
35
- * @RequireAnyPermission('admin.access', 'manager.access')
36
- */ export const RequireAnyPermission = (...permissions)=>SetMetadata(PERMISSIONS_KEY, {
7
+ /** Require ANY permission (OR logic) - use carefully */ export const RequireAnyPermission = (...permissions)=>SetMetadata(PERMISSIONS_KEY, {
37
8
  permissions,
38
- operator: 'or'
9
+ operator: 'OR'
39
10
  });
40
11
  /**
41
- * Decorator for complex permission conditions with nested logic
42
- *
43
- * Supports building complex permission trees:
44
- * - AND/OR operators
45
- * - Nested children for complex logic
46
- *
47
- * @param condition - Complex permission condition
48
- *
49
- * @example
50
- * // Simple: User needs 'admin' OR 'manager'
51
- * @RequirePermissionCondition({
52
- * operator: 'or',
53
- * permissions: ['admin', 'manager'],
54
- * })
55
- *
12
+ * Require complex permission logic using ILogicNode tree
56
13
  * @example
57
- * // Complex: User needs 'users.read' AND ('admin' OR 'manager')
58
- * @RequirePermissionCondition({
59
- * operator: 'and',
60
- * permissions: ['users.read'],
61
- * children: [
62
- * { operator: 'or', permissions: ['admin', 'manager'] }
63
- * ]
64
- * })
65
- *
14
+ * // Single permission
15
+ * @RequirePermissionLogic('users.read')
66
16
  * @example
67
- * // Very complex: (A AND B) OR (C AND D)
68
- * @RequirePermissionCondition({
69
- * operator: 'or',
70
- * children: [
71
- * { operator: 'and', permissions: ['finance.read', 'finance.write'] },
72
- * { operator: 'and', permissions: ['admin.full', 'reports.access'] }
73
- * ]
17
+ * // Complex: users.read AND (admin OR manager)
18
+ * @RequirePermissionLogic({
19
+ * type: 'group', operator: 'AND', children: [
20
+ * { type: 'action', actionId: 'users.read' },
21
+ * { type: 'group', operator: 'OR', children: [
22
+ * { type: 'action', actionId: 'admin' },
23
+ * { type: 'action', actionId: 'manager' },
24
+ * ]},
25
+ * ],
74
26
  * })
75
- */ export const RequirePermissionCondition = (condition)=>SetMetadata(PERMISSIONS_KEY, condition);
27
+ */ export const RequirePermissionLogic = (logic)=>SetMetadata(PERMISSIONS_KEY, logic);
28
+ /** @deprecated Use RequirePermissionLogic instead */ export const RequirePermissionCondition = RequirePermissionLogic;
@@ -0,0 +1,3 @@
1
+ export * from './notification-type.enum';
2
+ export * from './participant-status.enum';
3
+ export * from './recurrence-type.enum';
@@ -0,0 +1,7 @@
1
+ export var NotificationType = /*#__PURE__*/ function(NotificationType) {
2
+ NotificationType["INFO"] = "info";
3
+ NotificationType["WARNING"] = "warning";
4
+ NotificationType["SUCCESS"] = "success";
5
+ NotificationType["ERROR"] = "error";
6
+ return NotificationType;
7
+ }({});
@@ -0,0 +1,7 @@
1
+ export var ParticipantStatus = /*#__PURE__*/ function(ParticipantStatus) {
2
+ ParticipantStatus["PENDING"] = "pending";
3
+ ParticipantStatus["ACCEPTED"] = "accepted";
4
+ ParticipantStatus["DECLINED"] = "declined";
5
+ ParticipantStatus["TENTATIVE"] = "tentative";
6
+ return ParticipantStatus;
7
+ }({});
@@ -0,0 +1,8 @@
1
+ export var RecurrenceType = /*#__PURE__*/ function(RecurrenceType) {
2
+ RecurrenceType["NONE"] = "none";
3
+ RecurrenceType["DAILY"] = "daily";
4
+ RecurrenceType["WEEKLY"] = "weekly";
5
+ RecurrenceType["BIWEEKLY"] = "biweekly";
6
+ RecurrenceType["MONTHLY"] = "monthly";
7
+ return RecurrenceType;
8
+ }({});
@@ -13,8 +13,8 @@ import { ForbiddenException, InternalServerErrorException } from '@nestjs/common
13
13
  /**
14
14
  * Exception thrown when user lacks required permissions
15
15
  */ export class InsufficientPermissionsException extends ForbiddenException {
16
- constructor(missingPermissions, operator = 'and'){
17
- const message = operator === 'or' ? `Requires at least one of: ${missingPermissions.join(', ')}` : `Missing required permissions: ${missingPermissions.join(', ')}`;
16
+ constructor(missingPermissions, operator = 'AND'){
17
+ const message = operator === 'OR' ? `Requires at least one of: ${missingPermissions.join(', ')}` : `Missing required permissions: ${missingPermissions.join(', ')}`;
18
18
  super({
19
19
  success: false,
20
20
  message,
@@ -45,8 +45,6 @@ export class PermissionGuard {
45
45
  context.getClass()
46
46
  ]);
47
47
  if (!permissionConfig) return true;
48
- const { permissions: requiredPermissions, operator } = this.normalizePermissionConfig(permissionConfig);
49
- if (!requiredPermissions || requiredPermissions.length === 0) return true;
50
48
  const request = context.switchToHttp().getRequest();
51
49
  const user = request.user;
52
50
  if (!user) throw new UnauthorizedException('Authentication required');
@@ -59,90 +57,93 @@ export class PermissionGuard {
59
57
  this.logger.warn(`No permissions found (userId: ${user.id})`, 'PermissionGuard');
60
58
  throw new NoPermissionsFoundException();
61
59
  }
62
- if (this.isNestedCondition(permissionConfig)) {
63
- const result = this.evaluateCondition(permissionConfig, userPermissions);
64
- if (!result.passed) {
65
- this.logger.warn(`Permission denied (userId: ${user.id})`, 'PermissionGuard');
66
- throw new InsufficientPermissionsException(result.missingPermissions, result.operator);
67
- }
68
- } else {
69
- this.validateSimplePermissions(requiredPermissions, userPermissions, operator);
60
+ const logicNode = this.normalizeToLogicNode(permissionConfig);
61
+ if (!logicNode) return true;
62
+ const result = this.evaluateLogicNode(logicNode, userPermissions);
63
+ if (!result.passed) {
64
+ this.logger.warn(`Permission denied (userId: ${user.id})`, 'PermissionGuard');
65
+ throw new InsufficientPermissionsException(result.missingPermissions, result.operator);
70
66
  }
71
67
  return true;
72
68
  }
73
- normalizePermissionConfig(config) {
74
- if (Array.isArray(config)) return {
75
- permissions: config,
76
- operator: 'and'
77
- };
78
- return {
79
- permissions: config.permissions || [],
80
- operator: config.operator || 'and'
81
- };
82
- }
83
- validateSimplePermissions(requiredPermissions, userPermissions, operator) {
84
- if (operator === 'or') {
85
- const hasAny = requiredPermissions.some((p)=>this.hasPermission(userPermissions, p));
86
- if (!hasAny) throw new InsufficientPermissionsException(requiredPermissions, 'or');
87
- } else {
88
- const hasAll = requiredPermissions.every((p)=>this.hasPermission(userPermissions, p));
89
- if (!hasAll) {
90
- const missing = requiredPermissions.filter((p)=>!this.hasPermission(userPermissions, p));
91
- throw new InsufficientPermissionsException(missing, 'and');
92
- }
69
+ normalizeToLogicNode(config) {
70
+ // string - single permission
71
+ if (typeof config === 'string') {
72
+ return config ? {
73
+ type: 'action',
74
+ actionId: config
75
+ } : null;
93
76
  }
77
+ // string[] - treat as AND of multiple permissions
78
+ if (Array.isArray(config)) {
79
+ if (config.length === 0) return null;
80
+ if (config.length === 1) return {
81
+ type: 'action',
82
+ actionId: config[0]
83
+ };
84
+ return {
85
+ type: 'group',
86
+ operator: 'AND',
87
+ children: config.map((p)=>({
88
+ type: 'action',
89
+ actionId: p
90
+ }))
91
+ };
92
+ }
93
+ // SimplePermissionConfig - { permissions: string[], operator: 'AND'|'OR' }
94
+ if ('permissions' in config && Array.isArray(config.permissions)) {
95
+ const simple = config;
96
+ if (simple.permissions.length === 0) return null;
97
+ if (simple.permissions.length === 1) return {
98
+ type: 'action',
99
+ actionId: simple.permissions[0]
100
+ };
101
+ return {
102
+ type: 'group',
103
+ operator: simple.operator || 'AND',
104
+ children: simple.permissions.map((p)=>({
105
+ type: 'action',
106
+ actionId: p
107
+ }))
108
+ };
109
+ }
110
+ // ILogicNode
111
+ return config;
94
112
  }
95
- isNestedCondition(config) {
96
- if (Array.isArray(config)) return false;
97
- return 'children' in config && Array.isArray(config.children) && config.children.length > 0;
98
- }
99
- evaluateCondition(condition, userPermissions) {
100
- const { permissions = [], operator, children = [] } = condition;
101
- // SECURITY: Fail-closed - deny access when no permissions configured (empty condition)
102
- if (permissions.length === 0 && children.length === 0) {
113
+ evaluateLogicNode(node, userPermissions) {
114
+ if (node.type === 'action') {
115
+ const passed = this.hasPermission(userPermissions, node.actionId);
116
+ return {
117
+ passed,
118
+ missingPermissions: passed ? [] : [
119
+ node.actionId
120
+ ],
121
+ operator: 'AND'
122
+ };
123
+ }
124
+ // Group node
125
+ const { operator, children } = node;
126
+ // SECURITY: Fail-closed - deny access when no children configured
127
+ if (!children || children.length === 0) {
103
128
  return {
104
129
  passed: false,
105
- message: 'No permissions configured - access denied by default',
106
130
  missingPermissions: [],
107
131
  operator
108
132
  };
109
133
  }
110
134
  const results = [];
111
- const failureDetails = [];
112
135
  const missingPermissions = [];
113
- if (permissions.length > 0) {
114
- if (operator === 'or') {
115
- const hasAny = permissions.some((p)=>this.hasPermission(userPermissions, p));
116
- results.push(hasAny);
117
- if (!hasAny) {
118
- failureDetails.push(`needs one of: [${permissions.join(', ')}]`);
119
- missingPermissions.push(...permissions);
120
- }
121
- } else {
122
- const hasAll = permissions.every((p)=>this.hasPermission(userPermissions, p));
123
- results.push(hasAll);
124
- if (!hasAll) {
125
- const missing = permissions.filter((p)=>!this.hasPermission(userPermissions, p));
126
- failureDetails.push(`missing: [${missing.join(', ')}]`);
127
- missingPermissions.push(...missing);
128
- }
129
- }
130
- }
131
136
  for (const child of children){
132
- const childResult = this.evaluateCondition(child, userPermissions);
137
+ const childResult = this.evaluateLogicNode(child, userPermissions);
133
138
  results.push(childResult.passed);
134
139
  if (!childResult.passed) {
135
- failureDetails.push(`(${childResult.message})`);
136
140
  missingPermissions.push(...childResult.missingPermissions);
137
141
  }
138
142
  }
139
- // Evaluate based on operator - empty results already handled above
140
- const passed = operator === 'or' ? results.some((r)=>r) : results.every((r)=>r);
141
- const message = passed ? 'OK' : `Denied: ${failureDetails.join(` ${operator.toUpperCase()} `)}`;
143
+ const passed = operator === 'OR' ? results.some((r)=>r) : results.every((r)=>r);
142
144
  return {
143
145
  passed,
144
- message,
145
- missingPermissions,
146
+ missingPermissions: passed ? [] : missingPermissions,
146
147
  operator
147
148
  };
148
149
  }
package/fesm/index.js CHANGED
@@ -3,6 +3,7 @@ export * from './constants';
3
3
  export * from './decorators';
4
4
  export * from './dtos';
5
5
  export * from './entities';
6
+ export * from './enums';
6
7
  export * from './exceptions';
7
8
  export * from './guards';
8
9
  export * from './interceptors';
@@ -0,0 +1 @@
1
+ export const EVENT_MANAGER_ADAPTER = 'EVENT_MANAGER_ADAPTER';
@@ -1,7 +1,9 @@
1
1
  export * from './api.interface';
2
2
  export * from './datasource.interface';
3
+ export * from './event-manager-adapter.interface';
3
4
  export * from './identity.interface';
4
5
  export * from './logged-user-info.interface';
5
6
  export * from './logger.interface';
6
7
  export * from './module-config.interface';
8
+ export * from './notification-adapter.interface';
7
9
  export * from './permission.interface';
@@ -0,0 +1 @@
1
+ export const NOTIFICATION_ADAPTER = 'NOTIFICATION_ADAPTER';
@@ -1,3 +1 @@
1
- /**
2
- * Configuration for the permission guard
3
- */ export { };
1
+ /** Action node - checks a single permission/action code */ /** Configuration for the permission guard */ export { };
@@ -1,3 +1,4 @@
1
+ import { envConfig } from '@flusys/nestjs-core/config';
1
2
  import { CLIENT_TYPE_HEADER } from '../constants';
2
3
  /** Time unit multipliers in milliseconds */ const TIME_UNIT_MS = {
3
4
  s: 1000,
@@ -30,7 +31,7 @@ import { CLIENT_TYPE_HEADER } from '../constants';
30
31
  */ export function buildCookieOptions(req) {
31
32
  const hostname = req.hostname || '';
32
33
  const origin = req.headers.origin || '';
33
- const isProduction = process.env.NODE_ENV === 'production';
34
+ const isProduction = envConfig.isProduction();
34
35
  const forwardedProto = req.headers['x-forwarded-proto'];
35
36
  const isHttps = isProduction || forwardedProto === 'https' || origin.startsWith('https://') || req.secure;
36
37
  let domain;
@@ -10,10 +10,8 @@ export declare class PermissionGuard implements CanActivate {
10
10
  private readonly logger;
11
11
  constructor(reflector: Reflector, cache?: HybridCache, config?: PermissionGuardConfig, logger?: ILogger);
12
12
  canActivate(context: ExecutionContext): Promise<boolean>;
13
- private normalizePermissionConfig;
14
- private validateSimplePermissions;
15
- private isNestedCondition;
16
- private evaluateCondition;
13
+ private normalizeToLogicNode;
14
+ private evaluateLogicNode;
17
15
  private getUserPermissions;
18
16
  private buildPermissionCacheKey;
19
17
  private hasPermission;
package/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from './constants';
3
3
  export * from './decorators';
4
4
  export * from './dtos';
5
5
  export * from './entities';
6
+ export * from './enums';
6
7
  export * from './exceptions';
7
8
  export * from './guards';
8
9
  export * from './interceptors';
@@ -0,0 +1,43 @@
1
+ import { ParticipantStatus } from '../enums/participant-status.enum';
2
+ import { RecurrenceType } from '../enums/recurrence-type.enum';
3
+ export interface IEventManagerAdapter {
4
+ createEvent(options: CreateEventOptions): Promise<EventResult>;
5
+ addParticipants(eventId: string, userIds: string[], companyId?: string): Promise<void>;
6
+ removeParticipant(eventId: string, userId: string): Promise<void>;
7
+ updateParticipantStatus(participantId: string, status: ParticipantStatus): Promise<void>;
8
+ getEventsForUser?(userId: string, startDate: Date, endDate: Date, companyId?: string): Promise<EventResult[]>;
9
+ getEventById?(eventId: string): Promise<EventResult | null>;
10
+ }
11
+ export interface CreateEventOptions {
12
+ title: string;
13
+ description?: string;
14
+ meetingLink?: string;
15
+ startDateTime: Date;
16
+ endDateTime: Date;
17
+ isAllDay?: boolean;
18
+ recurrenceType?: RecurrenceType;
19
+ recurrenceEndDate?: Date;
20
+ color?: string;
21
+ metadata?: Record<string, unknown>;
22
+ participantIds?: string[];
23
+ organizerId?: string;
24
+ companyId?: string;
25
+ }
26
+ export interface EventResult {
27
+ id: string;
28
+ title: string;
29
+ description?: string | null;
30
+ meetingLink?: string | null;
31
+ startDateTime: Date;
32
+ endDateTime: Date;
33
+ isAllDay: boolean;
34
+ recurrenceType: string;
35
+ recurrenceEndDate?: Date | null;
36
+ color: string;
37
+ isActive: boolean;
38
+ metadata?: Record<string, unknown> | null;
39
+ companyId?: string | null;
40
+ createdAt: Date;
41
+ updatedAt: Date;
42
+ }
43
+ export declare const EVENT_MANAGER_ADAPTER = "EVENT_MANAGER_ADAPTER";
@@ -1,7 +1,9 @@
1
1
  export * from './api.interface';
2
2
  export * from './datasource.interface';
3
+ export * from './event-manager-adapter.interface';
3
4
  export * from './identity.interface';
4
5
  export * from './logged-user-info.interface';
5
6
  export * from './logger.interface';
6
7
  export * from './module-config.interface';
8
+ export * from './notification-adapter.interface';
7
9
  export * from './permission.interface';
@@ -0,0 +1,22 @@
1
+ import { NotificationType } from '../enums/notification-type.enum';
2
+ export interface INotificationAdapter {
3
+ send(options: NotificationSendOptions): Promise<void>;
4
+ sendToMany(options: NotificationBulkSendOptions): Promise<void>;
5
+ broadcastToCompany?(companyId: string, title: string, message?: string, type?: NotificationType, data?: Record<string, unknown>): Promise<void>;
6
+ isUserOnline?(userId: string): boolean;
7
+ }
8
+ interface NotificationBaseOptions {
9
+ title: string;
10
+ message?: string;
11
+ type?: NotificationType;
12
+ data?: Record<string, unknown>;
13
+ companyId?: string;
14
+ }
15
+ export interface NotificationSendOptions extends NotificationBaseOptions {
16
+ userId: string;
17
+ }
18
+ export interface NotificationBulkSendOptions extends NotificationBaseOptions {
19
+ userIds: string[];
20
+ }
21
+ export declare const NOTIFICATION_ADAPTER = "NOTIFICATION_ADAPTER";
22
+ export {};
@@ -1,14 +1,19 @@
1
- export type PermissionOperator = 'and' | 'or';
2
- export interface PermissionCondition {
3
- permissions?: string[];
4
- operator: PermissionOperator;
5
- children?: PermissionCondition[];
1
+ export interface IActionNode {
2
+ type: 'action';
3
+ actionId: string;
6
4
  }
7
- export interface LegacyPermissionConfig {
5
+ export interface IGroupNode {
6
+ type: 'group';
7
+ operator: 'AND' | 'OR';
8
+ children: ILogicNode[];
9
+ }
10
+ export type ILogicNode = IActionNode | IGroupNode;
11
+ export type IPermissionLogic = string | ILogicNode;
12
+ export interface SimplePermissionConfig {
8
13
  permissions: string[];
9
- operator: PermissionOperator;
14
+ operator: 'AND' | 'OR';
10
15
  }
11
- export type PermissionConfig = PermissionCondition | LegacyPermissionConfig | string[];
16
+ export type PermissionConfig = IPermissionLogic | SimplePermissionConfig | string[];
12
17
  export interface PermissionGuardConfig {
13
18
  enableCompanyFeature?: boolean;
14
19
  userPermissionKeyFormat?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-shared",
3
- "version": "3.0.0-rc",
3
+ "version": "3.0.1",
4
4
  "description": "Common shared utilities for Flusys NestJS applications",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -46,6 +46,11 @@
46
46
  "import": "./fesm/entities/index.js",
47
47
  "require": "./cjs/entities/index.js"
48
48
  },
49
+ "./enums": {
50
+ "types": "./enums/index.d.ts",
51
+ "import": "./fesm/enums/index.js",
52
+ "require": "./cjs/enums/index.js"
53
+ },
49
54
  "./exceptions": {
50
55
  "types": "./exceptions/index.d.ts",
51
56
  "import": "./fesm/exceptions/index.js",
@@ -105,6 +110,6 @@
105
110
  "winston-daily-rotate-file": "^5.0.0"
106
111
  },
107
112
  "dependencies": {
108
- "@flusys/nestjs-core": "3.0.0-rc"
113
+ "@flusys/nestjs-core": "3.0.1"
109
114
  }
110
115
  }