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
@@ -28,8 +28,12 @@ export const disallow = <H extends HookContext = HookContext>(
28
28
  transports?: MaybeArray<TransportName>,
29
29
  ) => {
30
30
  const transportsArr = toArray(transports)
31
- return (context: H, next?: NextFunction) => {
32
- if (!transports) {
31
+ function hook(context: H): void
32
+ function hook(context: H, next: NextFunction): Promise<void>
33
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
34
+ // No transports (undefined) or an empty list means "block completely".
35
+ // Fail closed for a guard hook rather than throwing a confusing internal error.
36
+ if (!transports || transportsArr.length === 0) {
33
37
  throw new MethodNotAllowed('Method not allowed')
34
38
  }
35
39
 
@@ -39,6 +43,9 @@ export const disallow = <H extends HookContext = HookContext>(
39
43
  )
40
44
  }
41
45
 
42
- if (next) return next().then(() => context)
46
+ if (next) return next()
47
+
48
+ return
43
49
  }
50
+ return hook
44
51
  }
@@ -43,6 +43,12 @@ export interface OnDeleteOptions<
43
43
  * @default false
44
44
  */
45
45
  blocking?: boolean
46
+ /**
47
+ * Called when a non-blocking (`blocking: false`) related-service call rejects.
48
+ * Without this, fire-and-forget rejections are swallowed (but never leak as an
49
+ * unhandled rejection). In `blocking` mode the error is thrown to the caller instead.
50
+ */
51
+ onError?: (error: any, context: H) => void
46
52
  }
47
53
 
