@cullet/erp-core 1.1.0 → 1.3.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 (196) hide show
  1. package/KIT_CONTEXT.md +1 -67
  2. package/dist/app-error.d.cts +108 -0
  3. package/dist/application/index.cjs +26 -0
  4. package/dist/application/index.d.cts +2 -0
  5. package/dist/application/index.d.ts +1 -1
  6. package/dist/application/index.js +2 -1
  7. package/dist/domain/index.cjs +16 -0
  8. package/dist/domain/index.d.cts +3 -0
  9. package/dist/domain/index.d.ts +3 -0
  10. package/dist/domain/index.js +3 -0
  11. package/dist/domain-event-contracts.cjs +33 -0
  12. package/dist/domain-event-contracts.cjs.map +1 -0
  13. package/dist/domain-event-contracts.d.cts +27 -0
  14. package/dist/domain-event-contracts.d.ts +27 -0
  15. package/dist/domain-event-contracts.js +22 -0
  16. package/dist/domain-event-contracts.js.map +1 -0
  17. package/dist/domain-exception.cjs +17 -0
  18. package/dist/domain-exception.cjs.map +1 -0
  19. package/dist/domain-exception.d.cts +7 -0
  20. package/dist/domain-exception.d.ts +7 -0
  21. package/dist/domain-exception.js +12 -0
  22. package/dist/domain-exception.js.map +1 -0
  23. package/dist/errors/index.cjs +41 -0
  24. package/dist/errors/index.d.cts +3 -0
  25. package/dist/errors/index.js +1 -1
  26. package/dist/exceptions/index.cjs +17 -0
  27. package/dist/exceptions/index.d.cts +5 -0
  28. package/dist/exceptions/index.d.ts +5 -0
  29. package/dist/exceptions/index.js +7 -0
  30. package/dist/exceptions/validation-field.cjs +3 -0
  31. package/dist/exceptions/validation-field.d.cts +2 -0
  32. package/dist/gate-engine-registry.cjs +308 -0
  33. package/dist/gate-engine-registry.cjs.map +1 -0
  34. package/dist/gate-engine-registry.d.cts +81 -0
  35. package/dist/gate-engine-registry.d.ts +2 -1
  36. package/dist/gate-engine-registry.js +2 -1
  37. package/dist/gate-engine-registry.js.map +1 -1
  38. package/dist/gate-types.d.cts +171 -0
  39. package/dist/gate-types.d.ts +3 -139
  40. package/dist/gate-v1-payload.schema.cjs +638 -0
  41. package/dist/gate-v1-payload.schema.cjs.map +1 -0
  42. package/dist/gate-v1-payload.schema.js +2 -116
  43. package/dist/gate-v1-payload.schema.js.map +1 -1
  44. package/dist/hashing.cjs +66 -0
  45. package/dist/hashing.cjs.map +1 -0
  46. package/dist/immutable.cjs +77 -0
  47. package/dist/immutable.cjs.map +1 -0
  48. package/dist/immutable.d.cts +6 -0
  49. package/dist/immutable.d.ts +6 -0
  50. package/dist/immutable.js +54 -0
  51. package/dist/immutable.js.map +1 -0
  52. package/dist/index.cjs +163 -0
  53. package/dist/index.cjs.map +1 -0
  54. package/dist/index.d.cts +30 -0
  55. package/dist/index.d.ts +15 -160
  56. package/dist/index.js +19 -176
  57. package/dist/index.js.map +1 -1
  58. package/dist/invalid-state-transition-exception.cjs +47 -0
  59. package/dist/invalid-state-transition-exception.cjs.map +1 -0
  60. package/dist/invalid-state-transition-exception.js +30 -0
  61. package/dist/invalid-state-transition-exception.js.map +1 -0
  62. package/dist/invariant-violation-exception.cjs +16 -0
  63. package/dist/invariant-violation-exception.cjs.map +1 -0
  64. package/dist/invariant-violation-exception.js +11 -0
  65. package/dist/invariant-violation-exception.js.map +1 -0
  66. package/dist/not-found-error.cjs +65 -0
  67. package/dist/not-found-error.cjs.map +1 -0
  68. package/dist/not-found-error.js +1 -1
  69. package/dist/outcome.cjs +97 -0
  70. package/dist/outcome.cjs.map +1 -0
  71. package/dist/outcome.d.cts +140 -0
  72. package/dist/outcome.d.ts +140 -0
  73. package/dist/outcome.js +1 -1
  74. package/dist/parse-gate-payload.d.cts +62 -0
  75. package/dist/parse-gate-payload.d.ts +2 -1
  76. package/dist/path.d.cts +90 -0
  77. package/dist/path.d.ts +2 -1
  78. package/dist/plugin.cjs +79 -0
  79. package/dist/plugin.cjs.map +1 -0
  80. package/dist/plugin.d.cts +85 -0
  81. package/dist/plugin.d.ts +85 -0
  82. package/dist/plugin.js +74 -0
  83. package/dist/plugin.js.map +1 -0
  84. package/dist/plugins/index.cjs +3 -0
  85. package/dist/plugins/index.d.cts +2 -0
  86. package/dist/plugins/index.d.ts +2 -0
  87. package/dist/plugins/index.js +2 -0
  88. package/dist/policies/engines/index.cjs +10 -0
  89. package/dist/policies/engines/index.d.cts +4 -0
  90. package/dist/policies/engines/index.d.ts +1 -1
  91. package/dist/policies/engines/v1/gate/index.cjs +91 -0
  92. package/dist/policies/engines/v1/gate/index.cjs.map +1 -0
  93. package/dist/policies/engines/v1/gate/index.d.cts +121 -0
  94. package/dist/policies/engines/v1/gate/index.d.ts +2 -1
  95. package/dist/policies/engines/v1/gate/index.js +2 -1
  96. package/dist/policies/engines/v1/gate/index.js.map +1 -1
  97. package/dist/policies/index.cjs +41 -0
  98. package/dist/policies/index.d.cts +7 -0
  99. package/dist/policies/index.d.ts +2 -1
  100. package/dist/policies/index.js +2 -1
  101. package/dist/policy-service.cjs +1190 -0
  102. package/dist/policy-service.cjs.map +1 -0
  103. package/dist/policy-service.d.cts +559 -0
  104. package/dist/policy-service.d.ts +2 -1
  105. package/dist/policy-service.js +6 -3
  106. package/dist/policy-service.js.map +1 -1
  107. package/dist/result/index.cjs +7 -0
  108. package/dist/result/index.d.cts +2 -0
  109. package/dist/result/index.d.ts +2 -0
  110. package/dist/result/index.js +3 -0
  111. package/dist/result.cjs +135 -0
  112. package/dist/result.cjs.map +1 -0
  113. package/dist/result.js +118 -0
  114. package/dist/result.js.map +1 -0
  115. package/dist/ruleset-registry.cjs +47 -0
  116. package/dist/ruleset-registry.cjs.map +1 -0
  117. package/dist/ruleset-registry.js +42 -0
  118. package/dist/ruleset-registry.js.map +1 -0
  119. package/dist/rulesets/index.cjs +3 -0
  120. package/dist/rulesets/index.d.cts +2 -0
  121. package/dist/rulesets/index.d.ts +2 -0
  122. package/dist/rulesets/index.js +2 -0
  123. package/dist/temporal-guards.cjs +32 -0
  124. package/dist/temporal-guards.cjs.map +1 -0
  125. package/dist/temporal-guards.js +2 -17
  126. package/dist/temporal-guards.js.map +1 -1
  127. package/dist/temporal-use-case.cjs +191 -0
  128. package/dist/temporal-use-case.cjs.map +1 -0
  129. package/dist/temporal-use-case.d.cts +304 -0
  130. package/dist/temporal-use-case.d.ts +4 -9
  131. package/dist/temporal-use-case.js +6 -140
  132. package/dist/temporal-use-case.js.map +1 -1
  133. package/dist/unexpected-error.cjs +208 -0
  134. package/dist/unexpected-error.cjs.map +1 -0
  135. package/dist/unexpected-error.js +179 -0
  136. package/dist/unexpected-error.js.map +1 -0
  137. package/dist/use-case.cjs +96 -0
  138. package/dist/use-case.cjs.map +1 -0
  139. package/dist/use-case.js +91 -0
  140. package/dist/use-case.js.map +1 -0
  141. package/dist/uuid-identifier.cjs +65 -0
  142. package/dist/uuid-identifier.cjs.map +1 -0
  143. package/dist/uuid-identifier.d.cts +230 -0
  144. package/dist/uuid-identifier.d.ts +230 -0
  145. package/dist/uuid-identifier.js +60 -0
  146. package/dist/uuid-identifier.js.map +1 -0
  147. package/dist/validation-code.cjs +60 -0
  148. package/dist/validation-code.cjs.map +1 -0
  149. package/dist/validation-code.d.cts +23 -0
  150. package/dist/validation-code.d.ts +23 -0
  151. package/dist/validation-code.js +1 -177
  152. package/dist/validation-code.js.map +1 -1
  153. package/dist/validation-error.cjs +1020 -0
  154. package/dist/validation-error.cjs.map +1 -0
  155. package/dist/validation-error.d.cts +777 -0
  156. package/dist/validation-error.d.ts +1 -21
  157. package/dist/validation-error.js +1 -1
  158. package/dist/validation-exception.cjs +41 -0
  159. package/dist/validation-exception.cjs.map +1 -0
  160. package/dist/validation-exception.d.cts +50 -0
  161. package/dist/validation-exception.d.ts +50 -0
  162. package/dist/validation-exception.js +8 -2
  163. package/dist/validation-exception.js.map +1 -1
  164. package/dist/validation-field.cjs +28 -0
  165. package/dist/validation-field.cjs.map +1 -0
  166. package/dist/validation-field.d.cts +12 -0
  167. package/dist/value-object-ruleset.contracts.d.cts +36 -0
  168. package/dist/value-object-ruleset.contracts.d.ts +36 -0
  169. package/dist/value-object.cjs +208 -0
  170. package/dist/value-object.cjs.map +1 -0
  171. package/dist/value-object.js +191 -0
  172. package/dist/value-object.js.map +1 -0
  173. package/dist/version.d.cts +10 -0
  174. package/dist/version.d.ts +10 -0
  175. package/dist/versioning/index.cjs +7 -0
  176. package/dist/versioning/index.d.cts +3 -0
  177. package/dist/versioning/index.d.ts +3 -0
  178. package/dist/versioning/index.js +3 -0
  179. package/meta.json +18 -3
  180. package/package.json +165 -17
  181. package/src/core/domain/rulesets/index.ts +7 -0
  182. package/src/core/domain/uuid-identifier.ts +72 -0
  183. package/src/core/domain/value-object.ts +37 -5
  184. package/src/core/exceptions/index.ts +13 -0
  185. package/src/core/index.ts +14 -2
  186. package/src/core/plugins/index.ts +7 -0
  187. package/src/core/plugins/plugin.ts +99 -0
  188. package/src/core/plugins/types.ts +53 -0
  189. package/src/core/versioning/index.ts +14 -0
  190. package/src/domain/index.ts +7 -0
  191. package/src/exceptions/index.ts +1 -0
  192. package/src/plugins/index.ts +1 -0
  193. package/src/result/index.ts +2 -0
  194. package/src/rulesets/index.ts +1 -0
  195. package/src/version.ts +1 -1
  196. package/src/versioning/index.ts +1 -0
