@klerick/acl-json-api-nestjs 0.1.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 (135) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +3556 -0
  3. package/package.json +41 -0
  4. package/src/index.d.ts +8 -0
  5. package/src/index.js +15 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/constants/index.d.ts +14 -0
  8. package/src/lib/constants/index.js +18 -0
  9. package/src/lib/constants/index.js.map +1 -0
  10. package/src/lib/decorators/acl-controller.decorator.d.ts +4 -0
  11. package/src/lib/decorators/acl-controller.decorator.js +19 -0
  12. package/src/lib/decorators/acl-controller.decorator.js.map +1 -0
  13. package/src/lib/decorators/index.d.ts +1 -0
  14. package/src/lib/decorators/index.js +6 -0
  15. package/src/lib/decorators/index.js.map +1 -0
  16. package/src/lib/factories/ability-proxy.factory.d.ts +17 -0
  17. package/src/lib/factories/ability-proxy.factory.js +100 -0
  18. package/src/lib/factories/ability-proxy.factory.js.map +1 -0
  19. package/src/lib/factories/ability.factory.d.ts +49 -0
  20. package/src/lib/factories/ability.factory.js +235 -0
  21. package/src/lib/factories/ability.factory.js.map +1 -0
  22. package/src/lib/factories/index.d.ts +2 -0
  23. package/src/lib/factories/index.js +6 -0
  24. package/src/lib/factories/index.js.map +1 -0
  25. package/src/lib/guards/acl.guard.d.ts +21 -0
  26. package/src/lib/guards/acl.guard.js +68 -0
  27. package/src/lib/guards/acl.guard.js.map +1 -0
  28. package/src/lib/guards/index.d.ts +1 -0
  29. package/src/lib/guards/index.js +5 -0
  30. package/src/lib/guards/index.js.map +1 -0
  31. package/src/lib/nestjs-acl-permissions.module.d.ts +9 -0
  32. package/src/lib/nestjs-acl-permissions.module.js +56 -0
  33. package/src/lib/nestjs-acl-permissions.module.js.map +1 -0
  34. package/src/lib/services/acl-authorization.service.d.ts +10 -0
  35. package/src/lib/services/acl-authorization.service.js +100 -0
  36. package/src/lib/services/acl-authorization.service.js.map +1 -0
  37. package/src/lib/services/index.d.ts +2 -0
  38. package/src/lib/services/index.js +6 -0
  39. package/src/lib/services/index.js.map +1 -0
  40. package/src/lib/services/rule-materializer.service.d.ts +73 -0
  41. package/src/lib/services/rule-materializer.service.js +251 -0
  42. package/src/lib/services/rule-materializer.service.js.map +1 -0
  43. package/src/lib/types/acl-context.types.d.ts +14 -0
  44. package/src/lib/types/acl-context.types.js +3 -0
  45. package/src/lib/types/acl-context.types.js.map +1 -0
  46. package/src/lib/types/acl-options.types.d.ts +97 -0
  47. package/src/lib/types/acl-options.types.js +3 -0
  48. package/src/lib/types/acl-options.types.js.map +1 -0
  49. package/src/lib/types/acl-rules.types.d.ts +201 -0
  50. package/src/lib/types/acl-rules.types.js +27 -0
  51. package/src/lib/types/acl-rules.types.js.map +1 -0
  52. package/src/lib/types/decorator-options.types.d.ts +64 -0
  53. package/src/lib/types/decorator-options.types.js +3 -0
  54. package/src/lib/types/decorator-options.types.js.map +1 -0
  55. package/src/lib/types/index.d.ts +4 -0
  56. package/src/lib/types/index.js +8 -0
  57. package/src/lib/types/index.js.map +1 -0
  58. package/src/lib/utils/index.d.ts +10 -0
  59. package/src/lib/utils/index.js +53 -0
  60. package/src/lib/utils/index.js.map +1 -0
  61. package/src/lib/utils/orm-proxy/extract-field-paths.d.ts +73 -0
  62. package/src/lib/utils/orm-proxy/extract-field-paths.js +155 -0
  63. package/src/lib/utils/orm-proxy/extract-field-paths.js.map +1 -0
  64. package/src/lib/utils/orm-proxy/handle-acl-query-error.d.ts +19 -0
  65. package/src/lib/utils/orm-proxy/handle-acl-query-error.js +53 -0
  66. package/src/lib/utils/orm-proxy/handle-acl-query-error.js.map +1 -0
  67. package/src/lib/utils/orm-proxy/index.d.ts +9 -0
  68. package/src/lib/utils/orm-proxy/index.js +24 -0
  69. package/src/lib/utils/orm-proxy/index.js.map +1 -0
  70. package/src/lib/utils/orm-proxy/merge-query-with-acl-data.d.ts +27 -0
  71. package/src/lib/utils/orm-proxy/merge-query-with-acl-data.js +78 -0
  72. package/src/lib/utils/orm-proxy/merge-query-with-acl-data.js.map +1 -0
  73. package/src/lib/utils/orm-proxy/prepare-acl-query.d.ts +11 -0
  74. package/src/lib/utils/orm-proxy/prepare-acl-query.js +35 -0
  75. package/src/lib/utils/orm-proxy/prepare-acl-query.js.map +1 -0
  76. package/src/lib/utils/orm-proxy/process-item-field-restrictions.d.ts +24 -0
  77. package/src/lib/utils/orm-proxy/process-item-field-restrictions.js +42 -0
  78. package/src/lib/utils/orm-proxy/process-item-field-restrictions.js.map +1 -0
  79. package/src/lib/utils/orm-proxy/remove-acl-added-fields.d.ts +31 -0
  80. package/src/lib/utils/orm-proxy/remove-acl-added-fields.js +104 -0
  81. package/src/lib/utils/orm-proxy/remove-acl-added-fields.js.map +1 -0
  82. package/src/lib/utils/orm-proxy/unset-deep.d.ts +13 -0
  83. package/src/lib/utils/orm-proxy/unset-deep.js +41 -0
  84. package/src/lib/utils/orm-proxy/unset-deep.js.map +1 -0
  85. package/src/lib/utils/orm-proxy/validate-no-current-in-rules.d.ts +19 -0
  86. package/src/lib/utils/orm-proxy/validate-no-current-in-rules.js +33 -0
  87. package/src/lib/utils/orm-proxy/validate-no-current-in-rules.js.map +1 -0
  88. package/src/lib/utils/orm-proxy/validate-rules-for-orm.d.ts +16 -0
  89. package/src/lib/utils/orm-proxy/validate-rules-for-orm.js +35 -0
  90. package/src/lib/utils/orm-proxy/validate-rules-for-orm.js.map +1 -0
  91. package/src/lib/wrappers/index.d.ts +9 -0
  92. package/src/lib/wrappers/index.js +32 -0
  93. package/src/lib/wrappers/index.js.map +1 -0
  94. package/src/lib/wrappers/logger-init.d.ts +2 -0
  95. package/src/lib/wrappers/logger-init.js +9 -0
  96. package/src/lib/wrappers/logger-init.js.map +1 -0
  97. package/src/lib/wrappers/wrapper-json-method-controller/get-proxy-orm.d.ts +4 -0
  98. package/src/lib/wrappers/wrapper-json-method-controller/get-proxy-orm.js +47 -0
  99. package/src/lib/wrappers/wrapper-json-method-controller/get-proxy-orm.js.map +1 -0
  100. package/src/lib/wrappers/wrapper-json-method-controller/index.d.ts +3 -0
  101. package/src/lib/wrappers/wrapper-json-method-controller/index.js +21 -0
  102. package/src/lib/wrappers/wrapper-json-method-controller/index.js.map +1 -0
  103. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-one-proxy.d.ts +3 -0
  104. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-one-proxy.js +51 -0
  105. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-one-proxy.js.map +1 -0
  106. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-relationship-proxy.d.ts +4 -0
  107. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-relationship-proxy.js +59 -0
  108. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-relationship-proxy.js.map +1 -0
  109. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-all-proxy.d.ts +13 -0
  110. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-all-proxy.js +67 -0
  111. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-all-proxy.js.map +1 -0
  112. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-one-proxy.d.ts +12 -0
  113. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-one-proxy.js +50 -0
  114. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-one-proxy.js.map +1 -0
  115. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-relationship-proxy.d.ts +4 -0
  116. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-relationship-proxy.js +50 -0
  117. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-relationship-proxy.js.map +1 -0
  118. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/index.d.ts +9 -0
  119. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/index.js +13 -0
  120. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/index.js.map +1 -0
  121. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-one-proxy.d.ts +3 -0
  122. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-one-proxy.js +132 -0
  123. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-one-proxy.js.map +1 -0
  124. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-relationship-proxy.d.ts +4 -0
  125. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-relationship-proxy.js +68 -0
  126. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-relationship-proxy.js.map +1 -0
  127. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-one-proxy.d.ts +3 -0
  128. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-one-proxy.js +73 -0
  129. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-one-proxy.js.map +1 -0
  130. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-relationship-proxy.d.ts +4 -0
  131. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-relationship-proxy.js +66 -0
  132. package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-relationship-proxy.js.map +1 -0
  133. package/src/lib/wrappers/wrapper-json-method-controller/on-module-init.d.ts +2 -0
  134. package/src/lib/wrappers/wrapper-json-method-controller/on-module-init.js +16 -0
  135. package/src/lib/wrappers/wrapper-json-method-controller/on-module-init.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acl-context.types.js","sourceRoot":"","sources":["../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/types/acl-context.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,97 @@
