{"version":3,"file":"utils-DByCpAsf.mjs","names":["deepEqual","deepEqual","deepEqual"],"sources":["../src/utils/sort-query-properties/sort-query-properties.util.ts","../src/utils/add-skip/add-skip.util.ts","../src/utils/add-to-query/add-to-query.util.ts","../src/utils/check-context/check-context.util.ts","../src/utils/chunk-find/chunk-find.util.ts","../src/utils/context-to-json/context-to-json.util.ts","../src/utils/define-hooks/define-hooks.util.ts","../src/feathers-cjs-fix.ts","../src/utils/get-exposed-methods/get-exposed-methods.util.ts","../src/utils/iterate-find/iterate-find.util.ts","../src/utils/merge-query/extract-query-filters.ts","../src/utils/merge-query/logical-branches.ts","../src/utils/merge-query/dedupe-branches.ts","../src/utils/merge-query/has-conflict.ts","../src/utils/merge-query/merge-query-bodies.ts","../src/utils/merge-query/merge-select.ts","../src/utils/merge-query/merge-query.util.ts","../src/utils/patch-batch/patch-batch.util.ts","../src/utils/walk-query/walk-query.util.ts","../src/utils/query-has-property/query-has-property.util.ts","../src/utils/query-defaults/query-defaults.util.ts","../src/utils/skip-result/skip-result.util.ts","../src/utils/to-paginated/to-paginated.util.ts","../src/utils/transform-params/transform-params.util.ts","../src/utils/wait-for-service-event/wait-for-service-event.util.ts","../src/utils/zip-data-result/zip-data-result.util.ts"],"sourcesContent":["import type { Query } from '@feathersjs/feathers'\n\nconst arrayOperators = new Set(['$or', '$and', '$nor', '$not', '$in', '$nin'])\n\nconst isPlainObjectLike = (value: unknown): value is Record<string, any> =>\n  value !== null && typeof value === 'object'\n\n/**\n * Recursively normalizes a Feathers query object for order-independent comparison.\n * Sorts object keys and sorts arrays within `$or`, `$and`, `$nor`, `$not`, `$in`,\n * and `$nin` operators so that different orderings produce the same result.\n *\n * This is useful for generating stable cache keys where\n * `{ $or: [{ a: 1 }, { b: 2 }] }` and `{ $or: [{ b: 2 }, { a: 1 }] }`\n * should be treated as equivalent.\n *\n * @example\n * ```ts\n * import { sortQueryProperties } from 'feathers-utils/utils'\n *\n * const normalized = sortQueryProperties({\n *   $or: [{ name: 'Jane' }, { name: 'John' }],\n *   age: { $in: [30, 25] },\n * })\n * // => { $or: [{ name: 'John' }, { name: 'Jane' }], age: { $in: [25, 30] } }\n * // (sorted by stable stringify comparison)\n * ```\n *\n * @see https://utils.feathersjs.com/utils/sort-query-properties.html\n */\nexport const sortQueryProperties = <Q extends Query>(query: Q): Q => {\n  return normalize(query) as Q\n}\n\nconst normalize = (value: any): any => {\n  if (Array.isArray(value)) {\n    return value.map(normalize)\n  }\n\n  if (!isPlainObjectLike(value)) {\n    return value\n  }\n\n  const sorted: Record<string, any> = {}\n\n  for (const key of Object.keys(value).sort()) {\n    const val = value[key]\n\n    if (arrayOperators.has(key) && Array.isArray(val)) {\n      // Schwartzian transform: serialize each normalized element once, sort by\n      // that key, then unwrap. Avoids the O(n log n) repeated JSON.stringify of\n      // the previous comparator (which also returned 1 for equal elements).\n      sorted[key] = val\n        .map((el) => {\n          const normalized = normalize(el)\n          return { k: JSON.stringify(normalized), v: normalized }\n        })\n        .sort((a, b) => (a.k < b.k ? -1 : a.k > b.k ? 1 : 0))\n        .map((entry) => entry.v)\n    } else {\n      sorted[key] = normalize(val)\n    }\n  }\n\n  return sorted\n}\n","import type { HookContext, HookType } from '@feathersjs/feathers'\nimport type { MaybeArray } from '../../internal.utils.js'\n\nexport type SkipHookName =\n  | 'all'\n  | HookType\n  | `${HookType}:${string}`\n  | (string & {})\n\n/**\n * Adds hook names to `context.params.skipHooks` so that `skippable`-wrapped hooks\n * will be bypassed for the current service call. Accepts a single name or an array.\n * Duplicates are automatically removed.\n *\n * @example\n * ```ts\n * import { addSkip } from 'feathers-utils/utils'\n *\n * // Inside a hook or custom code:\n * addSkip(context, 'myHook')\n * addSkip(context, ['hookA', 'hookB'])\n * ```\n *\n * @see https://utils.feathersjs.com/utils/add-skip.html\n */\nexport const addSkip = <H extends HookContext>(\n  context: H,\n  hooks: MaybeArray<SkipHookName>,\n) => {\n  const names = Array.isArray(hooks) ? hooks : [hooks]\n\n  if (context.params.skipHooks === undefined) {\n    context.params = {\n      ...context.params,\n      skipHooks: [...names],\n    }\n  } else {\n    if (!Array.isArray(context.params.skipHooks)) {\n      throw new Error('Invalid skipHooks parameter')\n    }\n\n    context.params = {\n      ...context.params,\n      skipHooks: [...new Set([...context.params.skipHooks, ...names])],\n    }\n  }\n}\n","import type { Query } from '@feathersjs/feathers'\nimport { dequal as deepEqual } from 'dequal'\n\n/**\n * Safely merges properties into a Feathers query object. If a property already exists\n * with a different value, it wraps both in a `$and` array to preserve both conditions.\n * If the exact same key-value pair already exists, no changes are made. When the added\n * query is itself a pure `$and` (`{ $and: [...] }`), its branches are flattened into the\n * target's `$and` rather than nested.\n *\n * @example\n * ```ts\n * import { addToQuery } from 'feathers-utils/utils'\n *\n * const query = { status: 'active' }\n * addToQuery(query, { role: 'admin' })\n * // => { status: 'active', role: 'admin' }\n * ```\n *\n * @see https://utils.feathersjs.com/utils/add-to-query.html\n */\nexport function addToQuery<Q extends Query>(targetQuery: Q, query: Q): Q {\n  targetQuery ??= {} as Q\n\n  if (Object.keys(query).length === 0) {\n    return targetQuery\n  }\n\n  const entries = Object.entries(query) as [keyof Q, any][]\n\n  if (entries.every(([property]) => !(property in targetQuery))) {\n    // if none of the properties exist, merge them directly\n    return {\n      ...targetQuery,\n      ...query,\n    }\n  }\n\n  function isAlreadyInQuery(targetQuery: Q, entries: [keyof Q, any][]) {\n    return entries.every(\n      ([property, value]) =>\n        property in targetQuery && deepEqual(targetQuery[property], value),\n    )\n  }\n\n  if (isAlreadyInQuery(targetQuery, entries)) {\n    // if all properties already exist with the exact same value, do nothing\n    return targetQuery\n  }\n\n  // when the added query is itself a pure `$and`, flatten its branches into the\n  // target's `$and` instead of nesting another `$and` inside it\n  if (entries.length === 1 && Array.isArray(query.$and)) {\n    const existing = (targetQuery.$and as any[]) ?? []\n    const newBranches = (query.$and as any[]).filter(\n      (branch) => !existing.some((q) => deepEqual(q, branch)),\n    )\n    if (newBranches.length === 0) {\n      return targetQuery\n    }\n    return {\n      ...targetQuery,\n      $and: [...existing, ...newBranches],\n    }\n  }\n\n  if (!targetQuery.$and) {\n    return {\n      ...targetQuery,\n      $and: [{ ...query }],\n    }\n  }\n\n  // check if the exact same value already exists in $and\n  if (targetQuery.$and.some((q: any) => isAlreadyInQuery(q, entries))) {\n    return targetQuery\n  }\n\n  return {\n    ...targetQuery,\n    $and: [...targetQuery.$and, { ...query }],\n  }\n}\n","import type { HookContext } from '@feathersjs/feathers'\nimport type { HookType, MethodName } from '../../types.js'\nimport {\n  isContext,\n  type IsContextOptions,\n} from '../../predicates/is-context/is-context.predicate.js'\nimport type { UnpackMaybeArray } from '../../internal.utils.js'\n\ntype NarrowedContext<H extends HookContext, O> = H &\n  (O extends { path: infer P }\n    ? [P] extends [undefined | null]\n      ? unknown\n      : { path: UnpackMaybeArray<P> }\n    : unknown) &\n  (O extends { type: infer T }\n    ? [T] extends [undefined | null]\n      ? unknown\n      : { type: UnpackMaybeArray<T> }\n    : unknown) &\n  (O extends { method: infer M }\n    ? [M] extends [undefined | null]\n      ? unknown\n      : { method: UnpackMaybeArray<M> }\n    : unknown)\n\nexport type CheckContextOptions<H extends HookContext = HookContext> =\n  IsContextOptions<H> & {\n    label?: string\n  }\n\n/**\n * Validates that the hook context matches the expected type(s) and method(s).\n * Throws an error if the context is invalid, preventing hooks from running in\n * unsupported configurations. Typically used internally by other hooks.\n * Also narrows the context type based on the passed options.\n *\n * @example\n * ```ts\n * import { checkContext } from 'feathers-utils/utils'\n *\n * const myHook = (context) => {\n *   checkContext(context, ['before', 'around'], ['create', 'patch'], 'myHook')\n *   // or with options object:\n *   checkContext(context, { type: ['before', 'around'], method: ['create', 'patch'], label: 'myHook' })\n *   // context.type is now 'before' | 'around', context.method is now 'create' | 'patch'\n * }\n * ```\n *\n * @see https://utils.feathersjs.com/utils/check-context.html\n */\nexport function checkContext<\n  H extends HookContext,\n  const O extends CheckContextOptions<NoInfer<H>>,\n>(context: H, options: O): asserts context is NarrowedContext<H, O>\nexport function checkContext<\n  H extends HookContext,\n  const T extends HookType | HookType[] | null | undefined = undefined,\n  const M extends MethodName | MethodName[] | null | undefined = undefined,\n>(\n  context: H,\n  type?: T,\n  methods?: M,\n  label?: string,\n): asserts context is NarrowedContext<H, { type: T; method: M }>\nexport function checkContext<H extends HookContext = HookContext>(\n  context: H,\n  typeOrOptions?:\n    | HookType\n    | HookType[]\n    | CheckContextOptions<NoInfer<H>>\n    | null,\n  methods?: MethodName | MethodName[] | null,\n  label = 'anonymous',\n): void {\n  let options: IsContextOptions\n  let hookLabel: string\n\n  if (\n    typeOrOptions != null &&\n    typeof typeOrOptions === 'object' &&\n    !Array.isArray(typeOrOptions)\n  ) {\n    const { label: optLabel, ...rest } = typeOrOptions\n    options = rest\n    hookLabel = optLabel ?? 'anonymous'\n  } else {\n    options = {\n      method: methods ?? undefined,\n      type: typeOrOptions ?? undefined,\n    }\n    hookLabel = label\n  }\n\n  if (!isContext(options)(context)) {\n    const details: string[] = []\n\n    if (options.type != null) {\n      details.push(\n        `type: expected '${Array.isArray(options.type) ? options.type.join(\"' | '\") : options.type}' but got '${context.type}'`,\n      )\n    }\n    if (options.method != null) {\n      details.push(\n        `method: expected '${Array.isArray(options.method) ? options.method.join(\"' | '\") : options.method}' but got '${context.method}'`,\n      )\n    }\n    if (options.path != null) {\n      details.push(\n        `path: expected '${Array.isArray(options.path) ? options.path.join(\"' | '\") : options.path}' but got '${context.path}'`,\n      )\n    }\n\n    throw new Error(\n      `The '${hookLabel}' hook has invalid context (${details.join(', ')}).`,\n    )\n  }\n}\n","import type { Application, Params } from '@feathersjs/feathers'\nimport type { KeyOf } from '../../internal.utils.js'\nimport type {\n  InferFindParams,\n  InferFindResultSingle,\n} from '../../utility-types/infer-service-methods.js'\n\ntype PaginateOption = { default?: number; max?: number }\n\ntype ChunkFindOptions<P extends Params = Params> = {\n  params?: P & { paginate?: PaginateOption }\n}\n\n/**\n * Use `for await` to iterate over chunks (pages) of results from a `find` method.\n *\n * This function is useful for processing large datasets in batches without loading everything into memory at once.\n * It uses pagination to fetch results in chunks, yielding each page's data array.\n *\n * @example\n * ```ts\n * import { chunkFind } from 'feathers-utils/utils'\n *\n * const app = feathers()\n *\n * // Assuming 'users' service has many records\n * for await (const users of chunkFind(app, 'users', {\n *  params: { query: { active: true }, // Custom query parameters\n * } })) {\n *  console.log(users) // Process each chunk of user records\n * }\n * ```\n *\n * @see https://utils.feathersjs.com/utils/chunk-find.html\n */\nexport async function* chunkFind<\n  Services,\n  Path extends KeyOf<Services>,\n  Service extends Services[Path] = Services[Path],\n  P extends Params = InferFindParams<Service>,\n  Item = InferFindResultSingle<Service>,\n>(\n  app: Application<Services>,\n  servicePath: Path,\n  options?: ChunkFindOptions<P>,\n): AsyncGenerator<Item[], void, unknown> {\n  const service = app.service(servicePath)\n\n  if (!service || !('find' in service)) {\n    throw new Error(`Service '${servicePath}' does not have a 'find' method.`)\n  }\n\n  const params = {\n    ...options?.params,\n    query: {\n      ...(options?.params?.query ?? {}),\n      $limit: options?.params?.query?.$limit ?? 10,\n      $skip: options?.params?.query?.$skip ?? 0,\n    },\n    paginate: {\n      default: options?.params?.paginate?.default ?? 10,\n      max: options?.params?.paginate?.max ?? 100,\n    },\n  }\n\n  let result\n\n  do {\n    result = await (service as any).find(params)\n\n    // Guard against an infinite loop: an empty page never advances $skip, so\n    // `total > $skip` could stay true forever (e.g. $limit:0, or a stale total\n    // when items are concurrently removed / filtered out by hooks).\n    if (!result.data.length) {\n      break\n    }\n\n    yield result.data\n\n    params.query.$skip = (params.query.$skip ?? 0) + result.data.length\n  } while (result.total > params.query.$skip)\n}\n","import type { HookContext } from '@feathersjs/feathers'\n\n/**\n * Converts a FeathersJS HookContext to a plain JSON object by calling `toJSON()` if available.\n * This is important when using lodash `get`/`has` on the context, since the HookContext\n * class uses getters that may not be enumerable.\n *\n * @example\n * ```ts\n * import { contextToJson } from 'feathers-utils/utils'\n *\n * const json = contextToJson(context)\n * console.log(json)\n * ```\n *\n * @see https://utils.feathersjs.com/utils/context-to-json.html\n */\nexport const contextToJson = (context: HookContext) => {\n  if (context.toJSON) {\n    return context.toJSON()\n  }\n  return context\n}\n","import type { Application, HookOptions } from '@feathersjs/feathers'\n\n/**\n * TypeScript helper that provides full type inference and autocompletion when defining\n * service hooks. It is an identity function that simply returns its input,\n * but enables your IDE to infer the correct hook context types.\n *\n * @example\n * ```ts\n * import { defineHooks } from 'feathers-utils/utils'\n *\n * export const userHooks = defineHooks({\n *   before: { create: [validateUser()] },\n *   after: { all: [sanitizeResult()] }\n * })\n * ```\n *\n * @see https://utils.feathersjs.com/utils/define-hooks.html\n */\nexport function defineHooks<\n  A extends Application = Application,\n  S = {\n    find: any\n    get: any\n    create: any\n    update: any\n    patch: any\n    remove: any\n  },\n  Options = HookOptions<A, S>,\n>(hooks: Options): Options {\n  return hooks\n}\n","// src/feathers.ts\nimport * as feathers from '@feathersjs/feathers'\n\n// Type-safe re-export of only what you need\nexport const SERVICE = (feathers as any).SERVICE || feathers.default?.SERVICE\n","import type { Service } from '@feathersjs/feathers'\nimport { SERVICE } from '../../feathers-cjs-fix.js'\n\n/**\n * Returns the list of method names that are publicly exposed by a Feathers service.\n * Reads the internal `[SERVICE].methods` property set during service registration.\n * Throws if the service does not have any exposed methods configured.\n *\n * @example\n * ```ts\n * import { getExposedMethods } from 'feathers-utils/utils'\n *\n * const methods = getExposedMethods(app.service('users'))\n * // => ['find', 'get', 'create', 'patch', 'remove']\n * ```\n *\n * @see https://utils.feathersjs.com/utils/get-exposed-methods.html\n */\nexport function getExposedMethods(service: Service) {\n  const result = (service as any)[SERVICE].methods\n\n  if (!result || !Array.isArray(result)) {\n    throw new Error(`Service does not have exposed methods`)\n  }\n\n  return result\n}\n","import type { Application, Params } from '@feathersjs/feathers'\nimport type { KeyOf } from '../../internal.utils.js'\nimport type {\n  InferFindParams,\n  InferFindResultSingle,\n} from '../../utility-types/infer-service-methods.js'\n\ntype PaginateOption = { default?: number; max?: number }\n\ntype IterateFindOptions<P extends Params = Params> = {\n  params?: P & { paginate?: PaginateOption }\n}\n\n/**\n * Use `for await` to iterate over the results of a `find` method.\n *\n * This function is useful for iterating over large datasets without loading everything into memory at once.\n * It uses pagination to fetch results in chunks, allowing you to process each item as it is retrieved.\n *\n * @example\n * ```ts\n * import { iterateFind } from 'feathers-utils/utils'\n *\n * const app = feathers()\n *\n * // Assuming 'users' service has many records\n * for await (const user of iterateFind(app, 'users', {\n *  params: { query: { active: true }, // Custom query parameters\n * } })) {\n *  console.log(user) // Process each user record\n * }\n * ```\n *\n * @see https://utils.feathersjs.com/utils/iterate-find.html\n */\nexport async function* iterateFind<\n  Services,\n  Path extends KeyOf<Services>,\n  Service extends Services[Path] = Services[Path],\n  P extends Params = InferFindParams<Service>,\n  Item = InferFindResultSingle<Service>,\n>(\n  app: Application<Services>,\n  servicePath: Path,\n  options?: IterateFindOptions<P>,\n): AsyncGenerator<Item, void, unknown> {\n  const service = app.service(servicePath)\n\n  if (!service || !('find' in service)) {\n    throw new Error(`Service '${servicePath}' does not have a 'find' method.`)\n  }\n\n  const params = {\n    ...options?.params,\n    query: {\n      ...(options?.params?.query ?? {}),\n      $limit: options?.params?.query?.$limit,\n      $skip: options?.params?.query?.$skip ?? 0,\n    },\n    paginate: {\n      default: options?.params?.paginate?.default ?? 10,\n      max: options?.params?.paginate?.max ?? 100,\n    },\n  }\n\n  let result\n\n  do {\n    result = await (service as any).find(params)\n\n    // Guard against an infinite loop: an empty page never advances $skip, so\n    // `total > $skip` could stay true forever (e.g. $limit:0, or a stale total\n    // when items are concurrently removed / filtered out by hooks).\n    if (!result.data.length) {\n      break\n    }\n\n    for (const item of result.data) {\n      yield item\n    }\n\n    params.query.$skip = (params.query.$skip ?? 0) + result.data.length\n  } while (result.total > params.query.$skip)\n}\n","import type { Query } from '@feathersjs/feathers'\n\nexport type FilterQueryResult<Q extends Query = Query> = {\n  $select?: Q['$select']\n  $limit?: Q['$limit']\n  $skip?: Q['$skip']\n  $sort?: Q['$sort']\n  query: Omit<Q, '$select' | '$limit' | '$skip' | '$sort'>\n}\n\n/**\n * Splits a query into its special filters ($select, $limit, $skip, $sort) and the\n * remaining query body. Internal helper for {@link mergeQuery} — not part of the\n * public API.\n */\nexport function extractQueryFilters<Q extends Query>(\n  providedQuery?: Q,\n): FilterQueryResult<Q> {\n  providedQuery ??= {} as Q\n  const { $select, $limit, $skip, $sort, ...query } = providedQuery\n\n  const result: FilterQueryResult<Q> = { query } as FilterQueryResult<Q>\n\n  if ('$select' in providedQuery) {\n    result.$select = $select\n  }\n\n  if ('$limit' in providedQuery) {\n    result.$limit = $limit\n  }\n\n  if ('$skip' in providedQuery) {\n    result.$skip = $skip\n  }\n\n  if ('$sort' in providedQuery) {\n    result.$sort = $sort\n  }\n\n  return result\n}\n\nif (import.meta.vitest) {\n  const { describe, it, expect } = import.meta.vitest\n\n  describe('extractQueryFilters', () => {\n    it('splits filters from the query body', () => {\n      expect(\n        extractQueryFilters({\n          $select: ['a'],\n          $limit: 10,\n          $skip: 10,\n          $sort: { a: 1 },\n          a: 1,\n          b: 2,\n        }),\n      ).toEqual({\n        $select: ['a'],\n        $limit: 10,\n        $skip: 10,\n        $sort: { a: 1 },\n        query: { a: 1, b: 2 },\n      })\n    })\n\n    it('omits filters that are not provided', () => {\n      expect(extractQueryFilters({ a: 1, b: 2 })).toEqual({\n        query: { a: 1, b: 2 },\n      })\n    })\n\n    it('returns an empty body for an empty query', () => {\n      expect(extractQueryFilters({})).toEqual({ query: {} })\n    })\n\n    it('returns an empty body for undefined', () => {\n      expect(extractQueryFilters(undefined)).toEqual({ query: {} })\n    })\n  })\n}\n","type QueryRecord = Record<string, any>\n\n/**\n * Returns the branches of a logical-only query (a query whose single key is `op`),\n * or `null` when the query is not purely `{ [op]: [...] }`. Internal helper for\n * {@link mergeQuery}.\n */\nexport function logicalBranches(\n  query: QueryRecord,\n  op: '$or' | '$and',\n): QueryRecord[] | null {\n  const keys = Object.keys(query)\n  if (keys.length === 1 && keys[0] === op && Array.isArray(query[op])) {\n    return query[op] as QueryRecord[]\n  }\n  return null\n}\n\nif (import.meta.vitest) {\n  const { describe, it, expect } = import.meta.vitest\n\n  describe('logicalBranches', () => {\n    it('returns branches for a logical-only query', () => {\n      expect(logicalBranches({ $or: [{ id: 1 }] }, '$or')).toEqual([{ id: 1 }])\n    })\n\n    it('returns null when the operator is mixed with other keys', () => {\n      expect(logicalBranches({ $or: [{ id: 1 }], a: 1 }, '$or')).toBeNull()\n    })\n\n    it('returns null for the wrong operator', () => {\n      expect(logicalBranches({ $and: [{ id: 1 }] }, '$or')).toBeNull()\n    })\n\n    it('returns null when the operator value is not an array', () => {\n      expect(logicalBranches({ $or: { id: 1 } }, '$or')).toBeNull()\n    })\n  })\n}\n","import { dequal as deepEqual } from 'dequal'\nimport { isEmptyObject } from '../../common/is-empty-object.js'\n\ntype QueryRecord = Record<string, any>\n\n/**\n * Removes empty (`{}`) and deep-equal duplicate branches, preserving order.\n * Internal helper for {@link mergeQuery}.\n */\nexport function dedupeBranches(branches: QueryRecord[]): QueryRecord[] {\n  const result: QueryRecord[] = []\n  for (const branch of branches) {\n    if (isEmptyObject(branch)) {\n      continue\n    }\n    if (!result.some((existing) => deepEqual(existing, branch))) {\n      result.push(branch)\n    }\n  }\n  return result\n}\n\nif (import.meta.vitest) {\n  const { describe, it, expect } = import.meta.vitest\n\n  describe('dedupeBranches', () => {\n    it('removes empty objects and deep-equal duplicates', () => {\n      expect(dedupeBranches([{ id: 1 }, {}, { id: 1 }, { id: 2 }])).toEqual([\n        { id: 1 },\n        { id: 2 },\n      ])\n    })\n\n    it('preserves order', () => {\n      expect(dedupeBranches([{ b: 2 }, { a: 1 }])).toEqual([{ b: 2 }, { a: 1 }])\n    })\n\n    it('returns an empty array when all branches are empty', () => {\n      expect(dedupeBranches([{}, {}])).toEqual([])\n    })\n  })\n}\n","import { dequal as deepEqual } from 'dequal'\n\ntype QueryRecord = Record<string, any>\n\n/**\n * Two query bodies conflict when they share at least one key whose values are not\n * deep-equal. Internal helper for {@link mergeQuery}.\n */\nexport function hasConflict(target: QueryRecord, source: QueryRecord): boolean {\n  for (const key of Object.keys(target)) {\n    if (key in source && !deepEqual(target[key], source[key])) {\n      return true\n    }\n  }\n  return false\n}\n\nif (import.meta.vitest) {\n  const { describe, it, expect } = import.meta.vitest\n\n  describe('hasConflict', () => {\n    it('is false for disjoint keys', () => {\n      expect(hasConflict({ a: 1 }, { b: 2 })).toBe(false)\n    })\n\n    it('is false for shared equal values', () => {\n      expect(hasConflict({ a: 1 }, { a: 1, b: 2 })).toBe(false)\n    })\n\n    it('is true for shared differing values', () => {\n      expect(hasConflict({ a: 1 }, { a: 2 })).toBe(true)\n    })\n\n    it('compares values deeply', () => {\n      expect(hasConflict({ a: { x: 1 } }, { a: { x: 1 } })).toBe(false)\n      expect(hasConflict({ a: { x: 1 } }, { a: { x: 2 } })).toBe(true)\n    })\n  })\n}\n","import type { MergeQueryMode } from './merge-query.util.js'\nimport { isEmptyObject } from '../../common/is-empty-object.js'\nimport { logicalBranches } from './logical-branches.js'\nimport { dedupeBranches } from './dedupe-branches.js'\nimport { hasConflict } from './has-conflict.js'\n\ntype QueryRecord = Record<string, any>\n\n/**\n * Merges two query bodies (filters already removed) according to the mode.\n * Internal helper for {@link mergeQuery}.\n *\n * - `target` / `source`: precedence merge (that side wins on conflict).\n * - `combine`: the two bodies always become branches of a single `$or`.\n * - `intersect`: non-conflicting bodies merge flat; on conflict they become\n *   branches of a single `$and`.\n *\n * Logical-only bodies (`{ $or: [...] }` for combine, `{ $and: [...] }` for\n * intersect) are flattened into the result and their branches de-duplicated.\n */\nexport function mergeQueryBodies(\n  target: QueryRecord,\n  source: QueryRecord,\n  mode: MergeQueryMode,\n): QueryRecord {\n  if (mode === 'target') {\n    return { ...source, ...target }\n  }\n  if (mode === 'source') {\n    return { ...target, ...source }\n  }\n\n  if (isEmptyObject(target)) {\n    return { ...source }\n  }\n  if (isEmptyObject(source)) {\n    return { ...target }\n  }\n\n  const op = mode === 'combine' ? '$or' : '$and'\n\n  const targetBranches = logicalBranches(target, op)\n  const sourceBranches = logicalBranches(source, op)\n\n  // For intersect (AND) the top level is itself an implicit AND, so two\n  // conflict-free bodies can be merged flat. For combine (OR) there is no flat\n  // representation — combine always produces an `$or`.\n  if (\n    op === '$and' &&\n    !targetBranches &&\n    !sourceBranches &&\n    !hasConflict(target, source)\n  ) {\n    return { ...target, ...source }\n  }\n\n  const branches = dedupeBranches([\n    ...(targetBranches ?? [target]),\n    ...(sourceBranches ?? [source]),\n  ])\n\n  if (branches.length === 0) {\n    return {}\n  }\n  if (branches.length === 1) {\n    return { ...branches[0] }\n  }\n  return { [op]: branches }\n}\n\nif (import.meta.vitest) {\n  const { describe, it, expect } = import.meta.vitest\n\n  describe('mergeQueryBodies', () => {\n    it('target / source precedence', () => {\n      expect(mergeQueryBodies({ id: 1 }, { id: 2, a: 3 }, 'target')).toEqual({\n        id: 1,\n        a: 3,\n      })\n      expect(mergeQueryBodies({ id: 1 }, { id: 2, a: 3 }, 'source')).toEqual({\n        id: 2,\n        a: 3,\n      })\n    })\n\n    it('returns the other side when one is empty', () => {\n      expect(mergeQueryBodies({}, { id: 1 }, 'combine')).toEqual({ id: 1 })\n      expect(mergeQueryBodies({ id: 1 }, {}, 'intersect')).toEqual({ id: 1 })\n    })\n\n    it('combine always produces an $or, even for disjoint keys', () => {\n      expect(mergeQueryBodies({ a: 1 }, { b: 2 }, 'combine')).toEqual({\n        $or: [{ a: 1 }, { b: 2 }],\n      })\n    })\n\n    it('combine flattens and dedupes $or branches', () => {\n      expect(\n        mergeQueryBodies(\n          { $or: [{ id: 1 }, { id: 2 }] },\n          { $or: [{ id: 2 }, { id: 3 }] },\n          'combine',\n        ),\n      ).toEqual({ $or: [{ id: 1 }, { id: 2 }, { id: 3 }] })\n    })\n\n    it('combine collapses to a single body', () => {\n      expect(mergeQueryBodies({ id: 1 }, { id: 1 }, 'combine')).toEqual({\n        id: 1,\n      })\n    })\n\n    it('intersect merges disjoint keys flat', () => {\n      expect(mergeQueryBodies({ id: 1 }, { userId: 2 }, 'intersect')).toEqual({\n        id: 1,\n        userId: 2,\n      })\n    })\n\n    it('intersect wraps conflicts in $and', () => {\n      expect(mergeQueryBodies({ id: 1 }, { id: 2 }, 'intersect')).toEqual({\n        $and: [{ id: 1 }, { id: 2 }],\n      })\n    })\n\n    it('intersect flattens $and branches', () => {\n      expect(\n        mergeQueryBodies(\n          { $and: [{ id: 1 }, { id: 2 }] },\n          { $and: [{ id: 3 }] },\n          'intersect',\n        ),\n      ).toEqual({ $and: [{ id: 1 }, { id: 2 }, { id: 3 }] })\n    })\n  })\n}\n","import type { MergeQueryMode } from './merge-query.util.js'\n\n/**\n * Merges two `$select` filters according to the mode: `combine` → union,\n * `intersect` → intersection, `target`/`source` → that side. When only one side\n * provides a `$select`, that one is used. Internal helper for {@link mergeQuery}.\n */\nexport function mergeSelect(\n  target: any,\n  source: any,\n  mode: MergeQueryMode,\n): any {\n  if (target === undefined) {\n    return source\n  }\n  if (source === undefined) {\n    return target\n  }\n  if (mode === 'target') {\n    return target\n  }\n  if (mode === 'source') {\n    return source\n  }\n  const targetArr = Array.isArray(target) ? target : [target]\n  const sourceArr = Array.isArray(source) ? source : [source]\n  if (mode === 'combine') {\n    return [...new Set([...targetArr, ...sourceArr])]\n  }\n  // intersect\n  return targetArr.filter((value) => sourceArr.includes(value))\n}\n\nif (import.meta.vitest) {\n  const { describe, it, expect } = import.meta.vitest\n\n  describe('mergeSelect', () => {\n    it('returns the defined side when one is missing', () => {\n      expect(mergeSelect(undefined, ['a'], 'combine')).toEqual(['a'])\n      expect(mergeSelect(['a'], undefined, 'combine')).toEqual(['a'])\n    })\n\n    it('unions on combine', () => {\n      expect(mergeSelect(['a', 'b'], ['b', 'c'], 'combine')).toEqual([\n        'a',\n        'b',\n        'c',\n      ])\n    })\n\n    it('intersects on intersect', () => {\n      expect(mergeSelect(['a', 'b'], ['b', 'c'], 'intersect')).toEqual(['b'])\n    })\n\n    it('can produce an empty intersection', () => {\n      expect(mergeSelect(['a'], ['b'], 'intersect')).toEqual([])\n    })\n\n    it('picks the requested side on target / source', () => {\n      expect(mergeSelect(['a'], ['b'], 'target')).toEqual(['a'])\n      expect(mergeSelect(['a'], ['b'], 'source')).toEqual(['b'])\n    })\n  })\n}\n","import type { Query } from '@feathersjs/feathers'\nimport { extractQueryFilters } from './extract-query-filters.js'\nimport { mergeQueryBodies } from './merge-query-bodies.js'\nimport { mergeSelect } from './merge-select.js'\n\nexport type MergeQueryMode = 'target' | 'source' | 'combine' | 'intersect'\n\nexport interface MergeQueryOptions {\n  /**\n   * How to merge query properties that both queries constrain.\n   *\n   * - `combine` (default): broaden — the two queries always become branches of an `$or`.\n   * - `intersect`: narrow — non-conflicting properties merge flat, conflicts become an `$and`.\n   * - `target`: keep the target's value on conflict.\n   * - `source`: keep the source's value on conflict.\n   */\n  mode?: MergeQueryMode\n}\n\n/**\n * Properties are combined with a logical operator rather than merged at the value\n * level, so the result is always a valid query: `combine` always wraps the two\n * queries in `$or` (broaden — OR has no flat form), while `intersect` merges\n * non-conflicting properties flat and wraps conflicts in `$and` (narrow). The\n * special filters `$select`, `$limit`, `$skip` and `$sort` are merged separately.\n * Inputs are never mutated.\n *\n * This is well suited to merging a client-provided query with a server-side\n * restriction inside a hook.\n *\n * @param target Query to be merged into\n * @param source Query to be merged from\n * @param options\n * @returns the merged query\n *\n * @example\n * ```ts\n * import { mergeQuery } from 'feathers-utils/utils'\n *\n * // combine (default): the two queries always become an $or\n * mergeQuery({ id: 1 }, { id: 2 })\n * // => { $or: [{ id: 1 }, { id: 2 }] }\n *\n * mergeQuery({ status: 'active' }, { authorId: 5 })\n * // => { $or: [{ status: 'active' }, { authorId: 5 }] }\n * ```\n *\n * @example\n * ```ts\n * // intersect: non-conflicting properties merge flat, conflicts become an $and\n * mergeQuery({ status: 'active' }, { authorId: 5 }, { mode: 'intersect' })\n * // => { status: 'active', authorId: 5 }\n *\n * mergeQuery({ id: 1 }, { id: 2 }, { mode: 'intersect' })\n * // => { $and: [{ id: 1 }, { id: 2 }] }\n * ```\n *\n * @see https://utils.feathersjs.com/utils/merge-query.html\n */\nexport function mergeQuery(\n  target: Query,\n  source: Query,\n  options?: MergeQueryOptions,\n): Query {\n  const mode = options?.mode ?? 'combine'\n\n  const targetFilters = extractQueryFilters(target)\n  const sourceFilters = extractQueryFilters(source)\n\n  const result: Query = mergeQueryBodies(\n    targetFilters.query,\n    sourceFilters.query,\n    mode,\n  )\n\n  const $select = mergeSelect(\n    targetFilters.$select,\n    sourceFilters.$select,\n    mode,\n  )\n  if ($select !== undefined) {\n    result.$select = $select\n  }\n\n  if ('$limit' in sourceFilters) {\n    result.$limit = sourceFilters.$limit\n  } else if ('$limit' in targetFilters) {\n    result.$limit = targetFilters.$limit\n  }\n\n  if ('$skip' in sourceFilters) {\n    result.$skip = sourceFilters.$skip\n  } else if ('$skip' in targetFilters) {\n    result.$skip = targetFilters.$skip\n  }\n\n  if ('$sort' in targetFilters || '$sort' in sourceFilters) {\n    result.$sort = { ...targetFilters.$sort, ...sourceFilters.$sort }\n  }\n\n  return result\n}\n","import type { Id, Params } from '@feathersjs/feathers'\nimport type { KeyOf } from '../../internal.utils.js'\n\n/**\n * Deterministic, key-order-independent serialization used to group items with\n * equal patch data in O(1) per item.\n */\nconst stableKey = (value: any): string =>\n  JSON.stringify(value, (_key, val) =>\n    val && typeof val === 'object' && !Array.isArray(val)\n      ? Object.keys(val)\n          .sort()\n          .reduce<Record<string, any>>((acc, k) => {\n            acc[k] = val[k]\n            return acc\n          }, {})\n      : val,\n  )\n\nexport type PatchBatchOptions<IdKey extends string> = {\n  /** the key of the id property */\n  id?: IdKey\n}\n\nexport type PatchBatchResultItem<T = Record<string, unknown>, P = Params> = [\n  Id | null,\n  T,\n  P | undefined,\n]\n\n/**\n * Batch patching utility that takes an array of items to be changed and returns an array of arguments to be called with the `patch` method.\n *\n * This utility is useful when you need to patch multiple items with varying data in as few requests as possible.\n *\n * @example\n * ```ts\n * const items = [\n *   { id: 1, value: 10 },\n *   { id: 2, value: 10 },\n *   { id: 3, value: 20 },\n * ];\n *\n * const batched = patchBatch(items, { id: 'id' });\n * // batched will be:\n * // [\n * //   [null, { value: 10 }, { query: { id: { $in: [1, 2] } } }],\n * //   [3, { value: 20 }, undefined],\n * // ]\n *\n * await Promise.all(batched.map(args => service.patch(...args)));\n * ```\n *\n * @see https://utils.feathersjs.com/utils/patch-batch.html\n */\nexport function patchBatch<\n  T extends Record<string, any>,\n  IdKey extends KeyOf<T>,\n  P extends Params,\n  R extends Omit<T, IdKey> = Omit<T, IdKey>,\n>(\n  items: T[],\n  options?: PatchBatchOptions<IdKey>,\n): PatchBatchResultItem<R, P>[] {\n  const idKey = options?.id ?? 'id'\n\n  // group items with identical (id-stripped) data in O(n) via a Map keyed by a\n  // stable serialization, instead of an O(n^2) findIndex + deepEqual scan.\n  const groups = new Map<string, { ids: Id[]; data: R }>()\n\n  for (const item of items) {\n    const source = item as Record<string, any>\n    const id = source[idKey] as Id\n    // shallow copy then drop the id key, so the caller's input is never mutated.\n    const data = { ...source }\n    delete data[idKey as any]\n\n    const key = stableKey(data)\n    const existing = groups.get(key)\n\n    if (existing) {\n      existing.ids.push(id)\n    } else {\n      groups.set(key, { ids: [id], data: data as unknown as R })\n    }\n  }\n\n  return [...groups.values()].map(({ ids, data }) => {\n    return ids.length === 1\n      ? ([ids[0], data, undefined] as PatchBatchResultItem<R, P>)\n      : ([\n          null,\n          data,\n          {\n            query: {\n              [idKey]: { $in: ids },\n            },\n          },\n        ] as PatchBatchResultItem<R, P>)\n  })\n}\n","import type { Query } from '@feathersjs/feathers'\n\ntype WalkQueryOptionsInit = {\n  property?: string\n  operator?: string | undefined\n  value?: any\n  path: (string | number)[]\n}\n\nexport type WalkQueryOptions = {\n  property: string\n  operator: string | undefined\n  value: any\n  path: (string | number)[]\n  /**\n   * Stops the traversal. Any replacement value returned from the current walker\n   * call is still applied, but no further properties are visited.\n   */\n  stop: () => void\n}\n\nexport type WalkQueryCallback = (options: WalkQueryOptions) => any\n\ntype WalkQueryState = { stopped: boolean }\n\nconst _walkQueryUtil = <Q extends Query>(\n  query: Q,\n  walker: WalkQueryCallback,\n  state: WalkQueryState,\n  options?: WalkQueryOptionsInit | WalkQueryOptions,\n): Q => {\n  const stop = () => {\n    state.stopped = true\n  }\n\n  let cloned = false\n  const clonedSecond: Record<string, boolean> = {}\n  function set(key: string, value: any, secondKey?: string | number) {\n    if (!cloned) {\n      query = { ...query }\n      cloned = true\n    }\n\n    if (secondKey !== undefined) {\n      if (!clonedSecond[key]) {\n        ;(query as any)[key] = { ...query[key] }\n        clonedSecond[key] = true\n      }\n      query[key][secondKey] = value\n      return\n    }\n\n    ;(query as any)[key] = value\n  }\n\n  for (const key in query) {\n    if (state.stopped) {\n      break\n    }\n\n    if (\n      (key === '$or' || key === '$and' || key === '$nor') &&\n      Array.isArray(query[key])\n    ) {\n      let array = query[key]\n\n      let copiedArray = false\n\n      for (let i = 0, n = array.length; i < n; i++) {\n        if (state.stopped) {\n          break\n        }\n\n        const nestedQuery = array[i]\n        const transformed = _walkQueryUtil(nestedQuery, walker, state, {\n          ...options,\n          path: [...(options?.path || []), key, i],\n        })\n\n        if (transformed !== nestedQuery) {\n          if (!copiedArray) {\n            array = [...array] as any\n            copiedArray = true\n          }\n\n          array[i] = transformed\n        }\n      }\n\n      if (copiedArray) {\n        set(key, array)\n      }\n    } else if (\n      typeof query[key] === 'object' &&\n      query[key] !== null &&\n      !Array.isArray(query[key])\n    ) {\n      let hasOperator = false\n      for (const operator in query[key]) {\n        if (state.stopped) {\n          break\n        }\n\n        if (operator.startsWith('$')) {\n          hasOperator = true\n          const value = walker({\n            operator,\n            path: [...(options?.path ?? []), key],\n            property: key,\n            value: query[key][operator],\n            stop,\n          })\n\n          if (value !== undefined && value !== query[key][operator]) {\n            set(key, value, operator)\n          }\n        }\n      }\n\n      if (!hasOperator) {\n        const value = walker({\n          operator: undefined,\n          path: [...(options?.path ?? []), key],\n          property: key,\n          value: query[key],\n          stop,\n        })\n\n        if (value !== undefined && value !== query[key]) {\n          set(key, value)\n        }\n      }\n    } else {\n      const value = walker({\n        operator: undefined,\n        path: [...(options?.path ?? []), key],\n        property: key,\n        value: query[key],\n        stop,\n      })\n\n      if (value !== undefined && value !== query[key]) {\n        set(key, value)\n      }\n    }\n  }\n\n  return query\n}\n\n/**\n * Walks every property of a Feathers query (including nested `$and`/`$or`/`$nor` arrays)\n * and calls the `walker` function for each one. The walker receives the property name, operator,\n * value, path, and a `stop` function, and can return a replacement value. Calling `stop()` halts\n * the traversal early. Returns a new query only if changes were made.\n *\n * @example\n * ```ts\n * import { walkQuery } from 'feathers-utils/utils'\n *\n * const query = walkQuery({ age: { $gt: '18' } }, ({ value, operator }) => {\n *   if (operator === '$gt') return Number(value)\n * })\n * // => { age: { $gt: 18 } }\n * ```\n *\n * @example\n * ```ts\n * // stop early once a property is found\n * let found = false\n * walkQuery(query, ({ property, stop }) => {\n *   if (property === 'isTemplate') {\n *     found = true\n *     stop()\n *   }\n * })\n * ```\n *\n * @see https://utils.feathersjs.com/utils/walk-query.html\n */\nexport const walkQuery = <Q extends Query>(\n  query: Q,\n  walker: WalkQueryCallback,\n): Q => {\n  return _walkQueryUtil(query, walker, { stopped: false })\n}\n","import type { Query } from '@feathersjs/feathers'\nimport { toArray, type MaybeArray } from '../../internal.utils.js'\nimport { walkQuery } from '../walk-query/walk-query.util.js'\n\n/**\n * Checks whether a Feathers query contains one or more properties — including\n * properties nested inside `$and`/`$or`/`$nor` arrays. Returns `true` as soon as\n * any of the given property names is found. The query is not mutated.\n *\n * @example\n * ```ts\n * import { queryHasProperty } from 'feathers-utils/utils'\n *\n * queryHasProperty({ isTemplate: true }, 'isTemplate') // true\n * queryHasProperty({ $or: [{ isTemplate: true }] }, 'isTemplate') // true\n * queryHasProperty({ age: { $gt: 18 } }, ['isTemplate', 'status']) // false\n * ```\n *\n * @see https://utils.feathersjs.com/utils/query-has-property.html\n */\nexport const queryHasProperty = (\n  query: Query,\n  property: MaybeArray<string>,\n): boolean => {\n  const properties = new Set(toArray(property))\n\n  let found = false\n  walkQuery(query, ({ property: key, stop }) => {\n    if (properties.has(key)) {\n      found = true\n      stop()\n    }\n    // returning undefined leaves the value untouched → no mutation\n  })\n\n  return found\n}\n","import type { Query } from '@feathersjs/feathers'\nimport { addToQuery } from '../add-to-query/add-to-query.util.js'\nimport { queryHasProperty } from '../query-has-property/query-has-property.util.js'\n\n/**\n * Adds default properties to a Feathers query — but only for fields the query does\n * not already constrain. Presence is checked with {@link queryHasProperty}, so a field\n * referenced anywhere (including nested in `$and`/`$or`/`$nor`) is left untouched and\n * the caller keeps control over it. The query is treated as the `data` equivalent of\n * the `defaults` transformer. Each default is applied independently (per-field).\n *\n * @example\n * ```ts\n * import { queryDefaults } from 'feathers-utils/utils'\n *\n * queryDefaults({ status: 'active' }, { isTemplate: false })\n * // => { status: 'active', isTemplate: false }\n *\n * queryDefaults({ $or: [{ isTemplate: true }] }, { isTemplate: false })\n * // => { $or: [{ isTemplate: true }] } (untouched — already referenced)\n * ```\n *\n * @see https://utils.feathersjs.com/utils/query-defaults.html\n */\nexport const queryDefaults = (\n  query: Query | undefined,\n  defaults: Query,\n): Query => {\n  const source: Query = query ?? {}\n\n  const toAdd: Query = {}\n  for (const key in defaults) {\n    if (!queryHasProperty(source, key)) {\n      toAdd[key] = defaults[key]\n    }\n  }\n\n  return addToQuery(source, toAdd)\n}\n","import type { HookContext } from '@feathersjs/feathers'\nimport { isMulti, isPaginated } from '../../predicates/index.js'\n\n/**\n * Sets `context.result` to an appropriate empty value based on the hook method.\n * Returns an empty paginated object for paginated `find`, an empty array for multi\n * operations, or `null` for single-item operations. Does nothing if a result already exists.\n *\n * @example\n * ```ts\n * import { skipResult } from 'feathers-utils/utils'\n *\n * // In a before hook to skip the actual database call:\n * skipResult(context)\n * ```\n *\n * @see https://utils.feathersjs.com/utils/skip-result.html\n */\nexport const skipResult = <H extends HookContext = HookContext>(context: H) => {\n  if (context.result) {\n    return context\n  }\n\n  const multi = isMulti(context)\n\n  if (multi) {\n    if (context.method === 'find' && isPaginated(context)) {\n      context.result = {\n        total: 0,\n        skip: 0,\n        limit: 0,\n        data: [],\n      }\n    } else {\n      context.result = []\n    }\n  } else {\n    context.result = null\n  }\n\n  return context\n}\n","import type { Paginated } from '@feathersjs/feathers'\n\n/**\n * Ensures a result is in Feathers paginated format (`{ total, limit, skip, data }`).\n * If the input is already paginated, it is returned as-is. If it is a plain array,\n * it is wrapped in a paginated object with `total` and `limit` set to the array length.\n *\n * @example\n * ```ts\n * import { toPaginated } from 'feathers-utils/utils'\n *\n * const paginated = toPaginated([{ id: 1 }, { id: 2 }])\n * // => { total: 2, limit: 2, skip: 0, data: [{ id: 1 }, { id: 2 }] }\n * ```\n *\n * @see https://utils.feathersjs.com/utils/to-paginated.html\n */\nexport function toPaginated<R>(result: R[] | Paginated<R>): Paginated<R> {\n  if (Array.isArray(result)) {\n    return {\n      total: result.length,\n      limit: result.length,\n      skip: 0,\n      data: result,\n    }\n  }\n  return result\n}\n","import type { Params } from '@feathersjs/feathers'\nimport type { TransformParamsFn } from '../../types.js'\n\n/**\n * Safely applies a `transformParams` function to a params object.\n * If no function is provided, the original params are returned unchanged.\n * The function receives a shallow copy of params, so the original is not mutated.\n *\n * @example\n * ```ts\n * import { transformParams } from 'feathers-utils/utils'\n *\n * const params = transformParams(context.params, (p) => { delete p.provider; return p })\n * ```\n *\n * @see https://utils.feathersjs.com/utils/transform-params.html\n */\nexport const transformParams = <P extends Params = Params>(\n  params: P,\n  fn: TransformParamsFn<P> | undefined,\n): P => {\n  if (!fn) {\n    return params\n  }\n\n  const result = fn({ ...params })\n\n  return result ?? params\n}\n","import type { Application, HookContext } from '@feathersjs/feathers'\nimport type { KeyOf, NeverFallback } from '../../internal.utils.js'\nimport type { InferFindResultSingle } from '../../utility-types/infer-service-methods.js'\n\n/**\n * The standard Feathers service events, plus any custom event name a service\n * might emit.\n */\nexport type ServiceEventName =\n  | 'created'\n  | 'updated'\n  | 'patched'\n  | 'removed'\n  | (string & {})\n\nexport type WaitForServiceEventOptions<Result = unknown> = {\n  /**\n   * Reject after this many milliseconds. Pass `false` to wait indefinitely.\n   *\n   * @default 5000\n   */\n  timeout?: number | false\n  /**\n   * Only resolve for events whose data passes this predicate. Receives the\n   * emitted record and the `HookContext` (the second argument Feathers emits).\n   */\n  filter?: (data: Result, context: HookContext) => boolean\n  /**\n   * Abort waiting via an `AbortSignal`. The promise rejects with the signal's\n   * `reason` (or a generic abort error) and all listeners are detached.\n   */\n  signal?: AbortSignal\n}\n\n/**\n * Service-agnostic defaults that can be bound once when currying with the app.\n * `filter` is intentionally omitted because it depends on the per-service\n * record type.\n */\nexport type WaitForServiceEventDefaults = Pick<\n  WaitForServiceEventOptions,\n  'timeout' | 'signal'\n>\n\nexport type WaitForServiceEventResult<Event extends string, Result> = [\n  /** The emitted record. */\n  data: Result,\n  meta: {\n    /** The event that fired (one of the requested events). */\n    event: Event\n    /** The `HookContext` Feathers emitted alongside the record. */\n    context: HookContext\n  },\n]\n\n/**\n * Wait for a service event to fire and resolve with the emitted record. Useful\n * in tests to await the result of an asynchronous service event, a bit like\n * `promisify` for Feathers events.\n *\n * Curried: bind the `app` (and optional defaults) once, then call the returned\n * function per service/event. Resolves with a `[data, { event, context }]`\n * tuple: `data` is typed as the service's record type, and `event` is the union\n * of the requested events.\n *\n * Feathers emits events as `emit(event, record, context)` and fires one event\n * per record, so each resolution carries a single record and its `HookContext`.\n *\n * @example\n * ```ts\n * import { waitForServiceEvent } from 'feathers-utils/utils'\n *\n * const app = feathers()\n * const waitForEvent = waitForServiceEvent(app)\n *\n * // Wait for the next `users` record to be created.\n * const [user] = await waitForEvent('users', 'created')\n *\n * // Wait for a specific record, with a custom timeout and filter.\n * const [data, { event }] = await waitForEvent(\n *   'users',\n *   ['created', 'patched'],\n *   { filter: (user) => user.email === 'jane@example.com', timeout: 1000 },\n * )\n * ```\n *\n * @see https://utils.feathersjs.com/utils/wait-for-service-event.html\n */\nexport function waitForServiceEvent<Services>(\n  app: Application<Services>,\n  defaultOptions?: WaitForServiceEventDefaults,\n) {\n  return function waitForEvent<\n    Path extends KeyOf<Services>,\n    const Event extends ServiceEventName,\n    Service extends Services[Path] = Services[Path],\n    Result = NeverFallback<InferFindResultSingle<Service>, unknown>,\n  >(\n    servicePath: Path,\n    eventOrEvents: Event | Event[],\n    options?: WaitForServiceEventOptions<Result>,\n  ): Promise<WaitForServiceEventResult<Event, Result>> {\n    const events = (\n      Array.isArray(eventOrEvents) ? eventOrEvents : [eventOrEvents]\n    ) as Event[]\n\n    const timeout = options?.timeout ?? defaultOptions?.timeout ?? 5000\n    const filter = options?.filter\n    const signal = options?.signal ?? defaultOptions?.signal\n\n    const service = app.service(servicePath)\n\n    return new Promise<WaitForServiceEventResult<Event, Result>>(\n      (resolve, reject) => {\n        let timer: ReturnType<typeof setTimeout> | undefined\n\n        // [event, listener] pairs so we know which event fired (Node's\n        // EventEmitter does not pass the event name to the listener) and can\n        // detach each listener precisely on cleanup.\n        const listeners = events.map((event) => {\n          const listener = (data: Result, context: HookContext) => {\n            if (filter && !filter(data, context)) {\n              return\n            }\n            cleanup()\n            resolve([data, { event, context }])\n          }\n          return [event, listener] as const\n        })\n\n        const abortError = () =>\n          signal?.reason ??\n          new Error(\n            `Aborted waiting for event \"${events.join(', ')}\" on service \"${String(servicePath)}\"`,\n          )\n\n        const onAbort = () => {\n          cleanup()\n          reject(abortError())\n        }\n\n        function cleanup() {\n          if (timer) {\n            clearTimeout(timer)\n            timer = undefined\n          }\n          for (const [event, listener] of listeners) {\n            ;(service as any).off(event, listener)\n          }\n          signal?.removeEventListener('abort', onAbort)\n        }\n\n        if (signal?.aborted) {\n          reject(abortError())\n          return\n        }\n\n        if (timeout !== false) {\n          timer = setTimeout(() => {\n            cleanup()\n            reject(\n              new Error(\n                `Timeout waiting for event \"${events.join(', ')}\" on service \"${String(servicePath)}\"`,\n              ),\n            )\n          }, timeout)\n        }\n\n        signal?.addEventListener('abort', onAbort, { once: true })\n\n        for (const [event, listener] of listeners) {\n          ;(service as any).on(event, listener)\n        }\n      },\n    )\n  }\n}\n","import type { HookContext } from '@feathersjs/feathers'\nimport { getDataIsArray } from '../get-data-is-array/get-data-is-array.util.js'\nimport { getResultIsArray } from '../get-result-is-array/get-result-is-array.util.js'\nimport { checkContext } from '../check-context/check-context.util.js'\nimport type {\n  DataSingleHookContext,\n  ResultSingleHookContext,\n} from '../../utility-types/hook-context.js'\n\nexport type ZipDataResultOptions = {\n  onMismatch?: (context: HookContext) => void\n}\n\nexport type ZipDataResultItem<D, R> = {\n  data: D | undefined\n  result: R | undefined\n}\n\n/**\n * Pairs each item in `context.data` with its corresponding item in `context.result` by index.\n * Handles both single-item and array data, normalizing them into an array of `{ data, result }` pairs.\n * Only works in `after`/`around` hooks for `create`, `update`, and `patch` methods.\n *\n * @example\n * ```ts\n * import { zipDataResult } from 'feathers-utils/utils'\n *\n * const pairs = zipDataResult(context)\n * pairs.forEach(({ data, result }) => { /* process each pair *\\/ })\n * ```\n *\n * @see https://utils.feathersjs.com/utils/zip-data-result.html\n */\nexport function zipDataResult<\n  H extends HookContext,\n  D extends DataSingleHookContext<H> = DataSingleHookContext<H>,\n  R extends ResultSingleHookContext<H> = ResultSingleHookContext<H>,\n>(context: H, options?: ZipDataResultOptions): ZipDataResultItem<D, R>[] {\n  checkContext(context, ['after', 'around'], ['create', 'update', 'patch'])\n\n  const input = getDataIsArray(context)\n  const output = getResultIsArray(context)\n\n  if (\n    input.isArray &&\n    output.isArray &&\n    input.data.length !== output.result.length\n  ) {\n    options?.onMismatch?.(context)\n  }\n\n  const result: ZipDataResultItem<D, R>[] = []\n\n  const length = Math.max(input.data.length, output.result.length)\n\n  for (let i = 0; i < length; i++) {\n    const dataItem = input.isArray ? input.data.at(i) : input.data[0]\n    const resultItem = output.result.at(i)\n\n    result.push({\n      data: dataItem,\n      result: resultItem,\n    })\n  }\n\n  return result\n}\n"],"mappings":"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"}