48
54
  /**
@@ -72,7 +78,7 @@ export const onDelete = <H extends HookContext = HookContext>(
72
78
  ) => {
73
79
  const optionsMulti = Array.isArray(options) ? options : [options]
74
80
 
75
- return async (context: H, next?: NextFunction) => {
81
+ return async (context: H, next?: NextFunction): Promise<void> => {
76
82
  checkContext(context, {
77
83
  type: ['after', 'around'],
78
84
  method: 'remove',
@@ -89,46 +95,60 @@ export const onDelete = <H extends HookContext = HookContext>(
89
95
  return
90
96
  }
91
97
 
92
- const promises: Promise<any>[] = []
93
-
94
- optionsMulti.forEach(
95
- async ({ keyHere, keyThere, onDelete, service, blocking, query }) => {
96
- let ids = result.map((x) => x[keyHere]).filter((x) => !!x)
97
- ids = [...new Set(ids)]
98
-
99
- if (!ids || ids.length <= 0) {
100
- return context
101
- }
102
-
103
- const params = {
104
- query: {
105
- ...query,
106
- ...(ids.length === 1
107
- ? { [keyThere]: ids[0] }
108
- : { [keyThere]: { $in: ids } }),
109
- },
110
- paginate: false,
111
- }
112
-
113
- let promise: Promise<any> | undefined = undefined
114
-
115
- if (onDelete === 'cascade') {
116
- promise = context.app.service(service as string).remove(null, params)
117
- } else if (onDelete === 'set null') {
118
- const data = { [keyThere]: null }
119
- promise = context.app
120
- .service(service as string)
121
- .patch(null, data, params)
122
- }
123
-
124
- if (promise && blocking) {
125
- promises.push(promise)
126
- }
127
- },
128
- )
129
-
130
- if (promises.length) {
131
- await Promise.all(promises)
98
+ const blockingPromises: Promise<any>[] = []
99
+
100
+ for (const {
101
+ keyHere,
102
+ keyThere,
103
+ onDelete,
104
+ service,
105
+ blocking,
106
+ query,
107
+ onError,
108
+ } of optionsMulti) {
109
+ let ids = result.map((x) => x[keyHere]).filter((x) => !!x)
110
+ ids = [...new Set(ids)]
111
+
112
+ if (!ids || ids.length <= 0) {
113
+ continue
114
+ }
115
+
116
+ const params = {
117
+ query: {
118
+ ...query,
119
+ ...(ids.length === 1
120
+ ? { [keyThere]: ids[0] }
121
+ : { [keyThere]: { $in: ids } }),
122
+ },
123
+ paginate: false,
124
+ }
125
+
126
+ let promise: Promise<any> | undefined = undefined
127
+
128
+ if (onDelete === 'cascade') {
129
+ promise = context.app.service(service as string).remove(null, params)
130
+ } else if (onDelete === 'set null') {
131
+ const data = { [keyThere]: null }
132
+ promise = context.app
133
+ .service(service as string)
134
+ .patch(null, data, params)
135
+ }
136
+
137
+ if (!promise) {
138
+ continue
139
+ }
140
+
141
+ if (blocking) {
142
+ blockingPromises.push(promise)
143
+ } else {
144
+ // fire-and-forget: always attach a catch so a rejection never becomes
145
+ // an unhandled promise rejection. Surface it via `onError` if provided.
146
+ promise.catch((error) => onError?.(error, context))
147
+ }
148
+ }
149
+
150
+ if (blockingPromises.length) {
151
+ await Promise.all(blockingPromises)
132
152
  }
133
153
 
134
154
  return
@@ -35,7 +35,15 @@ export const paramsForServer = (
35
35
 
36
36
  const { keyToHide = FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } = options || {}
37
37
 
38
- return <H extends HookContext>(context: H, next?: NextFunction) => {
38
+ function hook<H extends HookContext>(context: H): void
39
+ function hook<H extends HookContext>(
40
+ context: H,
41
+ next: NextFunction,
42
+ ): Promise<void>
43
+ function hook<H extends HookContext>(
44
+ context: H,
45
+ next?: NextFunction,
46
+ ): void | Promise<void> {
39
47
  // clone params on demand
40
48
  let clonedParams: any
41
49
 
@@ -56,6 +64,10 @@ export const paramsForServer = (
56
64
 
57
65
  if (!clonedParams.query[keyToHide]) {
58
66
  clonedParams.query[keyToHide] = {}
67
+ } else {
68
+ // The shallow query copy still aliases a pre-existing key object;
69
+ // clone it so we don't mutate the caller's original params.
70
+ clonedParams.query[keyToHide] = { ...clonedParams.query[keyToHide] }
59
71
  }
60
72
 
61
73
  clonedParams.query[keyToHide][key] = clonedParams[key]
@@ -67,10 +79,9 @@ export const paramsForServer = (
67
79
  context.params = clonedParams
68
80
  }
69
81
 
70
- if (next) {
71
- return next()
72
- }
82
+ if (next) return next()
73
83
 
74
- return context
84
+ return
75
85
  }
86
+ return hook
76
87
  }
@@ -33,13 +33,18 @@ export const paramsFromClient = (
33
33
  ) => {
34
34
  const whitelistArr = toArray(whitelist)
35
35
  const { keyToHide = FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } = options || {}
36
- return (context: HookContext, next?: NextFunction) => {
36
+ function hook(context: HookContext): void
37
+ function hook(context: HookContext, next: NextFunction): Promise<void>
38
+ function hook(
39
+ context: HookContext,
40
+ next?: NextFunction,
41
+ ): void | Promise<void> {
37
42
  if (
38
43
  !context.params?.query?.[keyToHide] ||
39
44
  typeof context.params.query[keyToHide] !== 'object'
40
45
  ) {
41
46
  if (next) return next()
42
- return context
47
+ return
43
48
  }
44
49
 
45
50
  const params = {
@@ -67,10 +72,9 @@ export const paramsFromClient = (
67
72
 
68
73
  context.params = params
69
74
 
70
- if (next) {
71
- return next()
72
- }
75
+ if (next) return next()
73
76
 
74
- return context
77
+ return
75
78
  }
79
+ return hook
76
80
  }
@@ -37,7 +37,7 @@ export const rateLimit = <H extends HookContext = HookContext>(
37
37
  const key = options?.key ?? ((context: HookContext) => context.path)
38
38
  const points = options?.points ?? (() => 1)
39
39
 
40
- return async (context: H, next?: NextFunction) => {
40
+ return async (context: H, next?: NextFunction): Promise<void> => {
41
41
  checkContext(context, { type: ['before', 'around'], label: 'rateLimit' })
42
42
 
43
43
  const resolvedKey = await key(context)
@@ -53,6 +53,6 @@ export const rateLimit = <H extends HookContext = HookContext>(
53
53
  })
54
54
  }
55
55
 
56
- if (next) return await next()
56
+ if (next) await next()
57
57
  }
58
58
  }
@@ -68,7 +68,9 @@ export function setData<H extends HookContext = HookContext>(
68
68
  ) {
69
69
  const { allowUndefined = false, overwrite = true } = options ?? {}
70
70
 
71
- return (context: H, next?: NextFunction) => {
71
+ function hook(context: H): void
72
+ function hook(context: H, next: NextFunction): Promise<void>
73
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
72
74
  const { data } = getDataIsArray(context)
73
75
 
74
76
  const contextJson = contextToJson(context)
@@ -76,7 +78,7 @@ export function setData<H extends HookContext = HookContext>(
76
78
  if (!_has(contextJson, from)) {
77
79
  if (!context.params?.provider || allowUndefined === true) {
78
80
  if (next) return next()
79
- return context
81
+ return
80
82
  }
81
83
 
82
84
  if (
@@ -84,7 +86,7 @@ export function setData<H extends HookContext = HookContext>(
84
86
  data.every((item: Record<string, unknown>) => _has(item, to))
85
87
  ) {
86
88
  if (next) return next()
87
- return context
89
+ return
88
90
  }
89
91
 
90
92
  throw options?.error
@@ -107,10 +109,9 @@ export function setData<H extends HookContext = HookContext>(
107
109
  _set(item, to, val)
108
110
  }
109
111
 
110
- if (next) {
111
- return next()
112
- }
112
+ if (next) return next()
113
113
 
114
- return context
114
+ return
115
115
  }
116
+ return hook
116
117
  }
@@ -6,9 +6,23 @@ import type { FeathersError } from '@feathersjs/errors'
6
6
  import { Forbidden } from '@feathersjs/errors'
7
7
  import type { HookContext, NextFunction } from '@feathersjs/feathers'
8
8
 
9
- export interface SetFieldOptions {
10
- as: string
11
- from: string
9
+ export interface SetFieldOptions<H extends HookContext = HookContext> {
10
+ /**
11
+ * The target path(s) to set. Pass an array to write the same value to several
12
+ * paths (e.g. multiple query keys).
13
+ *
14
+ * @example 'params.query.userId'
15
+ * @example ['params.query.userId', 'params.query.ownerId']
16
+ */
17
+ as: string | string[]
18
+ /**
19
+ * The source of the value: a `dot.notation` path on the context, or a function
20
+ * that derives the value from the context.
21
+ *
22
+ * @example 'params.user.id'
23
+ * @example (context) => context.params.user?.id
24
+ */
25
+ from: string | ((context: H) => unknown)
12
26
  /**
13
27
  * If set to `true`, allows the field to be undefined.
14
28
  * If the field is not available and this is `true`, the hook will not throw an error.
@@ -23,7 +37,10 @@ export interface SetFieldOptions {
23
37
  *
24
38
  * If not provided, throws a `Forbidden` error with a message indicating the missing field.
25
39
  */