1
+ import type { Type } from '@nestjs/common';
2
+ import { AclRule, AclRulesLoader } from './acl-rules.types';
3
+ import { AclContextStore } from './acl-context.types';
4
+ /**
5
+ * Policy for handling resources with no ACL rules defined
6
+ */
7
+ export type OnNoRulesPolicy = 'deny' | 'allow';
8
+ /**
9
+ * Options for configuring ACL module
10
+ */
11
+ export interface AclModuleOptions {
12
+ /**
13
+ * Service class that loads ACL rules from external source
14
+ * Must implement AclRulesLoader interface
15
+ * Will be retrieved via moduleRef to support services from other modules
16
+ */
17
+ rulesLoader: Type<AclRulesLoader>;
18
+ /**
19
+ * Context store for passing ACL data through request pipeline
20
+ * Required to access ExtendableAbility in pipes/guards/services via CLS
21
+ * Can be ClsService from nestjs-cls or any service with set/get methods
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * import { ClsService } from 'nestjs-cls';
26
+ *
27
+ * AclPermissionsModule.forRoot({
28
+ * rulesLoader: MyRulesLoader,
29
+ * contextStore: ClsService
30
+ * })
31
+ * ```
32
+ */
33
+ contextStore: Type<AclContextStore>;
34
+ /**
35
+ * Strict mode for template interpolation in rules
36
+ *
37
+ * - `true`: Throws error if variable/function not found in context
38
+ * - `false` (default): Logs warning and omits field with missing variable
39
+ *
40
+ * @default false
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Development mode - fail fast on configuration errors
45
+ * AclPermissionsModule.forRoot({
46
+ * rulesLoader: MyRulesLoader,
47
+ * strictInterpolation: true
48
+ * })
49
+ *
50
+ * // Production mode - graceful degradation
51
+ * AclPermissionsModule.forRoot({
52
+ * rulesLoader: MyRulesLoader,
53
+ * strictInterpolation: false
54
+ * })
55
+ * ```
56
+ */
57
+ strictInterpolation?: boolean;
58
+ /**
59
+ * Policy for handling resources with no ACL rules defined
60
+ *
61
+ * - 'deny': Throw 403 Forbidden - DEFAULT (production mode)
62
+ * - 'allow': Allow access + warning in logs (development mode)
63
+ *
64
+ * @default 'deny'
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * // Production - deny by default (strict)
69
+ * AclPermissionsModule.forRoot({
70
+ * rulesLoader: MyRulesLoader,
71
+ * onNoRules: 'deny'
72
+ * })
73
+ *
74
+ * // Development - allow access with warning
75
+ * AclPermissionsModule.forRoot({
76
+ * rulesLoader: MyRulesLoader,
77
+ * onNoRules: 'allow'
78
+ * })
79
+ * ```
80
+ */
81
+ onNoRules?: OnNoRulesPolicy;
82
+ /**
83
+ * Дефолтные правила fallback (опционально)
84
+ * Используются когда rulesLoader возвращает пустой массив
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * AclPermissionsModule.forRoot({
89
+ * rulesLoader: MyRulesLoader,
90
+ * defaultRules: [
91
+ * { action: 'getAll', subject: 'all', inverted: false }
92
+ * ]
93
+ * })
94
+ * ```
95
+ */
96
+ defaultRules?: AclRule[];
97
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=acl-options.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acl-options.types.js","sourceRoot":"","sources":["../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/types/acl-options.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,201 @@
1
+ import type { MongoQuery } from '@casl/ability';
2
+ import type { MethodName } from '@klerick/json-api-nestjs';
3
+ import type { AnyEntity, EntityClass } from '@klerick/json-api-nestjs-shared';
4
+ /**
5
+ * Reserved variable name for external input data in rule templates
6
+ * This data comes from outside (request body, query params, database entity, etc.)
7
+ * and is NOT part of the context returned by getContext()
8
+ *
9
+ * In templates, use @input (with @) for readability: '${@input.userId}'
10
+ * Internally, the @ symbol is removed before interpolation since @ is not valid in JS variable names
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // In rule template (user-facing):
15
+ * { conditions: { ownerId: '${@input.userId}' } }
16
+ *
17
+ * // Internally reserved variable name (without @):
18
+ * const scope = { input: externalData };
19
+ * ```
20
+ */
21
+ export declare const ACL_INPUT_VAR: "input";
22
+ /**
23
+ * Template placeholder with @ symbol for user-facing templates
24
+ * This is replaced with ACL_INPUT_VAR before interpolation
25
+ */
26
+ export declare const ACL_INPUT_TEMPLATE: "@input";
27
+ /**
28
+ * Type for external input data
29
+ *
30
+ * TODO: Extend to support both new input AND old values from database
31
+ * Use case: In patchOne, we need to compare old value vs new value in rules
32
+ * Example: Allow removing only self from coAuthorIds array
33
+ * - Current: { coAuthorIds: [1, 2, 3] } from DB
34
+ * - New: { coAuthorIds: [1, 3] } from @input
35
+ * - Helper: isOnlyRemovedUser(@input.__current.coAuthorIds, @input.coAuthorIds, userId)
36
+ *
37
+ * Proposed structure:
38
+ * - @input.* - new values from request
39
+ * - @input.__current.* - old values from database (for patchOne only)
40
+ */
41
+ export type AclInputData = Record<string, any>;
42
+ /**
43
+ * Utility type to exclude reserved @input variable from context/helpers
44
+ */
45
+ type WithoutReservedVars<T extends Record<string, any>> = {
46
+ [K in keyof T as K extends typeof ACL_INPUT_VAR ? never : K]: T[K];
47
+ };
48
+ /**
49
+ * Type for CASL action
50
+ * Can be any method from JsonBaseController or custom string
51
+ */
52
+ export type AclAction<E extends MethodName | string = MethodName | string> = E;
53
+ /**
54
+ * Type for CASL subject - entity class or instance
55
+ * Can be:
56
+ * - Entity class (e.g., User, Post)
57
+ * - Entity instance (e.g., new User())
58
+ * - String with entity name (e.g., 'User', 'Post')
59
+ */
60
+ export type AclSubject<E extends AnyEntity = AnyEntity> = EntityClass<E> | E | string;
61
+ /**
62
+ * ACL rule definition
63
+ */
64
+ export interface AclRule<E extends AnyEntity = AnyEntity, Action extends string = string> {
65
+ /**
66
+ * Action to check (e.g., 'getAll', 'postOne', 'patchOne', etc.)
67
+ */
68
+ action: Action;
69
+ /**
70
+ * Subject to check against (entity class or name)
71
+ */
72
+ subject: AclSubject<E>;
73
+ /**
74
+ * Optional conditions (MongoDB query format)
75
+ */
76
+ conditions?: MongoQuery<E>;
77
+ /**
78
+ * Optional fields restriction
79
+ */
80
+ fields?: Array<keyof E | string>;
81
+ /**
82
+ * Whether this is an inverted rule (cannot)
83
+ */
84
+ inverted?: boolean;
85
+ /**
86
+ * Optional reason for the rule
87
+ */
88
+ reason?: string;
89
+ }
90
+ /**
91
+ * Interface for loading ACL rules from external source
92
+ * Implementation is provided by the user
93
+ */
94
+ export interface AclRulesLoader {
95
+ /**
96
+ * Loads ACL rules for the current request
97
+ *
98
+ * @param subject - Entity class or name of subject for which to load rules
99
+ * @param action - Action being performed (method name from JsonBaseController)
100
+ * @returns Array of CASL rules in JSON format (may contain template strings like '${userId}')
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * @Injectable()
105
+ * class MyRulesLoader implements AclRulesLoader {
106
+ * async loadRules<E extends AnyEntity>(
107
+ * entity: EntityClass<E>,
108
+ * action: AclAction
109
+ * ): Promise<AclRule<E>[]> {
110
+ * const user = this.request.user;
111
+ * const rules = await this.db.query(
112
+ * 'SELECT * FROM permissions WHERE userId = ? AND entity = ? AND action = ?',
113
+ * [user.id, entity.name, action]
114
+ * );
115
+ * return rules.map(r => ({
116
+ * action: r.action,
117
+ * subject: entity,
118
+ * conditions: r.conditions, // May contain: { userId: '${userId}' }
119
+ * fields: r.fields
120
+ * }));
121
+ * }
122
+ * }
123
+ * ```
124
+ */
125
+ loadRules<E extends AnyEntity>(subject: AclSubject<E>, action: AclAction): Promise<AclRule<E>[]>;
126
+ /**
127
+ * Provides context variables for template interpolation in rules
128
+ *
129
+ * IMPORTANT: Cannot use reserved variable name 'input' - it's reserved for external input data
130
+ * In templates, write @input which gets converted to input internally
131
+ *
132
+ * @returns Promise with object containing variables (without 'input' key)
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * @Injectable()
137
+ * class MyRulesLoader implements AclRulesLoader {
138
+ * constructor(
139
+ * @Inject(REQUEST) private request: Request,
140
+ * private usersService: UsersService
141
+ * ) {}
142
+ *
143
+ * async getContext() {
144
+ * const user = this.request.user;
145
+ * const userGroups = await this.usersService.getUserGroups(user.id);
146
+ *
147
+ * return {
148
+ * userId: user.id,
149
+ * userEmail: user.email,
150
+ * userData: {
151
+ * groups: userGroups,
152
+ * roles: user.roles,
153
+ * },
154
+ * // 'input': {} // ← TypeScript error: reserved variable
155
+ * };
156
+ * }
157
+ * }
158
+ * ```
159
+ */
160
+ getContext(): Promise<WithoutReservedVars<Record<string, unknown>>>;
161
+ /**
162
+ * Provides custom helper functions for template interpolation in rules
163
+ *
164
+ * These functions can be used in rule templates like: '${getValProps(@input.userGroups, "id")}'
165
+ *
166
+ * IMPORTANT: Cannot use reserved function name 'input' - it's reserved for external input data
167
+ * In templates, write @input which gets converted to input internally
168
+ *
169
+ * @returns Promise with object containing helper functions (without 'input' key)
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * @Injectable()
174
+ * class MyRulesLoader implements AclRulesLoader {
175
+ * async getHelpers() {
176
+ * return {
177
+ * // Extract property values from array of objects
178
+ * getValProps: (arr: any[], prop: string) => arr.map(item => item[prop]),
179
+ *
180
+ * // Check if array contains value
181
+ * includes: (arr: any[], value: any) => arr.includes(value),
182
+ *
183
+ * // Get current timestamp
184
+ * now: () => Date.now(),
185
+ *
186
+ * // Custom business logic
187
+ * isOwner: (resource: any, userId: number) => resource.ownerId === userId,
188
+ *
189
+ * // 'input': () => {} // ← TypeScript error: reserved variable
190
+ * };
191
+ * }
192
+ * }
193
+ *
194
+ * // Usage in rule template:
195
+ * // { groupIds: { $in: '${getValProps(@input.userGroups, "id")}' } }
196
+ * // { ownerId: '${@input.userId}' }
197
+ * ```
198
+ */
199
+ getHelpers(): Promise<WithoutReservedVars<Record<string, (...args: any[]) => any>>>;
200
+ }
201
+ export {};
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ACL_INPUT_TEMPLATE = exports.ACL_INPUT_VAR = void 0;
4
+ /**
5
+ * Reserved variable name for external input data in rule templates
6
+ * This data comes from outside (request body, query params, database entity, etc.)
7
+ * and is NOT part of the context returned by getContext()
8
+ *
9
+ * In templates, use @input (with @) for readability: '${@input.userId}'
10
+ * Internally, the @ symbol is removed before interpolation since @ is not valid in JS variable names
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // In rule template (user-facing):
15
+ * { conditions: { ownerId: '${@input.userId}' } }
16
+ *
17
+ * // Internally reserved variable name (without @):
18
+ * const scope = { input: externalData };
19
+ * ```
20
+ */
21
+ exports.ACL_INPUT_VAR = 'input';
22
+ /**
23
+ * Template placeholder with @ symbol for user-facing templates
24
+ * This is replaced with ACL_INPUT_VAR before interpolation
25
+ */
26
+ exports.ACL_INPUT_TEMPLATE = '@input';
27
+ //# sourceMappingURL=acl-rules.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acl-rules.types.js","sourceRoot":"","sources":["../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/types/acl-rules.types.ts"],"names":[],"mappings":";;;AAIA;;;;;;;;;;;;;;;;GAgBG;AACU,QAAA,aAAa,GAAG,OAAgB,CAAC;AAE9C;;;GAGG;AACU,QAAA,kBAAkB,GAAG,QAAiB,CAAC"}
@@ -0,0 +1,64 @@
1
+ import type { JsonBaseController } from '@klerick/json-api-nestjs';
2
+ import type { AnyEntity } from '@klerick/json-api-nestjs-shared';
3
+ import type { AclSubject } from './acl-rules.types';
4
+ import { AclModuleOptions } from './acl-options.types';
5
+ /**
6
+ * Extract function property names from a type
7
+ */
8
+ type FunctionPropertyNames<T> = {
9
+ [K in keyof T]: T[K] extends Function ? K : never;
10
+ }[keyof T];
11
+ /**
12
+ * Extract method names from controller class
13
+ */
14
+ export type ControllerMethods<T> = FunctionPropertyNames<T>;
15
+ export type AclControllerMethodsOptions = boolean | Omit<AclModuleOptions, 'rulesLoader' | 'contextStore' | 'strictInterpolation'>;
16
+ /**
17
+ * Partial record of controller methods with boolean values
18
+ * Typed by specific controller class
19
+ */
20
+ export type ControllerMethodsConfig<T> = Partial<Record<ControllerMethods<T>, AclControllerMethodsOptions>>;
21
+ /**
22
+ * Options for @AclController decorator
23
+ * Generic Controller type allows type-safe method configuration
24
+ */
25
+ export interface AclControllerOptions<E extends AnyEntity = AnyEntity, Controller = JsonBaseController<E, 'id'>> {
26
+ /**
27
+ * Subject for ACL checks
28
+ * Can be Entity class, instance, or string name
29
+ *
30
+ * @example
31
+ * subject: User
32
+ * subject: 'User'
33
+ */
34
+ subject: AclSubject<E>;
35
+ /**
36
+ * Configuration for which controller methods should have ACL enabled
37
+ * If not specified, all methods are enabled by default
38
+ * Type-safe based on Controller generic parameter
39
+ *
40
+ * @example
41
+ * methods: {
42
+ * getAll: true,
43
+ * getOne: true,
44
+ * postOne: true,
45
+ * patchOne: false, // disabled
46
+ * deleteOne: false, // disabled
47
+ * }
48
+ */
49
+ methods?: ControllerMethodsConfig<Controller>;
50
+ /**
51
+ * Whether ACL is enabled for this controller
52
+ * @default true
53
+ */
54
+ enabled?: boolean;
55
+ }
56
+ /**
57
+ * Metadata stored by @AclController decorator
58
+ */
59
+ export interface AclControllerMetadata<E extends AnyEntity = AnyEntity> {
60
+ subject: AclSubject<E>;
61
+ methods: Record<string, AclControllerMethodsOptions>;
62
+ enabled: boolean;
63
+ }
64
+ export {};
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=decorator-options.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorator-options.types.js","sourceRoot":"","sources":["../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/types/decorator-options.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export * from './acl-options.types';
2
+ export * from './acl-rules.types';
3
+ export * from './decorator-options.types';
4
+ export * from './acl-context.types';
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./acl-options.types"), exports);
5
+ tslib_1.__exportStar(require("./acl-rules.types"), exports);
6
+ tslib_1.__exportStar(require("./decorator-options.types"), exports);
7
+ tslib_1.__exportStar(require("./acl-context.types"), exports);
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/types/index.ts"],"names":[],"mappings":";;;AAAA,8DAAmC;AACnC,4DAAiC;AACjC,oEAAyC;AACzC,8DAAmC"}
@@ -0,0 +1,10 @@
1
+ import { PipeTransform, Type } from '@nestjs/common';
2
+ import { AnyEntity, EntityClass } from '@klerick/json-api-nestjs-shared';
3
+ import { AclControllerMethodsOptions, AclModuleOptions } from '../types';
4
+ export * from './orm-proxy';
5
+ export declare function factoryPipeMixin(entity: EntityClass<AnyEntity>, pipe: Type<PipeTransform>): Type<PipeTransform<any, any>>;
6
+ export declare const nameIt: (name: string, cls: new (...rest: unknown[]) => Record<never, unknown>) => {
7
+ new (...arg: unknown[]): {};
8
+ };
9
+ export declare function copyMethodMetadata(source: Function, target: Function): void;
10
+ export declare function getActionOptions(moduleOptions: AclModuleOptions, actionOptions: AclControllerMethodsOptions): Exclude<AclControllerMethodsOptions, boolean>;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nameIt = void 0;
4
+ exports.factoryPipeMixin = factoryPipeMixin;
5
+ exports.copyMethodMetadata = copyMethodMetadata;
6
+ exports.getActionOptions = getActionOptions;
7
+ const tslib_1 = require("tslib");
8
+ const change_case_commonjs_1 = require("change-case-commonjs");
9
+ const common_1 = require("@nestjs/common");
10
+ tslib_1.__exportStar(require("./orm-proxy"), exports);
11
+ function factoryPipeMixin(entity, pipe) {
12
+ const entityName = entity.name;
13
+ const pipeClass = (0, exports.nameIt)(`${(0, change_case_commonjs_1.pascalCase)(entityName)}${pipe.name}`, pipe);
14
+ (0, common_1.Injectable)()(pipeClass);
15
+ return pipeClass;
16
+ }
17
+ const nameIt = (name, cls) => ({
18
+ [name]: class extends cls {
19
+ constructor(...arg) {
20
+ super(...arg);
21
+ }
22
+ },
23
+ }[name]);
24
+ exports.nameIt = nameIt;
25
+ function copyMethodMetadata(source, target) {
26
+ const metadataKeys = Reflect.getMetadataKeys(source);
27
+ for (const key of metadataKeys) {
28
+ const value = Reflect.getMetadata(key, source);
29
+ Reflect.defineMetadata(key, value, target);
30
+ }
31
+ Object.defineProperty(target, 'name', {
32
+ value: source.name,
33
+ writable: false,
34
+ });
35
+ }
36
+ function getActionOptions(moduleOptions, actionOptions) {
37
+ const defaultOptions = {
38
+ onNoRules: moduleOptions.onNoRules,
39
+ defaultRules: moduleOptions.defaultRules,
40
+ };
41
+ if (actionOptions === undefined ||
42
+ actionOptions === true ||
43
+ actionOptions === false)
44
+ return defaultOptions;
45
+ return {
46
+ ...defaultOptions,
47
+ ...{
48
+ onNoRules: actionOptions.onNoRules,
49
+ defaultRules: actionOptions.defaultRules,
50
+ },
51
+ };
52
+ }
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/utils/index.ts"],"names":[],"mappings":";;;AAQA,4CAcC;AAcD,gDAYC;AAED,4CAuBC;;AAzED,+DAAkD;AAClD,2CAAiE;AAKjE,sDAA4B;AAE5B,SAAgB,gBAAgB,CAC9B,MAA8B,EAC9B,IAAyB;IAEzB,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAE/B,MAAM,SAAS,GAAG,IAAA,cAAM,EACtB,GAAG,IAAA,iCAAU,EAAC,UAAU,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,EACvC,IAAI,CACkB,CAAC;IAEzB,IAAA,mBAAU,GAAE,CAAC,SAAS,CAAC,CAAC;IAExB,OAAO,SAAS,CAAC;AACnB,CAAC;AAEM,MAAM,MAAM,GAAG,CACpB,IAAY,EACZ,GAAuD,EACvD,EAAE,CACF,CAAC;IACC,CAAC,IAAI,CAAC,EAAE,KAAM,SAAQ,GAAG;QACvB,YAAY,GAAG,GAAc;YAC3B,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;QAChB,CAAC;KACF;CACF,CAAC,IAAI,CAAC,CAAC,CAAC;AAVE,QAAA,MAAM,UAUR;AAEX,SAAgB,kBAAkB,CAAC,MAAgB,EAAE,MAAgB;IACnE,MAAM,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAErD,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC/C,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE;QACpC,KAAK,EAAE,MAAM,CAAC,IAAI;QAClB,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,gBAAgB,CAC9B,aAA+B,EAC/B,aAA0C;IAE1C,MAAM,cAAc,GAAG;QACrB,SAAS,EAAE,aAAa,CAAC,SAAS;QAClC,YAAY,EAAE,aAAa,CAAC,YAAY;KACzC,CAAC;IAEF,IACE,aAAa,KAAK,SAAS;QAC3B,aAAa,KAAK,IAAI;QACtB,aAAa,KAAK,KAAK;QAEvB,OAAO,cAAc,CAAC;IAExB,OAAO;QACL,GAAG,cAAc;QACjB,GAAG;YACD,SAAS,EAAE,aAAa,CAAC,SAAS;YAClC,YAAY,EAAE,aAAa,CAAC,YAAY;SACzC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { AnyEntity, EntityClass, QueryField } from '@klerick/json-api-nestjs-shared';
2
+ import { EntityParam, EntityParamMap, QueryOne, Query } from '@klerick/json-api-nestjs';
3
+ import { ModuleRef } from '@nestjs/core';
4
+ /**
5
+ * Singleton class for extracting field paths from entity objects
6
+ *
7
+ * Features:
8
+ * - Skips primary keys (they are always accessible, no ACL check needed)
9
+ * - Recursively processes relationships
10
+ * - Returns flat array of dot-notation paths
11
+ * - Handles one-to-many (arrays) and one-to-one (objects) relationships
12
+ *
13
+ * @example
14
+ * const extractor = ExtractFieldPaths.getInstance(entityParamMap);
15
+ * const obj = {
16
+ * id: 1, // primary key - will be skipped
17
+ * login: 'user',
18
+ * profile: { id: 10, phone: '123' } // profile.id also skipped
19
+ * };
20
+ *
21
+ * const paths = extractor.fields(obj, User);
22
+ * // Returns: ['login', 'profile.phone']
23
+ */
24
+ export declare class ExtractFieldPaths {
25
+ private entityParamMap;
26
+ private constructor();
27
+ private extractField;
28
+ fields<E extends object>(obj: E, entityClass: EntityClass<E>): string[];
29
+ /**
30
+ * Extracts only props (entity fields) from object, excluding relationships and primary key
31
+ * Skips primary key (same as fields() method)
32
+ *
33
+ * Use case: Create merged entity with only base fields for ACL checks
34
+ *
35
+ * @param obj - Source entity object (may contain loaded relationships)
36
+ * @param entityClass - Entity class
37
+ * @returns New object with only entity props (no relationships, no primary key)
38
+ *
39
+ * @example
40
+ * const entity = { id: 1, login: 'user', role: 'admin', profile: { phone: '123' } };
41
+ * const propsOnly = extractor.props(entity, User);
42
+ * // Returns: { login: 'user', role: 'admin' }
43
+ * // Note: id (primary key) and profile (relationship) excluded
44
+ */
45
+ props<E extends object>(obj: E, entityClass: EntityClass<E>): Partial<E>;
46
+ private static instance;
47
+ static getInstance(entityParamMap: EntityParamMap<EntityClass<AnyEntity>>): ExtractFieldPaths;
48
+ }
49
+ export declare function getCurrentEntityAndParamMap<E extends object>(moduleRef: ModuleRef): {
50
+ readonly currentEntity: EntityClass<E>;
51
+ readonly entityParamMap: EntityParam<EntityClass<object>>;
52
+ readonly entityParamMapService: EntityParamMap<EntityClass<object>>;
53
+ };
54
+ /**
55
+ * Extracts field paths for ACL checking
56
+ *
57
+ * This function:
58
+ * 1. Gets entity metadata from moduleRef
59
+ * 2. Clones the sample item
60
+ * 3. Removes ACL-added fields that weren't requested by user
61
+ * 4. Extracts field paths for checking
62
+ *
63
+ * @param moduleRef - NestJS module reference
64
+ * @param sampleItem - Sample entity item (first item for getAll, result for getOne)
65
+ * @param userQuery - Original user query
66
+ * @param aclQueryData - ACL query data (fields and include that were added by ACL)
67
+ * @returns Array of field paths to check
68
+ */
69
+ export declare function extractFieldsForCheck<E extends object, IdKey extends string, Q extends QueryOne<E, IdKey> | Query<E, IdKey>>(moduleRef: ModuleRef, sampleItem: E, userQuery: Q, aclQueryData?: {
70
+ fields?: Q[QueryField.fields];
71
+ include?: Q[QueryField.include];
72
+ rulesForQuery?: Record<string, unknown>;
73
+ }): string[];