rulit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,745 @@
1
+ import { ZodType } from 'zod';
2
+
3
+ type ConditionTrace$1 = {
4
+ label: string;
5
+ result: boolean;
6
+ left?: unknown;
7
+ op?: string;
8
+ right?: unknown;
9
+ children?: ConditionTrace$1[];
10
+ reasonCode?: string;
11
+ };
12
+ type ConditionMeta$1<Facts> = {
13
+ label: string;
14
+ reasonCode?: string;
15
+ kind?: "atomic" | "and" | "or" | "not";
16
+ children?: Condition$1<Facts>[];
17
+ };
18
+ type RuleTrace$1 = {
19
+ ruleId: string;
20
+ matched: boolean;
21
+ conditions: ConditionTrace$1[];
22
+ notes: string[];
23
+ durationMs?: number;
24
+ error?: string;
25
+ meta?: RuleMeta$1;
26
+ skippedReason?: string;
27
+ };
28
+ type Condition$1<Facts> = ((facts: Facts) => ConditionTrace$1) & {
29
+ meta?: ConditionMeta$1<Facts>;
30
+ };
31
+ type ActionContext$1<Facts, Effects> = {
32
+ facts: Facts;
33
+ effects: Effects;
34
+ trace: {
35
+ note: (message: string) => void;
36
+ };
37
+ };
38
+ type RuleActivation$1 = "all" | "first";
39
+ type RuleMeta$1 = {
40
+ tags?: string[];
41
+ description?: string;
42
+ version?: string;
43
+ reasonCode?: string;
44
+ enabled?: boolean;
45
+ };
46
+ type EffectsMode$1 = "mutable" | "immutable";
47
+ type MergeStrategy$1 = "assign" | "deep";
48
+ type RunOptions$1 = {
49
+ activation?: RuleActivation$1;
50
+ effectsMode?: EffectsMode$1;
51
+ mergeStrategy?: MergeStrategy$1;
52
+ rollbackOnError?: boolean;
53
+ includeTags?: string[];
54
+ excludeTags?: string[];
55
+ };
56
+ type GraphNode$1 = {
57
+ id: string;
58
+ type: "ruleset" | "rule" | "condition";
59
+ label: string;
60
+ reasonCode?: string;
61
+ tags?: string[];
62
+ description?: string;
63
+ version?: string;
64
+ };
65
+ type GraphEdge$1 = {
66
+ from: string;
67
+ to: string;
68
+ };
69
+ type RulesetGraph$1 = {
70
+ nodes: GraphNode$1[];
71
+ edges: GraphEdge$1[];
72
+ };
73
+ type RunResult$1<Effects> = {
74
+ effects: Effects;
75
+ fired: string[];
76
+ trace: RuleTrace$1[];
77
+ explain: () => string;
78
+ };
79
+ type TraceRun$1 = {
80
+ id: string;
81
+ createdAt: number;
82
+ facts: unknown;
83
+ fired: string[];
84
+ trace: RuleTrace$1[];
85
+ };
86
+ type TelemetryAttributes$1 = Record<string, unknown>;
87
+ type TelemetrySpan = {
88
+ end: () => void;
89
+ recordException?: (error: unknown) => void;
90
+ setAttribute?: (key: string, value: unknown) => void;
91
+ setAttributes?: (attributes: TelemetryAttributes$1) => void;
92
+ };
93
+ type TelemetryAdapter$1 = {
94
+ startSpan: (name: string, attributes?: TelemetryAttributes$1) => TelemetrySpan;
95
+ };
96
+ type ActionResult<Effects> = void | Partial<Effects>;
97
+ type AsyncActionResult<Effects> = ActionResult<Effects> | Promise<ActionResult<Effects>>;
98
+
99
+ type Primitive = string | number | boolean | bigint | symbol | null | undefined;
100
+ type DotPrefix<T extends string> = T extends "" ? "" : `.${T}`;
101
+ type PathImpl<T, Key extends keyof T> = Key extends string ? T[Key] extends Primitive ? Key : T[Key] extends Array<unknown> ? Key : T[Key] extends Date ? Key : Key | `${Key}${DotPrefix<Path$1<T[Key]>>}` : never;
102
+ type Path$1<T> = T extends object ? {
103
+ [K in keyof T]-?: PathImpl<T, K>;
104
+ }[keyof T] : never;
105
+ type PathValue$1<T, P extends Path$1<T>> = P extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? Rest extends Path$1<T[Key]> ? PathValue$1<T[Key], Rest> : never : never : P extends keyof T ? T[P] : never;
106
+ type FieldOperators<T, P extends Path$1<T>> = PathValue$1<T, P> extends number ? NumberOperators<T, P> : PathValue$1<T, P> extends string ? StringOperators<T, P> : PathValue$1<T, P> extends boolean ? BooleanOperators<T, P> : PathValue$1<T, P> extends Date ? DateOperators<T, P> : PathValue$1<T, P> extends Array<infer U> ? ArrayOperators<T, P, U> : BaseOperators<T, P>;
107
+ type BaseOperators<T, P extends Path$1<T>> = {
108
+ eq: (value: PathValue$1<T, P>) => Condition$1<T>;
109
+ in: (values: PathValue$1<T, P>[]) => Condition$1<T>;
110
+ };
111
+ type NumberOperators<T, P extends Path$1<T>> = BaseOperators<T, P> & {
112
+ gt: (value: number) => Condition$1<T>;
113
+ gte: (value: number) => Condition$1<T>;
114
+ lt: (value: number) => Condition$1<T>;
115
+ lte: (value: number) => Condition$1<T>;
116
+ between: (min: number, max: number) => Condition$1<T>;
117
+ };
118
+ type StringOperators<T, P extends Path$1<T>> = BaseOperators<T, P> & {
119
+ contains: (value: string) => Condition$1<T>;
120
+ startsWith: (value: string) => Condition$1<T>;
121
+ matches: (value: RegExp) => Condition$1<T>;
122
+ };
123
+ type BooleanOperators<T, P extends Path$1<T>> = BaseOperators<T, P> & {
124
+ isTrue: () => Condition$1<T>;
125
+ isFalse: () => Condition$1<T>;
126
+ };
127
+ type DateOperators<T, P extends Path$1<T>> = BaseOperators<T, P> & {
128
+ before: (value: Date) => Condition$1<T>;
129
+ after: (value: Date) => Condition$1<T>;
130
+ };
131
+ type ArrayOperators<T, P extends Path$1<T>, U> = BaseOperators<T, P> & {
132
+ contains: (value: U) => Condition$1<T>;
133
+ any: (predicate: (item: U) => boolean, label?: string) => Condition$1<T>;
134
+ all: (predicate: (item: U) => boolean, label?: string) => Condition$1<T>;
135
+ };
136
+ type Field$1<T, P extends Path$1<T>> = {
137
+ path: P;
138
+ get: (facts: T) => PathValue$1<T, P>;
139
+ } & FieldOperators<T, P>;
140
+ /**
141
+ * Create a typed field accessor for a facts model.
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * const factsField = Rules.field<Facts>();
146
+ * const isAdult = factsField("user.age").gte(18);
147
+ * ```
148
+ */
149
+ declare function field<T>(): <P extends Path$1<T>>(path: P) => Field$1<T, P>;
150
+ /**
151
+ * Create a typed field accessor for a specific path.
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * const isVip = Rules.field<Facts>()("user.tags").contains("vip");
156
+ * ```
157
+ */
158
+ declare function field<T, P extends Path$1<T>>(path: P): Field$1<T, P>;
159
+
160
+ type ConditionDetails<Facts> = (facts: Facts) => Pick<ConditionTrace$1, "left" | "op" | "right">;
161
+ type ConditionOptions<Facts> = {
162
+ details?: ConditionDetails<Facts>;
163
+ reasonCode?: string;
164
+ };
165
+ /**
166
+ * Create a condition with optional trace details and a reason code.
167
+ *
168
+ * @example
169
+ * ```ts
170
+ * const isAdult = Rules.condition("is adult", (facts: Facts) => facts.user.age >= 18, {
171
+ * details: (facts) => ({ left: facts.user.age, op: ">=", right: 18 }),
172
+ * reasonCode: "AGE_18",
173
+ * });
174
+ * ```
175
+ */
176
+ declare function condition<Facts>(label: string, test: (facts: Facts) => boolean, options?: ConditionDetails<Facts> | ConditionOptions<Facts>): Condition$1<Facts>;
177
+
178
+ type ConditionLabel = string | {
179
+ label: string;
180
+ };
181
+ /**
182
+ * Boolean and extensibility operators for composing conditions.
183
+ */
184
+ declare const op: {
185
+ and: typeof and;
186
+ or: typeof or;
187
+ not: typeof not;
188
+ custom: typeof custom;
189
+ register: typeof register;
190
+ use: typeof use;
191
+ has: typeof has;
192
+ list: typeof list;
193
+ };
194
+ type OperatorFactory<Facts, Args extends unknown[]> = (...args: Args) => Condition$1<Facts>;
195
+ /**
196
+ * Combine conditions with logical AND.
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * const combined = Rules.op.and(isAdult, isVip);
201
+ * ```
202
+ */
203
+ declare function and<Facts>(...conditions: Condition$1<Facts>[]): Condition$1<Facts>;
204
+ declare function and<Facts>(label: ConditionLabel, ...conditions: Condition$1<Facts>[]): Condition$1<Facts>;
205
+ /**
206
+ * Combine conditions with logical OR.
207
+ *
208
+ * @example
209
+ * ```ts
210
+ * const combined = Rules.op.or(isAdult, isVip);
211
+ * ```
212
+ */
213
+ declare function or<Facts>(...conditions: Condition$1<Facts>[]): Condition$1<Facts>;
214
+ declare function or<Facts>(label: ConditionLabel, ...conditions: Condition$1<Facts>[]): Condition$1<Facts>;
215
+ /**
216
+ * Negate a condition.
217
+ *
218
+ * @example
219
+ * ```ts
220
+ * const notVip = Rules.op.not(isVip);
221
+ * ```
222
+ */
223
+ declare function not<Facts>(conditionToNegate: Condition$1<Facts>): Condition$1<Facts>;
224
+ declare function not<Facts>(label: ConditionLabel, conditionToNegate: Condition$1<Facts>): Condition$1<Facts>;
225
+ /**
226
+ * Create a custom condition with an optional reason code and trace details.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * const isEven = Rules.op.custom("is-even", (facts: { value: number }) => facts.value % 2 === 0);
231
+ * ```
232
+ */
233
+ declare function custom<Facts>(label: string, test: (facts: Facts) => boolean, options?: ((facts: Facts) => Pick<ConditionTrace$1, "left" | "op" | "right">) | {
234
+ details?: (facts: Facts) => Pick<ConditionTrace$1, "left" | "op" | "right">;
235
+ reasonCode?: string;
236
+ }): Condition$1<Facts>;
237
+ /**
238
+ * Register a custom operator factory by name.
239
+ *
240
+ * @example
241
+ * ```ts
242
+ * Rules.op.register("positive", () => Rules.condition("positive", (facts: { value: number }) => facts.value > 0));
243
+ * ```
244
+ */
245
+ declare function register<Facts, Args extends unknown[]>(name: string, factory: OperatorFactory<Facts, Args>): void;
246
+ /**
247
+ * Create a condition using a registered operator.
248
+ *
249
+ * @example
250
+ * ```ts
251
+ * const positive = Rules.op.use<{ value: number }, []>("positive");
252
+ * ```
253
+ */
254
+ declare function use<Facts, Args extends unknown[]>(name: string, ...args: Args): Condition$1<Facts>;
255
+ /**
256
+ * Check if a custom operator name is registered.
257
+ *
258
+ * @example
259
+ * ```ts
260
+ * if (!Rules.op.has("positive")) { ... }
261
+ * ```
262
+ */
263
+ declare function has(name: string): boolean;
264
+ /**
265
+ * List registered operator names.
266
+ *
267
+ * @example
268
+ * ```ts
269
+ * const names = Rules.op.list();
270
+ * ```
271
+ */
272
+ declare function list(): string[];
273
+
274
+ type Rule<Facts, Effects> = {
275
+ id: string;
276
+ priority: number;
277
+ order: number;
278
+ conditions: Condition$1<Facts>[];
279
+ action: (ctx: ActionContext$1<Facts, Effects>) => AsyncActionResult<Effects>;
280
+ meta?: RuleMeta$1;
281
+ };
282
+ type DefaultEffectsFactory<Effects> = () => Effects;
283
+ type Engine<Facts, Effects> = {
284
+ run: (input: {
285
+ facts: Facts;
286
+ } & RunOptions$1) => RunResult$1<Effects>;
287
+ runAsync: (input: {
288
+ facts: Facts;
289
+ } & RunOptions$1) => Promise<RunResult$1<Effects>>;
290
+ };
291
+ type RulesetBuilderWithDefaults<Facts, Effects> = RulesetBuilderImpl<Facts, Effects, true>;
292
+ type RulesetBuilder<Facts, Effects, HasDefaults extends boolean> = Omit<RulesetBuilderImpl<Facts, Effects, HasDefaults>, "compile"> & (HasDefaults extends true ? {
293
+ compile(): Engine<Facts, Effects>;
294
+ } : {
295
+ compile: never;
296
+ });
297
+ type RuleBuilder<Facts, Effects, HasDefaults extends boolean, HasThen extends boolean> = Omit<RuleBuilderImpl<Facts, Effects, HasDefaults, HasThen>, "end"> & (HasThen extends true ? {
298
+ end(): RulesetBuilder<Facts, Effects, HasDefaults>;
299
+ } : {
300
+ end: never;
301
+ });
302
+ declare class RulesetBuilderImpl<Facts, Effects, HasDefaults extends boolean> {
303
+ private readonly name?;
304
+ private readonly rules;
305
+ private defaultEffectsFactory?;
306
+ private validateFactsFn?;
307
+ private validateEffectsFn?;
308
+ private nextOrder;
309
+ private registryId?;
310
+ private telemetryAdapter?;
311
+ constructor(name?: string);
312
+ /**
313
+ * Set the default effects factory. Required before compile().
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * const rs = Rules.ruleset<Facts, Effects>("rs")
318
+ * .defaultEffects(() => ({ flags: [] }));
319
+ * ```
320
+ */
321
+ defaultEffects(factory: DefaultEffectsFactory<Effects>): RulesetBuilder<Facts, Effects, true>;
322
+ /**
323
+ * Provide a validation function for facts. Called before each run.
324
+ *
325
+ * @example
326
+ * ```ts
327
+ * const rs = Rules.ruleset<Facts, Effects>("validate")
328
+ * .validateFacts((facts) => {
329
+ * if (!facts.user) throw new Error("missing user");
330
+ * });
331
+ * ```
332
+ */
333
+ validateFacts(validator: (facts: Facts) => void): RulesetBuilder<Facts, Effects, HasDefaults>;
334
+ /**
335
+ * Provide a validation function for effects. Called after default effects creation
336
+ * and after each run completes.
337
+ *
338
+ * @example
339
+ * ```ts
340
+ * const rs = Rules.ruleset<Facts, Effects>("validate")
341
+ * .validateEffects((effects) => {
342
+ * if (!Array.isArray(effects.flags)) throw new Error("invalid effects");
343
+ * });
344
+ * ```
345
+ */
346
+ validateEffects(validator: (effects: Effects) => void): RulesetBuilder<Facts, Effects, HasDefaults>;
347
+ /**
348
+ * Attach telemetry adapter (OpenTelemetry-compatible).
349
+ *
350
+ * @example
351
+ * ```ts
352
+ * const adapter = Rules.otel.createAdapter(trace.getTracer("rulit"));
353
+ * Rules.ruleset("rs").telemetry(adapter);
354
+ * ```
355
+ */
356
+ telemetry(adapter: TelemetryAdapter$1): RulesetBuilder<Facts, Effects, HasDefaults>;
357
+ _setRegistryId(id: string): void;
358
+ /**
359
+ * Add a new rule to the ruleset.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * Rules.ruleset<Facts, Effects>("rs")
364
+ * .defaultEffects(() => ({ flags: [] }))
365
+ * .rule("vip")
366
+ * .when(factsField("user.tags").contains("vip"))
367
+ * .then(({ effects }) => effects.flags.push("vip"))
368
+ * .end();
369
+ * ```
370
+ */
371
+ rule(id: string): RuleBuilder<Facts, Effects, HasDefaults, false>;
372
+ /**
373
+ * Create a typed field helper bound to the facts type.
374
+ *
375
+ * @example
376
+ * ```ts
377
+ * const factsField = Rules.ruleset<Facts, Effects>("rs").field();
378
+ * const isAdult = factsField("user.age").gte(18);
379
+ * ```
380
+ */
381
+ field(): <P extends Path$1<Facts>>(path: P) => Field$1<Facts, P>;
382
+ _addRule(rule: Rule<Facts, Effects>): void;
383
+ _nextOrder(): number;
384
+ /**
385
+ * Export a graph representation of the ruleset.
386
+ *
387
+ * @example
388
+ * ```ts
389
+ * const graph = ruleset.graph();
390
+ * ```
391
+ */
392
+ graph(): RulesetGraph$1;
393
+ /**
394
+ * Export a Mermaid flowchart for visualization.
395
+ *
396
+ * @example
397
+ * ```ts
398
+ * const mermaid = ruleset.toMermaid();
399
+ * ```
400
+ */
401
+ toMermaid(): string;
402
+ /**
403
+ * Compile the ruleset into an engine.
404
+ *
405
+ * @example
406
+ * ```ts
407
+ * const engine = Rules.ruleset<Facts, Effects>("rs")
408
+ * .defaultEffects(() => ({ flags: [] }))
409
+ * .compile();
410
+ * ```
411
+ */
412
+ compile(this: RulesetBuilderWithDefaults<Facts, Effects>): Engine<Facts, Effects>;
413
+ }
414
+ declare class RuleBuilderImpl<Facts, Effects, HasDefaults extends boolean, HasThen extends boolean> {
415
+ private readonly ruleset;
416
+ private readonly id;
417
+ private priorityValue;
418
+ private conditions;
419
+ private action?;
420
+ private metaValue;
421
+ constructor(ruleset: RulesetBuilderImpl<Facts, Effects, HasDefaults>, id: string);
422
+ /**
423
+ * Set rule priority. Higher runs first.
424
+ *
425
+ * @example
426
+ * ```ts
427
+ * rule.priority(100);
428
+ * ```
429
+ */
430
+ priority(value: number): RuleBuilder<Facts, Effects, HasDefaults, HasThen>;
431
+ /**
432
+ * Add conditions to a rule.
433
+ *
434
+ * @example
435
+ * ```ts
436
+ * rule.when(factsField("user.age").gte(18), factsField("user.tags").contains("vip"));
437
+ * ```
438
+ */
439
+ when(...conditions: Condition$1<Facts>[]): RuleBuilder<Facts, Effects, HasDefaults, HasThen>;
440
+ /**
441
+ * Set rule metadata in one call.
442
+ *
443
+ * @example
444
+ * ```ts
445
+ * rule.meta({ tags: ["vip"], version: "1.0.0", reasonCode: "VIP_RULE" });
446
+ * ```
447
+ */
448
+ meta(meta: RuleMeta$1): RuleBuilder<Facts, Effects, HasDefaults, HasThen>;
449
+ /**
450
+ * Set rule tags used for filtering.
451
+ *
452
+ * @example
453
+ * ```ts
454
+ * rule.tags("vip", "adult");
455
+ * ```
456
+ */
457
+ tags(...tags: string[]): RuleBuilder<Facts, Effects, HasDefaults, HasThen>;
458
+ /**
459
+ * Set a human-readable description.
460
+ *
461
+ * @example
462
+ * ```ts
463
+ * rule.description("VIP adult rule");
464
+ * ```
465
+ */
466
+ description(description: string): RuleBuilder<Facts, Effects, HasDefaults, HasThen>;
467
+ /**
468
+ * Set a rule version string.
469
+ *
470
+ * @example
471
+ * ```ts
472
+ * rule.version("1.2.3");
473
+ * ```
474
+ */
475
+ version(version: string): RuleBuilder<Facts, Effects, HasDefaults, HasThen>;
476
+ /**
477
+ * Set a reason code for audit/explain output.
478
+ *
479
+ * @example
480
+ * ```ts
481
+ * rule.reasonCode("VIP_ADULT");
482
+ * ```
483
+ */
484
+ reasonCode(reasonCode: string): RuleBuilder<Facts, Effects, HasDefaults, HasThen>;
485
+ /**
486
+ * Enable or disable a rule.
487
+ *
488
+ * @example
489
+ * ```ts
490
+ * rule.enabled(false);
491
+ * ```
492
+ */
493
+ enabled(enabled: boolean): RuleBuilder<Facts, Effects, HasDefaults, HasThen>;
494
+ /**
495
+ * Set the rule action. Returning a partial effects object applies a patch.
496
+ *
497
+ * @example
498
+ * ```ts
499
+ * rule.then(({ effects }) => {
500
+ * effects.flags.push("vip");
501
+ * });
502
+ * ```
503
+ */
504
+ then(action: (ctx: ActionContext$1<Facts, Effects>) => ActionResult<Effects>): RuleBuilder<Facts, Effects, HasDefaults, true>;
505
+ /**
506
+ * Set an async rule action. Returning a partial effects object applies a patch.
507
+ *
508
+ * @example
509
+ * ```ts
510
+ * rule.thenAsync(async ({ effects }) => {
511
+ * effects.flags.push("vip");
512
+ * });
513
+ * ```
514
+ */
515
+ thenAsync(action: (ctx: ActionContext$1<Facts, Effects>) => Promise<ActionResult<Effects>>): RuleBuilder<Facts, Effects, HasDefaults, true>;
516
+ /**
517
+ * Finalize the rule and return to the ruleset builder.
518
+ *
519
+ * @example
520
+ * ```ts
521
+ * ruleset.rule("vip").then(() => undefined).end();
522
+ * ```
523
+ */
524
+ end(this: RuleBuilderImpl<Facts, Effects, HasDefaults, true>): RulesetBuilder<Facts, Effects, HasDefaults>;
525
+ }
526
+ /**
527
+ * Create a new ruleset builder.
528
+ *
529
+ * @example
530
+ * ```ts
531
+ * const rs = Rules.ruleset<Facts, Effects>("eligibility");
532
+ * ```
533
+ */
534
+ declare function ruleset<Facts, Effects>(name?: string): RulesetBuilder<Facts, Effects, false>;
535
+
536
+ /**
537
+ * Create a facts validator using a Zod schema.
538
+ *
539
+ * @example
540
+ * ```ts
541
+ * const factsSchema = z.object({ user: z.object({ age: z.number() }) });
542
+ * const rs = Rules.ruleset<Facts, Effects>("rs").validateFacts(Rules.zodFacts(factsSchema));
543
+ * ```
544
+ */
545
+ declare function zodFacts<Facts>(schema: ZodType<Facts>): (facts: Facts) => void;
546
+ /**
547
+ * Create an effects validator using a Zod schema.
548
+ *
549
+ * @example
550
+ * ```ts
551
+ * const effectsSchema = z.object({ flags: z.array(z.string()) });
552
+ * const rs = Rules.ruleset<Facts, Effects>("rs").validateEffects(Rules.zodEffects(effectsSchema));
553
+ * ```
554
+ */
555
+ declare function zodEffects<Effects>(schema: ZodType<Effects>): (effects: Effects) => void;
556
+
557
+ type GraphSource = {
558
+ graph: () => RulesetGraph$1;
559
+ toMermaid: () => string;
560
+ };
561
+ type RegistryListItem = {
562
+ id: string;
563
+ name?: string;
564
+ createdAt: number;
565
+ };
566
+ /**
567
+ * In-memory registry of rulesets created in this process.
568
+ */
569
+ declare const registry: {
570
+ /**
571
+ * Register a ruleset in the global registry.
572
+ *
573
+ * @example
574
+ * ```ts
575
+ * const rs = Rules.ruleset<Facts, Effects>("eligibility");
576
+ * Rules.registry.list();
577
+ * ```
578
+ */
579
+ register(source: GraphSource, name?: string): string;
580
+ /**
581
+ * List all registered rulesets.
582
+ *
583
+ * @example
584
+ * ```ts
585
+ * const list = Rules.registry.list();
586
+ * ```
587
+ */
588
+ list(): RegistryListItem[];
589
+ /**
590
+ * Get a graph by id or ruleset name.
591
+ *
592
+ * @example
593
+ * ```ts
594
+ * const graph = Rules.registry.getGraph("eligibility");
595
+ * ```
596
+ */
597
+ getGraph(idOrName: string): RulesetGraph$1 | undefined;
598
+ /**
599
+ * Get Mermaid output by id or ruleset name.
600
+ *
601
+ * @example
602
+ * ```ts
603
+ * const mermaid = Rules.registry.getMermaid("eligibility");
604
+ * ```
605
+ */
606
+ getMermaid(idOrName: string): string | undefined;
607
+ /**
608
+ * Record a trace run for a ruleset. Keeps a rolling window of traces.
609
+ *
610
+ * @example
611
+ * ```ts
612
+ * Rules.registry.recordTrace("eligibility", trace, fired);
613
+ * ```
614
+ */
615
+ recordTrace(idOrName: string, trace: RuleTrace$1[], fired: string[], facts: unknown): TraceRun$1 | undefined;
616
+ /**
617
+ * List trace runs for a ruleset.
618
+ *
619
+ * @example
620
+ * ```ts
621
+ * const traces = Rules.registry.listTraces("eligibility");
622
+ * ```
623
+ */
624
+ listTraces(idOrName: string): TraceRun$1[];
625
+ /**
626
+ * Get a trace by id for a ruleset.
627
+ *
628
+ * @example
629
+ * ```ts
630
+ * const trace = Rules.registry.getTrace("eligibility", "trace-0");
631
+ * ```
632
+ */
633
+ getTrace(idOrName: string, traceId: string): TraceRun$1 | undefined;
634
+ /**
635
+ * Clear the registry (useful in tests).
636
+ *
637
+ * @example
638
+ * ```ts
639
+ * Rules.registry.clear();
640
+ * ```
641
+ */
642
+ clear(): void;
643
+ };
644
+
645
+ type OtelSpanLike = {
646
+ end: () => void;
647
+ recordException?: (error: unknown) => void;
648
+ setAttribute?: (key: string, value: unknown) => void;
649
+ setAttributes?: (attributes: Record<string, unknown>) => void;
650
+ };
651
+ type OtelTracerLike = {
652
+ startSpan: (name: string, options?: {
653
+ attributes?: Record<string, unknown>;
654
+ }) => OtelSpanLike;
655
+ };
656
+ /**
657
+ * Create a telemetry adapter from an OpenTelemetry tracer.
658
+ *
659
+ * @example
660
+ * ```ts
661
+ * import { trace } from "@opentelemetry/api";
662
+ * const adapter = Rules.otel.createAdapter(trace.getTracer("rulit"));
663
+ * Rules.ruleset("rs").telemetry(adapter);
664
+ * ```
665
+ */
666
+ declare function createOtelAdapter(tracer: OtelTracerLike): TelemetryAdapter$1;
667
+
668
+ declare const Rules: {
669
+ ruleset: typeof ruleset;
670
+ condition: typeof condition;
671
+ field: typeof field;
672
+ op: {
673
+ and: {
674
+ <Facts>(...conditions: Condition$1<Facts>[]): Condition$1<Facts>;
675
+ <Facts>(label: string | {
676
+ label: string;
677
+ }, ...conditions: Condition$1<Facts>[]): Condition$1<Facts>;
678
+ };
679
+ or: {
680
+ <Facts>(...conditions: Condition$1<Facts>[]): Condition$1<Facts>;
681
+ <Facts>(label: string | {
682
+ label: string;
683
+ }, ...conditions: Condition$1<Facts>[]): Condition$1<Facts>;
684
+ };
685
+ not: {
686
+ <Facts>(conditionToNegate: Condition$1<Facts>): Condition$1<Facts>;
687
+ <Facts>(label: string | {
688
+ label: string;
689
+ }, conditionToNegate: Condition$1<Facts>): Condition$1<Facts>;
690
+ };
691
+ custom: <Facts>(label: string, test: (facts: Facts) => boolean, options?: ((facts: Facts) => Pick<ConditionTrace$1, "left" | "op" | "right">) | {
692
+ details?: (facts: Facts) => Pick<ConditionTrace$1, "left" | "op" | "right">;
693
+ reasonCode?: string;
694
+ }) => Condition$1<Facts>;
695
+ register: <Facts, Args extends unknown[]>(name: string, factory: (...args: Args) => Condition$1<Facts>) => void;
696
+ use: <Facts, Args extends unknown[]>(name: string, ...args: Args) => Condition$1<Facts>;
697
+ has: (name: string) => boolean;
698
+ list: () => string[];
699
+ };
700
+ registry: {
701
+ register(source: {
702
+ graph: () => RulesetGraph$1;
703
+ toMermaid: () => string;
704
+ }, name?: string): string;
705
+ list(): {
706
+ id: string;
707
+ name?: string;
708
+ createdAt: number;
709
+ }[];
710
+ getGraph(idOrName: string): RulesetGraph$1 | undefined;
711
+ getMermaid(idOrName: string): string | undefined;
712
+ recordTrace(idOrName: string, trace: RuleTrace$1[], fired: string[], facts: unknown): TraceRun$1 | undefined;
713
+ listTraces(idOrName: string): TraceRun$1[];
714
+ getTrace(idOrName: string, traceId: string): TraceRun$1 | undefined;
715
+ clear(): void;
716
+ };
717
+ zodFacts: typeof zodFacts;
718
+ zodEffects: typeof zodEffects;
719
+ otel: {
720
+ createAdapter: typeof createOtelAdapter;
721
+ };
722
+ };
723
+
724
+ type ActionContext<Facts, Effects> = ActionContext$1<Facts, Effects>;
725
+ type Condition<Facts> = Condition$1<Facts>;
726
+ type ConditionMeta<Facts> = ConditionMeta$1<Facts>;
727
+ type ConditionTrace = ConditionTrace$1;
728
+ type EffectsMode = EffectsMode$1;
729
+ type MergeStrategy = MergeStrategy$1;
730
+ type RuleActivation = RuleActivation$1;
731
+ type RuleMeta = RuleMeta$1;
732
+ type RulesetGraph = RulesetGraph$1;
733
+ type GraphNode = GraphNode$1;
734
+ type GraphEdge = GraphEdge$1;
735
+ type RuleTrace = RuleTrace$1;
736
+ type RunOptions = RunOptions$1;
737
+ type RunResult<Effects> = RunResult$1<Effects>;
738
+ type TraceRun = TraceRun$1;
739
+ type TelemetryAdapter = TelemetryAdapter$1;
740
+ type TelemetryAttributes = TelemetryAttributes$1;
741
+ type Field<T, P extends Path$1<T>> = Field$1<T, P>;
742
+ type Path<T> = Path$1<T>;
743
+ type PathValue<T, P extends Path$1<T>> = PathValue$1<T, P>;
744
+
745
+ export { type ActionContext, type Condition, type ConditionMeta, type ConditionTrace, type EffectsMode, type Field, type GraphEdge, type GraphNode, type MergeStrategy, type Path, type PathValue, type RuleActivation, type RuleMeta, type RuleTrace, Rules, type RulesetGraph, type RunOptions, type RunResult, type TelemetryAdapter, type TelemetryAttributes, type TraceRun, condition, createOtelAdapter, field, op, registry, ruleset, zodEffects, zodFacts };