feathers-utils 10.0.0 → 10.0.2

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 (80) hide show
  1. package/dist/{hooks-DPFxxjBu.mjs → hooks-yFJ5FmU5.mjs} +115 -99
  2. package/dist/hooks-yFJ5FmU5.mjs.map +1 -0
  3. package/dist/hooks.d.mts +98 -29
  4. package/dist/hooks.mjs +4 -4
  5. package/dist/{index-CNrzxmWo.d.mts → index-CgAuzxiv.d.mts} +49 -4
  6. package/dist/index.d.mts +4 -4
  7. package/dist/index.mjs +7 -7
  8. package/dist/{internal.utils-BWQ25nOd.mjs → internal.utils-3BrB8lRY.mjs} +8 -2
  9. package/dist/internal.utils-3BrB8lRY.mjs.map +1 -0
  10. package/dist/{mutate-result.util-CCBWix-G.mjs → mutate-result.util-B6FOkwrd.mjs} +73 -11
  11. package/dist/mutate-result.util-B6FOkwrd.mjs.map +1 -0
  12. package/dist/{predicates-CT08opkD.mjs → predicates-BC8p_YLo.mjs} +27 -24
  13. package/dist/predicates-BC8p_YLo.mjs.map +1 -0
  14. package/dist/predicates.d.mts +2 -2
  15. package/dist/predicates.mjs +1 -1
  16. package/dist/{resolve-Cx9osy8O.mjs → resolve-ClHfNFlm.mjs} +3 -3
  17. package/dist/resolve-ClHfNFlm.mjs.map +1 -0
  18. package/dist/resolvers.mjs +1 -1
  19. package/dist/{transform-result.hook-BUwLePT2.d.mts → transform-result.hook-C8-4Lezj.d.mts} +8 -5
  20. package/dist/{transform-result.hook-CevWK5TA.mjs → transform-result.hook-CanJtTPV.mjs} +13 -12
  21. package/dist/transform-result.hook-CanJtTPV.mjs.map +1 -0
  22. package/dist/transformers.d.mts +1 -1
  23. package/dist/transformers.mjs +8 -4
  24. package/dist/transformers.mjs.map +1 -1
  25. package/dist/{unless.hook-BYWO9hzO.d.mts → unless.hook-BX0mOvdN.d.mts} +6 -3
  26. package/dist/{utils-1I_iPZkV.mjs → utils-BrvpblXB.mjs} +38 -19
  27. package/dist/utils-BrvpblXB.mjs.map +1 -0
  28. package/dist/utils.d.mts +2 -2
  29. package/dist/utils.mjs +4 -4
  30. package/package.json +1 -1
  31. package/src/common/clone.ts +9 -7
  32. package/src/hooks/cache/cache-utils.ts +5 -18
  33. package/src/hooks/cache/cache.hook.ts +37 -16
  34. package/src/hooks/check-multi/check-multi.hook.ts +5 -2
  35. package/src/hooks/check-required/check-required.hook.ts +6 -1
  36. package/src/hooks/create-related/create-related.hook.ts +2 -2
  37. package/src/hooks/debug/debug.hook.ts +1 -1
  38. package/src/hooks/disable-pagination/disable-pagination.hook.ts +7 -4
  39. package/src/hooks/disallow/disallow.hook.ts +10 -3
  40. package/src/hooks/on-delete/on-delete.hook.ts +61 -41
  41. package/src/hooks/params-for-server/params-for-server.hook.ts +16 -5
  42. package/src/hooks/params-from-client/params-from-client.hook.ts +10 -6
  43. package/src/hooks/rate-limit/rate-limit.hook.ts +2 -2
  44. package/src/hooks/set-data/set-data.hook.ts +8 -7
  45. package/src/hooks/set-field/set-field.hook.ts +42 -17
  46. package/src/hooks/set-result/set-result.hook.ts +16 -3
  47. package/src/hooks/set-slug/set-slug.hook.ts +8 -6
  48. package/src/hooks/skippable/skippable.hook.ts +17 -12
  49. package/src/hooks/soft-delete/soft-delete.hook.ts +4 -5
  50. package/src/hooks/stashable/stashable.hook.ts +9 -8
  51. package/src/hooks/throw-if/throw-if.hook.ts +2 -2
  52. package/src/hooks/transform-data/transform-data.hook.ts +2 -4
  53. package/src/hooks/transform-query/transform-query.hook.ts +6 -5
  54. package/src/hooks/transform-result/transform-result.hook.ts +6 -9
  55. package/src/hooks/traverse/traverse.hook.ts +30 -10
  56. package/src/internal.utils.ts +6 -1
  57. package/src/predicates/and/and.predicate.ts +5 -5
  58. package/src/predicates/is-context/is-context.predicate.ts +1 -1
  59. package/src/predicates/or/or.predicate.ts +6 -8
  60. package/src/resolvers/resolve-result/resolve-result.ts +4 -1
  61. package/src/transformers/parse-date/parse-date.transformer.ts +6 -1
  62. package/src/utils/chunk-find/chunk-find.util.ts +7 -0
  63. package/src/utils/combine/combine.util.ts +8 -15
  64. package/src/utils/get-paginate/get-paginate.util.ts +1 -3
  65. package/src/utils/index.ts +2 -0
  66. package/src/utils/iterate-find/iterate-find.util.ts +8 -0
  67. package/src/utils/mutate-data/mutate-data.util.ts +21 -4
  68. package/src/utils/mutate-result/mutate-result.util.ts +4 -10
  69. package/src/utils/patch-batch/patch-batch.util.ts +32 -14
  70. package/src/utils/replace-data/replace-data.util.ts +26 -0
  71. package/src/utils/replace-result/replace-result.util.ts +60 -0
  72. package/src/utils/sort-query-properties/sort-query-properties.util.ts +15 -8
  73. package/src/utils/walk-query/walk-query.util.ts +2 -2
  74. package/dist/hooks-DPFxxjBu.mjs.map +0 -1
  75. package/dist/internal.utils-BWQ25nOd.mjs.map +0 -1
  76. package/dist/mutate-result.util-CCBWix-G.mjs.map +0 -1
  77. package/dist/predicates-CT08opkD.mjs.map +0 -1
  78. package/dist/resolve-Cx9osy8O.mjs.map +0 -1
  79. package/dist/transform-result.hook-CevWK5TA.mjs.map +0 -1
  80. package/dist/utils-1I_iPZkV.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"transformers.mjs","names":[],"sources":["../src/transformers/defaults/defaults.transformer.ts","../src/transformers/lowercase/lowercase.transformer.ts","../src/transformers/omit/omit.transformer.ts","../src/transformers/parse-date/parse-date.transformer.ts","../src/transformers/pick/pick.transformer.ts","../src/transformers/set-now/set-now.transformer.ts","../src/transformers/trim/trim.transformer.ts"],"sourcesContent":["import _get from 'lodash/get.js'\nimport _set from 'lodash/set.js'\nimport type { DefaultsInput } from '../../types.js'\n\n/**\n * Sets default values on an item for fields that are `undefined`.\n * Values can be static or functions that return a value.\n * Supports dot.notation for nested fields.\n *\n * @example\n * ```ts\n * import { transformData, defaults } from 'feathers-utils/transformers'\n *\n * transformData(item => defaults(item, { role: 'user', createdAt: () => new Date() }))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/defaults.html\n */\nexport function defaults<T extends Record<string, any>>(\n item: T,\n defaultValues: DefaultsInput<NoInfer<T>>,\n): void {\n const entries = Object.entries(defaultValues)\n\n for (let i = 0, len = entries.length; i < len; i++) {\n const [key, value] = entries[i]\n\n if (_get(item, key) === undefined) {\n _set(item, key, typeof value === 'function' ? value() : value)\n }\n }\n}\n","import _get from 'lodash/get.js'\nimport _set from 'lodash/set.js'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport { BadRequest } from '@feathersjs/errors'\nimport type { StringFieldKey } from '../../types.js'\n\n/**\n * Transforms the specified fields of an item to lowercase.\n *\n * @example\n * ```ts\n * import { transformData, lowercase } from 'feathers-utils/transformers'\n *\n * transformData(item => lowercase(item, 'email'))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/lowercase.html\n */\nexport function lowercase<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<StringFieldKey<NoInfer<T>>>,\n): void {\n const fieldNamesArr = toArray(fieldNames)\n\n for (let i = 0, len = fieldNamesArr.length; i < len; i++) {\n const fieldName = fieldNamesArr[i]\n const value = _get(item, fieldName)\n\n if (value == null) {\n continue\n }\n\n if (typeof value !== 'string') {\n throw new BadRequest(`Expected string (lowercase '${fieldName}')`)\n }\n\n _set(item, fieldName, value.toLowerCase())\n }\n}\n","import _omit from 'lodash/omit.js'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport type { FieldKey } from '../../types.js'\n\n/**\n * Omit the specified fields from an item.\n *\n * @example\n * ```ts\n * import { transformData, omit } from 'feathers-utils/transformers'\n *\n * transformData(item => omit(item, 'email'))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/omit.html\n */\nexport function omit<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<FieldKey<NoInfer<T>>>,\n): T {\n return _omit(item, toArray(fieldNames)) as T\n}\n","import { toArray, type MaybeArray } from '../../internal.utils.js'\nimport _get from 'lodash/get.js'\nimport _set from 'lodash/set.js'\nimport type { FieldKey } from '../../types.js'\n\n/**\n * Parses the specified fields of an item into Date objects.\n *\n * @example\n * ```ts\n * import { transformData, parseDate } from 'feathers-utils/transformers'\n *\n * transformData(item => parseDate(item, ['startDate', 'endDate']))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/parse-date.html\n */\nexport function parseDate<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<FieldKey<NoInfer<T>>>,\n): void {\n const fieldNamesArr = toArray(fieldNames)\n\n for (let i = 0, len = fieldNamesArr.length; i < len; i++) {\n const key = fieldNamesArr[i]\n const value = _get(item, key)\n if (value) {\n _set(item, key, new Date(value))\n }\n }\n}\n","import _pick from 'lodash/pick.js'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport type { FieldKey } from '../../types.js'\n\n/**\n * Picks the specified fields from an item.\n *\n * @example\n * ```ts\n * import { transformData, pick } from 'feathers-utils/transformers'\n *\n * transformData(item => pick(item, 'email'))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/pick.html\n */\nexport function pick<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<FieldKey<NoInfer<T>>>,\n): Partial<T> {\n return _pick(item, toArray(fieldNames)) as Partial<T>\n}\n","import _set from 'lodash/set.js'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport type { FieldKey } from '../../types.js'\n\n/**\n * Sets the specified fields of an item to the current date and time.\n *\n * @example\n * ```ts\n * import { transformData, setNow } from 'feathers-utils/transformers'\n *\n * transformData(item => setNow(item, ['createdAt', 'updatedAt']))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/set-now.html\n */\nexport function setNow<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<FieldKey<NoInfer<T>>>,\n): void {\n const fieldNamesArr = toArray(fieldNames)\n const now = new Date()\n\n for (let i = 0, len = fieldNamesArr.length; i < len; i++) {\n const fieldName = fieldNamesArr[i]\n _set(item, fieldName, now)\n }\n}\n","import { BadRequest } from '@feathersjs/errors'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport _get from 'lodash/get.js'\nimport _set from 'lodash/set.js'\nimport type { StringFieldKey } from '../../types.js'\n\n/**\n * Trims the specified fields of an item.\n *\n * @example\n * ```ts\n * import { transformData, trim } from 'feathers-utils/transformers'\n *\n * transformData(item => trim(item, 'password'))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/trim.html\n */\nexport function trim<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<StringFieldKey<NoInfer<T>>>,\n): void {\n const fieldNamesArr = toArray(fieldNames)\n\n for (let i = 0, len = fieldNamesArr.length; i < len; i++) {\n const fieldName = fieldNamesArr[i]\n const value = _get(item, fieldName)\n\n if (value == null) {\n continue\n }\n\n if (typeof value !== 'string') {\n throw new BadRequest(`Expected string (trim '${fieldName}')`)\n }\n\n _set(item, fieldName, value.trim())\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAkBA,SAAgB,SACd,MACA,eACM;CACN,MAAM,UAAU,OAAO,QAAQ,cAAc;CAE7C,KAAK,IAAI,IAAI,GAAG,MAAM,QAAQ,QAAQ,IAAI,KAAK,KAAK;EAClD,MAAM,CAAC,KAAK,SAAS,QAAQ;EAE7B,IAAI,KAAK,MAAM,IAAI,KAAK,KAAA,GACtB,KAAK,MAAM,KAAK,OAAO,UAAU,aAAa,OAAO,GAAG,MAAM;;;;;;;;;;;;;;;;;ACTpE,SAAgB,UACd,MACA,YACM;CACN,MAAM,gBAAgB,QAAQ,WAAW;CAEzC,KAAK,IAAI,IAAI,GAAG,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK;EACxD,MAAM,YAAY,cAAc;EAChC,MAAM,QAAQ,KAAK,MAAM,UAAU;EAEnC,IAAI,SAAS,MACX;EAGF,IAAI,OAAO,UAAU,UACnB,MAAM,IAAI,WAAW,+BAA+B,UAAU,IAAI;EAGpE,KAAK,MAAM,WAAW,MAAM,aAAa,CAAC;;;;;;;;;;;;;;;;;ACpB9C,SAAgB,KACd,MACA,YACG;CACH,OAAO,MAAM,MAAM,QAAQ,WAAW,CAAC;;;;;;;;;;;;;;;;ACJzC,SAAgB,UACd,MACA,YACM;CACN,MAAM,gBAAgB,QAAQ,WAAW;CAEzC,KAAK,IAAI,IAAI,GAAG,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK;EACxD,MAAM,MAAM,cAAc;EAC1B,MAAM,QAAQ,KAAK,MAAM,IAAI;EAC7B,IAAI,OACF,KAAK,MAAM,KAAK,IAAI,KAAK,MAAM,CAAC;;;;;;;;;;;;;;;;;ACVtC,SAAgB,KACd,MACA,YACY;CACZ,OAAO,MAAM,MAAM,QAAQ,WAAW,CAAC;;;;;;;;;;;;;;;;ACJzC,SAAgB,OACd,MACA,YACM;CACN,MAAM,gBAAgB,QAAQ,WAAW;CACzC,MAAM,sBAAM,IAAI,MAAM;CAEtB,KAAK,IAAI,IAAI,GAAG,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK;EACxD,MAAM,YAAY,cAAc;EAChC,KAAK,MAAM,WAAW,IAAI;;;;;;;;;;;;;;;;;ACP9B,SAAgB,KACd,MACA,YACM;CACN,MAAM,gBAAgB,QAAQ,WAAW;CAEzC,KAAK,IAAI,IAAI,GAAG,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK;EACxD,MAAM,YAAY,cAAc;EAChC,MAAM,QAAQ,KAAK,MAAM,UAAU;EAEnC,IAAI,SAAS,MACX;EAGF,IAAI,OAAO,UAAU,UACnB,MAAM,IAAI,WAAW,0BAA0B,UAAU,IAAI;EAG/D,KAAK,MAAM,WAAW,MAAM,MAAM,CAAC"}