@@ -0,0 +1,559 @@
1
+ import { a as Result } from "./outcome.cjs";
2
+ import { _ as PolicyReporter, b as SchoolId, t as GateOutcome, u as GatePayload, v as PolicyDecisionId, x as TenantId, y as PolicyDefinitionId } from "./gate-types.cjs";
3
+ import { a as ComputeOutcome, l as ComputePayload, n as ComputeRegistry, t as GateEngineRegistry } from "./gate-engine-registry.cjs";
4
+
5
+ //#region src/core/policies/catalog/catalog-types.d.ts
6
+ type PolicyKind = "GATE" | "COMPUTE";
7
+ type PolicyOwner = "PLATFORM_OWNER" | "TENANT_ADMIN" | "SCHOOL_ADMIN";
8
+ type PolicyScopeLevel = "GLOBAL" | "TENANT" | "SCHOOL";
9
+ /**
10
+ * Defines where the "as of" date comes from for a given policy.
11
+ */
12
+ type AsOfSource = "NOW" | "CALLER_PROVIDED";
13
+ //#endregion
14
+ //#region src/core/policies/catalog/policy-key.d.ts
15
+ declare class PolicyKey {
16
+ readonly module: string;
17
+ readonly area: string;
18
+ readonly name: string;
19
+ private constructor();
20
+ static parse(raw: string): Result<PolicyKey, string>;
21
+ toString(): string;
22
+ equals(other: PolicyKey): boolean;
23
+ }
24
+ //#endregion
25
+ //#region src/core/policies/catalog/policy-catalog-entry.d.ts
26
+ /**
27
+ * Properties for creating a PolicyCatalogEntry.
28
+ */
29
+ interface PolicyCatalogEntryProps {
30
+ readonly key: PolicyKey;
31
+ readonly kind: PolicyKind;
32
+ readonly gateEngineVersion?: number;
33
+ readonly computeEngineVersion?: number;
34
+ readonly payloadSchemaVersion?: number;
35
+ readonly owner: PolicyOwner;
36
+ readonly allowedScopes: readonly PolicyScopeLevel[];
37
+ readonly asOfSource: AsOfSource;
38
+ /** Paths the context must contain for this policy to be evaluable. */
39
+ readonly contextRequirements: readonly string[];
40
+ readonly tags?: readonly string[];
41
+ readonly description: string;
42
+ }
43
+ /**
44
+ * Represents a single entry in the Policy Catalog.
45
+ * Encapsulates metadata and validation logic for a policy.
46
+ */
47
+ declare class PolicyCatalogEntry {
48
+ readonly key: PolicyKey;
49
+ readonly kind: PolicyKind;
50
+ readonly gateEngineVersion?: number;
51
+ readonly computeEngineVersion?: number;
52
+ readonly payloadSchemaVersion?: number;
53
+ readonly owner: PolicyOwner;
54
+ readonly allowedScopes: readonly PolicyScopeLevel[];
55
+ readonly asOfSource: AsOfSource;
56
+ readonly contextRequirements: readonly string[];
57
+ readonly tags: readonly string[];
58
+ readonly description: string;
59
+ constructor(props: PolicyCatalogEntryProps);
60
+ static assertFamilyConsistency(entries: readonly PolicyCatalogEntry[]): void;
61
+ static from(entry: PolicyCatalogEntry | PolicyCatalogEntryProps): PolicyCatalogEntry;
62
+ isGate(): boolean;
63
+ isCompute(): boolean;
64
+ allowsScope(scope: PolicyScopeLevel): boolean;
65
+ hasExplicitVersionSelector(): boolean;
66
+ matchesVersion(params: {
67
+ readonly kind: PolicyKind;
68
+ readonly gateEngineVersion?: number;
69
+ readonly computeEngineVersion?: number;
70
+ readonly payloadSchemaVersion?: number;
71
+ }): boolean;
72
+ toVariantKey(): string;
73
+ usesNowAsOf(): boolean;
74
+ usesCallerProvidedAsOf(): boolean;
75
+ requiresContext(path: string): boolean;
76
+ requiresAllContexts(paths: readonly string[]): boolean;
77
+ hasTag(tag: string): boolean;
78
+ equals(other: PolicyCatalogEntry): boolean;
79
+ toJSON(): PolicyCatalogEntryProps;
80
+ }
81
+ //#endregion
82
+ //#region src/core/policies/catalog/policy-catalog.d.ts
83
+ /**
84
+ * In-code catalog of all known policies.
85
+ * The catalog defines the universe of policies; the database cannot invent new ones.
86
+ */
87
+ declare class PolicyCatalog {
88
+ private readonly versionedEntries;
89
+ private readonly entriesByKey;
90
+ /**
91
+ * Indexes the given entries up front into two lookups — one per exact
92
+ * variant, one per policy key (the "family") — and validates them eagerly:
93
+ * a duplicate variant or an internally inconsistent family throws here, at
94
+ * wiring time, so a malformed catalog fails fast at startup rather than on
95
+ * the first evaluation.
96
+ *
97
+ * @throws {UnexpectedError} When two entries resolve to the same variant key.
98
+ */
99
+ constructor(entries: readonly PolicyCatalogEntry[]);
100
+ /**
101
+ * Returns the single entry for a key. Deliberately strict: if the key has
102
+ * more than one variant it errs rather than guessing, steering the caller to
103
+ * {@link getVersioned} or {@link getFamily}. Use this only when a key is
104
+ * known to be unambiguous.
105
+ *
106
+ * @returns `ok` with the entry, or `err` when the key is unknown or ambiguous.
107
+ */
108
+ get(key: string): Result<PolicyCatalogEntry, string>;
109
+ /**
110
+ * Returns every variant registered under a key — the whole "family". This is
111
+ * the lookup the evaluation pipeline uses, since a single key may host
112
+ * several engine/schema variants that the resolver then chooses between.
113
+ *
114
+ * @returns `ok` with the family (always non-empty), or `err` when the key is unknown.
115
+ */
116
+ getFamily(key: string): Result<readonly PolicyCatalogEntry[], string>;
117
+ /**
118
+ * Resolves the one entry matching an exact variant — kind plus engine and
119
+ * payload-schema versions. Falls back to the sole family member when a key
120
+ * has exactly one entry and that entry declares no explicit version
121
+ * selector, so unversioned single-variant policies "just work" without the
122
+ * caller spelling out versions.
123
+ *
124
+ * @param params - The key and the variant coordinates to match on.
125
+ * @returns `ok` with the matching entry, or `err` when no variant matches.
126
+ */
127
+ getVersioned(params: {
128
+ readonly key: string;
129
+ readonly kind: "GATE" | "COMPUTE";
130
+ readonly gateEngineVersion?: number;
131
+ readonly computeEngineVersion?: number;
132
+ readonly payloadSchemaVersion?: number;
133
+ }): Result<PolicyCatalogEntry, string>;
134
+ /** Lists every registered variant across all keys — useful for introspection and diagnostics. */
135
+ list(): readonly PolicyCatalogEntry[];
136
+ /** Returns whether any variant is registered under the given key. */
137
+ has(key: string): boolean;
138
+ }
139
+ //#endregion
140
+ //#region src/core/policies/defs/policy-payload.contracts.d.ts
141
+ type AnyPolicyPayload = GatePayload | ComputePayload;
142
+ /**
143
+ * Payload type associated with a policy key.
144
+ *
145
+ * Intentionally NOT backed by global module augmentation: two modules registering
146
+ * different shapes for the same literal key would silently override each other and
147
+ * the last `declare module` wins. Per-key payload typing must be expressed
148
+ * explicitly at the definition site (see {@link PolicyDefinition} type params).
149
+ */
150
+ //#endregion
151
+ //#region src/core/policies/defs/policy-scope.d.ts
152
+ /**
153
+ * Scope attached to a PolicyDefinition — defines where it applies.
154
+ */
155
+ interface PolicyScope {
156
+ readonly level: PolicyScopeLevel;
157
+ readonly tenantId: TenantId | null;
158
+ readonly schoolId: SchoolId | null;
159
+ }
160
+ /**
161
+ * Ordered list of scopes from most-specific to least-specific.
162
+ * Used by the resolver to match definitions.
163
+ *
164
+ * Example:
165
+ * ```
166
+ * [
167
+ * { level: 'SCHOOL', tenantId: 't1', schoolId: 's1' },
168
+ * { level: 'TENANT', tenantId: 't1', schoolId: null },
169
+ * { level: 'GLOBAL', tenantId: null, schoolId: null },
170
+ * ]
171
+ * ```
172
+ */
173
+ type ScopeChain = readonly PolicyScope[];
174
+ declare class PolicyScopeMatcher {
175
+ static weight(level: PolicyScopeLevel): number;
176
+ static matchesChain(defScope: PolicyScope, chain: ScopeChain): boolean;
177
+ static equals(a: PolicyScope, b: PolicyScope): boolean;
178
+ }
179
+ //#endregion
180
+ //#region src/core/policies/defs/policy-definition.d.ts
181
+ type PolicyDefinitionStatus = "DRAFT" | "PUBLISHED" | "RETIRED";
182
+ interface BasePolicyDefinitionProps<K extends string = string, P extends AnyPolicyPayload = AnyPolicyPayload> {
183
+ readonly id: PolicyDefinitionId;
184
+ readonly policyKey: K;
185
+ readonly policyVersion: string;
186
+ readonly payloadSchemaVersion: number;
187
+ readonly contextVersionMin: number;
188
+ readonly contextVersionMax: number;
189
+ readonly enabled: boolean;
190
+ readonly status: PolicyDefinitionStatus;
191
+ readonly scope: PolicyScope;
192
+ readonly effectiveFrom: Date;
193
+ readonly effectiveTo: Date | null;
194
+ readonly priority: number;
195
+ readonly payloadJson: P;
196
+ readonly payloadHash: string;
197
+ readonly createdAt: Date;
198
+ readonly publishedAt: Date | null;
199
+ }
200
+ interface GatePolicyDefinitionProps<K extends string = string, P extends AnyPolicyPayload = AnyPolicyPayload> extends BasePolicyDefinitionProps<K, P> {
201
+ readonly kind: "GATE";
202
+ readonly gateEngineVersion: number;
203
+ }
204
+ interface ComputePolicyDefinitionProps<K extends string = string, P extends AnyPolicyPayload = AnyPolicyPayload> extends BasePolicyDefinitionProps<K, P> {
205
+ readonly kind: "COMPUTE";
206
+ readonly computeEngineVersion: number;
207
+ }
208
+ type GatePolicyDefinitionInput<K extends string = string, P extends AnyPolicyPayload = AnyPolicyPayload> = Omit<GatePolicyDefinitionProps<K, P>, "kind" | "enabled"> & {
209
+ readonly enabled?: boolean;
210
+ };
211
+ type ComputePolicyDefinitionInput<K extends string = string, P extends AnyPolicyPayload = AnyPolicyPayload> = Omit<ComputePolicyDefinitionProps<K, P>, "kind" | "enabled"> & {
212
+ readonly enabled?: boolean;
213
+ };
214
+ type PolicyDefinitionProps<K extends string = string, P extends AnyPolicyPayload = AnyPolicyPayload> = GatePolicyDefinitionProps<K, P> | ComputePolicyDefinitionProps<K, P>;
215
+ declare class PolicyDefinition<K extends string = string, P extends AnyPolicyPayload = AnyPolicyPayload> {
216
+ private static assertPolicyVersionIsSemver;
217
+ private static assertCoherentBounds;
218
+ readonly id: PolicyDefinitionId;
219
+ readonly policyKey: K;
220
+ readonly policyVersion: string;
221
+ readonly payloadSchemaVersion: number;
222
+ readonly contextVersionMin: number;
223
+ readonly contextVersionMax: number;
224
+ readonly gateEngineVersion?: number;
225
+ readonly computeEngineVersion?: number;
226
+ readonly enabled: boolean;
227
+ readonly status: PolicyDefinitionStatus;
228
+ readonly scope: PolicyScope;
229
+ readonly effectiveFrom: Date;
230
+ readonly effectiveTo: Date | null;
231
+ readonly priority: number;
232
+ readonly payloadJson: P;
233
+ readonly payloadHash: string;
234
+ readonly createdAt: Date;
235
+ readonly publishedAt: Date | null;
236
+ readonly kind: PolicyKind;
237
+ private constructor();
238
+ static gate<K extends string, P extends AnyPolicyPayload = AnyPolicyPayload>(props: GatePolicyDefinitionInput<K, P>): PolicyDefinition<K, P>;
239
+ static compute<K extends string, P extends AnyPolicyPayload = AnyPolicyPayload>(props: ComputePolicyDefinitionInput<K, P>): PolicyDefinition<K, P>;
240
+ isGate(): this is PolicyDefinition<K, P> & {
241
+ readonly kind: "GATE";
242
+ readonly gateEngineVersion: number;
243
+ };
244
+ isCompute(): this is PolicyDefinition<K, P> & {
245
+ readonly kind: "COMPUTE";
246
+ readonly computeEngineVersion: number;
247
+ };
248
+ }
249
+ interface FindCandidatesParams {
250
+ readonly policyKey: string;
251
+ readonly kind: PolicyKind;
252
+ readonly payloadSchemaVersion?: number;
253
+ readonly asOf: Date;
254
+ readonly contextVersion: number;
255
+ readonly scopeChain: readonly PolicyScope[];
256
+ }
257
+ //#endregion
258
+ //#region src/core/policies/defs/policy-definition-repository.d.ts
259
+ interface PolicyDefinitionRepository {
260
+ findCandidates(params: FindCandidatesParams): PolicyDefinition[];
261
+ }
262
+ //#endregion
263
+ //#region src/core/policies/context/context-seed.d.ts
264
+ /**
265
+ * Seed data provided by the use case / caller.
266
+ * Contains raw IDs and inputs that the context system will resolve into paths.
267
+ * Each resolver is responsible for validating and extracting what it needs from fields.
268
+ */
269
+ interface ContextSeed {
270
+ readonly tenantId: TenantId;
271
+ readonly schoolId: SchoolId;
272
+ readonly fields: Record<string, unknown>;
273
+ }
274
+ declare class ContextSeedValidator {
275
+ private static isBlankSeedId;
276
+ static validate(seed: ContextSeed): Result<ContextSeed, string>;
277
+ }
278
+ //#endregion
279
+ //#region src/core/policies/context/context-resolver.d.ts
280
+ interface ContextResolverRetryOptions {
281
+ readonly maxAttempts?: number;
282
+ readonly initialDelayMs?: number;
283
+ readonly maxDelayMs?: number;
284
+ readonly backoffMultiplier?: number;
285
+ }
286
+ interface ContextResolverCircuitBreakerOptions {
287
+ readonly failureThreshold?: number;
288
+ readonly cooldownMs?: number;
289
+ }
290
+ interface ContextResolverResilienceOptions {
291
+ readonly timeoutMs?: number;
292
+ readonly retry?: ContextResolverRetryOptions | false;
293
+ readonly circuitBreaker?: ContextResolverCircuitBreakerOptions | false;
294
+ }
295
+ /**
296
+ * A resolver that knows how to produce a value for a specific context path.
297
+ * Designed as async to allow future DB/API lookups without breaking the interface.
298
+ */
299
+ interface ContextValueResolver {
300
+ readonly path: string;
301
+ readonly resilience?: ContextResolverResilienceOptions;
302
+ resolve(seed: ContextSeed): Promise<Result<unknown, string>>;
303
+ }
304
+ //#endregion
305
+ //#region src/core/policies/context/context-registry.d.ts
306
+ interface ContextResolverRegistrationOptions {
307
+ readonly namespace?: string;
308
+ }
309
+ /**
310
+ * Registry of context value resolvers, keyed by path.
311
+ */
312
+ declare class ContextResolverRegistry {
313
+ private readonly resolvers;
314
+ register(resolver: ContextValueResolver, options?: ContextResolverRegistrationOptions): Result<void, string>;
315
+ registerAll(resolvers: readonly ContextValueResolver[], options?: ContextResolverRegistrationOptions): Result<void, string>;
316
+ get(path: string): ContextValueResolver | undefined;
317
+ has(path: string): boolean;
318
+ getNamespace(path: string): string | undefined;
319
+ }
320
+ declare function registerNamespacedContextResolversIn(registry: ContextResolverRegistry, namespace: string, resolvers: readonly ContextValueResolver[]): Result<ContextResolverRegistry, string>;
321
+ //#endregion
322
+ //#region src/core/policies/context/context-builder.d.ts
323
+ interface PolicyContextBuilderOptions {
324
+ readonly defaultResolverResilience?: ContextResolverResilienceOptions;
325
+ readonly now?: () => number;
326
+ readonly sleep?: (delayMs: number) => Promise<void>;
327
+ }
328
+ /**
329
+ * Builds a context object by resolving required paths from a seed.
330
+ */
331
+ declare class PolicyContextBuilder {
332
+ private readonly registry;
333
+ private readonly circuitStates;
334
+ private readonly defaultResolverResilience?;
335
+ private readonly now;
336
+ private readonly sleep;
337
+ constructor(registry: ContextResolverRegistry, options?: PolicyContextBuilderOptions);
338
+ private static clampPositiveInteger;
339
+ private static clampNonNegativeInteger;
340
+ private static normalizeTimeoutMs;
341
+ private static mergeRetryOptions;
342
+ private static mergeCircuitBreakerOptions;
343
+ private resolveResilienceOptions;
344
+ private getRetryDelayMs;
345
+ private resetCircuit;
346
+ private isCircuitOpen;
347
+ private recordResolverFailure;
348
+ private static describeThrownResolverError;
349
+ private resolveOnce;
350
+ private resolveWithResilience;
351
+ /**
352
+ * Resolves all required context paths and returns a flat context object.
353
+ * If any required path cannot be resolved, returns an error.
354
+ */
355
+ build(requirements: readonly string[], seed: ContextSeed): Promise<Result<Record<string, unknown>, string>>;
356
+ }
357
+ //#endregion
358
+ //#region src/core/policies/asof/asof.d.ts
359
+ interface DeriveAsOfOptions {
360
+ readonly maxFutureYears?: number;
361
+ }
362
+ declare class PolicyAsOfResolver {
363
+ private static resolveMaxFutureYears;
364
+ static derive(source: AsOfSource, seed: ContextSeed, now: Date, options?: DeriveAsOfOptions): Result<Date, string>;
365
+ }
366
+ //#endregion
367
+ //#region src/core/policies/resolver/policy-resolver.d.ts
368
+ /**
369
+ * Selects the best policy definition from a list of already-filtered candidates.
370
+ *
371
+ * Ordering criteria (highest priority first):
372
+ * 1. Scope specificity: SCHOOL (3) > TENANT (2) > GLOBAL (1)
373
+ * 2. Priority: higher number wins
374
+ * 3. publishedAt descending (fallback to createdAt)
375
+ * 4. Engine version descending (prefer-latest-engine-version — deterministic tiebreaker)
376
+ * 5. policyVersion descending (semver — final deterministic tiebreaker)
377
+ */
378
+ declare class PolicyResolver {
379
+ /**
380
+ * Picks the single winning definition from an already-filtered candidate
381
+ * list by applying the class's ordering criteria in priority order. The sort
382
+ * runs over a copy, so the caller's array is left untouched, and the final
383
+ * semver tiebreaker guarantees the winner is fully deterministic — it never
384
+ * depends on the order the repository returned the candidates in.
385
+ *
386
+ * @param candidates - Definitions already filtered to match key, scope, and as-of.
387
+ * @returns `ok` with the highest-ranked definition, or `err` when the list is empty.
388
+ */
389
+ resolveBest(candidates: readonly PolicyDefinition[]): Result<PolicyDefinition, string>;
390
+ }
391
+ //#endregion
392
+ //#region src/core/policies/service/policy-evaluation-error.d.ts
393
+ type PolicyEvaluationError = {
394
+ readonly kind: "INVALID_CONTEXT";
395
+ readonly stage: "SEED_VALIDATION" | "AS_OF_DERIVATION" | "CONTEXT_BUILD";
396
+ readonly policyKey: string;
397
+ readonly message: string;
398
+ readonly cause: string;
399
+ } | {
400
+ readonly kind: "INVALID_POLICY_KEY";
401
+ readonly rawPolicyKey: string;
402
+ readonly message: string;
403
+ readonly cause: string;
404
+ } | {
405
+ readonly kind: "POLICY_NOT_FOUND";
406
+ readonly policyKey: string;
407
+ readonly message: string;
408
+ readonly cause: string;
409
+ } | {
410
+ readonly kind: "POLICY_DEFINITION_NOT_FOUND";
411
+ readonly policyKey: string;
412
+ readonly contextVersion: number;
413
+ readonly asOf: Date;
414
+ readonly message: string;
415
+ readonly cause: string;
416
+ } | {
417
+ readonly kind: "POLICY_VARIANT_NOT_FOUND";
418
+ readonly policyKey: string;
419
+ readonly policyKind: PolicyKind;
420
+ readonly payloadSchemaVersion: number;
421
+ readonly gateEngineVersion?: number;
422
+ readonly computeEngineVersion?: number;
423
+ readonly message: string;
424
+ readonly cause: string;
425
+ } | {
426
+ readonly kind: "ENGINE_FAILURE";
427
+ readonly policyKey: string;
428
+ readonly engine: PolicyKind;
429
+ readonly engineVersion: number;
430
+ readonly message: string;
431
+ readonly cause: string;
432
+ };
433
+ declare class PolicyEvaluationErrors {
434
+ static invalidContext(stage: Extract<PolicyEvaluationError, {
435
+ kind: "INVALID_CONTEXT";
436
+ }>["stage"], policyKey: string, cause: string): PolicyEvaluationError;
437
+ static invalidPolicyKey(rawPolicyKey: string, cause: string): PolicyEvaluationError;
438
+ static policyNotFound(policyKey: string, cause: string): PolicyEvaluationError;
439
+ static policyDefinitionNotFound(policyKey: string, asOf: Date, contextVersion: number, cause: string): PolicyEvaluationError;
440
+ static policyVariantNotFound(params: {
441
+ readonly policyKey: string;
442
+ readonly policyKind: PolicyKind;
443
+ readonly payloadSchemaVersion: number;
444
+ readonly gateEngineVersion?: number;
445
+ readonly computeEngineVersion?: number;
446
+ readonly cause: string;
447
+ }): PolicyEvaluationError;
448
+ static engineFailure(policyKey: string, engine: PolicyKind, engineVersion: number, cause: string): PolicyEvaluationError;
449
+ }
450
+ //#endregion
451
+ //#region src/core/policies/service/policy-service.d.ts
452
+ /**
453
+ * Everything a single policy evaluation needs. `policyKey` names the policy,
454
+ * `scopeChain` narrows the search from most-specific to least-specific scope,
455
+ * `contextVersion` pins which context schema applies, and `seed` carries the
456
+ * raw facts the context builder expands. `decisionId` is the caller's
457
+ * idempotency/audit handle, echoed back on the result.
458
+ */
459
+ interface EvaluateInput {
460
+ readonly decisionId: PolicyDecisionId;
461
+ readonly policyKey: string;
462
+ readonly scopeChain: readonly PolicyScope[];
463
+ readonly contextVersion: number;
464
+ readonly seed: ContextSeed;
465
+ }
466
+ /**
467
+ * Cross-cutting knobs for a {@link PolicyService}: how the as-of instant is
468
+ * derived ({@link asOf}) and where evaluation telemetry is sent
469
+ * ({@link reporter}). Both are optional; the service defaults to a silent
470
+ * reporter so telemetry is opt-in.
471
+ */
472
+ interface PolicyServiceOptions {
473
+ readonly asOf?: DeriveAsOfOptions;
474
+ readonly reporter?: PolicyReporter;
475
+ }
476
+ /**
477
+ * The collaborators a {@link PolicyService} is wired with. Each is an injected
478
+ * port so the service stays storage- and engine-agnostic: the catalog defines
479
+ * the universe of policies, `defRepo` supplies their versioned definitions, the
480
+ * `resolver` picks the winning definition, and the engine registries execute it.
481
+ */
482
+ interface PolicyServiceParams {
483
+ readonly catalog: PolicyCatalog;
484
+ readonly contextBuilder: PolicyContextBuilder;
485
+ readonly defRepo: PolicyDefinitionRepository;
486
+ readonly resolver: PolicyResolver;
487
+ readonly gateEngines: GateEngineRegistry;
488
+ readonly computeRegistry: ComputeRegistry;
489
+ readonly options?: PolicyServiceOptions;
490
+ }
491
+ /** Union of all possible policy decision Outcomes. */
492
+ type PolicyDecision = GateOutcome | ComputeOutcome;
493
+ /**
494
+ * The full record of one successful evaluation. Beyond the business
495
+ * {@link decision}, it pins the exact definition that produced it — id, key,
496
+ * version, payload hash, and engine version — together with the `asOf` instant
497
+ * the policy was selected for and the wall-clock `evaluatedAt`. That provenance
498
+ * is what makes a decision reproducible and auditable after the fact.
499
+ */
500
+ interface PolicyEvaluationResult {
501
+ readonly decisionId: PolicyDecisionId;
502
+ readonly ref: {
503
+ readonly definitionId: PolicyDefinitionId;
504
+ readonly policyKey: string;
505
+ readonly policyVersion: string;
506
+ readonly payloadHash: string;
507
+ readonly gateEngineVersion?: number;
508
+ readonly computeEngineVersion?: number;
509
+ };
510
+ readonly kind: "GATE" | "COMPUTE";
511
+ readonly asOf: Date;
512
+ readonly evaluatedAt: Date;
513
+ readonly contextVersion: number;
514
+ /** Business decision expressed as an Outcome — not a technical Result. */
515
+ readonly decision: PolicyDecision;
516
+ }
517
+ /**
518
+ * Orchestrates the end-to-end evaluation of a policy: it parses and validates
519
+ * the context seed, derives the as-of instant, resolves the best matching
520
+ * definition for the requested key/scope/version, builds the context the policy
521
+ * needs, and runs it through the right engine (gate or compute).
522
+ *
523
+ * The service never throws for an expected failure: every step returns a
524
+ * {@link Result}, and the failures are folded into a typed
525
+ * {@link PolicyEvaluationError} so callers branch on `isErr()` rather than
526
+ * catching. Telemetry is best-effort — a throwing reporter can never abort an
527
+ * evaluation — which keeps observability strictly side-band.
528
+ */
529
+ declare class PolicyService {
530
+ #private;
531
+ private readonly catalog;
532
+ private readonly contextBuilder;
533
+ private readonly defRepo;
534
+ private readonly resolver;
535
+ private readonly gateEngines;
536
+ private readonly computeRegistry;
537
+ private readonly options;
538
+ constructor(params: PolicyServiceParams);
539
+ private resolveEvaluationNow;
540
+ /**
541
+ * Evaluates a policy and returns its decision.
542
+ *
543
+ * This is the single public entry point. It delegates the actual work to the
544
+ * private pipeline and wraps it with telemetry: a completed or failed event
545
+ * is reported either way, but reporting is guarded so it can never change the
546
+ * outcome. The returned {@link Result} is `ok` with a
547
+ * {@link PolicyEvaluationResult} on success, or `err` with a typed
548
+ * {@link PolicyEvaluationError} describing which stage rejected the input —
549
+ * the method itself does not throw for expected failures.
550
+ *
551
+ * @param input - The policy key, scope chain, context version, and seed to
552
+ * evaluate, plus the caller's `decisionId`.
553
+ * @returns A `Result` carrying the decision or the evaluation error.
554
+ */
555
+ evaluate(input: EvaluateInput): Promise<Result<PolicyEvaluationResult, PolicyEvaluationError>>;
556
+ }
557
+ //#endregion
558
+ export { PolicyScope as A, BasePolicyDefinitionProps as C, PolicyDefinition as D, GatePolicyDefinitionProps as E, PolicyKey as F, AsOfSource as I, PolicyKind as L, ScopeChain as M, PolicyCatalog as N, PolicyDefinitionProps as O, PolicyCatalogEntryProps as P, PolicyOwner as R, PolicyDefinitionRepository as S, FindCandidatesParams as T, ContextResolverResilienceOptions as _, PolicyServiceOptions as a, ContextSeed as b, PolicyEvaluationErrors as c, PolicyAsOfResolver as d, PolicyContextBuilder as f, ContextResolverCircuitBreakerOptions as g, registerNamespacedContextResolversIn as h, PolicyService as i, PolicyScopeMatcher as j, PolicyDefinitionStatus as k, PolicyResolver as l, ContextResolverRegistry as m, PolicyDecision as n, PolicyServiceParams as o, PolicyContextBuilderOptions as p, PolicyEvaluationResult as r, PolicyEvaluationError as s, EvaluateInput as t, DeriveAsOfOptions as u, ContextResolverRetryOptions as v, ComputePolicyDefinitionProps as w, ContextSeedValidator as x, ContextValueResolver as y, PolicyScopeLevel as z };
559
+ //# sourceMappingURL=policy-service.d.cts.map
@@ -1,4 +1,5 @@
1
- import { C as TenantId, I as Result, S as SchoolId, b as PolicyDecisionId, t as GateOutcome, u as GatePayload, x as PolicyDefinitionId, y as PolicyReporter } from "./gate-types.js";
1
+ import { a as Result } from "./outcome.js";
2
+ import { _ as PolicyReporter, b as SchoolId, t as GateOutcome, u as GatePayload, v as PolicyDecisionId, x as TenantId, y as PolicyDefinitionId } from "./gate-types.js";
2
3
  import { a as ComputeOutcome, l as ComputePayload, n as ComputeRegistry, t as GateEngineRegistry } from "./gate-engine-registry.js";
