import { BaseError as BaseError$1, IBaseError as IBaseError$1 } from "@ebec/core"; import { Issue, IssueItem } from "blemish"; //#region src/parameter/filters/condition.d.ts declare const CONDITION_MARKER: unique symbol; interface ICondition { readonly [CONDITION_MARKER]: true; /** * Relation-pruning protection marker. A preserved group stays atomic * during normalization and pruning applies its contract to the subtree. */ readonly preserved?: boolean; readonly operator: string; readonly value: T; } /** * Identify a live condition by its non-serializable marker. Visitor dispatch * is deliberately not part of this check. */ declare function isCondition(input: unknown): input is ICondition; /** * Construction options shared only by the built-in filter nodes. */ type ConditionOptions = { preserved?: boolean; }; /** * Optional implementation base for conditions; structural implementations * can implement {@link ICondition} without extending this class. */ declare abstract class Condition implements ICondition { get [CONDITION_MARKER](): true; readonly operator: string; readonly value: T; protected constructor(operator: string, value: T); } //#endregion //#region src/parameter/filters/collection/types.d.ts interface IFiltersVisitor { visitFilters(expr: IFilters): R; } interface IFilters extends ICondition { readonly operator: string; readonly value: T[]; accept(visitor: IFiltersVisitor): R; flatten(items?: T[]): IFilters; /** * Combine both groups as an ordered logical AND. Empty groups are the * identity; every condition from either non-empty group is retained. */ merge(other: IFilters): IFilters; and(...conditions: ICondition[]): IFilters; or(...conditions: ICondition[]): IFilters; } //#endregion //#region src/parameter/filters/collection/check.d.ts declare function isFilters(input: ICondition, operator?: string): input is IFilters; //#endregion //#region src/parameter/filters/collection/module.d.ts declare class Filters extends Condition implements IFilters { readonly preserved?: boolean; constructor(operator: string, conditions: T[], options?: ConditionOptions); accept(visitor: IFiltersVisitor): R; flatten(aggregatedResult?: T[]): IFilters; protected flattenInternal(conditions: F[], operator: string, aggregatedResult?: F[]): F[]; /** * Ordered logical conjunction. Each condition from both sides survives * in argument order. A non-preserved root AND contributes its flattened * child conjuncts, while every other root remains one conjunct. */ merge(other: IFilters): IFilters; /** * Wrap and append immutably: combine the given conditions with the * receiver under an AND group while retaining their object identity. */ and(...conditions: ICondition[]): IFilters; /** * Wrap & inject (immutable), OR variant of {@link Filters.and}. */ or(...conditions: ICondition[]): IFilters; protected wrap(operator: string, conditions: ICondition[]): IFilters; } //#endregion //#region src/parameter/filters/constants.d.ts /** * Reserved self-reference marker (spelled `$this` on the wire). * * Legal only as the complete field of a condition inside an * elemMatch interior. A leaf condition uses it to address the bound * array element itself instead of one of its properties; a nested * elemMatch may take it as its own field for arrays of arrays: * * ```ts * elemMatch('scores', gt(ITSELF, 5)) // some score > 5 * elemMatch('matrix', elemMatch(ITSELF, gt(ITSELF, 5))) // some row has a value > 5 * ``` * * Anywhere else the marker is a typed error — build layer and parsers * reject it, backend adapters without element semantics * (`@rapiq/adapter-sql`, `@rapiq/adapter-typeorm`) throw `featureUnsupported`. */ declare const ITSELF = "$this"; //#endregion //#region src/types.d.ts type ObjectLiteral = Record; type ObjectLiteralKeys> = { [K in keyof T as `${K & string}`]: T[K]; }; type MaybeAsync = T | Promise; type ArrayItem = Type extends Array ? Item : Type; type IsArray = Type extends Array ? Type : never; type Scalar = string | number | boolean | undefined | null; type IsScalar = T extends string | number | boolean | undefined | null ? T : never; type KeyWithOptionalPrefix = T extends string ? (`${O}${T}` | T) : never; type PrevIndex = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; /** * A property counts as a leaf when it is scalar-like (Scalar, Date) or an * index-signature record with no known literal keys (e.g. a JSON column * typed Record). `null`/`undefined` are stripped before the * structural checks so nullable/optional columns resolve like their * non-nullable counterparts. */ type IsLeafKeyValue = T extends Scalar | Date ? T : T extends Record ? string extends keyof T ? T : never : never; type SimpleKeys> = { [Key in keyof T & string]: NonNullable extends IsLeafKeyValue> ? `${Key}` : never; }[keyof T & string]; /** * The keys of `T` that are explicitly declared, with the `string`/`number` * index signatures of a "bag" type stripped out. A pure `Record` * has none; an entity that merely *carries* an index signature (e.g. * `{ id: string; name: string; [key: string]: any }`) still keeps its literal * keys. Relies on a homomorphic mapped type iterating the declared members, so * the `as`-filter removes the index signature without collapsing the literals. */ type KnownKeys = keyof { [K in keyof T as string extends K ? never : number extends K ? never : K]: 0; }; /** * A property is traversed as a nested branch only when it is a record with * known literal keys. Index-signature records (e.g. JSON columns typed * Record) stay leaves — recursing into them would produce * unbounded `${string}` key unions. */ type IsRecursiveKeyValue = T extends Date ? never : T extends Record ? string extends keyof T ? never : T : never; /** * A property is a *resource* (relation target) when it is a record that carries * at least one explicitly-declared key. Proper records qualify, and so does an * entity that additionally carries a dynamic-attribute index signature (see * #789) — the bag guard {@link IsRecursiveKeyValue} still stops the recursion, * but it must not drop the relation key itself. A pure index-signature bag * (`Record`, e.g. a JSON column) has no declared structure and is * therefore not a relation — it stays a leaf field. */ type IsRecordKeyValue = T extends Date ? never : T extends Record ? [KnownKeys] extends [never] ? never : T : never; type NestedKeys, DEPTH extends number = 4> = [DEPTH] extends [0] ? never : { [Key in keyof T & string]: NonNullable extends Array ? (NonNullable extends IsRecursiveKeyValue> ? `${Key}.${NestedKeys, PrevIndex[DEPTH]>}` : `${Key}`) : NonNullable extends IsRecursiveKeyValue> ? `${Key}.${NestedKeys, PrevIndex[DEPTH]>}` : `${Key}`; }[keyof T & string]; type SimpleResourceKeys> = { [Key in keyof T & string]: NonNullable extends Array ? (NonNullable extends IsRecordKeyValue> ? Key : never) : NonNullable extends IsRecordKeyValue> ? Key : never; }[keyof T & string]; /** * Keys a `fields` projection may list: scalar/leaf columns ({@link SimpleKeys}) * plus record/array-shaped keys ({@link SimpleResourceKeys}). The latter covers * concrete-typed json columns (e.g. `{ k: string }[]`) — single columns at the * database level that {@link SimpleKeys} would otherwise reject. Index-signature * json (`Record`) is already a {@link SimpleKeys}. * * A json column and a relation are structurally identical at the type level, so * relation keys are admitted here too. List only column-backed keys in `fields`; * relations belong in the `relations` allow-list (`include`). A relation key that * reaches a backend's `fields` is caller error — it is not a selectable column. */ type FieldKeys> = SimpleKeys | SimpleResourceKeys; type NestedResourceKeys, DEPTH extends number = 4> = [DEPTH] extends [0] ? never : { [Key in keyof T & string]: NonNullable extends Array ? (NonNullable extends IsRecordKeyValue> ? (NonNullable extends IsRecursiveKeyValue> ? Key | `${Key}.${NestedResourceKeys, PrevIndex[DEPTH]>}` : Key) : never) : NonNullable extends IsRecordKeyValue> ? (NonNullable extends IsRecursiveKeyValue> ? Key | `${Key}.${NestedResourceKeys>, PrevIndex[DEPTH]>}` : Key) : never; }[keyof T & string]; type TypeFromNestedKeyPath, Path extends string, DEPTH extends number = 4> = [DEPTH] extends [0] ? never : { [Key in Path & string]: Key extends keyof T ? (NonNullable extends Array ? ELEMENT : T[Key]) : Key extends `${infer P}.${infer S}` ? (P extends keyof T ? (NonNullable extends Array ? (NonNullable extends Record ? TypeFromNestedKeyPath, S, PrevIndex[DEPTH]> : never) : NonNullable extends Record ? TypeFromNestedKeyPath, S, PrevIndex[DEPTH]> : never) : never) : never; }[Path]; //#endregion //#region src/schema/indexes/types.d.ts /** * Ordered column lists of the indexes a record's storage declares: * own-table flat keys only (a composite index never spans tables), * resolved names (after mapping). The declaration is structural: rapiq * does not model operator servability (sargability differs per engine), * it trusts the author and enforces combinations only. */ type IndexesOption = SimpleKeys[][]; /** * How the filters parameter is checked against the declared indexes: * - `anchor`: every AND group must contain at least one conjunct whose * field leads an index (the rest is residual filtering); * - `cover`: additionally, per relation path, the AND group's field set * must equal a leftmost prefix of one index. */ type IndexedMode = 'anchor' | 'cover'; /** * Answers which indexes govern a relation path (`''` = the parameter * root). `null` when the governing schema declares none. */ type IndexesResolver = (path: string) => string[][] | null; type IndexCheckSuccess = { ok: true; }; type IndexCheckFailure = { ok: false; path: string; keys: string[]; }; type IndexCheckResult = IndexCheckSuccess | IndexCheckFailure; //#endregion //#region src/schema/indexes/module.d.ts /** * Structural index check for a filter condition tree. Operators, * negation semantics and case folding are deliberately out of scope: * the check is uniform across engines and trusts the declaration. */ declare function checkConditionIndexed(condition: ICondition, resolve: IndexesResolver, mode: IndexedMode): IndexCheckResult; /** * Ordered leftmost-prefix check for a sort key list. All keys must * share one relation path: no single index serves cross-table * ordering. Directions are ignored (structural check). */ declare function checkSortKeysIndexed(names: string[], resolve: IndexesResolver): IndexCheckResult; //#endregion //#region src/schema/parameter/fields/constants.d.ts declare enum FieldOperator { INCLUDE = "+", EXCLUDE = "-" } //#endregion //#region src/constants.d.ts declare enum Parameter { FILTERS = "filters", FIELDS = "fields", PAGINATION = "pagination", RELATIONS = "relations", SORTS = "sorts", /** * @deprecated use {@link Parameter.SORTS}. The value stays `sort`, * so `parameters` masks and `describe()` output keep working. * Removed in 3.0. */ SORT = "sort" } declare const DEFAULT_ID = "__DEFAULT__"; /** * Shared upper bound for recursive traversal: schema relation * resolution, expression compound nesting and mongo document * nesting all consume this cap, so every dialect accepts and * rejects the same depth. */ declare const MAX_TRAVERSAL_DEPTH = 32; //#endregion //#region src/schema/types.d.ts type BaseSchemaOptions = { /** * Name of the schema. */ name?: string; /** * throw an error on invalid input for building or parsing * input data. */ throwOnFailure?: boolean; /** * Strict mode: a parameter without an explicit allow-list * rejects every client key instead of falling back to the * syntactic property-name check. */ strict?: boolean; /** * Map alias to schema name */ schemaMapping?: Record; }; /** * Where a client key sits in the query. Handed to every key validation * hook as its third argument, so a hook can branch on the position of a * key and not only on its name, e.g. treat a field differently at the * query root than when it is reached through an include. * * - `parameter` is the parameter the key belongs to, so one hook * factory can serve `fields` and `sorts`. * - `path` is the dotted relation path of the schema governing the key: * `''` at the query root, `'client'` for `fields[client]=secret`, * `'items.realm'` deeper. * - `schema` is the registered name of the governing schema * (`undefined` for an inline, unregistered schema). */ type KeyValidationScope = { readonly parameter: `${Parameter}`; readonly path: string; readonly schema?: string; }; /** * The answer a key validation hook gives for one key. * * - a truthy value other than an {@link ICondition} accepts the key. * - `false` / `undefined` (and any other falsy value) rejects it: * dropped by default, thrown (`ErrorCode.KEY_VALIDATE_REJECTED`) * under `throwOnFailure`. * - an {@link ICondition} accepts the key, but marks it visible only on * rows satisfying that condition. Supported for the `fields` * parameter, where the condition is attached to the resulting `Field` * node; it never changes which rows the query returns, at any level. * The `sorts` and `relations` parameters have no column to gate, so a * condition rejects there (row-level narrowing of an included * relation is tracked in #810). */ type KeyValidationVerdict = boolean | ICondition | undefined; /** * One verdict per key, as returned by a {@link KeyValidatorMany}. A key * ABSENT from the record is REJECTED, matching the `undefined`-rejects * rule of the per-key hook: accepted keys must be echoed explicitly. * Keys that were not asked about are ignored. */ type KeyValidationVerdictRecord = Record; /** * Per-key validation hook shared by the relations, fields and sorts * parameters. Invoked once per resolved (alias-mapped, allow-listed) * client key against the schema that governs it — for dotted keys that * is the target schema of the relation path, not the root. The context * is the value passed to `parse()` / `decode()` via the `context` * option (`undefined` when the caller supplied none); the scope * describes where the key sits. * * Return a truthy value to accept the key. Returning `false` or * `undefined` rejects it — an inspect-only hook must therefore end * with `return true`. See {@link KeyValidationVerdict} for the * condition-returning form. The result may also be a Promise of any of * those; resolving it requires the `parseAsync()` / `decodeAsync()` * entry points. Rejections follow the schema failure policy: dropped by * default, thrown (`ErrorCode.KEY_VALIDATE_REJECTED`) under * `throwOnFailure`. Schema defaults are server-authored and bypass * the hook. * * Mutually exclusive with {@link KeyValidatorMany} on the same * sub-schema. */ type KeyValidator = (name: string, context: CONTEXT, scope: KeyValidationScope) => MaybeAsync; /** * Batched counterpart of {@link KeyValidator}: invoked once per * (governing schema, {@link KeyValidationScope.path}) with every client * key resolved at that position, deduplicated and in recorded order, so * a consumer can compile an authorization policy once instead of once * per key. * * `names` holds client-requested keys only, never schema defaults, * never excluded fields (`-email`), never keys the allow-list already * rejected. It is the requested key set, not the effective projection. * * Mutually exclusive with {@link KeyValidator} on the same sub-schema: * declaring both throws `ErrorCode.SCHEMA_KEY_VALIDATOR_CONFLICT` when * the schema is constructed. */ type KeyValidatorMany = (names: string[], context: CONTEXT, scope: KeyValidationScope) => MaybeAsync; /** * The hook pair shared by the fields, relations and sorts sub-schemas. * The two members are mutually exclusive. */ type KeyValidatableSchemaOptions = BaseSchemaOptions & { validate?: KeyValidator; validateMany?: KeyValidatorMany; }; type SchemaOptionsNormalized = BaseSchemaOptions & { fields: FieldsOptions | FieldsSchema; filters: FiltersOptions | FiltersSchema; relations: RelationsOptions | RelationsSchema; pagination: PaginationOptions | PaginationSchema; sorts: SortsOptions | SortsSchema; /** * @deprecated use {@link SchemaOptionsNormalized.sorts}. Removed in 3.0. */ sort: SortsOptions | SortsSchema; /** * Ordered column lists of the record's storage indexes, consumed * by the per-parameter `indexed` opt-ins (filters, sorts). See * {@link IndexesOption}. */ indexes: IndexesOption; }; type SchemaOptions = Partial>; /** * Options for {@link Schema.describe}. */ type SchemaDescribeOptions = { /** * Restrict the description to a subset of parameters, mirroring * a parse/decode surface that only processes some of them (e.g. * a single-record read handling `fields` and `relations` only). * Defaults to every parameter. */ parameters?: `${Parameter}`[]; }; /** * JSON-serializable snapshot of the constraints a schema declares — * the introspection surface an API can hand to its consumers so the * queryable vocabulary is discoverable without reading server code. * * The shape is NORMALIZED so every schema describes identically: * - a parameter key is present iff the description covers that * parameter ({@link SchemaDescribeOptions.parameters}; all of them * by default), and always carries every constraint key; * - within a parameter, a `null` constraint was never declared * (fallback semantics apply — by default the syntactic property-name * check, under {@link BaseSchemaOptions.strict} a full reject); * - an empty array is an explicit "nothing allowed". * * Relation capabilities are not expanded inline: `relations.schemas` * names the schema governing each relation, whose own description * covers the dotted vocabulary reachable through it. * * Dynamic constraints (validate/validateMany hooks, e.g. per-actor * authorization gates) are deliberately not represented — the * description is the static upper bound. */ type SchemaDescription = { name: string | null; strict: boolean; indexes: string[][] | null; fields?: FieldsSchemaDescription; filters?: FiltersSchemaDescription; pagination?: PaginationSchemaDescription; relations?: RelationsSchemaDescription; sorts?: SortsSchemaDescription; }; //#endregion //#region src/schema/parameter/fields/types.d.ts type FieldsOptions = Record, CONTEXT = any> = KeyValidatableSchemaOptions & { mapping?: Record; allowed?: FieldKeys[]; default?: FieldKeys[]; /** * Dynamic per-field gate, e.g. an actor permission check. * Runs once per client-requested field against the schema that * governs it (the target schema for dotted keys). Schema defaults * bypass the hook. * * Answering with an `ICondition` keeps the field and marks it * visible only on rows satisfying that condition. The condition is * carried on the resulting `Field` node and never narrows the row * set. Mutually exclusive with {@link FieldsOptions.validateMany}. */ validate?: KeyValidator; /** * Batched form of {@link FieldsOptions.validate}: called once per * relation position with every client-requested field this schema * governs there, so an authorization policy can be compiled once * instead of once per field. A field missing from the returned * record is rejected. Mutually exclusive with `validate`. */ validateMany?: KeyValidatorMany; }; /** * JSON-serializable snapshot of the fields constraints a schema * declares. The shape is uniform across schemas: a `null` constraint * was never declared (fallback semantics apply); an empty array is an * explicit "nothing". */ type FieldsSchemaDescription = { default: string[] | null; allowed: string[] | null; }; //#endregion //#region src/schema/base.d.ts declare class BaseSchema { protected options: OPTIONS; constructor(options: OPTIONS); set name(input: string | undefined); get name(): string | undefined; set throwOnFailure(input: boolean | undefined); get throwOnFailure(): boolean | undefined; set strict(input: boolean | undefined); get strict(): boolean | undefined; mapSchema(input: string): string; } //#endregion //#region src/schema/key-validatable.d.ts /** * Shared base of the three sub-schemas whose keys go through the * key-validation pass: fields, relations and sorts. Owns the `validate` / * `validateMany` hook pair so the mutual-exclusion rule and the * no-hook fast path are stated once. */ declare class BaseKeyValidatableSchema extends BaseSchema { /** * The parameter this sub-schema governs. Declared once, by the * subclass — the validation driver derives the hook scope and the * condition rules from it, so call sites never respecify it. */ readonly parameter: `${Parameter}`; constructor(options: OPTIONS, parameter: `${Parameter}`); hasValidator(): boolean; hasManyValidator(): boolean; /** * Invoke the per-key hook for `name`. The caller supplies only the * dotted relation path of the position being validated (`''` at the * query root) — the schema completes the hook scope from what it * already knows about itself (its parameter, its registered name). */ validate(name: string, context: any, path?: string): MaybeAsync; validateMany(names: string[], context: any, path?: string): MaybeAsync; protected scope(path: string): KeyValidationScope; } //#endregion //#region src/schema/parameter/fields/schema.d.ts declare class FieldsSchema extends BaseKeyValidatableSchema> { default: string[]; defaultIsUndefined: boolean; allowed: string[]; allowedIsUndefined: boolean; reverseMapping: Record; constructor(input?: FieldsOptions); /** * Check whether all fields are denied. */ get allDenied(): boolean; get mapping(): Record | undefined; setDefault(input?: FieldKeys[]): void; setAllowed(input?: FieldKeys[]): void; hasDefaults(): boolean; /** * Serialize the declared constraints. Arrays are cloned, so a * consumer mutating the description never touches the schema. */ describe(): FieldsSchemaDescription; /** * Check whether a name exists for a group. * * @param name */ isValid(name: string): boolean; protected initReverseMapping(): void; private buildReverseRecord; } //#endregion //#region src/schema/parameter/fields/define.d.ts declare function defineFieldsSchema(options?: FieldsOptions): FieldsSchema; //#endregion //#region src/schema/parameter/filters/constants.d.ts declare enum FilterFieldOperator { EQUAL = "eq", NOT_EQUAL = "ne", LESS_THAN_EQUAL = "lte", LESS_THAN = "lt", GREATER_THAN_EQUAL = "gte", GREATER_THAN = "gt", IN = "in", NOT_IN = "nin", STARTS_WITH = "startsWith", NOT_STARTS_WITH = "notStartsWith", ENDS_WITH = "endsWith", NOT_ENDS_WITH = "notEndsWith", CONTAINS = "contains", NOT_CONTAINS = "notContains", REGEX = "regex", MOD = "mod", SIZE = "size", EXISTS = "exists", ELEM_MATCH = "elemMatch" } declare enum FilterCompoundOperator { AND = "and", OR = "or", NOT = "not" } //#endregion //#region src/schema/parameter/filters/types.d.ts /** * Per-leaf filter validation hook. The return value decides the leaf's fate: * return the input filter to accept it, another condition to replace it, or * `undefined` to reject it. The replacement may be any `ICondition`, * including a compound (`and(...)`/`or(...)`), so a single authorization * decision like "you may filter on realm_id, but only within your realms" * can stay attached to the leaf that triggered it. An inspect-only hook * must therefore end with `return input` — a bare block body would reject * every filter. The result may also be a Promise of any of those values; * resolving it requires the `parseAsync()` / `decodeAsync()` / * `encodeAsync()` entry points. * * The second argument is the value passed to `parse()` / `decode()` via * the `context` option (`undefined` when the caller supplied none), so a * shared schema can make per-request decisions (e.g. actor permissions). */ type Validator = (input: IFilter, context: CONTEXT) => MaybeAsync; type FiltersOptions = BaseSchemaOptions & { mapping?: Record; allowed?: SimpleKeys[]; default?: ICondition; validate?: Validator; /** * Field keys whose equality comparisons (eq/ne/in/nin) stay * case-sensitive instead of the case-insensitive default — * e.g. identifier or token columns. Keys are resolved names * (after mapping), matching the entries of `allowed`. */ caseSensitive?: SimpleKeys[]; /** * Check parsed filter trees against the schema-level `indexes` * declaration: `true`/`'anchor'` requires one index-leading * conjunct per AND group, `'cover'` full prefix coverage. */ indexed?: boolean | IndexedMode; }; /** * JSON-serializable snapshot of the filter constraints a schema * declares. Only the consumer-facing vocabulary is exposed — the * `default` condition is a server-injected baseline, not something * a client can send, so it is deliberately absent. The shape is * uniform across schemas: a `null` allow-list was never declared * (fallback semantics apply); an empty array is an explicit * "nothing". */ type FiltersSchemaDescription = { allowed: string[] | null; caseSensitive: string[] | null; indexed: IndexedMode | false; }; //#endregion //#region src/schema/parameter/filters/schema.d.ts declare class FiltersSchema extends BaseSchema> { default: ICondition | undefined; defaultIsUndefined: boolean; allowed: string[]; allowedIsUndefined: boolean; caseSensitive: string[]; caseSensitiveIsUndefined: boolean; indexes: string[][]; indexesIsUndefined: boolean; indexed: IndexedMode | false; constructor(input?: FiltersOptions); get mapping(): Record | undefined; hasDefaults(): boolean; /** * Serialize the declared constraints. Arrays are cloned, so a * consumer mutating the description never touches the schema. */ describe(): FiltersSchemaDescription; hasValidator(): boolean; validate(input: IFilter, context: CONTEXT): MaybeAsync; setDefault(input?: ICondition): void; setAllowed(input?: SimpleKeys[]): void; setCaseSensitive(input?: SimpleKeys[]): void; setIndexes(input?: string[][]): void; } //#endregion //#region src/schema/parameter/filters/define.d.ts declare function defineFiltersSchema(options?: FiltersOptions): FiltersSchema; //#endregion //#region src/schema/parameter/pagination/types.d.ts type PaginationOptions = BaseSchemaOptions & { maxLimit?: number; }; /** * JSON-serializable snapshot of the pagination constraints a schema * declares. The shape is uniform across schemas: a `null` `maxLimit` * means no cap was declared. */ type PaginationSchemaDescription = { maxLimit: number | null; }; //#endregion //#region src/schema/parameter/pagination/schema.d.ts declare class PaginationSchema extends BaseSchema { get maxLimit(): number | undefined; /** * Serialize the declared constraints. */ describe(): PaginationSchemaDescription; } //#endregion //#region src/schema/parameter/pagination/define.d.ts declare function definePaginationSchema(options?: PaginationOptions): PaginationSchema; //#endregion //#region src/schema/parameter/relations/types.d.ts type RelationsOptions = Record, CONTEXT = any> = KeyValidatableSchemaOptions & { allowed?: SimpleResourceKeys[]; includeParents?: boolean | string[] | string; mapping?: Record; pathMapping?: Record; /** * Dynamic per-relation gate, e.g. an actor permission check. * Runs on the canonical relation name relative to this schema — * `include=client.realm` invokes the root schema's hook with * `client` and the client schema's hook with `realm`. Rejecting * a relation also drops every deeper relation reached through it. * * A relation is not a column, so there is nothing for an * `ICondition` answer to gate and it counts as a rejection. * Row-level narrowing of an included relation is tracked in #810. * Mutually exclusive with {@link RelationsOptions.validateMany}. */ validate?: KeyValidator; /** * Batched form of {@link RelationsOptions.validate}: called once per * relation position with every relation this schema governs there. * A relation missing from the returned record is rejected. * Mutually exclusive with `validate`. */ validateMany?: KeyValidatorMany; }; /** * JSON-serializable snapshot of the relation constraints a schema * declares. `schemas` maps each allowed relation to the name of the * schema governing it (composed by {@link Schema.describe} via the * parent `schemaMapping`; an unmapped relation maps to itself, * mirroring registry resolution) — nested capabilities are looked up * on that schema's own description instead of being expanded inline. * The shape is uniform across schemas: a `null` allow-list was never * declared (fallback semantics apply; the targets cannot be * enumerated then, so `schemas` is `null` alongside it), an empty * array is an explicit "nothing" (with an empty `schemas` record). */ type RelationsSchemaDescription = { allowed: string[] | null; schemas: Record | null; }; //#endregion //#region src/schema/parameter/relations/schema.d.ts declare class RelationsSchema extends BaseKeyValidatableSchema> { constructor(input?: RelationsOptions); get allowed(): SimpleResourceKeys[] | undefined; get mapping(): Record; /** * Serialize the declared constraints. The array is cloned, so a * consumer mutating the description never touches the schema. * The `schemas` target map is composed by {@link Schema.describe}, * since the schema mapping lives on the parent schema. */ describe(): RelationsSchemaDescription; } //#endregion //#region src/schema/parameter/relations/define.d.ts declare function defineRelationsSchema(options?: RelationsOptions): RelationsSchema; //#endregion //#region src/schema/parameter/sort/constants.d.ts declare enum SortDirection { ASC = "ASC", DESC = "DESC" } //#endregion //#region src/schema/parameter/sort/types.d.ts type SortsOptionDefault> = { [K in SimpleKeys]?: `${SortDirection}`; }; type SortsOptions = Record, CONTEXT = any> = KeyValidatableSchemaOptions & { allowed?: SimpleKeys[]; mapping?: Record; default?: SortsOptionDefault; /** * Check requested sort keys against the schema-level `indexes` * declaration: they must form a leftmost prefix of one index, * in order; directions are ignored. */ indexed?: boolean; /** * Dynamic per-sort-key gate, e.g. an actor permission check. * Runs once per client-requested sort key against the schema that * governs it (the target schema for dotted keys), before the index * policy is applied. Schema defaults bypass the hook. * * An ordering is not a row set, so there is nothing for an * `ICondition` answer to gate and it counts as a rejection. * Mutually exclusive with {@link SortsOptions.validateMany}. */ validate?: KeyValidator; /** * Batched form of {@link SortsOptions.validate}: called once per * relation position with every sort key this schema governs there. * A key missing from the returned record is rejected. * Mutually exclusive with `validate`. */ validateMany?: KeyValidatorMany; }; /** * JSON-serializable snapshot of the sort constraints a schema * declares. The shape is uniform across schemas: a `null` * constraint was never declared (fallback semantics apply); an empty * array is an explicit "nothing". */ type SortsSchemaDescription = { allowed: string[] | null; default: Record | null; indexed: boolean; }; //#endregion //#region src/schema/parameter/sort/schema.d.ts declare class SortsSchema extends BaseKeyValidatableSchema> { default: Record; defaultKeys: string[]; defaultIsUndefined: boolean; allowed: string[]; allowedIsUndefined: boolean; indexes: string[][]; indexesIsUndefined: boolean; indexed: boolean; constructor(input?: SortsOptions); get mapping(): Record | undefined; /** * Serialize the declared constraints. Arrays and records are * cloned, so a consumer mutating the description never touches * the schema. An allow-list derived from `default` keys (see * {@link SortsSchema.buildAllowed}) serializes like a declared one. */ describe(): SortsSchemaDescription; setIndexes(input?: string[][]): void; protected buildDefault(): void; protected buildAllowed(): void; } //#endregion //#region src/schema/parameter/sort/define.d.ts declare function defineSortsSchema(options?: SortsOptions): SortsSchema; //#endregion //#region src/schema/parameter/sort/deprecated.d.ts /** * @deprecated use {@link SortsSchema}. Removed in 3.0. */ declare const SortSchema: typeof SortsSchema; /** * @deprecated use {@link SortsSchema}. Removed in 3.0. */ type SortSchema = SortsSchema; /** * @deprecated use {@link defineSortsSchema}. Removed in 3.0. */ declare const defineSortSchema: typeof defineSortsSchema; /** * @deprecated use {@link SortsOptions}. Removed in 3.0. */ type SortOptions = Record, CONTEXT = any> = SortsOptions; /** * @deprecated use {@link SortsOptionDefault}. Removed in 3.0. */ type SortOptionDefault> = SortsOptionDefault; /** * @deprecated use {@link SortsSchemaDescription}. Removed in 3.0. */ type SortSchemaDescription = SortsSchemaDescription; //#endregion //#region src/schema/module.d.ts declare class Schema extends BaseSchema> { readonly fields: FieldsSchema; readonly filters: FiltersSchema; readonly pagination: PaginationSchema; readonly relations: RelationsSchema; readonly sorts: SortsSchema; /** * @deprecated use {@link Schema.sorts}. The identical instance. * Removed in 3.0. */ readonly sort: SortsSchema; readonly indexes: string[][]; readonly indexesIsUndefined: boolean; constructor(options?: SchemaOptions); /** * Reassigning the name restamps every sub-schema, which the * constructor otherwise does once. A sub-schema reaches back into * the registry by the name it carries, so a stale one would resolve * to the schema this one used to be. */ set name(input: string | undefined); get name(): string | undefined; private propagateName; /** * Serialize the declared constraints of every (selected) * parameter into a JSON-safe {@link SchemaDescription}. The * relation target map is composed here, since the schema * mapping lives on this schema — an unmapped relation maps to * itself, mirroring registry resolution. */ describe(options?: SchemaDescribeOptions): SchemaDescription; private extendSchemasOptions; private extendSchemaOptions; } //#endregion //#region src/schema/registry/module.d.ts declare class SchemaRegistry { protected entities: Map>; constructor(); add(schema: Schema): void; drop(name: string): void; get(name: Schema | string): Schema | undefined; getOrFail(name: string | Schema): Schema; /** * Every registered schema, in registration order. The array is a fresh * snapshot the caller owns: sorting or splicing it changes nothing here, * and a later {@link add} or {@link drop} leaves an array already held * untouched. Its elements are the live instances {@link get} returns, so * one can be handed straight back to a parser, a codec or an adapter. */ getAll(): Schema[]; resolve(...input: (undefined | Schema | string)[]): Schema | undefined; } //#endregion //#region src/schema/resolver/constants.d.ts declare const KeyResolutionErrorCode: { readonly KEY_INVALID: "keyInvalid"; readonly KEY_NOT_PERMITTED: "keyNotPermitted"; readonly PATH_NOT_PERMITTED: "pathNotPermitted"; readonly SCHEMA_UNRESOLVABLE: "schemaUnresolvable"; }; type KeyResolutionErrorCode = typeof KeyResolutionErrorCode[keyof typeof KeyResolutionErrorCode]; //#endregion //#region src/errors/code.d.ts declare enum ErrorCode { NONE = "none", /** * One or more parts of the input were rejected. The code of an aggregated * parse failure: what was rejected, and why, is in `error.issues`: a * request can violate several policies at once, and naming one of them on * the error would describe a subset of what went wrong. */ INPUT_REJECTED = "inputRejected", INPUT_INVALID = "inputInvalid", SYNTAX_INVALID = "syntaxInvalid", KEY_INVALID = "keyInvalid", KEY_PATH_INVALID = "keyPathInvalid", KEY_NOT_ALLOWED = "keyNotAllowed", KEY_PATH_NOT_ALLOWED = "keyPathNotAllowed", KEY_VALUE_INVALID = "keyValueInvalid", KEY_VALIDATE_REJECTED = "keyValidateRejected", KEY_UNKNOWN = "keyUnknown", KEY_AMBIGUOUS = "keyAmbiguous", KEY_COMBINATION_NOT_INDEXED = "keyCombinationNotIndexed", LIMIT_EXCEEDED = "limitExceeded", OPERATOR_UNSUPPORTED = "operatorUnsupported", FEATURE_UNSUPPORTED = "featureUnsupported", FIELDS_CONDITION_DISCARDED = "fieldsConditionDiscarded", CONDITION_DETACHED = "conditionDetached", CODEC_UNRESOLVABLE = "codecUnresolvable", SCHEMA_ENTITY_INDEX_MISMATCH = "schemaEntityIndexMismatch", SCHEMA_ENTITY_MISMATCH = "schemaEntityMismatch", SCHEMA_KEY_VALIDATOR_CONFLICT = "schemaKeyValidatorConflict", SCHEMA_NAME_INVALID = "schemaNameInvalid", SCHEMA_PRESERVED_CONDITION_PRUNED = "schemaPreservedConditionPruned", SCHEMA_UNRESOLVABLE = "schemaUnresolvable", SCHEMA_VALIDATOR_ASYNC_REQUIRES_ASYNC_PARSER = "schemaValidatorAsyncRequiresAsyncParser" } //#endregion //#region src/errors/types.d.ts /** * rapiq's own codes, without closing the vocabulary. * * The literals keep autocomplete and catch a typo in `e.code === '…'`, which * matters because branching on `code` is the documented machine contract. The * open half is not slack: a trace can merge issues another library recorded, * and a consumer's own error class carries its own code, so a closed union * would be describing a world rapiq does not control. Same idiom blemish uses * for `IssueItem.code`, so the two agree. */ type ErrorCodeInput = `${ErrorCode}` | (string & {}); type BaseErrorOptions = { code?: ErrorCodeInput; message: string; /** * The originating error, passed through to the native ES2022 `cause` * so a wrapped failure keeps its origin. */ cause?: unknown; /** * The trace this error was rebuilt from. See {@link BaseError.issues}. */ issues?: readonly Issue[]; }; /** * The shape every error rapiq raises satisfies: an `@ebec/core` error carrying * a machine-readable {@link ErrorCode} and the trace it was raised from. */ interface IBaseError extends IBaseError$1 { readonly code: ErrorCodeInput; readonly issues: readonly Issue[]; } /** * A client-input failure, as consumers see it. */ interface IParseError extends IBaseError {} /** * What `JSON.stringify` emits for a rapiq error. * * `issues` is the point of it: an error that crosses a boundary without its * trace has nothing to say on the far side. The `@instanceof` chain rides * along so `isBaseError` / `isParseError` still recognize the value once it is * a plain object: the guards match the serialized chain, not just a live * brand. Issue `expected` and `received` members are omitted at runtime even * though blemish's optional members keep this structural type assignable. */ type SerializedError = { name: string; message: string; code: ErrorCodeInput; issues: readonly Issue[]; cause?: unknown; '@instanceof': string[]; }; //#endregion //#region src/errors/base.d.ts /** * The root of rapiq's error hierarchy. * * Extends `@ebec/core`'s, the house error substrate, for everything an error * base does the same way everywhere: the class name, the stack capture, the * `code`, the `cause` passthrough and the brand chain. rapiq adds the one * thing that is its own, the trace, and narrows `code` to its vocabulary. * * What it does NOT take is the group half. `errors: Error[]` stays unset, * because everything rapiq aggregates is a client-input rejection, which is * data and lives in {@link issues}; minting an `Error` per rejected key is the * carrier this design exists to avoid. */ declare class BaseError extends BaseError$1 implements IBaseError { /** * Every rejection the operation recorded, in the order it hit them. * Empty unless the operation collected a trace. * * An ordinary enumerable property, so it shows up when the error is * inspected or spread. The cost, chosen deliberately: deep equality reads * enumerable properties, so two failures of the same kind compare equal * only when their traces match: `toThrow(SomeError.keyNotPermitted('x'))` * asserts the trace too. Assert the class or the code, or reach into * `issues`, rather than comparing whole errors. */ readonly issues: readonly Issue[]; constructor(input: BaseErrorOptions | string); /** * The wire form: the base's, plus the one thing rapiq adds. * * An error whose trace does not survive the boundary has nothing to say on * the far side, and the `@instanceof` chain the base emits is what lets * `isParseError` answer for the plain object that arrives. */ toJSON(): SerializedError; } //#endregion //#region src/errors/adapter.d.ts type AdapterErrorOptions = BaseErrorOptions & { /** * The capability tag {@link AdapterError.featureUnsupported} refuses * (e.g. `regexp`, `filters:mod`, `filters:regex`), structured * alongside `code` so a consumer can build a capability matrix * without parsing the message. `undefined` for every other factory. */ feature?: string; }; declare class AdapterError extends BaseError { readonly feature: string | undefined; constructor(message?: string | AdapterErrorOptions); static operatorUnsupported(operator: string): AdapterError; /** * A condition the built-in consumer cannot lower: either a live custom * implementation that needs its own consumer or detached transport data * that lost its behavior. Dropping it would silently widen the result set. */ static conditionDetached(operator?: string): AdapterError; static featureUnsupported(feature: string): AdapterError; } //#endregion //#region src/errors/build.d.ts declare class BuildError extends BaseError { constructor(message?: string | BaseErrorOptions); static inputInvalid(): BuildError; static keyInvalid(key: string): BuildError; static keyValueInvalid(key: string): BuildError; static operatorUnsupported(operator: string): BuildError; static keyUnknown(key: string, suggestion?: string): BuildError; static keyAmbiguous(canonical: string, alias: string): BuildError; } //#endregion //#region src/errors/check.d.ts /** * Cross-realm brands for the error hierarchy, mirroring `CONDITION_MARKER`. * * `instanceof` compares class identity, which two copies of `@rapiq/core` in * one process (mixed ESM/bundled builds, a dual-packaged dependency) do not * share. The failure mode is quiet and bad: a parse would rethrow a foreign * `ParseError` instead of recording it, and the trace would come back empty. * * `@ebec/core` owns the mechanism, which is the house standard and stronger * than one boolean per level: the markers form a CHAIN under one * non-enumerable `@instanceof` key, so a subclass is recognized as its * ancestors without marking itself twice, and the chain is serialized by * {@link BaseError.toJSON}, so `matchesInstanceof` also recognizes an * error that crossed a boundary as JSON and came back as a plain object. * * Only the brand utilities are borrowed. rapiq keeps its own `BaseError`, * interfaces and wire shape, and deliberately does NOT take ebec's error-group * mechanism (`errors: Error[]`): everything rapiq aggregates is a client-input * rejection, which is data, and lives in `issues`. */ declare const BASE_ERROR_MARKER: unique symbol; declare const PARSE_ERROR_MARKER: unique symbol; /** * Whether the value is an error this library raised. * * Prefer it to `instanceof BaseError` on any boundary a foreign copy of the * library, or a serialized error, could reach. */ declare function isBaseError(input: unknown): input is IBaseError; /** * Whether the value is a client-input failure. */ declare function isParseError(input: unknown): input is IParseError; //#endregion //#region src/errors/codec.d.ts declare class CodecError extends BaseError { constructor(message?: string | BaseErrorOptions); static notResolvable(name?: string): CodecError; } //#endregion //#region src/errors/issue/constants.d.ts /** * Upper bound of leaf issues one parse records. Hostile input can violate a * policy once per key, and the trace is a diagnostic, not a transcript: what * the parse raises (`INPUT_REJECTED`, as the parse that failed) does not * depend on how many rejections it holds, so a truncated tail changes nothing * about the outcome. */ declare const MAX_ISSUES = 100; //#endregion //#region src/errors/issue/types.d.ts /** * What a rapiq site reports when it rejects client input. * * The stored node is blemish's; this is the shape its producers speak, so a * recording site names `parameter` under type control rather than assembling * an untyped `meta` bag itself. * * `parameter` and `key` become blemish `meta` keys. Both meet its documented * bar for that field (provenance a consumer cannot reconstruct from `path`), * and neither is a rendering decision: a `fields` rejection and a `filters` * rejection at `['items', 'secret']` are indistinguishable by path, and the * path is alias-resolved, so the spelling the client sent is gone from it. */ type IssueInput = { /** * The parameter that owns the policy the input violated. A relation path * rejected inside a `fields` key reports `fields`, matching the error * class that parameter throws. */ parameter?: `${Parameter}`; /** * The raw client key, before alias mapping, recorded when it differs * from the canonical path. */ key?: string; /** * Machine contract, shared with the thrown error's `code`. */ code: ErrorCodeInput; /** * Canonical (alias-resolved) position, leaf included: `['items', 'title']` * for `items.title`. Empty for a parameter-level issue. */ path: string[]; /** * Human-facing text. NOT contractual: branch on `code`. */ message: string; /** * The offending value, echoed as received. Absent when the key itself, * not a value, was the problem. */ received?: unknown; }; //#endregion //#region src/errors/issue/module.d.ts /** * Build the issue a rapiq site reports. * * The parameter is normalized here, at the one point where it is still * typed: past this call it lives in blemish's open `meta` bag, where the * deprecated `sort` spelling would survive unnoticed. */ declare function buildIssue(input: IssueInput): IssueItem; /** * The parameter that owns the policy an issue reports, or undefined for an * issue no single parameter owns. * * `meta` is an open bag by design (issues cross library boundaries), so the * read is narrowed here once rather than at every consumer. */ declare function extractIssueParameter(input: Issue): `${Parameter}` | undefined; /** * The raw client key an issue was recorded for, when it differs from the * canonical (alias-resolved) path. */ declare function extractIssueKey(input: Issue): string | undefined; //#endregion //#region src/errors/merge.d.ts declare class MergeError extends BaseError { constructor(message?: string | BaseErrorOptions); static fieldsConditionDiscarded(name: string): MergeError; } //#endregion //#region src/errors/messages.d.ts /** * The message text of every client-input failure, as pure builders. * * A failure surfaces through two channels, a thrown {@link ParseError} and a * plain-data {@link Issue}, and both must read identically: an aggregated * error is rebuilt from its issue, so a divergence here would change a thrown * message depending on the failure policy. Building the text without * constructing an `Error` also keeps the drop-mode trace free of stack capture. */ declare const ErrorMessage: { readonly inputInvalid: () => string; readonly inputRejected: (count: number) => string; readonly syntaxInvalid: (details?: string) => string; readonly keyNotPermitted: (name: string) => string; readonly keyInvalid: (key: string) => string; readonly keyPathInvalid: (key: string) => string; readonly keyPathNotPermitted: (key: string) => string; readonly keyValueInvalid: (key: string) => string; readonly keyValidateRejected: (key: string) => string; readonly keyCombinationNotIndexed: (keys: string[]) => string; readonly operatorUnsupported: (operator: string) => string; readonly featureUnsupported: (feature: string) => string; readonly keyAmbiguous: (canonical: string, alias: string) => string; readonly limitExceeded: (limit: number) => string; }; //#endregion //#region src/errors/parse.d.ts declare class ParseError extends BaseError implements IParseError { constructor(message?: string | BaseErrorOptions); /** * The failure an aggregated parse raises: every violation it found, on * `issues`. Deliberately NOT the first violation's own class and code: * a parse that rejected keys in four parameters would then advertise one * of them, and a consumer branching on that would act on a subset of what * went wrong. The specific classes stay what a single violation throws * where no trace is collecting. * * A structural abort caught on the way is not carried either: only branded * parse errors are ever caught (a server bug propagates untouched), and * everything a client-input failure knows is already in its issue. */ static inputRejected(issues: readonly Issue[]): ParseError; static inputInvalid(): ParseError; static syntaxInvalid(details?: string): ParseError; static keyNotPermitted(name: string, issues?: readonly Issue[]): ParseError; static keyInvalid(key: string, issues?: readonly Issue[]): ParseError; static keyPathInvalid(key: string, issues?: readonly Issue[]): ParseError; static keyPathNotPermitted(key: string, issues?: readonly Issue[]): ParseError; static keyValueInvalid(key: string): ParseError; static keyValidateRejected(key: string, issues?: readonly Issue[]): ParseError; static keyCombinationNotIndexed(keys: string[]): ParseError; static operatorUnsupported(operator: string): ParseError; static featureUnsupported(feature: string): ParseError; static keyAmbiguous(canonical: string, alias: string): ParseError; } //#endregion //#region src/errors/schema.d.ts declare class SchemaError extends BaseError { constructor(message?: string | BaseErrorOptions); static nameUndefined(): SchemaError; static notResolvable(name: string): SchemaError; static keyValidatorConflict(parameter: string): SchemaError; static preservedConditionPruned(relation: string, field: string): SchemaError; static preservedConditionNotIndexed(keys: string[]): SchemaError; static validatorAsyncRequiresAsyncParser(): SchemaError; static keyUnknown(key: string, suggestion?: string): SchemaError; static keyAmbiguous(canonical: string, alias: string): SchemaError; } //#endregion //#region src/parser/issue/types.d.ts /** * The trace of one parse call: it collects what its sites record and serves * it back. It does not raise, and it does not build errors: a trace is * evidence, and deciding what to throw from it belongs to the caller that * owns the parse. * * Referenced instead of the class wherever a trace is threaded, so a parser * that wants to observe or wrap the recording can supply its own. */ interface IIssueCollector { /** * Add a rejection. A dropping policy adds nothing, which is the caller's * decision, made where the policy is known. */ add(input: IssueInput): void; /** * Record a thrown parse error as the issue it never got to be, or its * whole trace when it carries one. */ addError(input: IParseError, parameter?: `${Parameter}`, path?: string[]): void; /** * Take over the issues of a nested trace, rebased onto the position it * was merged at. */ merge(issues: readonly Issue[], path?: string[]): void; readonly issues: Issue[]; readonly failed: boolean; } //#endregion //#region src/parser/issue/module.d.ts /** * The trace of one parse call: every issue its sites recorded, and which of * them the parse failed on. * * A collector inverts the failure policy. Instead of throwing where a * violation is found, a site records it and takes the drop path, so a request * with several bad keys reports all of them. What to do about that is not its * decision: it collects and serves, and the call that owns the parse raises * the failure (`BaseParser.finishIssues`). * * Every issue is a failure. Under a dropping policy nothing is recorded at * all: the key is dropped, nothing will be raised, and a trace nobody can read * is a trace nobody should pay for. * * The trace is not observable anywhere else: a parse that raises nothing * discards it. `error.issues` is the single channel. * * A site without a collector keeps throwing immediately: `ResolutionScope` is * public API and usable outside a parse, where nobody would ever raise the * trace. */ declare class IssueCollector implements IIssueCollector { protected items: Issue[]; private terminalItems; private get leafCount(); /** * Add a rejection. * * Whether one is added at all is the caller's decision, made where the * failure policy is known: a dropping policy adds nothing, because there * is no failure to raise and so nobody to read it. The trace does not * second-guess that: it would mean building an issue in order to bin it, * and a collector that filters is a collector with an opinion. */ add(input: IssueInput): void; /** * Record a thrown parse error as the issue it never got to be: the * structural failures (a malformed expression, an input of the wrong * shape) abort their parameter instead of dropping one key, so the * caller catches them here. The error OBJECT is not kept: only branded * parse errors are ever recorded (a server bug propagates untouched), and * everything a client-input failure knows is in the issue it becomes. * * A throw that already carries a trace hands over that trace rather than * a summary of it: the positions its sites recorded are the ones no * enclosing site could reconstruct. */ addError(input: IParseError, parameter?: `${Parameter}`, path?: string[]): void; /** * Take over the issues of a nested trace, rebased onto the position it * was merged at. */ merge(issues: readonly Issue[], path?: string[]): void; protected record(input: Issue, options?: { ensure?: boolean; terminal?: boolean; }): boolean; get issues(): Issue[]; get failed(): boolean; } //#endregion //#region src/parser/parameter/validate.d.ts /** * The slice of a parameter schema the key-validation pass consumes — * implemented by RelationsSchema, FieldsSchema and SortsSchema. The * batched members are optional, so an external implementation without * them stays source compatible and is simply driven per key. */ type KeyValidatableSchema = { readonly name?: string; /** * The parameter this schema governs. Declared once by the schema * (the sub-schema classes set it in their constructors); the * driver derives the condition rules from it per entry, so mixed * obligation pools (a relation ledger fed by every parameter) need * no caller-side annotation. */ readonly parameter: `${Parameter}`; hasValidator(): boolean; hasManyValidator?(): boolean; /** * The caller supplies only the dotted relation path of the position * being validated (`''` at the query root); the schema completes the * {@link KeyValidationScope} its hook receives from what it already * knows about itself. The path is REQUIRED on this driver contract: * an omitted path would silently claim the root position, which * fails open for an allow-at-root hook. (The schema classes default * it for direct human calls; a defaulted method still satisfies the * required signature.) */ validate(name: string, context: any, path: string): MaybeAsync; validateMany?(names: string[], context: any, path: string): MaybeAsync; }; /** * A client-requested key whose governing schema may carry a validate * hook. Parsers record one entry per resolved key during resolution * and evaluate them once the parameter is assembled, so the sync and * async entry points share a single resolution pass. */ type PendingKeyValidation = { /** * The hook argument — the canonical key relative to the schema * that governs it (the target schema for dotted input). */ key: string; /** * Final dotted output name; parsers prefix it with the relation * segment while their recursion unwinds. Used for pruning. */ path: string; schema: KeyValidatableSchema; /** * The failure policy of the scope that resolved this key, recorded * at push time so a child schema's own `throwOnFailure` governs its * rejections even inside a pooled pending list. Falls back to the * pass-wide {@link KeyValidationOptions.throwOnFailure} when absent * (the relation ledger, whose policy is the root relations schema's * by contract). */ throwOnFailure?: boolean; }; type KeyValidationOptions = { throwOnFailure: boolean; errors: typeof ParseError; /** * Trace of the enclosing parse. A rejection records an issue there and * lets the parse continue on the drop path; the owning call raises it. */ issueCollector?: IIssueCollector; /** * Sink for the conditions of condition-gated keys, keyed by output * path. Supplied by callers that can carry a condition onward (the * fields parsers, onto the `Field` node). Absent means a condition * verdict has nowhere to go and counts as a rejection. */ conditions?: Map; }; /** * Evaluate the recorded validate-hook obligations. Returns the output * names (paths) of rejected keys for the caller to prune — or throws * the parameter's ParseError (`ErrorCode.KEY_VALIDATE_REJECTED`) under * `throwOnFailure`, naming the full client-facing path. Duplicate * obligations (the same key recorded twice, e.g. from duplicated * client input) invoke the hook once. A hook returning a Promise here * means the caller sits behind a synchronous `parse()`; that is * refused the same way as an async filters validator. */ declare function applyKeySchemaValidation(pending: PendingKeyValidation[], context: unknown, options: KeyValidationOptions): string[]; /** * Async counterpart of {@link applyKeySchemaValidation}. Hooks are * awaited sequentially so observable execution order matches the * synchronous pass. */ declare function applyKeySchemaValidationAsync(pending: PendingKeyValidation[], context: unknown, options: KeyValidationOptions): Promise; //#endregion //#region src/schema/resolver/types.d.ts type ParameterSchema

