@cullet/erp-core 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/KIT_CONTEXT.md +2 -2
  2. package/dist/abac/index.d.cts +2 -2
  3. package/dist/abac/index.d.ts +2 -2
  4. package/dist/aggregate-version.cjs +14 -0
  5. package/dist/aggregate-version.cjs.map +1 -0
  6. package/dist/aggregate-version.js +9 -0
  7. package/dist/aggregate-version.js.map +1 -0
  8. package/dist/app-error.cjs +8 -1
  9. package/dist/app-error.cjs.map +1 -1
  10. package/dist/app-error.js +8 -1
  11. package/dist/app-error.js.map +1 -1
  12. package/dist/application/index.cjs +8 -4
  13. package/dist/application/index.d.cts +2 -2
  14. package/dist/application/index.d.ts +2 -2
  15. package/dist/application/index.js +1 -2
  16. package/dist/authorization-error.cjs +67 -17
  17. package/dist/authorization-error.cjs.map +1 -1
  18. package/dist/authorization-error.d.cts +6 -2
  19. package/dist/authorization-error.d.ts +6 -2
  20. package/dist/authorization-error.js +50 -18
  21. package/dist/authorization-error.js.map +1 -1
  22. package/dist/authorizer.port.d.cts +18 -3
  23. package/dist/authorizer.port.d.ts +18 -3
  24. package/dist/composite-authorizer.d.cts +63 -10
  25. package/dist/composite-authorizer.d.ts +63 -10
  26. package/dist/condition-evaluator.cjs +115 -184
  27. package/dist/condition-evaluator.cjs.map +1 -1
  28. package/dist/condition-evaluator.js +116 -179
  29. package/dist/condition-evaluator.js.map +1 -1
  30. package/dist/core-config.d.cts +53 -6
  31. package/dist/core-config.d.ts +53 -6
  32. package/dist/decorate.cjs +14 -0
  33. package/dist/decorate.js +9 -0
  34. package/dist/domain/index.cjs +107 -2
  35. package/dist/domain/index.cjs.map +1 -0
  36. package/dist/domain/index.d.cts +25 -1
  37. package/dist/domain/index.d.ts +25 -1
  38. package/dist/domain/index.js +99 -3
  39. package/dist/domain/index.js.map +1 -0
  40. package/dist/domain-event-contracts.cjs +12 -8
  41. package/dist/domain-event-contracts.cjs.map +1 -1
  42. package/dist/domain-event-contracts.d.cts +29 -4
  43. package/dist/domain-event-contracts.d.ts +29 -4
  44. package/dist/domain-event-contracts.js +11 -7
  45. package/dist/domain-event-contracts.js.map +1 -1
  46. package/dist/domain-exception.cjs +2 -1
  47. package/dist/domain-exception.cjs.map +1 -1
  48. package/dist/domain-exception.js +2 -1
  49. package/dist/domain-exception.js.map +1 -1
  50. package/dist/errors/index.cjs +1 -1
  51. package/dist/errors/index.d.cts +1 -1
  52. package/dist/errors/index.d.ts +1 -1
  53. package/dist/errors/index.js +2 -2
  54. package/dist/exceptions/index.cjs +2 -2
  55. package/dist/exceptions/index.d.cts +1 -2
  56. package/dist/exceptions/index.d.ts +1 -2
  57. package/dist/exceptions/index.js +2 -2
  58. package/dist/gate-engine-registry.cjs.map +1 -1
  59. package/dist/gate-engine-registry.d.cts +1 -1
  60. package/dist/gate-engine-registry.d.ts +1 -1
  61. package/dist/gate-engine-registry.js.map +1 -1
  62. package/dist/gate-v1-payload.schema.cjs +11 -6
  63. package/dist/gate-v1-payload.schema.cjs.map +1 -1
  64. package/dist/gate-v1-payload.schema.js +11 -6
  65. package/dist/gate-v1-payload.schema.js.map +1 -1
  66. package/dist/hashing.cjs +1 -1
  67. package/dist/hashing.cjs.map +1 -1
  68. package/dist/hashing.js +2 -2
  69. package/dist/hashing.js.map +1 -1
  70. package/dist/immutable.cjs +25 -12
  71. package/dist/immutable.cjs.map +1 -1
  72. package/dist/immutable.js +24 -11
  73. package/dist/immutable.js.map +1 -1
  74. package/dist/index.cjs +13 -10
  75. package/dist/index.cjs.map +1 -1
  76. package/dist/index.d.cts +9 -10
  77. package/dist/index.d.ts +9 -10
  78. package/dist/index.js +7 -9
  79. package/dist/index.js.map +1 -1
  80. package/dist/invalid-state-transition-exception.cjs +6 -6
  81. package/dist/invalid-state-transition-exception.cjs.map +1 -1
  82. package/dist/invalid-state-transition-exception.js +6 -6
  83. package/dist/invalid-state-transition-exception.js.map +1 -1
  84. package/dist/invariant-violation-exception.cjs +2 -2
  85. package/dist/invariant-violation-exception.cjs.map +1 -1
  86. package/dist/invariant-violation-exception.js +2 -2
  87. package/dist/invariant-violation-exception.js.map +1 -1
  88. package/dist/not-found-error.cjs +6 -4
  89. package/dist/not-found-error.cjs.map +1 -1
  90. package/dist/not-found-error.js +6 -4
  91. package/dist/not-found-error.js.map +1 -1
  92. package/dist/outcome.cjs +5 -5
  93. package/dist/outcome.cjs.map +1 -1
  94. package/dist/outcome.js +5 -5
  95. package/dist/outcome.js.map +1 -1
  96. package/dist/parse-gate-payload.d.cts +1 -1
  97. package/dist/parse-gate-payload.d.ts +1 -1
  98. package/dist/path.d.cts +2 -2
  99. package/dist/path.d.ts +2 -2
  100. package/dist/plugin.cjs +23 -13
  101. package/dist/plugin.cjs.map +1 -1
  102. package/dist/plugin.d.cts +22 -8
  103. package/dist/plugin.d.ts +22 -8
  104. package/dist/plugin.js +23 -13
  105. package/dist/plugin.js.map +1 -1
  106. package/dist/policies/engines/index.d.cts +1 -1
  107. package/dist/policies/engines/index.d.ts +1 -1
  108. package/dist/policies/engines/v1/gate/index.d.cts +3 -15
  109. package/dist/policies/engines/v1/gate/index.d.ts +3 -15
  110. package/dist/policies/index.d.cts +1 -1
  111. package/dist/policies/index.d.ts +1 -1
  112. package/dist/policy-bridge.cjs +30 -2
  113. package/dist/policy-bridge.cjs.map +1 -1
  114. package/dist/policy-bridge.d.cts +18 -0
  115. package/dist/policy-bridge.d.ts +18 -0
  116. package/dist/policy-bridge.js +30 -2
  117. package/dist/policy-bridge.js.map +1 -1
  118. package/dist/policy-service.cjs +40 -46
  119. package/dist/policy-service.cjs.map +1 -1
  120. package/dist/policy-service.d.cts +72 -9
  121. package/dist/policy-service.d.ts +72 -9
  122. package/dist/policy-service.js +42 -48
  123. package/dist/policy-service.js.map +1 -1
  124. package/dist/requested-by.cjs +1 -1
  125. package/dist/requested-by.cjs.map +1 -1
  126. package/dist/requested-by.js +1 -1
  127. package/dist/requested-by.js.map +1 -1
  128. package/dist/result.cjs +29 -1
  129. package/dist/result.cjs.map +1 -1
  130. package/dist/result.d.cts +12 -0
  131. package/dist/result.d.ts +12 -0
  132. package/dist/result.js +29 -1
  133. package/dist/result.js.map +1 -1
  134. package/dist/rule.cjs +94 -24
  135. package/dist/rule.cjs.map +1 -1
  136. package/dist/rule.js +94 -24
  137. package/dist/rule.js.map +1 -1
  138. package/dist/ruleset-registry.cjs +19 -0
  139. package/dist/ruleset-registry.cjs.map +1 -1
  140. package/dist/ruleset-registry.js +19 -0
  141. package/dist/ruleset-registry.js.map +1 -1
  142. package/dist/stable-stringify.cjs +43 -3
  143. package/dist/stable-stringify.cjs.map +1 -1
  144. package/dist/stable-stringify.js +38 -4
  145. package/dist/stable-stringify.js.map +1 -1
  146. package/dist/temporal-snapshot.d.cts +87 -0
  147. package/dist/temporal-snapshot.d.ts +87 -0
  148. package/dist/temporal-use-case.cjs +169 -16
  149. package/dist/temporal-use-case.cjs.map +1 -1
  150. package/dist/temporal-use-case.d.cts +76 -43
  151. package/dist/temporal-use-case.d.ts +76 -43
  152. package/dist/temporal-use-case.js +162 -15
  153. package/dist/temporal-use-case.js.map +1 -1
  154. package/dist/unexpected-error.cjs +4 -2
  155. package/dist/unexpected-error.cjs.map +1 -1
  156. package/dist/unexpected-error.js +4 -2
  157. package/dist/unexpected-error.js.map +1 -1
  158. package/dist/uuid-identifier.cjs +140 -2
  159. package/dist/uuid-identifier.cjs.map +1 -1
  160. package/dist/uuid-identifier.d.cts +26 -7
  161. package/dist/uuid-identifier.d.ts +26 -7
  162. package/dist/uuid-identifier.js +135 -3
  163. package/dist/uuid-identifier.js.map +1 -1
  164. package/dist/uuid.cjs +11 -6
  165. package/dist/uuid.cjs.map +1 -1
  166. package/dist/uuid.js +11 -6
  167. package/dist/uuid.js.map +1 -1
  168. package/dist/validation-code.cjs +9 -0
  169. package/dist/validation-code.cjs.map +1 -1
  170. package/dist/validation-code.d.cts +3 -0
  171. package/dist/validation-code.d.ts +3 -0
  172. package/dist/validation-code.js +9 -0
  173. package/dist/validation-code.js.map +1 -1
  174. package/dist/validation-error.cjs +42 -67
  175. package/dist/validation-error.cjs.map +1 -1
  176. package/dist/validation-error.d.cts +24 -8
  177. package/dist/validation-error.d.ts +24 -8
  178. package/dist/validation-error.js +41 -66
  179. package/dist/validation-error.js.map +1 -1
  180. package/dist/validation-exception.cjs +17 -6
  181. package/dist/validation-exception.cjs.map +1 -1
  182. package/dist/validation-exception.d.cts +33 -9
  183. package/dist/validation-exception.d.ts +33 -9
  184. package/dist/validation-exception.js +17 -6
  185. package/dist/validation-exception.js.map +1 -1
  186. package/dist/validation-field.cjs +3 -0
  187. package/dist/validation-field.cjs.map +1 -1
  188. package/dist/validation-field.d.cts +1 -0
  189. package/dist/validation-field.d.ts +1 -0
  190. package/dist/validation-field.js +3 -0
  191. package/dist/validation-field.js.map +1 -1
  192. package/dist/value-object-ruleset.contracts.d.cts +10 -0
  193. package/dist/value-object-ruleset.contracts.d.ts +10 -0
  194. package/dist/value-object.cjs +12 -2
  195. package/dist/value-object.cjs.map +1 -1
  196. package/dist/value-object.d.cts +16 -0
  197. package/dist/value-object.d.ts +16 -0
  198. package/dist/value-object.js +13 -3
  199. package/dist/value-object.js.map +1 -1
  200. package/dist/version.d.cts +27 -0
  201. package/dist/version.d.ts +27 -0
  202. package/dist/versioning/index.d.cts +2 -2
  203. package/dist/versioning/index.d.ts +2 -2
  204. package/meta.json +3 -2
  205. package/package.json +1 -1
  206. package/src/core/abac/authorizer.ts +60 -10
  207. package/src/core/abac/domain/policy-set.ts +52 -5
  208. package/src/core/abac/domain/rule.ts +28 -16
  209. package/src/core/abac/index.ts +7 -1
  210. package/src/core/application/commands/command.ts +14 -1
  211. package/src/core/application/commands/requested-by.ts +12 -3
  212. package/src/core/application/index.ts +2 -1
  213. package/src/core/application/policy-error-mapper.ts +6 -0
  214. package/src/core/application/ports/index.ts +7 -0
  215. package/src/core/application/ports/temporal-repository.port.ts +35 -2
  216. package/src/core/application/queries/index.ts +1 -1
  217. package/src/core/application/queries/query.ts +19 -2
  218. package/src/core/application/temporal/temporal-use-case.ts +31 -4
  219. package/src/core/application/use-case.ts +44 -7
  220. package/src/core/config/core-config.ts +46 -25
  221. package/src/core/config/index.ts +1 -0
  222. package/src/core/config/policy-reporter.ts +32 -1
  223. package/src/core/domain/entity.ts +50 -7
  224. package/src/core/domain/rulesets/entity-ruleset.contracts.ts +0 -2
  225. package/src/core/domain/rulesets/ruleset-registry.ts +24 -0
  226. package/src/core/domain/rulesets/value-object-ruleset.contracts.ts +1 -7
  227. package/src/core/domain/temporal/half-open-interval.ts +34 -0
  228. package/src/core/domain/temporal/temporal-snapshot.ts +13 -2
  229. package/src/core/domain/temporal/transaction-time.ts +19 -15
  230. package/src/core/domain/temporal/valid-time.ts +20 -15
  231. package/src/core/domain/uuid-identifier.ts +5 -3
  232. package/src/core/domain/value-object.ts +17 -0
  233. package/src/core/errors/authentication-error.ts +5 -31
  234. package/src/core/errors/authorization-error.ts +12 -20
  235. package/src/core/errors/business-rule-violation-error.ts +4 -1
  236. package/src/core/errors/idempotency-error.ts +5 -2
  237. package/src/core/errors/index.ts +4 -0
  238. package/src/core/errors/integration-error.ts +4 -24
  239. package/src/core/errors/legacy-incompatible-error.ts +1 -0
  240. package/src/core/errors/not-found-error.ts +4 -1
  241. package/src/core/errors/temporal-error.ts +22 -20
  242. package/src/core/errors/unexpected-error.ts +5 -1
  243. package/src/core/errors/utils/factory-helpers.ts +70 -0
  244. package/src/core/errors/utils/index.ts +5 -0
  245. package/src/core/errors/utils/json-safe.ts +15 -1
  246. package/src/core/errors/validation-error.ts +4 -1
  247. package/src/core/exceptions/business-rule-violation-exception.ts +2 -1
  248. package/src/core/exceptions/domain-exception.ts +9 -1
  249. package/src/core/exceptions/entity-not-found-exception.ts +5 -1
  250. package/src/core/exceptions/invalid-state-transition-exception.ts +5 -2
  251. package/src/core/exceptions/invariant-violation-exception.ts +2 -2
  252. package/src/core/exceptions/validation-code.ts +14 -0
  253. package/src/core/exceptions/validation-exception.ts +44 -5
  254. package/src/core/exceptions/validation-field.ts +11 -1
  255. package/src/core/plugins/plugin.ts +25 -15
  256. package/src/core/plugins/types.ts +4 -2
  257. package/src/core/policies/asof/asof.ts +12 -0
  258. package/src/core/policies/catalog/policy-catalog-entry.ts +3 -1
  259. package/src/core/policies/catalog/policy-catalog.ts +5 -1
  260. package/src/core/policies/context/context-builder.ts +20 -0
  261. package/src/core/policies/context/context-resolver.ts +5 -0
  262. package/src/core/policies/context/context-seed.ts +11 -0
  263. package/src/core/policies/defs/in-memory-policy-definition-repo.ts +0 -2
  264. package/src/core/policies/engines/parse-gate-payload.ts +9 -0
  265. package/src/core/policies/engines/v1/condition-date-operands.ts +112 -0
  266. package/src/core/policies/engines/v1/condition-evaluator.ts +99 -325
  267. package/src/core/policies/engines/v1/condition-schema.ts +23 -19
  268. package/src/core/policies/engines/v1/condition-types.ts +18 -11
  269. package/src/core/policies/index.ts +4 -6
  270. package/src/core/policies/service/policy-service.ts +46 -35
  271. package/src/core/policies/utils/hash.ts +5 -69
  272. package/src/core/policies/utils/result.ts +1 -1
  273. package/src/core/rbac/access-request.ts +12 -2
  274. package/src/core/rbac/authorizer.ts +8 -1
  275. package/src/core/rbac/domain/role.ts +20 -0
  276. package/src/core/rbac/domain/scope.ts +6 -1
  277. package/src/core/result/index.ts +5 -0
  278. package/src/core/result/outcome.ts +5 -7
  279. package/src/core/result/result.ts +34 -1
  280. package/src/core/shared/hashing.ts +6 -3
  281. package/src/core/shared/immutable.ts +22 -4
  282. package/src/core/shared/stable-stringify.ts +91 -4
  283. package/src/core/shared/uuid.ts +11 -6
  284. package/src/core/versioning/domain-event-contracts.ts +43 -15
  285. package/src/core/versioning/index.ts +1 -0
  286. package/src/core/versioning/version.ts +30 -1
  287. package/src/domain/index.ts +5 -0
  288. package/src/examples/rulesets/entity/order-creation-rules-v1.ts +1 -1
  289. package/src/examples/rulesets/entity/order-invariants-v1.ts +2 -4
  290. package/src/examples/rulesets/entity/order-invariants-v2.ts +2 -4
  291. package/src/examples/rulesets/value-object/cpf-rules-v1.ts +2 -4
  292. package/src/examples/rulesets/value-object/cpf-rules-v2.ts +2 -4
  293. package/src/examples/rulesets/value-object/person-name-rules-v1.ts +2 -4
  294. package/src/examples/rulesets/value-object/person-name-rules-v2.ts +2 -4
  295. package/src/result/index.ts +7 -2
  296. package/src/version.ts +1 -1
  297. package/dist/domain-exception.d.cts +0 -7
  298. package/dist/domain-exception.d.ts +0 -7
  299. package/dist/entity.cjs +0 -122
  300. package/dist/entity.cjs.map +0 -1
  301. package/dist/entity.js +0 -111
  302. package/dist/entity.js.map +0 -1
  303. package/dist/use-case.cjs +0 -92
  304. package/dist/use-case.cjs.map +0 -1
  305. package/dist/use-case.js +0 -87
  306. package/dist/use-case.js.map +0 -1