3
4
 
4
5
  //#region src/core/policies/catalog/catalog-types.d.ts
@@ -1,9 +1,12 @@
1
- import { n as UnexpectedError, t as ValidationCode } from "./validation-code.js";
1
+ import { t as UnexpectedError } from "./unexpected-error.js";
2
2
  import { n as sha256Hex, r as stableStringify } from "./hashing.js";
3
+ import { t as ValidationCode } from "./validation-code.js";
3
4
  import { t as ValidationField } from "./validation-field.js";
4
- import { i as InvariantViolationException, r as isValidDate } from "./temporal-guards.js";
5
+ import { t as InvariantViolationException } from "./invariant-violation-exception.js";
5
6
  import { t as InvalidValueException } from "./validation-exception.js";
6
- import { f as SilentPolicyReporter, l as Result, o as PolicyContextPath } from "./gate-v1-payload.schema.js";
7
+ import { r as isValidDate } from "./temporal-guards.js";
8
+ import { l as SilentPolicyReporter, o as PolicyContextPath } from "./gate-v1-payload.schema.js";
9
+ import { r as Result } from "./result.js";
7
10
  //#region src/core/policies/utils/hash.ts
8
11
  /**
9
12
  * Produces a deterministic SHA-256 hex digest of a canonical JSON representation.