feathers-utils 10.2.0 → 10.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/{hooks-tfw03iVM.mjs → hooks-D_u2QFhM.mjs} +65 -65
  2. package/dist/{hooks-tfw03iVM.mjs.map → hooks-D_u2QFhM.mjs.map} +1 -1
  3. package/dist/hooks.d.mts +48 -48
  4. package/dist/hooks.mjs +4 -4
  5. package/dist/{index-CKAzIogj.d.mts → index-H1zXVhff.d.mts} +209 -105
  6. package/dist/index.d.mts +2 -2
  7. package/dist/index.mjs +7 -7
  8. package/dist/internal.utils-CWuBYzpQ.mjs +120 -0
  9. package/dist/internal.utils-CWuBYzpQ.mjs.map +1 -0
  10. package/dist/{mutate-result.util-Dqzepn1M.mjs → mutate-result.util-mxvMl6bw.mjs} +2 -2
  11. package/dist/mutate-result.util-mxvMl6bw.mjs.map +1 -0
  12. package/dist/{predicates-puYa4nkf.mjs → predicates-CR4O2nSr.mjs} +53 -53
  13. package/dist/{predicates-puYa4nkf.mjs.map → predicates-CR4O2nSr.mjs.map} +1 -1
  14. package/dist/predicates.d.mts +18 -18
  15. package/dist/predicates.mjs +1 -1
  16. package/dist/{resolve-B9hRleHY.mjs → resolve-BbbdWdlO.mjs} +2 -2
  17. package/dist/{resolve-B9hRleHY.mjs.map → resolve-BbbdWdlO.mjs.map} +1 -1
  18. package/dist/resolvers.mjs +1 -1
  19. package/dist/{transform-result.hook-B65pTRJO.mjs → transform-result.hook-0D676rcY.mjs} +2 -2
  20. package/dist/{transform-result.hook-B65pTRJO.mjs.map → transform-result.hook-0D676rcY.mjs.map} +1 -1
  21. package/dist/transformers.mjs +3 -3
  22. package/dist/{utils-BAIcSl7u.mjs → utils-sTvj8-Jy.mjs} +467 -209
  23. package/dist/utils-sTvj8-Jy.mjs.map +1 -0
  24. package/dist/utils.d.mts +2 -2
  25. package/dist/utils.mjs +4 -4
  26. package/package.json +1 -1
  27. package/src/common/dedupe-branches.ts +42 -0
  28. package/src/common/flatten-and-branches.ts +56 -0
  29. package/src/common/flatten-or-branches.ts +52 -0
  30. package/src/common/index.ts +4 -0
  31. package/src/common/is-empty-object.ts +38 -0
  32. package/src/hooks/index.ts +1 -1
  33. package/src/predicates/index.ts +3 -3
  34. package/src/utils/add-to-query/add-to-query.util.ts +19 -1
  35. package/src/utils/index.ts +6 -4
  36. package/src/utils/merge-query/extract-query-filters.ts +80 -0
  37. package/src/utils/merge-query/has-conflict.ts +39 -0
  38. package/src/utils/merge-query/logical-branches.ts +39 -0
  39. package/src/utils/merge-query/merge-query-bodies.ts +152 -0
  40. package/src/utils/merge-query/merge-query.util.ts +105 -0
  41. package/src/utils/merge-query/merge-select.ts +64 -0
  42. package/src/utils/replace-data/replace-data.util.ts +4 -4
  43. package/src/utils/replace-result/replace-result.util.ts +18 -18
  44. package/src/utils/simplify-query/merge-and-branches-up.ts +86 -0
  45. package/src/utils/simplify-query/merge-or-branch-up.ts +74 -0
  46. package/src/utils/simplify-query/simplify-query.util.ts +98 -0
  47. package/dist/internal.utils-BMzV_-xp.mjs +0 -55
  48. package/dist/internal.utils-BMzV_-xp.mjs.map +0 -1
  49. package/dist/mutate-result.util-Dqzepn1M.mjs.map +0 -1
  50. package/dist/utils-BAIcSl7u.mjs.map +0 -1
