@flusys/nestjs-entity-builder 9.1.0-rc.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 (115) hide show
  1. package/README.md +103 -0
  2. package/config/entity-builder.constants.d.ts +6 -0
  3. package/config/event-actions.d.ts +8 -0
  4. package/config/index.d.ts +3 -0
  5. package/config/message-keys.d.ts +481 -0
  6. package/controllers/entity-definition.controller.d.ts +40 -0
  7. package/controllers/field-definition.controller.d.ts +22 -0
  8. package/controllers/flow-api-key.controller.d.ts +14 -0
  9. package/controllers/flow-definition.controller.d.ts +45 -0
  10. package/controllers/flow-execution.controller.d.ts +21 -0
  11. package/controllers/flow-runtime.controller.d.ts +16 -0
  12. package/controllers/index.d.ts +6 -0
  13. package/docs/entity-builder-swagger.config.d.ts +3 -0
  14. package/docs/index.d.ts +1 -0
  15. package/dtos/entity-definition.dto.d.ts +58 -0
  16. package/dtos/field-definition.dto.d.ts +42 -0
  17. package/dtos/flow.dto.d.ts +85 -0
  18. package/dtos/index.d.ts +3 -0
  19. package/dtos/schema-change.dto.d.ts +53 -0
  20. package/entities/entity-definition.entity.d.ts +15 -0
  21. package/entities/field-definition.entity.d.ts +23 -0
  22. package/entities/flow-api-key.entity.d.ts +10 -0
  23. package/entities/flow-definition.entity.d.ts +20 -0
  24. package/entities/flow-execution.entity.d.ts +18 -0
  25. package/entities/index.d.ts +14 -0
  26. package/entities/schema-change-log.entity.d.ts +15 -0
  27. package/enums/ddl-operation.enum.d.ts +13 -0
  28. package/enums/entity-status.enum.d.ts +5 -0
  29. package/enums/field-type.enum.d.ts +15 -0
  30. package/enums/index.d.ts +3 -0
  31. package/fesm/21.js +515 -0
  32. package/fesm/362.js +1074 -0
  33. package/fesm/489.js +1238 -0
  34. package/fesm/606.js +1655 -0
  35. package/fesm/719.js +3615 -0
  36. package/fesm/794.js +1050 -0
  37. package/fesm/996.js +6537 -0
  38. package/fesm/config/index.js +126 -0
  39. package/fesm/controllers/index.js +28 -0
  40. package/fesm/docs/index.js +82 -0
  41. package/fesm/dtos/index.js +327 -0
  42. package/fesm/entities/index.js +18 -0
  43. package/fesm/enums/index.js +97 -0
  44. package/fesm/guards/index.js +228 -0
  45. package/fesm/index.js +1125 -0
  46. package/fesm/interfaces/index.js +80 -0
  47. package/fesm/modules/index.js +642 -0
  48. package/fesm/rule-engine/index.js +21 -0
  49. package/fesm/runtime.js +85 -0
  50. package/fesm/services/index.js +495 -0
  51. package/flow-engine/flow-api-key.d.ts +10 -0
  52. package/flow-engine/flow-code-sandbox.d.ts +5 -0
  53. package/flow-engine/flow-engine.d.ts +22 -0
  54. package/flow-engine/flow-graph.validator.d.ts +19 -0
  55. package/flow-engine/flow-http.client.d.ts +15 -0
  56. package/flow-engine/flow-input.validator.d.ts +7 -0
  57. package/flow-engine/flow-node-handlers.d.ts +5 -0
  58. package/flow-engine/flow-rate-limiter.d.ts +8 -0
  59. package/flow-engine/flow-reference.d.ts +7 -0
  60. package/flow-engine/flow-run.types.d.ts +120 -0
  61. package/flow-engine/flow.errors.d.ts +27 -0
  62. package/flow-engine/flow.types.d.ts +217 -0
  63. package/flow-engine/index.d.ts +4 -0
  64. package/flow-engine/redact.d.ts +3 -0
  65. package/flow-engine/ssrf-guard.d.ts +6 -0
  66. package/guards/flow-access.guard.d.ts +11 -0
  67. package/guards/index.d.ts +1 -0
  68. package/index.d.ts +11 -0
  69. package/interfaces/entity-builder-module.interface.d.ts +28 -0
  70. package/interfaces/field-definition.interface.d.ts +33 -0
  71. package/interfaces/flow-definition.interface.d.ts +20 -0
  72. package/interfaces/generic-record.interface.d.ts +15 -0
  73. package/interfaces/index.d.ts +5 -0
  74. package/interfaces/reference-provider.interface.d.ts +8 -0
  75. package/interfaces/schema-dialect-adapter.interface.d.ts +15 -0
  76. package/modules/entity-builder.module.d.ts +10 -0
  77. package/modules/index.d.ts +1 -0
  78. package/package.json +93 -0
  79. package/rule-engine/index.d.ts +3 -0
  80. package/rule-engine/rule-engine.service.d.ts +39 -0
  81. package/rule-engine/rule-evaluation-context.interface.d.ts +28 -0
  82. package/rule-engine/rule-ip.d.ts +3 -0
  83. package/rule-engine/rule-permission.d.ts +10 -0
  84. package/rule-engine/rule-regex.d.ts +4 -0
  85. package/rule-engine/rule-values.d.ts +5 -0
  86. package/rule-engine/rule.interface.d.ts +79 -0
  87. package/services/database-error.mapper.d.ts +2 -0
  88. package/services/definition-cache.service.d.ts +8 -0
  89. package/services/entity-builder-config.service.d.ts +12 -0
  90. package/services/entity-builder-datasource.provider.d.ts +24 -0
  91. package/services/entity-definition.service.d.ts +17 -0
  92. package/services/entity-flow-scaffold.d.ts +26 -0
  93. package/services/entity-permission.service.d.ts +8 -0
  94. package/services/field-definition.service.d.ts +17 -0
  95. package/services/field-type-conversion.d.ts +15 -0
  96. package/services/field-value-validator.d.ts +17 -0
  97. package/services/flow-api-key.service.d.ts +31 -0
  98. package/services/flow-definition.service.d.ts +49 -0
  99. package/services/flow-execution.service.d.ts +37 -0
  100. package/services/flow-executor.service.d.ts +40 -0
  101. package/services/flow-reference.provider.d.ts +13 -0
  102. package/services/flow-runtime.service.d.ts +29 -0
  103. package/services/generic-entity-service.factory.d.ts +12 -0
  104. package/services/generic-entity.service.d.ts +67 -0
  105. package/services/identifier-rules.d.ts +9 -0
  106. package/services/index.d.ts +27 -0
  107. package/services/reference-rewrite.d.ts +7 -0
  108. package/services/reference-scanner.service.d.ts +10 -0
  109. package/services/schema-change-executor.service.d.ts +39 -0
  110. package/services/schema-change.types.d.ts +59 -0
  111. package/services/schema-columns.d.ts +26 -0
  112. package/services/schema-dialect-adapter.service.d.ts +13 -0
  113. package/services/schema-evolution.service.d.ts +67 -0
  114. package/services/schema-registry.service.d.ts +13 -0
  115. package/services/schema-sync.service.d.ts +28 -0