26
- error?: (context: HookContext, from: string) => FeathersError
40
+ error?: (
41
+ context: H,
42
+ from: string | ((context: H) => unknown),
43
+ ) => FeathersError
27
44
  }
28
45
 
29
46
  /**
@@ -42,34 +59,42 @@ export interface SetFieldOptions {
42
59
  *
43
60
  * @see https://utils.feathersjs.com/hooks/set-field.html
44
61
  */
45
- export const setField =
46
- <H extends HookContext = HookContext>({
47
- as,
48
- from,
49
- allowUndefined = false,
50
- error,
51
- }: SetFieldOptions) =>
52
- (context: H, next?: NextFunction) => {
62
+ export const setField = <H extends HookContext = HookContext>({
63
+ as,
64
+ from,
65
+ allowUndefined = false,
66
+ error,
67
+ }: SetFieldOptions<H>) => {
68
+ const targets = Array.isArray(as) ? as : [as]
69
+
70
+ function hook(context: H): void
71
+ function hook(context: H, next: NextFunction): Promise<void>
72
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
53
73
  const { params } = context
54
74
 
55
75
  checkContext(context, { type: ['before', 'around'], label: 'setField' })
56
76
 
57
- const value = _get(context, from)
77
+ const value =
78
+ typeof from === 'function' ? from(context) : _get(context, from)
58
79
 
59
80
  if (value === undefined) {
60
81
  if (!params.provider || allowUndefined) {
61
82
  if (next) return next()
62
- return context
83
+ return
63
84
  }
64
85
 
65
86
  throw error
66
87
  ? error(context, from)
67
- : new Forbidden(`Expected field ${as} not available`)
88
+ : new Forbidden(`Expected field ${targets.join(', ')} not available`)
68
89
  }
69
90
 
70
- context = _setWith(context, as, value, _clone)
91
+ for (const target of targets) {
92
+ _setWith(context, target, value, _clone)
93
+ }
71
94
 
72
95
  if (next) return next()
73
96
 
74
- return context
97
+ return
75
98
  }
99
+ return hook
100
+ }
@@ -1,6 +1,7 @@
1
1
  import _get from 'lodash/get.js'
