@cullet/erp-core 1.4.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 +7 -1
  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 +21 -6
  9. package/dist/app-error.cjs.map +1 -1
  10. package/dist/app-error.js +21 -6
  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 +117 -172
  27. package/dist/condition-evaluator.cjs.map +1 -1
  28. package/dist/condition-evaluator.js +118 -167
  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 +3 -2
  51. package/dist/errors/index.d.cts +1 -1
  52. package/dist/errors/index.d.ts +1 -1
  53. package/dist/errors/index.js +3 -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 +2 -44
  67. package/dist/hashing.cjs.map +1 -1
  68. package/dist/hashing.js +3 -39
  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 +15 -11
  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 +8 -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 -13
  109. package/dist/policies/engines/v1/gate/index.d.ts +3 -13
  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 +41 -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 +43 -48
  123. package/dist/policy-service.js.map +1 -1
  124. package/dist/requested-by.cjs +4 -4
  125. package/dist/requested-by.cjs.map +1 -1
  126. package/dist/requested-by.js +2 -2
  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 +87 -0
  143. package/dist/stable-stringify.cjs.map +1 -0
  144. package/dist/stable-stringify.js +76 -0
  145. package/dist/stable-stringify.js.map +1 -0
  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 +174 -16
  149. package/dist/temporal-use-case.cjs.map +1 -1
  150. package/dist/temporal-use-case.d.cts +82 -44
  151. package/dist/temporal-use-case.d.ts +82 -44
  152. package/dist/temporal-use-case.js +167 -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 +141 -8
  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 -8
  163. package/dist/uuid-identifier.js.map +1 -1
  164. package/dist/uuid.cjs +23 -0
  165. package/dist/uuid.cjs.map +1 -0
  166. package/dist/uuid.js +18 -0
  167. package/dist/uuid.js.map +1 -0
  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 +29 -8
  177. package/dist/validation-error.d.ts +29 -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 +23 -4
  195. package/dist/value-object.cjs.map +1 -1
  196. package/dist/value-object.d.cts +25 -1
  197. package/dist/value-object.d.ts +25 -1
  198. package/dist/value-object.js +23 -4
  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 +5 -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 +13 -5
  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 +25 -3
  218. package/src/core/application/temporal/temporal-use-case.ts +31 -4
  219. package/src/core/application/use-case.ts +45 -8
  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 +51 -8
  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 +6 -11
  232. package/src/core/domain/value-object.ts +29 -3
  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 +35 -12
  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 +120 -291
  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 -57
  281. package/src/core/shared/immutable.ts +22 -4
  282. package/src/core/shared/stable-stringify.ts +144 -0
  283. package/src/core/shared/uuid.ts +16 -0
  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 -126
  300. package/dist/entity.cjs.map +0 -1
  301. package/dist/entity.js +0 -115
  302. package/dist/entity.js.map +0 -1
  303. package/dist/use-case.cjs +0 -96
  304. package/dist/use-case.cjs.map +0 -1
  305. package/dist/use-case.js +0 -91
  306. package/dist/use-case.js.map +0 -1
@@ -2,7 +2,8 @@ import { r as Result } from "./result.cjs";
2
2
  import { n as Outcome } from "./outcome.cjs";
3
3
 
4
4
  //#region src/core/policies/engines/v1/condition-types.d.ts
