@cullet/erp-core 1.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 (182) hide show
  1. package/KIT_CONTEXT.md +39 -0
  2. package/README.md +110 -0
  3. package/dist/errors/index.d.ts +2 -0
  4. package/dist/errors/index.js +3 -0
  5. package/dist/exceptions/validation-field.d.ts +2 -0
  6. package/dist/exceptions/validation-field.js +2 -0
  7. package/dist/gate-engine-registry.js +260 -0
  8. package/dist/gate-engine-registry.js.map +1 -0
  9. package/dist/gate-types.d.ts +307 -0
  10. package/dist/gate-v1-payload.schema.js +677 -0
  11. package/dist/gate-v1-payload.schema.js.map +1 -0
  12. package/dist/index.d.ts +88 -0
  13. package/dist/index.js +153 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/outcome.js +92 -0
  16. package/dist/outcome.js.map +1 -0
  17. package/dist/parse-gate-payload.d.ts +136 -0
  18. package/dist/policies/engines/index.d.ts +3 -0
  19. package/dist/policies/engines/index.js +2 -0
  20. package/dist/policies/engines/v1/gate/index.d.ts +115 -0
  21. package/dist/policies/engines/v1/gate/index.js +84 -0
  22. package/dist/policies/engines/v1/gate/index.js.map +1 -0
  23. package/dist/policies/index.d.ts +4 -0
  24. package/dist/policies/index.js +5 -0
  25. package/dist/policy-service.d.ts +541 -0
  26. package/dist/policy-service.js +992 -0
  27. package/dist/policy-service.js.map +1 -0
  28. package/dist/validation-code.js +210 -0
  29. package/dist/validation-code.js.map +1 -0
  30. package/dist/validation-error.d.ts +686 -0
  31. package/dist/validation-error.js +757 -0
  32. package/dist/validation-error.js.map +1 -0
  33. package/dist/validation-field.d.ts +12 -0
  34. package/dist/validation-field.js +23 -0
  35. package/dist/validation-field.js.map +1 -0
  36. package/meta.json +66 -0
  37. package/package.json +59 -0
  38. package/src/core/application/commands/command.ts +28 -0
  39. package/src/core/application/commands/index.ts +2 -0
  40. package/src/core/application/commands/requested-by.ts +97 -0
  41. package/src/core/application/index.ts +31 -0
  42. package/src/core/application/policy-error-mapper.ts +60 -0
  43. package/src/core/application/ports/index.ts +14 -0
  44. package/src/core/application/ports/logger.port.ts +10 -0
  45. package/src/core/application/ports/metrics.port.ts +9 -0
  46. package/src/core/application/ports/policy-port.ts +20 -0
  47. package/src/core/application/ports/repository.port.ts +7 -0
  48. package/src/core/application/ports/temporal-repository.port.ts +14 -0
  49. package/src/core/application/ports/tracer.port.ts +16 -0
  50. package/src/core/application/queries/index.ts +2 -0
  51. package/src/core/application/queries/query.ts +53 -0
  52. package/src/core/application/temporal/index.ts +11 -0
  53. package/src/core/application/temporal/temporal-context.ts +41 -0
  54. package/src/core/application/temporal/temporal-use-case.ts +41 -0
  55. package/src/core/application/use-case.ts +24 -0
  56. package/src/core/config/core-config.instance.ts +14 -0
  57. package/src/core/config/core-config.ts +87 -0
  58. package/src/core/config/index.ts +12 -0
  59. package/src/core/config/policy-reporter.ts +60 -0
  60. package/src/core/config/silent-policy-reporter.ts +5 -0
  61. package/src/core/domain/entity.ts +69 -0
  62. package/src/core/domain/rulesets/entity-ruleset.contracts.ts +16 -0
  63. package/src/core/domain/rulesets/ruleset-registry.ts +71 -0
  64. package/src/core/domain/rulesets/ruleset.contracts.ts +15 -0
  65. package/src/core/domain/rulesets/value-object-ruleset.contracts.ts +13 -0
  66. package/src/core/domain/temporal/index.ts +18 -0
  67. package/src/core/domain/temporal/temporal-range.ts +53 -0
  68. package/src/core/domain/temporal/temporal-snapshot.ts +47 -0
  69. package/src/core/domain/temporal/transaction-time.ts +60 -0
  70. package/src/core/domain/temporal/valid-time.ts +57 -0
  71. package/src/core/domain/value-object.ts +30 -0
  72. package/src/core/errors/app-error.ts +85 -0
  73. package/src/core/errors/authentication-error.ts +171 -0
  74. package/src/core/errors/authorization-error.ts +204 -0
  75. package/src/core/errors/business-rule-violation-error.ts +28 -0
  76. package/src/core/errors/conflict-error.ts +246 -0
  77. package/src/core/errors/error-codes.ts +60 -0
  78. package/src/core/errors/idempotency-error.ts +372 -0
  79. package/src/core/errors/index.ts +99 -0
  80. package/src/core/errors/integration-error.ts +157 -0
  81. package/src/core/errors/legacy-incompatible-error.ts +26 -0
  82. package/src/core/errors/not-found-error.ts +27 -0
  83. package/src/core/errors/serialization-error.ts +233 -0
  84. package/src/core/errors/temporal-error.ts +145 -0
  85. package/src/core/errors/types.ts +74 -0
  86. package/src/core/errors/unexpected-error.ts +22 -0
  87. package/src/core/errors/utils/index.ts +4 -0
  88. package/src/core/errors/utils/json-safe.ts +93 -0
  89. package/src/core/errors/validation-error.ts +34 -0
  90. package/src/core/exceptions/business-rule-violation-exception.ts +12 -0
  91. package/src/core/exceptions/domain-exception.ts +9 -0
  92. package/src/core/exceptions/entity-not-found-exception.ts +12 -0
  93. package/src/core/exceptions/invalid-state-transition-exception.ts +15 -0
  94. package/src/core/exceptions/invariant-violation-exception.ts +9 -0
  95. package/src/core/exceptions/validation-code.ts +39 -0
  96. package/src/core/exceptions/validation-exception.ts +39 -0
  97. package/src/core/exceptions/validation-field.ts +32 -0
  98. package/src/core/index.ts +15 -0
  99. package/src/core/policies/asof/asof.ts +68 -0
  100. package/src/core/policies/asof/index.ts +2 -0
  101. package/src/core/policies/catalog/catalog-types.ts +12 -0
  102. package/src/core/policies/catalog/catalog.instance.ts +21 -0
  103. package/src/core/policies/catalog/index.ts +11 -0
  104. package/src/core/policies/catalog/policy-catalog-entry.ts +220 -0
  105. package/src/core/policies/catalog/policy-catalog.ts +124 -0
  106. package/src/core/policies/catalog/policy-key.ts +78 -0
  107. package/src/core/policies/context/context-builder.ts +391 -0
  108. package/src/core/policies/context/context-registry.instance.ts +26 -0
  109. package/src/core/policies/context/context-registry.ts +95 -0
  110. package/src/core/policies/context/context-resolver.ts +31 -0
  111. package/src/core/policies/context/context-seed.ts +32 -0
  112. package/src/core/policies/context/index.ts +21 -0
  113. package/src/core/policies/context/path.ts +152 -0
  114. package/src/core/policies/defs/in-memory-policy-definition-repo.ts +73 -0
  115. package/src/core/policies/defs/index.ts +20 -0
  116. package/src/core/policies/defs/policy-definition-repository.ts +8 -0
  117. package/src/core/policies/defs/policy-definition.ts +192 -0
  118. package/src/core/policies/defs/policy-payload.contracts.ts +13 -0
  119. package/src/core/policies/defs/policy-scope.ts +53 -0
  120. package/src/core/policies/defs/policy-semver.ts +83 -0
  121. package/src/core/policies/engines/compute-engine-registry.ts +57 -0
  122. package/src/core/policies/engines/compute-evaluator-registry.ts +28 -0
  123. package/src/core/policies/engines/compute-payload.ts +5 -0
  124. package/src/core/policies/engines/compute-registry.ts +67 -0
  125. package/src/core/policies/engines/compute-types.ts +51 -0
  126. package/src/core/policies/engines/condition-evaluator-reporter.ts +34 -0
  127. package/src/core/policies/engines/gate-engine-registry.ts +38 -0
  128. package/src/core/policies/engines/gate-payload.ts +5 -0
  129. package/src/core/policies/engines/gate-types.ts +63 -0
  130. package/src/core/policies/engines/index.ts +48 -0
  131. package/src/core/policies/engines/parse-compute-payload.ts +71 -0
  132. package/src/core/policies/engines/parse-gate-payload.ts +68 -0
  133. package/src/core/policies/engines/v1/compute/compute-engine-v1.ts +55 -0
  134. package/src/core/policies/engines/v1/compute/compute-payload.schema.ts +75 -0
  135. package/src/core/policies/engines/v1/compute/index.ts +12 -0
  136. package/src/core/policies/engines/v1/compute/resolve-decision-table-v1.ts +54 -0
  137. package/src/core/policies/engines/v1/condition-evaluator.ts +592 -0
  138. package/src/core/policies/engines/v1/condition-schema.ts +50 -0
  139. package/src/core/policies/engines/v1/condition-types.ts +41 -0
  140. package/src/core/policies/engines/v1/gate/gate-engine-v1.ts +157 -0
  141. package/src/core/policies/engines/v1/gate/gate-types-v1.ts +12 -0
  142. package/src/core/policies/engines/v1/gate/gate-v1-payload.schema.ts +46 -0
  143. package/src/core/policies/engines/v1/gate/index.ts +9 -0
  144. package/src/core/policies/engines/v1/index.ts +13 -0
  145. package/src/core/policies/index.ts +132 -0
  146. package/src/core/policies/package/policy-package.ts +17 -0
  147. package/src/core/policies/policy-ids.ts +60 -0
  148. package/src/core/policies/resolver/index.ts +1 -0
  149. package/src/core/policies/resolver/policy-resolver.ts +57 -0
  150. package/src/core/policies/service/index.ts +10 -0
  151. package/src/core/policies/service/policy-evaluation-error.ts +148 -0
  152. package/src/core/policies/service/policy-service.ts +493 -0
  153. package/src/core/policies/utils/date.ts +7 -0
  154. package/src/core/policies/utils/hash.ts +90 -0
  155. package/src/core/policies/utils/index.ts +3 -0
  156. package/src/core/policies/utils/result.ts +4 -0
  157. package/src/core/result/outcome.ts +158 -0
  158. package/src/core/result/result.ts +153 -0
  159. package/src/core/shared/aggregate-version.ts +11 -0
  160. package/src/core/shared/hashing.ts +38 -0
  161. package/src/core/shared/immutable.ts +46 -0
  162. package/src/core/shared/temporal-guards.ts +22 -0
  163. package/src/core/versioning/domain-event-contracts.ts +73 -0
  164. package/src/core/versioning/version.ts +34 -0
  165. package/src/errors/index.ts +1 -0
  166. package/src/examples/rulesets/entity/order-creation-rules-v1.ts +31 -0
  167. package/src/examples/rulesets/entity/order-invariants-v1.ts +48 -0
  168. package/src/examples/rulesets/entity/order-invariants-v2.ts +28 -0
  169. package/src/examples/rulesets/entity/order.ts +162 -0
  170. package/src/examples/rulesets/value-object/cpf-rules-v1.ts +52 -0
  171. package/src/examples/rulesets/value-object/cpf-rules-v2.ts +27 -0
  172. package/src/examples/rulesets/value-object/cpf.ts +37 -0
  173. package/src/examples/rulesets/value-object/customer.ts +67 -0
  174. package/src/examples/rulesets/value-object/person-name-rules-v1.ts +37 -0
  175. package/src/examples/rulesets/value-object/person-name-rules-v2.ts +27 -0
  176. package/src/examples/rulesets/value-object/person-name.ts +39 -0
  177. package/src/exceptions/validation-field.ts +1 -0
  178. package/src/index.ts +11 -0
  179. package/src/policies/engines/index.ts +1 -0
  180. package/src/policies/engines/v1/gate/index.ts +1 -0
  181. package/src/policies/index.ts +1 -0
  182. package/src/version.ts +7 -0