= P extends `${Parameter.FIELDS}` ? FieldsSchema : P extends `${Parameter.FILTERS}` ? FiltersSchema : P extends `${Parameter.PAGINATION}` ? PaginationSchema : P extends `${Parameter.RELATIONS}` ? RelationsSchema : P extends `${Parameter.SORTS}` | `${Parameter.SORT}` ? SortsSchema : never; type KeyResolutionSuccess

= { success: true; /** * Canonical (alias-resolved) leaf field name. */ name: string; /** * Canonical relation path segments; empty for own attributes. */ path: string[]; /** * Scope governing the leaf: `this` for local keys, * a descendant scope for dotted keys. */ scope: ResolutionScope; }; type KeyResolutionFailure = { success: false; code: KeyResolutionErrorCode; /** * Raw input key. */ input: string; /** * Canonical offending token (path segment or leaf name). */ segment?: string; }; type KeyResolution

= KeyResolutionSuccess | KeyResolutionFailure; type ResolutionScopeContext = { /** * Parsed relations governing which relation segments may be entered. */ relations?: IRelations; /** * Failure-policy override: takes precedence over the schema-level setting. */ throwOnFailure?: boolean; /** * Failure policy for KEY RESOLUTION alone (allow-list and traversal * verdicts), taking precedence over {@link throwOnFailure} there and * nowhere else. * * For a dialect whose resolution cannot drop: the expression parser * forces it, because an expression cannot be partially reinterpreted. * That says nothing about whether a relations validator declining a * relation should fail the request, which stays the caller's * `throwOnFailure`, the same separation the filters leaf validator makes * with its own override. */ resolutionThrowOnFailure?: boolean; /** * Strict-mode override: takes precedence over the schema-level setting. * Under strict mode a parameter without an explicit allow-list rejects * every client key instead of falling back to the syntactic name check. */ strict?: boolean; /** * Relation-authorization ledger. When present, every relation a resolved key * traverses (and a relation targeted directly, e.g. by `$size`/`$elemMatch`) * is appended as a {@link PendingKeyValidation} obligation, so the caller can * evaluate the relations validate hook once per distinct relation and prune * the dependent keys. Absent: resolution records nothing. */ obligationSink?: PendingKeyValidation[]; /** * Trace of the parse this scope resolves for. When present, a failed * resolution records its verdict as an issue and returns the failure * verdict even under `throwOnFailure`; the owning parse call raises the * whole trace once every parameter has been seen. Absent: failures throw * where they are found. */ issueCollector?: IIssueCollector; }; //#endregion //#region src/schema/resolver/module.d.ts type ResolutionScopeOptions