5
- type ConditionOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "isNull" | "isNotNull";
5
+ declare const CONDITION_OPS: readonly ["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "isNull", "isNotNull"];
6
+ type ConditionOp = (typeof CONDITION_OPS)[number];
6
7
  interface ConditionLeafNode {
7
8
  readonly field: string;
8
9
  readonly op: ConditionOp;
@@ -143,7 +144,39 @@ interface PolicyEvaluationCompletedEvent {
143
144
  readonly engineKind: "GATE" | "COMPUTE";
144
145
  readonly occurredAt: Date;
145
146
  }
146
- type PolicyEvent = ConditionEvalEvent | PolicyResolutionEvent | PolicyEvaluationFailedEvent | PolicyEvaluationCompletedEvent;
147
+ /**
148
+ * A resolved ABAC decision (both PERMIT and DENY). Emitted best-effort by the
149
+ * `AbacAuthorizer` so a host can build an authorization audit trail without an
150
+ * adapter of its own; silent by default like every other event. Types are kept
151
+ * self-contained (no import from `core/abac`) to avoid a config→abac cycle.
152
+ */
153
+ interface AbacDecisionEvent {
154
+ readonly kind: "abac-decision";
155
+ readonly level: "info";
156
+ readonly action: string;
157
+ readonly resource?: {
158
+ readonly type: string;
159
+ readonly id?: string;
160
+ };
161
+ readonly actorId: string;
162
+ readonly effect: "PERMIT" | "DENY";
163
+ /** Deciding rule id, or `"<default>"` / `"<default-deny>"` when the set's default decided. */
164
+ readonly decidingRuleId: string;
165
+ readonly decidingRuleVersion?: number;
166
+ readonly algorithm: string;
167
+ readonly occurredAt: Date;
168
+ }
169
+ type PolicyEvent = ConditionEvalEvent | PolicyResolutionEvent | PolicyEvaluationFailedEvent | PolicyEvaluationCompletedEvent | AbacDecisionEvent;
170
+ /**
171
+ * Sink for policy telemetry. The core never logs on its own — it hands typed
172
+ * events here and a host implementation decides what to do with them.
173
+ *
174
+ * Redaction is the host's responsibility: a `condition-eval` event carries the
175
+ * evaluated field path and value in `details` (e.g. `student.flags.*`), so in
176
+ * an ERP those payloads can contain PII. Sanitize before persisting or shipping
177
+ * events off-box; the core deliberately keeps no redaction seam so it stays
178
+ * pure and unopinionated about your logging stack.
179
+ */
147
180
  interface PolicyReporter {
148
181
  report(event: PolicyEvent): void;
149
182
  }
@@ -156,17 +189,31 @@ interface CoreConfigOptions {
156
189
  readonly observability?: CoreObservabilityConfig;
157
190
  }
158
191
  /**
159
- * Centraliza a configuracao pura do core sem depender de implementacoes
160
- * concretas de logging, tracing ou report.
192
+ * The core's config namespace. Today it holds a single section —
193
+ * `observability` whose whole job is to decide *where policy telemetry goes*
194
+ * while guaranteeing telemetry is best-effort (a throwing reporter can never
195
+ * abort a domain flow). App config (env, settings, feature flags) is
196
+ * deliberately absent for now: when the core needs it, it joins here as a
197
+ * sibling section rather than a new module — which is why this is `config`,
198
+ * not `observability`. It holds the active {@link PolicyReporter} (silent by
199
+ * default, so the core carries no logging dependency), bridges it to the
200
+ * engines' {@link ConditionEvaluatorReporter}, and offers `reportSafely` as
201
+ * the single guarded emit path shared with {@link PolicyService}.
161
202
  */
162
203
  declare class CoreConfig {
163
204
  #private;
164
205
  constructor(options?: CoreConfigOptions);
206
+ /**
207
+ * Swaps the active reporter. Pass `observability.reporter` to enable
208
+ * telemetry, or set it explicitly to `undefined` to go silent again.
209
+ * Omitting `observability` (or its `reporter` key) is a no-op.
210
+ */
165
211
  configure(options: CoreConfigOptions): this;
166
212
  reset(): this;
167
- getPolicyReporter(): PolicyReporter;
213
+ /** Emits a policy event through the active reporter, best-effort. */
214
+ reportSafely(event: PolicyEvent): void;
168
215
  getConditionEvaluationOptions(engineVersion: number): ConditionEvaluationOptions;
169
216
  }
170
217
  //#endregion
171
- export { ConditionLeafNode as A, GateTraceNodeSnapshot as C, VersionedGateEngine as D, PolicyViolation as E, GatePayload as O, GateTraceLeafSnapshot as S, PolicyContext as T, ConditionEvaluationReportTag as _, PolicyDecisionId as a, GateOutcomeData as b, TenantId as c, asSchoolId as d, asTenantId as f, ConditionEvaluationReportLevel as g, ConditionEvaluationReport as h, PolicyReporter as i, ConditionNode as j, GatePayloadV1 as k, asPolicyDecisionId as l, ConditionEvaluationOptions as m, CoreConfigOptions as n, PolicyDefinitionId as o, ConditionEvaluationCause as p, CoreObservabilityConfig as r, SchoolId as s, CoreConfig as t, asPolicyDefinitionId as u, ConditionEvaluatorReporter as v, GateViolationTrace as w, GateStatus as x, GateOutcome as y };
218
+ export { ConditionNode as A, GateViolationTrace as C, GatePayload as D, VersionedGateEngine as E, GatePayloadV1 as O, GateTraceNodeSnapshot as S, PolicyViolation as T, ConditionEvaluatorReporter as _, PolicyDefinitionId as a, GateStatus as b, asPolicyDecisionId as c, asTenantId as d, ConditionEvaluationCause as f, ConditionEvaluationReportTag as g, ConditionEvaluationReportLevel as h, PolicyDecisionId as i, ConditionLeafNode as k, asPolicyDefinitionId as l, ConditionEvaluationReport as m, CoreConfigOptions as n, SchoolId as o, ConditionEvaluationOptions as p, CoreObservabilityConfig as r, TenantId as s, CoreConfig as t, asSchoolId as u, GateOutcome as v, PolicyContext as w, GateTraceLeafSnapshot as x, GateOutcomeData as y };
172
219
  //# sourceMappingURL=core-config.d.cts.map
@@ -2,7 +2,8 @@ import { r as Result } from "./result.js";
2
2
  import { n as Outcome } from "./outcome.js";
3
3
 
4
4
  //#region src/core/policies/engines/v1/condition-types.d.ts
5
- type ConditionOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "isNull" | "isNotNull";
5
+ declare const CONDITION_OPS: readonly ["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "isNull", "isNotNull"];
6
+ type ConditionOp = (typeof CONDITION_OPS)[number];
6
7
  interface ConditionLeafNode {
7
8
  readonly field: string;
8
9
  readonly op: ConditionOp;
@@ -143,7 +144,39 @@ interface PolicyEvaluationCompletedEvent {
143
144
  readonly engineKind: "GATE" | "COMPUTE";
144
145
  readonly occurredAt: Date;
145
146
  }
146
- type PolicyEvent = ConditionEvalEvent | PolicyResolutionEvent | PolicyEvaluationFailedEvent | PolicyEvaluationCompletedEvent;
147
+ /**
148
+ * A resolved ABAC decision (both PERMIT and DENY). Emitted best-effort by the
149
+ * `AbacAuthorizer` so a host can build an authorization audit trail without an
150
+ * adapter of its own; silent by default like every other event. Types are kept
151
+ * self-contained (no import from `core/abac`) to avoid a config→abac cycle.
152
+ */
153
+ interface AbacDecisionEvent {
154
+ readonly kind: "abac-decision";
155
+ readonly level: "info";
156
+ readonly action: string;
157
+ readonly resource?: {
158
+ readonly type: string;
159
+ readonly id?: string;
160
+ };
161
+ readonly actorId: string;
162
+ readonly effect: "PERMIT" | "DENY";
163
+ /** Deciding rule id, or `"<default>"` / `"<default-deny>"` when the set's default decided. */
164
+ readonly decidingRuleId: string;
165
+ readonly decidingRuleVersion?: number;
166
+ readonly algorithm: string;
167
+ readonly occurredAt: Date;
168
+ }
169
+ type PolicyEvent = ConditionEvalEvent | PolicyResolutionEvent | PolicyEvaluationFailedEvent | PolicyEvaluationCompletedEvent | AbacDecisionEvent;
170
+ /**
171
+ * Sink for policy telemetry. The core never logs on its own — it hands typed
172
+ * events here and a host implementation decides what to do with them.
173
+ *
174
+ * Redaction is the host's responsibility: a `condition-eval` event carries the
175
+ * evaluated field path and value in `details` (e.g. `student.flags.*`), so in
176
+ * an ERP those payloads can contain PII. Sanitize before persisting or shipping
177
+ * events off-box; the core deliberately keeps no redaction seam so it stays
178
+ * pure and unopinionated about your logging stack.
179
+ */
147
180
  interface PolicyReporter {
148
181
  report(event: PolicyEvent): void;
149
182
  }
@@ -156,17 +189,31 @@ interface CoreConfigOptions {
156
189
  readonly observability?: CoreObservabilityConfig;
157
190
  }
158
191
  /**
159
- * Centraliza a configuracao pura do core sem depender de implementacoes
160
- * concretas de logging, tracing ou report.
192
+ * The core's config namespace. Today it holds a single section —
193
+ * `observability` whose whole job is to decide *where policy telemetry goes*
194
+ * while guaranteeing telemetry is best-effort (a throwing reporter can never
195
+ * abort a domain flow). App config (env, settings, feature flags) is
196
+ * deliberately absent for now: when the core needs it, it joins here as a
197
+ * sibling section rather than a new module — which is why this is `config`,
198
+ * not `observability`. It holds the active {@link PolicyReporter} (silent by
199
+ * default, so the core carries no logging dependency), bridges it to the
200
+ * engines' {@link ConditionEvaluatorReporter}, and offers `reportSafely` as
201
+ * the single guarded emit path shared with {@link PolicyService}.
161
202
  */
162
203
  declare class CoreConfig {
163
204
  #private;
164
205
  constructor(options?: CoreConfigOptions);
206
+ /**
207
+ * Swaps the active reporter. Pass `observability.reporter` to enable
208
+ * telemetry, or set it explicitly to `undefined` to go silent again.
209
+ * Omitting `observability` (or its `reporter` key) is a no-op.
210
+ */
165
211
  configure(options: CoreConfigOptions): this;
166
212
  reset(): this;
167
- getPolicyReporter(): PolicyReporter;
213
+ /** Emits a policy event through the active reporter, best-effort. */
214
+ reportSafely(event: PolicyEvent): void;
168
215
  getConditionEvaluationOptions(engineVersion: number): ConditionEvaluationOptions;
169
216
  }
170
217
  //#endregion
171
- export { ConditionLeafNode as A, GateTraceNodeSnapshot as C, VersionedGateEngine as D, PolicyViolation as E, GatePayload as O, GateTraceLeafSnapshot as S, PolicyContext as T, ConditionEvaluationReportTag as _, PolicyDecisionId as a, GateOutcomeData as b, TenantId as c, asSchoolId as d, asTenantId as f, ConditionEvaluationReportLevel as g, ConditionEvaluationReport as h, PolicyReporter as i, ConditionNode as j, GatePayloadV1 as k, asPolicyDecisionId as l, ConditionEvaluationOptions as m, CoreConfigOptions as n, PolicyDefinitionId as o, ConditionEvaluationCause as p, CoreObservabilityConfig as r, SchoolId as s, CoreConfig as t, asPolicyDefinitionId as u, ConditionEvaluatorReporter as v, GateViolationTrace as w, GateStatus as x, GateOutcome as y };
218
+ export { ConditionNode as A, GateViolationTrace as C, GatePayload as D, VersionedGateEngine as E, GatePayloadV1 as O, GateTraceNodeSnapshot as S, PolicyViolation as T, ConditionEvaluatorReporter as _, PolicyDefinitionId as a, GateStatus as b, asPolicyDecisionId as c, asTenantId as d, ConditionEvaluationCause as f, ConditionEvaluationReportTag as g, ConditionEvaluationReportLevel as h, PolicyDecisionId as i, ConditionLeafNode as k, asPolicyDefinitionId as l, ConditionEvaluationReport as m, CoreConfigOptions as n, SchoolId as o, ConditionEvaluationOptions as p, CoreObservabilityConfig as r, TenantId as s, CoreConfig as t, asSchoolId as u, GateOutcome as v, PolicyContext as w, GateTraceLeafSnapshot as x, GateOutcomeData as y };
172
219
  //# sourceMappingURL=core-config.d.ts.map
@@ -0,0 +1,14 @@
1
+ //#region \0@oxc-project+runtime@0.132.0/helpers/decorate.js
2
+ function __decorate(decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ }
8
+ //#endregion
9
+ Object.defineProperty(exports, "__decorate", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return __decorate;
13
+ }
14
+ });
@@ -0,0 +1,9 @@
1
+ //#region \0@oxc-project+runtime@0.132.0/helpers/decorate.js
2
+ function __decorate(decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ }
8
+ //#endregion
9
+ export { __decorate as t };
@@ -1,11 +1,105 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_entity = require("../entity.cjs");
2
+ const require_invariant_violation_exception = require("../invariant-violation-exception.cjs");
3
+ const require_temporal_guards = require("../temporal-guards.cjs");
4
+ const require_immutable = require("../immutable.cjs");
3
5
  const require_value_object = require("../value-object.cjs");
4
6
  const require_uuid_identifier = require("../uuid-identifier.cjs");
7
+ //#region src/core/domain/temporal/half-open-interval.ts
8
+ /**
9
+ * Shared core of the bitemporal primitives: a half-open interval
10
+ * `[start, end)` whose end, when present, must be strictly later than its
11
+ * start. `ValidTime` and `TransactionTime` are the same shape under different
12
+ * (deliberate) vocabularies — the invariant lives here once so the two files
13
+ * cannot drift apart.
14
+ *
15
+ * Internal to `domain/temporal`; not exported from the barrel.
16
+ */
17
+ function assertHalfOpenInterval(startLabel, start, endLabel, end) {
18
+ require_temporal_guards.assertValidDate(startLabel, start);
19
+ if (end === void 0) return;
20
+ require_temporal_guards.assertValidDate(endLabel, end);
21
+ if (end.getTime() <= start.getTime()) throw new require_invariant_violation_exception.InvariantViolationException(`${endLabel} must be later than ${startLabel}`);
22
+ }
23
+ //#endregion
24
+ //#region src/core/domain/temporal/transaction-time.ts
25
+ function assertTransactionTime(txTime, fieldName = "txTime") {
26
+ assertHalfOpenInterval(`${fieldName}.recordedAt`, txTime.recordedAt, `${fieldName}.supersededAt`, txTime.supersededAt);
27
+ }
28
+ function createTransactionTime(input) {
29
+ assertTransactionTime(input, "txTime");
30
+ if (input.supersededAt === void 0) return require_immutable.makeImmutable({ recordedAt: input.recordedAt });
31
+ return require_immutable.makeImmutable({
32
+ recordedAt: input.recordedAt,
33
+ supersededAt: input.supersededAt
34
+ });
35
+ }
36
+ //#endregion
37
+ //#region src/core/domain/temporal/valid-time.ts
38
+ function assertValidTime(validTime, fieldName = "validTime") {
39
+ assertHalfOpenInterval(`${fieldName}.from`, validTime.from, `${fieldName}.to`, validTime.to);
40
+ }
41
+ function createValidTime(input) {
42
+ assertValidTime(input, "validTime");
43
+ if (input.to === void 0) return require_immutable.makeImmutable({ from: input.from });
44
+ return require_immutable.makeImmutable({
45
+ from: input.from,
46
+ to: input.to
47
+ });
48
+ }
49
+ //#endregion
50
+ //#region src/core/domain/temporal/temporal-range.ts
51
+ /**
52
+ * Checks whether a temporal range is "open" (has no end date).
53
+ * Useful for identifying information that is still in effect / active.
54
+ */
55
+ function isOpen(range) {
56
+ assertValidTime(range, "range");
57
+ return range.to === void 0;
58
+ }
59
+ /**
60
+ * Checks whether a temporal range is "closed" (has a defined end date).
61
+ */
62
+ function isClosed(range) {
63
+ return !isOpen(range);
64
+ }
65
+ /**
66
+ * Checks whether a specific date is contained within the temporal range.
67
+ * The lower bound (`from`) is inclusive, while the upper bound (`to`) is exclusive.
68
+ */
69
+ function contains(range, date) {
70
+ assertValidTime(range, "range");
71
+ require_temporal_guards.assertValidDate("date", date);
72
+ const fromTime = range.from.getTime();
73
+ const toTime = range.to?.getTime() ?? Number.POSITIVE_INFINITY;
74
+ const targetTime = date.getTime();
75
+ return targetTime >= fromTime && targetTime < toTime;
76
+ }
77
+ /**
78
+ * Checks whether two temporal ranges overlap at any point.
79
+ * Useful for validating whether a new rule conflicts with an existing one.
80
+ */
81
+ function overlaps(left, right) {
82
+ assertValidTime(left, "left");
83
+ assertValidTime(right, "right");
84
+ const leftFrom = left.from.getTime();
85
+ const leftTo = left.to?.getTime() ?? Number.POSITIVE_INFINITY;
86
+ const rightFrom = right.from.getTime();
87
+ return leftFrom < (right.to?.getTime() ?? Number.POSITIVE_INFINITY) && rightFrom < leftTo;
88
+ }
89
+ //#endregion
90
+ //#region src/core/domain/temporal/temporal-snapshot.ts
91
+ function createTemporalSnapshot(input) {
92
+ return Object.freeze({
93
+ data: require_immutable.makeImmutable(input.data),
94
+ validTime: createValidTime(input.validTime),
95
+ txTime: createTransactionTime(input.txTime)
96
+ });
97
+ }
98
+ //#endregion
5
99
  Object.defineProperty(exports, "Entity", {
6
100
  enumerable: true,
7
101
  get: function() {
8
- return require_entity.Entity;
102
+ return require_uuid_identifier.Entity;
9
103
  }
10
104
  });
11
105
  exports.UuidIdentifier = require_uuid_identifier.UuidIdentifier;
@@ -15,3 +109,14 @@ Object.defineProperty(exports, "ValueObject", {
15
109
  return require_value_object.ValueObject;
16
110
  }
17
111
  });
112
+ exports.assertTransactionTime = assertTransactionTime;
113
+ exports.assertValidTime = assertValidTime;
114
+ exports.contains = contains;
115
+ exports.createTemporalSnapshot = createTemporalSnapshot;
116
+ exports.createTransactionTime = createTransactionTime;
117
+ exports.createValidTime = createValidTime;
118
+ exports.isClosed = isClosed;
119
+ exports.isOpen = isOpen;
120
+ exports.overlaps = overlaps;
121
+
122
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["InvariantViolationException","makeImmutable","makeImmutable","makeImmutable"],"sources":["../../src/core/domain/temporal/half-open-interval.ts","../../src/core/domain/temporal/transaction-time.ts","../../src/core/domain/temporal/valid-time.ts","../../src/core/domain/temporal/temporal-range.ts","../../src/core/domain/temporal/temporal-snapshot.ts"],"sourcesContent":["import { InvariantViolationException } from \"../../exceptions/invariant-violation-exception.js\";\nimport { assertValidDate } from \"../../shared/temporal-guards.js\";\n\n/**\n * Shared core of the bitemporal primitives: a half-open interval\n * `[start, end)` whose end, when present, must be strictly later than its\n * start. `ValidTime` and `TransactionTime` are the same shape under different\n * (deliberate) vocabularies — the invariant lives here once so the two files\n * cannot drift apart.\n *\n * Internal to `domain/temporal`; not exported from the barrel.\n */\nfunction assertHalfOpenInterval(\n startLabel: string,\n start: Date,\n endLabel: string,\n end: Date | undefined,\n): void {\n assertValidDate(startLabel, start);\n\n if (end === undefined) {\n return;\n }\n\n assertValidDate(endLabel, end);\n\n if (end.getTime() <= start.getTime()) {\n throw new InvariantViolationException(\n `${endLabel} must be later than ${startLabel}`,\n );\n }\n}\n\nexport { assertHalfOpenInterval };\n","import { makeImmutable } from \"../../shared/immutable.js\";\n\nimport { assertHalfOpenInterval } from \"./half-open-interval.js\";\n\n/**\n * Represents transaction time (Transaction Time).\n * Defines when the system learned about or recorded a piece of information.\n * Useful for auditing and reconstructing system state at a specific past moment.\n *\n * The window is half-open — `recordedAt` inclusive, `supersededAt` exclusive —\n * and strictly non-empty: `supersededAt` must be later than `recordedAt`, so a\n * record superseded in the same instant it was written is not representable.\n *\n * One caveat mirrors {@link ValueObject}: `createTransactionTime` clones the\n * input dates (no aliasing) but the inner `Date`s are NOT frozen —\n * `Object.freeze` cannot block `setTime`/`setFullYear`, so a caller can still\n * mutate `recordedAt` in place and corrupt the audit record after creation.\n * `readonly` only prevents reassignment. Treat the dates as read-only, or keep\n * instants as ISO/epoch in your own state when that guarantee matters.\n */\ninterface TransactionTime {\n /** When the information was first recorded in the system. */\n readonly recordedAt: Date;\n /** When this information was superseded or invalidated by a newer version. */\n readonly supersededAt?: Date;\n}\n\ntype CreateTransactionTimeInput = TransactionTime;\n\nfunction assertTransactionTime(\n txTime: TransactionTime,\n fieldName: string = \"txTime\",\n): void {\n assertHalfOpenInterval(\n `${fieldName}.recordedAt`,\n txTime.recordedAt,\n `${fieldName}.supersededAt`,\n txTime.supersededAt,\n );\n}\n\nfunction createTransactionTime(\n input: CreateTransactionTimeInput,\n): TransactionTime {\n assertTransactionTime(input, \"txTime\");\n\n if (input.supersededAt === undefined) {\n return makeImmutable({\n recordedAt: input.recordedAt,\n });\n }\n\n return makeImmutable({\n recordedAt: input.recordedAt,\n supersededAt: input.supersededAt,\n });\n}\n\nexport {\n assertTransactionTime,\n createTransactionTime,\n type CreateTransactionTimeInput,\n type TransactionTime,\n};\n","import { makeImmutable } from \"../../shared/immutable.js\";\n\nimport { assertHalfOpenInterval } from \"./half-open-interval.js\";\n\n/**\n * Represents business time (Valid Time).\n * Defines when a piece of information is considered true or in effect in the real world.\n *\n * The window is half-open — `from` inclusive, `to` exclusive — and strictly\n * non-empty: `to` must be later than `from`, so a zero-duration range `[t, t)`\n * is deliberately not representable. Model an instantaneous event as an open\n * range closed by the next fact, not as an empty window.\n *\n * One caveat mirrors {@link ValueObject}: `createValidTime` clones the input\n * dates (no aliasing) but the inner `Date`s are NOT frozen — `Object.freeze`\n * cannot block `setTime`/`setFullYear`, so a caller can still mutate `from`\n * in place and corrupt the range after creation. `readonly` only prevents\n * reassignment. Treat the dates as read-only, or keep instants as ISO/epoch in\n * your own state when that guarantee matters.\n */\ninterface ValidTime {\n /** Start of the validity window (inclusive). */\n readonly from: Date;\n /** End of the validity window (exclusive). When absent, the information is still in effect. */\n readonly to?: Date;\n}\n\ntype CreateValidTimeInput = ValidTime;\n\nfunction assertValidTime(\n validTime: ValidTime,\n fieldName: string = \"validTime\",\n): void {\n assertHalfOpenInterval(\n `${fieldName}.from`,\n validTime.from,\n `${fieldName}.to`,\n validTime.to,\n );\n}\n\nfunction createValidTime(input: CreateValidTimeInput): ValidTime {\n assertValidTime(input, \"validTime\");\n\n if (input.to === undefined) {\n return makeImmutable({\n from: input.from,\n });\n }\n\n return makeImmutable({\n from: input.from,\n to: input.to,\n });\n}\n\nexport {\n assertValidTime,\n createValidTime,\n type CreateValidTimeInput,\n type ValidTime,\n};\n","import { assertValidDate } from \"../../shared/temporal-guards.js\";\n\nimport { assertValidTime, type ValidTime } from \"./valid-time.js\";\n\n/**\n * Checks whether a temporal range is \"open\" (has no end date).\n * Useful for identifying information that is still in effect / active.\n */\nfunction isOpen(range: ValidTime): boolean {\n assertValidTime(range, \"range\");\n\n return range.to === undefined;\n}\n\n/**\n * Checks whether a temporal range is \"closed\" (has a defined end date).\n */\nfunction isClosed(range: ValidTime): boolean {\n return !isOpen(range);\n}\n\n/**\n * Checks whether a specific date is contained within the temporal range.\n * The lower bound (`from`) is inclusive, while the upper bound (`to`) is exclusive.\n */\nfunction contains(range: ValidTime, date: Date): boolean {\n assertValidTime(range, \"range\");\n assertValidDate(\"date\", date);\n\n const fromTime = range.from.getTime();\n const toTime = range.to?.getTime() ?? Number.POSITIVE_INFINITY;\n const targetTime = date.getTime();\n\n return targetTime >= fromTime && targetTime < toTime;\n}\n\n/**\n * Checks whether two temporal ranges overlap at any point.\n * Useful for validating whether a new rule conflicts with an existing one.\n */\nfunction overlaps(left: ValidTime, right: ValidTime): boolean {\n assertValidTime(left, \"left\");\n assertValidTime(right, \"right\");\n\n const leftFrom = left.from.getTime();\n const leftTo = left.to?.getTime() ?? Number.POSITIVE_INFINITY;\n const rightFrom = right.from.getTime();\n const rightTo = right.to?.getTime() ?? Number.POSITIVE_INFINITY;\n\n return leftFrom < rightTo && rightFrom < leftTo;\n}\n\nexport { contains, isClosed, isOpen, overlaps };\n","import { type DeepReadonly, makeImmutable } from \"../../shared/immutable.js\";\n\nimport {\n createTransactionTime,\n type CreateTransactionTimeInput,\n type TransactionTime,\n} from \"./transaction-time.js\";\nimport {\n createValidTime,\n type CreateValidTimeInput,\n type ValidTime,\n} from \"./valid-time.js\";\n\n/**\n * Pairs a domain datum with its time dimensions (Business and Transaction).\n * It is the representation of an entry in the append-only (historical) table.\n *\n * `data` must be plain, structured-cloneable state — the primitive shape of an\n * aggregate, not the aggregate itself. `createTemporalSnapshot` deep-clones it\n * via `structuredClone`: functions and symbols inside `data` throw an\n * `InvariantViolationException`, and class instances (a `ValueObject`, an\n * `Entity`) are NOT rejected — they are silently flattened to plain objects,\n * losing their prototype (and with it `equals`/`toPrimitive`). Project rich\n * objects down first, e.g. with `toPrimitive()`.\n */\ninterface TemporalSnapshot<T> {\n /** The data or state captured by the snapshot. */\n readonly data: DeepReadonly<T>;\n /** Period during which this datum was valid in the real world. */\n readonly validTime: ValidTime;\n /** Period during which this record was the state known to the system. */\n readonly txTime: TransactionTime;\n}\n\ninterface CreateTemporalSnapshotInput<T> {\n readonly data: T;\n readonly validTime: CreateValidTimeInput;\n readonly txTime: CreateTransactionTimeInput;\n}\n\nfunction createTemporalSnapshot<T>(\n input: CreateTemporalSnapshotInput<T>,\n): TemporalSnapshot<T> {\n // The time dimensions come out of their factories already cloned and\n // frozen; only `data` still needs the clone+freeze. Freezing the shell by\n // hand avoids a second structuredClone pass over the whole snapshot.\n return Object.freeze({\n data: makeImmutable(input.data),\n validTime: createValidTime(input.validTime),\n txTime: createTransactionTime(input.txTime),\n });\n}\n\nexport {\n createTemporalSnapshot,\n type CreateTemporalSnapshotInput,\n type TemporalSnapshot,\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAYA,SAAS,uBACL,YACA,OACA,UACA,KACI;CACJ,wBAAA,gBAAgB,YAAY,KAAK;CAEjC,IAAI,QAAQ,KAAA,GACR;CAGJ,wBAAA,gBAAgB,UAAU,GAAG;CAE7B,IAAI,IAAI,QAAQ,KAAK,MAAM,QAAQ,GAC/B,MAAM,IAAIA,sCAAAA,4BACN,GAAG,SAAS,sBAAsB,YACtC;AAER;;;ACFA,SAAS,sBACL,QACA,YAAoB,UAChB;CACJ,uBACI,GAAG,UAAU,cACb,OAAO,YACP,GAAG,UAAU,gBACb,OAAO,YACX;AACJ;AAEA,SAAS,sBACL,OACe;CACf,sBAAsB,OAAO,QAAQ;CAErC,IAAI,MAAM,iBAAiB,KAAA,GACvB,OAAOC,kBAAAA,cAAc,EACjB,YAAY,MAAM,WACtB,CAAC;CAGL,OAAOA,kBAAAA,cAAc;EACjB,YAAY,MAAM;EAClB,cAAc,MAAM;CACxB,CAAC;AACL;;;AC3BA,SAAS,gBACL,WACA,YAAoB,aAChB;CACJ,uBACI,GAAG,UAAU,QACb,UAAU,MACV,GAAG,UAAU,MACb,UAAU,EACd;AACJ;AAEA,SAAS,gBAAgB,OAAwC;CAC7D,gBAAgB,OAAO,WAAW;CAElC,IAAI,MAAM,OAAO,KAAA,GACb,OAAOC,kBAAAA,cAAc,EACjB,MAAM,MAAM,KAChB,CAAC;CAGL,OAAOA,kBAAAA,cAAc;EACjB,MAAM,MAAM;EACZ,IAAI,MAAM;CACd,CAAC;AACL;;;;;;;AC9CA,SAAS,OAAO,OAA2B;CACvC,gBAAgB,OAAO,OAAO;CAE9B,OAAO,MAAM,OAAO,KAAA;AACxB;;;;AAKA,SAAS,SAAS,OAA2B;CACzC,OAAO,CAAC,OAAO,KAAK;AACxB;;;;;AAMA,SAAS,SAAS,OAAkB,MAAqB;CACrD,gBAAgB,OAAO,OAAO;CAC9B,wBAAA,gBAAgB,QAAQ,IAAI;CAE5B,MAAM,WAAW,MAAM,KAAK,QAAQ;CACpC,MAAM,SAAS,MAAM,IAAI,QAAQ,KAAK,OAAO;CAC7C,MAAM,aAAa,KAAK,QAAQ;CAEhC,OAAO,cAAc,YAAY,aAAa;AAClD;;;;;AAMA,SAAS,SAAS,MAAiB,OAA2B;CAC1D,gBAAgB,MAAM,MAAM;CAC5B,gBAAgB,OAAO,OAAO;CAE9B,MAAM,WAAW,KAAK,KAAK,QAAQ;CACnC,MAAM,SAAS,KAAK,IAAI,QAAQ,KAAK,OAAO;CAC5C,MAAM,YAAY,MAAM,KAAK,QAAQ;CAGrC,OAAO,YAFS,MAAM,IAAI,QAAQ,KAAK,OAAO,sBAEjB,YAAY;AAC7C;;;ACVA,SAAS,uBACL,OACmB;CAInB,OAAO,OAAO,OAAO;EACjB,MAAMC,kBAAAA,cAAc,MAAM,IAAI;EAC9B,WAAW,gBAAgB,MAAM,SAAS;EAC1C,QAAQ,sBAAsB,MAAM,MAAM;CAC9C,CAAC;AACL"}
@@ -1,4 +1,28 @@
1
1
  import { t as DeepReadonly } from "../immutable.cjs";
2
2
  import { n as ValueObjectPluginContract, t as ValueObject } from "../value-object.cjs";
3
+ import { a as ValidTime, c as CreateTransactionTimeInput, d as createTransactionTime, i as CreateValidTimeInput, l as TransactionTime, n as TemporalSnapshot, o as assertValidTime, r as createTemporalSnapshot, s as createValidTime, t as CreateTemporalSnapshotInput, u as assertTransactionTime } from "../temporal-snapshot.cjs";
3
4
  import { n as Entity, r as EntityState, t as UuidIdentifier } from "../uuid-identifier.cjs";
4
- export { type DeepReadonly, Entity, type EntityState, UuidIdentifier, ValueObject, type ValueObjectPluginContract };
5
+
6
+ //#region src/core/domain/temporal/temporal-range.d.ts
7
+ /**
8
+ * Checks whether a temporal range is "open" (has no end date).
9
+ * Useful for identifying information that is still in effect / active.
10
+ */
11
+ declare function isOpen(range: ValidTime): boolean;
12
+ /**
13
+ * Checks whether a temporal range is "closed" (has a defined end date).
14
+ */
15
+ declare function isClosed(range: ValidTime): boolean;
16
+ /**
17
+ * Checks whether a specific date is contained within the temporal range.
18
+ * The lower bound (`from`) is inclusive, while the upper bound (`to`) is exclusive.
19
+ */
20
+ declare function contains(range: ValidTime, date: Date): boolean;
21
+ /**
22
+ * Checks whether two temporal ranges overlap at any point.
23
+ * Useful for validating whether a new rule conflicts with an existing one.
24
+ */
25
+ declare function overlaps(left: ValidTime, right: ValidTime): boolean;
26
+ //#endregion
27
+ export { CreateTemporalSnapshotInput, CreateTransactionTimeInput, CreateValidTimeInput, type DeepReadonly, Entity, type EntityState, TemporalSnapshot, TransactionTime, UuidIdentifier, ValidTime, ValueObject, type ValueObjectPluginContract, assertTransactionTime, assertValidTime, contains, createTemporalSnapshot, createTransactionTime, createValidTime, isClosed, isOpen, overlaps };
28
+ //# sourceMappingURL=index.d.cts.map
@@ -1,4 +1,28 @@
1
1
  import { t as DeepReadonly } from "../immutable.js";
2
2
  import { n as ValueObjectPluginContract, t as ValueObject } from "../value-object.js";
3
+ import { a as ValidTime, c as CreateTransactionTimeInput, d as createTransactionTime, i as CreateValidTimeInput, l as TransactionTime, n as TemporalSnapshot, o as assertValidTime, r as createTemporalSnapshot, s as createValidTime, t as CreateTemporalSnapshotInput, u as assertTransactionTime } from "../temporal-snapshot.js";
3
4
  import { n as Entity, r as EntityState, t as UuidIdentifier } from "../uuid-identifier.js";
4
- export { type DeepReadonly, Entity, type EntityState, UuidIdentifier, ValueObject, type ValueObjectPluginContract };
5
+
6
+ //#region src/core/domain/temporal/temporal-range.d.ts
7
+ /**
8
+ * Checks whether a temporal range is "open" (has no end date).
9
+ * Useful for identifying information that is still in effect / active.
10
+ */
11
+ declare function isOpen(range: ValidTime): boolean;
12
+ /**
13
+ * Checks whether a temporal range is "closed" (has a defined end date).
14
+ */
15
+ declare function isClosed(range: ValidTime): boolean;
16
+ /**
17
+ * Checks whether a specific date is contained within the temporal range.
18
+ * The lower bound (`from`) is inclusive, while the upper bound (`to`) is exclusive.
19
+ */
20
+ declare function contains(range: ValidTime, date: Date): boolean;
21
+ /**
22
+ * Checks whether two temporal ranges overlap at any point.
23
+ * Useful for validating whether a new rule conflicts with an existing one.
24
+ */
25
+ declare function overlaps(left: ValidTime, right: ValidTime): boolean;
26
+ //#endregion
27
+ export { CreateTemporalSnapshotInput, CreateTransactionTimeInput, CreateValidTimeInput, type DeepReadonly, Entity, type EntityState, TemporalSnapshot, TransactionTime, UuidIdentifier, ValidTime, ValueObject, type ValueObjectPluginContract, assertTransactionTime, assertValidTime, contains, createTemporalSnapshot, createTransactionTime, createValidTime, isClosed, isOpen, overlaps };
28
+ //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,100 @@
1
- import { t as Entity } from "../entity.js";
1
+ import { t as InvariantViolationException } from "../invariant-violation-exception.js";
2
+ import { t as assertValidDate } from "../temporal-guards.js";
3
+ import { n as makeImmutable } from "../immutable.js";
2
4
  import { t as ValueObject } from "../value-object.js";
3
- import { t as UuidIdentifier } from "../uuid-identifier.js";
4
- export { Entity, UuidIdentifier, ValueObject };
5
+ import { n as Entity, t as UuidIdentifier } from "../uuid-identifier.js";
6
+ //#region src/core/domain/temporal/half-open-interval.ts
7
+ /**
8
+ * Shared core of the bitemporal primitives: a half-open interval
9
+ * `[start, end)` whose end, when present, must be strictly later than its
10
+ * start. `ValidTime` and `TransactionTime` are the same shape under different
11
+ * (deliberate) vocabularies — the invariant lives here once so the two files
12
+ * cannot drift apart.
13
+ *
14
+ * Internal to `domain/temporal`; not exported from the barrel.
15
+ */
16
+ function assertHalfOpenInterval(startLabel, start, endLabel, end) {
17
+ assertValidDate(startLabel, start);
18
+ if (end === void 0) return;
19
+ assertValidDate(endLabel, end);
20
+ if (end.getTime() <= start.getTime()) throw new InvariantViolationException(`${endLabel} must be later than ${startLabel}`);
21
+ }
22
+ //#endregion
23
+ //#region src/core/domain/temporal/transaction-time.ts
24
+ function assertTransactionTime(txTime, fieldName = "txTime") {
25
+ assertHalfOpenInterval(`${fieldName}.recordedAt`, txTime.recordedAt, `${fieldName}.supersededAt`, txTime.supersededAt);
26
+ }
27
+ function createTransactionTime(input) {
28
+ assertTransactionTime(input, "txTime");
29
+ if (input.supersededAt === void 0) return makeImmutable({ recordedAt: input.recordedAt });
30
+ return makeImmutable({
31
+ recordedAt: input.recordedAt,
32
+ supersededAt: input.supersededAt
33
+ });
34
+ }
35
+ //#endregion
36
+ //#region src/core/domain/temporal/valid-time.ts
37
+ function assertValidTime(validTime, fieldName = "validTime") {
38
+ assertHalfOpenInterval(`${fieldName}.from`, validTime.from, `${fieldName}.to`, validTime.to);
39
+ }
40
+ function createValidTime(input) {
41
+ assertValidTime(input, "validTime");
42
+ if (input.to === void 0) return makeImmutable({ from: input.from });
43
+ return makeImmutable({
44
+ from: input.from,
45
+ to: input.to
46
+ });
47
+ }
48
+ //#endregion
49
+ //#region src/core/domain/temporal/temporal-range.ts
50
+ /**
51
+ * Checks whether a temporal range is "open" (has no end date).
52
+ * Useful for identifying information that is still in effect / active.
53
+ */
54
+ function isOpen(range) {
55
+ assertValidTime(range, "range");
56
+ return range.to === void 0;
57
+ }
58
+ /**
59
+ * Checks whether a temporal range is "closed" (has a defined end date).
60
+ */
61
+ function isClosed(range) {
62
+ return !isOpen(range);
63
+ }
64
+ /**
65
+ * Checks whether a specific date is contained within the temporal range.
66
+ * The lower bound (`from`) is inclusive, while the upper bound (`to`) is exclusive.
67
+ */
68
+ function contains(range, date) {
69
+ assertValidTime(range, "range");
70
+ assertValidDate("date", date);
71
+ const fromTime = range.from.getTime();
72
+ const toTime = range.to?.getTime() ?? Number.POSITIVE_INFINITY;
73
+ const targetTime = date.getTime();
74
+ return targetTime >= fromTime && targetTime < toTime;
75
+ }
76
+ /**
77
+ * Checks whether two temporal ranges overlap at any point.
78
+ * Useful for validating whether a new rule conflicts with an existing one.
79
+ */
80
+ function overlaps(left, right) {
81
+ assertValidTime(left, "left");
82
+ assertValidTime(right, "right");
83
+ const leftFrom = left.from.getTime();
84
+ const leftTo = left.to?.getTime() ?? Number.POSITIVE_INFINITY;
85
+ const rightFrom = right.from.getTime();
86
+ return leftFrom < (right.to?.getTime() ?? Number.POSITIVE_INFINITY) && rightFrom < leftTo;
87
+ }
88
+ //#endregion
89
+ //#region src/core/domain/temporal/temporal-snapshot.ts
90
+ function createTemporalSnapshot(input) {
91
+ return Object.freeze({
92
+ data: makeImmutable(input.data),
93
+ validTime: createValidTime(input.validTime),
94
+ txTime: createTransactionTime(input.txTime)
95
+ });
96
+ }
97
+ //#endregion
98
+ export { Entity, UuidIdentifier, ValueObject, assertTransactionTime, assertValidTime, contains, createTemporalSnapshot, createTransactionTime, createValidTime, isClosed, isOpen, overlaps };
99
+
100
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/core/domain/temporal/half-open-interval.ts","../../src/core/domain/temporal/transaction-time.ts","../../src/core/domain/temporal/valid-time.ts","../../src/core/domain/temporal/temporal-range.ts","../../src/core/domain/temporal/temporal-snapshot.ts"],"sourcesContent":["import { InvariantViolationException } from \"../../exceptions/invariant-violation-exception.js\";\nimport { assertValidDate } from \"../../shared/temporal-guards.js\";\n\n/**\n * Shared core of the bitemporal primitives: a half-open interval\n * `[start, end)` whose end, when present, must be strictly later than its\n * start. `ValidTime` and `TransactionTime` are the same shape under different\n * (deliberate) vocabularies — the invariant lives here once so the two files\n * cannot drift apart.\n *\n * Internal to `domain/temporal`; not exported from the barrel.\n */\nfunction assertHalfOpenInterval(\n startLabel: string,\n start: Date,\n endLabel: string,\n end: Date | undefined,\n): void {\n assertValidDate(startLabel, start);\n\n if (end === undefined) {\n return;\n }\n\n assertValidDate(endLabel, end);\n\n if (end.getTime() <= start.getTime()) {\n throw new InvariantViolationException(\n `${endLabel} must be later than ${startLabel}`,\n );\n }\n}\n\nexport { assertHalfOpenInterval };\n","import { makeImmutable } from \"../../shared/immutable.js\";\n\nimport { assertHalfOpenInterval } from \"./half-open-interval.js\";\n\n/**\n * Represents transaction time (Transaction Time).\n * Defines when the system learned about or recorded a piece of information.\n * Useful for auditing and reconstructing system state at a specific past moment.\n *\n * The window is half-open — `recordedAt` inclusive, `supersededAt` exclusive —\n * and strictly non-empty: `supersededAt` must be later than `recordedAt`, so a\n * record superseded in the same instant it was written is not representable.\n *\n * One caveat mirrors {@link ValueObject}: `createTransactionTime` clones the\n * input dates (no aliasing) but the inner `Date`s are NOT frozen —\n * `Object.freeze` cannot block `setTime`/`setFullYear`, so a caller can still\n * mutate `recordedAt` in place and corrupt the audit record after creation.\n * `readonly` only prevents reassignment. Treat the dates as read-only, or keep\n * instants as ISO/epoch in your own state when that guarantee matters.\n */\ninterface TransactionTime {\n /** When the information was first recorded in the system. */\n readonly recordedAt: Date;\n /** When this information was superseded or invalidated by a newer version. */\n readonly supersededAt?: Date;\n}\n\ntype CreateTransactionTimeInput = TransactionTime;\n\nfunction assertTransactionTime(\n txTime: TransactionTime,\n fieldName: string = \"txTime\",\n): void {\n assertHalfOpenInterval(\n `${fieldName}.recordedAt`,\n txTime.recordedAt,\n `${fieldName}.supersededAt`,\n txTime.supersededAt,\n );\n}\n\nfunction createTransactionTime(\n input: CreateTransactionTimeInput,\n): TransactionTime {\n assertTransactionTime(input, \"txTime\");\n\n if (input.supersededAt === undefined) {\n return makeImmutable({\n recordedAt: input.recordedAt,\n });\n }\n\n return makeImmutable({\n recordedAt: input.recordedAt,\n supersededAt: input.supersededAt,\n });\n}\n\nexport {\n assertTransactionTime,\n createTransactionTime,\n type CreateTransactionTimeInput,\n type TransactionTime,\n};\n","import { makeImmutable } from \"../../shared/immutable.js\";\n\nimport { assertHalfOpenInterval } from \"./half-open-interval.js\";\n\n/**\n * Represents business time (Valid Time).\n * Defines when a piece of information is considered true or in effect in the real world.\n *\n * The window is half-open — `from` inclusive, `to` exclusive — and strictly\n * non-empty: `to` must be later than `from`, so a zero-duration range `[t, t)`\n * is deliberately not representable. Model an instantaneous event as an open\n * range closed by the next fact, not as an empty window.\n *\n * One caveat mirrors {@link ValueObject}: `createValidTime` clones the input\n * dates (no aliasing) but the inner `Date`s are NOT frozen — `Object.freeze`\n * cannot block `setTime`/`setFullYear`, so a caller can still mutate `from`\n * in place and corrupt the range after creation. `readonly` only prevents\n * reassignment. Treat the dates as read-only, or keep instants as ISO/epoch in\n * your own state when that guarantee matters.\n */\ninterface ValidTime {\n /** Start of the validity window (inclusive). */\n readonly from: Date;\n /** End of the validity window (exclusive). When absent, the information is still in effect. */\n readonly to?: Date;\n}\n\ntype CreateValidTimeInput = ValidTime;\n\nfunction assertValidTime(\n validTime: ValidTime,\n fieldName: string = \"validTime\",\n): void {\n assertHalfOpenInterval(\n `${fieldName}.from`,\n validTime.from,\n `${fieldName}.to`,\n validTime.to,\n );\n}\n\nfunction createValidTime(input: CreateValidTimeInput): ValidTime {\n assertValidTime(input, \"validTime\");\n\n if (input.to === undefined) {\n return makeImmutable({\n from: input.from,\n });\n }\n\n return makeImmutable({\n from: input.from,\n to: input.to,\n });\n}\n\nexport {\n assertValidTime,\n createValidTime,\n type CreateValidTimeInput,\n type ValidTime,\n};\n","import { assertValidDate } from \"../../shared/temporal-guards.js\";\n\nimport { assertValidTime, type ValidTime } from \"./valid-time.js\";\n\n/**\n * Checks whether a temporal range is \"open\" (has no end date).\n * Useful for identifying information that is still in effect / active.\n */\nfunction isOpen(range: ValidTime): boolean {\n assertValidTime(range, \"range\");\n\n return range.to === undefined;\n}\n\n/**\n * Checks whether a temporal range is \"closed\" (has a defined end date).\n */\nfunction isClosed(range: ValidTime): boolean {\n return !isOpen(range);\n}\n\n/**\n * Checks whether a specific date is contained within the temporal range.\n * The lower bound (`from`) is inclusive, while the upper bound (`to`) is exclusive.\n */\nfunction contains(range: ValidTime, date: Date): boolean {\n assertValidTime(range, \"range\");\n assertValidDate(\"date\", date);\n\n const fromTime = range.from.getTime();\n const toTime = range.to?.getTime() ?? Number.POSITIVE_INFINITY;\n const targetTime = date.getTime();\n\n return targetTime >= fromTime && targetTime < toTime;\n}\n\n/**\n * Checks whether two temporal ranges overlap at any point.\n * Useful for validating whether a new rule conflicts with an existing one.\n */\nfunction overlaps(left: ValidTime, right: ValidTime): boolean {\n assertValidTime(left, \"left\");\n assertValidTime(right, \"right\");\n\n const leftFrom = left.from.getTime();\n const leftTo = left.to?.getTime() ?? Number.POSITIVE_INFINITY;\n const rightFrom = right.from.getTime();\n const rightTo = right.to?.getTime() ?? Number.POSITIVE_INFINITY;\n\n return leftFrom < rightTo && rightFrom < leftTo;\n}\n\nexport { contains, isClosed, isOpen, overlaps };\n","import { type DeepReadonly, makeImmutable } from \"../../shared/immutable.js\";\n\nimport {\n createTransactionTime,\n type CreateTransactionTimeInput,\n type TransactionTime,\n} from \"./transaction-time.js\";\nimport {\n createValidTime,\n type CreateValidTimeInput,\n type ValidTime,\n} from \"./valid-time.js\";\n\n/**\n * Pairs a domain datum with its time dimensions (Business and Transaction).\n * It is the representation of an entry in the append-only (historical) table.\n *\n * `data` must be plain, structured-cloneable state — the primitive shape of an\n * aggregate, not the aggregate itself. `createTemporalSnapshot` deep-clones it\n * via `structuredClone`: functions and symbols inside `data` throw an\n * `InvariantViolationException`, and class instances (a `ValueObject`, an\n * `Entity`) are NOT rejected — they are silently flattened to plain objects,\n * losing their prototype (and with it `equals`/`toPrimitive`). Project rich\n * objects down first, e.g. with `toPrimitive()`.\n */\ninterface TemporalSnapshot<T> {\n /** The data or state captured by the snapshot. */\n readonly data: DeepReadonly<T>;\n /** Period during which this datum was valid in the real world. */\n readonly validTime: ValidTime;\n /** Period during which this record was the state known to the system. */\n readonly txTime: TransactionTime;\n}\n\ninterface CreateTemporalSnapshotInput<T> {\n readonly data: T;\n readonly validTime: CreateValidTimeInput;\n readonly txTime: CreateTransactionTimeInput;\n}\n\nfunction createTemporalSnapshot<T>(\n input: CreateTemporalSnapshotInput<T>,\n): TemporalSnapshot<T> {\n // The time dimensions come out of their factories already cloned and\n // frozen; only `data` still needs the clone+freeze. Freezing the shell by\n // hand avoids a second structuredClone pass over the whole snapshot.\n return Object.freeze({\n data: makeImmutable(input.data),\n validTime: createValidTime(input.validTime),\n txTime: createTransactionTime(input.txTime),\n });\n}\n\nexport {\n createTemporalSnapshot,\n type CreateTemporalSnapshotInput,\n type TemporalSnapshot,\n};\n"],"mappings":";;;;;;;;;;;;;;;AAYA,SAAS,uBACL,YACA,OACA,UACA,KACI;CACJ,gBAAgB,YAAY,KAAK;CAEjC,IAAI,QAAQ,KAAA,GACR;CAGJ,gBAAgB,UAAU,GAAG;CAE7B,IAAI,IAAI,QAAQ,KAAK,MAAM,QAAQ,GAC/B,MAAM,IAAI,4BACN,GAAG,SAAS,sBAAsB,YACtC;AAER;;;ACFA,SAAS,sBACL,QACA,YAAoB,UAChB;CACJ,uBACI,GAAG,UAAU,cACb,OAAO,YACP,GAAG,UAAU,gBACb,OAAO,YACX;AACJ;AAEA,SAAS,sBACL,OACe;CACf,sBAAsB,OAAO,QAAQ;CAErC,IAAI,MAAM,iBAAiB,KAAA,GACvB,OAAO,cAAc,EACjB,YAAY,MAAM,WACtB,CAAC;CAGL,OAAO,cAAc;EACjB,YAAY,MAAM;EAClB,cAAc,MAAM;CACxB,CAAC;AACL;;;AC3BA,SAAS,gBACL,WACA,YAAoB,aAChB;CACJ,uBACI,GAAG,UAAU,QACb,UAAU,MACV,GAAG,UAAU,MACb,UAAU,EACd;AACJ;AAEA,SAAS,gBAAgB,OAAwC;CAC7D,gBAAgB,OAAO,WAAW;CAElC,IAAI,MAAM,OAAO,KAAA,GACb,OAAO,cAAc,EACjB,MAAM,MAAM,KAChB,CAAC;CAGL,OAAO,cAAc;EACjB,MAAM,MAAM;EACZ,IAAI,MAAM;CACd,CAAC;AACL;;;;;;;AC9CA,SAAS,OAAO,OAA2B;CACvC,gBAAgB,OAAO,OAAO;CAE9B,OAAO,MAAM,OAAO,KAAA;AACxB;;;;AAKA,SAAS,SAAS,OAA2B;CACzC,OAAO,CAAC,OAAO,KAAK;AACxB;;;;;AAMA,SAAS,SAAS,OAAkB,MAAqB;CACrD,gBAAgB,OAAO,OAAO;CAC9B,gBAAgB,QAAQ,IAAI;CAE5B,MAAM,WAAW,MAAM,KAAK,QAAQ;CACpC,MAAM,SAAS,MAAM,IAAI,QAAQ,KAAK,OAAO;CAC7C,MAAM,aAAa,KAAK,QAAQ;CAEhC,OAAO,cAAc,YAAY,aAAa;AAClD;;;;;AAMA,SAAS,SAAS,MAAiB,OAA2B;CAC1D,gBAAgB,MAAM,MAAM;CAC5B,gBAAgB,OAAO,OAAO;CAE9B,MAAM,WAAW,KAAK,KAAK,QAAQ;CACnC,MAAM,SAAS,KAAK,IAAI,QAAQ,KAAK,OAAO;CAC5C,MAAM,YAAY,MAAM,KAAK,QAAQ;CAGrC,OAAO,YAFS,MAAM,IAAI,QAAQ,KAAK,OAAO,sBAEjB,YAAY;AAC7C;;;ACVA,SAAS,uBACL,OACmB;CAInB,OAAO,OAAO,OAAO;EACjB,MAAM,cAAc,MAAM,IAAI;EAC9B,WAAW,gBAAgB,MAAM,SAAS;EAC1C,QAAQ,sBAAsB,MAAM,MAAM;CAC9C,CAAC;AACL"}
@@ -1,17 +1,21 @@
1
- const require_use_case = require("./use-case.cjs");
2
- const require_entity = require("./entity.cjs");
3
- const require_value_object = require("./value-object.cjs");
1
+ const require_immutable = require("./immutable.cjs");
2
+ const require_aggregate_version = require("./aggregate-version.cjs");
4
3
  //#region src/core/versioning/domain-event-contracts.ts
