@querykitjs/core 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-VD7XT52J.cjs → chunk-72KNINHB.cjs} +48 -2
- package/dist/chunk-72KNINHB.cjs.map +1 -0
- package/dist/{chunk-NHNDPIPM.js → chunk-XEETYJA3.js} +47 -3
- package/dist/chunk-XEETYJA3.js.map +1 -0
- package/dist/index.cjs +25 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -46
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +160 -10
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +138 -11
- package/dist/internal.d.ts +138 -11
- package/dist/internal.js +148 -5
- package/dist/internal.js.map +1 -1
- package/dist/{raw-Bx8c-TrC.d.cts → raw-AiElbDzC.d.cts} +2 -2
- package/dist/{raw-Bx8c-TrC.d.ts → raw-AiElbDzC.d.ts} +2 -2
- package/package.json +1 -1
- package/dist/chunk-NHNDPIPM.js.map +0 -1
- package/dist/chunk-VD7XT52J.cjs.map +0 -1
package/dist/internal.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SkippedCondition, SortDirection, Sort, CursorMeta, InfiniteMeta, OffsetMeta, Relations, QueryLimits, Filterable } from './index.cjs';
|
|
2
|
-
export { Z as isRaw } from './raw-
|
|
1
|
+
import { SkippedCondition, SortDirection, Sort, CursorMeta, InfiniteMeta, OffsetMeta, Relations, QueryLimits, Filterable, FilterOperator } from './index.cjs';
|
|
2
|
+
export { Z as isRaw } from './raw-AiElbDzC.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Opaque cursor tokens for keyset pagination, shared by every adapter so a token
|
|
@@ -53,7 +53,7 @@ interface NormalizedSortItem {
|
|
|
53
53
|
* The wire `sort` array with a direction on every item. An item without a `key`
|
|
54
54
|
* (`null`, `{}`) is dropped — sort comes from the client, and a malformed item
|
|
55
55
|
* must not crash the query — and, with `diag`, reported as `invalid-value` on
|
|
56
|
-
* `site: "sort"` (a `QueryKitError` under strict
|
|
56
|
+
* `site: "sort"` (a `QueryKitError` under strict).
|
|
57
57
|
*/
|
|
58
58
|
declare function normalizeSort(sort?: Sort, diag?: Diagnostics): NormalizedSortItem[];
|
|
59
59
|
|
|
@@ -71,7 +71,7 @@ declare function clampPage(requested: number | undefined): number;
|
|
|
71
71
|
declare function clampOffset(requested: number | undefined): number;
|
|
72
72
|
declare function offsetMeta(page: number, perPage: number, totalItems: number): OffsetMeta;
|
|
73
73
|
/**
|
|
74
|
-
* `withTotal: false
|
|
74
|
+
* `withTotal: false`: rows fetched with `perPage + 1` and no count →
|
|
75
75
|
* the page and its meta; the extra row only signals `has_next`, totals are `null`.
|
|
76
76
|
*/
|
|
77
77
|
declare function offsetPageWithoutTotal<T>(rows: readonly T[], page: number, perPage: number): {
|
|
@@ -90,7 +90,7 @@ interface CursorPageOptions {
|
|
|
90
90
|
hasCursor: boolean;
|
|
91
91
|
/** The row field the tokens are read from. */
|
|
92
92
|
cursorField: string;
|
|
93
|
-
/** The primary-key field — the tie-break value in every token
|
|
93
|
+
/** The primary-key field — the tie-break value in every token. */
|
|
94
94
|
idField: string;
|
|
95
95
|
/** Signs the tokens (registry `cursorSecret`). */
|
|
96
96
|
secret?: string;
|
|
@@ -113,7 +113,7 @@ declare function refuseEmptyFilter(source: string, method: "updateWhere" | "dele
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* A repository `scope` (the server's RBAC / tenancy filter) split once for every
|
|
116
|
-
* adapter
|
|
116
|
+
* adapter: equality values and `{ in: [...] }` lists.
|
|
117
117
|
*/
|
|
118
118
|
/** One scope condition, in the shape every adapter's `buildWhere` reads. */
|
|
119
119
|
interface ScopeCondition {
|
|
@@ -152,7 +152,7 @@ interface WithDialect {
|
|
|
152
152
|
declare function checkWith(withValue: unknown, relations: Relations | undefined, dialect: WithDialect, source: string, path?: string): Record<string, unknown> | undefined;
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
* The filter-limit walk shared by the validators
|
|
155
|
+
* The filter-limit walk shared by the validators. It runs on the raw,
|
|
156
156
|
* unvalidated payload **before** any recursive schema sees it, so it is
|
|
157
157
|
* iterative — no recursion at all, whatever the payload's depth — and a
|
|
158
158
|
* 10 000-level `not` chain is rejected after `maxDepth + 1` steps.
|
|
@@ -190,9 +190,9 @@ declare function likeWildcards(pattern: string): number;
|
|
|
190
190
|
declare const offsetOf: (page: number | undefined, perPage: number | undefined) => number;
|
|
191
191
|
|
|
192
192
|
/**
|
|
193
|
-
* The server-side request policy every adapter applies
|
|
193
|
+
* The server-side request policy every adapter applies: which fields
|
|
194
194
|
* a client may filter by and with which operators (`filterable`), which it may
|
|
195
|
-
* sort and page by (`sortable`), and the request limits (`limits
|
|
195
|
+
* sort and page by (`sortable`), and the request limits (`limits`).
|
|
196
196
|
*
|
|
197
197
|
* A plain object that is not a condition, a group, a branded `raw()` node or a
|
|
198
198
|
* driver-native object (`isNative`) is refused as well (R19): it would otherwise
|
|
@@ -245,5 +245,132 @@ interface Policy {
|
|
|
245
245
|
}
|
|
246
246
|
declare function resolvePolicy(options: PolicyOptions): Policy;
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Wire-contract checks for validator authors: the filter, the sort and the
|
|
250
|
+
* pagination params exactly as they arrive from JSON. Framework-free and
|
|
251
|
+
* text-free — an issue carries a path, a message key and its arguments; each
|
|
252
|
+
* validator renders its own message. The size walk runs first, iteratively, so
|
|
253
|
+
* an oversized payload never reaches the recursive shape check.
|
|
254
|
+
*/
|
|
255
|
+
|
|
256
|
+
type WireFilterIssueKey = "querykit.filter.invalid_node" | "querykit.filter.missing_key" | "querykit.filter.unknown_key" | "querykit.filter.invalid_operator" | "querykit.filter.invalid_value" | "querykit.filter.invalid_group" | "querykit.filter.max_depth" | "querykit.filter.value_requires_array" | "querykit.filter.value_requires_tuple" | "querykit.filter.value_forbidden" | "querykit.limit.exceeded";
|
|
257
|
+
type WireSortIssueKey = "querykit.sort.not_array" | "querykit.sort.invalid_item" | "querykit.sort.missing_key" | "querykit.sort.unknown_key" | "querykit.sort.invalid_direction" | "querykit.limit.exceeded";
|
|
258
|
+
type WireParamsIssueKey = "querykit.params.invalid_type" | "querykit.params.not_integer" | "querykit.params.out_of_range" | "querykit.params.invalid_enum";
|
|
259
|
+
type WireIssueKey = WireFilterIssueKey | WireSortIssueKey | WireParamsIssueKey;
|
|
260
|
+
/** Message arguments: strings and numbers only, so any message catalog can interpolate them. */
|
|
261
|
+
type WireIssueArgs = Record<string, string | number>;
|
|
262
|
+
/** One rejected spot: object keys and array indexes from the checked value, the message key and its arguments. */
|
|
263
|
+
interface WireIssue<TKey extends WireIssueKey = WireIssueKey> {
|
|
264
|
+
path: LimitPath;
|
|
265
|
+
key: TKey;
|
|
266
|
+
args: WireIssueArgs;
|
|
267
|
+
}
|
|
268
|
+
interface WireFilterOptions extends Partial<Pick<QueryLimits, "maxDepth" | "maxConditions" | "maxInItems" | "maxStringLength">> {
|
|
269
|
+
/** Only these keys may be filtered on; another key is an issue. Absent — any string key. */
|
|
270
|
+
allowedKeys?: readonly string[];
|
|
271
|
+
/** Absent — every core operator. */
|
|
272
|
+
allowedOperators?: readonly FilterOperator[];
|
|
273
|
+
/** `in`/`notIn` need an array, `between`/`notBetween` exactly two values, `isNull`/`isNotNull` no value. */
|
|
274
|
+
strictValue?: boolean;
|
|
275
|
+
}
|
|
276
|
+
interface WireSortOptions extends Partial<Pick<QueryLimits, "maxSortFields">> {
|
|
277
|
+
/** Only these keys may be sorted on. */
|
|
278
|
+
allowedKeys?: readonly string[];
|
|
279
|
+
}
|
|
280
|
+
/** Request fields only the server may set; a client sends them only where `allow` opens them. */
|
|
281
|
+
type WireServerOwnedField = "columns" | "with" | "withDeleted";
|
|
282
|
+
/** The same names and defaults as the `@querykitjs/zod` params factories. */
|
|
283
|
+
interface WireParamsOptions {
|
|
284
|
+
/** Default `DEFAULT_MAX_PER_PAGE` (200). */
|
|
285
|
+
maxPerPage?: number;
|
|
286
|
+
/** Default `DEFAULT_MAX_LIMIT` (200). */
|
|
287
|
+
maxLimit?: number;
|
|
288
|
+
limits?: Partial<QueryLimits>;
|
|
289
|
+
allow?: readonly WireServerOwnedField[];
|
|
290
|
+
}
|
|
291
|
+
type WireParamsKind = "offset" | "infinite" | "cursor";
|
|
292
|
+
interface WireParamsResult {
|
|
293
|
+
/** The accepted fields only (unknown and closed server-owned fields stripped); absent when there are issues. */
|
|
294
|
+
value?: Record<string, unknown>;
|
|
295
|
+
issues: WireIssue[];
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Checks a wire filter (a node, or a flat array as an implicit AND). An empty
|
|
299
|
+
* list means valid; `undefined` is valid. A crossed size limit is the only issue.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```ts
|
|
303
|
+
* checkFilter({ key: "age", operation: "~" }); // [{ path: ["operation"], key: "querykit.filter.invalid_operator", args: { operation: "~" } }]
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
declare function checkFilter(value: unknown, options?: WireFilterOptions): WireIssue<WireFilterIssueKey>[];
|
|
307
|
+
/** Checks a wire sort, `{ key, direction }[]`. An empty list means valid; `undefined` is valid. */
|
|
308
|
+
declare function checkSort(value: unknown, options?: WireSortOptions): WireIssue<WireSortIssueKey>[];
|
|
309
|
+
/**
|
|
310
|
+
* Checks offset, infinite or cursor params the way the `@querykitjs/zod`
|
|
311
|
+
* factories do: unknown fields and closed server-owned fields are stripped,
|
|
312
|
+
* `(page - 1) × perPage` stays within `maxOffset`, and a cursor request has no `sort`.
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```ts
|
|
316
|
+
* checkParams("offset", { page: 2, perPage: 201 }).issues;
|
|
317
|
+
* // [{ path: ["perPage"], key: "querykit.params.out_of_range", args: { max: 200 } }]
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
declare function checkParams(kind: WireParamsKind, value: unknown, options?: WireParamsOptions): WireParamsResult;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* English message texts for the wire-check issue keys, shared by the
|
|
324
|
+
* validators so a rejected payload reads the same everywhere. `{placeholder}`s
|
|
325
|
+
* are filled from the issue's `args`; `{path}` is the issue path as text.
|
|
326
|
+
*/
|
|
327
|
+
/**
|
|
328
|
+
* The filter, sort and limit messages — the canonical key list of
|
|
329
|
+
* `@querykitjs/class-validator`, which also ships `uz` and `ru` catalogs for it.
|
|
330
|
+
*/
|
|
331
|
+
declare const QUERYKIT_MESSAGES_EN: {
|
|
332
|
+
readonly "querykit.filter.invalid_node": "{path} must be a filter condition or an and/or/not group";
|
|
333
|
+
readonly "querykit.filter.missing_key": "{path} is missing the required `key` string";
|
|
334
|
+
readonly "querykit.filter.unknown_key": "{path}: `{key}` is not an allowed filter key";
|
|
335
|
+
readonly "querykit.filter.invalid_operator": "{path}: `{operation}` is not a supported filter operator";
|
|
336
|
+
readonly "querykit.filter.invalid_value": "{path} must be a string, number, boolean, null, or an array of those";
|
|
337
|
+
readonly "querykit.filter.invalid_group": "{path} must be an array of filter nodes";
|
|
338
|
+
readonly "querykit.filter.max_depth": "{path} exceeds maxDepth ({max})";
|
|
339
|
+
readonly "querykit.filter.value_requires_array": "{path}: `{operation}` requires an array value";
|
|
340
|
+
readonly "querykit.filter.value_requires_tuple": "{path}: `{operation}` requires exactly two values";
|
|
341
|
+
readonly "querykit.filter.value_forbidden": "{path}: `{operation}` must not carry a value";
|
|
342
|
+
readonly "querykit.sort.not_array": "{path} must be an array of { key, direction } items";
|
|
343
|
+
readonly "querykit.sort.invalid_item": "{path} must be an object with a `key` string";
|
|
344
|
+
readonly "querykit.sort.missing_key": "{path} is missing the required `key` string";
|
|
345
|
+
readonly "querykit.sort.unknown_key": "{path}: `{key}` is not an allowed sort key";
|
|
346
|
+
readonly "querykit.sort.invalid_direction": "{path}: direction must be `asc` or `desc`";
|
|
347
|
+
readonly "querykit.limit.exceeded": "{path} exceeds {limit} ({max})";
|
|
348
|
+
};
|
|
349
|
+
/** The pagination-params messages (`checkParams`); kept apart so the class-validator catalogs keep their key set. */
|
|
350
|
+
declare const QUERYKIT_PARAMS_MESSAGES_EN: {
|
|
351
|
+
readonly "querykit.params.invalid_type": "{path} must be {expected}";
|
|
352
|
+
readonly "querykit.params.not_integer": "{path} must be an integer";
|
|
353
|
+
readonly "querykit.params.out_of_range": "{path} is out of the allowed range";
|
|
354
|
+
readonly "querykit.params.invalid_enum": "{path} must be one of: {values}";
|
|
355
|
+
};
|
|
356
|
+
/** A filter, sort or limit message key. */
|
|
357
|
+
type QueryKitMessageKey = keyof typeof QUERYKIT_MESSAGES_EN;
|
|
358
|
+
/** One language's full catalog — every key required, so a new key breaks every catalog at compile time. */
|
|
359
|
+
type QueryKitMessageCatalog = Record<QueryKitMessageKey, string>;
|
|
360
|
+
/** Interpolation arguments. */
|
|
361
|
+
type MessageArgs = Record<string, string | number>;
|
|
362
|
+
/** Fills `{name}` placeholders from `args`; a placeholder with no argument stays as it is, so a message is never empty. */
|
|
363
|
+
declare const interpolate: (template: string, args: MessageArgs) => string;
|
|
364
|
+
/**
|
|
365
|
+
* The message for `key` from `catalog` (default English), placeholders filled.
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
368
|
+
* ```ts
|
|
369
|
+
* formatMessage("querykit.limit.exceeded", { path: "filter", limit: "maxConditions", max: 30 });
|
|
370
|
+
* // "filter exceeds maxConditions (30)"
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
declare function formatMessage(key: QueryKitMessageKey, args?: MessageArgs, catalog?: QueryKitMessageCatalog): string;
|
|
374
|
+
|
|
375
|
+
export { QUERYKIT_MESSAGES_EN, QUERYKIT_PARAMS_MESSAGES_EN, checkFilter, checkParams, checkSort, checkWith, clampOffset, clampPage, clampPageSize, createContextStore, cursorPage, decodeCursor, decodeCursorToken, encodeCursor, encodeCursorToken, findFilterLimitViolation, formatLimit, formatMessage, infinitePage, interpolate, isAllRows, isEmptyFilter, isLikeOperator, likeWildcards, normalizeSort, offsetMeta, offsetOf, offsetPageWithoutTotal, refuseEmptyFilter, reportSkip, resolvePolicy, scopeConditions, scopeDefaults };
|
|
376
|
+
export type { ContextStore, CursorPageOptions, CursorToken, Diagnostics, FilterLimits, LimitPath, LimitViolation, MessageArgs, NormalizedSortItem, Policy, PolicyOptions, QueryKitMessageCatalog, QueryKitMessageKey, ScopeCondition, WireFilterIssueKey, WireFilterOptions, WireIssue, WireIssueArgs, WireIssueKey, WireParamsIssueKey, WireParamsKind, WireParamsOptions, WireParamsResult, WireServerOwnedField, WireSortIssueKey, WireSortOptions, WithDialect };
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SkippedCondition, SortDirection, Sort, CursorMeta, InfiniteMeta, OffsetMeta, Relations, QueryLimits, Filterable } from './index.js';
|
|
2
|
-
export { Z as isRaw } from './raw-
|
|
1
|
+
import { SkippedCondition, SortDirection, Sort, CursorMeta, InfiniteMeta, OffsetMeta, Relations, QueryLimits, Filterable, FilterOperator } from './index.js';
|
|
2
|
+
export { Z as isRaw } from './raw-AiElbDzC.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Opaque cursor tokens for keyset pagination, shared by every adapter so a token
|
|
@@ -53,7 +53,7 @@ interface NormalizedSortItem {
|
|
|
53
53
|
* The wire `sort` array with a direction on every item. An item without a `key`
|
|
54
54
|
* (`null`, `{}`) is dropped — sort comes from the client, and a malformed item
|
|
55
55
|
* must not crash the query — and, with `diag`, reported as `invalid-value` on
|
|
56
|
-
* `site: "sort"` (a `QueryKitError` under strict
|
|
56
|
+
* `site: "sort"` (a `QueryKitError` under strict).
|
|
57
57
|
*/
|
|
58
58
|
declare function normalizeSort(sort?: Sort, diag?: Diagnostics): NormalizedSortItem[];
|
|
59
59
|
|
|
@@ -71,7 +71,7 @@ declare function clampPage(requested: number | undefined): number;
|
|
|
71
71
|
declare function clampOffset(requested: number | undefined): number;
|
|
72
72
|
declare function offsetMeta(page: number, perPage: number, totalItems: number): OffsetMeta;
|
|
73
73
|
/**
|
|
74
|
-
* `withTotal: false
|
|
74
|
+
* `withTotal: false`: rows fetched with `perPage + 1` and no count →
|
|
75
75
|
* the page and its meta; the extra row only signals `has_next`, totals are `null`.
|
|
76
76
|
*/
|
|
77
77
|
declare function offsetPageWithoutTotal<T>(rows: readonly T[], page: number, perPage: number): {
|
|
@@ -90,7 +90,7 @@ interface CursorPageOptions {
|
|
|
90
90
|
hasCursor: boolean;
|
|
91
91
|
/** The row field the tokens are read from. */
|
|
92
92
|
cursorField: string;
|
|
93
|
-
/** The primary-key field — the tie-break value in every token
|
|
93
|
+
/** The primary-key field — the tie-break value in every token. */
|
|
94
94
|
idField: string;
|
|
95
95
|
/** Signs the tokens (registry `cursorSecret`). */
|
|
96
96
|
secret?: string;
|
|
@@ -113,7 +113,7 @@ declare function refuseEmptyFilter(source: string, method: "updateWhere" | "dele
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* A repository `scope` (the server's RBAC / tenancy filter) split once for every
|
|
116
|
-
* adapter
|
|
116
|
+
* adapter: equality values and `{ in: [...] }` lists.
|
|
117
117
|
*/
|
|
118
118
|
/** One scope condition, in the shape every adapter's `buildWhere` reads. */
|
|
119
119
|
interface ScopeCondition {
|
|
@@ -152,7 +152,7 @@ interface WithDialect {
|
|
|
152
152
|
declare function checkWith(withValue: unknown, relations: Relations | undefined, dialect: WithDialect, source: string, path?: string): Record<string, unknown> | undefined;
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
* The filter-limit walk shared by the validators
|
|
155
|
+
* The filter-limit walk shared by the validators. It runs on the raw,
|
|
156
156
|
* unvalidated payload **before** any recursive schema sees it, so it is
|
|
157
157
|
* iterative — no recursion at all, whatever the payload's depth — and a
|
|
158
158
|
* 10 000-level `not` chain is rejected after `maxDepth + 1` steps.
|
|
@@ -190,9 +190,9 @@ declare function likeWildcards(pattern: string): number;
|
|
|
190
190
|
declare const offsetOf: (page: number | undefined, perPage: number | undefined) => number;
|
|
191
191
|
|
|
192
192
|
/**
|
|
193
|
-
* The server-side request policy every adapter applies
|
|
193
|
+
* The server-side request policy every adapter applies: which fields
|
|
194
194
|
* a client may filter by and with which operators (`filterable`), which it may
|
|
195
|
-
* sort and page by (`sortable`), and the request limits (`limits
|
|
195
|
+
* sort and page by (`sortable`), and the request limits (`limits`).
|
|
196
196
|
*
|
|
197
197
|
* A plain object that is not a condition, a group, a branded `raw()` node or a
|
|
198
198
|
* driver-native object (`isNative`) is refused as well (R19): it would otherwise
|
|
@@ -245,5 +245,132 @@ interface Policy {
|
|
|
245
245
|
}
|
|
246
246
|
declare function resolvePolicy(options: PolicyOptions): Policy;
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Wire-contract checks for validator authors: the filter, the sort and the
|
|
250
|
+
* pagination params exactly as they arrive from JSON. Framework-free and
|
|
251
|
+
* text-free — an issue carries a path, a message key and its arguments; each
|
|
252
|
+
* validator renders its own message. The size walk runs first, iteratively, so
|
|
253
|
+
* an oversized payload never reaches the recursive shape check.
|
|
254
|
+
*/
|
|
255
|
+
|
|
256
|
+
type WireFilterIssueKey = "querykit.filter.invalid_node" | "querykit.filter.missing_key" | "querykit.filter.unknown_key" | "querykit.filter.invalid_operator" | "querykit.filter.invalid_value" | "querykit.filter.invalid_group" | "querykit.filter.max_depth" | "querykit.filter.value_requires_array" | "querykit.filter.value_requires_tuple" | "querykit.filter.value_forbidden" | "querykit.limit.exceeded";
|
|
257
|
+
type WireSortIssueKey = "querykit.sort.not_array" | "querykit.sort.invalid_item" | "querykit.sort.missing_key" | "querykit.sort.unknown_key" | "querykit.sort.invalid_direction" | "querykit.limit.exceeded";
|
|
258
|
+
type WireParamsIssueKey = "querykit.params.invalid_type" | "querykit.params.not_integer" | "querykit.params.out_of_range" | "querykit.params.invalid_enum";
|
|
259
|
+
type WireIssueKey = WireFilterIssueKey | WireSortIssueKey | WireParamsIssueKey;
|
|
260
|
+
/** Message arguments: strings and numbers only, so any message catalog can interpolate them. */
|
|
261
|
+
type WireIssueArgs = Record<string, string | number>;
|
|
262
|
+
/** One rejected spot: object keys and array indexes from the checked value, the message key and its arguments. */
|
|
263
|
+
interface WireIssue<TKey extends WireIssueKey = WireIssueKey> {
|
|
264
|
+
path: LimitPath;
|
|
265
|
+
key: TKey;
|
|
266
|
+
args: WireIssueArgs;
|
|
267
|
+
}
|
|
268
|
+
interface WireFilterOptions extends Partial<Pick<QueryLimits, "maxDepth" | "maxConditions" | "maxInItems" | "maxStringLength">> {
|
|
269
|
+
/** Only these keys may be filtered on; another key is an issue. Absent — any string key. */
|
|
270
|
+
allowedKeys?: readonly string[];
|
|
271
|
+
/** Absent — every core operator. */
|
|
272
|
+
allowedOperators?: readonly FilterOperator[];
|
|
273
|
+
/** `in`/`notIn` need an array, `between`/`notBetween` exactly two values, `isNull`/`isNotNull` no value. */
|
|
274
|
+
strictValue?: boolean;
|
|
275
|
+
}
|
|
276
|
+
interface WireSortOptions extends Partial<Pick<QueryLimits, "maxSortFields">> {
|
|
277
|
+
/** Only these keys may be sorted on. */
|
|
278
|
+
allowedKeys?: readonly string[];
|
|
279
|
+
}
|
|
280
|
+
/** Request fields only the server may set; a client sends them only where `allow` opens them. */
|
|
281
|
+
type WireServerOwnedField = "columns" | "with" | "withDeleted";
|
|
282
|
+
/** The same names and defaults as the `@querykitjs/zod` params factories. */
|
|
283
|
+
interface WireParamsOptions {
|
|
284
|
+
/** Default `DEFAULT_MAX_PER_PAGE` (200). */
|
|
285
|
+
maxPerPage?: number;
|
|
286
|
+
/** Default `DEFAULT_MAX_LIMIT` (200). */
|
|
287
|
+
maxLimit?: number;
|
|
288
|
+
limits?: Partial<QueryLimits>;
|
|
289
|
+
allow?: readonly WireServerOwnedField[];
|
|
290
|
+
}
|
|
291
|
+
type WireParamsKind = "offset" | "infinite" | "cursor";
|
|
292
|
+
interface WireParamsResult {
|
|
293
|
+
/** The accepted fields only (unknown and closed server-owned fields stripped); absent when there are issues. */
|
|
294
|
+
value?: Record<string, unknown>;
|
|
295
|
+
issues: WireIssue[];
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Checks a wire filter (a node, or a flat array as an implicit AND). An empty
|
|
299
|
+
* list means valid; `undefined` is valid. A crossed size limit is the only issue.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```ts
|
|
303
|
+
* checkFilter({ key: "age", operation: "~" }); // [{ path: ["operation"], key: "querykit.filter.invalid_operator", args: { operation: "~" } }]
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
declare function checkFilter(value: unknown, options?: WireFilterOptions): WireIssue<WireFilterIssueKey>[];
|
|
307
|
+
/** Checks a wire sort, `{ key, direction }[]`. An empty list means valid; `undefined` is valid. */
|
|
308
|
+
declare function checkSort(value: unknown, options?: WireSortOptions): WireIssue<WireSortIssueKey>[];
|
|
309
|
+
/**
|
|
310
|
+
* Checks offset, infinite or cursor params the way the `@querykitjs/zod`
|
|
311
|
+
* factories do: unknown fields and closed server-owned fields are stripped,
|
|
312
|
+
* `(page - 1) × perPage` stays within `maxOffset`, and a cursor request has no `sort`.
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```ts
|
|
316
|
+
* checkParams("offset", { page: 2, perPage: 201 }).issues;
|
|
317
|
+
* // [{ path: ["perPage"], key: "querykit.params.out_of_range", args: { max: 200 } }]
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
declare function checkParams(kind: WireParamsKind, value: unknown, options?: WireParamsOptions): WireParamsResult;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* English message texts for the wire-check issue keys, shared by the
|
|
324
|
+
* validators so a rejected payload reads the same everywhere. `{placeholder}`s
|
|
325
|
+
* are filled from the issue's `args`; `{path}` is the issue path as text.
|
|
326
|
+
*/
|
|
327
|
+
/**
|
|
328
|
+
* The filter, sort and limit messages — the canonical key list of
|
|
329
|
+
* `@querykitjs/class-validator`, which also ships `uz` and `ru` catalogs for it.
|
|
330
|
+
*/
|
|
331
|
+
declare const QUERYKIT_MESSAGES_EN: {
|
|
332
|
+
readonly "querykit.filter.invalid_node": "{path} must be a filter condition or an and/or/not group";
|
|
333
|
+
readonly "querykit.filter.missing_key": "{path} is missing the required `key` string";
|
|
334
|
+
readonly "querykit.filter.unknown_key": "{path}: `{key}` is not an allowed filter key";
|
|
335
|
+
readonly "querykit.filter.invalid_operator": "{path}: `{operation}` is not a supported filter operator";
|
|
336
|
+
readonly "querykit.filter.invalid_value": "{path} must be a string, number, boolean, null, or an array of those";
|
|
337
|
+
readonly "querykit.filter.invalid_group": "{path} must be an array of filter nodes";
|
|
338
|
+
readonly "querykit.filter.max_depth": "{path} exceeds maxDepth ({max})";
|
|
339
|
+
readonly "querykit.filter.value_requires_array": "{path}: `{operation}` requires an array value";
|
|
340
|
+
readonly "querykit.filter.value_requires_tuple": "{path}: `{operation}` requires exactly two values";
|
|
341
|
+
readonly "querykit.filter.value_forbidden": "{path}: `{operation}` must not carry a value";
|
|
342
|
+
readonly "querykit.sort.not_array": "{path} must be an array of { key, direction } items";
|
|
343
|
+
readonly "querykit.sort.invalid_item": "{path} must be an object with a `key` string";
|
|
344
|
+
readonly "querykit.sort.missing_key": "{path} is missing the required `key` string";
|
|
345
|
+
readonly "querykit.sort.unknown_key": "{path}: `{key}` is not an allowed sort key";
|
|
346
|
+
readonly "querykit.sort.invalid_direction": "{path}: direction must be `asc` or `desc`";
|
|
347
|
+
readonly "querykit.limit.exceeded": "{path} exceeds {limit} ({max})";
|
|
348
|
+
};
|
|
349
|
+
/** The pagination-params messages (`checkParams`); kept apart so the class-validator catalogs keep their key set. */
|
|
350
|
+
declare const QUERYKIT_PARAMS_MESSAGES_EN: {
|
|
351
|
+
readonly "querykit.params.invalid_type": "{path} must be {expected}";
|
|
352
|
+
readonly "querykit.params.not_integer": "{path} must be an integer";
|
|
353
|
+
readonly "querykit.params.out_of_range": "{path} is out of the allowed range";
|
|
354
|
+
readonly "querykit.params.invalid_enum": "{path} must be one of: {values}";
|
|
355
|
+
};
|
|
356
|
+
/** A filter, sort or limit message key. */
|
|
357
|
+
type QueryKitMessageKey = keyof typeof QUERYKIT_MESSAGES_EN;
|
|
358
|
+
/** One language's full catalog — every key required, so a new key breaks every catalog at compile time. */
|
|
359
|
+
type QueryKitMessageCatalog = Record<QueryKitMessageKey, string>;
|
|
360
|
+
/** Interpolation arguments. */
|
|
361
|
+
type MessageArgs = Record<string, string | number>;
|
|
362
|
+
/** Fills `{name}` placeholders from `args`; a placeholder with no argument stays as it is, so a message is never empty. */
|
|
363
|
+
declare const interpolate: (template: string, args: MessageArgs) => string;
|
|
364
|
+
/**
|
|
365
|
+
* The message for `key` from `catalog` (default English), placeholders filled.
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
368
|
+
* ```ts
|
|
369
|
+
* formatMessage("querykit.limit.exceeded", { path: "filter", limit: "maxConditions", max: 30 });
|
|
370
|
+
* // "filter exceeds maxConditions (30)"
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
declare function formatMessage(key: QueryKitMessageKey, args?: MessageArgs, catalog?: QueryKitMessageCatalog): string;
|
|
374
|
+
|
|
375
|
+
export { QUERYKIT_MESSAGES_EN, QUERYKIT_PARAMS_MESSAGES_EN, checkFilter, checkParams, checkSort, checkWith, clampOffset, clampPage, clampPageSize, createContextStore, cursorPage, decodeCursor, decodeCursorToken, encodeCursor, encodeCursorToken, findFilterLimitViolation, formatLimit, formatMessage, infinitePage, interpolate, isAllRows, isEmptyFilter, isLikeOperator, likeWildcards, normalizeSort, offsetMeta, offsetOf, offsetPageWithoutTotal, refuseEmptyFilter, reportSkip, resolvePolicy, scopeConditions, scopeDefaults };
|
|
376
|
+
export type { ContextStore, CursorPageOptions, CursorToken, Diagnostics, FilterLimits, LimitPath, LimitViolation, MessageArgs, NormalizedSortItem, Policy, PolicyOptions, QueryKitMessageCatalog, QueryKitMessageKey, ScopeCondition, WireFilterIssueKey, WireFilterOptions, WireIssue, WireIssueArgs, WireIssueKey, WireParamsIssueKey, WireParamsKind, WireParamsOptions, WireParamsResult, WireServerOwnedField, WireSortIssueKey, WireSortOptions, WithDialect };
|
package/dist/internal.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { QueryKitError, resolveLimits, isRaw } from './chunk-
|
|
2
|
-
export { isRaw } from './chunk-
|
|
1
|
+
import { QueryKitError, resolveLimits, isRaw, FILTER_OPERATORS } from './chunk-XEETYJA3.js';
|
|
2
|
+
export { isRaw } from './chunk-XEETYJA3.js';
|
|
3
3
|
|
|
4
4
|
// src/internal/cursor.ts
|
|
5
5
|
function encodeCursor(value) {
|
|
@@ -283,7 +283,7 @@ function filterRules(options, canonical) {
|
|
|
283
283
|
function resolvePolicy(options) {
|
|
284
284
|
let limits = resolveLimits(options.limits), canonical = (key) => options.fieldOf(key) ?? key, rules = filterRules(options, canonical), sortable = new Set((options.sortable ?? [options.primaryKey, ...options.createdAt ? [options.createdAt] : []]).map(canonical)), refuse = (site, key, reason, operation) => {
|
|
285
285
|
throw new QueryKitError({ source: options.source, site, key, reason, ...operation ? { operation } : {} });
|
|
286
|
-
},
|
|
286
|
+
}, checkCondition2 = (node) => {
|
|
287
287
|
let key = String(node.key), field = options.fieldOf(key);
|
|
288
288
|
if (field === void 0) return;
|
|
289
289
|
let operation = typeof node.operation == "string" ? node.operation : "=", rule = rules.get(field);
|
|
@@ -300,7 +300,7 @@ function resolvePolicy(options) {
|
|
|
300
300
|
let pending = Array.isArray(filter) ? [...filter] : [filter];
|
|
301
301
|
for (; pending.length > 0; ) {
|
|
302
302
|
let node = pending.pop();
|
|
303
|
-
isRecord2(node) && ("key" in node ?
|
|
303
|
+
isRecord2(node) && ("key" in node ? checkCondition2(node) : Array.isArray(node.and) ? pending.push(...node.and) : Array.isArray(node.or) ? pending.push(...node.or) : "not" in node ? pending.push(node.not) : !isRaw(node) && !options.isNative?.(node) && refuse("filter", Object.keys(node)[0] ?? "", "forbidden-key"));
|
|
304
304
|
}
|
|
305
305
|
},
|
|
306
306
|
checkSort(sort) {
|
|
@@ -322,6 +322,149 @@ function resolvePolicy(options) {
|
|
|
322
322
|
};
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
|
|
325
|
+
// src/internal/wire-checks.ts
|
|
326
|
+
var ALL_OPERATORS = /* @__PURE__ */ new Set(FILTER_OPERATORS), isRecord3 = (value) => typeof value == "object" && value !== null && !Array.isArray(value), isScalar2 = (value) => value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" && Number.isFinite(value), isFilterValue = (value) => Array.isArray(value) ? value.every(isScalar2) : isScalar2(value), label = (value) => {
|
|
327
|
+
try {
|
|
328
|
+
return String(value);
|
|
329
|
+
} catch {
|
|
330
|
+
return Object.prototype.toString.call(value);
|
|
331
|
+
}
|
|
332
|
+
}, wireIssue = (key, path, args = {}) => ({ path, key, args });
|
|
333
|
+
function checkCondition(node, path, walk) {
|
|
334
|
+
if (!isRecord3(node)) {
|
|
335
|
+
walk.issues.push(wireIssue("querykit.filter.invalid_node", path));
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
let { key, operation, value } = node;
|
|
339
|
+
if (typeof key != "string") {
|
|
340
|
+
walk.issues.push(wireIssue("querykit.filter.missing_key", path));
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
walk.allowedKeys && !walk.allowedKeys.has(key) && walk.issues.push(wireIssue("querykit.filter.unknown_key", path, { key }));
|
|
344
|
+
let operator;
|
|
345
|
+
operation !== void 0 && (typeof operation == "string" && walk.operators.has(operation) ? operator = operation : walk.issues.push(wireIssue("querykit.filter.invalid_operator", [...path, "operation"], { operation: label(operation) }))), value !== void 0 && !isFilterValue(value) && walk.issues.push(wireIssue("querykit.filter.invalid_value", [...path, "value"])), walk.strictValue && operator !== void 0 && checkValueShape(operator, value, [...path, "value"], walk);
|
|
346
|
+
}
|
|
347
|
+
function checkValueShape(operator, value, path, walk) {
|
|
348
|
+
let key = (operator === "in" || operator === "notIn") && !Array.isArray(value) ? "querykit.filter.value_requires_array" : (operator === "between" || operator === "notBetween") && (!Array.isArray(value) || value.length !== 2) ? "querykit.filter.value_requires_tuple" : (operator === "isNull" || operator === "isNotNull") && value !== void 0 ? "querykit.filter.value_forbidden" : void 0;
|
|
349
|
+
key && walk.issues.push(wireIssue(key, path, { operation: operator }));
|
|
350
|
+
}
|
|
351
|
+
function walkGroup(group, depth, path, walk) {
|
|
352
|
+
if (!Array.isArray(group)) {
|
|
353
|
+
walk.issues.push(wireIssue("querykit.filter.invalid_group", path));
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
group.forEach((child, index) => walkNode(child, depth + 1, [...path, index], walk));
|
|
357
|
+
}
|
|
358
|
+
function walkNode(node, depth, path, walk) {
|
|
359
|
+
if (depth > walk.maxDepth) {
|
|
360
|
+
walk.issues.push(wireIssue("querykit.filter.max_depth", path, { max: walk.maxDepth }));
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (!isRecord3(node)) {
|
|
364
|
+
walk.issues.push(wireIssue("querykit.filter.invalid_node", path));
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
"key" in node ? checkCondition(node, path, walk) : "and" in node ? walkGroup(node.and, depth, [...path, "and"], walk) : "or" in node ? walkGroup(node.or, depth, [...path, "or"], walk) : "not" in node ? walkNode(node.not, depth + 1, [...path, "not"], walk) : walk.issues.push(wireIssue("querykit.filter.missing_key", path));
|
|
368
|
+
}
|
|
369
|
+
function checkFilter(value, options = {}) {
|
|
370
|
+
if (value === void 0) return [];
|
|
371
|
+
let limits = resolveLimits(options), violation = findFilterLimitViolation(value, limits);
|
|
372
|
+
if (violation) {
|
|
373
|
+
let key = violation.limit === "maxDepth" ? "querykit.filter.max_depth" : "querykit.limit.exceeded";
|
|
374
|
+
return [wireIssue(key, violation.path, { limit: violation.limit, max: violation.max })];
|
|
375
|
+
}
|
|
376
|
+
let walk = {
|
|
377
|
+
issues: [],
|
|
378
|
+
allowedKeys: options.allowedKeys ? new Set(options.allowedKeys) : void 0,
|
|
379
|
+
operators: options.allowedOperators ? new Set(options.allowedOperators) : ALL_OPERATORS,
|
|
380
|
+
maxDepth: limits.maxDepth,
|
|
381
|
+
strictValue: options.strictValue ?? false
|
|
382
|
+
};
|
|
383
|
+
return Array.isArray(value) ? value.forEach((item, index) => checkCondition(item, [index], walk)) : walkNode(value, 1, [], walk), walk.issues;
|
|
384
|
+
}
|
|
385
|
+
function checkSort(value, options = {}) {
|
|
386
|
+
if (value === void 0) return [];
|
|
387
|
+
if (!Array.isArray(value)) return [wireIssue("querykit.sort.not_array", [])];
|
|
388
|
+
let { maxSortFields } = resolveLimits(options);
|
|
389
|
+
if (value.length > maxSortFields) return [wireIssue("querykit.limit.exceeded", [], { limit: "maxSortFields", max: maxSortFields })];
|
|
390
|
+
let allowedKeys = options.allowedKeys ? new Set(options.allowedKeys) : void 0, issues = [];
|
|
391
|
+
return value.forEach((item, index) => {
|
|
392
|
+
if (!isRecord3(item)) {
|
|
393
|
+
issues.push(wireIssue("querykit.sort.invalid_item", [index]));
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
let { key, direction } = item;
|
|
397
|
+
if (typeof key != "string") {
|
|
398
|
+
issues.push(wireIssue("querykit.sort.missing_key", [index]));
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
allowedKeys && !allowedKeys.has(key) && issues.push(wireIssue("querykit.sort.unknown_key", [index], { key })), direction !== void 0 && direction !== "asc" && direction !== "desc" && issues.push(wireIssue("querykit.sort.invalid_direction", [index, "direction"]));
|
|
402
|
+
}), issues;
|
|
403
|
+
}
|
|
404
|
+
var prefixed = (path, issues) => issues.map((found) => ({ ...found, path: [...path, ...found.path] })), accepts = (expected, value) => expected === "object" ? isRecord3(value) : expected === "string or null" ? value === null || typeof value == "string" : typeof value === expected, typed = (expected) => (value, path, issues) => {
|
|
405
|
+
accepts(expected, value) || issues.push(wireIssue("querykit.params.invalid_type", path, { expected: `${expected === "object" ? "an" : "a"} ${expected}` }));
|
|
406
|
+
}, oneOf = (values) => (value, path, issues) => {
|
|
407
|
+
(typeof value != "string" || !values.includes(value)) && issues.push(wireIssue("querykit.params.invalid_enum", path, { values: values.join(", ") }));
|
|
408
|
+
}, integer = (min, max, overLimit) => (value, path, issues) => {
|
|
409
|
+
typeof value != "number" || !Number.isFinite(value) ? issues.push(wireIssue("querykit.params.invalid_type", path, { expected: "a number" })) : Number.isInteger(value) ? value < min ? issues.push(wireIssue("querykit.params.out_of_range", path, { min })) : value > max && overLimit ? issues.push(wireIssue("querykit.limit.exceeded", path, { limit: overLimit, max })) : value > max && issues.push(wireIssue("querykit.params.out_of_range", path, { max })) : issues.push(wireIssue("querykit.params.not_integer", path));
|
|
410
|
+
}, checkColumns = (value, path, issues) => {
|
|
411
|
+
if (typed("object")(value, path, issues), isRecord3(value)) for (let [name, flag] of Object.entries(value)) typed("boolean")(flag, [...path, name], issues);
|
|
412
|
+
}, serverOwnedCheck = (field) => field === "columns" ? checkColumns : typed(field === "with" ? "object" : "boolean");
|
|
413
|
+
function fieldChecks(kind, options, limits) {
|
|
414
|
+
let checks = /* @__PURE__ */ new Map();
|
|
415
|
+
checks.set("filter", (value, path, issues) => issues.push(...prefixed(path, checkFilter(value, limits)))), kind !== "cursor" && checks.set("sort", (value, path, issues) => issues.push(...prefixed(path, checkSort(value, limits))));
|
|
416
|
+
for (let field of options.allow ?? []) checks.set(field, serverOwnedCheck(field));
|
|
417
|
+
let maxLimit = options.maxLimit ?? 200;
|
|
418
|
+
return kind === "offset" ? (checks.set("page", integer(1, Number.POSITIVE_INFINITY)), checks.set("perPage", integer(1, options.maxPerPage ?? 200)), checks.set("withTotal", typed("boolean"))) : kind === "infinite" ? (checks.set("limit", integer(1, maxLimit)), checks.set("offset", integer(0, limits.maxOffset, "maxOffset"))) : (checks.set("limit", integer(1, maxLimit)), checks.set("cursor", typed("string or null")), checks.set("cursorKey", typed("string")), checks.set("order", oneOf(["asc", "desc"])), checks.set("direction", oneOf(["forward", "backward"]))), checks;
|
|
419
|
+
}
|
|
420
|
+
function checkParams(kind, value, options = {}) {
|
|
421
|
+
if (!isRecord3(value)) return { issues: [wireIssue("querykit.params.invalid_type", [], { expected: "an object" })] };
|
|
422
|
+
let limits = resolveLimits(options.limits), checks = fieldChecks(kind, options, limits), issues = [], accepted = {};
|
|
423
|
+
for (let [name, field] of Object.entries(value)) {
|
|
424
|
+
let check = checks.get(name);
|
|
425
|
+
if (!check || field === void 0) continue;
|
|
426
|
+
let before = issues.length;
|
|
427
|
+
check(field, [name], issues), issues.length === before && (accepted[name] = field);
|
|
428
|
+
}
|
|
429
|
+
if (kind === "offset" && issues.length === 0) {
|
|
430
|
+
let page = typeof accepted.page == "number" ? accepted.page : void 0, perPage = typeof accepted.perPage == "number" ? accepted.perPage : void 0;
|
|
431
|
+
offsetOf(page, perPage) > limits.maxOffset && issues.push(wireIssue("querykit.limit.exceeded", ["page"], { limit: "maxOffset", max: limits.maxOffset }));
|
|
432
|
+
}
|
|
433
|
+
return issues.length ? { issues } : { value: accepted, issues };
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/internal/messages.ts
|
|
437
|
+
var QUERYKIT_MESSAGES_EN = {
|
|
438
|
+
"querykit.filter.invalid_node": "{path} must be a filter condition or an and/or/not group",
|
|
439
|
+
"querykit.filter.missing_key": "{path} is missing the required `key` string",
|
|
440
|
+
"querykit.filter.unknown_key": "{path}: `{key}` is not an allowed filter key",
|
|
441
|
+
"querykit.filter.invalid_operator": "{path}: `{operation}` is not a supported filter operator",
|
|
442
|
+
"querykit.filter.invalid_value": "{path} must be a string, number, boolean, null, or an array of those",
|
|
443
|
+
"querykit.filter.invalid_group": "{path} must be an array of filter nodes",
|
|
444
|
+
"querykit.filter.max_depth": "{path} exceeds maxDepth ({max})",
|
|
445
|
+
"querykit.filter.value_requires_array": "{path}: `{operation}` requires an array value",
|
|
446
|
+
"querykit.filter.value_requires_tuple": "{path}: `{operation}` requires exactly two values",
|
|
447
|
+
"querykit.filter.value_forbidden": "{path}: `{operation}` must not carry a value",
|
|
448
|
+
"querykit.sort.not_array": "{path} must be an array of { key, direction } items",
|
|
449
|
+
"querykit.sort.invalid_item": "{path} must be an object with a `key` string",
|
|
450
|
+
"querykit.sort.missing_key": "{path} is missing the required `key` string",
|
|
451
|
+
"querykit.sort.unknown_key": "{path}: `{key}` is not an allowed sort key",
|
|
452
|
+
"querykit.sort.invalid_direction": "{path}: direction must be `asc` or `desc`",
|
|
453
|
+
"querykit.limit.exceeded": "{path} exceeds {limit} ({max})"
|
|
454
|
+
}, QUERYKIT_PARAMS_MESSAGES_EN = {
|
|
455
|
+
"querykit.params.invalid_type": "{path} must be {expected}",
|
|
456
|
+
"querykit.params.not_integer": "{path} must be an integer",
|
|
457
|
+
// args carry only the crossed bound (`min` or `max`), so the text names neither
|
|
458
|
+
"querykit.params.out_of_range": "{path} is out of the allowed range",
|
|
459
|
+
"querykit.params.invalid_enum": "{path} must be one of: {values}"
|
|
460
|
+
}, PLACEHOLDER = /\{(\w+)\}/g, interpolate = (template, args) => template.replace(PLACEHOLDER, (match, name) => {
|
|
461
|
+
let value = args[name];
|
|
462
|
+
return value === void 0 ? match : String(value);
|
|
463
|
+
});
|
|
464
|
+
function formatMessage(key, args = {}, catalog = QUERYKIT_MESSAGES_EN) {
|
|
465
|
+
return interpolate(catalog[key], args);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export { QUERYKIT_MESSAGES_EN, QUERYKIT_PARAMS_MESSAGES_EN, checkFilter, checkParams, checkSort, checkWith, clampOffset, clampPage, clampPageSize, createContextStore, cursorPage, decodeCursor, decodeCursorToken, encodeCursor, encodeCursorToken, findFilterLimitViolation, formatLimit, formatMessage, infinitePage, interpolate, isAllRows, isEmptyFilter, isLikeOperator, likeWildcards, normalizeSort, offsetMeta, offsetOf, offsetPageWithoutTotal, refuseEmptyFilter, reportSkip, resolvePolicy, scopeConditions, scopeDefaults };
|
|
326
469
|
//# sourceMappingURL=internal.js.map
|
|
327
470
|
//# sourceMappingURL=internal.js.map
|