@@ -6,14 +6,23 @@ var SilentPolicyReporter = class {
6
6
  };
7
7
  //#endregion
8
8
  //#region src/core/config/core-config.ts
9
- function reportSafely(policyReporter, event) {
9
+ /** Reports an event without letting a throwing reporter abort the caller. */
10
+ function safeReport(policyReporter, event) {
10
11
  try {
11
12
  policyReporter.report(event);
12
13
  } catch {}
13
14
  }
14
15
  /**
15
- * Centraliza a configuracao pura do core sem depender de implementacoes
16
- * concretas de logging, tracing ou report.
16
+ * The core's config namespace. Today it holds a single section —
17
+ * `observability` whose whole job is to decide *where policy telemetry goes*
18
+ * while guaranteeing telemetry is best-effort (a throwing reporter can never
19
+ * abort a domain flow). App config (env, settings, feature flags) is
20
+ * deliberately absent for now: when the core needs it, it joins here as a
21
+ * sibling section rather than a new module — which is why this is `config`,
22
+ * not `observability`. It holds the active {@link PolicyReporter} (silent by
23
+ * default, so the core carries no logging dependency), bridges it to the
24
+ * engines' {@link ConditionEvaluatorReporter}, and offers `reportSafely` as
25
+ * the single guarded emit path shared with {@link PolicyService}.
17
26
  */
18
27
  var CoreConfig = class {
19
28
  #initialReporter;
@@ -23,17 +32,23 @@ var CoreConfig = class {
23
32
  this.#initialReporter = reporter;
24
33
  this.#currentReporter = reporter;
25
34
  }
35
+ /**
36
+ * Swaps the active reporter. Pass `observability.reporter` to enable
37
+ * telemetry, or set it explicitly to `undefined` to go silent again.
38
+ * Omitting `observability` (or its `reporter` key) is a no-op.
39
+ */
26
40
  configure(options) {
27
- const reporter = options.observability?.reporter;
28
- if (reporter) this.#currentReporter = reporter;
41
+ const observability = options.observability;
42
+ if (observability && "reporter" in observability) this.#currentReporter = observability.reporter ?? new SilentPolicyReporter();
29
43
  return this;
30
44
  }
31
45
  reset() {
32
46
  this.#currentReporter = this.#initialReporter;
33
47
  return this;
34
48
  }
35
- getPolicyReporter() {
36
- return this.#currentReporter;
49
+ /** Emits a policy event through the active reporter, best-effort. */
50
+ reportSafely(event) {
51
+ safeReport(this.#currentReporter, event);
37
52
  }
38
53
  getConditionEvaluationOptions(engineVersion) {
39
54
  return {
@@ -42,19 +57,16 @@ var CoreConfig = class {
42
57
  };
43
58
  }
44
59
  #bridgeToConditionReporter(policyReporter) {
60
+ const emit = (level, report) => {
61
+ safeReport(policyReporter, {
62
+ kind: "condition-eval",
63
+ ...report,
64
+ level
65
+ });
66
+ };
45
67
  return {
46
- warn(report) {
47
- reportSafely(policyReporter, {
48
- kind: "condition-eval",
49
- ...report
50
- });
51
- },
52
- error(report) {
53
- reportSafely(policyReporter, {
54
- kind: "condition-eval",
55
- ...report
56
- });
57
- }
68
+ warn: (report) => emit("warn", report),
69
+ error: (report) => emit("error", report)
58
70
  };
59
71
  }
60
72
  };
@@ -159,6 +171,54 @@ var PolicyDateUtils = class {
159
171
  }
160
172
  };
161
173
  //#endregion
174
+ //#region src/core/policies/engines/v1/condition-date-operands.ts
175
+ /**
176
+ * The one instant format condition date operands may use. Strict on purpose
177
+ * (UTC, milliseconds) so comparisons are unambiguous across time zones — and
178
+ * so a malformed operand fails loudly instead of comparing wrong.
179
+ */
180
+ const CANONICAL_UTC_DATE_FORMAT = "YYYY-MM-DDTHH:mm:ss.SSSZ";
181
+ const ISO_8601_UTC_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
182
+ const ISO_8601_DATE_LIKE_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}/;
183
+ /**
184
+ * Parses a value used as a date operand:
185
+ * - `Result.ok(Date)` for a valid Date or a canonical ISO-8601 UTC string;
186
+ * - `Result.err` when it is date-shaped but malformed (invalid Date, or a
187
+ * date-like string that isn't canonical UTC) — a configuration error worth
188
+ * surfacing rather than silently treating as "not a date";
189
+ * - `null` when the value isn't date-shaped at all, so the caller can fall
190
+ * through to a numeric comparison.
191
+ */
192
+ function parseComparableDate(value) {
193
+ if (value instanceof Date) return PolicyDateUtils.isValid(value) ? Result.ok(value) : Result.err("Invalid Date instance");
194
+ if (typeof value !== "string") return null;
195
+ if (ISO_8601_UTC_DATE_PATTERN.test(value)) {
196
+ const parsed = new Date(value);
197
+ if (!PolicyDateUtils.isValid(parsed) || parsed.toISOString() !== value) return Result.err("Invalid ISO 8601 UTC date string");
198
+ return Result.ok(parsed);
199
+ }
200
+ if (ISO_8601_DATE_LIKE_PATTERN.test(value)) return Result.err(`date operand must be canonical ISO 8601 UTC (${CANONICAL_UTC_DATE_FORMAT})`);
201
+ return null;
202
+ }
203
+ function evaluateRelationalNumbers(actual, op, expected) {
204
+ switch (op) {
205
+ case "gt": return actual > expected;
206
+ case "gte": return actual >= expected;
207
+ case "lt": return actual < expected;
208
+ case "lte": return actual <= expected;
209
+ }
210
+ }
211
+ function containsInvalidDate(value) {
212
+ if (value instanceof Date) return !PolicyDateUtils.isValid(value);
213
+ if (Array.isArray(value)) return value.some((item) => containsInvalidDate(item));
214
+ return false;
215
+ }
216
+ function normalizeDateOperand(value) {
217
+ if (value instanceof Date) return value.toISOString();
218
+ if (Array.isArray(value)) return value.map((item) => normalizeDateOperand(item));
219
+ return value;
220
+ }
221
+ //#endregion
162
222
  //#region src/core/policies/engines/v1/condition-evaluator.ts
163
223
  const CONDITION_EVAL_THROWN_TAG = "CONDITION_EVAL_THREW";
164
224
  const NULLISH_NUMERIC_OPERAND_NOT_ALLOWED_TAG = "NULLISH_NUMERIC_OPERAND_NOT_ALLOWED";
@@ -168,7 +228,6 @@ const INVALID_NUMERIC_OPERAND_TAG = "INVALID_NUMERIC_OPERAND";
168
228
  const INVALID_SET_OPERAND_TAG = "INVALID_SET_OPERAND";
169
229
  const EMPTY_OR_CONDITION_TAG = "EMPTY_OR_CONDITION";
170
230
  const EMPTY_AND_CONDITION_TAG = "EMPTY_AND_CONDITION";
171
- const ISO_8601_UTC_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
172
231
  var ConditionEvaluatorV1 = class ConditionEvaluatorV1 {
173
232
  constructor(context, options) {
174
233
  this.context = context;
@@ -199,46 +258,8 @@ var ConditionEvaluatorV1 = class ConditionEvaluatorV1 {
199
258
  message: String(error)
200
259
  };
201
260
  }
202
- static buildNullishNumericOperandMessage(node, actual) {
203
- const resolvedValue = actual === null ? "null" : "undefined";
204
- return `${NULLISH_NUMERIC_OPERAND_NOT_ALLOWED_TAG}: "${node.field}" resolved to ${resolvedValue} for numeric operator "${node.op}"`;
205
- }
206
- static buildNullishDateOperandMessage(node, actual) {
207
- const resolvedValue = actual === null ? "null" : "undefined";
208
- return `${NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG}: "${node.field}" resolved to ${resolvedValue} for date comparison operator "${node.op}"`;
209
- }
210
- static buildInvalidDateOperandMessage(node) {
211
- return `${INVALID_DATE_OPERAND_TAG}: "${node.field}" with operator "${node.op}" requires Date or ISO 8601 UTC string operands`;
212
- }
213
- static buildInvalidNumericOperandMessage(node) {
214
- return `${INVALID_NUMERIC_OPERAND_TAG}: "${node.field}" with operator "${node.op}" requires numeric operands`;
215
- }
216
- static buildInvalidSetOperandMessage(node) {
217
- return `${INVALID_SET_OPERAND_TAG}: "${node.field}" with operator "${node.op}" requires an array operand`;
218
- }
219
- static buildEmptyOrConditionMessage() {
220
- return `${EMPTY_OR_CONDITION_TAG}: OR nodes must contain at least one child condition`;
221
- }
222
- static buildEmptyAndConditionMessage() {
223
- return `${EMPTY_AND_CONDITION_TAG}: AND nodes must contain at least one child condition`;
224
- }
225
- static parseComparableDate(value) {
226
- if (value instanceof Date) {
227
- if (!PolicyDateUtils.isValid(value)) return Result.err("Invalid Date instance");
228
- return Result.ok(value);
229
- }
230
- if (typeof value !== "string" || !ISO_8601_UTC_DATE_PATTERN.test(value)) return null;
231
- const parsed = new Date(value);
232
- if (!PolicyDateUtils.isValid(parsed) || parsed.toISOString() !== value) return Result.err("Invalid ISO 8601 UTC date string");
233
- return Result.ok(parsed);
234
- }
235
- static evaluateRelationalNumbers(actual, op, expected) {
236
- switch (op) {
237
- case "gt": return actual > expected;
238
- case "gte": return actual >= expected;
239
- case "lt": return actual < expected;
240
- case "lte": return actual <= expected;
241
- }
261
+ static invalidDateOperandMessage(node) {
262
+ return `${INVALID_DATE_OPERAND_TAG}: "${node.field}" with operator "${node.op}" requires Date or ISO 8601 UTC (${CANONICAL_UTC_DATE_FORMAT}) string operands`;
242
263
  }
243
264
  buildReport(params) {
244
265
  return {
@@ -250,172 +271,88 @@ var ConditionEvaluatorV1 = class ConditionEvaluatorV1 {
250
271
  details: params.details
251
272
  };
252
273
  }
253
- conditionEvalErr(node, error) {
254
- const cause = ConditionEvaluatorV1.describeError(error);
255
- const message = `${CONDITION_EVAL_THROWN_TAG}: ${cause.name}: ${cause.message}`;
274
+ reportLeafError(tag, message, node, actual, extra) {
256
275
  this.options.reporter.error(this.buildReport({
257
276
  level: "error",
258
- tag: CONDITION_EVAL_THROWN_TAG,
259
- message,
260
- details: {
261
- node,
262
- cause
263
- }
264
- }));
265
- return Result.err(message);
266
- }
267
- static containsInvalidDate(value) {
268
- if (value instanceof Date) return !PolicyDateUtils.isValid(value);
269
- if (Array.isArray(value)) return value.some((item) => ConditionEvaluatorV1.containsInvalidDate(item));
270
- return false;
271
- }
272
- static normalizeDateOperand(value) {
273
- if (value instanceof Date) return value.toISOString();
274
- if (Array.isArray(value)) return value.map((item) => ConditionEvaluatorV1.normalizeDateOperand(item));
275
- return value;
276
- }
277
- reportDateOperandError(node, actual) {
278
- const message = ConditionEvaluatorV1.buildInvalidDateOperandMessage(node);
279
- this.options.reporter.error(this.buildReport({
280
- level: "error",
281
- tag: INVALID_DATE_OPERAND_TAG,
277
+ tag,
282
278
  message,
283
279
  details: {
284
280
  field: node.field,
285
281
  op: node.op,
286
282
  actual,
287
283
  expected: node.value,
284
+ ...extra,
288
285
  node
289
286
  }
290
287
  }));
291
288
  return Result.err(message);
292
289
  }
293
- reportInvalidNumericOperand(node, actual) {
294
- const message = ConditionEvaluatorV1.buildInvalidNumericOperandMessage(node);
295
- this.options.reporter.error(this.buildReport({
296
- level: "error",
297
- tag: INVALID_NUMERIC_OPERAND_TAG,
298
- message,
299
- details: {
300
- field: node.field,
301
- op: node.op,
302
- actual,
303
- expected: node.value,
304
- node
305
- }
306
- }));
307
- return Result.err(message);
308
- }
309
- reportInvalidSetOperand(node, actual) {
310
- const message = ConditionEvaluatorV1.buildInvalidSetOperandMessage(node);
290
+ conditionEvalErr(node, error) {
291
+ const cause = ConditionEvaluatorV1.describeError(error);
292
+ const message = `${CONDITION_EVAL_THROWN_TAG}: ${cause.name}: ${cause.message}`;
311
293
  this.options.reporter.error(this.buildReport({
312
294
  level: "error",
313
- tag: INVALID_SET_OPERAND_TAG,
295
+ tag: CONDITION_EVAL_THROWN_TAG,
314
296
  message,
315
297
  details: {
316
- field: node.field,
317
- op: node.op,
318
- actual,
319
- expected: node.value,
320
- node
298
+ node,
299
+ cause
321
300
  }
322
301
  }));
323
302
  return Result.err(message);
324
303
  }
325
304
  evaluateDateRelationalNode(node, actual) {
326
305
  if (!ConditionEvaluatorV1.isRelationalOperator(node.op)) return null;
327
- const actualDateResult = ConditionEvaluatorV1.parseComparableDate(actual);
328
- const expectedDateResult = ConditionEvaluatorV1.parseComparableDate(node.value);
329
- if (actualDateResult === null && expectedDateResult === null) return null;
306
+ const actualDate = parseComparableDate(actual);
307
+ const expectedDate = parseComparableDate(node.value);
308
+ if (actualDate === null && expectedDate === null) return null;
330
309
  const allowsNull = node.allowNull === true;
331
- if (actual === null) {
332
- if (allowsNull) return Result.ok(false);
333
- const message = ConditionEvaluatorV1.buildNullishDateOperandMessage(node, actual);
334
- this.options.reporter.error(this.buildReport({
335
- level: "error",
336
- tag: NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG,
337
- message,
338
- details: {
339
- field: node.field,
340
- op: node.op,
341
- actual,
342
- expected: node.value,
343
- allowNull: allowsNull,
344
- node
345
- }
346
- }));
347
- return Result.err(message);
348
- }
349
- if (actual === void 0) {
350
- const message = ConditionEvaluatorV1.buildNullishDateOperandMessage(node, actual);
351
- this.options.reporter.error(this.buildReport({
352
- level: "error",
353
- tag: NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG,
354
- message,
355
- details: {
356
- field: node.field,
357
- op: node.op,
358
- actual,
359
- expected: node.value,
360
- allowNull: allowsNull,
361
- node
362
- }
363
- }));
364
- return Result.err(message);
310
+ if (actual === null && allowsNull) return Result.ok(false);
311
+ if (actual === null || actual === void 0) {
312
+ const resolved = actual === null ? "null" : "undefined";
313
+ return this.reportLeafError(NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG, `${NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG}: "${node.field}" resolved to ${resolved} for date comparison operator "${node.op}"`, node, actual, { allowNull: allowsNull });
365
314
  }
366
- if (actualDateResult === null || actualDateResult.isErr() || expectedDateResult === null || expectedDateResult.isErr()) return this.reportDateOperandError(node, actual);
367
- return Result.ok(ConditionEvaluatorV1.evaluateRelationalNumbers(actualDateResult.getOrNull().getTime(), node.op, expectedDateResult.getOrNull().getTime()));
315
+ if (actualDate === null || actualDate.isErr() || expectedDate === null || expectedDate.isErr()) return this.reportLeafError(INVALID_DATE_OPERAND_TAG, ConditionEvaluatorV1.invalidDateOperandMessage(node), node, actual);
316
+ return Result.ok(evaluateRelationalNumbers(actualDate.getOrNull().getTime(), node.op, expectedDate.getOrNull().getTime()));
368
317
  }
369
318
  evaluateOperator(actual, op, expected) {
370
319
  switch (op) {
371
320
  case "eq": return actual === expected;
372
321
  case "neq": return actual !== expected;
373
- case "gt": return typeof actual === "number" && typeof expected === "number" && ConditionEvaluatorV1.evaluateRelationalNumbers(actual, op, expected);
374
- case "gte": return typeof actual === "number" && typeof expected === "number" && ConditionEvaluatorV1.evaluateRelationalNumbers(actual, op, expected);
375
- case "lt": return typeof actual === "number" && typeof expected === "number" && ConditionEvaluatorV1.evaluateRelationalNumbers(actual, op, expected);
376
- case "lte": return typeof actual === "number" && typeof expected === "number" && ConditionEvaluatorV1.evaluateRelationalNumbers(actual, op, expected);
322
+ case "gt":
323
+ case "gte":
324
+ case "lt":
325
+ case "lte": return typeof actual === "number" && typeof expected === "number" && evaluateRelationalNumbers(actual, op, expected);
377
326
  case "in": return Array.isArray(expected) && expected.includes(actual);
378
327
  case "notIn": return Array.isArray(expected) && !expected.includes(actual);
379
- case "isNull": return actual === null;
328
+ case "isNull": return actual === null || actual === void 0;
380
329
  case "isNotNull": return actual !== null && actual !== void 0;
381
330
  }
382
331
  }
383
332
  evaluateNumericRelationalNode(node, actual) {
384
333
  const allowsNull = node.allowNull === true;
385
334
  if (actual === void 0 || actual === null && !allowsNull) {
386
- const message = ConditionEvaluatorV1.buildNullishNumericOperandMessage(node, actual);
387
- this.options.reporter.error(this.buildReport({
388
- level: "error",
389
- tag: NULLISH_NUMERIC_OPERAND_NOT_ALLOWED_TAG,
390
- message,
391
- details: {
392
- field: node.field,
393
- op: node.op,
394
- actual,
395
- expected: node.value,
396
- allowNull: allowsNull,
397
- node
398
- }
399
- }));
400
- return Result.err(message);
335
+ const resolved = actual === null ? "null" : "undefined";
336
+ return this.reportLeafError(NULLISH_NUMERIC_OPERAND_NOT_ALLOWED_TAG, `${NULLISH_NUMERIC_OPERAND_NOT_ALLOWED_TAG}: "${node.field}" resolved to ${resolved} for numeric operator "${node.op}"`, node, actual, { allowNull: allowsNull });
401
337
  }
402
338
  if (actual === null) return Result.ok(false);
403
- if (typeof actual !== "number" || typeof node.value !== "number") return this.reportInvalidNumericOperand(node, actual);
339
+ if (typeof actual !== "number" || Number.isNaN(actual) || typeof node.value !== "number" || Number.isNaN(node.value)) return this.reportLeafError(INVALID_NUMERIC_OPERAND_TAG, `${INVALID_NUMERIC_OPERAND_TAG}: "${node.field}" with operator "${node.op}" requires numeric operands`, node, actual);
404
340
  return Result.ok(this.evaluateOperator(actual, node.op, node.value));
405
341
  }
406
342
  evaluateLeafNode(node) {
407
343
  const actualResult = PolicyContextPath.getOrAbsent(this.context, node.field);
408
344
  if (actualResult.isErr()) {
345
+ const message = `MISSING_CONTEXT_FIELD: "${node.field}" not found in context`;
409
346
  this.options.reporter.warn(this.buildReport({
410
347
  level: "warn",
411
348
  tag: "MISSING_CONTEXT_FIELD",
412
- message: `MISSING_CONTEXT_FIELD: "${node.field}" not found in context`,
349
+ message,
413
350
  details: {
414
351
  field: node.field,
415
352
  node
416
353
  }
417
354
  }));
418
- return Result.err(`MISSING_CONTEXT_FIELD: "${node.field}" not found in context`);
355
+ return Result.err(message);
419
356
  }
420
357
  try {
421
358
  const actual = actualResult.getOrThrow();
@@ -424,10 +361,10 @@ var ConditionEvaluatorV1 = class ConditionEvaluatorV1 {
424
361
  if (dateResult !== null) return dateResult;
425
362
  return this.evaluateNumericRelationalNode(node, actual);
426
363
  }
427
- if ((node.op === "in" || node.op === "notIn") && !Array.isArray(node.value)) return this.reportInvalidSetOperand(node, actual);
364
+ if ((node.op === "in" || node.op === "notIn") && !Array.isArray(node.value)) return this.reportLeafError(INVALID_SET_OPERAND_TAG, `${INVALID_SET_OPERAND_TAG}: "${node.field}" with operator "${node.op}" requires an array operand`, node, actual);
428
365
  if (node.op === "eq" || node.op === "neq" || node.op === "in" || node.op === "notIn") {
429
- if (ConditionEvaluatorV1.containsInvalidDate(actual) || ConditionEvaluatorV1.containsInvalidDate(node.value)) return this.reportDateOperandError(node, actual);
430
- return Result.ok(this.evaluateOperator(ConditionEvaluatorV1.normalizeDateOperand(actual), node.op, ConditionEvaluatorV1.normalizeDateOperand(node.value)));
366
+ if (containsInvalidDate(actual) || containsInvalidDate(node.value)) return this.reportLeafError(INVALID_DATE_OPERAND_TAG, ConditionEvaluatorV1.invalidDateOperandMessage(node), node, actual);
367
+ return Result.ok(this.evaluateOperator(normalizeDateOperand(actual), node.op, normalizeDateOperand(node.value)));
431
368
  }
432
369
  return Result.ok(this.evaluateOperator(actual, node.op, node.value));
433
370
  } catch (error) {
@@ -460,7 +397,7 @@ var ConditionEvaluatorV1 = class ConditionEvaluatorV1 {
460
397
  });
461
398
  }
462
399
  if (ConditionEvaluatorV1.isAndNode(node)) {
463
- if (node.and.length === 0) return Result.err(ConditionEvaluatorV1.buildEmptyAndConditionMessage());
400
+ if (node.and.length === 0) return Result.err(`${EMPTY_AND_CONDITION_TAG}: AND nodes must contain at least one child condition`);
464
401
  let lastTracedChild = null;
465
402
  for (const [index, child] of node.and.entries()) {
466
403
  const childPath = `${path}.and[${index}]`;
@@ -496,7 +433,7 @@ var ConditionEvaluatorV1 = class ConditionEvaluatorV1 {
496
433
  trace: tracedChild.trace
497
434
  });
498
435
  }
499
- if (lastTrace === null) return Result.err(ConditionEvaluatorV1.buildEmptyOrConditionMessage());
436
+ if (lastTrace === null) return Result.err(`${EMPTY_OR_CONDITION_TAG}: OR nodes must contain at least one child condition`);
500
437
  return Result.ok({
501
438
  matched: false,
502
439
  trace: lastTrace
@@ -545,6 +482,6 @@ var ConditionEvaluatorV1 = class ConditionEvaluatorV1 {
545
482
  }
546
483
  };
547
484
  //#endregion
548
- export { SilentPolicyReporter as a, CoreConfig as i, PolicyContextPath as n, coreConfig as r, ConditionEvaluatorV1 as t };
485
+ export { CoreConfig as i, PolicyContextPath as n, coreConfig as r, ConditionEvaluatorV1 as t };
549
486
 
550
487
  //# sourceMappingURL=condition-evaluator.js.map