1
+ {"version":3,"file":"transformers.mjs","names":[],"sources":["../src/transformers/defaults/defaults.transformer.ts","../src/transformers/lowercase/lowercase.transformer.ts","../src/transformers/omit/omit.transformer.ts","../src/transformers/parse-date/parse-date.transformer.ts","../src/transformers/pick/pick.transformer.ts","../src/transformers/set-now/set-now.transformer.ts","../src/transformers/trim/trim.transformer.ts"],"sourcesContent":["import _get from 'lodash/get.js'\nimport _set from 'lodash/set.js'\nimport type { DefaultsInput } from '../../types.js'\n\n/**\n * Sets default values on an item for fields that are `undefined`.\n * Values can be static or functions that return a value.\n * Supports dot.notation for nested fields.\n *\n * @example\n * ```ts\n * import { transformData, defaults } from 'feathers-utils/transformers'\n *\n * transformData(item => defaults(item, { role: 'user', createdAt: () => new Date() }))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/defaults.html\n */\nexport function defaults<T extends Record<string, any>>(\n item: T,\n defaultValues: DefaultsInput<NoInfer<T>>,\n): void {\n const entries = Object.entries(defaultValues)\n\n for (let i = 0, len = entries.length; i < len; i++) {\n const [key, value] = entries[i]\n\n if (_get(item, key) === undefined) {\n _set(item, key, typeof value === 'function' ? value() : value)\n }\n }\n}\n","import _get from 'lodash/get.js'\nimport _set from 'lodash/set.js'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport { BadRequest } from '@feathersjs/errors'\nimport type { StringFieldKey } from '../../types.js'\n\n/**\n * Transforms the specified fields of an item to lowercase.\n *\n * @example\n * ```ts\n * import { transformData, lowercase } from 'feathers-utils/transformers'\n *\n * transformData(item => lowercase(item, 'email'))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/lowercase.html\n */\nexport function lowercase<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<StringFieldKey<NoInfer<T>>>,\n): void {\n const fieldNamesArr = toArray(fieldNames)\n\n for (let i = 0, len = fieldNamesArr.length; i < len; i++) {\n const fieldName = fieldNamesArr[i]\n const value = _get(item, fieldName)\n\n if (value == null) {\n continue\n }\n\n if (typeof value !== 'string') {\n throw new BadRequest(`Expected string (lowercase '${fieldName}')`)\n }\n\n _set(item, fieldName, value.toLowerCase())\n }\n}\n","import _omit from 'lodash/omit.js'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport type { FieldKey } from '../../types.js'\n\n/**\n * Omit the specified fields from an item.\n *\n * @example\n * ```ts\n * import { transformData, omit } from 'feathers-utils/transformers'\n *\n * transformData(item => omit(item, 'email'))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/omit.html\n */\nexport function omit<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<FieldKey<NoInfer<T>>>,\n): T {\n return _omit(item, toArray(fieldNames)) as T\n}\n","import { BadRequest } from '@feathersjs/errors'\nimport { toArray, type MaybeArray } from '../../internal.utils.js'\nimport _get from 'lodash/get.js'\nimport _set from 'lodash/set.js'\nimport type { FieldKey } from '../../types.js'\n\n/**\n * Parses the specified fields of an item into Date objects.\n *\n * @example\n * ```ts\n * import { transformData, parseDate } from 'feathers-utils/transformers'\n *\n * transformData(item => parseDate(item, ['startDate', 'endDate']))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/parse-date.html\n */\nexport function parseDate<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<FieldKey<NoInfer<T>>>,\n): void {\n const fieldNamesArr = toArray(fieldNames)\n\n for (let i = 0, len = fieldNamesArr.length; i < len; i++) {\n const key = fieldNamesArr[i]\n const value = _get(item, key)\n if (value) {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) {\n throw new BadRequest(`Expected valid date (parseDate '${key}')`)\n }\n _set(item, key, date)\n }\n }\n}\n","import _pick from 'lodash/pick.js'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport type { FieldKey } from '../../types.js'\n\n/**\n * Picks the specified fields from an item.\n *\n * @example\n * ```ts\n * import { transformData, pick } from 'feathers-utils/transformers'\n *\n * transformData(item => pick(item, 'email'))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/pick.html\n */\nexport function pick<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<FieldKey<NoInfer<T>>>,\n): Partial<T> {\n return _pick(item, toArray(fieldNames)) as Partial<T>\n}\n","import _set from 'lodash/set.js'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport type { FieldKey } from '../../types.js'\n\n/**\n * Sets the specified fields of an item to the current date and time.\n *\n * @example\n * ```ts\n * import { transformData, setNow } from 'feathers-utils/transformers'\n *\n * transformData(item => setNow(item, ['createdAt', 'updatedAt']))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/set-now.html\n */\nexport function setNow<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<FieldKey<NoInfer<T>>>,\n): void {\n const fieldNamesArr = toArray(fieldNames)\n const now = new Date()\n\n for (let i = 0, len = fieldNamesArr.length; i < len; i++) {\n const fieldName = fieldNamesArr[i]\n _set(item, fieldName, now)\n }\n}\n","import { BadRequest } from '@feathersjs/errors'\nimport type { MaybeArray } from '../../internal.utils.js'\nimport { toArray } from '../../internal.utils.js'\nimport _get from 'lodash/get.js'\nimport _set from 'lodash/set.js'\nimport type { StringFieldKey } from '../../types.js'\n\n/**\n * Trims the specified fields of an item.\n *\n * @example\n * ```ts\n * import { transformData, trim } from 'feathers-utils/transformers'\n *\n * transformData(item => trim(item, 'password'))\n * ```\n *\n * @see https://utils.feathersjs.com/transformers/trim.html\n */\nexport function trim<T extends Record<string, any>>(\n item: T,\n fieldNames: MaybeArray<StringFieldKey<NoInfer<T>>>,\n): void {\n const fieldNamesArr = toArray(fieldNames)\n\n for (let i = 0, len = fieldNamesArr.length; i < len; i++) {\n const fieldName = fieldNamesArr[i]\n const value = _get(item, fieldName)\n\n if (value == null) {\n continue\n }\n\n if (typeof value !== 'string') {\n throw new BadRequest(`Expected string (trim '${fieldName}')`)\n }\n\n _set(item, fieldName, value.trim())\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAkBA,SAAgB,SACd,MACA,eACM;CACN,MAAM,UAAU,OAAO,QAAQ,cAAc;CAE7C,KAAK,IAAI,IAAI,GAAG,MAAM,QAAQ,QAAQ,IAAI,KAAK,KAAK;EAClD,MAAM,CAAC,KAAK,SAAS,QAAQ;EAE7B,IAAI,KAAK,MAAM,IAAI,KAAK,KAAA,GACtB,KAAK,MAAM,KAAK,OAAO,UAAU,aAAa,OAAO,GAAG,MAAM;;;;;;;;;;;;;;;;;ACTpE,SAAgB,UACd,MACA,YACM;CACN,MAAM,gBAAgB,QAAQ,WAAW;CAEzC,KAAK,IAAI,IAAI,GAAG,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK;EACxD,MAAM,YAAY,cAAc;EAChC,MAAM,QAAQ,KAAK,MAAM,UAAU;EAEnC,IAAI,SAAS,MACX;EAGF,IAAI,OAAO,UAAU,UACnB,MAAM,IAAI,WAAW,+BAA+B,UAAU,IAAI;EAGpE,KAAK,MAAM,WAAW,MAAM,aAAa,CAAC;;;;;;;;;;;;;;;;;ACpB9C,SAAgB,KACd,MACA,YACG;CACH,OAAO,MAAM,MAAM,QAAQ,WAAW,CAAC;;;;;;;;;;;;;;;;ACHzC,SAAgB,UACd,MACA,YACM;CACN,MAAM,gBAAgB,QAAQ,WAAW;CAEzC,KAAK,IAAI,IAAI,GAAG,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK;EACxD,MAAM,MAAM,cAAc;EAC1B,MAAM,QAAQ,KAAK,MAAM,IAAI;EAC7B,IAAI,OAAO;GACT,MAAM,OAAO,IAAI,KAAK,MAAM;GAC5B,IAAI,OAAO,MAAM,KAAK,SAAS,CAAC,EAC9B,MAAM,IAAI,WAAW,mCAAmC,IAAI,IAAI;GAElE,KAAK,MAAM,KAAK,KAAK;;;;;;;;;;;;;;;;;;ACf3B,SAAgB,KACd,MACA,YACY;CACZ,OAAO,MAAM,MAAM,QAAQ,WAAW,CAAC;;;;;;;;;;;;;;;;ACJzC,SAAgB,OACd,MACA,YACM;CACN,MAAM,gBAAgB,QAAQ,WAAW;CACzC,MAAM,sBAAM,IAAI,MAAM;CAEtB,KAAK,IAAI,IAAI,GAAG,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK;EACxD,MAAM,YAAY,cAAc;EAChC,KAAK,MAAM,WAAW,IAAI;;;;;;;;;;;;;;;;;ACP9B,SAAgB,KACd,MACA,YACM;CACN,MAAM,gBAAgB,QAAQ,WAAW;CAEzC,KAAK,IAAI,IAAI,GAAG,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK;EACxD,MAAM,YAAY,cAAc;EAChC,MAAM,QAAQ,KAAK,MAAM,UAAU;EAEnC,IAAI,SAAS,MACX;EAGF,IAAI,OAAO,UAAU,UACnB,MAAM,IAAI,WAAW,0BAA0B,UAAU,IAAI;EAG/D,KAAK,MAAM,WAAW,MAAM,MAAM,CAAC"}
@@ -63,7 +63,10 @@ declare function iff<H extends HookContext = HookContext>(predicate: boolean | P
63
63
  *
64
64
  * @see https://utils.feathersjs.com/hooks/skippable.html
65
65
  */
66
- declare const skippable: <H extends HookContext = HookContext>(hook: HookFunction<H>, predicate: PredicateFn<H>) => (context: H, next?: NextFunction) => void | Promise<any> | H;
66
+ declare const skippable: <H extends HookContext = HookContext>(innerHook: HookFunction<H>, predicate: PredicateFn<H>) => {
67
+ (context: H): H | void | Promise<H | void>;
68
+ (context: H, next: NextFunction): Promise<void>;
69
+ };
67
70
  //#endregion
68
71
  //#region src/hooks/throw-if/throw-if.hook.d.ts
69
72
  type ThrowIfOptions = {
@@ -90,7 +93,7 @@ type ThrowIfOptions = {
90
93
  *
91
94
  * @see https://utils.feathersjs.com/hooks/throw-if.html
92
95
  */
93
- declare const throwIf: <H extends HookContext = HookContext>(predicate: PredicateFn, options?: ThrowIfOptions) => (context: H, next?: NextFunction) => Promise<any>;
96
+ declare const throwIf: <H extends HookContext = HookContext>(predicate: PredicateFn, options?: ThrowIfOptions) => (context: H, next?: NextFunction) => Promise<void>;
94
97
  //#endregion
95
98
  //#region src/hooks/unless/unless.hook.d.ts
96
99
  /**
@@ -112,4 +115,4 @@ declare const throwIf: <H extends HookContext = HookContext>(predicate: Predicat
112
115
  declare function unless<H extends HookContext = HookContext>(predicate: boolean | PredicateFn, ...hooks: HookFunction<H>[]): (this: any, ctx: H, next?: _$_feathersjs_feathers0.NextFunction) => HookContext<_$_feathersjs_feathers0.Application<any, any>, any> | Promise<any>;
113
116
  //#endregion
114
117
  export { IffHook as a, skippable as i, ThrowIfOptions as n, iff as o, throwIf as r, iffElse as s, unless as t };
115
- //# sourceMappingURL=unless.hook-BYWO9hzO.d.mts.map
118
+ //# sourceMappingURL=unless.hook-BX0mOvdN.d.mts.map
@@ -1,6 +1,5 @@
1
- import { d as isPaginated, m as isContext, p as isMulti } from "./predicates-CT08opkD.mjs";
2
- import { i as getDataIsArray, r as getResultIsArray } from "./mutate-result.util-CCBWix-G.mjs";
3
- import isObject from "lodash/isObject.js";
1
+ import { d as isPaginated, m as isContext, p as isMulti } from "./predicates-BC8p_YLo.mjs";
2
+ import { a as getResultIsArray, o as getDataIsArray } from "./mutate-result.util-B6FOkwrd.mjs";
4
3
  import { dequal } from "dequal";
5
4
  import * as feathers from "@feathersjs/feathers";
6
5
  //#region src/utils/sort-query-properties/sort-query-properties.util.ts
@@ -12,6 +11,7 @@ const arrayOperators = new Set([
12
11
  "$in",
13
12
  "$nin"
14
13
  ]);
14
+ const isPlainObjectLike = (value) => value !== null && typeof value === "object";
15
15
  /**
16
16
  * Recursively normalizes a Feathers query object for order-independent comparison.
17
17
  * Sorts object keys and sorts arrays within `$or`, `$and`, `$nor`, `$not`, `$in`,
@@ -40,11 +40,17 @@ const sortQueryProperties = (query) => {
40
40
  };
41
41
  const normalize = (value) => {
42
42
  if (Array.isArray(value)) return value.map(normalize);
43
- if (!isObject(value)) return value;
43
+ if (!isPlainObjectLike(value)) return value;
44
44
  const sorted = {};
45
45
  for (const key of Object.keys(value).sort()) {
46
46
  const val = value[key];
47
- if (arrayOperators.has(key) && Array.isArray(val)) sorted[key] = val.map(normalize).sort((a, b) => JSON.stringify(a) < JSON.stringify(b) ? -1 : 1);
47
+ if (arrayOperators.has(key) && Array.isArray(val)) sorted[key] = val.map((el) => {
48
+ const normalized = normalize(el);
49
+ return {
50
+ k: JSON.stringify(normalized),
51
+ v: normalized
52
+ };
53
+ }).sort((a, b) => a.k < b.k ? -1 : a.k > b.k ? 1 : 0).map((entry) => entry.v);
48
54
  else sorted[key] = normalize(val);
49
55
  }
50
56
  return sorted;
@@ -123,6 +129,7 @@ async function* chunkFind(app, servicePath, options) {
123
129
  let result;
124
130
  do {
125
131
  result = await service.find(params);
132
+ if (!result.data.length) break;
126
133
  yield result.data;
127
134
  params.query.$skip = (params.query.$skip ?? 0) + result.data.length;
128
135
  } while (result.total > params.query.$skip);
@@ -293,11 +300,15 @@ async function* iterateFind(app, servicePath, options) {
293
300
  $limit: options?.params?.query?.$limit,
294
301
  $skip: options?.params?.query?.$skip ?? 0
295
302
  },
296
- paginate: { default: options?.params?.paginate?.default ?? 10 }
303
+ paginate: {
304
+ default: options?.params?.paginate?.default ?? 10,
305
+ max: options?.params?.paginate?.max ?? 100
306
+ }
297
307
  };
298
308
  let result;
299
309
  do {
300
310
  result = await service.find(params);
311
+ if (!result.data.length) break;
301
312
  for (const item of result.data) yield item;
302
313
  params.query.$skip = (params.query.$skip ?? 0) + result.data.length;
303
314
  } while (result.total > params.query.$skip);
@@ -305,6 +316,14 @@ async function* iterateFind(app, servicePath, options) {
305
316
  //#endregion
306
317
  //#region src/utils/patch-batch/patch-batch.util.ts
307
318
  /**
319
+ * Deterministic, key-order-independent serialization used to group items with
320
+ * equal patch data in O(1) per item.
321
+ */
322
+ const stableKey = (value) => JSON.stringify(value, (_key, val) => val && typeof val === "object" && !Array.isArray(val) ? Object.keys(val).sort().reduce((acc, k) => {
323
+ acc[k] = val[k];
324
+ return acc;
325
+ }, {}) : val);
326
+ /**
308
327
  * 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.
309
328
  *
310
329
  * This utility is useful when you need to patch multiple items with varying data in as few requests as possible.
@@ -330,22 +349,22 @@ async function* iterateFind(app, servicePath, options) {
330
349
  * @see https://utils.feathersjs.com/utils/patch-batch.html
331
350
  */
332
351
  function patchBatch(items, options) {
333
- const map = [];
334
352
  const idKey = options?.id ?? "id";
335
- for (const _data of items) {
336
- const data = _data;
337
- const id = _data[idKey];
353
+ const groups = /* @__PURE__ */ new Map();
354
+ for (const item of items) {
355
+ const source = item;
356
+ const id = source[idKey];
357
+ const data = { ...source };
338
358
  delete data[idKey];
339
- const index = map.findIndex((item) => {
340
- return dequal(item.data, data);
341
- });
342
- if (index === -1) map.push({
359
+ const key = stableKey(data);
360
+ const existing = groups.get(key);
361
+ if (existing) existing.ids.push(id);
362
+ else groups.set(key, {
343
363
  ids: [id],
344
364
  data
345
365
  });
346
- else map[index].ids.push(id);
347
366
  }
348
- return map.map(({ ids, data }) => {
367
+ return [...groups.values()].map(({ ids, data }) => {
349
368
  return ids.length === 1 ? [
350
369
  ids[0],
351
370
  data,
@@ -452,7 +471,7 @@ const _walkQueryUtil = (query, walker, options) => {
452
471
  }
453
472
  query[key] = value;
454
473
  }
455
- for (const key in query) if ((key === "$or" || key === "$and" || key === "$nor" || key === "$not") && Array.isArray(query[key])) {
474
+ for (const key in query) if ((key === "$or" || key === "$and" || key === "$nor") && Array.isArray(query[key])) {
456
475
  let array = query[key];
457
476
  let copiedArray = false;
458
477
  for (let i = 0, n = array.length; i < n; i++) {
@@ -507,7 +526,7 @@ const _walkQueryUtil = (query, walker, options) => {
507
526
  return query;
508
527
  };
509
528
  /**
510
- * Walks every property of a Feathers query (including nested `$and`/`$or`/`$nor`/`$not` arrays)
529
+ * Walks every property of a Feathers query (including nested `$and`/`$or`/`$nor` arrays)
511
530
  * and calls the `walker` function for each one. The walker receives the property name, operator,
512
531
  * value, and path, and can return a replacement value. Returns a new query only if changes were made.
513
532
  *
@@ -567,4 +586,4 @@ function zipDataResult(context, options) {
567
586
  //#endregion
568
587
  export { skipResult as a, getExposedMethods as c, checkContext as d, addToQuery as f, sortQueryProperties as h, toPaginated as i, defineHooks as l, addSkip as m, walkQuery as n, patchBatch as o, chunkFind as p, transformParams as r, iterateFind as s, zipDataResult as t, contextToJson as u };
569
588
 
570
- //# sourceMappingURL=utils-1I_iPZkV.mjs.map
589
+ //# sourceMappingURL=utils-BrvpblXB.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-BrvpblXB.mjs","names":["deepEqual"],"sources":["../src/utils/sort-query-properties/sort-query-properties.util.ts","../src/utils/add-skip/add-skip.util.ts","../src/utils/chunk-find/chunk-find.util.ts","../src/utils/add-to-query/add-to-query.util.ts","../src/utils/check-context/check-context.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/patch-batch/patch-batch.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/walk-query/walk-query.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 { 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 { 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.\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 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 { 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 { 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 { 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 { 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\nexport type WalkQueryCallback = (options: WalkQueryOptions) => any\n\nconst _walkQueryUtil = <Q extends Query>(\n query: Q,\n walker: WalkQueryCallback,\n options?: WalkQueryOptionsInit | WalkQueryOptions,\n): Q => {\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 (\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 const nestedQuery = array[i]\n const transformed = _walkQueryUtil(nestedQuery, walker, {\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 (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 })\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 })\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 })\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, and path, and can return a replacement value. 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 * @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)\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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"}
package/dist/utils.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { A as SkipHookName, C as contextToJson, O as addToQuery, S as defineHooks, T as checkContext, _ as getResultIsArray, a as WalkQueryOptions, b as GetDataIsArrayReturn, c as transformParams, d as PatchBatchOptions, f as PatchBatchResultItem, g as GetResultIsArrayReturn, h as GetResultIsArrayOptions, i as WalkQueryCallback, j as addSkip, k as chunkFind, l as toPaginated, m as iterateFind, n as ZipDataResultOptions, o as walkQuery, p as patchBatch, r as zipDataResult, s as sortQueryProperties, t as ZipDataResultItem, u as skipResult, v as getPaginate, w as CheckContextOptions, x as getDataIsArray, y as getExposedMethods } from "./index-CNrzxmWo.mjs";
1
+ import { C as GetDataIsArrayReturn, D as CheckContextOptions, E as contextToJson, M as chunkFind, N as SkipHookName, O as checkContext, P as addSkip, S as getExposedMethods, T as defineHooks, _ as iterateFind, a as WalkQueryOptions, b as getResultIsArray, c as transformParams, d as ReplaceResultOptions, f as replaceResult, g as patchBatch, h as PatchBatchResultItem, i as WalkQueryCallback, j as addToQuery, l as toPaginated, m as PatchBatchOptions, n as ZipDataResultOptions, o as walkQuery, p as replaceData, r as zipDataResult, s as sortQueryProperties, t as ZipDataResultItem, u as skipResult, v as GetResultIsArrayOptions, w as getDataIsArray, x as getPaginate, y as GetResultIsArrayReturn } from "./index-CgAuzxiv.mjs";
2
2
  import { n as mutateResult, r as mutateData, t as MutateResultOptions } from "./mutate-result.util-BIeYlqqT.mjs";
3
- export { CheckContextOptions, GetDataIsArrayReturn, GetResultIsArrayOptions, GetResultIsArrayReturn, MutateResultOptions, PatchBatchOptions, PatchBatchResultItem, SkipHookName, WalkQueryCallback, WalkQueryOptions, ZipDataResultItem, ZipDataResultOptions, addSkip, addToQuery, checkContext, chunkFind, contextToJson, defineHooks, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, iterateFind, mutateData, mutateResult, patchBatch, skipResult, sortQueryProperties, toPaginated, transformParams, walkQuery, zipDataResult };
3
+ export { CheckContextOptions, GetDataIsArrayReturn, GetResultIsArrayOptions, GetResultIsArrayReturn, MutateResultOptions, PatchBatchOptions, PatchBatchResultItem, ReplaceResultOptions, SkipHookName, WalkQueryCallback, WalkQueryOptions, ZipDataResultItem, ZipDataResultOptions, addSkip, addToQuery, checkContext, chunkFind, contextToJson, defineHooks, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, iterateFind, mutateData, mutateResult, patchBatch, replaceData, replaceResult, skipResult, sortQueryProperties, toPaginated, transformParams, walkQuery, zipDataResult };
package/dist/utils.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { f as getPaginate } from "./predicates-CT08opkD.mjs";
2
- import { a as skipResult, c as getExposedMethods, d as checkContext, f as addToQuery, h as sortQueryProperties, i as toPaginated, l as defineHooks, m as addSkip, n as walkQuery, o as patchBatch, p as chunkFind, r as transformParams, s as iterateFind, t as zipDataResult, u as contextToJson } from "./utils-1I_iPZkV.mjs";
3
- import { i as getDataIsArray, n as mutateData, r as getResultIsArray, t as mutateResult } from "./mutate-result.util-CCBWix-G.mjs";
4
- export { addSkip, addToQuery, checkContext, chunkFind, contextToJson, defineHooks, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, iterateFind, mutateData, mutateResult, patchBatch, skipResult, sortQueryProperties, toPaginated, transformParams, walkQuery, zipDataResult };
1
+ import { f as getPaginate } from "./predicates-BC8p_YLo.mjs";
2
+ import { a as skipResult, c as getExposedMethods, d as checkContext, f as addToQuery, h as sortQueryProperties, i as toPaginated, l as defineHooks, m as addSkip, n as walkQuery, o as patchBatch, p as chunkFind, r as transformParams, s as iterateFind, t as zipDataResult, u as contextToJson } from "./utils-BrvpblXB.mjs";
3
+ import { a as getResultIsArray, i as replaceData, n as replaceResult, o as getDataIsArray, r as mutateData, t as mutateResult } from "./mutate-result.util-B6FOkwrd.mjs";
4
+ export { addSkip, addToQuery, checkContext, chunkFind, contextToJson, defineHooks, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, iterateFind, mutateData, mutateResult, patchBatch, replaceData, replaceResult, skipResult, sortQueryProperties, toPaginated, transformParams, walkQuery, zipDataResult };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feathers-utils",
3
- "version": "10.0.0",
3
+ "version": "10.0.2",
4
4
  "description": "Useful hooks and utils for use with feathers services.",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.mjs",
@@ -1,13 +1,15 @@
1
+ import { copy } from 'fast-copy'
2
+
1
3
  /**
2
- * Deep-clones an object using `JSON.parse(JSON.stringify(...))`.
3
- * Simple and fast for JSON-serializable data, but does not handle
4
- * `Date` objects, `undefined` values, functions, or circular references.
4
+ * Deep-clones a value using `fast-copy`.
5
+ *
6
+ * Unlike a `JSON.parse(JSON.stringify(...))` round-trip, this correctly handles
7
+ * `Date`, `Map`, `Set`, `RegExp`, typed arrays, `undefined` values and circular
8
+ * references — all of which FeathersJS payloads routinely contain.
5
9
  *
6
10
  * @example
7
11
  * ```ts
8
- * const copy = clone({ name: 'Alice', nested: { value: 1 } })
12
+ * const copyOf = clone({ name: 'Alice', createdAt: new Date(), nested: { value: 1 } })
9
13
  * ```
10
14
  */
11
- export function clone(obj: any) {
12
- return JSON.parse(JSON.stringify(obj))
13
- }
15
+ export const clone = copy
@@ -1,30 +1,17 @@
1
- import isObject from 'lodash/isObject.js'
2
1
  import { sortQueryProperties } from '../../utils/sort-query-properties/sort-query-properties.util.js'
3
2
 
4
3
  export { sortQueryProperties }
5
4
 
6
5
  export const stableStringify = (obj: Record<string, any>) => {
7
- if (obj.query) {
8
- obj = { ...obj, query: sortQueryProperties(obj.query) }
9
- }
6
+ // Canonicalize the whole params object once (recursive key-sort + operator-array
7
+ // sort). The JSON.stringify pass then only needs to reject non-JSON values
8
+ // instead of re-sorting and re-allocating every node.
9
+ const normalized = sortQueryProperties(obj as any)
10
10
 
11
- return JSON.stringify(obj, (key, value) => {
11
+ return JSON.stringify(normalized, (_key, value) => {
12
12
  if (typeof value === 'function') {
13
13
  throw new Error('Cannot stringify non JSON value')
14
14
  }
15
-
16
- if (isObject(value)) {
17
- return Object.keys(value)
18
- .sort()
19
- .reduce(
20
- (result, key) => {
21
- result[key] = (value as any)[key]
22
- return result
23
- },
24
- {} as Record<string, any>,
25
- )
26
- }
27
-
28
15
  return value
29
16
  })
30
17
  }
@@ -67,6 +67,16 @@ export type CacheOptions = {
67
67
  * ```
68
68
  */
69
69
  logger?: (event: CacheEvent) => void
70
+ /**
71
+ * How to clone results on store and on hit so callers can't mutate the shared
72
+ * cached object. Defaults to a `fast-copy` deep clone.
73
+ *
74
+ * Set to `false` to skip cloning entirely (fastest, but the caller MUST treat
75
+ * results as immutable), or pass a custom clone function (e.g. `structuredClone`).
76
+ *
77
+ * @default true
78
+ */
79
+ clone?: boolean | (<T>(value: T) => T)
70
80
  }
71
81
 
72
82
  /**
@@ -93,7 +103,7 @@ export const cache = <H extends HookContext = HookContext>(
93
103
  options: CacheOptions,
94
104
  ) => {
95
105
  const cacheMap = new ContextCacheMap(options)
96
- return async (context: H, next?: NextFunction) => {
106
+ return async (context: H, next?: NextFunction): Promise<void> => {
97
107
  if (context.type === 'before') {
98
108
  return await cacheBefore(context, cacheMap)
99
109
  }
@@ -110,25 +120,27 @@ export const cache = <H extends HookContext = HookContext>(
110
120
  }
111
121
  }
112
122
 
113
- const cacheBefore = async (context: HookContext, cacheMap: ContextCacheMap) => {
123
+ const cacheBefore = async (
124
+ context: HookContext,
125
+ cacheMap: ContextCacheMap,
126
+ ): Promise<void> => {
114
127
  if (context.method === 'get' || context.method === 'find') {
115
128
  const value = await cacheMap.get(context)
116
129
  if (value) {
117
130
  context.result = value
118
131
  }
119
132
  }
120
-
121
- return context
122
133
  }
123
134
 
124
- const cacheAfter = async (context: HookContext, cacheMap: ContextCacheMap) => {
135
+ const cacheAfter = async (
136
+ context: HookContext,
137
+ cacheMap: ContextCacheMap,
138
+ ): Promise<void> => {
125
139
  if (context.method === 'get' || context.method === 'find') {
126
140
  await cacheMap.set(context)
127
141
  } else {
128
142
  await cacheMap.clear(context)
129
143
  }
130
-
131
- return context
132
144
  }
133
145
 
134
146
  class ContextCacheMap {
@@ -137,12 +149,19 @@ class ContextCacheMap {
137
149
  private options: CacheOptions
138
150
  private log: ((event: CacheEvent) => void) | undefined
139
151
  private serialize: (params: Params) => string
152
+ private clone: <T>(value: T) => T
140
153
 
141
154
  constructor(options: CacheOptions) {
142
155
  this.map = options.map
143
156
  this.options = options
144
157
  this.log = options.logger
145
158
  this.serialize = options.serialize ?? stableStringify
159
+ this.clone =
160
+ options.clone === false
161
+ ? (value) => value
162
+ : typeof options.clone === 'function'
163
+ ? options.clone
164
+ : copy
146
165
  }
147
166
 
148
167
  private stringifyCacheKey(context: HookContext) {
@@ -182,10 +201,10 @@ class ContextCacheMap {
182
201
  */
183
202
  async get(context: HookContext) {
184
203
  const key = this.stringifyCacheKey(context)
185
- const result = this.map.get(key)
204
+ const result = await this.map.get(key)
186
205
  if (result) {
187
206
  this.log?.({ type: 'hit', method: context.method, key })
188
- return copy(result) // Use copy to avoid mutation of the original result
207
+ return this.clone(result) // clone to avoid mutation of the cached result
189
208
  }
190
209
  this.log?.({ type: 'miss', method: context.method, key })
191
210
  }
@@ -198,7 +217,8 @@ class ContextCacheMap {
198
217
  async set(context: HookContext) {
199
218
  const key = this.stringifyCacheKey(context)
200
219
  this.log?.({ type: 'set', method: context.method, key })
201
- return this.map.set(key, copy(context.result)) // Use copy to avoid mutation of the original result
220
+ // clone to avoid later mutation of the cached result
221
+ return this.map.set(key, this.clone(context.result))
202
222
  }
203
223
 
204
224
  // Called after create(), update(), patch(), and remove()
@@ -220,6 +240,9 @@ class ContextCacheMap {
220
240
  return context
221
241
  }
222
242
 
243
+ // O(1) membership instead of an O(itemIds) scan per cached key.
244
+ const idSet = new Set<string>(itemIds.map((id: any) => `${id}`))
245
+
223
246
  for (const key of this.map.keys()) {
224
247
  const cachedId = this.getCachedId(key)
225
248
  if (cachedId === 'null') {
@@ -237,12 +260,10 @@ class ContextCacheMap {
237
260
  continue
238
261
  }
239
262
 
240
- for (const itemId of itemIds) {
241
- if (cachedId === itemId) {
242
- // If the cached id matches the item id, delete the cached get
243
- this.log?.({ type: 'invalidate', method: context.method, key })
244
- promises.push(this.map.delete(key))
245
- }
263
+ if (idSet.has(cachedId)) {
264
+ // If the cached id matches a mutated item id, delete the cached get
265
+ this.log?.({ type: 'invalidate', method: context.method, key })
266
+ promises.push(this.map.delete(key))
246
267
  }
247
268
  }
248
269
 
@@ -31,7 +31,9 @@ export type CheckMultiOptions = {
31
31
  export function checkMulti<H extends HookContext = HookContext>(
32
32
  options?: CheckMultiOptions,
33
33
  ) {
34
- return (context: H, next?: NextFunction) => {
34
+ function hook(context: H): void
35
+ function hook(context: H, next: NextFunction): Promise<void>
36
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
35
37
  const { service, method } = context
36
38
  if (
37
39
  !service.allowsMulti ||
@@ -40,11 +42,12 @@ export function checkMulti<H extends HookContext = HookContext>(
40
42
  service.allowsMulti(method)
41
43
  ) {
42
44
  if (next) return next()
43
- return context
45
+ return
44
46
  }
45
47
 
46
48
  throw options?.error
47
49
  ? options.error(context)
48
50
  : new MethodNotAllowed(`Can not ${method} multiple entries`)
49
51
  }
52
+ return hook
50
53
  }
@@ -27,7 +27,9 @@ export function checkRequired<H extends HookContext = HookContext>(
27
27
  fieldNames: MaybeArray<string>,
28
28
  ) {
29
29
  const fieldNamesArray = toArray(fieldNames)
30
- return (context: H, next?: NextFunction) => {
30
+ function hook(context: H): void
31
+ function hook(context: H, next: NextFunction): Promise<void>
32
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
31
33
  checkContext(context, {
32
34
  type: ['before', 'around'],
33
35
  method: ['create', 'update', 'patch'],
@@ -55,5 +57,8 @@ export function checkRequired<H extends HookContext = HookContext>(
55
57
  }
56
58
 
57
59
  if (next) return next()
60
+
61
+ return
58
62
  }
63
+ return hook
59
64
  }
@@ -54,7 +54,7 @@ export interface CreateRelatedOptions<
54
54
  export function createRelated<H extends HookContext = HookContext>(
55
55
  options: MaybeArray<CreateRelatedOptions<H>>,
56
56
  ) {
57
- return async (context: H, next?: NextFunction) => {
57
+ return async (context: H, next?: NextFunction): Promise<void> => {
58
58
  checkContext(context, {
59
59
  type: ['after', 'around'],
60
60
  method: ['create'],
@@ -80,7 +80,7 @@ export function createRelated<H extends HookContext = HookContext>(
80
80
  .filter((x) => !!x)
81
81
 
82
82
  if (!dataToCreate || dataToCreate.length <= 0) {
83
- return context
83
+ return
84
84
  }
85
85
 
86
86
  if (multi || dataToCreate.length === 1) {
@@ -18,7 +18,7 @@ import type { HookContext, NextFunction } from '@feathersjs/feathers'
18
18
  */
19
19
  export const debug =
20
20
  <H extends HookContext = HookContext>(msg: string, ...fieldNames: string[]) =>
21
- async (context: H, next?: NextFunction) => {
21
+ async (context: H, next?: NextFunction): Promise<void> => {
22
22
  if (next) {
23
23
  await next()
24
24
  }
@@ -18,9 +18,10 @@ import { checkContext } from '../../utils/index.js'
18
18
  *
19
19
  * @see https://utils.feathersjs.com/hooks/disable-pagination.html
20
20
  */
21
- export const disablePagination =
22
- <H extends HookContext = HookContext>() =>
23
- (context: H, next?: NextFunction) => {
21
+ export const disablePagination = <H extends HookContext = HookContext>() => {
22
+ function hook(context: H): void
23
+ function hook(context: H, next: NextFunction): Promise<void>
24
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
24
25
  checkContext(context, {
25
26
  type: ['before', 'around'],
26
27
  method: ['find'],
@@ -35,5 +36,7 @@ export const disablePagination =
35
36
 
36
37
  if (next) return next()
37
38
 
38
- return context
39
+ return
39
40
  }
41
+ return hook
42
+ }