2
2
  import _set from 'lodash/set.js'
3
3
  import _has from 'lodash/has.js'
4
+ import { copy } from 'fast-copy'
4
5
 
5
6
  import type { FeathersError } from '@feathersjs/errors'
6
7
  import { Forbidden } from '@feathersjs/errors'
@@ -110,6 +111,12 @@ export function setResult<H extends HookContext = HookContext>(
110
111
  }
111
112
 
112
113
  const fn = (context: H) => {
114
+ // Seed context.dispatch from result so the dispatch branch mutates (and
115
+ // persists to) a real object instead of a throwaway copy. Mirrors mutateResult.
116
+ if (!!options?.dispatch && !context.dispatch) {
117
+ context.dispatch = copy(context.result)
118
+ }
119
+
113
120
  if (options?.dispatch === 'both') {
114
121
  forResultOrDispatch(context, true)
115
122
  return forResultOrDispatch(context, false)
@@ -118,11 +125,17 @@ export function setResult<H extends HookContext = HookContext>(
118
125
  return forResultOrDispatch(context, !!options?.dispatch)
119
126
  }
120
127
 
121
- return (context: H, next?: NextFunction) => {
128
+ function hook(context: H): void
129
+ function hook(context: H, next: NextFunction): Promise<void>
130
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
122
131
  if (next) {
123
- return next().then(() => fn(context))
132
+ return next().then(() => {
133
+ fn(context)
134
+ })
124
135
  }
125
136
 
126
- return fn(context)
137
+ fn(context)
138
+ return
127
139
  }
140
+ return hook
128
141
  }
@@ -21,20 +21,22 @@ export const setSlug = <H extends HookContext = HookContext>(
21
21
  slug: string,
22
22
  fieldName?: string,
23
23
  ) => {
24
- if (typeof fieldName !== 'string') {
25
- fieldName = `query.${slug}`
26
- }
24
+ const targetField: string =
25
+ typeof fieldName === 'string' ? fieldName : `query.${slug}`
27
26
 
28
- return (context: H, next?: NextFunction) => {
27
+ function hook(context: H): void
28
+ function hook(context: H, next: NextFunction): Promise<void>
29
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
29
30
  if (context.params && context.params.provider === 'rest') {
30
31
  const value = context.params.route[slug]
31
32
  if (typeof value === 'string' && value[0] !== ':') {
32
- _set(context.params, fieldName, value)
33
+ _set(context.params, targetField, value)
33
34
  }
34
35
  }
35
36
 
36
37
  if (next) return next()
37
38
 
38
- return context
39
+ return
39
40
  }
41
+ return hook
40
42
  }
@@ -15,26 +15,31 @@ import type { HookFunction, PredicateFn } from '../../types.js'
15
15
  *
16
16
  * @see https://utils.feathersjs.com/hooks/skippable.html
17
17
  */
18
- export const skippable =
19
- <H extends HookContext = HookContext>(
20
- hook: HookFunction<H>,
21
- predicate: PredicateFn<H>,
22
- ) =>
23
- (context: H, next?: NextFunction) => {
18
+ export const skippable = <H extends HookContext = HookContext>(
19
+ innerHook: HookFunction<H>,
20
+ predicate: PredicateFn<H>,
21
+ ) => {
22
+ function hook(context: H): H | void | Promise<H | void>
23
+ function hook(context: H, next: NextFunction): Promise<void>
24
+ function hook(context: H, next?: NextFunction): H | void | Promise<H | void> {
24
25
  const skip = predicate(context)
25
26
 
26
- function skipOrRun(skip: boolean) {
27
- if (skip) {
27
+ const skipOrRun = (shouldSkip: boolean): H | void | Promise<H | void> => {
28
+ if (shouldSkip) {
28
29
  if (next) return next()
29
- return context
30
- } else {
31
- return hook(context, next)
30
+ return
32
31
  }
32
+ if (next) return innerHook(context, next) as Promise<void>
33
+ // before/after mode: return the inner hook's result so an async hook is
34
+ // awaited and a returned/modified context is propagated to the pipeline.
35
+ return innerHook(context)
33
36
  }
34
37
 
35
38
  if (!skip || typeof skip === 'boolean') {
36
39
  return skipOrRun(skip)
37
40
  }
38
41
 
39
- return skip.then(skipOrRun)
42
+ return skip.then(skipOrRun) as Promise<void>
40
43
  }
44
+ return hook
45
+ }
@@ -65,13 +65,14 @@ export const softDelete = <H extends HookContext = HookContext>(
65
65
  )
66
66
  }
67
67
 
68
- return async (context: H, next?: NextFunction) => {
68
+ return async (context: H, next?: NextFunction): Promise<void> => {
69
69
  checkContext(context, { type: ['before', 'around'], label: 'softDelete' })
70
70
 
71
71
  const { disableSoftDeleteKey = 'disableSoftDelete' } = options
72
72
 
73
73
  if (context.params[disableSoftDeleteKey]) {
74
- return early(context, next)
74
+ await early(context, next)
75
+ return
75
76
  }
76
77
 
77
78
  const { deletedQuery, removeData } = options
@@ -105,10 +106,8 @@ export const softDelete = <H extends HookContext = HookContext>(
105
106
  }
106
107
 
107
108
  if (next) {
108
- return await next()
109
+ await next()
109
110
  }
110
-
111
- return context
112
111
  }
113
112
  }
114
113
 
@@ -44,17 +44,16 @@ const defaultStashFunc = (context: HookContext) => {
44
44
  */
45
45
  export function stashable<H extends HookContext = HookContext>(
46
46
  options?: StashableOptions,
47
- ): {
48
- (context: H, next: NextFunction): Promise<void>
49
- (context: H): H
50
- } {
47
+ ) {
51
48
  const propName = options?.propName ?? 'stashed'
52
49
  const stashFunc = options?.stashFunc ?? defaultStashFunc
53
50
 
54
- return ((context: H, next?: NextFunction) => {
51
+ function hook(context: H): void
52
+ function hook(context: H, next: NextFunction): Promise<void>
53
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
55
54
  if (context.params._stashable) {
56
55
  if (next) return next()
57
- return context
56
+ return
58
57
  }
59
58
 
60
59
  checkContext(context, {
@@ -68,6 +67,8 @@ export function stashable<H extends HookContext = HookContext>(
68
67
  context.params[propName] = () => promise
69
68
 
70
69
  if (next) return next()
71
- return context
72
- }) as any
70
+
71
+ return
72
+ }
73
+ return hook
73
74
  }
@@ -32,7 +32,7 @@ export const throwIf = <H extends HookContext = HookContext>(
32
32
  predicate: PredicateFn,
33
33
  options?: ThrowIfOptions,
34
34
  ) => {
35
- return async (context: H, next?: NextFunction) => {
35
+ return async (context: H, next?: NextFunction): Promise<void> => {
36
36
  const result = await predicate(context)
37
37
 
38
38
  if (result) {
@@ -42,7 +42,7 @@ export const throwIf = <H extends HookContext = HookContext>(
42
42
  }
43
43
 
44
44
  if (next) {
45
- return await next()
45
+ await next()
46
46
  }
47
47
  }
48
48
  }
@@ -29,12 +29,10 @@ export const transformData =
29
29
  <H extends HookContext = HookContext, D = Data<H>>(
30
30
  transformer: TransformerInputFn<D, H>,
31
31
  ) =>
32
- async (context: H, next?: NextFunction) => {
32
+ async (context: H, next?: NextFunction): Promise<void> => {
33
33
  await mutateData(context, transformer)
34
34
 
35
35
  if (next) {
36
- return next()
36
+ await next()
37
37
  }
38
-
39
- return context
40
38
  }
@@ -23,16 +23,17 @@ export const transformQuery = <
23
23
  >(
24
24
  transformer: TransformerFn<Q, H>,
25
25
  ) => {
26
- return (context: H, next?: NextFunction) => {
26
+ function hook(context: H): void
27
+ function hook(context: H, next: NextFunction): Promise<void>
28
+ function hook(context: H, next?: NextFunction): void | Promise<void> {
27
29
  context.params.query = transformer(context.params.query ?? {}, {
28
30
  context,
29
31
  i: 0,
30
32
  })
31
33
 
32
- if (next) {
33
- return next().then(() => context)
34
- }
34
+ if (next) return next()
35
35
 
36
- return context
36
+ return
37
37
  }
38
+ return hook
38
39
  }
@@ -1,10 +1,6 @@
1
1
  import type { HookContext, NextFunction } from '@feathersjs/feathers'
2
2
  import { mutateResult } from '../../utils/mutate-result/mutate-result.util.js'
3
- import type {
4
- DispatchOption,
5
- HookFunction,
6
- TransformerInputFn,
7
- } from '../../types.js'
3
+ import type { DispatchOption, TransformerInputFn } from '../../types.js'
8
4
  import type { ResultSingleHookContext } from '../../utility-types/hook-context.js'
9
5
  import type { AnyFallback } from '../../internal.utils.js'
10
6
 
@@ -37,9 +33,10 @@ export const transformResult =
37
33
  <H extends HookContext = HookContext, R = Result<H>>(
38
34
  transformer: TransformerInputFn<R, H>,
39
35
  options?: TransformResultOptions,
40
- ): HookFunction<H> =>
41
- (context: H, next?: NextFunction) =>
42
- mutateResult(context, transformer, {
36
+ ) =>
37
+ async (context: H, next?: NextFunction): Promise<void> => {
38
+ await mutateResult(context, transformer, {
43
39
  next,
44
40
  dispatch: options?.dispatch,
45
- }) as Promise<H>
41
+ })
42
+ }