= { registry: SchemaRegistry; parameter: P; schema: ParameterSchema; bound: boolean; base?: Schema; rootBase?: Schema; rootSchema?: ParameterSchema; relations?: IRelations; segment?: string; path?: string[]; obligationSink?: PendingKeyValidation[]; issueCollector?: IIssueCollector; depth?: number; throwOnFailure?: boolean; resolutionThrowOnFailure?: boolean; strict?: boolean; }; /** * An immutable handle on one parameter of one schema, under one failure policy. * * Owns the shared resolution pipeline every parser previously duplicated: * schema-input normalization, alias mapping, allow-list verdicts, * relation-path traversal through the registry (schemaMapping-aware) * and the throw-vs-drop failure policy including error-class selection. */ declare class ResolutionScope

{ readonly parameter: P; /** * The resolved parameter sub-schema — escape hatch for parameter quirks. */ readonly schema: ParameterSchema; /** * The parameter sub-schema this scope chain STARTED from. A descended * scope with no registered child schema falls back to an empty one, so * the original is kept: for a bare (base-less) relations sub-schema it * is the only authorization authority there is, and it has to govern * every hop rather than the first one alone. */ protected rootSchema: ParameterSchema; /** * Parsed relations governing which relation segments may be entered. */ readonly relations: IRelations | undefined; /** * Canonical (alias-resolved) relation segment this scope was entered through, * undefined for root scopes. */ readonly segment: string | undefined; /** * Canonical (alias-resolved) relation path from the parameter root to this * scope (root: `[]`). Drives absolute obligation/prune paths across the * grouping recursion — see {@link relationObligations}. */ readonly path: string[]; protected registry: SchemaRegistry; protected base: Schema | undefined; /** * The parameter root record schema, propagated unchanged through descents. * The anchor {@link relationObligations} walks to reach the relations * sub-schema governing each traversed segment. */ protected rootBase: Schema | undefined; /** * Relation-authorization ledger this scope records into on every successful * {@link resolveKey}; propagated to descendants. Undefined for scopes whose * caller does not authorize relations. */ protected obligationSink: PendingKeyValidation[] | undefined; /** * Trace of the parse this scope resolves for; propagated to descendants. * Present: {@link fail} records its verdict and lets the parse continue on * the drop path, and the owning parse call raises the whole trace at the * end. Absent (a scope built outside a parse): failures throw where they * are found, as they always did. */ readonly issueCollector: IIssueCollector | undefined; protected bound: boolean; protected depth: number; protected throwOnFailureContext: boolean | undefined; /** * Key-resolution policy a dialect forces on this scope, overriding * {@link throwOnFailureContext} for allow-list and traversal verdicts * alone. */ protected resolutionThrowOnFailureContext: boolean | undefined; protected strictContext: boolean | undefined; protected constructor(options: ResolutionScopeOptions); /** * Effective failure policy for key resolution: the dialect's forced one * ({@link ResolutionScopeContext.resolutionThrowOnFailure}) ?? context * override ?? schema setting ?? false. */ get throwOnFailure(): boolean; /** * Failure policy governing relation authorization for this scope's record: * the call-time override, backed by the relations sub-schema's own * `throwOnFailure` (schema-level intent), the same * `throwOnFailure ?? schema.relations.throwOnFailure ?? false` the query * pass applies, so standalone and query parses agree. * * Deliberately blind to {@link throwOnFailure}'s forced half: a dialect * that cannot resolve keys partially (expression) must still *drop* an * unauthorized relation unless the caller or the relations schema opts * into throwing. */ get relationsThrowOnFailure(): boolean; /** * Effective strict policy: context override ?? schema setting ?? false. * Under strict mode a parameter without an explicit allow-list rejects * every client key instead of falling back to the syntactic name check. */ get strict(): boolean; /** * Entry point. Normalizes every schema input shape * (registry name | Schema | parameter sub-schema | undefined → empty schema) * and binds the parse context. */ static for

(registry: SchemaRegistry, parameter: P, schema?: string | Schema | ParameterSchema, context?: ResolutionScopeContext): ResolutionScope; /** * Resolve a raw client key (local "title", aliased "abc" or dotted "items.title"). * Applies mapping aliases, checks the allow-list (or the property-name pattern when * no allow-list is set) and for dotted keys walks the relation path through the * registry honoring schemaMapping — validating the leaf against the target schema. * * Throws the parameter's ParseError subclass instead of returning `{ success: false }` * when the effective failure policy is set. */ resolveKey(key: string, raw?: string): KeyResolution; /** * Report a violation this scope's parameter found on its own (an input of * the wrong shape, an unparseable value, a limit above the maximum) * rather than one key resolution decided. * * Same policy as {@link resolveKey}: nothing at all while the policy * drops, and under a throwing one recorded into the parse's trace when * there is one (the owning call raises it once every parameter has been * seen), thrown here when there is not. The caller always continues on its * drop path; whether that path's result is ever observed is the trace's * decision, not the caller's. */ refuse(input: { code: `${ErrorCode}`; message: string; /** * Canonical position, defaulting to this scope's relation path. */ path?: string[]; key?: string; input?: unknown; /** * Policy override, for a site governed by another sub-schema's * failure policy than its own scope's. */ throwOnFailure?: boolean; }): void; /** * Enter a relation: checks the (alias-resolved) segment against the permitted * relations, resolves the child schema via the registry (schemaMapping-aware, * starting from the schema instance when available), extracts the child * relations sub-tree and returns a child scope inheriting the failure policy. * * A mapping alias may expand to a dotted path — every segment is walked, * and the returned scope reports the full relative path as its segment. * * `optional` marks a descent whose target may legitimately not be a * relation at all: an array operator's interior (`elemMatch`) addresses * the elements of whatever it names, so "no schema for this key" is an * answer, not a violation, and is returned as a bare verdict without * being thrown or recorded. Every other failure stays a failure. */ descend(key: string, options?: { optional?: boolean; }): ResolutionScope | KeyResolutionFailure; protected descendSegment(segment: string, input: string, raw?: string, optional?: boolean): ResolutionScope | KeyResolutionFailure; /** * Record — into {@link obligationSink}, when present — the relation- * authorization obligations a resolved leaf `name` implies: every relation on * this scope's absolute {@link path}, plus `name` itself when it is a relation * an operator targets directly. Invoked from the {@link resolveKey} leaf case, * so it fires exactly once per resolved key across every dialect. */ protected recordObligations(name: string): void; /** * The relation-authorization obligations incurred by traversing a resolved * relation path: one {@link PendingKeyValidation} per segment, against the * governing record's relations sub-schema. The emitted `schema` is the very * `RelationsSchema` instance the relations parser records for the same * relation (registry identity), so the query-level pass dedups include-driven * and traversal-driven obligations for one relation into a single hook call. * * `relativeSegments` are canonical (alias-resolved) relation names relative to * this scope; they are joined onto this scope's absolute {@link path} so the * obligation paths are absolute and prune the dependent keys directly — no * per-recursion prefixing. Returns `[]` for an unbound scope (no record * identity, nothing to authorize). Obligations against a validator-less * relations schema are harmless — the evaluation pass skips them. */ protected relationObligations(relativeSegments: string[]): PendingKeyValidation[]; /** * The obligation for a leaf `name` that is *itself* a relation of this * scope's record. For the relations parameter the leaf always is one (an * include). For fields/filters/sorts it is one only when it maps to a related * schema — an operator applied directly to a relation array * (`$size`/`$all`/`$elemMatch`) that the backends join; unlike a dotted path, * {@link resolveKey} classifies such a leaf as the terminal `name` (empty * `path`), so {@link relationObligations} would miss it. Returns `[]` for a * scalar / JSON-array leaf (no join). A pure registry lookup — no relation * gating, never throws (so it is safe on every resolved leaf, including * scalars, regardless of the failure policy). */ protected relationObligationForTerminal(name: string): PendingKeyValidation[]; /** * Allow-list verdict for a local (alias-resolved) name. */ protected checkName(name: string): KeyResolutionErrorCode | undefined; /** * Permission verdict for entering a relation segment. */ protected checkSegment(segment: string): KeyResolutionErrorCode | undefined; protected resolveBase(): Schema | undefined; /** * A scope created without any schema input describes no record * and imposes no traversal constraints. */ protected isUnbound(): boolean; protected withSegment(segment: string): ResolutionScope; protected fail(code: KeyResolutionErrorCode, input: string, segment?: string, raw?: string): KeyResolutionFailure; /** * The error one key-resolution verdict fails with, through the parameter's * own static factories, so class, `code` and message stay what the * fail-fast path has always thrown. */ protected raise(code: KeyResolutionErrorCode, name: string, issues?: readonly Issue[]): ParseError; protected get mapping(): Record | undefined; } //#endregion //#region src/schema/define.d.ts declare function defineSchema(options?: SchemaOptions): Schema; //#endregion //#region src/parameter/filters/record/types.d.ts /** * The leaf-condition visitor. Operator semantics live in the plan * layer: consume {@link planCondition} via {@link interpretPlan} * (or a serializer over {@link distributeNegation}) instead of * branching on operator names here. The broad leaf input admits every * operator and value specialization. */ interface IFilterVisitor { visitFilter(expr: IFilter): R; } interface IFilter extends ICondition { readonly field: string; readonly operator: string | OPERATOR; readonly value: VALUE; accept(visitor: IFilterVisitor): R; } //#endregion //#region src/parameter/filters/record/check.d.ts declare function isFilter(input: unknown): input is IFilter; //#endregion //#region src/parameter/filters/record/module.d.ts declare class Filter extends Condition implements IFilter { readonly field: string; readonly preserved?: boolean; constructor(operator: string, field: string, value: VALUE, options?: ConditionOptions); accept(visitor: IFilterVisitor): R; } //#endregion //#region src/parameter/filters/helpers/module.d.ts /** * Field paths are typed against the record generic when one is supplied * (helper('realm.name', ...)); without a generic the parameter * falls back to a plain string. */ type FieldKey = string extends keyof RECORD ? string : NestedKeys; /** * One helper per {@link FilterFieldOperator}, named after the operator's * enum value, mirroring the expression dialect (eq('name', 'John') in * code ≙ eq(name, 'John') on the wire). Sole exception: `in` is a * reserved word in JavaScript, so the IN helper is named {@link inArray}. */ declare function eq(field: FieldKey, value: unknown): Filter; declare function ne(field: FieldKey, value: unknown): Filter; declare function lt(field: FieldKey, value: unknown): Filter; declare function lte(field: FieldKey, value: unknown): Filter; declare function gt(field: FieldKey, value: unknown): Filter; declare function gte(field: FieldKey, value: unknown): Filter; /** * IN condition (wire keyword: `in`). `null` is a legal element; * backend adapters own the `OR IS NULL` rewrite. */ declare function inArray(field: FieldKey, value: unknown[]): Filter; declare function nin(field: FieldKey, value: unknown[]): Filter; declare function startsWith(field: FieldKey, value: string): Filter; declare function notStartsWith(field: FieldKey, value: string): Filter; declare function endsWith(field: FieldKey, value: string): Filter; declare function notEndsWith(field: FieldKey, value: string): Filter; declare function contains(field: FieldKey, value: string): Filter; declare function notContains(field: FieldKey, value: string): Filter; declare function regex(field: FieldKey, value: RegExp | string): Filter; declare function mod(field: FieldKey, divisor: number, remainder: number): Filter; /** * Match arrays with exactly the given number of elements * (a non-negative integer); missing or non-array values never match. */ declare function size(field: FieldKey, value: number): Filter; declare function exists(field: FieldKey, value?: boolean): Filter; /** * Match array elements against a condition; field paths inside the * condition are relative to the array element. */ declare function elemMatch(field: FieldKey, value: ICondition): Filter; declare function and(...conditions: ICondition[]): Filters; declare function or(...conditions: ICondition[]): Filters; /** * Negation: matches exactly what the interior does not match — the * null-inclusive complement law extended from negated leaf operators * to arbitrary condition trees. Multiple conditions negate their * conjunction: not(a, b) ≙ not(and(a, b)). */ declare function not(...conditions: ICondition[]): Filters; //#endregion //#region src/parameter/filters/plan/constants.d.ts /** * The operator-semantics table — one row per filter operator, the * single source of truth for what an operator MEANS: its family, * its negation twin (complement law), its anchor placement, its * comparison range and its case-fold participation. * * The {@link planCondition} lowering derives every policy decision * from this table. Adding an operator means adding a row (plus a * lowering rule when it opens a new family) — not editing backends. */ declare const FILTER_OPERATOR_SEMANTICS: { eq: { family: "equality"; foldable: true; }; ne: { family: "equality"; complementOf: "eq"; foldable: true; }; lt: { family: "ordering"; compare: { min: -1; max: -1; }; foldable: false; }; lte: { family: "ordering"; compare: { min: -1; max: 0; }; foldable: false; }; gt: { family: "ordering"; compare: { min: 1; max: 1; }; foldable: false; }; gte: { family: "ordering"; compare: { min: 0; max: 1; }; foldable: false; }; in: { family: "membership"; foldable: true; }; nin: { family: "membership"; complementOf: "in"; foldable: true; }; startsWith: { family: "anchored"; anchor: { start: true; end: false; }; foldable: false; }; notStartsWith: { family: "anchored"; complementOf: "startsWith"; anchor: { start: true; end: false; }; foldable: false; }; endsWith: { family: "anchored"; anchor: { start: false; end: true; }; foldable: false; }; notEndsWith: { family: "anchored"; complementOf: "endsWith"; anchor: { start: false; end: true; }; foldable: false; }; contains: { family: "anchored"; anchor: { start: false; end: false; }; foldable: false; }; notContains: { family: "anchored"; complementOf: "contains"; anchor: { start: false; end: false; }; foldable: false; }; regex: { family: "regex"; foldable: false; }; mod: { family: "arithmetic"; foldable: false; }; size: { family: "cardinality"; foldable: false; }; exists: { family: "existence"; foldable: false; }; elemMatch: { family: "structural"; foldable: false; }; }; //#endregion //#region src/parameter/filters/plan/types.d.ts /** * Semantic classification of a filter operator — the row shape of * {@link FILTER_OPERATOR_SEMANTICS}. The table is the single source * of truth the {@link planCondition} lowering derives its decisions * from; backends never branch on operator names. */ type FilterOperatorFamily = 'equality' | 'ordering' | 'membership' | 'anchored' | 'regex' | 'existence' | 'arithmetic' | 'cardinality' | 'structural'; type FilterOperatorSemantics = { family: FilterOperatorFamily; /** * Negation twin: this operator is the null-inclusive complement * of the named positive operator (complement law). Only set on * negated operators; the target must itself be positive. */ complementOf?: `${FilterFieldOperator}`; /** * Anchored family only: anchor placement of the derived pattern. */ anchor?: { start: boolean; end: boolean; }; /** * Ordering family only: accepted three-way comparison range * (result of a compare(value, condition) in {-1, 0, 1}). */ compare?: { min: -1 | 0 | 1; max: -1 | 0 | 1; }; /** * Whether the operator participates in the case-insensitive * default for string values (equality family + membership). */ foldable: boolean; }; /** * Comparison primitive of a {@link ComparePlan}. */ type PlanCompareOperator = 'eq' | 'lt' | 'lte' | 'gt' | 'gte'; /** * and/or group. `negated` (from `not`/`nor` input compounds) is the * EXACT complement of the group verdict — the null-inclusive * complement law of negated leaves, extended to whole trees. A * backend must render it two-valued: rows where the interior does * not evaluate to a match — including null-bearing rows — match the * negation (SQL therefore cannot use a bare three-valued `not (…)`). */ type CompoundPlan = { kind: 'compound'; operator: 'and' | 'or'; negated: boolean; /** * Never empty — compounds whose children all vanish are lowered * to `null` themselves. */ children: ConditionPlan[]; }; /** * Verdict known at plan time: `in([])` matches nothing, * `nin([])` matches everything, an invalid `mod` value matches * nothing (mongo parity). */ type ConstantPlan = { kind: 'constant'; verdict: boolean; }; /** * `exists`, `eq(field, null)` and `ne(field, null)`. * `negated` reads IS NOT NULL. `elementwise` distributes the test * over array-valued fields by element (the equality family does, * `exists` addresses the value itself). */ type NullCheckPlan = { kind: 'null-check'; field: string; negated: boolean; elementwise: boolean; }; /** * Binary comparison on a scalar. `op` is `'eq'` for the equality * family (`negated` marks `ne`; ordering operators are never * negated). `caseFold` carries the settled policy verdict — the * value is a string and the field is not opted out via * `caseSensitive`; backends apply only their remaining capability * veto (column foldability) and the folding mechanism. * * Contract for `negated`: the exact null-inclusive complement of * the positive form — null/missing values match. */ type ComparePlan = { kind: 'compare'; field: string; op: PlanCompareOperator; value: unknown; caseFold: boolean; negated: boolean; }; /** * `in`/`nin`. `values` is null-free and non-empty; null members are * extracted into `includesNull` (they stay leaf-local because a * null member participates in element quantification — `in([x, null])` * matches an array-valued field containing null). * * The four-case contract every backend must satisfy: * - positive, no null: v ∈ values * - positive, null: v ∈ values OR v IS NULL * - negated, no null: complement (v ∉ values OR v IS NULL) * - negated, null: v ∉ values AND v IS NOT NULL */ type OneOfPlan = { kind: 'one-of'; field: string; values: unknown[]; includesNull: boolean; caseFold: boolean; negated: boolean; }; /** * String matching — the anchored family and the regex operator in * one node. Anchored literals keep their text so LIKE-only dialects * can derive a wildcard pattern; `regexSource` is always a usable * POSITIVE pattern (metacharacters escaped, anchors applied — never * a negative lookahead; negation is the `negated` flag, with the * null-inclusive leaf contract). */ type MatchPattern = { mode: 'starts' | 'ends' | 'contains'; text: string; } | { mode: 'regex'; source: string; flags: string; }; type MatchPlan = { kind: 'match'; field: string; pattern: MatchPattern; regexSource: string; ignoreCase: boolean; negated: boolean; }; /** * `mod` — value already validated ([divisor, remainder], finite, * divisor non-zero); invalid input lowers to a false constant. */ type ModPlan = { kind: 'mod'; field: string; divisor: number; remainder: number; }; /** * `size` — addresses the array itself, not its elements. * `count` is null when the condition value is invalid (not a * non-negative integer): the condition then never matches, but the * node keeps its identity so backends without array-length support * still fail typed instead of silently rendering a constant. */ type SizePlan = { kind: 'size'; field: string; count: number | null; }; /** * `elemMatch` — the interior is recursively planned. ITSELF * placement legality is already verified during lowering. */ type ElemMatchPlan = { kind: 'elem-match'; field: string; condition: ConditionPlan; }; type ConditionPlan = CompoundPlan | ConstantPlan | NullCheckPlan | ComparePlan | OneOfPlan | MatchPlan | ModPlan | SizePlan | ElemMatchPlan; /** * The backend contract over a {@link ConditionPlan} — and its * declared support matrix: an optional handler that is absent means * the feature is unsupported ({@link interpretPlan} throws the * typed error, in exactly one place). `itself` declares whether * leaf fields may be the ITSELF (`$this`) marker. * * `compound` and `elemMatch` handlers recurse via * {@link interpretPlan} on their children. */ interface IPlanInterpreter { readonly itself?: boolean; compound(plan: CompoundPlan): R; constant(plan: ConstantPlan): R; nullCheck(plan: NullCheckPlan): R; compare(plan: ComparePlan): R; oneOf(plan: OneOfPlan): R; match(plan: MatchPlan): R; mod?(plan: ModPlan): R; size?(plan: SizePlan): R; elemMatch?(plan: ElemMatchPlan): R; } type PlanConditionOptions = { /** * Field keys whose equality comparisons (eq/ne/in/nin) stay * case-sensitive instead of the case-insensitive default — * matched against the full path composed through elemMatch * scopes. `true` keeps every comparison case-sensitive. */ caseSensitive?: string[] | boolean; }; //#endregion //#region src/parameter/filters/plan/distribute.d.ts /** * Push group negation down to the leaves, eliminating * `CompoundPlan.negated` from the tree. * * `planCondition` keeps group negation because SQL and the in-memory * backend render it two-valued cheaply (a CASE wrapper, a `!`). * Backends without a two-valued NOT of their own (prisma, and the * other structured-args ORMs of plan 023) instead consume this * transform. It is semantics-preserving under the settled negation * contract: * * - group negation is the two-valued complement PER BINDING, with the * binding quantifier outermost (SQL applies its CASE wrapper per * join row; the in-memory backend negates per binding context): * so De Morgan applies, negation commutes through `elemMatch` * (`not(elemMatch(c))` selects bindings where an element fails `c`, * NOT records without a matching element), and leaves flip to their * null-inclusive complement twins. * - the complement of an ordering comparison has no leaf twin; it * becomes the complementary operator OR a null check: expressible * in the existing plan vocabulary, so backends need no new node * kinds and their usual constant folding (e.g. a non-nullable * column) applies unchanged. * - `mod` and `size` have no complement form and stay wrapped in a * residual negated single-child compound; a backend that cannot * render that keeps failing typed, exactly as before. */ declare function distributeNegation(plan: ConditionPlan): ConditionPlan; //#endregion //#region src/parameter/filters/plan/module.d.ts /** * Lower a built-in condition tree into a * {@link ConditionPlan} with every semantic policy decision already * made: negation twins resolved to `negated` leaf flags, null * equality turned into null checks, in/nin decomposed (empty list, * null members), the case-fold policy verdict computed, anchored * operators derived into positive patterns, value shapes validated * and ITSELF placement checked. * * Backends interpret the plan via {@link interpretPlan} — they * render or compile primitives, they never re-derive operator * semantics. * * Returns `null` when the tree is empty (an empty compound * vanishes). */ declare function planCondition(input: ICondition, options?: PlanConditionOptions): ConditionPlan | null; /** * Dispatch a plan node to the matching interpreter handler. * * The single support-enforcement point: a missing optional handler * (`mod`/`size`/`elemMatch`) and an ITSELF leaf without the * `itself` declaration throw the typed feature error here — never * inside a backend. */ declare function interpretPlan(plan: ConditionPlan, interpreter: IPlanInterpreter): R; //#endregion //#region src/parameter/filters/preserve.d.ts declare function preserve(condition: IFilter): IFilter; declare function preserve(condition: IFilters): IFilters; /** * The catch-all admits every subtype too, so it cannot promise the * {@link IFilters} wrapper a custom condition receives: an argument merely * *typed* as {@link ICondition} may still be a leaf at runtime. Narrow the * result with `isFilter` / `isFilters` when the kind matters. */ declare function preserve(condition: ICondition): ICondition; //#endregion //#region src/parameter/filters/regex.d.ts declare enum FilterRegexFlag { STARTS_WITH = 1, ENDS_WITH = 2, CONTAINS = 4, NEGATION = 8 } declare function createFilterRegex(input: string, flag?: number): RegExp; declare function createFilterRegexPattern(input: string, flag?: number): string; //#endregion //#region src/parameter/fields/record/module.d.ts declare class Field implements IField { readonly name: string; readonly operator: string | undefined; readonly condition: ICondition | undefined; constructor(name: string, operator?: string, condition?: ICondition); accept(visitor: IFieldVisitor): R; } //#endregion //#region src/parameter/fields/record/types.d.ts interface IFieldVisitor { visitField(expr: Field): R; } interface IField { readonly name: string; readonly operator: string | undefined; /** * Server-side visibility gate: the field is projected, but its value * is only visible on rows satisfying this condition. Set by a schema * `validate` / `validateMany` hook answering with an `ICondition`; * never client-supplied, and never encoded onto the wire. * * The condition constrains the VALUE of this one field, never the * row set: a gated field never removes a row at any level. The SQL * backends cannot express that (a selection must stay a bare column * for entity hydration), so they project the column unconditionally * and the gate is applied after the fetch; `@rapiq/adapter-memory` honours * it while projecting. */ readonly condition: ICondition | undefined; accept(visitor: IFieldVisitor): R; } //#endregion //#region src/parameter/fields/record/check.d.ts /** * A `Field` record is identified by its visitor dispatch: accept() of a * field node calls visitField and nothing else. Works across package * instances, where instanceof fails, and distinguishes the structurally * overlapping record nodes (Field, Sort, Relation). */ declare function isField(input: unknown): input is IField; //#endregion //#region src/parameter/fields/collection/types.d.ts interface IFieldsVisitor { visitFields(expr: IFields): R; } interface IFields { readonly value: IField[]; accept(visitor: IFieldsVisitor): R; merge(other: IFields): IFields; } //#endregion //#region src/parameter/fields/collection/check.d.ts /** * A `Fields` collection is identified by its visitor dispatch: accept() * of a fields node calls visitFields and nothing else. Works across * package instances, where instanceof fails, and distinguishes the * structurally identical collection nodes (Fields, Sorts, ...). */ declare function isFields(input: unknown): input is IFields; /** * Whether any field of the selection carries a visibility condition * (see `IField.condition`). The gate is only applied while projecting * by `@rapiq/adapter-memory`; the SQL backends fetch the column for every row * and rely on the consumer running the fetched rows through * `applyFieldConditions` before serializing them. This is the check a * response path can assert on to guarantee no gated column ships * unredacted. */ declare function hasFieldConditions(input: IFields | { fields: IFields; }): boolean; //#endregion //#region src/parameter/fields/collection/module.d.ts type FieldsExecuteOptions = { default: string[]; allowed: string[]; }; declare class Fields implements IFields { readonly value: IField[]; constructor(value?: IField[]); accept(visitor: IFieldsVisitor): R; /** * Keyed by name, left/receiver priority; order = first occurrence. * Immutable — returns a new collection. * * A name collision that would discard a visibility condition (see * `IField.condition`) throws a typed MergeError instead: a gate is a * server-authored authorization decision, and dropping it silently * would widen disclosure. The surviving node keeping the identical * condition instance is fine; anything else refuses. Filters express * the same protection differently: a preserved condition stays atomic * through `Filters.merge()` because a filter can be combined as a * conjunct while a field is either gated or not. */ merge(other: IFields): IFields; /** * Extract field set, with includes and excludes. * * @param options */ execute(options: FieldsExecuteOptions): IFields; /** * Rebuild the resolved field `name`. The include/exclude operator is * deliberately consumed (execute() resolves it), but a visibility * condition is orthogonal metadata and must survive, so a gated field * cannot lose its gate by being run through the projection resolver. */ protected rebuild(name: string): IField; protected toUnique(input: string[]): string[]; protected applyExplicates(input: string[], explicates: string[], options: FieldsExecuteOptions): void; protected applyIncludes(input: string[], includes: string[], options: FieldsExecuteOptions): void; protected applyExcludes(input: string[], excludes: string[]): string[]; } //#endregion //#region src/parameter/pagination/types.d.ts interface IPaginationVisitor { visitPagination(expr: IPagination): R; } interface IPagination { limit?: number; offset?: number; accept(visitor: IPaginationVisitor): R; merge(other: IPagination): IPagination; } //#endregion //#region src/parameter/pagination/check.d.ts /** * A `Pagination` node is identified by its visitor dispatch: accept() * of a pagination node calls visitPagination and nothing else. Works * across package instances, where instanceof fails. */ declare function isPagination(input: unknown): input is IPagination; //#endregion //#region src/parameter/pagination/pagination.d.ts declare class Pagination implements IPagination { limit: number | undefined; offset: number | undefined; constructor(limit?: number, offset?: number); accept(visitor: IPaginationVisitor): R; /** * Per-property left/receiver priority — limit and offset are merged * independently. Immutable — returns a new instance. */ merge(other: IPagination): IPagination; } //#endregion //#region src/parameter/relations/record/types.d.ts interface IRelationVisitor { visitRelation(expr: IRelation): R; } interface IRelation { readonly name: string; accept(visitor: IRelationVisitor): R; } //#endregion //#region src/parameter/relations/record/check.d.ts /** * A `Relation` record is identified by its visitor dispatch: accept() * of a relation node calls visitRelation and nothing else. Works across * package instances, where instanceof fails, and distinguishes the * structurally overlapping record nodes (Relation, Field, Sort). */ declare function isRelation(input: unknown): input is IRelation; //#endregion //#region src/parameter/relations/record/module.d.ts declare class Relation implements IRelation { readonly name: string; constructor(name: string); accept(visitor: IRelationVisitor): R; } //#endregion //#region src/parameter/relations/collection/types.d.ts interface IRelationsVisitor { visitRelations(expr: IRelations): R; } interface IRelations { readonly value: IRelation[]; accept(visitor: IRelationsVisitor): R; extract(root: string): IRelations; merge(other: IRelations): IRelations; } //#endregion //#region src/parameter/relations/collection/check.d.ts /** * A `Relations` collection is identified by its visitor dispatch: * accept() of a relations node calls visitRelations and nothing else. * Works across package instances, where instanceof fails, and * distinguishes the structurally identical collection nodes * (Relations, Sorts, ...). */ declare function isRelations(input: unknown): input is IRelations; //#endregion //#region src/parameter/relations/collection/module.d.ts declare class Relations implements IRelations { readonly value: IRelation[]; constructor(value?: IRelation[]); accept(visitor: IRelationsVisitor): R; /** * Collect the child relations below a given root * (e.g. root "items" yields "realm" for "items.realm"). * * The collection itself is left untouched — parsers share one * relations instance across all parameters, so consuming entries * here would corrupt the parsed query. */ extract(root: string): IRelations; /** * Keyed by name, left/receiver priority; order = first occurrence. * Immutable — returns a new collection. */ merge(other: IRelations): IRelations; } //#endregion //#region src/parameter/sorts/record/types.d.ts interface ISortVisitor { visitSort(expr: ISort): R; } interface ISort { readonly name: string; readonly operator: `${SortDirection}`; accept(visitor: ISortVisitor): R; } //#endregion //#region src/parameter/sorts/record/check.d.ts /** * A `Sort` record is identified by its visitor dispatch: accept() of a * sort node calls visitSort and nothing else. Works across package * instances, where instanceof fails, and distinguishes the structurally * overlapping record nodes (Sort, Field, Relation). */ declare function isSort(input: unknown): input is ISort; //#endregion //#region src/parameter/sorts/record/module.d.ts declare class Sort implements ISort { readonly name: string; readonly operator: `${SortDirection}`; constructor(name: string, operator?: `${SortDirection}`); accept(visitor: ISortVisitor): R; } //#endregion //#region src/parameter/sorts/collection/types.d.ts interface ISortsVisitor { visitSorts(expr: ISorts): R; } interface ISorts { readonly value: ISort[]; accept(visitor: ISortsVisitor): R; merge(other: ISorts): ISorts; } //#endregion //#region src/parameter/sorts/collection/check.d.ts /** * A `Sorts` collection is identified by its visitor dispatch: accept() * of a sorts node calls visitSorts and nothing else. Works across * package instances, where instanceof fails, and distinguishes the * structurally identical collection nodes (Sorts, Fields, ...). */ declare function isSorts(input: unknown): input is ISorts; //#endregion //#region src/parameter/sorts/collection/module.d.ts declare class Sorts implements ISorts { readonly value: ISort[]; constructor(value?: ISort[]); accept(visitor: ISortsVisitor): R; /** * Keyed by name, left/receiver priority; order = first occurrence. * Immutable — returns a new collection. */ merge(other: ISorts): ISorts; } //#endregion //#region src/parameter/types.d.ts type QueryContext = { fields?: IFields; filters?: IFilters; relations?: IRelations; pagination?: IPagination; sorts?: ISorts; }; interface IQueryVisitor { visitQuery(expr: IQuery): R; } interface IQuery { readonly fields: IFields; readonly filters: IFilters; readonly relations: IRelations; readonly pagination: IPagination; readonly sorts: ISorts; accept(visitor: IQueryVisitor): R; } //#endregion //#region src/parameter/check.d.ts /** * A `Query` node is identified by its visitor dispatch: accept() of a * query node calls visitQuery and nothing else. Works across package * instances, where instanceof fails. */ declare function isQuery(input: unknown): input is IQuery; //#endregion //#region src/parameter/module.d.ts declare class Query implements IQuery { readonly fields: IFields; readonly filters: IFilters; readonly relations: IRelations; readonly pagination: IPagination; readonly sorts: ISorts; constructor(options?: QueryContext); accept(visitor: IQueryVisitor): R; } //#endregion //#region src/parameter/merge.d.ts /** * Merge queries (the IR). Fields, relations and sorts have left priority: * the first occurrence sets value and position. Pagination merges * limit/offset independently. Filters use {@link IFilters.merge} as an * ordered logical AND, retaining every condition. * * Immutable — inputs stay untouched, a new {@link Query} is returned. */ declare function mergeQueries(...input: IQuery[]): Query; //#endregion //#region src/build/parameter/fields/types.d.ts type FieldWithOperator = KeyWithOptionalPrefix; type FieldsBuildSimpleKeyInput = FieldWithOperator | SimpleResourceKeys>; type FieldsBuildNestedKeyInput = FieldWithOperator | SimpleResourceKeys>; type FieldsBuildRecordInput, DEPTH extends number = 5> = [DEPTH] extends [0] ? never : { [K in keyof T & string]?: T[K] extends Array ? (ELEMENT extends Record ? FieldsBuildInput : never) : T[K] extends Record ? FieldsBuildInput : never; }; type FieldsBuildTupleInput, DEPTH extends number = 5> = [DEPTH] extends [0] ? never : [FieldsBuildSimpleKeyInput[], FieldsBuildRecordInput]; type FieldsBuildInput, DEPTH extends number = 5> = [DEPTH] extends [0] ? never : FieldsBuildRecordInput | FieldsBuildTupleInput | FieldsBuildNestedKeyInput[] | FieldsBuildNestedKeyInput; //#endregion //#region src/build/parameter/fields/module.d.ts /** * The generic-less overload comes first: without an explicit record * generic, input is checked against the plain-string grammar instead of * letting inference derive RECORD from the argument (a bare string would * otherwise become the record type and yield nonsense key types). */ declare function defineFields(input: FieldsBuildInput | IFields): IFields; declare function defineFields(input: FieldsBuildInput | IFields): IFields; //#endregion //#region src/build/parameter/filters/types.d.ts /** * Operator-object notation: `$` + {@link FilterFieldOperator} enum value, * one key per operator. Compound keys ($and/$or) are reserved for the * planned mongo parser dialect and deliberately absent here — compound * trees are built with the condition helpers instead (`filters: or(...)`). */ type FiltersBuildOperatorInput = { $eq?: V | null; $ne?: V | null; $lt?: V; $lte?: V; $gt?: V; $gte?: V; $in?: (V | null)[]; $nin?: (V | null)[]; $startsWith?: string; $notStartsWith?: string; $endsWith?: string; $notEndsWith?: string; $contains?: string; $notContains?: string; $regex?: RegExp | string; $mod?: [number, number]; $size?: number; $exists?: boolean; }; /** * Value grammar for a single field — four equivalent notations, none * enforced: scalar (eq), bare array (in — `null` is a legal element), * operator object, or a raw RegExp (regex). */ type FiltersBuildValueInput = V | null | (V | null)[] | (V extends string ? RegExp : never) | FiltersBuildOperatorInput; /** * Array-level operators of an object-array field — element matching * and the array-length check (scalar arrays reach both through the * plain operator object). */ type FiltersBuildElemMatchInput = { $elemMatch?: FiltersBuildInput | ICondition; $size?: number; }; /** * Value grammar for a single key of the nested-object arm. Record-valued * keys recurse into {@link FiltersBuildNestedInput} — the nested-object * form only — rather than the full {@link FiltersBuildInput}. Recursing * into the full input would re-enumerate the child's dotted relation paths * at every nesting level, but the flat arm of {@link FiltersBuildInput} * already lists each of those paths once; the repetition is pure redundancy * that grows the inferred type super-linearly and, for deeply/cyclically * related records, overflows declaration-emit serialization (#821). The * `$elemMatch` interior deliberately keeps the full input — it opens a * fresh filter scope over the element type. */ type FiltersBuildNestedKeyValueInput = V extends Array ? (ELEMENT extends Date ? FiltersBuildValueInput : ELEMENT extends Record ? FiltersBuildNestedInput | FiltersBuildElemMatchInput : FiltersBuildValueInput) : V extends Date ? FiltersBuildValueInput : V extends Record ? FiltersBuildNestedInput : FiltersBuildValueInput; /** * The nested-object arm: every declared key of `T`, with record-valued keys * recursing into the nested form only (dotted relation paths are the flat * arm's job, see {@link FiltersBuildInput}). DEPTH bounds the recursion the * same way the flat arm does. */ type FiltersBuildNestedInput = [DEPTH] extends [0] ? never : { [K in keyof T & string]?: FiltersBuildNestedKeyValueInput; }; /** * Filter input for a record — two complementary arms, intersected: * * - the nested-object arm ({@link FiltersBuildNestedInput}) — * `{ realm: { name: 'x' } }`; * - the flat dotted-key arm — `{ 'realm.name': 'x' }`, every relation path * reachable within DEPTH. * * The arms are kept disjoint: the nested arm does not re-enumerate its * children's dotted paths (the flat arm already does, once). The only shape * this drops versus a naive full recursion is the redundant mixed form * `{ realm: { 'x.y': v } }` — write `{ 'realm.x.y': v }` (flat) or * `{ realm: { x: { y: v } } }` (nested) instead. That disjointness is what * keeps the inferred type serializable for deeply/cyclically related * records (#821); the runtime still accepts the mixed form. */ type FiltersBuildInput = [DEPTH] extends [0] ? never : FiltersBuildNestedInput & { [K in NestedKeys]?: FiltersBuildValueInput>; }; //#endregion //#region src/build/parameter/filters/merge.d.ts /** * Excludes a live condition from an input position at compile time. The * generic-less arm resolves `FiltersBuildInput` to a bag of * `any` values, which a condition object structurally satisfies, so without * this the type-level half of the guard would hold only for callers who * supply the record generic. */ type NotACondition = { [CONDITION_MARKER]?: never; }; /** * Per-field replace over filter build input: the first input to constrain a * field wins it, and every field only one side constrains survives. This is * the override-a-default operation, and it lives here rather than on the * `Query` because a build input is plain data: it cannot carry a * server-authored scope, so replacement cannot displace one. Composition of * queries is conjunction and never drops a predicate ({@link mergeQueries}). * * Both notations {@link FiltersBuildInput} admits address the same fields — * `{ 'realm.name': v }` and `{ realm: { name: v } }` — so inputs are reduced * to their canonical dotted paths before being compared. Two inputs written * in different notations therefore still replace each other, and a nested * record is replaced key by key instead of wholesale the way an object * spread would. * * ```typescript * mergeFiltersInput( * { realm: { name: 'b' } }, * { 'realm.name': 'a', 'realm.id': 1 }, * ); * // { 'realm.name': 'b', 'realm.id': 1 } * ``` * * Replacement is per field, not per operator: `{ age: { $gte: 18 } }` beating * `{ age: { $lt: 65 } }` yields the lower bound alone. Keeping both is * conjunction, which is what composing two queries does. * * A `$elemMatch` interior is a value, replaced whole. An `undefined` value * claims no field, so a later input still supplies it. The result is the flat * notation, itself valid input for {@link defineFilters} or another merge. */ declare function mergeFiltersInput(...input: (FiltersBuildInput & NotACondition)[]): FiltersBuildInput; declare function mergeFiltersInput(...input: (FiltersBuildInput & NotACondition)[]): FiltersBuildInput; //#endregion //#region src/build/parameter/filters/module.d.ts /** * The generic-less overload comes first: without an explicit record * generic, input is checked against the plain-string grammar instead of * letting inference derive RECORD from the argument. */ declare function defineFilters(input: FiltersBuildInput | ICondition): IFilters; declare function defineFilters(input: FiltersBuildInput | ICondition): IFilters; //#endregion //#region src/build/parameter/pagination/types.d.ts type PaginationBuildInput = { limit?: number; offset?: number; }; //#endregion //#region src/build/parameter/pagination/module.d.ts declare function definePagination(input: PaginationBuildInput | IPagination): IPagination; //#endregion //#region src/build/parameter/relations/types.d.ts type RelationsBuildInput, DEPTH extends number = 5> = [DEPTH] extends [0] ? never : { [K in keyof T & string]?: T[K] extends Array ? (ELEMENT extends Record ? RelationsBuildInput | boolean : never) : T[K] extends Record ? RelationsBuildInput | boolean : never; } | NestedResourceKeys[] | NestedResourceKeys; //#endregion //#region src/build/parameter/relations/module.d.ts /** * The generic-less overload comes first: without an explicit record * generic, input is checked against the plain-string grammar instead of * letting inference derive RECORD from the argument (a bare string would * otherwise become the record type and yield nonsense key types). */ declare function defineRelations(input: RelationsBuildInput | IRelations): IRelations; declare function defineRelations(input: RelationsBuildInput | IRelations): IRelations; //#endregion //#region src/build/parameter/sorts/types.d.ts type SortWithOperator = KeyWithOptionalPrefix; type SortsBuildRecordInput, DEPTH extends number = 5> = [DEPTH] extends [0] ? never : { [K in keyof T & string]?: T[K] extends Array ? (ELEMENT extends Record ? SortsBuildInput : `${SortDirection}`) : T[K] extends Record ? SortsBuildInput : `${SortDirection}`; }; type SortsBuildInput = [DEPTH] extends [0] ? never : SortsBuildRecordInput | [SortWithOperator>[], SortsBuildRecordInput] | SortWithOperator>[] | SortWithOperator>; //#endregion //#region src/build/parameter/sorts/module.d.ts /** * The generic-less overload comes first: without an explicit record * generic, input is checked against the plain-string grammar instead of * letting inference derive RECORD from the argument (a bare string would * otherwise become the record type and yield nonsense key types). */ declare function defineSorts(input: SortsBuildInput | ISorts): ISorts; declare function defineSorts(input: SortsBuildInput | ISorts): ISorts; //#endregion //#region src/build/types.d.ts /** * Keys are the canonical {@link Parameter} names. Every parameter accepts * either raw build input or an already-built AST fragment (the define* * factories return the latter), so fragments assign without casts. * * DEPTH bounds the recursive per-parameter input types (default 5, like * the per-parameter Build*Input types). Lower it for self-recursive * record types whose inferred input type would otherwise grow too large. */ type QueryBuildInput = { fields?: FieldsBuildInput | IFields; filters?: FiltersBuildInput | ICondition; pagination?: PaginationBuildInput | IPagination; relations?: RelationsBuildInput | IRelations; sorts?: SortsBuildInput | ISorts; /** * @deprecated use {@link QueryBuildInput.sorts}. Removed in 3.0. */ sort?: SortsBuildInput | ISorts; }; //#endregion //#region src/build/module.d.ts /** * Build a {@link Query} (the IR) directly from typed input — no string * round-trip, no parsing, no schema. Validation against a schema happens * server-side after transport. */ declare function defineQuery(input?: QueryBuildInput): Query; declare function defineQuery(input?: QueryBuildInput): Query; //#endregion //#region src/build/utils.d.ts type ParameterNode = { accept: (visitor: any) => any; }; /** * Every AST parameter node (Fields, Filters, Filter, Pagination, ...) * carries an accept method for visitor dispatch; plain build input never * does. This separates already-built fragments from raw input. */ declare function isParameterNode(input: unknown): input is T; //#endregion //#region src/parser/parameter/fields/error.d.ts declare class FieldsParseError extends ParseError {} //#endregion //#region src/parser/types.d.ts type ParseParameterOptions = { schema?: Schema | string; relations?: Relations; strict?: boolean; /** * Call-time override: takes precedence over the schema-level setting. * Effective policy is `throwOnFailure ?? schema.throwOnFailure ?? false`, * mirroring {@link ParseParameterOptions.strict}. */ throwOnFailure?: boolean; /** * Caller-defined context forwarded to the schema validate hooks * (relations/fields/sorts key validators, filters leaf validator). * Opaque to the parser. */ context?: unknown; }; /** * What opening a trace needs to know: which parameter the call parses, and * whether an enclosing parse handed one down. * * An object rather than two positional arguments, because the driver is absent * at every entry point and present only when a query parse drives a * sub-parser; as positions that reads as a literal `undefined` at half the * call sites, saying nothing. */ type ParseTraceContext = { parameter: `${Parameter}`; /** * The enclosing parse's trace. Absent: this call opens and raises its own. */ driver?: IIssueCollector; }; /** * One parse call's trace, and whether this call owns it. * * `owned` is the whole reason the handle exists: a driven sub-parser records * into the enclosing trace and lets the orchestrator decide what to raise, * while the call that opened one raises it itself. Carrying the answer beats * re-deriving it from an identity comparison at every step, which needed the * driver and the collector to travel together and inverted silently when they * were swapped. */ type ParseTrace = { collector: IIssueCollector; owned: boolean; /** * The parameter this call parses, when it parses exactly one. Decides what * a failure is raised as: its parameter's own error class, or the general * one for a query parse, which speaks for all five. */ parameter?: `${Parameter}`; }; /** * The pooled relation-authorization ledger the query orchestrator threads * through {@link IQueryParameterParser.parseParameter}: each sub-parser appends * the relation obligations it traverses, and `BaseQueryParser` evaluates the * relations validate hook once per distinct relation across all parameters and * prunes the assembled query. An explicit driver argument, never part of the * public parse options. */ type RelationLedger = PendingKeyValidation[]; type ParseQueryOptions = { fields?: boolean; filters?: boolean; pagination?: boolean; relations?: boolean; sorts?: boolean; /** * @deprecated use {@link ParseQueryOptions.sorts}. Removed in 3.0. */ sort?: boolean; /** * Process only the listed parameters. A parameter that is not * listed is neither parsed nor defaulted — the resulting query * leaves it empty, exactly as if neither the input nor the schema * had mentioned it (schema defaults such as `pagination.maxLimit` * do not materialize). When relations are masked out, relation * paths in the other parameters resolve as if the client had * requested no relations. Omitting the option processes all * parameters. */ parameters?: `${Parameter}`[]; schema?: Schema | string; /** * Strict-mode override: takes precedence over the schema-level setting. * Under strict mode a parameter without an explicit allow-list rejects * every client key instead of falling back to the syntactic name check. */ strict?: boolean; /** * Call-time override: takes precedence over the schema-level setting. * Effective policy is `throwOnFailure ?? schema.throwOnFailure ?? false`, * inherited into relation recursion exactly like * {@link ParseQueryOptions.strict}. */ throwOnFailure?: boolean; /** * Caller-defined context (e.g. the authenticated actor) forwarded to * every schema validate hook this parse run invokes. Hooks receive * `undefined` when no context is supplied. Opaque to the parser; * typing happens at the schema definition site * (`defineSchema`). */ context?: unknown; }; interface IParser { parse(input: Input, options?: Options): Output; parseAsync(input: Input, options?: Options): Promise; } /** * Contract of a per-parameter sub-parser, as consumed by the * query parse orchestration. * * `parse`/`parseAsync` are the public standalone entry points — they authorize * and prune the relations they traverse themselves. `parseParameter`/ * `parseParameterAsync` are the internal driver the query orchestrator uses: * they build the node and append relation obligations to the shared * {@link RelationLedger} but defer the single authorization pass (and cross- * parameter pruning) to `BaseQueryParser`. */ interface IQueryParameterParser { parse(input: unknown, options?: ParseParameterOptions): Output; parseAsync(input: unknown, options?: ParseParameterOptions): Promise; parseParameter(input: unknown, options: ParseParameterOptions, ledger: RelationLedger, issueCollector?: IIssueCollector): Output; parseParameterAsync(input: unknown, options: ParseParameterOptions, ledger: RelationLedger, issueCollector?: IIssueCollector): Promise; } //#endregion //#region src/parser/parameter/fields/types.d.ts type FieldsParseOptions = Omit, 'schema'> & { schema?: string | Schema | FieldsSchema; throwOnFailure?: boolean; isChild?: boolean; }; //#endregion //#region src/parser/parameter/filters/error.d.ts declare class FiltersParseError extends ParseError {} //#endregion //#region src/parser/parameter/filters/types.d.ts type FiltersParseOptions = { relations?: Relations; schema?: string | Schema | FiltersSchema; /** * Throw on a key resolution failure instead of dropping the key. * Honored by the simple and mongo dialects. The expression dialect * IGNORES it and always throws: an expression cannot be partially * reinterpreted safely — pruning a leaf inside `or(...)` would * change the compound's meaning rather than narrow it. */ throwOnFailure?: boolean; strict?: boolean; context?: unknown; }; //#endregion //#region src/parser/parameter/filters/validate.d.ts type FiltersValidationOptions = { /** * Trace of the enclosing parse. */ issueCollector?: IIssueCollector; /** * Call-time failure-policy override, taking precedence over the filters * sub-schema's own setting exactly like everywhere else * (`throwOnFailure ?? schema.throwOnFailure ?? false`). Without it a leaf * rejection would be the one violation a call-time override cannot * govern. * * Deliberately NOT the resolving scope's effective policy: the expression * dialect forces its scope to throw because an expression cannot be * partially reinterpreted, and that says nothing about whether a policy * hook declining a leaf should fail the request. */ throwOnFailure?: boolean; /** * Absolute path prefix carried through nested filter values. */ path?: string[]; }; /** * The conditions a parser falls back to when the input carries no * (surviving) filters — the schema `default`, or nothing. */ declare function buildFiltersDefaults(schema: FiltersSchema): ICondition[]; /** * Apply a filter schema's leaf validator without flattening or otherwise * changing the compound tree. Returning `undefined` from the validator drops * only that leaf; replacement conditions (a leaf or a whole compound, e.g. * `and(, )`) are inserted in the same position. * A compound whose every child is rejected is dropped entirely (`undefined`), * so callers fall back to the schema defaults instead of keeping a vacuous * node. An `elemMatch` leaf is validated inside-out: the interior condition * tree first (dropping the whole leaf when nothing survives), then the * rebuilt leaf itself. */ declare function applyFiltersSchemaValidation(input: IFilters, schema: FiltersSchema, context?: unknown, options?: FiltersValidationOptions): IFilters | undefined; declare function applyFiltersSchemaValidation(input: ICondition, schema: FiltersSchema, context?: unknown, options?: FiltersValidationOptions): ICondition | undefined; /** * Async counterpart of {@link applyFiltersSchemaValidation}. Validators are * awaited sequentially so leaf order and observable execution order remain * identical to the synchronous traversal. */ declare function applyFiltersSchemaValidationAsync(input: IFilters, schema: FiltersSchema, context?: unknown, options?: FiltersValidationOptions): Promise; declare function applyFiltersSchemaValidationAsync(input: ICondition, schema: FiltersSchema, context?: unknown, options?: FiltersValidationOptions): Promise; //#endregion //#region src/parser/parameter/pagination/error.d.ts declare class PaginationParseError extends ParseError { static limitExceeded(limit: number): PaginationParseError; } //#endregion //#region src/parser/parameter/pagination/types.d.ts type PaginationParseOptions = { schema?: string | Schema | PaginationSchema; throwOnFailure?: boolean; }; //#endregion //#region src/parser/parameter/relations/error.d.ts declare class RelationsParseError extends ParseError {} //#endregion //#region src/parser/parameter/relations/types.d.ts type RelationsParseOptions = { throwOnFailure?: boolean; strict?: boolean; schema?: string | Schema | RelationsSchema; context?: unknown; }; //#endregion //#region src/parser/parameter/sort/error.d.ts declare class SortsParseError extends ParseError {} /** * @deprecated use {@link SortsParseError}. Removed in 3.0. */ declare const SortParseError: typeof SortsParseError; /** * @deprecated use {@link SortsParseError}. Removed in 3.0. */ type SortParseError = SortsParseError; //#endregion //#region src/parser/parameter/sort/types.d.ts type SortsParseOptions = { relations?: Relations; throwOnFailure?: boolean; strict?: boolean; schema?: string | Schema | SortsSchema; context?: unknown; }; /** * @deprecated use {@link SortsParseOptions}. Removed in 3.0. */ type SortParseOptions = SortsParseOptions; //#endregion //#region src/parser/base.d.ts type TempType = { attributes: Record; relations: Record; }; declare abstract class BaseParser implements IParser { protected registry: SchemaRegistry; constructor(input?: SchemaRegistry); abstract parse(input: unknown, options?: OPTIONS): OUTPUT; parseAsync(input: unknown, options?: OPTIONS): Promise; /** * Open the trace this parse call records into: the enclosing call's when a * driver handed one down (a query parse driving its five parameters), a * fresh one otherwise. * * The handle carries whether this call OWNS the trace, because that is the * one thing every later step needs and the one thing a collector cannot * answer about itself. It used to be re-derived by comparing a driver * against the collector at each step, which meant passing both everywhere * and made an inverted comparison (a rejection silently degrading into a * drop) a plain argument-order mistake. * * It also carries the parameter the call parses, which decides what a * failure is raised AS: see {@link raise}. A query parse opens its trace * without one, because it speaks for all five. */ protected beginIssues(driver?: IIssueCollector, parameter?: `${Parameter}`): ParseTrace; /** * The failure a trace stands for, raised as the parse that owns it. * * A single-parameter parse names its parameter (`parseFields` fails with * `FieldsParseError`): the caller asked about one parameter, so saying * which one is the whole truth, and it is the class that parameter has * always thrown. A query parse names none, because a request can violate * policies in four parameters at once and an error advertising one of them * describes a SUBSET: a consumer branching on the class would act on the * part it happened to be handed. Either way the code is `INPUT_REJECTED` * and `error.issues` is what actually went wrong; the sub-parser failures * a query parse catches are merged into its trace rather than raised. */ protected raise(trace: ParseTrace): ParseError; /** * Raise what the trace collected, but only in the call that started it: a * sub-parser driven by a query parse records across all five parameters and * lets the orchestrator decide, so a single bad key no longer hides what the * other four would have reported. Every other call raises its own, so a * rejection can never end up recorded into a trace nobody reads. * * A trace nothing raises is discarded: the error a parse throws is the only * way it is ever read. */ protected finishIssues(trace: ParseTrace): void; /** * Run one parse call end to end: open a trace, record what the body * rejects into it, and raise it on the way out. * * Every entry point has this shape, so it is one call rather than three: * a body that forgets to finish turns every rejection it recorded into a * silent drop, which is the failure this whole mechanism exists to prevent. */ protected withTrace(context: ParseTraceContext, fn: (collector: IIssueCollector) => T): T; protected withTraceAsync(context: ParseTraceContext, fn: (collector: IIssueCollector) => Promise): Promise; /** * Run a parse body whose failures belong in `trace`. * * A structural failure (a malformed expression, an input of the wrong * shape, a hostile key) aborts by throwing rather than by dropping one * key, so without this it would escape the call before anything recorded * it: the caller would catch an error with an empty trace, and * `formatErrors(error.issues)`, the documented way to render a * failure, would answer with nothing at all. * * Recorded, the throw is re-raised through the trace, so the error that * leaves is the FIRST violation with the whole trace attached (an earlier * recorded rejection still wins over a structural abort that follows it). * A call driven by an enclosing parse records nothing here and simply * propagates: that parse catches the abort per parameter, keeps the other * four parsing, and decides. */ protected recordFailure(trace: ParseTrace, fn: () => T): T; protected recordFailureAsync(trace: ParseTrace, fn: () => Promise): Promise; /** * The error a caught throw should leave the call as. */ protected failure(input: unknown, trace: ParseTrace): unknown; protected getBaseSchema(input?: string | Schema): Schema; /** * Expand dotted keys and nested objects into one canonical tree. * Every leaf is written via its full dotted path, so a dotted key * and a nested object sharing a prefix (`{'realm.id': 1, realm: * {name: 'x'}}`) merge instead of the later key replacing the * earlier subtree. Paths are capped at the shared traversal depth: * a crafted deeply nested (or cyclic) input must fail typed instead * of overflowing the call stack — no valid path exceeds the cap, * since relation traversal is bounded by the same constant. */ protected expandObject(input: Record, output?: Record, prefix?: string): Record; /** * Reject an input object carrying a key whose path addresses an * inherited prototype member. A parameter parser that never expands * or groups its keys (pagination) does not run the hardened helpers * above, but must not accept such keys silently either — the guard * contract is uniform across every parameter. Nesting is bounded by * the shared traversal depth for the same reason as `expandObject`. */ protected assertSafeObjectKeys(input: Record, depth?: number): void; protected groupObject(input: Record): TempType; protected groupObjectByBasePath>(input: T): Record; protected groupArrayByBasePath(input: string[]): Record; /** * Group keys by everything before their last path segment * (e.g. "items.realm.id" -> { 'items.realm': ['id'] }). */ protected groupArrayByKeyPath(input: string[]): Record; protected groupByFieldPathWithFn(items: string[], cb: (prefix: string, key: string, index: number) => void): void; } //#endregion //#region src/parser/index-policy.d.ts type IndexPolicyContext = { throwOnFailure?: boolean; /** * Trace of the enclosing parse. Present: the violation is recorded and * the parse continues to its own end. Absent: it throws here. */ issueCollector?: IIssueCollector; }; /** * Enforce the schema's `indexed` filters policy on a final parsed tree. * Runs after validate hooks and relation pruning, so server-authored * residuals legitimately anchor the executed query; the schema default * tree is server-authored and bypasses. Violations follow the standard * failure policy: drop the parameter whole (falling back to the * default), or throw typed under `throwOnFailure`. */ declare function applyFiltersIndexPolicy(output: IFilters, registry: SchemaRegistry, schema?: string | Schema | FiltersSchema, context?: IndexPolicyContext): IFilters; /** * Sorts counterpart of {@link applyFiltersIndexPolicy}: ordered * leftmost-prefix rule applied to the client-authored keys only * (server-authored default entries, root or relation-scoped, are * exempt), standard failure policy. */ declare function applySortsIndexPolicy(output: ISorts, registry: SchemaRegistry, schema?: string | Schema | SortsSchema, context?: IndexPolicyContext): ISorts; /** * @deprecated use {@link applySortsIndexPolicy}. Removed in 3.0. */ declare const applySortIndexPolicy: typeof applySortsIndexPolicy; //#endregion //#region src/parser/query.d.ts /** * Shared query parse orchestration. Dialect packages supply the * per-parameter sub-parsers; this base owns the composition: * parameter key lookup, relation gating and the delegation order * (relations first, since they gate the rest). */ declare abstract class BaseQueryParser extends BaseParser { protected abstract fieldsParser: IQueryParameterParser; protected abstract filtersParser: IQueryParameterParser; protected abstract paginationParser: IQueryParameterParser; protected abstract relationsParser: IQueryParameterParser; protected abstract sortParser: IQueryParameterParser; parse(input: unknown, options?: ParseQueryOptions): Query; parseAsync(input: unknown, options?: ParseQueryOptions): Promise; /** * Run one parameter, keeping a structural failure inside it. * * A malformed expression or an input of the wrong shape aborts the * parameter it was found in (there is no next key to move on to), but the * other four parameters are independent and still parse. The failure is * recorded as an error issue, so the query parse ends on it (or on an * earlier one) exactly as it would have ended on the immediate throw. */ protected parseOne(issueCollector: IIssueCollector, parameter: `${Parameter}`, fallback: T, fn: () => T): T; protected parseOneAsync(issueCollector: IIssueCollector, parameter: `${Parameter}`, fallback: T, fn: () => Promise): Promise; /** * The option plumbing shared by {@link parse} and {@link parseAsync}. * Forwards the ORIGINAL schema input — a manufactured empty schema * would wrongly bind the parameter scopes. */ protected prepareQueryContext(input: unknown, options: ParseQueryOptions): { data: ObjectLiteral; parameterOptions: ParseParameterOptions; trace: ParseTrace; }; /** * Relation paths of the other parameters are only gated by the * relations parameter when the client actually supplied one. */ protected gateRelations(parameterOptions: ParseParameterOptions, relationsInput: unknown, relations: IRelations): void; /** * Evaluate the pooled relation-authorization obligations once — deduped * across every parameter — under the relations schema's failure policy. * Returns the canonical relation paths the hook rejected, for * {@link pruneByRelations}. A rejection under `throwOnFailure` throws * `RelationsParseError`, regardless of which parameter forced the join. */ protected applyRelationValidations(ledger: RelationLedger, options: ParseQueryOptions, issueCollector?: IIssueCollector): string[]; protected applyRelationValidationsAsync(ledger: RelationLedger, options: ParseQueryOptions, issueCollector?: IIssueCollector): Promise; /** * Drop every field/filter/sort/relation traversing a rejected relation from * the assembled query. Filters and sorts fall back to their schema defaults * when pruning empties them, matching the parser's own default fallback. */ protected pruneByRelations(output: QueryContext, rejected: string[], options: ParseQueryOptions, issueCollector?: IIssueCollector): void; /** * Enforce the schema's `indexed` policies on the final composed * query, after relation pruning: the check governs the tree that * will actually execute. Per-parameter throw policy comes from the * sub-schemas themselves. */ protected applyIndexPolicies(output: QueryContext, options: ParseQueryOptions, issueCollector?: IIssueCollector): void; /** * Parse relations input parameter. * * @param input * @param options */ parseRelations(input: unknown, options?: ParseParameterOptions): IRelations; parseRelationsAsync(input: unknown, options?: ParseParameterOptions): Promise; /** * Parse fields input parameter. * * @param input * @param options */ parseFields(input: unknown, options?: ParseParameterOptions): IFields; parseFieldsAsync(input: unknown, options?: ParseParameterOptions): Promise; /** * Parse filter(s) input parameter. * * @param input * @param options */ parseFilters(input: unknown, options?: ParseParameterOptions): IFilters; parseFiltersAsync(input: unknown, options?: ParseParameterOptions): Promise; /** * Parse pagination input parameter. * * @param input * @param options */ parsePagination(input: unknown, options?: ParseParameterOptions): IPagination; parsePaginationAsync(input: unknown, options?: ParseParameterOptions): Promise; /** * Parse sorts input parameter. * * @param input * @param options */ parseSorts(input: unknown, options?: ParseParameterOptions): ISorts; parseSortsAsync(input: unknown, options?: ParseParameterOptions): Promise; /** * @deprecated use {@link BaseQueryParser.parseSorts}. Removed in 3.0. */ parseSort(input: unknown, options?: ParseParameterOptions): ISorts; /** * @deprecated use {@link BaseQueryParser.parseSortsAsync}. Removed in 3.0. */ parseSortAsync(input: unknown, options?: ParseParameterOptions): Promise; /** * Read a parameter from the input object by its * canonical {@link Parameter} key. */ protected readParameter(input: ObjectLiteral, key: `${Parameter}`): unknown; /** * A parameter is skipped when the `parameters` allow-list * excludes it or its per-parameter option is `false`. A skipped * parameter is neither parsed nor defaulted — the query leaves * it empty, as if input and schema said nothing about it. */ protected skipParameter(options: ParseQueryOptions, parameter: `${Parameter}`): boolean; } //#endregion //#region src/parser/relation-prune.d.ts /** * Whether a canonical relation/field path is governed by a rejected relation — * the path is the relation itself or lives underneath it. */ declare function isRelationRejected(path: string, rejected: string[]): boolean; /** * Drop every field whose canonical name traverses a rejected relation. */ declare function pruneFieldsByRelations(fields: IFields, rejected: string[]): IFields; /** * Drop every sort whose canonical name traverses a rejected relation. Falls back * to the schema `default` when pruning empties the parameter — mirroring the * parser, which re-applies defaults once relation gating removes every key. */ declare function pruneSortsByRelations(sorts: ISorts, rejected: string[], schema?: SortsSchema): ISorts; /** * Drop every relation at or below a rejected relation. */ declare function pruneRelationsByRelations(relations: IRelations, rejected: string[]): IRelations; /** * Prune a filter tree of every leaf traversing a rejected relation, collapsing * empty compounds (mirrors {@link applyFiltersSchemaValidation}). Interior * `elemMatch` conditions are addressed relative to the array element, so a * running `prefix` reconstructs their absolute path before matching. Falls back * to the schema `default` when pruning empties the parameter. * * A preserved condition is exempt from the drop, not from the gate: pruning * anything out of a preserved subtree returns a query the preserved condition * does not describe (wider under the `and(, )` shape a filters * validator produces, narrower under an `or`), while keeping it would join a * relation the relations validator rejected. Neither outcome is correct, so the * contradiction between the two validators throws {@link SchemaError} * (`SCHEMA_PRESERVED_CONDITION_PRUNED`) instead of resolving it silently. The * decision is per node, not per operator: preservation says the condition * survives composition intact, and pruning is not asked to reason about which shapes * happen to fail open. */ declare function pruneFiltersByRelations(filters: IFilters, rejected: string[], schema?: FiltersSchema, issueCollector?: IIssueCollector): IFilters; declare function buildSortsDefaults(schema: SortsSchema): Sorts; /** * @deprecated use {@link buildSortsDefaults}. Removed in 3.0. */ declare const buildSortDefaults: typeof buildSortsDefaults; //#endregion //#region src/utils/input.d.ts /** * Read a canonical key or its deprecated alias. Supplying both with a * defined value each is a caller mistake, never a merge: the two spell * one parameter, and picking a winner would silently drop the other. * An `undefined` side (including one that is present but unset, e.g. * `{ sorts: undefined }` from a spread migration wrapper) never * triggers the ambiguity check, since there is nothing to drop. * * Presence is still checked as an OWN property (`isPropertySet`), not a * bare `typeof` read: a bare read walks the prototype chain, so an * array input would see `Array.prototype.sort` as a "defined" alias. */ declare function resolveAliasedKey(input: ObjectLiteral, canonical: string, alias: string, createError: (canonical: string, alias: string) => Error): unknown; //#endregion //#region src/utils/key.d.ts type KeyDetails = { name: string; group?: string; path?: string; }; /** * Parse a raw key ("[group:][path.]name", e.g. "0:items.title") * into its group, relation path and leaf name. */ declare function parseKey(input: string): KeyDetails; /** * Serialize key details back into the "[group:][path.]name" form. */ declare function stringifyKey(key: KeyDetails): string; /** * The canonical segments of a dotted key, as an {@link Issue} records them. * * `pathToArray` rather than `split('.')`, so a key whose segment carries an * escaped dot is not torn in half, and bracket indices survive. Segments are * stringified: an issue path is what a client reads back, not an accessor. */ declare function toIssuePath(input: string): string[]; //#endregion //#region src/utils/object.d.ts /** * Check whether the input is a plain (non-array) object. */ declare function isObject(item: unknown): item is Record; /** * Check whether an own property is set on the given object. */ declare function isPropertySet, K extends keyof X>(obj: X, prop: K): boolean; //#endregion //#region src/utils/parameter.d.ts /** * Fold the deprecated `sort` spelling onto the canonical `sorts`. * Applied wherever a caller-supplied parameter name is compared * against a list, so both spellings select the same parameter. */ declare function normalizeParameter(input: string): string; //#endregion export { AdapterError, AdapterErrorOptions, ArrayItem, BASE_ERROR_MARKER, BaseError, BaseErrorOptions, BaseParser, BaseQueryParser, BaseSchemaOptions, BuildError, CONDITION_MARKER, CodecError, ComparePlan, CompoundPlan, Condition, ConditionOptions, ConditionPlan, ConstantPlan, DEFAULT_ID, ElemMatchPlan, ErrorCode, ErrorCodeInput, ErrorMessage, FILTER_OPERATOR_SEMANTICS, Field, FieldKeys, FieldOperator, Fields, FieldsBuildInput, FieldsBuildNestedKeyInput, FieldsBuildRecordInput, FieldsBuildSimpleKeyInput, FieldsBuildTupleInput, FieldsOptions, FieldsParseError, FieldsParseOptions, FieldsSchema, FieldsSchemaDescription, Filter, FilterCompoundOperator, FilterFieldOperator, FilterOperatorFamily, FilterOperatorSemantics, FilterRegexFlag, Filters, FiltersBuildElemMatchInput, FiltersBuildInput, FiltersBuildOperatorInput, FiltersBuildValueInput, FiltersOptions, FiltersParseError, FiltersParseOptions, FiltersSchema, FiltersSchemaDescription, FiltersValidationOptions, IBaseError, ICondition, IField, IFieldVisitor, IFields, IFieldsVisitor, IFilter, IFilterVisitor, IFilters, IFiltersVisitor, IIssueCollector, IPagination, IPaginationVisitor, IParseError, IParser, IPlanInterpreter, IQuery, IQueryParameterParser, IQueryVisitor, IRelation, IRelationVisitor, IRelations, IRelationsVisitor, ISort, ISortVisitor, ISorts, ISortsVisitor, ITSELF, IndexCheckFailure, IndexCheckResult, IndexCheckSuccess, IndexedMode, IndexesOption, IndexesResolver, IsArray, IsScalar, IssueCollector, IssueInput, type KeyDetails, KeyResolution, KeyResolutionErrorCode, KeyResolutionFailure, KeyResolutionSuccess, KeyValidatableSchema, KeyValidatableSchemaOptions, KeyValidationOptions, KeyValidationScope, KeyValidationVerdict, KeyValidationVerdictRecord, KeyValidator, KeyValidatorMany, KeyWithOptionalPrefix, MAX_ISSUES, MAX_TRAVERSAL_DEPTH, MatchPattern, MatchPlan, MaybeAsync, MergeError, ModPlan, NestedKeys, NestedResourceKeys, NullCheckPlan, ObjectLiteral, ObjectLiteralKeys, OneOfPlan, PARSE_ERROR_MARKER, Pagination, PaginationBuildInput, PaginationOptions, PaginationParseError, PaginationParseOptions, PaginationSchema, PaginationSchemaDescription, Parameter, ParameterNode, ParameterSchema, ParseError, ParseParameterOptions, ParseQueryOptions, ParseTrace, ParseTraceContext, PendingKeyValidation, PlanCompareOperator, PlanConditionOptions, PrevIndex, Query, QueryBuildInput, QueryContext, Relation, RelationLedger, Relations, RelationsBuildInput, RelationsOptions, RelationsParseError, RelationsParseOptions, RelationsSchema, RelationsSchemaDescription, ResolutionScope, ResolutionScopeContext, Scalar, Schema, SchemaDescribeOptions, SchemaDescription, SchemaError, SchemaOptions, SchemaOptionsNormalized, SchemaRegistry, SerializedError, SimpleKeys, SimpleResourceKeys, SizePlan, Sort, SortDirection, SortOptionDefault, SortOptions, SortParseError, SortParseOptions, SortSchema, SortSchemaDescription, Sorts, SortsBuildInput, SortsBuildRecordInput, SortsOptionDefault, SortsOptions, SortsParseError, SortsParseOptions, SortsSchema, SortsSchemaDescription, TempType, TypeFromNestedKeyPath, Validator, and, applyFiltersIndexPolicy, applyFiltersSchemaValidation, applyFiltersSchemaValidationAsync, applyKeySchemaValidation, applyKeySchemaValidationAsync, applySortIndexPolicy, applySortsIndexPolicy, buildFiltersDefaults, buildIssue, buildSortDefaults, buildSortsDefaults, checkConditionIndexed, checkSortKeysIndexed, contains, createFilterRegex, createFilterRegexPattern, defineFields, defineFieldsSchema, defineFilters, defineFiltersSchema, definePagination, definePaginationSchema, defineQuery, defineRelations, defineRelationsSchema, defineSchema, defineSortSchema, defineSorts, defineSortsSchema, distributeNegation, elemMatch, endsWith, eq, exists, extractIssueKey, extractIssueParameter, gt, gte, hasFieldConditions, inArray, interpretPlan, isBaseError, isCondition, isField, isFields, isFilter, isFilters, isObject, isPagination, isParameterNode, isParseError, isPropertySet, isQuery, isRelation, isRelationRejected, isRelations, isSort, isSorts, lt, lte, mergeFiltersInput, mergeQueries, mod, ne, nin, normalizeParameter, not, notContains, notEndsWith, notStartsWith, or, parseKey, planCondition, preserve, pruneFieldsByRelations, pruneFiltersByRelations, pruneRelationsByRelations, pruneSortsByRelations, regex, resolveAliasedKey, size, startsWith, stringifyKey, toIssuePath }; //# sourceMappingURL=index.d.mts.map