package/fesm/489.js ADDED
@@ -0,0 +1,1238 @@
1
+ import * as __rspack_external__flusys_nestjs_shared_exceptions_3edf22e9 from "@flusys/nestjs-shared/exceptions";
2
+ import * as __rspack_external__flusys_nestjs_shared_modules_24702bee from "@flusys/nestjs-shared/modules";
3
+ import * as __rspack_external__flusys_nestjs_shared_utils_9125c1f1 from "@flusys/nestjs-shared/utils";
4
+ import * as __rspack_external__nestjs_common_a04939da from "@nestjs/common";
5
+ import * as __rspack_external_node_crypto_2e7c4b46 from "node:crypto";
6
+ import * as __rspack_external_node_net_5ed819e1 from "node:net";
7
+ import * as __rspack_external__flusys_nestjs_shared_interfaces_413f2706 from "@flusys/nestjs-shared/interfaces";
8
+ import * as __rspack_external_re2js from "re2js";
9
+ export const __rspack_esm_id = 489;
10
+ export const __rspack_esm_ids = [489];
11
+ export const __webpack_modules__ = {
12
+ 3372(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
13
+ const RECORD_FILTER_OPS = [
14
+ 'eq',
15
+ 'ne',
16
+ 'gt',
17
+ 'gte',
18
+ 'lt',
19
+ 'lte',
20
+ 'in',
21
+ 'is_null',
22
+ 'not_null'
23
+ ];
24
+ const RECORD_FILTER_LIMITS = {
25
+ MAX_IN_VALUES: 100
26
+ };
27
+ const FILTER_CONDITION_KEYS = new Set([
28
+ 'op',
29
+ 'value'
30
+ ]);
31
+ /**
32
+ * Strict: a plain object whose `op` is a known filter operator and whose only keys are `op` and
33
+ * `value`. Anything else (an expression such as `{ type: 'arithmetic', op: 'sum', ... }`, an
34
+ * object with an unknown `op`) is not a condition.
35
+ */ function isRecordFilterCondition(value) {
36
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
37
+ const op = value.op;
38
+ return typeof op === 'string' && RECORD_FILTER_OPS.includes(op) && Object.keys(value).every((key)=>FILTER_CONDITION_KEYS.has(key));
39
+ }
40
+
41
+ __webpack_require__.d(__webpack_exports__, {
42
+ t1: () => (isRecordFilterCondition)
43
+ }, {
44
+ M5: RECORD_FILTER_LIMITS,
45
+ ox: RECORD_FILTER_OPS
46
+ });
47
+
48
+
49
+ },
50
+ 5920(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
51
+
52
+ // EXPORTS
53
+ __webpack_require__.d(__webpack_exports__, {
54
+ dJ: () => (/* reexport */ rule_interface/* .RULE_COMPARISON_OPERATORS */.dJ),
55
+ qO: () => (/* reexport */ rule_interface/* .RULE_DURATION_UNITS */.qO),
56
+ bw: () => (/* reexport */ rule_interface/* .RULE_ENGINE_LIMITS */.bw),
57
+ l2: () => (/* reexport */ rule_interface/* .RULE_PERMISSION_FUNCTIONS */.l2),
58
+ PK: () => (/* reexport */ rule_interface/* .RULE_REQUEST_FUNCTIONS */.PK),
59
+ ym: () => (/* reexport */ (/* inlined export .RULE_TEMPLATE_MAX_LENGTH */4000)),
60
+ iI: () => (/* reexport */ RuleEngineService),
61
+ A8: () => (/* reexport */ rule_interface/* .isPermissionFunction */.A8),
62
+ GD: () => (/* reexport */ rule_interface/* .isRuleGroup */.GD)
63
+ });
64
+
65
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule.interface.ts
66
+ var rule_interface = __webpack_require__(2354);
67
+ ;// CONCATENATED MODULE: external "@flusys/nestjs-shared/interfaces"
68
+
69
+ // EXTERNAL MODULE: external "@flusys/nestjs-shared/modules"
70
+ var modules_ = __webpack_require__(1236);
71
+ // EXTERNAL MODULE: external "@flusys/nestjs-shared/utils"
72
+ var utils_ = __webpack_require__(9216);
73
+ // EXTERNAL MODULE: external "@nestjs/common"
74
+ var common_ = __webpack_require__(6157);
75
+ // EXTERNAL MODULE: external "node:crypto"
76
+ var external_node_crypto_ = __webpack_require__(2561);
77
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/config/message-keys.ts
78
+ var message_keys = __webpack_require__(5732);
79
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/interfaces/generic-record.interface.ts
80
+ var generic_record_interface = __webpack_require__(3372);
81
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-ip.ts
82
+ var rule_ip = __webpack_require__(809);
83
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-permission.ts
84
+ var rule_permission = __webpack_require__(5191);
85
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-regex.ts + 1 modules
86
+ var rule_regex = __webpack_require__(6308);
87
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-values.ts
88
+ var rule_values = __webpack_require__(6622);
89
+ ;// CONCATENATED MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-engine.service.ts
90
+ function _ts_decorate(decorators, target, key, desc) {
91
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
92
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
93
+ r = Reflect.decorate(decorators, target, key, desc);
94
+ } else {
95
+ for(var i = decorators.length - 1; i >= 0; i--){
96
+ if (d = decorators[i]) {
97
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
98
+ }
99
+ }
100
+ }
101
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
102
+ }
103
+ function _ts_metadata(metadataKey, metadataValue) {
104
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
105
+ return Reflect.metadata(metadataKey, metadataValue);
106
+ }
107
+ }
108
+ function _ts_param(paramIndex, decorator) {
109
+ return function(target, key) {
110
+ decorator(target, key, paramIndex);
111
+ };
112
+ }
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+ const FORBIDDEN_PATH_KEYS = new Set([
126
+ '__proto__',
127
+ 'constructor',
128
+ 'prototype'
129
+ ]);
130
+ const DAY_MS = 86_400_000;
131
+ const UNIT_MS = {
132
+ second: 1000,
133
+ minute: 60_000,
134
+ hour: 3_600_000,
135
+ day: DAY_MS
136
+ };
137
+ class RuleEngineService {
138
+ permissionResolver;
139
+ permissionCache;
140
+ constructor(permissionResolver, permissionCache){
141
+ this.permissionResolver = permissionResolver;
142
+ this.permissionCache = permissionCache;
143
+ }
144
+ /** For callers that evaluate many rules for one user (a flow run): codes are then fetched once per branch. */ createPermissionResolver(user) {
145
+ return (0,rule_permission/* .createRulePermissionResolver */.ce)(user, {
146
+ resolver: this.permissionResolver,
147
+ cache: this.permissionCache
148
+ });
149
+ }
150
+ async evaluateGroup(group, ctx, depth = 0, budget = {}) {
151
+ this.assertWithinLimits(group, depth);
152
+ const evaluate = (node)=>(0,rule_interface/* .isRuleGroup */.GD)(node) ? this.evaluateGroup(node, ctx, depth + 1, budget) : this.evaluateCondition(node, ctx, budget);
153
+ switch(group.operator){
154
+ case 'AND':
155
+ return this.every(group.conditions, evaluate);
156
+ case 'OR':
157
+ for (const node of group.conditions)if (await evaluate(node)) return true;
158
+ return false;
159
+ case 'NOT':
160
+ // NOT negates the combined (AND) result of its children.
161
+ return !await this.every(group.conditions, evaluate);
162
+ default:
163
+ throw new common_.BadRequestException({
164
+ message: `Unknown rule group operator '${String(group.operator)}'.`,
165
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.UNKNOWN_GROUP_OPERATOR */.x3.UNKNOWN_GROUP_OPERATOR,
166
+ messageVariables: {
167
+ operator: String(group.operator)
168
+ }
169
+ });
170
+ }
171
+ }
172
+ async every(nodes, evaluate) {
173
+ for (const node of nodes)if (!await evaluate(node)) return false;
174
+ return true;
175
+ }
176
+ async evaluateCondition(condition, ctx, budget = {}) {
177
+ if (!rule_interface/* .RULE_COMPARISON_OPERATORS.includes */.dJ.includes(condition.comparison)) {
178
+ throw new common_.BadRequestException({
179
+ message: `Unknown rule comparison '${String(condition.comparison)}'.`,
180
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.UNKNOWN_COMPARISON */.x3.UNKNOWN_COMPARISON,
181
+ messageVariables: {
182
+ comparison: String(condition.comparison)
183
+ }
184
+ });
185
+ }
186
+ const actual = await this.resolveConditionLeft(condition, ctx, budget);
187
+ const expected = await this.resolveConditionValue(condition.value, ctx, budget);
188
+ switch(condition.comparison){
189
+ case 'equals':
190
+ return (0,rule_values/* .valuesEqual */.lu)(actual, expected);
191
+ case 'not_equals':
192
+ return !(0,rule_values/* .valuesEqual */.lu)(actual, expected);
193
+ case 'greater_than':
194
+ return this.ordered(actual, expected, (d)=>d > 0);
195
+ case 'less_than':
196
+ return this.ordered(actual, expected, (d)=>d < 0);
197
+ case 'greater_or_equal':
198
+ return this.ordered(actual, expected, (d)=>d >= 0);
199
+ case 'less_or_equal':
200
+ return this.ordered(actual, expected, (d)=>d <= 0);
201
+ case 'contains':
202
+ return this.toContainerCheck(actual, expected);
203
+ case 'not_contains':
204
+ return !this.toContainerCheck(actual, expected);
205
+ case 'starts_with':
206
+ return typeof actual === 'string' && typeof expected === 'string' && actual.startsWith(expected);
207
+ case 'ends_with':
208
+ return typeof actual === 'string' && typeof expected === 'string' && actual.endsWith(expected);
209
+ case 'is_empty':
210
+ return this.isEmptyValue(actual);
211
+ case 'is_not_empty':
212
+ return !this.isEmptyValue(actual);
213
+ case 'in':
214
+ return Array.isArray(expected) && (0,rule_values/* .includesValue */.XL)(expected, actual);
215
+ case 'not_in':
216
+ return Array.isArray(expected) && !(0,rule_values/* .includesValue */.XL)(expected, actual);
217
+ case 'is_any_of':
218
+ return this.hasIntersection(actual, expected);
219
+ case 'is_none_of':
220
+ return !this.hasIntersection(actual, expected);
221
+ case 'is_true':
222
+ return actual === true;
223
+ case 'is_false':
224
+ return actual === false;
225
+ case 'matches':
226
+ return (0,rule_regex/* .matchesPattern */.MT)(actual, expected);
227
+ case 'not_matches':
228
+ return !(0,rule_regex/* .matchesPattern */.MT)(actual, expected);
229
+ }
230
+ }
231
+ async resolveConditionLeft(condition, ctx, budget) {
232
+ if (condition.left) return this.resolveExpression(condition.left, ctx, budget);
233
+ if (typeof condition.field === 'string' && condition.field) return this.resolveFieldReference(condition.field, ctx);
234
+ throw new common_.BadRequestException({
235
+ message: 'A rule condition needs a field or a left-hand expression.',
236
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.CONDITION_INCOMPLETE */.x3.CONDITION_INCOMPLETE
237
+ });
238
+ }
239
+ async resolveConditionValue(value, ctx, budget) {
240
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return value;
241
+ if ('$field' in value) return this.resolveFieldReference(value.$field, ctx);
242
+ if ('$expr' in value) return this.resolveExpression(value.$expr, ctx, budget);
243
+ return value;
244
+ }
245
+ async resolveExpression(expression, ctx, budget = {}) {
246
+ switch(expression.type){
247
+ case 'literal':
248
+ return expression.value;
249
+ case 'field_ref':
250
+ return this.resolveFieldReference(expression.ref, ctx);
251
+ case 'arithmetic':
252
+ {
253
+ const operands = await Promise.all(expression.operands.map((op)=>this.resolveExpression(op, ctx, budget)));
254
+ const numbers = operands.map((v)=>this.toNumber(v));
255
+ return this.applyArithmetic(expression.op, numbers);
256
+ }
257
+ case 'concat':
258
+ {
259
+ const parts = await Promise.all(expression.parts.map((p)=>this.resolveExpression(p, ctx, budget)));
260
+ return parts.map((p)=>p ?? '').join('');
261
+ }
262
+ case 'function':
263
+ return this.resolveFunction(expression.name, expression.args, ctx, budget);
264
+ case 'template':
265
+ return this.resolveTemplate(expression.template, ctx);
266
+ case 'lookup':
267
+ return this.resolveLookup(expression, ctx, budget);
268
+ }
269
+ }
270
+ async resolveLookup(expression, ctx, budget) {
271
+ if (!ctx.lookupResolver) {
272
+ throw new common_.BadRequestException({
273
+ message: `A lookup on '${expression.entity}' is only available inside flows.`,
274
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.LOOKUP_RESOLVER_UNAVAILABLE */.x3.LOOKUP_RESOLVER_UNAVAILABLE,
275
+ messageVariables: {
276
+ entity: expression.entity
277
+ }
278
+ });
279
+ }
280
+ budget.lookups = (budget.lookups ?? 0) + 1;
281
+ if (budget.lookups > rule_interface/* .RULE_ENGINE_LIMITS.MAX_LOOKUPS */.bw.MAX_LOOKUPS) {
282
+ throw new common_.BadRequestException({
283
+ message: `Rule exceeded the maximum of ${rule_interface/* .RULE_ENGINE_LIMITS.MAX_LOOKUPS */.bw.MAX_LOOKUPS} lookups per evaluation.`,
284
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.LOOKUP_LIMIT_EXCEEDED */.x3.LOOKUP_LIMIT_EXCEEDED,
285
+ messageVariables: {
286
+ max: rule_interface/* .RULE_ENGINE_LIMITS.MAX_LOOKUPS */.bw.MAX_LOOKUPS
287
+ }
288
+ });
289
+ }
290
+ const filter = {};
291
+ for (const [key, item] of Object.entries(expression.filter ?? {})){
292
+ if ((0,generic_record_interface/* .isRecordFilterCondition */.t1)(item)) {
293
+ const value = item.value === undefined ? undefined : await this.resolveExpression(item.value, ctx, budget);
294
+ filter[key] = value === undefined ? {
295
+ op: item.op
296
+ } : {
297
+ op: item.op,
298
+ value
299
+ };
300
+ } else {
301
+ filter[key] = (0,rule_values/* .equalsOperand */.$b)(await this.resolveExpression(item, ctx, budget));
302
+ }
303
+ }
304
+ const { rows, total } = await ctx.lookupResolver.find(expression.entity, {
305
+ filter,
306
+ sort: expression.sort ? {
307
+ [expression.sort.field]: expression.sort.direction === 'DESC' ? 'DESC' : 'ASC'
308
+ } : undefined,
309
+ limit: 1
310
+ });
311
+ switch(expression.mode){
312
+ case 'exists':
313
+ return total > 0;
314
+ case 'count':
315
+ return total;
316
+ default:
317
+ {
318
+ const row = rows[0];
319
+ if (!row) return null;
320
+ return expression.field ? this.getPath(row, expression.field) ?? null : row;
321
+ }
322
+ }
323
+ }
324
+ resolveTemplate(template, ctx) {
325
+ if (template.length > (/* inlined export .RULE_TEMPLATE_MAX_LENGTH */4000)) {
326
+ throw new common_.BadRequestException({
327
+ message: `Template is longer than ${(/* inlined export .RULE_TEMPLATE_MAX_LENGTH */4000)} characters.`,
328
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.TEMPLATE_TOO_LONG */.x3.TEMPLATE_TOO_LONG,
329
+ messageVariables: {
330
+ max: (/* inlined export .RULE_TEMPLATE_MAX_LENGTH */4000)
331
+ }
332
+ });
333
+ }
334
+ const pattern = /\{\{\s*([A-Za-z_][\w.]*)\s*\}\}/g;
335
+ let result = '';
336
+ let last = 0;
337
+ for (const match of template.matchAll(pattern)){
338
+ result += template.slice(last, match.index);
339
+ const value = this.resolveFieldReference(match[1], ctx);
340
+ result += value === null || value === undefined ? '' : typeof value === 'object' ? JSON.stringify(value) : String(value);
341
+ last = match.index + match[0].length;
342
+ }
343
+ return result + template.slice(last);
344
+ }
345
+ // ── Field references ────────────────────────────────────────────────────────────────
346
+ resolveFieldReference(ref, ctx) {
347
+ const [scope, ...rest] = ref.split('.');
348
+ const path = rest.join('.');
349
+ switch(scope){
350
+ case 'input':
351
+ return this.getPath(ctx.input, path);
352
+ case 'context':
353
+ {
354
+ const [stepId, ...fieldPath] = rest;
355
+ return this.getPath(ctx.context?.[stepId], fieldPath.join('.'));
356
+ }
357
+ case 'vars':
358
+ return this.getPath(ctx.vars, path);
359
+ case 'loop':
360
+ return this.getPath(ctx.loop, path);
361
+ case 'request':
362
+ return this.getPath(ctx.request, path);
363
+ case 'user':
364
+ return this.getPath(ctx.user, path);
365
+ default:
366
+ throw new common_.BadRequestException({
367
+ message: `Unknown field reference scope '${scope}' in '${ref}'. Must start with input., context., vars., loop., request. or user.`,
368
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.INVALID_FIELD_REFERENCE */.x3.INVALID_FIELD_REFERENCE,
369
+ messageVariables: {
370
+ scope,
371
+ ref
372
+ }
373
+ });
374
+ }
375
+ }
376
+ getPath(source, path) {
377
+ if (!source) return undefined;
378
+ if (!path) return source;
379
+ return path.split('.').reduce((acc, key)=>{
380
+ if (FORBIDDEN_PATH_KEYS.has(key)) return undefined;
381
+ if (acc && typeof acc === 'object') return acc[key];
382
+ return undefined;
383
+ }, source);
384
+ }
385
+ // ── Functions ────────────────────────────────────────────────────────────────────────
386
+ async resolveFunction(name, args, ctx, budget) {
387
+ const resolvedArgs = await Promise.all(args.map((a)=>this.resolveExpression(a, ctx, budget)));
388
+ switch(name){
389
+ case 'NOW':
390
+ return new Date().toISOString();
391
+ case 'UUID':
392
+ return (0,external_node_crypto_.randomUUID)();
393
+ case 'CURRENT_USER_ID':
394
+ return ctx.user?.id ?? null;
395
+ case 'COALESCE':
396
+ return resolvedArgs.find((v)=>v !== null && v !== undefined) ?? null;
397
+ case 'ROUND':
398
+ {
399
+ const [value, precision] = resolvedArgs;
400
+ const factor = 10 ** this.toNumber(precision ?? 0);
401
+ return Math.round(this.toNumber(value) * factor) / factor;
402
+ }
403
+ case 'DATE_DIFF':
404
+ {
405
+ const [a, b, unit] = resolvedArgs;
406
+ const from = this.toTime(a);
407
+ const to = this.toTime(b);
408
+ if (from === null || to === null) return null;
409
+ return (from - to) / UNIT_MS[this.toDurationUnit(unit)];
410
+ }
411
+ case 'START_OF_DAY':
412
+ case 'END_OF_DAY':
413
+ {
414
+ const [value, offset] = resolvedArgs;
415
+ const time = this.toTime(value);
416
+ if (time === null) return null;
417
+ const offsetMs = this.toUtcOffset(offset) * 60_000;
418
+ const start = Math.floor((time + offsetMs) / DAY_MS) * DAY_MS - offsetMs;
419
+ return new Date(name === 'START_OF_DAY' ? start : start + DAY_MS - 1).toISOString();
420
+ }
421
+ case 'ADD_DURATION':
422
+ {
423
+ const [value, amount, unit] = resolvedArgs;
424
+ const time = this.toTime(value);
425
+ if (time === null) return null;
426
+ return new Date(time + this.toNumber(amount) * UNIT_MS[this.toDurationUnit(unit)]).toISOString();
427
+ }
428
+ case 'HAS_PERMISSION':
429
+ case 'HAS_ANY_PERMISSION':
430
+ case 'HAS_ALL_PERMISSIONS':
431
+ return this.hasPermissions(name, resolvedArgs, ctx, budget);
432
+ case 'HEADER':
433
+ {
434
+ const headers = ctx.request?.['headers'];
435
+ const value = typeof resolvedArgs[0] === 'string' && headers ? headers[resolvedArgs[0].trim().toLowerCase()] : undefined;
436
+ return typeof value === 'string' ? value : null;
437
+ }
438
+ case 'QUERY_PARAM':
439
+ {
440
+ const query = ctx.request?.['query'];
441
+ const value = typeof resolvedArgs[0] === 'string' && query && Object.hasOwn(query, resolvedArgs[0]) ? query[resolvedArgs[0]] : undefined;
442
+ return typeof value === 'string' ? value : null;
443
+ }
444
+ case 'IP_IN_RANGE':
445
+ return (0,rule_ip/* .ipInRanges */.p_)(resolvedArgs[0], resolvedArgs[1]);
446
+ case 'LOWER':
447
+ case 'UPPER':
448
+ case 'TRIM':
449
+ {
450
+ const text = this.toText(resolvedArgs[0]);
451
+ if (text === null) return null;
452
+ return name === 'LOWER' ? text.toLowerCase() : name === 'UPPER' ? text.toUpperCase() : text.trim();
453
+ }
454
+ case 'LENGTH':
455
+ {
456
+ const [value] = resolvedArgs;
457
+ if (Array.isArray(value)) return value.length;
458
+ return this.toText(value)?.length ?? 0;
459
+ }
460
+ case 'SPLIT_PART':
461
+ {
462
+ const [value, separator, position] = resolvedArgs;
463
+ const text = this.toText(value);
464
+ if (text === null || typeof separator !== 'string' || !separator) return null;
465
+ const parts = text.split(separator);
466
+ const n = this.toNumber(position ?? 1);
467
+ const part = Number.isInteger(n) && n !== 0 ? parts[n > 0 ? n - 1 : parts.length + n] : undefined;
468
+ return part === undefined ? null : part.trim();
469
+ }
470
+ case 'REGEX_EXTRACT':
471
+ return (0,rule_regex/* .extractPattern */.Ax)(resolvedArgs[0], resolvedArgs[1], resolvedArgs[2]);
472
+ case 'REPLACE':
473
+ {
474
+ const [value, search, replacement] = resolvedArgs;
475
+ const text = this.toText(value);
476
+ if (text === null) return null;
477
+ const needle = this.toText(search) ?? '';
478
+ return needle ? text.replaceAll(needle, this.toText(replacement) ?? '') : text;
479
+ }
480
+ case 'TO_NUMBER':
481
+ {
482
+ const [value] = resolvedArgs;
483
+ if (typeof value === 'number') return Number.isFinite(value) ? value : null;
484
+ if (typeof value === 'boolean') return value ? 1 : 0;
485
+ if (typeof value !== 'string' || value.trim() === '') return null;
486
+ const n = Number(value.trim());
487
+ return Number.isFinite(n) ? n : null;
488
+ }
489
+ default:
490
+ throw new common_.BadRequestException({
491
+ message: `Unknown rule function '${String(name)}'.`,
492
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.UNKNOWN_FUNCTION */.x3.UNKNOWN_FUNCTION,
493
+ messageVariables: {
494
+ name: String(name)
495
+ }
496
+ });
497
+ }
498
+ }
499
+ // ── Permissions ──────────────────────────────────────────────────────────────────────
500
+ /** HAS_PERMISSION(code, branch?) / HAS_ANY_PERMISSION(codes, branch?) / HAS_ALL_PERMISSIONS(codes, branch?). */ async hasPermissions(name, args, ctx, budget) {
501
+ const codes = (0,rule_permission/* .parsePermissionCodes */.PS)(args[0]);
502
+ if (!codes.length || !ctx.user) return false;
503
+ const resolver = ctx.permissions ?? (budget.permissions ??= this.createPermissionResolver(ctx.user));
504
+ const granted = await resolver.granted((0,rule_permission/* .toBranchArgument */.lH)(args, 1));
505
+ const held = (code)=>(0,utils_.matchesPermission)(granted, code);
506
+ return name === 'HAS_ANY_PERMISSION' ? codes.some(held) : codes.every(held);
507
+ }
508
+ // ── Comparison / value helpers ──────────────────────────────────────────────────────
509
+ /** Text of a scalar; null for null/undefined and for objects/lists. */ toText(value) {
510
+ if (typeof value === 'string') return value;
511
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value);
512
+ return null;
513
+ }
514
+ /** Epoch ms of a Date, ISO text or epoch number; null for null/undefined. */ toTime(value) {
515
+ if (value === null || value === undefined) return null;
516
+ const time = value instanceof Date ? value.getTime() : typeof value === 'number' ? value : typeof value === 'string' ? (0,rule_values/* .parseDateText */.hz)(value) : Number.NaN;
517
+ if (!Number.isFinite(time)) {
518
+ throw new common_.BadRequestException({
519
+ message: `Expected a date, got '${JSON.stringify(value)}'.`,
520
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.EXPECTED_DATE */.x3.EXPECTED_DATE,
521
+ messageVariables: {
522
+ value: JSON.stringify(value)
523
+ }
524
+ });
525
+ }
526
+ return time;
527
+ }
528
+ toDurationUnit(value) {
529
+ if (typeof value === 'string' && rule_interface/* .RULE_DURATION_UNITS.includes */.qO.includes(value)) return value;
530
+ throw new common_.BadRequestException({
531
+ message: `Unknown duration unit '${String(value)}'. Use ${rule_interface/* .RULE_DURATION_UNITS.join */.qO.join(', ')}.`,
532
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.INVALID_DURATION_UNIT */.x3.INVALID_DURATION_UNIT,
533
+ messageVariables: {
534
+ unit: String(value),
535
+ units: rule_interface/* .RULE_DURATION_UNITS.join */.qO.join(', ')
536
+ }
537
+ });
538
+ }
539
+ toUtcOffset(value) {
540
+ if (value === null || value === undefined) return 0;
541
+ const offset = this.tryToNumber(value);
542
+ if (offset === null || !Number.isInteger(offset) || Math.abs(offset) > rule_interface/* .RULE_ENGINE_LIMITS.MAX_UTC_OFFSET_MINUTES */.bw.MAX_UTC_OFFSET_MINUTES) {
543
+ throw new common_.BadRequestException({
544
+ message: `The UTC offset must be a whole number of minutes between -${rule_interface/* .RULE_ENGINE_LIMITS.MAX_UTC_OFFSET_MINUTES */.bw.MAX_UTC_OFFSET_MINUTES} and ${rule_interface/* .RULE_ENGINE_LIMITS.MAX_UTC_OFFSET_MINUTES */.bw.MAX_UTC_OFFSET_MINUTES}.`,
545
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.INVALID_UTC_OFFSET */.x3.INVALID_UTC_OFFSET,
546
+ messageVariables: {
547
+ max: rule_interface/* .RULE_ENGINE_LIMITS.MAX_UTC_OFFSET_MINUTES */.bw.MAX_UTC_OFFSET_MINUTES
548
+ }
549
+ });
550
+ }
551
+ return offset;
552
+ }
553
+ /** Ordering is false whenever either side is null/missing - a missing amount is never "<= limit". */ ordered(a, b, test) {
554
+ if (a === null || a === undefined || b === null || b === undefined) return false;
555
+ const numA = this.tryToNumber(a);
556
+ const numB = this.tryToNumber(b);
557
+ if (numA !== null && numB !== null) return test(numA - numB);
558
+ return test(String(a).localeCompare(String(b)));
559
+ }
560
+ toContainerCheck(actual, expected) {
561
+ if (typeof actual === 'string' && typeof expected === 'string') {
562
+ return actual.includes(expected);
563
+ }
564
+ if (Array.isArray(actual)) {
565
+ return (0,rule_values/* .includesValue */.XL)(actual, expected);
566
+ }
567
+ return false;
568
+ }
569
+ isEmptyValue(value) {
570
+ if (value === null || value === undefined) return true;
571
+ if (typeof value === 'string') return value.length === 0;
572
+ if (Array.isArray(value)) return value.length === 0;
573
+ return false;
574
+ }
575
+ hasIntersection(actual, expected) {
576
+ const actualArray = Array.isArray(actual) ? actual : [
577
+ actual
578
+ ];
579
+ const expectedArray = Array.isArray(expected) ? expected : [
580
+ expected
581
+ ];
582
+ return actualArray.some((v)=>(0,rule_values/* .includesValue */.XL)(expectedArray, v));
583
+ }
584
+ toNumber(value) {
585
+ const num = this.tryToNumber(value);
586
+ if (num === null) {
587
+ throw new common_.BadRequestException({
588
+ message: `Expected a numeric value, got '${JSON.stringify(value)}'.`,
589
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.EXPECTED_NUMBER */.x3.EXPECTED_NUMBER,
590
+ messageVariables: {
591
+ value: JSON.stringify(value)
592
+ }
593
+ });
594
+ }
595
+ return num;
596
+ }
597
+ tryToNumber(value) {
598
+ if (typeof value === 'number') return value;
599
+ if (value instanceof Date) return value.getTime();
600
+ if (typeof value === 'string') {
601
+ const asDate = rule_values/* .ISO_DATE_PREFIX.test */.YN.test(value) ? (0,rule_values/* .parseDateText */.hz)(value) : Number.NaN;
602
+ if (!Number.isNaN(asDate)) return asDate;
603
+ const asNumber = Number(value);
604
+ if (!Number.isNaN(asNumber) && value.trim() !== '') return asNumber;
605
+ }
606
+ return null;
607
+ }
608
+ applyArithmetic(op, values) {
609
+ switch(op){
610
+ case 'sum':
611
+ return values.reduce((a, b)=>a + b, 0);
612
+ case 'subtract':
613
+ return values.slice(1).reduce((a, b)=>a - b, values[0] ?? 0);
614
+ case 'multiply':
615
+ return values.reduce((a, b)=>a * b, 1);
616
+ case 'divide':
617
+ return values.slice(1).reduce((a, b)=>{
618
+ if (b === 0) {
619
+ throw new common_.BadRequestException({
620
+ message: 'Division by zero in rule arithmetic expression.',
621
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.DIVISION_BY_ZERO */.x3.DIVISION_BY_ZERO
622
+ });
623
+ }
624
+ return a / b;
625
+ }, values[0] ?? 0);
626
+ case 'min':
627
+ return Math.min(...values);
628
+ case 'max':
629
+ return Math.max(...values);
630
+ }
631
+ }
632
+ // ── Save-time / defensive limits ────────────────────────────────────────────────────
633
+ assertWithinLimits(group, depth) {
634
+ if (depth > rule_interface/* .RULE_ENGINE_LIMITS.MAX_GROUP_DEPTH */.bw.MAX_GROUP_DEPTH) {
635
+ throw new common_.BadRequestException({
636
+ message: `Rule group nesting exceeds the maximum depth of ${rule_interface/* .RULE_ENGINE_LIMITS.MAX_GROUP_DEPTH */.bw.MAX_GROUP_DEPTH}.`,
637
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.MAX_DEPTH_EXCEEDED */.x3.MAX_DEPTH_EXCEEDED,
638
+ messageVariables: {
639
+ max: rule_interface/* .RULE_ENGINE_LIMITS.MAX_GROUP_DEPTH */.bw.MAX_GROUP_DEPTH
640
+ }
641
+ });
642
+ }
643
+ if (group.conditions.length > rule_interface/* .RULE_ENGINE_LIMITS.MAX_CONDITIONS_PER_GROUP */.bw.MAX_CONDITIONS_PER_GROUP) {
644
+ throw new common_.BadRequestException({
645
+ message: `Rule group has ${group.conditions.length} conditions, exceeding the maximum of ${rule_interface/* .RULE_ENGINE_LIMITS.MAX_CONDITIONS_PER_GROUP */.bw.MAX_CONDITIONS_PER_GROUP}.`,
646
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.MAX_CONDITIONS_EXCEEDED */.x3.MAX_CONDITIONS_EXCEEDED,
647
+ messageVariables: {
648
+ count: group.conditions.length,
649
+ max: rule_interface/* .RULE_ENGINE_LIMITS.MAX_CONDITIONS_PER_GROUP */.bw.MAX_CONDITIONS_PER_GROUP
650
+ }
651
+ });
652
+ }
653
+ }
654
+ }
655
+ RuleEngineService = _ts_decorate([
656
+ (0,common_.Injectable)(),
657
+ _ts_param(0, (0,common_.Optional)()),
658
+ _ts_param(0, (0,common_.Inject)(__rspack_external__flusys_nestjs_shared_interfaces_413f2706.PERMISSION_RESOLVER)),
659
+ _ts_param(1, (0,common_.Optional)()),
660
+ _ts_param(1, (0,common_.Inject)(modules_.SharedPermissionCacheService)),
661
+ _ts_metadata("design:type", Function),
662
+ _ts_metadata("design:paramtypes", [
663
+ typeof IPermissionResolver === "undefined" ? Object : IPermissionResolver,
664
+ typeof modules_.SharedPermissionCacheService === "undefined" ? Object : modules_.SharedPermissionCacheService
665
+ ])
666
+ ], RuleEngineService);
667
+
668
+ ;// CONCATENATED MODULE: ./projects/nestjs-entity-builder/src/rule-engine/index.ts
669
+
670
+
671
+
672
+
673
+
674
+ },
675
+ 809(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
676
+ /* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
677
+ /* import */ var node_net__rspack_import_1 = __webpack_require__(8299);
678
+ /* import */ var _config_message_keys_js__rspack_import_3 = __webpack_require__(5732);
679
+ /* import */ var _rule_interface_js__rspack_import_2 = __webpack_require__(2354);
680
+
681
+
682
+
683
+
684
+ const MAX_CACHED_LISTS = 200;
685
+ const lists = new Map();
686
+ /** Drops `[...]`, a zone id and the IPv4-mapped prefix, so `::ffff:10.0.0.1` compares as `10.0.0.1`. */ function normalizeIp(value) {
687
+ let ip = value.trim();
688
+ if (ip.startsWith('[') && ip.endsWith(']')) ip = ip.slice(1, -1);
689
+ ip = ip.split('%')[0];
690
+ const mapped = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(ip);
691
+ return mapped ? mapped[1] : ip;
692
+ }
693
+ function familyOf(ip) {
694
+ const version = (0,node_net__rspack_import_1.isIP)(ip);
695
+ return version === 4 ? 'ipv4' : version === 6 ? 'ipv6' : null;
696
+ }
697
+ /** One range: an address (`10.0.0.1`, `2001:db8::1`) or a CIDR block (`10.0.0.0/8`, `fd00::/8`). */ function addRange(list, range) {
698
+ const [address, prefix, extra] = range.split('/');
699
+ const ip = normalizeIp(address ?? '');
700
+ const family = familyOf(ip);
701
+ if (!family || extra !== undefined) return false;
702
+ if (prefix === undefined) {
703
+ list.addAddress(ip, family);
704
+ return true;
705
+ }
706
+ const bits = /^\d{1,3}$/.test(prefix) ? Number(prefix) : Number.NaN;
707
+ if (!(bits >= 0 && bits <= (family === 'ipv4' ? 32 : 128))) return false;
708
+ list.addSubnet(ip, bits, family);
709
+ return true;
710
+ }
711
+ /** A list, or text separated by commas / whitespace. */ function parseIpRanges(value) {
712
+ const raw = Array.isArray(value) ? value : typeof value === 'string' ? value.split(/[\s,]+/) : [];
713
+ return raw.filter((r)=>typeof r === 'string').map((r)=>r.trim()).filter(Boolean);
714
+ }
715
+ /** The first range that is not a valid address or CIDR block, or null when all are. */ function invalidIpRange(value) {
716
+ const probe = new node_net__rspack_import_1.BlockList();
717
+ return parseIpRanges(value).find((range)=>!addRange(probe, range)) ?? null;
718
+ }
719
+ /** Whether `ip` falls in any of `ranges`; a missing or malformed ip is never in range. */ function ipInRanges(ip, ranges) {
720
+ if (typeof ip !== 'string') return false;
721
+ const address = normalizeIp(ip);
722
+ const family = familyOf(address);
723
+ if (!family) return false;
724
+ return blockListFor(parseIpRanges(ranges)).check(address, family);
725
+ }
726
+ function blockListFor(ranges) {
727
+ if (ranges.length > _rule_interface_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_IP_RANGES */.bw.MAX_IP_RANGES) {
728
+ throw new _nestjs_common__rspack_import_0.BadRequestException({
729
+ message: `An IP range check can list at most ${_rule_interface_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_IP_RANGES */.bw.MAX_IP_RANGES} ranges.`,
730
+ messageKey: _config_message_keys_js__rspack_import_3/* .RULE_ENGINE_MESSAGES.TOO_MANY_IP_RANGES */.x3.TOO_MANY_IP_RANGES,
731
+ messageVariables: {
732
+ max: _rule_interface_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_IP_RANGES */.bw.MAX_IP_RANGES
733
+ }
734
+ });
735
+ }
736
+ const key = ranges.join(',');
737
+ const cached = lists.get(key);
738
+ if (cached) return cached;
739
+ const list = new node_net__rspack_import_1.BlockList();
740
+ for (const range of ranges){
741
+ if (!addRange(list, range)) {
742
+ throw new _nestjs_common__rspack_import_0.BadRequestException({
743
+ message: `'${range}' is not an IP address or CIDR range.`,
744
+ messageKey: _config_message_keys_js__rspack_import_3/* .RULE_ENGINE_MESSAGES.INVALID_IP_RANGE */.x3.INVALID_IP_RANGE,
745
+ messageVariables: {
746
+ range
747
+ }
748
+ });
749
+ }
750
+ }
751
+ if (lists.size >= MAX_CACHED_LISTS) lists.delete(lists.keys().next().value);
752
+ lists.set(key, list);
753
+ return list;
754
+ }
755
+
756
+ __webpack_require__.d(__webpack_exports__, {
757
+ I8: () => (invalidIpRange),
758
+ p_: () => (ipInRanges)
759
+ });
760
+
761
+
762
+ },
763
+ 5191(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
764
+ /* import */ var _flusys_nestjs_shared_exceptions__rspack_import_0 = __webpack_require__(2417);
765
+ /* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(6157);
766
+ /* import */ var _config_message_keys_js__rspack_import_3 = __webpack_require__(5732);
767
+ /* import */ var _rule_interface_js__rspack_import_2 = __webpack_require__(2354);
768
+
769
+
770
+
771
+
772
+ /**
773
+ * Codes are looked up once per branch for the resolver's lifetime (one flow run, or one rule
774
+ * evaluation), so a permission check inside a loop does not hit the cache per item. No user = no
775
+ * permissions; no permission system at all fails closed with PermissionSystemUnavailableException.
776
+ */ function createRulePermissionResolver(user, sources) {
777
+ const memo = new Map();
778
+ return {
779
+ granted (branchId) {
780
+ if (!user) return Promise.resolve([]);
781
+ const branch = branchId === undefined ? user.branchId ?? null : branchId;
782
+ const key = branch ?? '';
783
+ let codes = memo.get(key);
784
+ if (!codes) {
785
+ codes = loadCodes({
786
+ userId: user.id,
787
+ companyId: user.companyId ?? null,
788
+ branchId: branch
789
+ }, sources);
790
+ memo.set(key, codes);
791
+ }
792
+ return codes;
793
+ }
794
+ };
795
+ }
796
+ async function loadCodes(scope, sources) {
797
+ if (sources.resolver) return sources.resolver.getPermissionCodes(scope);
798
+ if (sources.cache?.isCacheConfigured()) return sources.cache.getPermissions(scope);
799
+ throw new _flusys_nestjs_shared_exceptions__rspack_import_0.PermissionSystemUnavailableException();
800
+ }
801
+ /** A list, or text separated by commas / whitespace, as distinct codes. */ function parsePermissionCodes(value) {
802
+ const raw = Array.isArray(value) ? value : typeof value === 'string' ? value.split(/[\s,]+/) : [];
803
+ const codes = [
804
+ ...new Set(raw.filter((c)=>typeof c === 'string').map((c)=>c.trim()).filter(Boolean))
805
+ ];
806
+ if (codes.length > _rule_interface_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_PERMISSION_CODES */.bw.MAX_PERMISSION_CODES) {
807
+ throw new _nestjs_common__rspack_import_1.BadRequestException({
808
+ message: `A permission check can name at most ${_rule_interface_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_PERMISSION_CODES */.bw.MAX_PERMISSION_CODES} permissions.`,
809
+ messageKey: _config_message_keys_js__rspack_import_3/* .RULE_ENGINE_MESSAGES.TOO_MANY_PERMISSION_CODES */.x3.TOO_MANY_PERMISSION_CODES,
810
+ messageVariables: {
811
+ max: _rule_interface_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_PERMISSION_CODES */.bw.MAX_PERMISSION_CODES
812
+ }
813
+ });
814
+ }
815
+ return codes;
816
+ }
817
+ /** The branch argument: omitted = the user's current branch, null/empty = company-wide only. */ function toBranchArgument(args, index) {
818
+ if (args.length <= index) return undefined;
819
+ const value = args[index];
820
+ if (value === null || value === undefined || value === '') return null;
821
+ return String(value);
822
+ }
823
+
824
+ __webpack_require__.d(__webpack_exports__, {
825
+ PS: () => (parsePermissionCodes),
826
+ ce: () => (createRulePermissionResolver),
827
+ lH: () => (toBranchArgument)
828
+ });
829
+
830
+
831
+ },
832
+ 6308(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
833
+
834
+ // EXPORTS
835
+ __webpack_require__.d(__webpack_exports__, {
836
+ Ax: () => (/* binding */ extractPattern),
837
+ MT: () => (/* binding */ matchesPattern),
838
+ _V: () => (/* binding */ rulePatternProblem)
839
+ });
840
+
841
+ // EXTERNAL MODULE: external "@nestjs/common"
842
+ var common_ = __webpack_require__(6157);
843
+ ;// CONCATENATED MODULE: external "re2js"
844
+
845
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/config/message-keys.ts
846
+ var message_keys = __webpack_require__(5732);
847
+ // EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule.interface.ts
848
+ var rule_interface = __webpack_require__(2354);
849
+ ;// CONCATENATED MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-regex.ts
850
+
851
+
852
+
853
+
854
+ const MAX_CACHED_PATTERNS = 200;
855
+ const compiled = new Map();
856
+ const tooComplex = new Map();
857
+ function remember(cache, pattern, make) {
858
+ if (cache.has(pattern)) return cache.get(pattern);
859
+ const value = make(pattern);
860
+ if (cache.size >= MAX_CACHED_PATTERNS) cache.delete(cache.keys().next().value);
861
+ cache.set(pattern, value);
862
+ return value;
863
+ }
864
+ /** Why a pattern cannot be used, or null when it compiles within the limits. */ function rulePatternProblem(pattern) {
865
+ if (pattern.length > rule_interface/* .RULE_ENGINE_LIMITS.MAX_REGEX_PATTERN_LENGTH */.bw.MAX_REGEX_PATTERN_LENGTH) return 'too_long';
866
+ if (remember(tooComplex, pattern, isTooComplex)) return 'too_complex';
867
+ try {
868
+ compile(pattern);
869
+ return null;
870
+ } catch {
871
+ return 'invalid';
872
+ }
873
+ }
874
+ const newFrame = ()=>({
875
+ size: 0,
876
+ last: 0,
877
+ lastProduct: 1,
878
+ maxProduct: 1
879
+ });
880
+ /**
881
+ * RE2 unrolls counted repeats (`x{2,50}` becomes 50 copies of x), so match time grows with the
882
+ * product of nested counts. Rejects a count above MAX_REGEX_REPEAT, nested counts whose product
883
+ * is above it, and a pattern whose unrolled size grows by more than MAX_REGEX_REPEAT_EXPANSION.
884
+ * `*`, `+` and `?` do not unroll and stay allowed, nested or not.
885
+ */ function isTooComplex(pattern) {
886
+ const { MAX_REGEX_REPEAT, MAX_REGEX_REPEAT_EXPANSION } = rule_interface/* .RULE_ENGINE_LIMITS */.bw;
887
+ const stack = [
888
+ newFrame()
889
+ ];
890
+ const top = ()=>stack[stack.length - 1];
891
+ let atoms = 0;
892
+ const atom = (size, product)=>{
893
+ const frame = top();
894
+ frame.size += size;
895
+ frame.last = size;
896
+ frame.lastProduct = product;
897
+ frame.maxProduct = Math.max(frame.maxProduct, product);
898
+ };
899
+ let i = 0;
900
+ while(i < pattern.length){
901
+ const c = pattern[i];
902
+ if (c === '\\') {
903
+ const next = pattern[i + 1];
904
+ i += 2;
905
+ if ((next === 'p' || next === 'P' || next === 'x') && pattern[i] === '{') i = closing(pattern, i, '}');
906
+ atoms++;
907
+ atom(1, 1);
908
+ } else if (c === '[') {
909
+ i = classEnd(pattern, i);
910
+ atoms++;
911
+ atom(1, 1);
912
+ } else if (c === '(') {
913
+ i++;
914
+ if (pattern[i] === '?') {
915
+ const flagsOnly = /^\?[a-zA-Z-]*\)/.exec(pattern.slice(i));
916
+ if (flagsOnly) {
917
+ i += flagsOnly[0].length;
918
+ continue;
919
+ }
920
+ const marker = /^\?(?:P?<[^>]*>|[a-zA-Z-]*:)/.exec(pattern.slice(i));
921
+ i += marker ? marker[0].length : 1;
922
+ }
923
+ stack.push(newFrame());
924
+ } else if (c === ')') {
925
+ i++;
926
+ if (stack.length === 1) continue;
927
+ const group = stack.pop();
928
+ atom(group.size, group.maxProduct);
929
+ } else if (c === '|') {
930
+ i++;
931
+ top().last = 0;
932
+ top().lastProduct = 1;
933
+ } else if (c === '{') {
934
+ const repeat = /^\{(\d+)(,(\d*))?\}\??/.exec(pattern.slice(i));
935
+ if (!repeat) {
936
+ i++;
937
+ atoms++;
938
+ atom(1, 1);
939
+ continue;
940
+ }
941
+ i += repeat[0].length;
942
+ const min = Number(repeat[1]);
943
+ const max = repeat[2] === undefined ? min : repeat[3] ? Number(repeat[3]) : min + 1;
944
+ if (min > MAX_REGEX_REPEAT || max > MAX_REGEX_REPEAT) return true;
945
+ const frame = top();
946
+ const product = frame.lastProduct * Math.max(max, 1);
947
+ if (product > MAX_REGEX_REPEAT) return true;
948
+ const extra = frame.last * (Math.max(max, 1) - 1);
949
+ frame.size += extra;
950
+ frame.last += extra;
951
+ frame.lastProduct = product;
952
+ frame.maxProduct = Math.max(frame.maxProduct, product);
953
+ } else {
954
+ i++;
955
+ if (c !== '*' && c !== '+' && c !== '?') {
956
+ atoms++;
957
+ atom(1, 1);
958
+ }
959
+ }
960
+ }
961
+ while(stack.length > 1){
962
+ const group = stack.pop();
963
+ atom(group.size, group.maxProduct);
964
+ }
965
+ return stack[0].size - atoms > MAX_REGEX_REPEAT_EXPANSION;
966
+ }
967
+ function closing(pattern, from, char) {
968
+ const end = pattern.indexOf(char, from);
969
+ return end < 0 ? pattern.length : end + 1;
970
+ }
971
+ function classEnd(pattern, start) {
972
+ let j = start + 1;
973
+ if (pattern[j] === '^') j++;
974
+ if (pattern[j] === ']') j++;
975
+ while(j < pattern.length && pattern[j] !== ']'){
976
+ if (pattern[j] === '\\') j += 2;
977
+ else if (pattern.startsWith('[:', j)) j = closing(pattern, j + 2, ']');
978
+ else j++;
979
+ }
980
+ return j + 1;
981
+ }
982
+ /** RE2 (linear-time) search: true when the pattern matches anywhere in the input. */ function matchesPattern(input, pattern) {
983
+ const prepared = prepare(input, pattern);
984
+ return prepared ? prepared.regex.matcher(prepared.text).find() : false;
985
+ }
986
+ /**
987
+ * The first match's capture `group` (default: the first group when the pattern has one, else the
988
+ * whole match); null when nothing matches or the group does not exist.
989
+ */ function extractPattern(input, pattern, group) {
990
+ const prepared = prepare(input, pattern);
991
+ if (!prepared) return null;
992
+ const index = group === undefined || group === null || group === '' ? prepared.regex.groupCount() > 0 ? 1 : 0 : Number(group);
993
+ if (!Number.isInteger(index) || index < 0 || index > prepared.regex.groupCount()) return null;
994
+ const matcher = prepared.regex.matcher(prepared.text);
995
+ return matcher.find() ? matcher.group(index) ?? null : null;
996
+ }
997
+ function prepare(input, pattern) {
998
+ if (typeof pattern !== 'string') {
999
+ throw new common_.BadRequestException({
1000
+ message: 'A regular expression pattern must be text.',
1001
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.REGEX_INVALID */.x3.REGEX_INVALID,
1002
+ messageVariables: {
1003
+ pattern: JSON.stringify(pattern ?? null)
1004
+ }
1005
+ });
1006
+ }
1007
+ const problem = rulePatternProblem(pattern);
1008
+ if (problem) throw patternError(problem, pattern);
1009
+ const text = typeof input === 'string' ? input : typeof input === 'number' || typeof input === 'boolean' ? String(input) : null;
1010
+ if (text === null) return null;
1011
+ if (text.length > rule_interface/* .RULE_ENGINE_LIMITS.MAX_REGEX_INPUT_LENGTH */.bw.MAX_REGEX_INPUT_LENGTH) {
1012
+ throw new common_.BadRequestException({
1013
+ message: `Text matched against a regular expression can be at most ${rule_interface/* .RULE_ENGINE_LIMITS.MAX_REGEX_INPUT_LENGTH */.bw.MAX_REGEX_INPUT_LENGTH} characters.`,
1014
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.REGEX_INPUT_TOO_LONG */.x3.REGEX_INPUT_TOO_LONG,
1015
+ messageVariables: {
1016
+ max: rule_interface/* .RULE_ENGINE_LIMITS.MAX_REGEX_INPUT_LENGTH */.bw.MAX_REGEX_INPUT_LENGTH
1017
+ }
1018
+ });
1019
+ }
1020
+ return {
1021
+ regex: compile(pattern),
1022
+ text
1023
+ };
1024
+ }
1025
+ function patternError(problem, pattern) {
1026
+ switch(problem){
1027
+ case 'too_long':
1028
+ return new common_.BadRequestException({
1029
+ message: `A regular expression pattern can be at most ${rule_interface/* .RULE_ENGINE_LIMITS.MAX_REGEX_PATTERN_LENGTH */.bw.MAX_REGEX_PATTERN_LENGTH} characters.`,
1030
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.REGEX_PATTERN_TOO_LONG */.x3.REGEX_PATTERN_TOO_LONG,
1031
+ messageVariables: {
1032
+ max: rule_interface/* .RULE_ENGINE_LIMITS.MAX_REGEX_PATTERN_LENGTH */.bw.MAX_REGEX_PATTERN_LENGTH
1033
+ }
1034
+ });
1035
+ case 'too_complex':
1036
+ return new common_.BadRequestException({
1037
+ message: `A regular expression can repeat a part at most ${rule_interface/* .RULE_ENGINE_LIMITS.MAX_REGEX_REPEAT */.bw.MAX_REGEX_REPEAT} times, nested repeats included.`,
1038
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.REGEX_TOO_COMPLEX */.x3.REGEX_TOO_COMPLEX,
1039
+ messageVariables: {
1040
+ max: rule_interface/* .RULE_ENGINE_LIMITS.MAX_REGEX_REPEAT */.bw.MAX_REGEX_REPEAT
1041
+ }
1042
+ });
1043
+ case 'invalid':
1044
+ return new common_.BadRequestException({
1045
+ message: `'${pattern}' is not a valid regular expression.`,
1046
+ messageKey: message_keys/* .RULE_ENGINE_MESSAGES.REGEX_INVALID */.x3.REGEX_INVALID,
1047
+ messageVariables: {
1048
+ pattern
1049
+ }
1050
+ });
1051
+ }
1052
+ }
1053
+ function compile(pattern) {
1054
+ return remember(compiled, pattern, (p)=>__rspack_external_re2js.RE2JS.compile(p));
1055
+ }
1056
+
1057
+
1058
+ },
1059
+ 6622(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1060
+ const ISO_DATE_PREFIX = /^\s*\d{4}-\d{2}-\d{2}/;
1061
+ const ISO_DATE_TIME = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:[.,](\d{1,9}))?)?)?\s*(Z|[+-]\d{2}(?::?\d{2})?)?$/i;
1062
+ const EXPLICIT_ZONE = /(?:\bZ|\bGMT|\bUTC|[+-]\d{2}:?\d{2})$/i;
1063
+ /**
1064
+ * Epoch ms of date text, NaN when it is not a date. ISO 8601 text without a zone ("2026-04-03",
1065
+ * "2026-04-03T09:00", "2026-04-03 09:00:00") is read as UTC, never as the server's local time;
1066
+ * other formats are only accepted with an explicit zone (Z, GMT, UTC or +hh:mm).
1067
+ */ function parseDateText(text) {
1068
+ const value = text.trim();
1069
+ const match = ISO_DATE_TIME.exec(value);
1070
+ if (!match) return EXPLICIT_ZONE.test(value) ? Date.parse(value) : Number.NaN;
1071
+ const [, year, month, day, hour = '0', minute = '0', second = '0', fraction = '', zone] = match;
1072
+ const parts = [
1073
+ year,
1074
+ month,
1075
+ day,
1076
+ hour,
1077
+ minute,
1078
+ second
1079
+ ].map(Number);
1080
+ const [y, mo, d, h, mi, s] = parts;
1081
+ const date = new Date(Date.UTC(2000, mo - 1, d, h, mi, s, Number(`${fraction}000`.slice(0, 3))));
1082
+ date.setUTCFullYear(y);
1083
+ if (date.getUTCFullYear() !== y || date.getUTCMonth() !== mo - 1 || date.getUTCDate() !== d || date.getUTCHours() !== h || date.getUTCMinutes() !== mi || date.getUTCSeconds() !== s) {
1084
+ return Number.NaN;
1085
+ }
1086
+ return date.getTime() - zoneOffsetMinutes(zone) * 60_000;
1087
+ }
1088
+ function zoneOffsetMinutes(zone) {
1089
+ if (!zone || zone.toUpperCase() === 'Z') return 0;
1090
+ const sign = zone.startsWith('-') ? -1 : 1;
1091
+ const digits = zone.slice(1).replace(':', '');
1092
+ return sign * (Number(digits.slice(0, 2)) * 60 + Number(digits.slice(2) || 0));
1093
+ }
1094
+ function instant(value) {
1095
+ const time = value instanceof Date ? value.getTime() : typeof value === 'string' && ISO_DATE_PREFIX.test(value) ? parseDateText(value) : Number.NaN;
1096
+ return Number.isFinite(time) ? time : null;
1097
+ }
1098
+ /** Rule equality: null and missing are the same, and a Date equals date text for the same instant. */ function valuesEqual(a, b) {
1099
+ const aMissing = a === null || a === undefined;
1100
+ const bMissing = b === null || b === undefined;
1101
+ if (aMissing || bMissing) return aMissing && bMissing;
1102
+ if (a instanceof Date || b instanceof Date) {
1103
+ const timeA = instant(a);
1104
+ return timeA !== null && timeA === instant(b);
1105
+ }
1106
+ return a === b;
1107
+ }
1108
+ const includesValue = (list, value)=>list.some((item)=>valuesEqual(item, value));
1109
+ /**
1110
+ * A resolved filter value is only ever an operand: an object or a list (e.g. `{ "op": "not_null" }`
1111
+ * sent as input) is wrapped as the operand of `eq`, which the entity service refuses as not a single
1112
+ * value, so it never becomes an operator. Only authored `{ op, value }` entries are operators.
1113
+ */ const equalsOperand = (value)=>value !== null && typeof value === 'object' ? {
1114
+ op: 'eq',
1115
+ value
1116
+ } : value;
1117
+
1118
+ __webpack_require__.d(__webpack_exports__, {
1119
+ hz: () => (parseDateText),
1120
+ lu: () => (valuesEqual)
1121
+ }, {
1122
+ $b: equalsOperand,
1123
+ XL: includesValue,
1124
+ YN: ISO_DATE_PREFIX
1125
+ });
1126
+
1127
+
1128
+ },
1129
+ 2354(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1130
+ /** Declarative JSON rule/expression grammar - evaluated by a closed switch, never as code. */ const RULE_COMPARISON_OPERATORS = [
1131
+ 'equals',
1132
+ 'not_equals',
1133
+ 'greater_than',
1134
+ 'less_than',
1135
+ 'greater_or_equal',
1136
+ 'less_or_equal',
1137
+ 'contains',
1138
+ 'not_contains',
1139
+ 'starts_with',
1140
+ 'ends_with',
1141
+ 'is_empty',
1142
+ 'is_not_empty',
1143
+ 'in',
1144
+ 'not_in',
1145
+ 'is_any_of',
1146
+ 'is_none_of',
1147
+ 'is_true',
1148
+ 'is_false',
1149
+ 'matches',
1150
+ 'not_matches'
1151
+ ];
1152
+ function isRuleGroup(node) {
1153
+ return 'operator' in node && 'conditions' in node;
1154
+ }
1155
+ const RULE_PERMISSION_FUNCTIONS = [
1156
+ 'HAS_PERMISSION',
1157
+ 'HAS_ANY_PERMISSION',
1158
+ 'HAS_ALL_PERMISSIONS'
1159
+ ];
1160
+ /** Functions that read the incoming HTTP request - only flows have one; elsewhere they return null. */ const RULE_REQUEST_FUNCTIONS = [
1161
+ 'HEADER',
1162
+ 'QUERY_PARAM',
1163
+ 'IP_IN_RANGE'
1164
+ ];
1165
+ function isPermissionFunction(name) {
1166
+ return RULE_PERMISSION_FUNCTIONS.includes(name);
1167
+ }
1168
+ const RULE_DURATION_UNITS = [
1169
+ 'second',
1170
+ 'minute',
1171
+ 'hour',
1172
+ 'day'
1173
+ ];
1174
+ /** Save-time guardrails - enforced both when a flow is saved and defensively again at evaluation time. */ const RULE_TEMPLATE_MAX_LENGTH = 4000;
1175
+ const RULE_ENGINE_LIMITS = {
1176
+ MAX_GROUP_DEPTH: 8,
1177
+ MAX_CONDITIONS_PER_GROUP: 100,
1178
+ MAX_LOOKUPS: 10,
1179
+ MAX_REGEX_PATTERN_LENGTH: 500,
1180
+ MAX_REGEX_INPUT_LENGTH: 10_000,
1181
+ /** Largest `{n,m}` count, also for the product of nested counts. */ MAX_REGEX_REPEAT: 100,
1182
+ /** How much larger counted repeats may make the unrolled pattern than the pattern itself. */ MAX_REGEX_REPEAT_EXPANSION: 300,
1183
+ /** Largest `offsetMinutes` accepted by START_OF_DAY / END_OF_DAY (UTC+14 / UTC-12). */ MAX_UTC_OFFSET_MINUTES: 840,
1184
+ MAX_PERMISSION_CODES: 50,
1185
+ MAX_IP_RANGES: 100
1186
+ };
1187
+
1188
+ __webpack_require__.d(__webpack_exports__, {
1189
+ A8: () => (isPermissionFunction),
1190
+ GD: () => (isRuleGroup)
1191
+ }, {
1192
+ PK: RULE_REQUEST_FUNCTIONS,
1193
+ bw: RULE_ENGINE_LIMITS,
1194
+ dJ: RULE_COMPARISON_OPERATORS,
1195
+ l2: RULE_PERMISSION_FUNCTIONS,
1196
+ qO: RULE_DURATION_UNITS
1197
+ });
1198
+
1199
+
1200
+ },
1201
+ 2417(module) {
1202
+
1203
+ module.exports = __rspack_external__flusys_nestjs_shared_exceptions_3edf22e9;
1204
+
1205
+
1206
+ },
1207
+ 1236(module) {
1208
+
1209
+ module.exports = __rspack_external__flusys_nestjs_shared_modules_24702bee;
1210
+
1211
+
1212
+ },
1213
+ 9216(module) {
1214
+
1215
+ module.exports = __rspack_external__flusys_nestjs_shared_utils_9125c1f1;
1216
+
1217
+
1218
+ },
1219
+ 6157(module) {
1220
+
1221
+ module.exports = __rspack_external__nestjs_common_a04939da;
1222
+
1223
+
1224
+ },
1225
+ 2561(module) {
1226
+
1227
+ module.exports = __rspack_external_node_crypto_2e7c4b46;
1228
+
1229
+
1230
+ },
1231
+ 8299(module) {
1232
+
1233
+ module.exports = __rspack_external_node_net_5ed819e1;
1234
+
1235
+
1236
+ },
1237
+
1238
+ };