package/dist/hooks.d.mts CHANGED
@@ -249,6 +249,54 @@ declare function createRelated<H extends HookContext = HookContext>(options: May
249
249
  */
250
250
  declare const debug: <H extends HookContext = HookContext>(msg: string, ...fieldNames: string[]) => (context: H, next?: NextFunction) => Promise<void>;
251
251
  //#endregion
252
+ //#region src/hooks/disable-pagination/disable-pagination.hook.d.ts
253
+ /**
254
+ * Disables pagination when `query.$limit` is `-1` or `'-1'`.
255
+ * Removes the `$limit` from the query and sets `params.paginate = false`.
256
+ * Must be used as a `before` or `around` hook on the `find` method.
257
+ *
258
+ * @example
259
+ * ```ts
260
+ * import { disablePagination } from 'feathers-utils/hooks'
261
+ *
262
+ * app.service('users').hooks({
263
+ * before: { find: [disablePagination()] }
264
+ * })
265
+ * // Then call: app.service('users').find({ query: { $limit: -1 } })
266
+ * ```
267
+ *
268
+ * @see https://utils.feathersjs.com/hooks/disable-pagination.html
269
+ */
270
+ declare const disablePagination: <H extends HookContext = HookContext>() => {
271
+ (context: H): void;
272
+ (context: H, next: NextFunction): Promise<void>;
273
+ };
274
+ //#endregion
275
+ //#region src/hooks/disallow/disallow.hook.d.ts
276
+ /**
277
+ * Prevents access to a service method completely or for specific transports.
278
+ * When called without arguments, the method is blocked for all callers.
279
+ * When called with transport names, only those transports are blocked.
280
+ *
281
+ * @example
282
+ * ```ts
283
+ * import { disallow } from 'feathers-utils/hooks'
284
+ *
285
+ * app.service('users').hooks({
286
+ * before: {
287
+ * remove: [disallow('external')], // block external access
288
+ * update: [disallow()], // block completely
289
+ * }
290
+ * })
291
+ * ```
292
+ *
293
+ * @see https://utils.feathersjs.com/hooks/disallow.html
294
+ */
295
+ declare const disallow: <H extends HookContext = HookContext>(transports?: MaybeArray<TransportName>) => {
296
+ (context: H): void;
297
+ (context: H, next: NextFunction): Promise<void>;
298
+ };
299
+ //#endregion
252
300
  //#region src/hooks/find-or-create/find-or-create.hook.d.ts
253
301
  /**
254
302
  * The valid `uniqueBy` paths for a service's create data. Falls back to a plain
@@ -303,54 +351,6 @@ interface FindOrCreateOptions<H extends HookContext = HookContext, Services exte
303
351
  */
304
352
  declare function findOrCreate<H extends HookContext = HookContext>(options: FindOrCreateOptions<H>): (context: H, next?: NextFunction) => Promise<void>;
305
353
  //#endregion
306
- //#region src/hooks/disable-pagination/disable-pagination.hook.d.ts
307
- /**
308
- * Disables pagination when `query.$limit` is `-1` or `'-1'`.
309
- * Removes the `$limit` from the query and sets `params.paginate = false`.
310
- * Must be used as a `before` or `around` hook on the `find` method.
311
- *
312
- * @example
313
- * ```ts
314
- * import { disablePagination } from 'feathers-utils/hooks'
315
- *
316
- * app.service('users').hooks({
317
- * before: { find: [disablePagination()] }
318
- * })
319
- * // Then call: app.service('users').find({ query: { $limit: -1 } })
320
- * ```
321
- *
322
- * @see https://utils.feathersjs.com/hooks/disable-pagination.html
323
- */
324
- declare const disablePagination: <H extends HookContext = HookContext>() => {
325
- (context: H): void;
326
- (context: H, next: NextFunction): Promise<void>;
327
- };
328
- //#endregion
329
- //#region src/hooks/disallow/disallow.hook.d.ts
330
- /**
331
- * Prevents access to a service method completely or for specific transports.
332
- * When called without arguments, the method is blocked for all callers.
333
- * When called with transport names, only those transports are blocked.
334
- *
335
- * @example
336
- * ```ts
337
- * import { disallow } from 'feathers-utils/hooks'
338
- *
339
- * app.service('users').hooks({
340
- * before: {
341
- * remove: [disallow('external')], // block external access
342
- * update: [disallow()], // block completely
343
- * }
344
- * })
345
- * ```
346
- *
347
- * @see https://utils.feathersjs.com/hooks/disallow.html
348
- */
349
- declare const disallow: <H extends HookContext = HookContext>(transports?: MaybeArray<TransportName>) => {
350
- (context: H): void;
351
- (context: H, next: NextFunction): Promise<void>;
352
- };
353
- //#endregion
354
354
  //#region src/hooks/mute-event/mute-event.hook.d.ts
355
355
  type MuteEventOptions<H extends HookContext = HookContext> = {
356
356
  /**
package/dist/hooks.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { _ as combine, a as iffElse, i as iff, n as skippable, r as unless, t as throwIf } from "./predicates-puYa4nkf.mjs";
2
- import { C as checkMulti, S as checkRequired, _ as disallow, a as softDelete, b as debug, c as setQueryDefaults, d as rateLimit, f as preventChanges, g as muteEvent, h as onDelete, i as stashable, l as setField, m as paramsForServer, n as throwIfIsProvider, o as setSlug, p as paramsFromClient, r as throwIfIsMulti, s as setResult, t as traverse, u as setData, v as disablePagination, w as cache, x as createRelated, y as findOrCreate } from "./hooks-tfw03iVM.mjs";
3
- import { n as transformQuery, r as transformData, t as transformResult } from "./transform-result.hook-B65pTRJO.mjs";
4
- import { i as resolveData, n as resolveQuery, r as resolveResult, t as resolve } from "./resolve-B9hRleHY.mjs";
1
+ import { _ as combine, a as iffElse, i as iff, n as throwIf, r as skippable, t as unless } from "./predicates-CR4O2nSr.mjs";
2
+ import { C as checkMulti, S as checkRequired, _ as findOrCreate, a as softDelete, b as debug, c as setQueryDefaults, d as rateLimit, f as preventChanges, g as muteEvent, h as onDelete, i as stashable, l as setField, m as paramsForServer, n as throwIfIsProvider, o as setSlug, p as paramsFromClient, r as throwIfIsMulti, s as setResult, t as traverse, u as setData, v as disallow, w as cache, x as createRelated, y as disablePagination } from "./hooks-D_u2QFhM.mjs";
3
+ import { n as transformQuery, r as transformData, t as transformResult } from "./transform-result.hook-0D676rcY.mjs";
4
+ import { i as resolveData, n as resolveQuery, r as resolveResult, t as resolve } from "./resolve-BbbdWdlO.mjs";
5
5
  export { cache, checkMulti, checkRequired, combine, createRelated, debug, disablePagination, disallow, findOrCreate, iff, iff as when, iffElse, muteEvent, onDelete, paramsForServer, paramsFromClient, preventChanges, rateLimit, resolve, resolveData, resolveQuery, resolveResult, setData, setField, setQueryDefaults, setResult, setSlug, skippable, softDelete, stashable, throwIf, throwIfIsMulti, throwIfIsProvider, transformData, transformQuery, transformResult, traverse, unless };
@@ -23,45 +23,13 @@ type SkipHookName = 'all' | HookType | `${HookType}:${string}` | (string & {});
23
23
  */
24
24
  declare const addSkip: <H extends HookContext>(context: H, hooks: MaybeArray<SkipHookName>) => void;
25
25
  //#endregion
26
- //#region src/utils/chunk-find/chunk-find.util.d.ts
27
- type PaginateOption$1 = {
28
- default?: number;
29
- max?: number;
30
- };
31
- type ChunkFindOptions<P extends Params = Params> = {
32
- params?: P & {
33
- paginate?: PaginateOption$1;
34
- };
35
- };
36
- /**
37
- * Use `for await` to iterate over chunks (pages) of results from a `find` method.
38
- *
39
- * This function is useful for processing large datasets in batches without loading everything into memory at once.
40
- * It uses pagination to fetch results in chunks, yielding each page's data array.
41
- *
42
- * @example
43
- * ```ts
44
- * import { chunkFind } from 'feathers-utils/utils'
45
- *
46
- * const app = feathers()
47
- *
48
- * // Assuming 'users' service has many records
49
- * for await (const users of chunkFind(app, 'users', {
50
- * params: { query: { active: true }, // Custom query parameters
51
- * } })) {
52
- * console.log(users) // Process each chunk of user records
53
- * }
54
- * ```
55
- *
56
- * @see https://utils.feathersjs.com/utils/chunk-find.html
57
- */
58
- declare function chunkFind<Services, Path extends KeyOf<Services>, Service extends Services[Path] = Services[Path], P extends Params = InferFindParams<Service>, Item = InferFindResultSingle<Service>>(app: Application<Services>, servicePath: Path, options?: ChunkFindOptions<P>): AsyncGenerator<Item[], void, unknown>;
59
- //#endregion
60
26
  //#region src/utils/add-to-query/add-to-query.util.d.ts
61
27
  /**
62
28
  * Safely merges properties into a Feathers query object. If a property already exists
63
29
  * with a different value, it wraps both in a `$and` array to preserve both conditions.
64
- * If the exact same key-value pair already exists, no changes are made.
30
+ * If the exact same key-value pair already exists, no changes are made. When the added
31
+ * query is itself a pure `$and` (`{ $and: [...] }`), its branches are flattened into the
32
+ * target's `$and` rather than nested.
65
33
  *
66
34
  * @example
67
35
  * ```ts
@@ -143,6 +111,40 @@ declare function checkContext<H extends HookContext, const T extends HookType$1
143
111
  method: M;
144
112
  }>;
145
113
  //#endregion
114
+ //#region src/utils/chunk-find/chunk-find.util.d.ts
115
+ type PaginateOption$1 = {
116
+ default?: number;
117
+ max?: number;
118
+ };
119
+ type ChunkFindOptions<P extends Params = Params> = {
120
+ params?: P & {
121
+ paginate?: PaginateOption$1;
122
+ };
123
+ };
124
+ /**
125
+ * Use `for await` to iterate over chunks (pages) of results from a `find` method.
126
+ *
127
+ * This function is useful for processing large datasets in batches without loading everything into memory at once.
128
+ * It uses pagination to fetch results in chunks, yielding each page's data array.
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * import { chunkFind } from 'feathers-utils/utils'
133
+ *
134
+ * const app = feathers()
135
+ *
136
+ * // Assuming 'users' service has many records
137
+ * for await (const users of chunkFind(app, 'users', {
138
+ * params: { query: { active: true }, // Custom query parameters
139
+ * } })) {
140
+ * console.log(users) // Process each chunk of user records
141
+ * }
142
+ * ```
143
+ *
144
+ * @see https://utils.feathersjs.com/utils/chunk-find.html
145
+ */
146
+ declare function chunkFind<Services, Path extends KeyOf<Services>, Service extends Services[Path] = Services[Path], P extends Params = InferFindParams<Service>, Item = InferFindResultSingle<Service>>(app: Application<Services>, servicePath: Path, options?: ChunkFindOptions<P>): AsyncGenerator<Item[], void, unknown>;
147
+ //#endregion
146
148
  //#region src/utils/context-to-json/context-to-json.util.d.ts
147
149
  /**
148
150
  * Converts a FeathersJS HookContext to a plain JSON object by calling `toJSON()` if available.
@@ -308,6 +310,61 @@ type IterateFindOptions<P extends Params = Params> = {
308
310
  */
309
311
  declare function iterateFind<Services, Path extends KeyOf<Services>, Service extends Services[Path] = Services[Path], P extends Params = InferFindParams<Service>, Item = InferFindResultSingle<Service>>(app: Application<Services>, servicePath: Path, options?: IterateFindOptions<P>): AsyncGenerator<Item, void, unknown>;
310
312
  //#endregion
313
+ //#region src/utils/merge-query/merge-query.util.d.ts
314
+ type MergeQueryMode = 'target' | 'source' | 'combine' | 'intersect';
315
+ interface MergeQueryOptions {
316
+ /**
317
+ * How to merge query properties that both queries constrain.
318
+ *
319
+ * - `combine` (default): broaden — the two queries always become branches of an `$or`.
320
+ * - `intersect`: narrow — non-conflicting properties merge flat, conflicts become an `$and`.
321
+ * - `target`: keep the target's value on conflict.
322
+ * - `source`: keep the source's value on conflict.
323
+ */
324
+ mode?: MergeQueryMode;
325
+ }
326
+ /**
327
+ * Properties are combined with a logical operator rather than merged at the value
328
+ * level, so the result is always a valid query: `combine` always wraps the two
329
+ * queries in `$or` (broaden — OR has no flat form), while `intersect` merges
330
+ * non-conflicting properties flat and wraps conflicts in `$and` (narrow). The
331
+ * special filters `$select`, `$limit`, `$skip` and `$sort` are merged separately.
332
+ * Inputs are never mutated.
333
+ *
334
+ * This is well suited to merging a client-provided query with a server-side
335
+ * restriction inside a hook.
336
+ *
337
+ * @param target Query to be merged into
338
+ * @param source Query to be merged from
339
+ * @param options
340
+ * @returns the merged query
341
+ *
342
+ * @example
343
+ * ```ts
344
+ * import { mergeQuery } from 'feathers-utils/utils'
345
+ *
346
+ * // combine (default): the two queries always become an $or
347
+ * mergeQuery({ id: 1 }, { id: 2 })
348
+ * // => { $or: [{ id: 1 }, { id: 2 }] }
349
+ *
350
+ * mergeQuery({ status: 'active' }, { authorId: 5 })
351
+ * // => { $or: [{ status: 'active' }, { authorId: 5 }] }
352
+ * ```
353
+ *
354
+ * @example
355
+ * ```ts
356
+ * // intersect: non-conflicting properties merge flat, conflicts become an $and
357
+ * mergeQuery({ status: 'active' }, { authorId: 5 }, { mode: 'intersect' })
358
+ * // => { status: 'active', authorId: 5 }
359
+ *
360
+ * mergeQuery({ id: 1 }, { id: 2 }, { mode: 'intersect' })
361
+ * // => { $and: [{ id: 1 }, { id: 2 }] }
362
+ * ```
363
+ *
364
+ * @see https://utils.feathersjs.com/utils/merge-query.html
365
+ */
366
+ declare function mergeQuery(target: Query, source: Query, options?: MergeQueryOptions): Query;
367
+ //#endregion
311
368
  //#region src/utils/patch-batch/patch-batch.util.d.ts
312
369
  type PatchBatchOptions<IdKey extends string> = {
313
370
  /** the key of the id property */id?: IdKey;
@@ -340,6 +397,48 @@ type PatchBatchResultItem<T = Record<string, unknown>, P = Params> = [Id | null,
340
397
  */
341
398
  declare function patchBatch<T extends Record<string, any>, IdKey extends KeyOf<T>, P extends Params, R extends Omit<T, IdKey> = Omit<T, IdKey>>(items: T[], options?: PatchBatchOptions<IdKey>): PatchBatchResultItem<R, P>[];
342
399
  //#endregion
400
+ //#region src/utils/query-defaults/query-defaults.util.d.ts
401
+ /**
402
+ * Adds default properties to a Feathers query — but only for fields the query does
403
+ * not already constrain. Presence is checked with {@link queryHasProperty}, so a field
404
+ * referenced anywhere (including nested in `$and`/`$or`/`$nor`) is left untouched and
405
+ * the caller keeps control over it. The query is treated as the `data` equivalent of
406
+ * the `defaults` transformer. Each default is applied independently (per-field).
407
+ *
408
+ * @example
409
+ * ```ts
410
+ * import { queryDefaults } from 'feathers-utils/utils'
411
+ *
412
+ * queryDefaults({ status: 'active' }, { isTemplate: false })
413
+ * // => { status: 'active', isTemplate: false }
414
+ *
415
+ * queryDefaults({ $or: [{ isTemplate: true }] }, { isTemplate: false })
416
+ * // => { $or: [{ isTemplate: true }] } (untouched — already referenced)
417
+ * ```
418
+ *
419
+ * @see https://utils.feathersjs.com/utils/query-defaults.html
420
+ */
421
+ declare const queryDefaults: (query: Query | undefined, defaults: Query) => Query;
422
+ //#endregion
423
+ //#region src/utils/query-has-property/query-has-property.util.d.ts
424
+ /**
425
+ * Checks whether a Feathers query contains one or more properties — including
426
+ * properties nested inside `$and`/`$or`/`$nor` arrays. Returns `true` as soon as
427
+ * any of the given property names is found. The query is not mutated.
428
+ *
429
+ * @example
430
+ * ```ts
431
+ * import { queryHasProperty } from 'feathers-utils/utils'
432
+ *
433
+ * queryHasProperty({ isTemplate: true }, 'isTemplate') // true
434
+ * queryHasProperty({ $or: [{ isTemplate: true }] }, 'isTemplate') // true
435
+ * queryHasProperty({ age: { $gt: 18 } }, ['isTemplate', 'status']) // false
436
+ * ```
437
+ *
438
+ * @see https://utils.feathersjs.com/utils/query-has-property.html
439
+ */
440
+ declare const queryHasProperty: (query: Query, property: MaybeArray<string>) => boolean;
441
+ //#endregion
343
442
  //#region src/utils/replace-data/replace-data.util.d.ts
344
443
  /**
345
444
  * Replaces `context.data` wholesale with the given items, preserving the original
@@ -385,6 +484,53 @@ type ReplaceResultOptions = {
385
484
  */
386
485
  declare function replaceResult<H extends HookContext = HookContext>(context: H, result: ResultSingleHookContext<H>[], options?: ReplaceResultOptions): H;
387
486
  //#endregion
487
+ //#region src/utils/simplify-query/simplify-query.util.d.ts
488
+ interface SimplifyQueryOptions {
489
+ /**
490
+ * Dissolve a top-level single-branch `$and` by merging its branch up into the
491
+ * query (only when no key would collide). Nested levels are always dissolved.
492
+ * Default `true`.
493
+ */
494
+ replaceAnd?: boolean;
495
+ /**
496
+ * Dissolve a top-level single-branch `$or` by merging its branch up into the
497
+ * query (only when no key would collide). Nested levels are always dissolved.
498
+ * Default `true`.
499
+ */
500
+ replaceOr?: boolean;
501
+ }
502
+ /**
503
+ * Normalizes the logical structure of a Feathers query without changing what it
504
+ * matches: empty `$and`/`$or` are dropped, duplicate branches removed, nested
505
+ * same-operator branches hoisted (`$and`-in-`$and`, pure `$or`-in-`$or`), and
506
+ * branches merged up into the parent where it is safe — all of an `$and` when no
507
+ * key collides, a single-branch `$or`. Runs recursively. Inputs are not mutated;
508
+ * a query with nothing to simplify is returned unchanged.
509
+ *
510
+ * @param query the query to simplify (a falsy query is returned as-is)
511
+ * @param options
512
+ * @returns the simplified query
513
+ *
514
+ * @example
515
+ * ```ts
516
+ * import { simplifyQuery } from 'feathers-utils/utils'
517
+ *
518
+ * // non-colliding $and branches (here also a hoisted nested $and) merge up
519
+ * simplifyQuery({ $and: [{ id: 1 }, { $and: [{ status: 'a' }] }] })
520
+ * // => { id: 1, status: 'a' }
521
+ *
522
+ * simplifyQuery({ $or: [{ id: 1 }] })
523
+ * // => { id: 1 }
524
+ *
525
+ * // a colliding key keeps the $and intact
526
+ * simplifyQuery({ $and: [{ price: { $gt: 1 } }, { price: { $lt: 9 } }] })
527
+ * // => { $and: [{ price: { $gt: 1 } }, { price: { $lt: 9 } }] }
528
+ * ```
529
+ *
530
+ * @see https://utils.feathersjs.com/utils/simplify-query.html
531
+ */
532
+ declare function simplifyQuery<Q extends Query | null | undefined>(query: Q, options?: SimplifyQueryOptions): Q;
533
+ //#endregion
388
534
  //#region src/utils/skip-result/skip-result.util.d.ts
389
535
  /**
390
536
  * Sets `context.result` to an appropriate empty value based on the hook method.
@@ -403,6 +549,32 @@ declare function replaceResult<H extends HookContext = HookContext>(context: H,
403
549
  */
404
550
  declare const skipResult: <H extends HookContext = HookContext>(context: H) => H;
405
551
  //#endregion
552
+ //#region src/utils/sort-query-properties/sort-query-properties.util.d.ts
553
+ /**
554
+ * Recursively normalizes a Feathers query object for order-independent comparison.
555
+ * Sorts object keys and sorts arrays within `$or`, `$and`, `$nor`, `$not`, `$in`,
556
+ * and `$nin` operators so that different orderings produce the same result.
557
+ *
558
+ * This is useful for generating stable cache keys where
559
+ * `{ $or: [{ a: 1 }, { b: 2 }] }` and `{ $or: [{ b: 2 }, { a: 1 }] }`
560
+ * should be treated as equivalent.
561
+ *
562
+ * @example
563
+ * ```ts
564
+ * import { sortQueryProperties } from 'feathers-utils/utils'
565
+ *
566
+ * const normalized = sortQueryProperties({
567
+ * $or: [{ name: 'Jane' }, { name: 'John' }],
568
+ * age: { $in: [30, 25] },
569
+ * })
570
+ * // => { $or: [{ name: 'John' }, { name: 'Jane' }], age: { $in: [25, 30] } }
571
+ * // (sorted by stable stringify comparison)
572
+ * ```
573
+ *
574
+ * @see https://utils.feathersjs.com/utils/sort-query-properties.html
575
+ */
576
+ declare const sortQueryProperties: <Q extends Query>(query: Q) => Q;
577
+ //#endregion
406
578
  //#region src/utils/to-paginated/to-paginated.util.d.ts
407
579
  /**
408
580
  * Ensures a result is in Feathers paginated format (`{ total, limit, skip, data }`).
@@ -438,32 +610,6 @@ declare function toPaginated<R>(result: R[] | Paginated<R>): Paginated<R>;
438
610
  */
439
611
  declare const transformParams: <P extends Params = Params>(params: P, fn: TransformParamsFn<P> | undefined) => P;
440
612
  //#endregion
441
- //#region src/utils/sort-query-properties/sort-query-properties.util.d.ts
442
- /**
443
- * Recursively normalizes a Feathers query object for order-independent comparison.
444
- * Sorts object keys and sorts arrays within `$or`, `$and`, `$nor`, `$not`, `$in`,
445
- * and `$nin` operators so that different orderings produce the same result.
446
- *
447
- * This is useful for generating stable cache keys where
448
- * `{ $or: [{ a: 1 }, { b: 2 }] }` and `{ $or: [{ b: 2 }, { a: 1 }] }`
449
- * should be treated as equivalent.
450
- *
451
- * @example
452
- * ```ts
453
- * import { sortQueryProperties } from 'feathers-utils/utils'
454
- *
455
- * const normalized = sortQueryProperties({
456
- * $or: [{ name: 'Jane' }, { name: 'John' }],
457
- * age: { $in: [30, 25] },
458
- * })
459
- * // => { $or: [{ name: 'John' }, { name: 'Jane' }], age: { $in: [25, 30] } }
460
- * // (sorted by stable stringify comparison)
461
- * ```
462
- *
463
- * @see https://utils.feathersjs.com/utils/sort-query-properties.html
464
- */
465
- declare const sortQueryProperties: <Q extends Query>(query: Q) => Q;
466
- //#endregion
467
613
  //#region src/utils/wait-for-service-event/wait-for-service-event.util.d.ts
468
614
  /**
469
615
  * The standard Feathers service events, plus any custom event name a service
@@ -578,48 +724,6 @@ type WalkQueryCallback = (options: WalkQueryOptions) => any;
578
724
  */
579
725
  declare const walkQuery: <Q extends Query>(query: Q, walker: WalkQueryCallback) => Q;
580
726
  //#endregion
581
- //#region src/utils/query-has-property/query-has-property.util.d.ts
582
- /**
583
- * Checks whether a Feathers query contains one or more properties — including
584
- * properties nested inside `$and`/`$or`/`$nor` arrays. Returns `true` as soon as
585
- * any of the given property names is found. The query is not mutated.
586
- *
587
- * @example
588
- * ```ts
589
- * import { queryHasProperty } from 'feathers-utils/utils'
590
- *
591
- * queryHasProperty({ isTemplate: true }, 'isTemplate') // true
592
- * queryHasProperty({ $or: [{ isTemplate: true }] }, 'isTemplate') // true
593
- * queryHasProperty({ age: { $gt: 18 } }, ['isTemplate', 'status']) // false
594
- * ```
595
- *
596
- * @see https://utils.feathersjs.com/utils/query-has-property.html
597
- */
598
- declare const queryHasProperty: (query: Query, property: MaybeArray<string>) => boolean;
599
- //#endregion
600
- //#region src/utils/query-defaults/query-defaults.util.d.ts
601
- /**
602
- * Adds default properties to a Feathers query — but only for fields the query does
603
- * not already constrain. Presence is checked with {@link queryHasProperty}, so a field
604
- * referenced anywhere (including nested in `$and`/`$or`/`$nor`) is left untouched and
605
- * the caller keeps control over it. The query is treated as the `data` equivalent of
606
- * the `defaults` transformer. Each default is applied independently (per-field).
607
- *
608
- * @example
609
- * ```ts
610
- * import { queryDefaults } from 'feathers-utils/utils'
611
- *
612
- * queryDefaults({ status: 'active' }, { isTemplate: false })
613
- * // => { status: 'active', isTemplate: false }
614
- *
615
- * queryDefaults({ $or: [{ isTemplate: true }] }, { isTemplate: false })
616
- * // => { $or: [{ isTemplate: true }] } (untouched — already referenced)
617
- * ```
618
- *
619
- * @see https://utils.feathersjs.com/utils/query-defaults.html
620
- */
621
- declare const queryDefaults: (query: Query | undefined, defaults: Query) => Query;
622
- //#endregion
623
727
  //#region src/utils/zip-data-result/zip-data-result.util.d.ts
624
728
  type ZipDataResultOptions = {
625
729
  onMismatch?: (context: HookContext) => void;
@@ -645,5 +749,5 @@ type ZipDataResultItem<D, R> = {
645
749
  */
646
750
  declare function zipDataResult<H extends HookContext, D extends DataSingleHookContext<H> = DataSingleHookContext<H>, R extends ResultSingleHookContext<H> = ResultSingleHookContext<H>>(context: H, options?: ZipDataResultOptions): ZipDataResultItem<D, R>[];
647
751
  //#endregion
648
- export { GetDataIsArrayReturn as A, SkipHookName as B, patchBatch as C, getResultIsArray as D, GetResultIsArrayReturn as E, checkContext as F, IsContextOptions as I, isContext as L, defineHooks as M, contextToJson as N, getPaginate as O, CheckContextOptions as P, addToQuery as R, PatchBatchResultItem as S, GetResultIsArrayOptions as T, addSkip as V, skipResult as _, queryHasProperty as a, replaceData as b, walkQuery as c, WaitForServiceEventOptions as d, WaitForServiceEventResult as f, toPaginated as g, transformParams as h, queryDefaults as i, getDataIsArray as j, getExposedMethods as k, ServiceEventName as l, sortQueryProperties as m, ZipDataResultOptions as n, WalkQueryCallback as o, waitForServiceEvent as p, zipDataResult as r, WalkQueryOptions as s, ZipDataResultItem as t, WaitForServiceEventDefaults as u, ReplaceResultOptions as v, iterateFind as w, PatchBatchOptions as x, replaceResult as y, chunkFind as z };
649
- //# sourceMappingURL=index-CKAzIogj.d.mts.map
752
+ export { GetResultIsArrayOptions as A, CheckContextOptions as B, PatchBatchOptions as C, MergeQueryOptions as D, MergeQueryMode as E, GetDataIsArrayReturn as F, SkipHookName as G, IsContextOptions as H, getDataIsArray as I, addSkip as K, defineHooks as L, getResultIsArray as M, getPaginate as N, mergeQuery as O, getExposedMethods as P, contextToJson as R, queryDefaults as S, patchBatch as T, isContext as U, checkContext as V, addToQuery as W, simplifyQuery as _, WalkQueryOptions as a, replaceData as b, WaitForServiceEventDefaults as c, waitForServiceEvent as d, transformParams as f, SimplifyQueryOptions as g, skipResult as h, WalkQueryCallback as i, GetResultIsArrayReturn as j, iterateFind as k, WaitForServiceEventOptions as l, sortQueryProperties as m, ZipDataResultOptions as n, walkQuery as o, toPaginated as p, zipDataResult as r, ServiceEventName as s, ZipDataResultItem as t, WaitForServiceEventResult as u, ReplaceResultOptions as v, PatchBatchResultItem as w, queryHasProperty as x, replaceResult as y, chunkFind as z };
753
+ //# sourceMappingURL=index-H1zXVhff.d.mts.map
package/dist/index.d.mts CHANGED
@@ -4,7 +4,7 @@ import { a as IffHook, i as skippable, n as ThrowIfOptions, o as iff, r as throw
4
4
  import { i as transformData, n as transformResult, r as transformQuery, t as TransformResultOptions } from "./transform-result.hook-C9wMLWs2.mjs";
5
5
  import { i as resolveData, n as resolveQuery, r as resolveResult, t as resolve } from "./resolve-Cmxskunj.mjs";
6
6
  import { CacheEvent, CacheOptions, CheckMultiOptions, CreateRelatedOptions, FindOrCreateOptions, HookSetDataOptions, MuteEventOptions, OnDeleteAction, OnDeleteOptions, ParamsForServerOptions, PreventChangesOptions, RateLimitOptions, SetFieldOptions, SetResultOptions, SoftDeleteOptionFunction, SoftDeleteOptions, StashableOptions, ThrowIfIsIsProviderOptions, ThrowIfIsMultiOptions, TraverseOptions, cache, checkMulti, checkRequired, combine, createRelated, debug, disablePagination, disallow, findOrCreate, muteEvent, onDelete, paramsForServer, paramsFromClient, paramsFromClientOptions, preventChanges, rateLimit, setData, setField, setQueryDefaults, setResult, setSlug, softDelete, stashable, throwIfIsMulti, throwIfIsProvider, traverse } from "./hooks.mjs";
7
- import { A as GetDataIsArrayReturn, B as SkipHookName, C as patchBatch, D as getResultIsArray, E as GetResultIsArrayReturn, F as checkContext, M as defineHooks, N as contextToJson, O as getPaginate, P as CheckContextOptions, R as addToQuery, S as PatchBatchResultItem, T as GetResultIsArrayOptions, V as addSkip, _ as skipResult, a as queryHasProperty, b as replaceData, c as walkQuery, d as WaitForServiceEventOptions, f as WaitForServiceEventResult, g as toPaginated, h as transformParams, i as queryDefaults, j as getDataIsArray, k as getExposedMethods, l as ServiceEventName, m as sortQueryProperties, n as ZipDataResultOptions, o as WalkQueryCallback, p as waitForServiceEvent, r as zipDataResult, s as WalkQueryOptions, t as ZipDataResultItem, u as WaitForServiceEventDefaults, v as ReplaceResultOptions, w as iterateFind, x as PatchBatchOptions, y as replaceResult, z as chunkFind } from "./index-CKAzIogj.mjs";
7
+ import { A as GetResultIsArrayOptions, B as CheckContextOptions, C as PatchBatchOptions, D as MergeQueryOptions, E as MergeQueryMode, F as GetDataIsArrayReturn, G as SkipHookName, I as getDataIsArray, K as addSkip, L as defineHooks, M as getResultIsArray, N as getPaginate, O as mergeQuery, P as getExposedMethods, R as contextToJson, S as queryDefaults, T as patchBatch, V as checkContext, W as addToQuery, _ as simplifyQuery, a as WalkQueryOptions, b as replaceData, c as WaitForServiceEventDefaults, d as waitForServiceEvent, f as transformParams, g as SimplifyQueryOptions, h as skipResult, i as WalkQueryCallback, j as GetResultIsArrayReturn, k as iterateFind, l as WaitForServiceEventOptions, m as sortQueryProperties, n as ZipDataResultOptions, o as walkQuery, p as toPaginated, r as zipDataResult, s as ServiceEventName, t as ZipDataResultItem, u as WaitForServiceEventResult, v as ReplaceResultOptions, w as PatchBatchResultItem, x as queryHasProperty, y as replaceResult, z as chunkFind } from "./index-H1zXVhff.mjs";
8
8
  import { n as mutateResult, r as mutateData, t as MutateResultOptions } from "./mutate-result.util-DR9JMsvl.mjs";
9
9
  import { Paginated, PaginationOptions } from "@feathersjs/feathers";
10
10
 
@@ -15,5 +15,5 @@ type PaginatedOrArray<R, P = undefined> = P extends {
15
15
  paginate: PaginationOptions;
16
16
  } ? Paginated<R> : Paginated<R> | R[];
17
17
  //#endregion
18
- export { CacheEvent, CacheOptions, CheckContextOptions, CheckMultiOptions, ContextFunction, ContextFunctionAsync, ContextFunctionSync, CreateRelatedOptions, DataSingleHookContext, DefaultsInput, DispatchOption, FieldKey, FindOrCreateOptions, GetDataIsArrayReturn, GetResultIsArrayOptions, GetResultIsArrayReturn, GetService, HookFunction, HookSetDataOptions, HookType, IffHook, InferCreateData, InferCreateDataFromPath, InferCreateDataSingle, InferCreateDataSingleFromPath, InferCreateResult, InferCreateResultFromPath, InferCreateResultSingle, InferCreateResultSingleFromPath, InferDataFromPath, InferFindParams, InferFindResult, InferFindResultFromPath, InferFindResultSingle, InferGetResult, InferGetResultFromPath, InferPatchData, InferPatchDataFromPath, InferPatchResult, InferPatchResultFromPath, InferRemoveResult, InferRemoveResultFromPath, InferResultFromPath, InferUpdateData, InferUpdateDataFromPath, InferUpdateResult, InferUpdateResultFromPath, MethodName, MutateResultOptions, MuteEventOptions, OnDeleteAction, OnDeleteOptions, PaginatedOrArray, ParamsForServerOptions, PatchBatchOptions, PatchBatchResultItem, PredicateContextAsync, PredicateContextSync, PredicateFn, PredicateItemWithContext, PreventChangesOptions, RateLimitOptions, ReplaceResultOptions, ResultSingleHookContext, ServiceEventName, SetFieldOptions, SetResultOptions, SkipHookName, SoftDeleteOptionFunction, SoftDeleteOptions, StashableOptions, StringFieldKey, ThrowIfIsIsProviderOptions, ThrowIfIsMultiOptions, ThrowIfOptions, TransformParamsFn, TransformResultOptions, TransformerFn, TransformerInputFn, TransportName, TraverseOptions, UnwrapPaginated, UnwrapPaginatedOrArray, WaitForServiceEventDefaults, WaitForServiceEventOptions, WaitForServiceEventResult, WalkQueryCallback, WalkQueryOptions, ZipDataResultItem, ZipDataResultOptions, addSkip, addToQuery, cache, checkContext, checkMulti, checkRequired, chunkFind, combine, contextToJson, createRelated, debug, defineHooks, disablePagination, disallow, findOrCreate, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, hookTypes, iff, iff as when, iffElse, iterateFind, methodNames, mutateData, mutateResult, muteEvent, onDelete, paramsForServer, paramsFromClient, paramsFromClientOptions, patchBatch, preventChanges, queryDefaults, queryHasProperty, rateLimit, replaceData, replaceResult, resolve, resolveData, resolveQuery, resolveResult, setData, setField, setQueryDefaults, setResult, setSlug, skipResult, skippable, softDelete, sortQueryProperties, stashable, throwIf, throwIfIsMulti, throwIfIsProvider, toPaginated, transformData, transformParams, transformQuery, transformResult, traverse, unless, waitForServiceEvent, walkQuery, zipDataResult };
18
+ export { CacheEvent, CacheOptions, CheckContextOptions, CheckMultiOptions, ContextFunction, ContextFunctionAsync, ContextFunctionSync, CreateRelatedOptions, DataSingleHookContext, DefaultsInput, DispatchOption, FieldKey, FindOrCreateOptions, GetDataIsArrayReturn, GetResultIsArrayOptions, GetResultIsArrayReturn, GetService, HookFunction, HookSetDataOptions, HookType, IffHook, InferCreateData, InferCreateDataFromPath, InferCreateDataSingle, InferCreateDataSingleFromPath, InferCreateResult, InferCreateResultFromPath, InferCreateResultSingle, InferCreateResultSingleFromPath, InferDataFromPath, InferFindParams, InferFindResult, InferFindResultFromPath, InferFindResultSingle, InferGetResult, InferGetResultFromPath, InferPatchData, InferPatchDataFromPath, InferPatchResult, InferPatchResultFromPath, InferRemoveResult, InferRemoveResultFromPath, InferResultFromPath, InferUpdateData, InferUpdateDataFromPath, InferUpdateResult, InferUpdateResultFromPath, MergeQueryMode, MergeQueryOptions, MethodName, MutateResultOptions, MuteEventOptions, OnDeleteAction, OnDeleteOptions, PaginatedOrArray, ParamsForServerOptions, PatchBatchOptions, PatchBatchResultItem, PredicateContextAsync, PredicateContextSync, PredicateFn, PredicateItemWithContext, PreventChangesOptions, RateLimitOptions, ReplaceResultOptions, ResultSingleHookContext, ServiceEventName, SetFieldOptions, SetResultOptions, SimplifyQueryOptions, SkipHookName, SoftDeleteOptionFunction, SoftDeleteOptions, StashableOptions, StringFieldKey, ThrowIfIsIsProviderOptions, ThrowIfIsMultiOptions, ThrowIfOptions, TransformParamsFn, TransformResultOptions, TransformerFn, TransformerInputFn, TransportName, TraverseOptions, UnwrapPaginated, UnwrapPaginatedOrArray, WaitForServiceEventDefaults, WaitForServiceEventOptions, WaitForServiceEventResult, WalkQueryCallback, WalkQueryOptions, ZipDataResultItem, ZipDataResultOptions, addSkip, addToQuery, cache, checkContext, checkMulti, checkRequired, chunkFind, combine, contextToJson, createRelated, debug, defineHooks, disablePagination, disallow, findOrCreate, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, hookTypes, iff, iff as when, iffElse, iterateFind, mergeQuery, methodNames, mutateData, mutateResult, muteEvent, onDelete, paramsForServer, paramsFromClient, paramsFromClientOptions, patchBatch, preventChanges, queryDefaults, queryHasProperty, rateLimit, replaceData, replaceResult, resolve, resolveData, resolveQuery, resolveResult, setData, setField, setQueryDefaults, setResult, setSlug, simplifyQuery, skipResult, skippable, softDelete, sortQueryProperties, stashable, throwIf, throwIfIsMulti, throwIfIsProvider, toPaginated, transformData, transformParams, transformQuery, transformResult, traverse, unless, waitForServiceEvent, walkQuery, zipDataResult };
19
19
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { _ as combine, a as iffElse, f as getPaginate, i as iff, n as skippable, r as unless, t as throwIf } from "./predicates-puYa4nkf.mjs";
2
- import { _ as addSkip, a as waitForServiceEvent, c as skipResult, d as getExposedMethods, f as defineHooks, g as chunkFind, h as addToQuery, i as walkQuery, l as patchBatch, m as checkContext, n as queryDefaults, o as transformParams, p as contextToJson, r as queryHasProperty, s as toPaginated, t as zipDataResult, u as iterateFind, v as sortQueryProperties } from "./utils-BAIcSl7u.mjs";
3
- import { C as checkMulti, S as checkRequired, _ as disallow, a as softDelete, b as debug, c as setQueryDefaults, d as rateLimit, f as preventChanges, g as muteEvent, h as onDelete, i as stashable, l as setField, m as paramsForServer, n as throwIfIsProvider, o as setSlug, p as paramsFromClient, r as throwIfIsMulti, s as setResult, t as traverse, u as setData, v as disablePagination, w as cache, x as createRelated, y as findOrCreate } from "./hooks-tfw03iVM.mjs";
4
- import { a as getResultIsArray, i as replaceData, n as replaceResult, o as getDataIsArray, r as mutateData, t as mutateResult } from "./mutate-result.util-Dqzepn1M.mjs";
5
- import { n as transformQuery, r as transformData, t as transformResult } from "./transform-result.hook-B65pTRJO.mjs";
6
- import { i as resolveData, n as resolveQuery, r as resolveResult, t as resolve } from "./resolve-B9hRleHY.mjs";
1
+ import { _ as combine, a as iffElse, f as getPaginate, i as iff, n as throwIf, r as skippable, t as unless } from "./predicates-CR4O2nSr.mjs";
2
+ import { _ as checkContext, a as skipResult, b as sortQueryProperties, c as walkQuery, d as simplifyQuery, f as iterateFind, g as chunkFind, h as contextToJson, i as toPaginated, l as patchBatch, m as defineHooks, n as waitForServiceEvent, o as queryDefaults, p as getExposedMethods, r as transformParams, s as queryHasProperty, t as zipDataResult, u as mergeQuery, v as addToQuery, y as addSkip } from "./utils-sTvj8-Jy.mjs";
3
+ import { C as checkMulti, S as checkRequired, _ as findOrCreate, a as softDelete, b as debug, c as setQueryDefaults, d as rateLimit, f as preventChanges, g as muteEvent, h as onDelete, i as stashable, l as setField, m as paramsForServer, n as throwIfIsProvider, o as setSlug, p as paramsFromClient, r as throwIfIsMulti, s as setResult, t as traverse, u as setData, v as disallow, w as cache, x as createRelated, y as disablePagination } from "./hooks-D_u2QFhM.mjs";
4
+ import { a as getResultIsArray, i as replaceData, n as replaceResult, o as getDataIsArray, r as mutateData, t as mutateResult } from "./mutate-result.util-mxvMl6bw.mjs";
5
+ import { n as transformQuery, r as transformData, t as transformResult } from "./transform-result.hook-0D676rcY.mjs";
6
+ import { i as resolveData, n as resolveQuery, r as resolveResult, t as resolve } from "./resolve-BbbdWdlO.mjs";
7
7
  //#region src/types.ts
8
8
  const hookTypes = [
9
9
  "around",
@@ -20,6 +20,6 @@ const methodNames = [
20
20
  "remove"
21
21
  ];
22
22
  //#endregion
23
- export { addSkip, addToQuery, cache, checkContext, checkMulti, checkRequired, chunkFind, combine, contextToJson, createRelated, debug, defineHooks, disablePagination, disallow, findOrCreate, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, hookTypes, iff, iff as when, iffElse, iterateFind, methodNames, mutateData, mutateResult, muteEvent, onDelete, paramsForServer, paramsFromClient, patchBatch, preventChanges, queryDefaults, queryHasProperty, rateLimit, replaceData, replaceResult, resolve, resolveData, resolveQuery, resolveResult, setData, setField, setQueryDefaults, setResult, setSlug, skipResult, skippable, softDelete, sortQueryProperties, stashable, throwIf, throwIfIsMulti, throwIfIsProvider, toPaginated, transformData, transformParams, transformQuery, transformResult, traverse, unless, waitForServiceEvent, walkQuery, zipDataResult };
23
+ export { addSkip, addToQuery, cache, checkContext, checkMulti, checkRequired, chunkFind, combine, contextToJson, createRelated, debug, defineHooks, disablePagination, disallow, findOrCreate, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, hookTypes, iff, iff as when, iffElse, iterateFind, mergeQuery, methodNames, mutateData, mutateResult, muteEvent, onDelete, paramsForServer, paramsFromClient, patchBatch, preventChanges, queryDefaults, queryHasProperty, rateLimit, replaceData, replaceResult, resolve, resolveData, resolveQuery, resolveResult, setData, setField, setQueryDefaults, setResult, setSlug, simplifyQuery, skipResult, skippable, softDelete, sortQueryProperties, stashable, throwIf, throwIfIsMulti, throwIfIsProvider, toPaginated, transformData, transformParams, transformQuery, transformResult, traverse, unless, waitForServiceEvent, walkQuery, zipDataResult };
24
24
 
25
25
  //# sourceMappingURL=index.mjs.map