@@ -0,0 +1,677 @@
1
+ import { z } from "zod";
2
+ //#region src/core/exceptions/domain-exception.ts
3
+ var DomainException = class extends Error {
4
+ constructor(message) {
5
+ super(message);
6
+ Object.setPrototypeOf(this, new.target.prototype);
7
+ this.name = new.target.name;
8
+ }
9
+ };
10
+ //#endregion
11
+ //#region src/core/exceptions/invariant-violation-exception.ts
12
+ var InvariantViolationException = class extends DomainException {
13
+ constructor(message) {
14
+ super(message);
15
+ }
16
+ };
17
+ //#endregion
18
+ //#region src/core/shared/temporal-guards.ts
19
+ function isValidDate(value) {
20
+ return value instanceof Date && !Number.isNaN(value.getTime());
21
+ }
22
+ function cloneDate(date) {
23
+ return new Date(date.getTime());
24
+ }
25
+ function assertValidDate(fieldName, value) {
26
+ if (!isValidDate(value)) throw new InvariantViolationException(`${fieldName} must be a valid Date instance`);
27
+ }
28
+ //#endregion
29
+ //#region src/core/config/silent-policy-reporter.ts
30
+ var SilentPolicyReporter = class {
31
+ report(_event) {}
32
+ };
33
+ //#endregion
34
+ //#region src/core/config/core-config.ts
35
+ function reportSafely(policyReporter, event) {
36
+ try {
37
+ policyReporter.report(event);
38
+ } catch {}
39
+ }
40
+ /**
41
+ * Centraliza a configuracao pura do core sem depender de implementacoes
42
+ * concretas de logging, tracing ou report.
43
+ */
44
+ var CoreConfig = class {
45
+ #initialReporter;
46
+ #currentReporter;
47
+ constructor(options = {}) {
48
+ const reporter = options.observability?.reporter ?? new SilentPolicyReporter();
49
+ this.#initialReporter = reporter;
50
+ this.#currentReporter = reporter;
51
+ }
52
+ configure(options) {
53
+ const reporter = options.observability?.reporter;
54
+ if (reporter) this.#currentReporter = reporter;
55
+ return this;
56
+ }
57
+ reset() {
58
+ this.#currentReporter = this.#initialReporter;
59
+ return this;
60
+ }
61
+ getPolicyReporter() {
62
+ return this.#currentReporter;
63
+ }
64
+ getConditionEvaluationOptions(engineVersion) {
65
+ return {
66
+ reporter: this.#bridgeToConditionReporter(this.#currentReporter),
67
+ engineVersion
68
+ };
69
+ }
70
+ #bridgeToConditionReporter(policyReporter) {
71
+ return {
72
+ warn(report) {
73
+ reportSafely(policyReporter, {
74
+ kind: "condition-eval",
75
+ ...report
76
+ });
77
+ },
78
+ error(report) {
79
+ reportSafely(policyReporter, {
80
+ kind: "condition-eval",
81
+ ...report
82
+ });
83
+ }
84
+ };
85
+ }
86
+ };
87
+ //#endregion
88
+ //#region src/core/config/core-config.instance.ts
89
+ /**
90
+ * Shared instance for the application composition root.
91
+ * Use `new CoreConfig()` for isolated runtimes, tests, or multi-tenant hosts.
92
+ *
93
+ * The default reporter is silent so the core has no runtime logging dependency.
94
+ * Hosts can swap in their own `PolicyReporter` via
95
+ * `coreConfig.configure({ observability: { reporter } })`.
96
+ */
97
+ const coreConfig = new CoreConfig({ observability: { reporter: new SilentPolicyReporter() } });
98
+ //#endregion
99
+ //#region src/core/result/result.ts
100
+ /**
101
+ * Represents the outcome of an operation that may succeed or fail.
102
+ * Useful for avoiding excessive exceptions and making error flows explicit.
103
+ */
104
+ var Result = class Result {
105
+ constructor() {}
106
+ /**
107
+ * Creates a success result containing a value.
108
+ */
109
+ static ok(value) {
110
+ return new Ok(value);
111
+ }
112
+ /**
113
+ * Creates an error result containing an error object.
114
+ */
115
+ static err(error) {
116
+ return new Err(error);
117
+ }
118
+ /**
119
+ * Returns the value when this is success, or null when this is an error.
120
+ */
121
+ getOrNull() {
122
+ return this.match({
123
+ ok: (value) => value,
124
+ err: () => null
125
+ });
126
+ }
127
+ /**
128
+ * Returns the error when this is a failure, or null when this is a success.
129
+ */
130
+ errorOrNull() {
131
+ return this.match({
132
+ ok: () => null,
133
+ err: (error) => error
134
+ });
135
+ }
136
+ /**
137
+ * Returns the value when this is a success, or throws the error when this is a failure.
138
+ */
139
+ getOrThrow() {
140
+ return this.match({
141
+ ok: (value) => value,
142
+ err: (error) => {
143
+ throw error instanceof Error ? error : new Error(String(error));
144
+ }
145
+ });
146
+ }
147
+ /**
148
+ * Transforms the success value using the provided function. Keeps the error when this is a failure.
149
+ */
150
+ map(transform) {
151
+ return this.match({
152
+ ok: (value) => Result.ok(transform(value)),
153
+ err: (error) => Result.err(error)
154
+ });
155
+ }
156
+ /**
157
+ * Transforms the error using the provided function. Keeps the value when this is a success.
158
+ */
159
+ mapError(transform) {
160
+ return this.match({
161
+ ok: (value) => Result.ok(value),
162
+ err: (error) => Result.err(transform(error))
163
+ });
164
+ }
165
+ /**
166
+ * Chains another operation that returns a Result when this result is a success.
167
+ */
168
+ flatMap(transform) {
169
+ return this.match({
170
+ ok: (value) => transform(value),
171
+ err: (error) => Result.err(error)
172
+ });
173
+ }
174
+ };
175
+ /**
176
+ * Success variant of Result.
177
+ */
178
+ var Ok = class extends Result {
179
+ constructor(value) {
180
+ super();
181
+ this.value = value;
182
+ Object.freeze(this);
183
+ }
184
+ isOk() {
185
+ return true;
186
+ }
187
+ isErr() {
188
+ return false;
189
+ }
190
+ match(handlers) {
191
+ return handlers.ok(this.value);
192
+ }
193
+ };
194
+ /**
195
+ * Error variant of Result.
196
+ */
197
+ var Err = class extends Result {
198
+ constructor(error) {
199
+ super();
200
+ this.error = error;
201
+ Object.freeze(this);
202
+ }
203
+ isOk() {
204
+ return false;
205
+ }
206
+ isErr() {
207
+ return true;
208
+ }
209
+ match(handlers) {
210
+ return handlers.err(this.error);
211
+ }
212
+ };
213
+ //#endregion
214
+ //#region src/core/policies/utils/date.ts
215
+ var PolicyDateUtils = class {
216
+ static isValid(value) {
217
+ return isValidDate(value);
218
+ }
219
+ };
220
+ //#endregion
221
+ //#region src/core/policies/context/path.ts
222
+ /**
223
+ * Utilities for reading/writing values at dot-separated paths
224
+ * in plain objects, e.g. "installment.dueDate".
225
+ */
226
+ var PolicyContextPath = class PolicyContextPath {
227
+ static {
228
+ this.FORBIDDEN_SEGMENTS = new Set([
229
+ "__proto__",
230
+ "prototype",
231
+ "constructor"
232
+ ]);
233
+ }
234
+ static resolve(obj, path) {
235
+ const segmentsResult = PolicyContextPath.parseSegments(path);
236
+ if (segmentsResult.isErr()) return Result.err(segmentsResult.errorOrNull());
237
+ const segments = segmentsResult.getOrNull();
238
+ let current = obj;
239
+ for (const segment of segments) {
240
+ if (current === null || current === void 0 || typeof current !== "object") return Result.ok({
241
+ found: false,
242
+ value: void 0
243
+ });
244
+ const record = current;
245
+ if (!Object.prototype.hasOwnProperty.call(record, segment)) return Result.ok({
246
+ found: false,
247
+ value: void 0
248
+ });
249
+ current = record[segment];
250
+ }
251
+ return Result.ok({
252
+ found: true,
253
+ value: current
254
+ });
255
+ }
256
+ static parseSegments(path) {
257
+ if (path.trim().length === 0) return Result.err("Path cannot be empty");
258
+ const segments = path.split(".");
259
+ if (segments.some((segment) => segment.length === 0)) return Result.err(`Path "${path}" contains an empty segment`);
260
+ const forbiddenSegment = segments.find((segment) => PolicyContextPath.FORBIDDEN_SEGMENTS.has(segment));
261
+ if (forbiddenSegment !== void 0) return Result.err(`Path "${path}" contains forbidden segment "${forbiddenSegment}"`);
262
+ return Result.ok(segments);
263
+ }
264
+ static isPlainRecord(value) {
265
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
266
+ const prototype = Object.getPrototypeOf(value);
267
+ return prototype === Object.prototype || prototype === null;
268
+ }
269
+ static getOrAbsent(obj, path) {
270
+ const resolvedPath = PolicyContextPath.resolve(obj, path);
271
+ if (resolvedPath.isErr()) return Result.err("absent");
272
+ const { found, value } = resolvedPath.getOrNull();
273
+ if (!found) return Result.err("absent");
274
+ return Result.ok(value);
275
+ }
276
+ static has(obj, path) {
277
+ const resolvedPath = PolicyContextPath.resolve(obj, path);
278
+ if (resolvedPath.isErr()) return false;
279
+ return resolvedPath.getOrNull().found;
280
+ }
281
+ static set(obj, path, value) {
282
+ const segmentsResult = PolicyContextPath.parseSegments(path);
283
+ if (segmentsResult.isErr()) return Result.err(segmentsResult.errorOrNull());
284
+ const segments = segmentsResult.getOrNull();
285
+ let current = obj;
286
+ for (let i = 0; i < segments.length - 1; i++) {
287
+ const seg = segments[i];
288
+ const next = current[seg];
289
+ if (next === void 0) {
290
+ const container = Object.create(null);
291
+ current[seg] = container;
292
+ current = container;
293
+ continue;
294
+ }
295
+ if (!PolicyContextPath.isPlainRecord(next)) return Result.err(`Cannot create nested path "${path}" because "${segments.slice(0, i + 1).join(".")}" already contains a non-plain object`);
296
+ current = next;
297
+ }
298
+ current[segments[segments.length - 1]] = value;
299
+ return Result.ok(void 0);
300
+ }
301
+ };
302
+ //#endregion
303
+ //#region src/core/policies/engines/v1/condition-schema.ts
304
+ const conditionOpSchema = z.enum([
305
+ "eq",
306
+ "neq",
307
+ "gt",
308
+ "gte",
309
+ "lt",
310
+ "lte",
311
+ "in",
312
+ "notIn",
313
+ "isNull",
314
+ "isNotNull"
315
+ ]);
316
+ const conditionLeafNodeSchema = z.object({
317
+ field: z.string().min(1),
318
+ op: conditionOpSchema,
319
+ value: z.unknown(),
320
+ allowNull: z.literal(true).optional()
321
+ }).strict();
322
+ const conditionNodeSchema = z.lazy(() => z.union([
323
+ conditionLeafNodeSchema,
324
+ z.object({ and: z.array(conditionNodeSchema).min(1) }).strict(),
325
+ z.object({ or: z.array(conditionNodeSchema).min(1) }).strict(),
326
+ z.object({ not: conditionNodeSchema }).strict()
327
+ ]));
328
+ //#endregion
329
+ //#region src/core/policies/engines/v1/condition-evaluator.ts
330
+ const CONDITION_EVAL_THROWN_TAG = "CONDITION_EVAL_THREW";
331
+ const NULLISH_NUMERIC_OPERAND_NOT_ALLOWED_TAG = "NULLISH_NUMERIC_OPERAND_NOT_ALLOWED";
332
+ const NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG = "NULLISH_DATE_OPERAND_NOT_ALLOWED";
333
+ const INVALID_DATE_OPERAND_TAG = "INVALID_DATE_OPERAND";
334
+ const EMPTY_OR_CONDITION_TAG = "EMPTY_OR_CONDITION";
335
+ const ISO_8601_UTC_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
336
+ var ConditionEvaluatorV1 = class ConditionEvaluatorV1 {
337
+ constructor(context, options) {
338
+ this.context = context;
339
+ this.options = options;
340
+ }
341
+ static isLeafNode(node) {
342
+ return "field" in node && "op" in node;
343
+ }
344
+ static isAndNode(node) {
345
+ return "and" in node;
346
+ }
347
+ static isOrNode(node) {
348
+ return "or" in node;
349
+ }
350
+ static isNotNode(node) {
351
+ return "not" in node;
352
+ }
353
+ static isRelationalOperator(op) {
354
+ return op === "gt" || op === "gte" || op === "lt" || op === "lte";
355
+ }
356
+ static describeError(error) {
357
+ if (error instanceof Error) return {
358
+ name: error.name,
359
+ message: error.message
360
+ };
361
+ return {
362
+ name: "NonErrorThrown",
363
+ message: String(error)
364
+ };
365
+ }
366
+ static buildNullishNumericOperandMessage(node, actual) {
367
+ const resolvedValue = actual === null ? "null" : "undefined";
368
+ return `${NULLISH_NUMERIC_OPERAND_NOT_ALLOWED_TAG}: "${node.field}" resolved to ${resolvedValue} for numeric operator "${node.op}"`;
369
+ }
370
+ static buildNullishDateOperandMessage(node, actual) {
371
+ const resolvedValue = actual === null ? "null" : "undefined";
372
+ return `${NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG}: "${node.field}" resolved to ${resolvedValue} for date comparison operator "${node.op}"`;
373
+ }
374
+ static buildInvalidDateOperandMessage(node) {
375
+ return `${INVALID_DATE_OPERAND_TAG}: "${node.field}" with operator "${node.op}" requires Date or ISO 8601 UTC string operands`;
376
+ }
377
+ static buildEmptyOrConditionMessage() {
378
+ return `${EMPTY_OR_CONDITION_TAG}: OR nodes must contain at least one child condition`;
379
+ }
380
+ static parseComparableDate(value) {
381
+ if (value instanceof Date) {
382
+ if (!PolicyDateUtils.isValid(value)) return Result.err("Invalid Date instance");
383
+ return Result.ok(value);
384
+ }
385
+ if (typeof value !== "string" || !ISO_8601_UTC_DATE_PATTERN.test(value)) return null;
386
+ const parsed = new Date(value);
387
+ if (!PolicyDateUtils.isValid(parsed) || parsed.toISOString() !== value) return Result.err("Invalid ISO 8601 UTC date string");
388
+ return Result.ok(parsed);
389
+ }
390
+ static evaluateRelationalNumbers(actual, op, expected) {
391
+ switch (op) {
392
+ case "gt": return actual > expected;
393
+ case "gte": return actual >= expected;
394
+ case "lt": return actual < expected;
395
+ case "lte": return actual <= expected;
396
+ }
397
+ }
398
+ buildReport(params) {
399
+ return {
400
+ occurredAt: /* @__PURE__ */ new Date(),
401
+ level: params.level,
402
+ tag: params.tag,
403
+ message: params.message,
404
+ engineVersion: this.options.engineVersion,
405
+ details: params.details
406
+ };
407
+ }
408
+ conditionEvalErr(node, error) {
409
+ const cause = ConditionEvaluatorV1.describeError(error);
410
+ const message = `${CONDITION_EVAL_THROWN_TAG}: ${cause.name}: ${cause.message}`;
411
+ this.options.reporter.error(this.buildReport({
412
+ level: "error",
413
+ tag: CONDITION_EVAL_THROWN_TAG,
414
+ message,
415
+ details: {
416
+ node,
417
+ cause
418
+ }
419
+ }));
420
+ return Result.err(message);
421
+ }
422
+ reportDateOperandError(node, actual) {
423
+ const message = ConditionEvaluatorV1.buildInvalidDateOperandMessage(node);
424
+ this.options.reporter.error(this.buildReport({
425
+ level: "error",
426
+ tag: INVALID_DATE_OPERAND_TAG,
427
+ message,
428
+ details: {
429
+ field: node.field,
430
+ op: node.op,
431
+ actual,
432
+ expected: node.value,
433
+ node
434
+ }
435
+ }));
436
+ return Result.err(message);
437
+ }
438
+ evaluateDateRelationalNode(node, actual) {
439
+ if (!ConditionEvaluatorV1.isRelationalOperator(node.op)) return null;
440
+ const actualDateResult = ConditionEvaluatorV1.parseComparableDate(actual);
441
+ const expectedDateResult = ConditionEvaluatorV1.parseComparableDate(node.value);
442
+ if (actualDateResult === null && expectedDateResult === null) return null;
443
+ const allowsNull = node.allowNull === true;
444
+ if (actual === null) {
445
+ if (allowsNull) return Result.ok(false);
446
+ const message = ConditionEvaluatorV1.buildNullishDateOperandMessage(node, actual);
447
+ this.options.reporter.error(this.buildReport({
448
+ level: "error",
449
+ tag: NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG,
450
+ message,
451
+ details: {
452
+ field: node.field,
453
+ op: node.op,
454
+ actual,
455
+ expected: node.value,
456
+ allowNull: allowsNull,
457
+ node
458
+ }
459
+ }));
460
+ return Result.err(message);
461
+ }
462
+ if (actual === void 0) {
463
+ const message = ConditionEvaluatorV1.buildNullishDateOperandMessage(node, actual);
464
+ this.options.reporter.error(this.buildReport({
465
+ level: "error",
466
+ tag: NULLISH_DATE_OPERAND_NOT_ALLOWED_TAG,
467
+ message,
468
+ details: {
469
+ field: node.field,
470
+ op: node.op,
471
+ actual,
472
+ expected: node.value,
473
+ allowNull: allowsNull,
474
+ node
475
+ }
476
+ }));
477
+ return Result.err(message);
478
+ }
479
+ if (actualDateResult === null || actualDateResult.isErr() || expectedDateResult === null || expectedDateResult.isErr()) return this.reportDateOperandError(node, actual);
480
+ return Result.ok(ConditionEvaluatorV1.evaluateRelationalNumbers(actualDateResult.getOrNull().getTime(), node.op, expectedDateResult.getOrNull().getTime()));
481
+ }
482
+ evaluateOperator(actual, op, expected) {
483
+ switch (op) {
484
+ case "eq": return actual === expected;
485
+ case "neq": return actual !== expected;
486
+ case "gt": return typeof actual === "number" && typeof expected === "number" && ConditionEvaluatorV1.evaluateRelationalNumbers(actual, op, expected);
487
+ case "gte": return typeof actual === "number" && typeof expected === "number" && ConditionEvaluatorV1.evaluateRelationalNumbers(actual, op, expected);
488
+ case "lt": return typeof actual === "number" && typeof expected === "number" && ConditionEvaluatorV1.evaluateRelationalNumbers(actual, op, expected);
489
+ case "lte": return typeof actual === "number" && typeof expected === "number" && ConditionEvaluatorV1.evaluateRelationalNumbers(actual, op, expected);
490
+ case "in": return Array.isArray(expected) && expected.includes(actual);
491
+ case "notIn": return Array.isArray(expected) && !expected.includes(actual);
492
+ case "isNull": return actual === null;
493
+ case "isNotNull": return actual !== null && actual !== void 0;
494
+ }
495
+ }
496
+ evaluateNumericRelationalNode(node, actual) {
497
+ const allowsNull = node.allowNull === true;
498
+ if (actual === void 0 || actual === null && !allowsNull) {
499
+ const message = ConditionEvaluatorV1.buildNullishNumericOperandMessage(node, actual);
500
+ this.options.reporter.error(this.buildReport({
501
+ level: "error",
502
+ tag: NULLISH_NUMERIC_OPERAND_NOT_ALLOWED_TAG,
503
+ message,
504
+ details: {
505
+ field: node.field,
506
+ op: node.op,
507
+ actual,
508
+ expected: node.value,
509
+ allowNull: allowsNull,
510
+ node
511
+ }
512
+ }));
513
+ return Result.err(message);
514
+ }
515
+ return Result.ok(this.evaluateOperator(actual, node.op, node.value));
516
+ }
517
+ evaluateLeafNode(node) {
518
+ const actualResult = PolicyContextPath.getOrAbsent(this.context, node.field);
519
+ if (actualResult.isErr()) {
520
+ this.options.reporter.warn(this.buildReport({
521
+ level: "warn",
522
+ tag: "MISSING_CONTEXT_FIELD",
523
+ message: `MISSING_CONTEXT_FIELD: "${node.field}" not found in context`,
524
+ details: {
525
+ field: node.field,
526
+ node
527
+ }
528
+ }));
529
+ return Result.err(`MISSING_CONTEXT_FIELD: "${node.field}" not found in context`);
530
+ }
531
+ try {
532
+ const actual = actualResult.getOrThrow();
533
+ if (ConditionEvaluatorV1.isRelationalOperator(node.op)) {
534
+ const dateResult = this.evaluateDateRelationalNode(node, actual);
535
+ if (dateResult !== null) return dateResult;
536
+ return this.evaluateNumericRelationalNode(node, actual);
537
+ }
538
+ return Result.ok(this.evaluateOperator(actual, node.op, node.value));
539
+ } catch (error) {
540
+ return this.conditionEvalErr(node, error);
541
+ }
542
+ }
543
+ buildTrace(params) {
544
+ return {
545
+ conditionPath: params.conditionPath,
546
+ decisiveNode: params.decisiveNode,
547
+ lastEvaluatedLeaf: params.lastEvaluatedLeaf,
548
+ lastEvaluatedLeafPath: params.lastEvaluatedLeafPath,
549
+ lastEvaluatedLeafResult: params.lastEvaluatedLeafResult
550
+ };
551
+ }
552
+ evaluateWithTraceInternal(node, path) {
553
+ if (ConditionEvaluatorV1.isLeafNode(node)) {
554
+ const leafResult = this.evaluateLeafNode(node);
555
+ if (leafResult.isErr()) return Result.err(leafResult.errorOrNull());
556
+ const matched = leafResult.getOrNull();
557
+ return Result.ok({
558
+ matched,
559
+ trace: this.buildTrace({
560
+ conditionPath: path,
561
+ decisiveNode: node,
562
+ lastEvaluatedLeaf: node,
563
+ lastEvaluatedLeafPath: path,
564
+ lastEvaluatedLeafResult: matched
565
+ })
566
+ });
567
+ }
568
+ if (ConditionEvaluatorV1.isAndNode(node)) {
569
+ let lastTracedChild = null;
570
+ for (const [index, child] of node.and.entries()) {
571
+ const childPath = `${path}.and[${index}]`;
572
+ const childResult = this.evaluateWithTraceInternal(child, childPath);
573
+ if (childResult.isErr()) return Result.err(childResult.errorOrNull());
574
+ const tracedChild = childResult.getOrNull();
575
+ lastTracedChild = tracedChild;
576
+ if (!tracedChild.matched) return Result.ok({
577
+ matched: false,
578
+ trace: this.buildTrace({
579
+ conditionPath: childPath,
580
+ decisiveNode: child,
581
+ lastEvaluatedLeaf: tracedChild.trace.lastEvaluatedLeaf,
582
+ lastEvaluatedLeafPath: tracedChild.trace.lastEvaluatedLeafPath,
583
+ lastEvaluatedLeafResult: tracedChild.trace.lastEvaluatedLeafResult
584
+ })
585
+ });
586
+ }
587
+ return Result.ok({
588
+ matched: true,
589
+ trace: lastTracedChild.trace
590
+ });
591
+ }
592
+ if (ConditionEvaluatorV1.isOrNode(node)) {
593
+ let lastTrace = null;
594
+ for (const [index, child] of node.or.entries()) {
595
+ const childResult = this.evaluateWithTraceInternal(child, `${path}.or[${index}]`);
596
+ if (childResult.isErr()) return Result.err(childResult.errorOrNull());
597
+ const tracedChild = childResult.getOrNull();
598
+ lastTrace = tracedChild.trace;
599
+ if (tracedChild.matched) return Result.ok({
600
+ matched: true,
601
+ trace: tracedChild.trace
602
+ });
603
+ }
604
+ if (lastTrace === null) return Result.err(ConditionEvaluatorV1.buildEmptyOrConditionMessage());
605
+ return Result.ok({
606
+ matched: false,
607
+ trace: lastTrace
608
+ });
609
+ }
610
+ if (ConditionEvaluatorV1.isNotNode(node)) {
611
+ const childPath = `${path}.not`;
612
+ const childResult = this.evaluateWithTraceInternal(node.not, childPath);
613
+ if (childResult.isErr()) return Result.err(childResult.errorOrNull());
614
+ const tracedChild = childResult.getOrNull();
615
+ return Result.ok({
616
+ matched: !tracedChild.matched,
617
+ trace: this.buildTrace({
618
+ conditionPath: path,
619
+ decisiveNode: node,
620
+ lastEvaluatedLeaf: tracedChild.trace.lastEvaluatedLeaf,
621
+ lastEvaluatedLeafPath: tracedChild.trace.lastEvaluatedLeafPath,
622
+ lastEvaluatedLeafResult: tracedChild.trace.lastEvaluatedLeafResult
623
+ })
624
+ });
625
+ }
626
+ return this.conditionEvalErr(node, /* @__PURE__ */ new TypeError("Invalid condition node shape"));
627
+ }
628
+ evaluate(node) {
629
+ try {
630
+ const result = this.evaluateWithTraceInternal(node, "$");
631
+ if (result.isErr()) return Result.err(result.errorOrNull());
632
+ return Result.ok(result.getOrNull().matched);
633
+ } catch (error) {
634
+ return this.conditionEvalErr(node, error);
635
+ }
636
+ }
637
+ evaluateWithTrace(node) {
638
+ try {
639
+ return this.evaluateWithTraceInternal(node, "$");
640
+ } catch (error) {
641
+ return this.conditionEvalErr(node, error);
642
+ }
643
+ }
644
+ static extractFields(node) {
645
+ if (ConditionEvaluatorV1.isLeafNode(node)) return [node.field];
646
+ if (ConditionEvaluatorV1.isAndNode(node)) return node.and.flatMap((child) => ConditionEvaluatorV1.extractFields(child));
647
+ if (ConditionEvaluatorV1.isOrNode(node)) return node.or.flatMap((child) => ConditionEvaluatorV1.extractFields(child));
648
+ if (ConditionEvaluatorV1.isNotNode(node)) return ConditionEvaluatorV1.extractFields(node.not);
649
+ return [];
650
+ }
651
+ };
652
+ //#endregion
653
+ //#region src/core/policies/engines/v1/gate/gate-v1-payload.schema.ts
654
+ var GatePayloadSchemaV1 = class GatePayloadSchemaV1 {
655
+ static {
656
+ this.schema = z.union([z.object({ condition: conditionNodeSchema }).strict(), z.object({
657
+ allowIf: conditionNodeSchema,
658
+ defaultOutcome: z.enum(["ALLOW", "DENY"])
659
+ }).strict()]);
660
+ }
661
+ static parse(payload) {
662
+ const parsed = GatePayloadSchemaV1.schema.safeParse(payload);
663
+ if (!parsed.success) {
664
+ const details = parsed.error.issues.map((issue) => {
665
+ const path = issue.path.join(".");
666
+ return path.length > 0 ? `${path}: ${issue.message}` : issue.message;
667
+ }).join("; ");
668
+ return Result.err(`Invalid gate payload: ${details}`);
669
+ }
670
+ return Result.ok(parsed.data);
671
+ }
672
+ };
673
+ const gatePayloadSchema = GatePayloadSchemaV1.schema;
674
+ //#endregion
675
+ export { DomainException as _, conditionNodeSchema as a, Ok as c, CoreConfig as d, SilentPolicyReporter as f, InvariantViolationException as g, isValidDate as h, conditionLeafNodeSchema as i, Result as l, cloneDate as m, gatePayloadSchema as n, PolicyContextPath as o, assertValidDate as p, ConditionEvaluatorV1 as r, Err as s, GatePayloadSchemaV1 as t, coreConfig as u };
676
+
677
+ //# sourceMappingURL=gate-v1-payload.schema.js.map