@inixiative/json-rules 2.26.0 → 3.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.
package/dist/index.d.ts CHANGED
@@ -18,7 +18,9 @@ declare const Operator: {
18
18
  readonly exists: "exists";
19
19
  readonly notExists: "notExists";
20
20
  readonly startsWith: "startsWith";
21
+ readonly notStartsWith: "notStartsWith";
21
22
  readonly endsWith: "endsWith";
23
+ readonly notEndsWith: "notEndsWith";
22
24
  };
23
25
  type Operator = (typeof Operator)[keyof typeof Operator];
24
26
  declare const ArrayOperator: {
@@ -48,12 +50,95 @@ declare const DateOperator: {
48
50
  };
49
51
  type DateOperator = (typeof DateOperator)[keyof typeof DateOperator];
50
52
 
53
+ /** A selectable option — the standard `<select>` shape: a value with an optional display
54
+ * label, plus the partition keys (index-aligned with the source's `groupBy` axes)
55
+ * when the source is grouped. */
56
+ type SourceOption = {
57
+ value: string;
58
+ label?: string;
59
+ groups?: string[];
60
+ };
61
+ type FieldMapEntry = {
62
+ kind: 'scalar' | 'object' | 'enum' | 'bridge';
63
+ type: string;
64
+ isList?: boolean;
65
+ /**
66
+ * Whether the column is NOT NULL. `toPrisma` reads this to decide if a negated
67
+ * operator needs an explicit `equals: null` arm (Prisma's `not`/`notIn` follow SQL
68
+ * three-valued logic and drop NULL rows); absent = unknown = no arm.
69
+ */
70
+ isRequired?: boolean;
71
+ fromFields?: string[];
72
+ toFields?: string[];
73
+ relationName?: string;
74
+ /**
75
+ * Per-field allowed values, primarily for enum fields. Takes precedence over
76
+ * `FieldMap.enums[type]` if both are set. Pass-through from codegen
77
+ * (e.g. prisma-map's `EnumField.values`). Consumed by `validateRuleInLens`.
78
+ */
79
+ values?: readonly string[];
80
+ /**
81
+ * A field's selectable option set as `{ value, label? }` pairs — the display
82
+ * shape a picker consumes. On projection/surface output this is populated for
83
+ * every value-gated field (enum members normalized to `{ value, label: value }`)
84
+ * and for sourced fields (the fetched pairs from a materialized `SourceValues`).
85
+ */
86
+ options?: readonly SourceOption[];
87
+ /**
88
+ * Present on projection/surface output when the field's source partitions its
89
+ * options: the dotted to-one axes (relative to this model) whose values are
90
+ * each option's `groups`, index-aligned.
91
+ */
92
+ groupBy?: readonly string[];
93
+ };
94
+ type ModelEntry = {
95
+ dbName?: string | null;
96
+ fields: Record<string, FieldMapEntry>;
97
+ };
98
+ /**
99
+ * A schema map: models keyed by name, plus an optional enum registry scoped to
100
+ * this source. In multi-source setups (Prisma + Salesforce + CRM) each FieldMap
101
+ * carries its own enums so namespaces don't collide across sources.
102
+ */
103
+ type FieldMap = {
104
+ models: Record<string, ModelEntry>;
105
+ /** Enum name → allowed values, e.g. `{ UserRole: ['ADMIN', 'USER'] }`. */
106
+ enums?: Record<string, readonly string[]>;
107
+ };
108
+ type BridgeEndpoint = {
109
+ fieldMap: string;
110
+ model: string;
111
+ on: string;
112
+ };
113
+ type BridgeCardinality = 'oneToOne' | 'oneToMany';
114
+ /**
115
+ * A cross-source edge between two endpoints.
116
+ *
117
+ * Endpoint ordering convention for `oneToMany`:
118
+ * - `endpoints[0]` is the "one" side — its `on` field must be unique per row
119
+ * (typically a primary key).
120
+ * - `endpoints[1]` is the "many" side — its `on` field may repeat across rows
121
+ * (typically a foreign key).
122
+ *
123
+ * Mis-ordering produces wrong `isList` flags during stitching and silent
124
+ * row-dedup when building bridge dictionaries. `indexBridges` throws
125
+ * at runtime if endpoint[0]'s data has duplicate `on` values to catch this.
126
+ *
127
+ * For `oneToOne`, both `on` fields must be unique; endpoint order is symmetric.
128
+ */
129
+ type Bridge = {
130
+ endpoints: [BridgeEndpoint, BridgeEndpoint];
131
+ cardinality: BridgeCardinality;
132
+ };
133
+ type FieldMapSet = {
134
+ maps: Record<string, FieldMap>;
135
+ bridges?: Bridge[];
136
+ };
137
+
51
138
  type FuzzyConfig = {
52
139
  maxDistance?: number;
53
140
  maxRatio?: number;
54
141
  };
55
- declare const maxFuzzyDistance: (length: number) => number;
56
- declare const fuzzyContains: (haystack: string, query: string, config?: FuzzyConfig) => boolean;
57
142
 
58
143
  declare const FieldKind: {
59
144
  readonly String: "String";
@@ -69,11 +154,7 @@ declare const FieldKind: {
69
154
  };
70
155
  type FieldKind = (typeof FieldKind)[keyof typeof FieldKind];
71
156
  declare const NUMERIC_KINDS: readonly FieldKind[];
72
- declare const ORDERABLE_KINDS: readonly FieldKind[];
73
- declare const STRINGY_KINDS: readonly FieldKind[];
74
- declare const EQUATABLE_KINDS: readonly FieldKind[];
75
157
  declare const ALL_KINDS: readonly FieldKind[];
76
- declare const NULLABLE_KINDS: readonly FieldKind[];
77
158
  declare const RuleTarget: {
78
159
  readonly check: "check";
79
160
  readonly toPrisma: "toPrisma";
@@ -96,57 +177,15 @@ declare const ValueShape: {
96
177
  readonly predicate: "predicate";
97
178
  };
98
179
  type ValueShape = (typeof ValueShape)[keyof typeof ValueShape];
99
- type CatalogEntry = {
100
- kinds: readonly FieldKind[];
101
- targets: readonly RuleTarget[];
102
- valueShape: ValueShape;
103
- acceptsExpr?: boolean;
104
- };
105
- declare const FIELD_OPERATOR_CATALOG: Record<Operator, CatalogEntry>;
106
- declare const DATE_OPERATOR_CATALOG: Record<DateOperator, CatalogEntry>;
107
- type ArrayCatalogEntry = {
108
- targets: readonly RuleTarget[];
109
- valueShape: ValueShape;
110
- };
111
- declare const ARRAY_OPERATOR_CATALOG: Record<ArrayOperator, ArrayCatalogEntry>;
112
- declare const WindowSupport: {
113
- readonly full: "full";
114
- readonly extremal: "extremal";
115
- readonly none: "none";
116
- };
117
- type WindowSupport = (typeof WindowSupport)[keyof typeof WindowSupport];
118
- declare const WINDOW_SELECTOR: {
119
- readonly fields: readonly ["filter", "orderBy", "take", "skip"];
120
- readonly sortDirs: readonly ["asc", "desc"];
121
- readonly support: {
122
- readonly array: {
123
- readonly check: "full";
124
- readonly toPrisma: "extremal";
125
- readonly toSql: "none";
126
- };
127
- readonly aggregate: {
128
- readonly check: "full";
129
- readonly toPrisma: "none";
130
- readonly toSql: "none";
131
- };
132
- };
133
- };
134
- type WindowRuleType = keyof typeof WINDOW_SELECTOR.support;
135
- declare const getWindowSupport: (ruleType: WindowRuleType, target: RuleTarget) => WindowSupport;
136
- declare const AGGREGATE_OPERATORS: readonly Operator[];
137
- /** The aggregate threshold comparisons `target` can compile — all of them when no
138
- * target is given. The one source for both the validator's rejection and a builder's
139
- * threshold picker, so neither has to restate which target drops which operator. */
140
- declare const getAggregateOperators: (target?: RuleTarget) => readonly Operator[];
141
- declare const isAggregateSingleOperator: (operator: Operator) => boolean;
142
- declare const isAggregateRangeOperator: (operator: Operator) => boolean;
143
- declare const getValueShape: (operator: Operator | DateOperator | ArrayOperator) => ValueShape;
144
- declare const isOperatorSupportedForTarget: (operator: Operator | DateOperator | ArrayOperator, target: RuleTarget) => boolean;
180
+ /** Which catalog an operator belongs to — `between` is both a field and a date operator. */
181
+ type OperatorFamily = 'field' | 'date' | 'array';
182
+ declare const getValueShape: (operator: string, family: OperatorFamily) => ValueShape;
145
183
  declare const getOperatorsForKind: (kind: FieldKind, target?: RuleTarget) => {
146
184
  field: Operator[];
147
185
  date: DateOperator[];
148
186
  };
149
187
  declare const getArrayOperators: (target?: RuleTarget) => ArrayOperator[];
188
+ declare const getAggregateOperators: () => readonly Operator[];
150
189
 
151
190
  type OperatorValues = typeof Operator;
152
191
  type ArrayOperatorValues = typeof ArrayOperator;
@@ -158,21 +197,33 @@ type RuleValue = RuleScalar | Date | RegExp | RuleValue[] | {
158
197
  };
159
198
  type OrderedRuleValue = string | number | Date;
160
199
  type DateInputValue = string | number | Date;
161
- type RelativeUnits = {
162
- years?: number;
163
- quarters?: number;
164
- months?: number;
165
- weeks?: number;
166
- days?: number;
167
- hours?: number;
168
- minutes?: number;
169
- seconds?: number;
200
+ type SourceSlots<TValue> = {
201
+ value: TValue;
202
+ path: string;
203
+ bind: string;
204
+ bindOptional: boolean;
205
+ };
206
+ type Never<K extends PropertyKey> = {
207
+ [P in K]?: never;
208
+ };
209
+ type ValueSourceOf<TValue> = (Pick<SourceSlots<TValue>, 'value'> & Never<'path' | 'bind' | 'bindOptional'>) | (Pick<SourceSlots<TValue>, 'path'> & Never<'value' | 'bind' | 'bindOptional'>) | (Pick<SourceSlots<TValue>, 'bind'> & Partial<Pick<SourceSlots<TValue>, 'bindOptional'>> & Never<'value' | 'path'>);
210
+ type ValueSourceFields<TValue> = Partial<SourceSlots<TValue>>;
211
+ type Magnitude = number | ValueSourceOf<number>;
212
+ type RelativeUnits<TAmount = Magnitude> = {
213
+ years?: TAmount;
214
+ quarters?: TAmount;
215
+ months?: TAmount;
216
+ weeks?: TAmount;
217
+ days?: TAmount;
218
+ hours?: TAmount;
219
+ minutes?: TAmount;
220
+ seconds?: TAmount;
170
221
  };
171
222
  type PeriodUnit = 'year' | 'quarter' | 'month' | 'week' | 'isoWeek' | 'day' | 'hour' | 'minute' | 'second';
172
- type RollingExpr = {
173
- ago: RelativeUnits;
223
+ type RollingExpr<TAmount = Magnitude> = {
224
+ ago: RelativeUnits<TAmount>;
174
225
  } | {
175
- ahead: RelativeUnits;
226
+ ahead: RelativeUnits<TAmount>;
176
227
  };
177
228
  type PeriodExpr = {
178
229
  this: PeriodUnit;
@@ -186,38 +237,22 @@ type EdgeExpr = {
186
237
  } | {
187
238
  end: PeriodExpr;
188
239
  };
189
- type DateExpr = RollingExpr | PeriodExpr | EdgeExpr;
240
+ type DateExpr<TAmount = Magnitude> = RollingExpr<TAmount> | PeriodExpr | EdgeExpr;
190
241
  type DateInputOrExpr = DateInputValue | DateExpr;
191
242
  type DateRuleValue = DateInputValue | DateExpr | [DateInputOrExpr, DateInputOrExpr] | string[];
192
243
  type WeekStart = 'monday' | 'sunday';
193
- type TimeZoneConfig = string | {
194
- bind: string;
195
- };
244
+ type TimeZoneConfig = string | ValueSourceOf<string>;
196
245
  type DateConfig = {
197
246
  now?: DateInputValue;
198
247
  timeZone?: TimeZoneConfig;
199
248
  weekStart?: WeekStart;
200
249
  };
201
- type ValueSource<TValue> = {
202
- value: TValue;
203
- path?: never;
204
- bind?: never;
205
- bindOptional?: never;
206
- } | {
207
- path: string;
208
- value?: never;
209
- bind?: never;
210
- bindOptional?: never;
211
- } | {
212
- bind: string;
213
- bindOptional?: boolean;
214
- value?: never;
215
- path?: never;
216
- };
217
- type NoValueSource = {
218
- value?: never;
219
- path?: never;
250
+ type ValueSource<TValue, TOffset = never> = ValueSourceOf<TValue> & {
251
+ offset?: TOffset;
220
252
  };
253
+ type NumberOffset = ValueSourceOf<number>;
254
+ type DateOffset = ValueSourceOf<RollingExpr>;
255
+ type NoValueSource = Never<keyof SourceSlots<unknown> | 'offset'>;
221
256
  type RuleBase<TOperator extends Operator> = {
222
257
  field: string;
223
258
  operator: TOperator;
@@ -230,13 +265,13 @@ type DateRuleBase<TOperator extends DateOperator> = {
230
265
  dateOperator: TOperator;
231
266
  error?: string;
232
267
  };
233
- type StrictEqualityRule<TValue = RuleValue> = (RuleBase<OperatorValues['equals']> & ValueSource<TValue>) | (RuleBase<OperatorValues['notEquals']> & ValueSource<TValue>);
234
- type StrictOrderedComparisonRule = (RuleBase<OperatorValues['lessThan']> & ValueSource<OrderedRuleValue>) | (RuleBase<OperatorValues['lessThanEquals']> & ValueSource<OrderedRuleValue>) | (RuleBase<OperatorValues['greaterThan']> & ValueSource<OrderedRuleValue>) | (RuleBase<OperatorValues['greaterThanEquals']> & ValueSource<OrderedRuleValue>);
268
+ type StrictEqualityRule<TValue = RuleValue> = (RuleBase<OperatorValues['equals']> & ValueSource<TValue, NumberOffset>) | (RuleBase<OperatorValues['notEquals']> & ValueSource<TValue, NumberOffset>);
269
+ type StrictOrderedComparisonRule = (RuleBase<OperatorValues['lessThan']> & ValueSource<OrderedRuleValue, NumberOffset>) | (RuleBase<OperatorValues['lessThanEquals']> & ValueSource<OrderedRuleValue, NumberOffset>) | (RuleBase<OperatorValues['greaterThan']> & ValueSource<OrderedRuleValue, NumberOffset>) | (RuleBase<OperatorValues['greaterThanEquals']> & ValueSource<OrderedRuleValue, NumberOffset>);
235
270
  type StrictMembershipRule<TValue = RuleValue> = (RuleBase<OperatorValues['in']> & ValueSource<TValue[]>) | (RuleBase<OperatorValues['notIn']> & ValueSource<TValue[]>);
236
271
  type StrictContainsRule<TValue = RuleValue> = (RuleBase<OperatorValues['contains']> & ValueSource<TValue>) | (RuleBase<OperatorValues['notContains']> & ValueSource<TValue>);
237
272
  type StrictPatternRule = (RuleBase<OperatorValues['matches']> & ValueSource<RegExp | string>) | (RuleBase<OperatorValues['notMatches']> & ValueSource<RegExp | string>);
238
- type StrictStringBoundaryRule = (RuleBase<OperatorValues['startsWith']> & ValueSource<string>) | (RuleBase<OperatorValues['endsWith']> & ValueSource<string>);
239
- type StrictRangeRule = (RuleBase<OperatorValues['between']> & ValueSource<[OrderedRuleValue, OrderedRuleValue]>) | (RuleBase<OperatorValues['notBetween']> & ValueSource<[OrderedRuleValue, OrderedRuleValue]>);
273
+ type StrictStringBoundaryRule = (RuleBase<OperatorValues['startsWith']> & ValueSource<string>) | (RuleBase<OperatorValues['notStartsWith']> & ValueSource<string>) | (RuleBase<OperatorValues['endsWith']> & ValueSource<string>) | (RuleBase<OperatorValues['notEndsWith']> & ValueSource<string>);
274
+ type StrictRangeRule = (RuleBase<OperatorValues['between']> & ValueSource<[OrderedRuleValue, OrderedRuleValue], NumberOffset>) | (RuleBase<OperatorValues['notBetween']> & ValueSource<[OrderedRuleValue, OrderedRuleValue], NumberOffset>);
240
275
  type StrictPresenceRule = (RuleBase<OperatorValues['isEmpty']> & NoValueSource) | (RuleBase<OperatorValues['notEmpty']> & NoValueSource) | (RuleBase<OperatorValues['exists']> & NoValueSource) | (RuleBase<OperatorValues['notExists']> & NoValueSource);
241
276
  type StrictRule<TValue = RuleValue> = StrictEqualityRule<TValue> | StrictOrderedComparisonRule | StrictMembershipRule<TValue> | StrictContainsRule<TValue> | StrictPatternRule | StrictStringBoundaryRule | StrictRangeRule | StrictPresenceRule;
242
277
  type ArrayRuleBase<TOperator extends ArrayOperator> = {
@@ -272,15 +307,9 @@ type StrictArrayPresenceRule = (ArrayRuleBase<ArrayOperatorValues['empty']> & {
272
307
  count?: never;
273
308
  });
274
309
  type StrictArrayRule<TRuleValue = RuleValue, TDateValue = DateRuleValue> = StrictArrayPredicateRule<TRuleValue, TDateValue> | StrictArrayCountRule<TRuleValue, TDateValue> | StrictArrayPresenceRule;
275
- type StrictDateComparisonRule = (DateRuleBase<DateOperatorValues['before']> & ValueSource<DateInputValue>) | (DateRuleBase<DateOperatorValues['after']> & ValueSource<DateInputValue>) | (DateRuleBase<DateOperatorValues['onOrBefore']> & ValueSource<DateInputValue>) | (DateRuleBase<DateOperatorValues['onOrAfter']> & ValueSource<DateInputValue>) | (DateRuleBase<DateOperatorValues['notBefore']> & ValueSource<DateInputValue>) | (DateRuleBase<DateOperatorValues['notAfter']> & ValueSource<DateInputValue>);
276
- type StrictDateRangeRule = (DateRuleBase<DateOperatorValues['between']> & ValueSource<[DateInputValue, DateInputValue]>) | (DateRuleBase<DateOperatorValues['notBetween']> & ValueSource<[DateInputValue, DateInputValue]>);
277
- type StrictDateDayRule = (DateRuleBase<DateOperatorValues['dayIn']> & {
278
- value: string[];
279
- path?: never;
280
- }) | (DateRuleBase<DateOperatorValues['dayNotIn']> & {
281
- value: string[];
282
- path?: never;
283
- });
310
+ type StrictDateComparisonRule = (DateRuleBase<DateOperatorValues['before']> & ValueSource<DateInputValue, DateOffset>) | (DateRuleBase<DateOperatorValues['after']> & ValueSource<DateInputValue, DateOffset>) | (DateRuleBase<DateOperatorValues['onOrBefore']> & ValueSource<DateInputValue, DateOffset>) | (DateRuleBase<DateOperatorValues['onOrAfter']> & ValueSource<DateInputValue, DateOffset>) | (DateRuleBase<DateOperatorValues['notBefore']> & ValueSource<DateInputValue, DateOffset>) | (DateRuleBase<DateOperatorValues['notAfter']> & ValueSource<DateInputValue, DateOffset>);
311
+ type StrictDateRangeRule = (DateRuleBase<DateOperatorValues['between']> & ValueSource<[DateInputValue, DateInputValue], DateOffset>) | (DateRuleBase<DateOperatorValues['notBetween']> & ValueSource<[DateInputValue, DateInputValue], DateOffset>);
312
+ type StrictDateDayRule = (DateRuleBase<DateOperatorValues['dayIn']> & ValueSource<string[]>) | (DateRuleBase<DateOperatorValues['dayNotIn']> & ValueSource<string[]>);
284
313
  type StrictDateRule = StrictDateComparisonRule | StrictDateRangeRule | StrictDateDayRule;
285
314
  type AggregateRuleBase<TRuleValue = RuleValue, TDateValue = DateRuleValue> = {
286
315
  field: string;
@@ -317,19 +346,12 @@ type AggregateRule<TRuleValue = RuleValue, TDateValue = DateRuleValue> = WindowF
317
346
  };
318
347
  condition?: Condition<TRuleValue, TDateValue>;
319
348
  operator: Operator;
320
- value?: number | [number, number];
321
- path?: string;
322
- bind?: string;
323
- bindOptional?: boolean;
324
349
  error?: string;
325
- };
326
- type Rule<TValue = RuleValue> = {
350
+ } & ValueSourceFields<number | [number, number]>;
351
+ type Rule<TValue = RuleValue> = ValueSourceFields<TValue> & {
327
352
  field: string;
328
353
  operator: Operator;
329
- value?: TValue;
330
- path?: string;
331
- bind?: string;
332
- bindOptional?: boolean;
354
+ offset?: NumberOffset;
333
355
  error?: string;
334
356
  caseInsensitive?: boolean;
335
357
  fuzzy?: boolean | FuzzyConfig;
@@ -342,13 +364,10 @@ type ArrayRule<TRuleValue = RuleValue, TDateValue = DateRuleValue> = WindowField
342
364
  count?: number;
343
365
  error?: string;
344
366
  };
345
- type DateRule<TValue = DateRuleValue> = {
367
+ type DateRule<TValue = DateRuleValue> = ValueSourceFields<TValue> & {
346
368
  field: string;
347
369
  dateOperator: DateOperator;
348
- value?: TValue;
349
- path?: string;
350
- bind?: string;
351
- bindOptional?: boolean;
370
+ offset?: DateOffset;
352
371
  error?: string;
353
372
  };
354
373
  type All<TRuleValue = RuleValue, TDateValue = DateRuleValue> = {
@@ -381,24 +400,36 @@ type StrictIfThenElse<TRuleValue = RuleValue, TDateValue = DateRuleValue> = {
381
400
  error?: string;
382
401
  };
383
402
  type StrictCondition<TRuleValue = RuleValue, TDateValue = DateRuleValue> = StrictRule<TRuleValue> | StrictAggregateRule<TRuleValue, TDateValue> | StrictArrayRule<TRuleValue, TDateValue> | StrictDateRule | StrictAll<TRuleValue, TDateValue> | StrictAny<TRuleValue, TDateValue> | StrictIfThenElse<TRuleValue, TDateValue> | boolean;
403
+ /** A row as a rule reads it: a record of fields. */
404
+ type Row = Record<string, unknown>;
405
+ /** What both compilers take: the schema (a FieldMap, or a FieldMapSet with `mapName`), the
406
+ * model the rule reads, the context `$` refs read, and the clock. */
407
+ type CompileOptions = {
408
+ map?: FieldMap | FieldMapSet;
409
+ mapName?: string;
410
+ model?: string;
411
+ context?: Row;
412
+ } & DateConfig;
413
+ /** What check() evaluates: one row, or a root array of them. */
414
+ type CheckData = Row | unknown[];
384
415
 
385
- /** Names of every `{ bind }` token in the tree, optional or not — what a lens declares. */
386
- declare const bindingNames: (condition: Condition) => Set<string>;
416
+ /** `required`: leave out the names an optional bind (`bindOptional`) may go unsupplied. */
417
+ type ListBindingsOptions = {
418
+ required?: boolean;
419
+ };
387
420
  /**
388
- * Names a bindings map must cover: every `{ bind }` token not marked `bindOptional`. A
389
- * name that is optional at one leaf and required at another is required. An optional
390
- * name left unsupplied evaluates and compiles as `null`.
421
+ * The bind names a rule reads, sorted. With `required`, only those a bindings map must cover —
422
+ * not `bindOptional` (unsupplied, it reads null); a name optional at one leaf and required at
423
+ * another is required.
391
424
  */
392
- declare const requiredBindings: (condition: Condition) => Set<string>;
425
+ declare const listBindings: (condition: Condition, { required }?: ListBindingsOptions) => string[];
393
426
  /**
394
427
  * Substitute covered binds with their values; uncovered tokens stay in place (partial
395
428
  * resolution). A supplied-but-undefined binding becomes null to stay serializable.
396
429
  * Non-mutating.
397
430
  */
398
- declare const resolveBindings: (condition: Condition, bindings: Record<string, RuleValue>) => Condition;
431
+ declare const bindRule: (condition: Condition, bindings: Record<string, RuleValue>) => Condition;
399
432
 
400
- type Row$3 = Record<string, unknown>;
401
- type CheckData = Row$3 | unknown[];
402
433
  type CheckOptions = {
403
434
  context?: CheckData;
404
435
  bindings?: Record<string, RuleValue>;
@@ -415,6 +446,9 @@ type EngineGlobalsState = {
415
446
  datasource: {
416
447
  provider: PrismaProvider;
417
448
  };
449
+ /** Prisma's `AnyNull` — matches a DB NULL, a JSON null and an absent Json path. Defaults to
450
+ * your installed @prisma/client's; set it only to use another. */
451
+ anyNull?: unknown;
418
452
  };
419
453
  };
420
454
  type DeepPartial<T> = {
@@ -426,137 +460,33 @@ declare const engineGlobals: {
426
460
  reset: () => void;
427
461
  with: <T>(partial: DeepPartial<EngineGlobalsState>, fn: () => T) => T;
428
462
  };
429
- declare const supportsQueryMode: (provider: PrismaProvider) => boolean;
430
- declare const resolveCaseInsensitive: (ruleFlag?: boolean) => boolean;
431
- declare const resolveFuzzy: (ruleFlag?: boolean | FuzzyConfig) => FuzzyConfig | false;
432
463
 
433
- type PrismaWhere = Record<string, unknown>;
434
- /** A selectable option — the standard `<select>` shape: a value with an optional display
435
- * label, plus the partition keys (index-aligned with the source's `groupBy` axes)
436
- * when the source is grouped. */
437
- type SourceOption = {
438
- value: string;
439
- label?: string;
440
- groups?: string[];
441
- };
442
- type FieldMapEntry = {
443
- kind: 'scalar' | 'object' | 'enum' | 'bridge';
444
- type: string;
445
- isList?: boolean;
446
- /**
447
- * Whether the column is NOT NULL. `toPrisma` reads this to decide if a negated
448
- * operator needs an explicit `equals: null` arm (Prisma's `not`/`notIn` follow SQL
449
- * three-valued logic and drop NULL rows); absent = unknown = no arm.
450
- */
451
- isRequired?: boolean;
452
- fromFields?: string[];
453
- toFields?: string[];
454
- relationName?: string;
455
- /**
456
- * Per-field allowed values, primarily for enum fields. Takes precedence over
457
- * `FieldMap.enums[type]` if both are set. Pass-through from codegen
458
- * (e.g. prisma-map's `EnumField.values`). Consumed by `checkRuleAgainstLens`.
459
- */
460
- values?: readonly string[];
461
- /**
462
- * A field's selectable option set as `{ value, label? }` pairs — the display
463
- * shape a picker consumes. On projection/surface output this is populated for
464
- * every value-gated field (enum members normalized to `{ value, label: value }`)
465
- * and for sourced fields (the fetched pairs from a materialized `SourceValues`).
466
- */
467
- options?: readonly SourceOption[];
468
- /**
469
- * Present on projection/surface output when the field's source partitions its
470
- * options: the dotted to-one axes (relative to this model) whose values are
471
- * each option's `groups`, index-aligned.
472
- */
473
- groupBy?: readonly string[];
474
- };
475
- type ModelEntry = {
476
- dbName?: string | null;
477
- fields: Record<string, FieldMapEntry>;
478
- };
479
- /**
480
- * A schema map: models keyed by name, plus an optional enum registry scoped to
481
- * this source. In multi-source setups (Prisma + Salesforce + CRM) each FieldMap
482
- * carries its own enums so namespaces don't collide across sources.
483
- */
484
- type FieldMap = {
485
- models: Record<string, ModelEntry>;
486
- /** Enum name → allowed values, e.g. `{ UserRole: ['ADMIN', 'USER'] }`. */
487
- enums?: Record<string, readonly string[]>;
488
- };
489
- type StepRef = {
490
- __step: number;
491
- };
492
- type GroupByStep = {
493
- operation: 'groupBy';
494
- model: string;
495
- args: {
496
- by: string[];
497
- where: Record<string, unknown>;
498
- having: Record<string, unknown>;
499
- };
500
- extract: string;
501
- };
502
- type WhereStep = {
503
- operation: 'where';
504
- where: Record<string, unknown>;
505
- };
506
- type PrismaStep = GroupByStep | WhereStep;
507
- type ToPrismaResult = {
508
- steps: PrismaStep[];
509
- };
510
- type BuildOptions = {
511
- map?: FieldMap | FieldMapSet;
512
- mapName?: string;
513
- model?: string;
514
- context?: Record<string, unknown>;
515
- datasource?: {
516
- provider?: PrismaProvider;
517
- };
518
- } & DateConfig;
519
-
520
- type BridgeEndpoint = {
521
- fieldMap: string;
522
- model: string;
523
- on: string;
524
- };
525
- type BridgeCardinality = 'oneToOne' | 'oneToMany';
526
- /**
527
- * A cross-source edge between two endpoints.
528
- *
529
- * Endpoint ordering convention for `oneToMany`:
530
- * - `endpoints[0]` is the "one" side — its `on` field must be unique per row
531
- * (typically a primary key).
532
- * - `endpoints[1]` is the "many" side — its `on` field may repeat across rows
533
- * (typically a foreign key).
534
- *
535
- * Mis-ordering produces wrong `isList` flags during stitching and silent
536
- * row-dedup when building bridge dictionaries. `buildBridgeDictionary` throws
537
- * at runtime if endpoint[0]'s data has duplicate `on` values to catch this.
538
- *
539
- * For `oneToOne`, both `on` fields must be unique; endpoint order is symmetric.
540
- */
541
- type Bridge = {
542
- endpoints: [BridgeEndpoint, BridgeEndpoint];
543
- cardinality: BridgeCardinality;
544
- };
545
- type FieldMapSet = {
546
- maps: Record<string, FieldMap>;
547
- bridges?: Bridge[];
548
- };
549
-
550
- type Row$2 = Record<string, unknown>;
551
464
  type BridgeDictionary = Record<string, // map name
552
465
  Record<string, // model name
553
- Record<string, Record<string, Row$2 | Row$2[]>>>>;
554
- declare const buildBridgeDictionary: (set: FieldMapSet, rawData: Record<string, Row$2[]>) => BridgeDictionary;
466
+ Record<string, Record<string, Row | Row[]>>>>;
467
+ declare const indexBridges: (set: FieldMapSet, rawData: Record<string, Row[]>) => BridgeDictionary;
555
468
 
556
469
  declare const stitchFieldMaps: (set: FieldMapSet) => FieldMapSet;
557
470
 
558
- declare const validateFieldMapSet: (set: FieldMapSet) => void;
559
- declare const validateFieldMap: (fieldMap: FieldMap, mapName?: string) => void;
471
+ type ValidationIssue = {
472
+ path: string;
473
+ message: string;
474
+ code: string;
475
+ };
476
+ type ValidationResult = {
477
+ ok: boolean;
478
+ errors: ValidationIssue[];
479
+ };
480
+ /** Which engine a rule must compile for; `check` (the default) accepts every rule. */
481
+ type ValidateRuleOptions = {
482
+ target?: RuleTarget;
483
+ };
484
+ declare const validateRule: (condition: unknown, options?: ValidateRuleOptions) => ValidationResult;
485
+ declare const assertValidRule: (condition: unknown, options?: ValidateRuleOptions) => asserts condition is Condition;
486
+
487
+ /** Field names are plain identifiers: `.` walks a path and `:` names a bridge target. */
488
+ declare const validateFieldMaps: (set: FieldMapSet) => ValidationResult;
489
+ declare const assertValidFieldMaps: (set: FieldMapSet) => void;
560
490
 
561
491
  type Lens = FieldMapSet & {
562
492
  mapName: string;
@@ -570,8 +500,8 @@ type Lens = FieldMapSet & {
570
500
  * - SCHEMA narrowing (picks/omits/enumPicks/enumOmits): controls what's visible
571
501
  * in the type surface. AI/SDK consumers can't see narrowed-away fields.
572
502
  * - DATA narrowing (where): controls which ROWS are in scope. Filter-first
573
- * semantic, anchored to the model. Under arrayOperator: 'all', applied via
574
- * implication (negate) to preserve filter-first meaning — see applyLens.
503
+ * semantic, anchored to the model. Under arrayOperator: 'all', it becomes the window filter
504
+ * (filter-first) — see narrowRule.
575
505
  */
576
506
  type ModelDefaultNarrowing = {
577
507
  picks?: string[];
@@ -594,7 +524,7 @@ type ModelDefaultNarrowing = {
594
524
  * model that path resolves to. The `where` composes AND-only across layers (general
595
525
  * via `mapDefaults`, path-specific via `root`/`relations`); a later layer's `label` wins.
596
526
  */
597
- sources?: Record<string, SourceValue>;
527
+ sources?: Record<string, SourceEntry>;
598
528
  };
599
529
  /**
600
530
  * A sourced field's eligibility `where` plus an optional display-label column — a
@@ -618,7 +548,7 @@ type SourceSpec = {
618
548
  groupBy: string | string[];
619
549
  };
620
550
  /** A `sources` entry: a bare eligibility `Condition`, or a richer `SourceSpec`. */
621
- type SourceValue = Condition | SourceSpec;
551
+ type SourceEntry = Condition | SourceSpec;
622
552
  /** Narrowing for a model at a specific traversal path. Adds relations to the default shape. */
623
553
  type ModelNarrowing = ModelDefaultNarrowing & {
624
554
  relations?: Record<string, ModelNarrowing>;
@@ -647,8 +577,6 @@ type LensNarrowing = {
647
577
  mapDefaults?: Record<string, NarrowingDefaults>;
648
578
  };
649
579
 
650
- declare const applyLens: (rule: Condition, lensOrNarrowing: Lens | LensNarrowing) => Condition;
651
-
652
580
  /**
653
581
  * Every bind name a lens (its whole narrowing chain) needs supplied to execute —
654
582
  * `bindOptional` tokens are not required (unsupplied, they resolve to null).
@@ -657,29 +585,74 @@ declare const applyLens: (rule: Condition, lensOrNarrowing: Lens | LensNarrowing
657
585
  * this lens require" answer; pass `narrowing.parent` to see the names a child must
658
586
  * not collide with.
659
587
  */
660
- declare const lensRequiredBindings: (lensOrNarrowing: Lens | LensNarrowing) => Set<string>;
588
+ declare const listLensBindings: (lensOrNarrowing: Lens | LensNarrowing) => string[];
661
589
  /**
662
590
  * Preprocess a lens: resolve every `{ bind }` token the map covers in the chain's
663
591
  * `where`/`sources`, returning a structurally-new lens with concrete conditions.
664
592
  * Partial — uncovered tokens stay, so stages bind progressively. Once resolved,
665
- * `applyLens` / `toPrisma` / `toSql` / `sourceQueries` / `projectByPath` consume the
593
+ * `narrowRule` / `toPrisma` / `toSql` / `toSourceQueries` / `projectPaths` consume the
666
594
  * lens unchanged: a bind needs nothing new downstream. `parent:name` draws the same
667
595
  * value as the ancestor's `name`. Does not mutate the input.
668
596
  */
669
- declare const resolveLensBindings: (lensOrNarrowing: Lens | LensNarrowing, bindings: Record<string, RuleValue>) => Lens | LensNarrowing;
597
+ declare const bindLens: (lensOrNarrowing: Lens | LensNarrowing, bindings: Record<string, RuleValue>) => Lens | LensNarrowing;
598
+
599
+ declare const coerceRule: (condition: Condition, lensOrNarrowing: Lens | LensNarrowing) => Condition;
600
+
601
+ /** A lens over field maps, its bridges stitched into the maps as fields. */
602
+ declare const createLens: ({ maps, bridges, mapName, model }: Lens) => Lens;
603
+
604
+ type RuleDescription = {
605
+ sources: string[];
606
+ bridgesCrossed: boolean;
607
+ supportedTargets: RuleTarget[];
608
+ /** What the lens refuses in the rule — validateRuleInLens's issues. */
609
+ errors: ValidationIssue[];
610
+ };
611
+ declare const describeRule: (rule: Condition, lensOrNarrowing: Lens | LensNarrowing) => RuleDescription;
612
+
670
613
  /**
671
- * Bind names are unique across a composed chain: a layer may not re-declare a name
672
- * an ancestor already declares — rename it, or reference the inherited one read-only
673
- * as `parent:name`. A `parent:name` reference must point at a name some ancestor
674
- * actually declares. Returns the violation messages (folded into `validateNarrowing`).
614
+ * The values one rule compares at one declared source — keyed the way `projectPaths`
615
+ * keys a source (`path` + `field`), so the caller can join it back to the source's
616
+ * model without spelling a path of its own. A `mapDefaults`-declared source resolves
617
+ * wherever its model appears, so `path` may name a relation chain the narrowing never
618
+ * spelled under `root.relations`; the dotted format is the same.
675
619
  */
676
- declare const validateBindNames: (narrowing: LensNarrowing) => string[];
620
+ type RuleSourceDescription = {
621
+ path: string;
622
+ mapName: string;
623
+ model: string;
624
+ field: string;
625
+ /** Every literal a leaf at this source named; list operators flattened, deduped by content. */
626
+ values: RuleValue[];
627
+ /**
628
+ * The set of values cannot be enumerated from literals: a leaf read a value at evaluation
629
+ * (a `path` / `bind` on its comparison value, an offset or an amount) or moved it by an offset, used an operator that describes values without naming them
630
+ * (substring, pattern, range, date window), or used an operator the catalog does not
631
+ * know. A caller deciding anything from `values` must fail closed.
632
+ */
633
+ dynamic: boolean;
634
+ };
635
+ /**
636
+ * Which values a rule names at each source the lens declares — the lens owns the
637
+ * vocabulary, so it answers questions about it; callers never spell a path. A leaf reaches a
638
+ * source by its absolute path through the lens: nested (`{ field: 'orders', arrayOperator,
639
+ * condition: { field: 'sku' } }`) and dotted (`{ field: 'orders.sku' }`) spellings are one path,
640
+ * resolved by `lensPathEnd` — visibility, `mapDefaults`, and the Json boundary all apply, so a
641
+ * source declared in `mapDefaults` answers wherever its model appears. Quantifier-blind on
642
+ * purpose — a `none` relation names its value as much as an `any` one, `notIn` as much as `in` —
643
+ * but shape-aware via the operator catalog: only literal-naming shapes contribute `values`;
644
+ * substring / pattern / range / window operators, and operators the catalog does not know, mark
645
+ * the source `dynamic` instead of inventing values. A relation node's own comparison (an
646
+ * aggregate's threshold, an array `count`) belongs to the node, not to a source. Paths invisible
647
+ * under the lens, unmapped segments, and sub-paths beneath a Json column are silent.
648
+ */
649
+ declare const describeRuleSources: (rule: Condition, lensOrNarrowing: Lens | LensNarrowing) => RuleSourceDescription[];
677
650
 
678
651
  type LensPathHop = {
679
652
  field: string;
680
653
  entry: FieldMapEntry;
681
654
  mapName: string;
682
- modelName: string;
655
+ model: string;
683
656
  /** The relation path from the lens anchor to the model this hop reads. */
684
657
  relPath: string[];
685
658
  };
@@ -700,35 +673,9 @@ type LensPathResolution = {
700
673
  hops: LensPathHop[];
701
674
  };
702
675
 
703
- type RuleLensViolation = {
704
- path: string;
705
- reason: string;
706
- };
707
- type RuleLensCheck = {
708
- ok: boolean;
709
- violations: RuleLensViolation[];
710
- };
711
- declare const checkRuleAgainstLens: (rule: Condition, lensOrNarrowing: Lens | LensNarrowing) => RuleLensCheck;
712
-
713
- type CreateLensInput = {
714
- maps: Record<string, FieldMap>;
715
- bridges?: Bridge[];
716
- mapName: string;
717
- model: string;
718
- };
719
- declare const createLens: (input: CreateLensInput) => Lens;
720
-
721
- type RuleDescription = {
722
- sources: string[];
723
- bridgesCrossed: boolean;
724
- supportedTargets: RuleTarget[];
725
- violations: string[];
726
- };
727
- declare const describeRule: (rule: Condition, lensOrNarrowing: Lens | LensNarrowing) => RuleDescription;
728
-
729
676
  type ProjectedVisit = {
730
677
  mapName: string;
731
- modelName: string;
678
+ model: string;
732
679
  fields: Record<string, FieldMapEntry>;
733
680
  whereClauses: Condition[];
734
681
  /** Per-field source eligibility wheres, composed across layers (general + path). */
@@ -739,12 +686,13 @@ type ProjectedVisit = {
739
686
  /** Per-field option-partition axes for a sourced field (from a SourceSpec's `groupBy`). */
740
687
  sourceGroupBys: Record<string, string[]>;
741
688
  };
742
- type PathProjection = Map<string, ProjectedVisit>;
689
+ /** Each declared path's projected visit, keyed by dotted path from the lens model. */
690
+ type PathProjection = Record<string, ProjectedVisit>;
743
691
  /**
744
692
  * The materialized option set for one sourced field — the fetched companion to a
745
693
  * serializable lens. Its `options` are `{ value, label? }` pairs (the standard
746
- * `<select>` shape); it feeds both projections: `projectByPath` keys by
747
- * `path`+`field` (exact), `exposedSurface` by `mapName`+`model`+`field` (union).
694
+ * `<select>` shape); it feeds both projections: `projectPaths` keys by
695
+ * `path`+`field` (exact), `projectModels` by `mapName`+`model`+`field` (union).
748
696
  */
749
697
  type SourceValues = {
750
698
  path: string;
@@ -753,61 +701,37 @@ type SourceValues = {
753
701
  field: string;
754
702
  options: readonly SourceOption[];
755
703
  };
756
- type ProjectOptions = {
704
+ type ProjectLensOptions = {
757
705
  sourceValues?: readonly SourceValues[];
758
706
  };
759
- declare const projectByPath: (lensOrNarrowing: Lens | LensNarrowing, opts?: ProjectOptions) => PathProjection;
760
707
 
761
- declare const exposedSurface: (lensOrNarrowing: Lens | LensNarrowing, opts?: ProjectOptions) => Lens;
762
-
763
- declare const validateNarrowing: (narrowing: LensNarrowing) => void;
764
-
765
- /**
766
- * Resolve one dotted path through a lens, hop by hop, verifying as it walks: every hop is checked
767
- * against the narrowing at that visit, so a relation the narrowing dropped is `hidden`, a column the
768
- * model lacks is `missing`, and a segment past a scalar is `pastScalar`. This is the walk
769
- * `checkRuleAgainstLens` gates a rule's field with, exposed for consumers that resolve paths of their
770
- * own (template tokens, loop bindings, presence guards).
771
- */
772
- declare const resolveLensPath: (lensOrNarrowing: Lens | LensNarrowing, path: string) => LensPathResolution;
773
-
774
- /**
775
- * The values one rule compares at one declared source — keyed the way `projectByPath`
776
- * keys a source (`path` + `field`), so the caller can join it back to the source's
777
- * model without spelling a path of its own. A `mapDefaults`-declared source resolves
778
- * wherever its model appears, so `path` may name a relation chain the narrowing never
779
- * spelled under `root.relations`; the dotted format is the same.
780
- */
781
- type RuleSourceValues = {
782
- path: string;
783
- mapName: string;
708
+ type PrismaWhere = Record<string, unknown>;
709
+ type StepRef = {
710
+ __step: number;
711
+ };
712
+ type GroupByStep = {
713
+ operation: 'groupBy';
784
714
  model: string;
785
- field: string;
786
- /** Every literal a leaf at this source named; list operators flattened, deduped by content. */
787
- values: RuleValue[];
788
- /**
789
- * The set of values cannot be enumerated from literals: a leaf took its value from
790
- * `path` / `bind`, used an operator that describes values without naming them
791
- * (substring, pattern, range, date window), or used an operator the catalog does not
792
- * know. A caller deciding anything from `values` must fail closed.
793
- */
794
- dynamic: boolean;
715
+ args: {
716
+ by: string[];
717
+ where: Record<string, unknown>;
718
+ having: Record<string, unknown>;
719
+ };
720
+ extract: string;
721
+ };
722
+ type WhereStep = {
723
+ operation: 'where';
724
+ where: Record<string, unknown>;
725
+ };
726
+ type PrismaStep = GroupByStep | WhereStep;
727
+ type ToPrismaResult = {
728
+ steps: PrismaStep[];
729
+ };
730
+ type ToPrismaOptions = CompileOptions & {
731
+ datasource?: {
732
+ provider?: PrismaProvider;
733
+ };
795
734
  };
796
- /**
797
- * Which values a rule names at each source the lens declares — the lens owns the
798
- * vocabulary, so it answers questions about it; callers never spell a path. A leaf reaches a
799
- * source by its absolute path through the lens: nested (`{ field: 'orders', arrayOperator,
800
- * condition: { field: 'sku' } }`) and dotted (`{ field: 'orders.sku' }`) spellings are one path,
801
- * resolved by `walkLensPath` — visibility, `mapDefaults`, and the Json boundary all apply, so a
802
- * source declared in `mapDefaults` answers wherever its model appears. Quantifier-blind on
803
- * purpose — a `none` relation names its value as much as an `any` one, `notIn` as much as `in` —
804
- * but shape-aware via the operator catalog: only literal-naming shapes contribute `values`;
805
- * substring / pattern / range / window operators, and operators the catalog does not know, mark
806
- * the source `dynamic` instead of inventing values. A relation node's own comparison (an
807
- * aggregate's threshold, an array `count`) belongs to the node, not to a source. Paths invisible
808
- * under the lens, unmapped segments, and sub-paths beneath a Json column are silent.
809
- */
810
- declare const ruleSourceValues: (lensOrNarrowing: Lens | LensNarrowing, rule: Condition) => RuleSourceValues[];
811
735
 
812
736
  /** Prisma `select` shape — nested for a grouped source's relation path. */
813
737
  type SourceSelect = {
@@ -818,11 +742,11 @@ type SourceSelect = {
818
742
  type SourcePrismaQuery = {
819
743
  model: string;
820
744
  /** Absent for grouped sources — DISTINCT on the value column alone would collapse
821
- * same-value rows across groups; dedup happens in `sourceValuesFromQueryRows`. */
745
+ * same-value rows across groups; dedup happens in `materializeSourceQuery`. */
822
746
  distinct?: string[];
823
747
  select: SourceSelect;
824
748
  where: PrismaWhere;
825
- /** Present only if the composed where used count operators (run via executePrismaQueryPlan). */
749
+ /** Present only if the composed where used count operators (run via executePrismaPlan). */
826
750
  steps?: PrismaStep[];
827
751
  };
828
752
  /** `sql` is null when the composed where uses a predicate SQL can't express
@@ -854,41 +778,89 @@ type SourceQuery = {
854
778
  * the projected lens. The WHERE is the field's composed eligibility: the model's
855
779
  * own narrowing at that path AND its source where(s). The app runs these (with
856
780
  * its own client) to materialize each field's option set — feed the fetched rows
857
- * to `sourceValuesFromQueryRows`.
781
+ * to `materializeSourceQuery`.
858
782
  */
859
- declare const sourceQueries: (lensOrNarrowing: Lens | LensNarrowing) => SourceQuery[];
783
+ declare const toSourceQueries: (lensOrNarrowing: Lens | LensNarrowing) => SourceQuery[];
860
784
 
861
- type Row$1 = Record<string, unknown>;
862
785
  /** Which executor produced the rows — the caller always knows; never guessed. */
863
786
  type SourceRowShape = 'prisma' | 'sql';
864
787
  /**
865
788
  * Materialize one compiled `SourceQuery`'s fetched rows into its `SourceValues` —
866
- * the executor-side counterpart of `sourceQueries`, so apps never hand-map rows.
789
+ * the executor-side counterpart of `toSourceQueries`, so apps never hand-map rows.
867
790
  * `rowShape` names the wire format: prisma rows (default) nest each `groupBy` axis
868
791
  * (and a dotted `label`) as related objects; sql rows carry them flat under the
869
792
  * statement's `__group_i` / `__label` aliases. Grouped queries fetch without
870
793
  * DISTINCT, so dedup per (groups, value) happens here.
871
794
  */
872
- declare const sourceValuesFromQueryRows: (query: SourceQuery, rows: readonly Row$1[], opts?: {
795
+ /** `rowShape`: how the rows came back — nested Prisma rows (the default) or flat SQL rows. */
796
+ type MaterializeSourceQueryOptions = {
873
797
  rowShape?: SourceRowShape;
874
- }) => SourceValues;
798
+ };
799
+ declare const materializeSourceQuery: (query: SourceQuery, rows: readonly Row[], opts?: MaterializeSourceQueryOptions) => SourceValues;
875
800
 
876
- type Row = Record<string, unknown>;
877
801
  /**
878
802
  * Materialize each sourced field's option set from an already-fetched collection —
879
- * the in-memory executor of `sources` declarations, alongside `sourceQueries`
803
+ * the in-memory executor of `sources` declarations, alongside `toSourceQueries`
880
804
  * (which compiles the same declarations to DISTINCT queries for a DB). Rows are
881
- * the collection fetched UNDER the lens (relations inline), so they are already
882
- * lens-scoped: eligibility here is the field's source `where` only, evaluated via
883
- * `check()` (`options` feeds `{bind}` clauses). Scalar-list fields contribute one
805
+ * the collection fetched under the lens (relations inline). Each row must meet the field's
806
+ * eligibility as `toSourceQueries` composes it — its source `where`, the grants above it, the
807
+ * guards of the relations it crosses and any allowed values — evaluated with `check()`
808
+ * (`options` feeds `{bind}` clauses). Scalar-list fields contribute one
884
809
  * option per element, labels take the first non-null value of the label column
885
810
  * (a sibling, or a dotted to-one path read through the nested rows), and sorting is
886
- * numeric-aware in a fixed locale. Feed the result to `exposedSurface` /
887
- * `projectByPath` as `{ sourceValues }`.
811
+ * numeric-aware in a fixed locale. Feed the result to `projectLens` as `{ sourceValues }`.
888
812
  */
889
- declare const sourceValuesFromRows: (lensOrNarrowing: Lens | LensNarrowing, rows: readonly Row[], options?: CheckOptions) => SourceValues[];
813
+ declare const materializeSources: (lensOrNarrowing: Lens | LensNarrowing, rows: readonly Row[], options?: CheckOptions) => SourceValues[];
814
+
815
+ declare const validateNarrowing: (narrowing: LensNarrowing) => ValidationResult;
816
+ declare const assertValidNarrowing: (narrowing: LensNarrowing) => void;
890
817
 
891
- declare const stampCoercions: (condition: Condition, lensOrNarrowing: Lens | LensNarrowing) => Condition;
818
+ declare const narrowRule: (rule: Condition, lensOrNarrowing: Lens | LensNarrowing) => Condition;
819
+
820
+ /**
821
+ * What a narrowed lens exposes. `by: 'path'` (the default) projects each declared path — its
822
+ * visible fields, `where` clauses and sources — keyed by dotted path. `by: 'model'` flattens the
823
+ * whole surface into a Lens: every model a path or relation reaches, each field the union of its
824
+ * visits, bridges kept only where an exposed field crosses them.
825
+ */
826
+ declare function projectLens(lensOrNarrowing: Lens | LensNarrowing, options?: ProjectLensOptions & {
827
+ by?: 'path';
828
+ }): PathProjection;
829
+ declare function projectLens(lensOrNarrowing: Lens | LensNarrowing, options: ProjectLensOptions & {
830
+ by: 'model';
831
+ }): Lens;
832
+
833
+ /**
834
+ * A lens as stored, one record per layer: its `id`, the ids of every layer it composes with —
835
+ * the base lens first, the nearest parent last — and its own part. The base lens is the
836
+ * root-most layer: the lens itself, with no parents.
837
+ */
838
+ type StoredLens = {
839
+ id: string;
840
+ parents: string[];
841
+ } & (Lens | Omit<LensNarrowing, 'parent'>);
842
+ /**
843
+ * The composed lens a stored layer resolves to: its parents, read from `records`, nested from
844
+ * the base down, each layer validated against the ones above it. Fails closed on a missing
845
+ * record, a base that isn't first, or a parent whose own parents disagree with the list.
846
+ */
847
+ declare const composeLens: (id: string, records: Record<string, StoredLens>) => Lens | LensNarrowing;
848
+ /** A composed lens as the records `composeLens` reads back: one per layer, the base first,
849
+ * named by `ids` in the same order. */
850
+ declare const storeLens: (lens: Lens | LensNarrowing, ids: readonly string[]) => StoredLens[];
851
+
852
+ /** Gate a rule against a lens: every field and value-side ref resolves through it, and every
853
+ * operator, value and amount fits the field it reaches. */
854
+ declare const validateRuleInLens: (rule: Condition, lensOrNarrowing: Lens | LensNarrowing) => ValidationResult;
855
+
856
+ /**
857
+ * Resolve one dotted path through a lens, hop by hop, verifying as it walks: every hop is checked
858
+ * against the narrowing at that visit, so a relation the narrowing dropped is `hidden`, a column the
859
+ * model lacks is `missing`, and a segment past a scalar is `pastScalar`. This is the walk
860
+ * `validateRuleInLens` gates a rule's field with, exposed for consumers that resolve paths of their
861
+ * own (template tokens, loop bindings, presence guards).
862
+ */
863
+ declare const walkLensPath: (lensOrNarrowing: Lens | LensNarrowing, path: string) => LensPathResolution;
892
864
 
893
865
  type ScopeRef = {
894
866
  depth: number;
@@ -902,7 +874,7 @@ type ScopedRef<S> = {
902
874
  type ScopeOutOfBounds = {
903
875
  outOfBounds: string;
904
876
  };
905
- declare const resolveScopeRef: <S>(ref: string, scopes: readonly S[]) => ScopedRef<S> | ScopeOutOfBounds;
877
+ declare const readScopeRef: <S>(ref: string, scopes: readonly S[]) => ScopedRef<S> | ScopeOutOfBounds;
906
878
 
907
879
  /**
908
880
  * Execute a Prisma query plan produced by toPrisma().
@@ -918,75 +890,39 @@ declare const resolveScopeRef: <S>(ref: string, scopes: readonly S[]) => ScopedR
918
890
  *
919
891
  * @example
920
892
  * const plan = toPrisma(condition, { map, model: 'User' });
921
- * const where = await executePrismaQueryPlan(plan, { post: prisma.post });
893
+ * const where = await executePrismaPlan(plan, { post: prisma.post });
922
894
  * await prisma.user.findMany({ where });
923
895
  */
924
- declare const executePrismaQueryPlan: (result: ToPrismaResult, prismaDelegate: Record<string, Record<string, (...args: unknown[]) => unknown>>) => Promise<Record<string, unknown>>;
896
+ declare const executePrismaPlan: (plan: ToPrismaResult, prismaDelegate: Record<string, Record<string, (...args: unknown[]) => unknown>>) => Promise<Record<string, unknown>>;
925
897
 
926
898
  /**
927
- * Convert a json-rules Condition to a Prisma query plan.
928
- *
929
- * Returns a `ToPrismaResult` with:
930
- * - `where` – the Prisma WHERE clause
931
- * - `steps` – optional array of groupBy steps for count-based relation filters
932
- * (only present when `atLeast`/`atMost`/`exactly` operators are used with a map)
933
- *
934
- * When `steps` is present, pass the result to `executePrismaQueryPlan` to
935
- * resolve step refs before using `where` in a Prisma query.
936
- *
937
- * @param condition - The rule condition to convert
938
- * @param options - Optional map, model, and context
899
+ * Compile a condition to a Prisma query plan: `steps`, any groupBy steps (counts and relation
900
+ * aggregates, which need `{ map, model }`) and then the final `where`. Run a plan with
901
+ * `executePrismaPlan(plan, client)` to resolve step refs; a single-step plan's `where` is its
902
+ * last step's.
939
903
  *
940
904
  * @example
941
905
  * ```typescript
942
- * // Simple scalar
943
- * toPrisma({ field: 'status', operator: Operator.equals, value: 'active' })
944
- * // → { where: { status: { equals: 'active' } } }
945
- *
946
- * // JSON field detection (map required)
947
- * toPrisma({ field: 'metadata.theme', operator: Operator.equals, value: 'dark' }, { map, model: 'User' })
948
- * // → { where: { metadata: { path: ['theme'], equals: 'dark' } } }
949
- *
950
- * // Context path ref
951
- * toPrisma({ field: 'userId', operator: Operator.equals, path: 'currentUser.id' }, { context: { currentUser: { id: '123' } } })
952
- * // → { where: { userId: { equals: '123' } } }
906
+ * toPrisma({ field: 'status', operator: Operator.equals, value: 'active' }).steps
907
+ * // → [{ operation: 'where', where: { status: { equals: 'active' } } }]
953
908
  *
954
- * // Multi-step (map required)
955
- * const plan = toPrisma({ field: 'posts', arrayOperator: 'atLeast', count: 3, condition: {...} }, { map, model: 'User' });
956
- * const where = await executePrismaQueryPlan(plan, { post: prisma.post });
909
+ * const plan = toPrisma({ field: 'posts', arrayOperator: 'atLeast', count: 3, condition }, { map, model: 'User' });
910
+ * const where = await executePrismaPlan(plan, prisma);
957
911
  * await prisma.user.findMany({ where });
958
912
  * ```
959
913
  */
960
- declare const toPrisma: (condition: Condition, options?: BuildOptions) => ToPrismaResult;
914
+ declare const toPrisma: (condition: Condition, options?: ToPrismaOptions) => ToPrismaResult;
961
915
 
962
- type SqlResult = {
916
+ type ToSqlResult = {
963
917
  sql: string;
964
918
  params: unknown[];
965
919
  joins: string[];
966
920
  };
967
-
968
- type SqlBuildOptions = {
969
- map?: FieldMap;
970
- model?: string;
921
+ type ToSqlOptions = CompileOptions & {
922
+ /** The root table alias; `t0` when a map is given. */
971
923
  alias?: string;
972
- context?: Record<string, unknown>;
973
- } & DateConfig;
974
- declare const toSql: (condition: Condition, options?: SqlBuildOptions) => SqlResult;
975
-
976
- type ValidationIssue = {
977
- path: string;
978
- message: string;
979
- code: string;
980
- };
981
- type ValidationResult = {
982
- ok: boolean;
983
- errors: ValidationIssue[];
984
924
  };
985
- declare const validateRule: (condition: unknown, options?: {
986
- target?: RuleTarget;
987
- }) => ValidationResult;
988
- declare const assertValidRule: (condition: unknown, options?: {
989
- target?: RuleTarget;
990
- }) => asserts condition is Condition;
991
925
 
992
- export { AGGREGATE_OPERATORS, ALL_KINDS, ARRAY_OPERATOR_CATALOG, type AggregateMode, type AggregateRule, type All, type Any, type ArrayCatalogEntry, ArrayOperator, type ArrayRule, type Bridge, type BridgeCardinality, type BridgeDictionary, type BridgeEndpoint, type BuildOptions, type CatalogEntry, type CheckOptions, type Condition, type CreateLensInput, DATE_OPERATOR_CATALOG, type DateConfig, type DateExpr, type DateInputOrExpr, type DateInputValue, DateOperator, type DateRule, type DateRuleValue, EQUATABLE_KINDS, type EdgeExpr, type EngineGlobalsState, type EnumNarrowing, FIELD_OPERATOR_CATALOG, FieldKind, type FieldMap, type FieldMapEntry, type FieldMapSet, type FuzzyConfig, type GroupByStep, type IfThenElse, type Lens, type LensNarrowing, type LensPathHop, type LensPathResolution, type ModelDefaultNarrowing, type ModelNarrowing, NULLABLE_KINDS, NUMERIC_KINDS, type NarrowingDefaults, ORDERABLE_KINDS, Operator, type OrderBy, type OrderedRuleValue, type PathProjection, type PeriodExpr, type PeriodUnit, type PrismaProvider, type PrismaStep, type PrismaWhere, type ProjectOptions, type ProjectedVisit, type RelativeUnits, type RollingExpr, type Rule, type RuleDescription, type RuleLensCheck, type RuleLensViolation, type RuleScalar, type RuleSourceValues, RuleTarget, type RuleValue, STRINGY_KINDS, type ScopeOutOfBounds, type ScopeRef, type ScopedRef, type SortDir, type SourceOption, type SourcePrismaQuery, type SourceQuery, type SourceRowShape, type SourceSpec, type SourceSqlQuery, type SourceValue, type SourceValues, type SqlResult, type StepRef, type StrictAggregateRule, type StrictAll, type StrictAny, type StrictArrayCountRule, type StrictArrayPredicateRule, type StrictArrayPresenceRule, type StrictArrayRule, type StrictCondition, type StrictContainsRule, type StrictDateComparisonRule, type StrictDateDayRule, type StrictDateRangeRule, type StrictDateRule, type StrictEqualityRule, type StrictIfThenElse, type StrictMembershipRule, type StrictOrderedComparisonRule, type StrictPatternRule, type StrictPresenceRule, type StrictRangeRule, type StrictRule, type StrictStringBoundaryRule, type TimeZoneConfig, type ToPrismaResult, type ValidationIssue, type ValidationResult, ValueShape, WINDOW_SELECTOR, type WeekStart, type WhereStep, type WindowFields, type WindowRuleType, WindowSupport, applyLens, assertValidRule, bindingNames, buildBridgeDictionary, check, checkRuleAgainstLens, createLens, describeRule, engineGlobals, executePrismaQueryPlan, exposedSurface, fuzzyContains, getAggregateOperators, getArrayOperators, getOperatorsForKind, getValueShape, getWindowSupport, isAggregateRangeOperator, isAggregateSingleOperator, isOperatorSupportedForTarget, lensRequiredBindings, maxFuzzyDistance, parseScopeRef, projectByPath, requiredBindings, resolveBindings, resolveCaseInsensitive, resolveFuzzy, resolveLensBindings, resolveLensPath, resolveScopeRef, ruleSourceValues, sourceQueries, sourceValuesFromQueryRows, sourceValuesFromRows, stampCoercions, stitchFieldMaps, supportsQueryMode, toPrisma, toSql, validateBindNames, validateFieldMap, validateFieldMapSet, validateNarrowing, validateRule };
926
+ declare const toSql: (condition: Condition, options?: ToSqlOptions) => ToSqlResult;
927
+
928
+ export { ALL_KINDS, type AggregateMode, type AggregateRule, type All, type Any, ArrayOperator, type ArrayRule, type Bridge, type BridgeCardinality, type BridgeDictionary, type BridgeEndpoint, type CheckData, type CheckOptions, type CompileOptions, type Condition, type DateConfig, type DateExpr, type DateInputOrExpr, type DateInputValue, type DateOffset, DateOperator, type DateRule, type DateRuleValue, type EdgeExpr, type EngineGlobalsState, type EnumNarrowing, FieldKind, type FieldMap, type FieldMapEntry, type FieldMapSet, type FuzzyConfig, type GroupByStep, type IfThenElse, type Lens, type LensNarrowing, type LensPathHop, type LensPathResolution, type ListBindingsOptions, type Magnitude, type MaterializeSourceQueryOptions, type ModelDefaultNarrowing, type ModelEntry, type ModelNarrowing, NUMERIC_KINDS, type NarrowingDefaults, type NumberOffset, Operator, type OperatorFamily, type OrderBy, type OrderedRuleValue, type PathProjection, type PeriodExpr, type PeriodUnit, type PrismaProvider, type PrismaStep, type PrismaWhere, type ProjectLensOptions, type ProjectedVisit, type RelativeUnits, type RollingExpr, type Row, type Rule, type RuleDescription, type RuleScalar, type RuleSourceDescription, RuleTarget, type RuleValue, type ScopeOutOfBounds, type ScopeRef, type ScopedRef, type SortDir, type SourceEntry, type SourceOption, type SourcePrismaQuery, type SourceQuery, type SourceRowShape, type SourceSelect, type SourceSpec, type SourceSqlQuery, type SourceValues, type StepRef, type StoredLens, type StrictAggregateRule, type StrictAll, type StrictAny, type StrictArrayCountRule, type StrictArrayPredicateRule, type StrictArrayPresenceRule, type StrictArrayRule, type StrictCondition, type StrictContainsRule, type StrictDateComparisonRule, type StrictDateDayRule, type StrictDateRangeRule, type StrictDateRule, type StrictEqualityRule, type StrictIfThenElse, type StrictMembershipRule, type StrictOrderedComparisonRule, type StrictPatternRule, type StrictPresenceRule, type StrictRangeRule, type StrictRule, type StrictStringBoundaryRule, type TimeZoneConfig, type ToPrismaOptions, type ToPrismaResult, type ToSqlOptions, type ToSqlResult, type ValidateRuleOptions, type ValidationIssue, type ValidationResult, ValueShape, type ValueSourceFields, type ValueSourceOf, type WeekStart, type WhereStep, type WindowFields, assertValidFieldMaps, assertValidNarrowing, assertValidRule, bindLens, bindRule, check, coerceRule, composeLens, createLens, describeRule, describeRuleSources, engineGlobals, executePrismaPlan, getAggregateOperators, getArrayOperators, getOperatorsForKind, getValueShape, indexBridges, listBindings, listLensBindings, materializeSourceQuery, materializeSources, narrowRule, parseScopeRef, projectLens, readScopeRef, stitchFieldMaps, storeLens, toPrisma, toSourceQueries, toSql, validateFieldMaps, validateNarrowing, validateRule, validateRuleInLens, walkLensPath };