5
4
  function buildDomainEventContractVersions(selection) {
6
5
  const contractVersions = {};
7
- if (selection.entity) contractVersions.entity_contract = require_entity.Entity.CONTRACT_VERSION;
8
- if (selection.valueObject) contractVersions.value_object_contract = require_value_object.ValueObject.CONTRACT_VERSION;
9
- if (selection.useCase) contractVersions.use_case_contract = require_use_case.UseCase.CONTRACT_VERSION;
6
+ if (selection.entity) contractVersions.entity_contract = selection.entity.CONTRACT_VERSION;
7
+ if (selection.valueObject) contractVersions.value_object_contract = selection.valueObject.CONTRACT_VERSION;
8
+ if (selection.useCase) contractVersions.use_case_contract = selection.useCase.CONTRACT_VERSION;
10
9
  return Object.freeze(contractVersions);
11
10
  }
11
+ /**
12
+ * Builds a frozen domain-event envelope. The whole envelope is deep-frozen,
13
+ * so the `payload` handed in becomes immutable too — an event is an immutable
14
+ * fact, and the caller must not mutate the payload after wrapping it.
15
+ */
12
16
  function createDomainEventEnvelope(input) {
13
- require_entity.assertValidAggregateVersion(input.aggregateVersion);
14
- return Object.freeze({
17
+ require_aggregate_version.assertValidAggregateVersion(input.aggregateVersion);
18
+ return require_immutable.deepFreeze({
15
19
  aggregate_version: input.aggregateVersion,
16
20
  payload: input.payload,
17
21
  ...buildDomainEventContractVersions(input.contracts)
@@ -1 +1 @@
1
- {"version":3,"file":"domain-event-contracts.cjs","names":["Entity","ValueObject","UseCase"],"sources":["../src/core/versioning/domain-event-contracts.ts"],"sourcesContent":["import { UseCase } from \"../application/use-case.js\";\nimport { Entity } from \"../domain/entity.js\";\nimport { ValueObject } from \"../domain/value-object.js\";\nimport { assertValidAggregateVersion } from \"../shared/aggregate-version.js\";\nimport { type ContractVersion } from \"./version.js\";\n\ninterface DomainEventContractSelection {\n readonly entity?: boolean;\n readonly valueObject?: boolean;\n readonly useCase?: boolean;\n}\n\ninterface DomainEventContractVersions {\n readonly entity_contract?: ContractVersion;\n readonly value_object_contract?: ContractVersion;\n readonly use_case_contract?: ContractVersion;\n}\n\ninterface CreateDomainEventEnvelopeInput<TPayload> {\n readonly aggregateVersion: number;\n readonly payload: TPayload;\n readonly contracts: DomainEventContractSelection;\n}\n\ninterface DomainEventEnvelope<TPayload> extends DomainEventContractVersions {\n readonly aggregate_version: number;\n readonly payload: TPayload;\n}\n\nfunction buildDomainEventContractVersions(\n selection: DomainEventContractSelection,\n): DomainEventContractVersions {\n const contractVersions: {\n entity_contract?: ContractVersion;\n value_object_contract?: ContractVersion;\n use_case_contract?: ContractVersion;\n } = {};\n\n if (selection.entity) {\n contractVersions.entity_contract = Entity.CONTRACT_VERSION;\n }\n\n if (selection.valueObject) {\n contractVersions.value_object_contract = ValueObject.CONTRACT_VERSION;\n }\n\n if (selection.useCase) {\n contractVersions.use_case_contract = UseCase.CONTRACT_VERSION;\n }\n\n return Object.freeze(contractVersions);\n}\n\nfunction createDomainEventEnvelope<TPayload>(\n input: CreateDomainEventEnvelopeInput<TPayload>,\n): DomainEventEnvelope<TPayload> {\n assertValidAggregateVersion(input.aggregateVersion);\n\n return Object.freeze({\n aggregate_version: input.aggregateVersion,\n payload: input.payload,\n ...buildDomainEventContractVersions(input.contracts),\n });\n}\n\nexport {\n buildDomainEventContractVersions,\n createDomainEventEnvelope,\n type CreateDomainEventEnvelopeInput,\n type DomainEventContractSelection,\n type DomainEventContractVersions,\n type DomainEventEnvelope,\n};\n"],"mappings":";;;;AA6BA,SAAS,iCACL,WAC2B;CAC3B,MAAM,mBAIF,CAAC;CAEL,IAAI,UAAU,QACV,iBAAiB,kBAAkBA,eAAAA,OAAO;CAG9C,IAAI,UAAU,aACV,iBAAiB,wBAAwBC,qBAAAA,YAAY;CAGzD,IAAI,UAAU,SACV,iBAAiB,oBAAoBC,iBAAAA,QAAQ;CAGjD,OAAO,OAAO,OAAO,gBAAgB;AACzC;AAEA,SAAS,0BACL,OAC6B;CAC7B,eAAA,4BAA4B,MAAM,gBAAgB;CAElD,OAAO,OAAO,OAAO;EACjB,mBAAmB,MAAM;EACzB,SAAS,MAAM;EACf,GAAG,iCAAiC,MAAM,SAAS;CACvD,CAAC;AACL"}
1
+ {"version":3,"file":"domain-event-contracts.cjs","names":["deepFreeze"],"sources":["../src/core/versioning/domain-event-contracts.ts"],"sourcesContent":["import { assertValidAggregateVersion } from \"../shared/aggregate-version.js\";\nimport { deepFreeze } from \"../shared/immutable.js\";\nimport { type ContractVersion } from \"./version.js\";\n\n/** Anything carrying a `CONTRACT_VERSION` — a class decorated with `@version`. */\ninterface ContractVersioned {\n readonly CONTRACT_VERSION: ContractVersion;\n}\n\n/**\n * The classes whose contract version should be recorded on the envelope.\n *\n * Pass the **concrete** aggregate/value-object/use-case class (not the base),\n * so the envelope records the version the caller actually annotated with\n * `@version`. A base class handed here would report only the framework's\n * version, not the concrete shape that produced the event.\n */\ninterface DomainEventContractSelection {\n readonly entity?: ContractVersioned;\n readonly valueObject?: ContractVersioned;\n readonly useCase?: ContractVersioned;\n}\n\n// Wire-format shape: `snake_case` keys, deliberately distinct from the\n// `camelCase` builder input above — these travel in the serialized event.\ninterface DomainEventContractVersions {\n readonly entity_contract?: ContractVersion;\n readonly value_object_contract?: ContractVersion;\n readonly use_case_contract?: ContractVersion;\n}\n\ntype MutableContractVersions = {\n -readonly [K in keyof DomainEventContractVersions]: DomainEventContractVersions[K];\n};\n\ninterface CreateDomainEventEnvelopeInput<TPayload> {\n readonly aggregateVersion: number;\n readonly payload: TPayload;\n readonly contracts: DomainEventContractSelection;\n}\n\n/**\n * A deliberately minimal domain-event envelope: it carries only the aggregate\n * version and the structural contract versions needed for state/event\n * migration. It intentionally omits `eventId`, `eventType`, `occurredAt` and\n * correlation ids — those require a clock/id source and belong to the\n * consumer's event infrastructure. Treat this as a versioning core to extend,\n * not a complete event record.\n */\ninterface DomainEventEnvelope<TPayload> extends DomainEventContractVersions {\n readonly aggregate_version: number;\n readonly payload: TPayload;\n}\n\nfunction buildDomainEventContractVersions(\n selection: DomainEventContractSelection,\n): DomainEventContractVersions {\n const contractVersions: MutableContractVersions = {};\n\n if (selection.entity) {\n contractVersions.entity_contract = selection.entity.CONTRACT_VERSION;\n }\n\n if (selection.valueObject) {\n contractVersions.value_object_contract =\n selection.valueObject.CONTRACT_VERSION;\n }\n\n if (selection.useCase) {\n contractVersions.use_case_contract = selection.useCase.CONTRACT_VERSION;\n }\n\n return Object.freeze(contractVersions);\n}\n\n/**\n * Builds a frozen domain-event envelope. The whole envelope is deep-frozen,\n * so the `payload` handed in becomes immutable too — an event is an immutable\n * fact, and the caller must not mutate the payload after wrapping it.\n */\nfunction createDomainEventEnvelope<TPayload>(\n input: CreateDomainEventEnvelopeInput<TPayload>,\n): DomainEventEnvelope<TPayload> {\n assertValidAggregateVersion(input.aggregateVersion);\n\n return deepFreeze({\n aggregate_version: input.aggregateVersion,\n payload: input.payload,\n ...buildDomainEventContractVersions(input.contracts),\n });\n}\n\nexport {\n buildDomainEventContractVersions,\n createDomainEventEnvelope,\n type ContractVersioned,\n type CreateDomainEventEnvelopeInput,\n type DomainEventContractSelection,\n type DomainEventContractVersions,\n type DomainEventEnvelope,\n};\n"],"mappings":";;;AAsDA,SAAS,iCACL,WAC2B;CAC3B,MAAM,mBAA4C,CAAC;CAEnD,IAAI,UAAU,QACV,iBAAiB,kBAAkB,UAAU,OAAO;CAGxD,IAAI,UAAU,aACV,iBAAiB,wBACb,UAAU,YAAY;CAG9B,IAAI,UAAU,SACV,iBAAiB,oBAAoB,UAAU,QAAQ;CAG3D,OAAO,OAAO,OAAO,gBAAgB;AACzC;;;;;;AAOA,SAAS,0BACL,OAC6B;CAC7B,0BAAA,4BAA4B,MAAM,gBAAgB;CAElD,OAAOA,kBAAAA,WAAW;EACd,mBAAmB,MAAM;EACzB,SAAS,MAAM;EACf,GAAG,iCAAiC,MAAM,SAAS;CACvD,CAAC;AACL"}