feathers-utils 10.0.0 → 10.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{hooks-DPFxxjBu.mjs → hooks-CzxNpt2c.mjs} +89 -77
- package/dist/hooks-CzxNpt2c.mjs.map +1 -0
- package/dist/hooks.d.mts +53 -24
- package/dist/hooks.mjs +4 -4
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +5 -5
- package/dist/{predicates-CT08opkD.mjs → predicates-C2SeOKGd.mjs} +16 -11
- package/dist/{predicates-CT08opkD.mjs.map → predicates-C2SeOKGd.mjs.map} +1 -1
- package/dist/predicates.d.mts +1 -1
- package/dist/predicates.mjs +1 -1
- package/dist/{resolve-Cx9osy8O.mjs → resolve-B81gQqXW.mjs} +2 -2
- package/dist/resolve-B81gQqXW.mjs.map +1 -0
- package/dist/resolvers.mjs +1 -1
- package/dist/{transform-result.hook-BUwLePT2.d.mts → transform-result.hook-C8-4Lezj.d.mts} +8 -5
- package/dist/{transform-result.hook-CevWK5TA.mjs → transform-result.hook-DifNj7zf.mjs} +12 -11
- package/dist/transform-result.hook-DifNj7zf.mjs.map +1 -0
- package/dist/transformers.d.mts +1 -1
- package/dist/transformers.mjs +1 -1
- package/dist/{unless.hook-BYWO9hzO.d.mts → unless.hook-CVD7SrZh.d.mts} +6 -3
- package/dist/{utils-1I_iPZkV.mjs → utils-ByzrJKGQ.mjs} +2 -2
- package/dist/{utils-1I_iPZkV.mjs.map → utils-ByzrJKGQ.mjs.map} +1 -1
- package/dist/utils.mjs +2 -2
- package/package.json +1 -1
- package/src/hooks/cache/cache.hook.ts +9 -7
- package/src/hooks/check-multi/check-multi.hook.ts +5 -2
- package/src/hooks/check-required/check-required.hook.ts +6 -1
- package/src/hooks/create-related/create-related.hook.ts +2 -2
- package/src/hooks/debug/debug.hook.ts +1 -1
- package/src/hooks/disable-pagination/disable-pagination.hook.ts +7 -4
- package/src/hooks/disallow/disallow.hook.ts +7 -2
- package/src/hooks/on-delete/on-delete.hook.ts +2 -2
- package/src/hooks/params-for-server/params-for-server.hook.ts +12 -5
- package/src/hooks/params-from-client/params-from-client.hook.ts +10 -6
- package/src/hooks/rate-limit/rate-limit.hook.ts +2 -2
- package/src/hooks/set-data/set-data.hook.ts +8 -7
- package/src/hooks/set-field/set-field.hook.ts +14 -11
- package/src/hooks/set-result/set-result.hook.ts +9 -3
- package/src/hooks/set-slug/set-slug.hook.ts +8 -6
- package/src/hooks/skippable/skippable.hook.ts +15 -12
- package/src/hooks/soft-delete/soft-delete.hook.ts +4 -5
- package/src/hooks/stashable/stashable.hook.ts +9 -8
- package/src/hooks/throw-if/throw-if.hook.ts +2 -2
- package/src/hooks/transform-data/transform-data.hook.ts +2 -4
- package/src/hooks/transform-query/transform-query.hook.ts +6 -5
- package/src/hooks/transform-result/transform-result.hook.ts +6 -9
- package/src/hooks/traverse/traverse.hook.ts +11 -10
- package/src/resolvers/resolve-result/resolve-result.ts +4 -1
- package/dist/hooks-DPFxxjBu.mjs.map +0 -1
- package/dist/resolve-Cx9osy8O.mjs.map +0 -1
- package/dist/transform-result.hook-CevWK5TA.mjs.map +0 -1
package/dist/transformers.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { O as MaybeArray, b as TransformerFn, c as DefaultsInput, u as FieldKey, v as StringFieldKey } from "./hook-context-aHkq1h0N.mjs";
|
|
2
|
-
import { i as transformData, n as transformResult, r as transformQuery, t as TransformResultOptions } from "./transform-result.hook-
|
|
2
|
+
import { i as transformData, n as transformResult, r as transformQuery, t as TransformResultOptions } from "./transform-result.hook-C8-4Lezj.mjs";
|
|
3
3
|
import { n as mutateResult, r as mutateData, t as MutateResultOptions } from "./mutate-result.util-BIeYlqqT.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/transformers/defaults/defaults.transformer.d.ts
|
package/dist/transformers.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as toArray } from "./internal.utils-BWQ25nOd.mjs";
|
|
2
2
|
import { n as mutateData, t as mutateResult } from "./mutate-result.util-CCBWix-G.mjs";
|
|
3
|
-
import { n as transformQuery, r as transformData, t as transformResult } from "./transform-result.hook-
|
|
3
|
+
import { n as transformQuery, r as transformData, t as transformResult } from "./transform-result.hook-DifNj7zf.mjs";
|
|
4
4
|
import { BadRequest } from "@feathersjs/errors";
|
|
5
5
|
import _get from "lodash/get.js";
|
|
6
6
|
import _omit from "lodash/omit.js";
|
|
@@ -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>(
|
|
66
|
+
declare const skippable: <H extends HookContext = HookContext>(innerHook: HookFunction<H>, predicate: PredicateFn<H>) => {
|
|
67
|
+
(context: 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<
|
|
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-
|
|
118
|
+
//# sourceMappingURL=unless.hook-CVD7SrZh.d.mts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as isPaginated, m as isContext, p as isMulti } from "./predicates-
|
|
1
|
+
import { d as isPaginated, m as isContext, p as isMulti } from "./predicates-C2SeOKGd.mjs";
|
|
2
2
|
import { i as getDataIsArray, r as getResultIsArray } from "./mutate-result.util-CCBWix-G.mjs";
|
|
3
3
|
import isObject from "lodash/isObject.js";
|
|
4
4
|
import { dequal } from "dequal";
|
|
@@ -567,4 +567,4 @@ function zipDataResult(context, options) {
|
|
|
567
567
|
//#endregion
|
|
568
568
|
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
569
|
|
|
570
|
-
//# sourceMappingURL=utils-
|
|
570
|
+
//# sourceMappingURL=utils-ByzrJKGQ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils-1I_iPZkV.mjs","names":["deepEqual","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'\nimport isObject from 'lodash/isObject.js'\n\nconst arrayOperators = new Set(['$or', '$and', '$nor', '$not', '$in', '$nin'])\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 (!isObject(value)) {\n return value\n }\n\n const sorted: Record<string, any> = {}\n\n for (const key of Object.keys(value as Record<string, any>).sort()) {\n const val = (value as Record<string, any>)[key]\n\n if (arrayOperators.has(key) && Array.isArray(val)) {\n sorted[key] = val\n .map(normalize)\n .sort((a: any, b: any) =>\n JSON.stringify(a) < JSON.stringify(b) ? -1 : 1,\n )\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 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 },\n }\n\n let result\n\n do {\n result = await (service as any).find(params)\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 { dequal as deepEqual } from 'dequal'\nimport type { KeyOf } from '../../internal.utils.js'\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 map: { ids: Id[]; data: R }[] = []\n\n const idKey = options?.id ?? 'id'\n\n for (const _data of items) {\n const data = _data as unknown as R\n const id = _data[idKey]\n delete (data as any)[idKey as any]\n\n const index = map.findIndex((item) => {\n return deepEqual(item.data, data)\n })\n\n if (index === -1) {\n map.push({ ids: [id], data })\n } else {\n map[index].ids.push(id)\n }\n }\n\n return map.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' || key === '$not') &&\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`/`$not` 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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"}
|
|
1
|
+
{"version":3,"file":"utils-ByzrJKGQ.mjs","names":["deepEqual","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'\nimport isObject from 'lodash/isObject.js'\n\nconst arrayOperators = new Set(['$or', '$and', '$nor', '$not', '$in', '$nin'])\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 (!isObject(value)) {\n return value\n }\n\n const sorted: Record<string, any> = {}\n\n for (const key of Object.keys(value as Record<string, any>).sort()) {\n const val = (value as Record<string, any>)[key]\n\n if (arrayOperators.has(key) && Array.isArray(val)) {\n sorted[key] = val\n .map(normalize)\n .sort((a: any, b: any) =>\n JSON.stringify(a) < JSON.stringify(b) ? -1 : 1,\n )\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 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 },\n }\n\n let result\n\n do {\n result = await (service as any).find(params)\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 { dequal as deepEqual } from 'dequal'\nimport type { KeyOf } from '../../internal.utils.js'\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 map: { ids: Id[]; data: R }[] = []\n\n const idKey = options?.id ?? 'id'\n\n for (const _data of items) {\n const data = _data as unknown as R\n const id = _data[idKey]\n delete (data as any)[idKey as any]\n\n const index = map.findIndex((item) => {\n return deepEqual(item.data, data)\n })\n\n if (index === -1) {\n map.push({ ids: [id], data })\n } else {\n map[index].ids.push(id)\n }\n }\n\n return map.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' || key === '$not') &&\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`/`$not` 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.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as getPaginate } from "./predicates-
|
|
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-
|
|
1
|
+
import { f as getPaginate } from "./predicates-C2SeOKGd.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-ByzrJKGQ.mjs";
|
|
3
3
|
import { i as getDataIsArray, n as mutateData, r as getResultIsArray, t as mutateResult } from "./mutate-result.util-CCBWix-G.mjs";
|
|
4
4
|
export { addSkip, addToQuery, checkContext, chunkFind, contextToJson, defineHooks, getDataIsArray, getExposedMethods, getPaginate, getResultIsArray, iterateFind, mutateData, mutateResult, patchBatch, skipResult, sortQueryProperties, toPaginated, transformParams, walkQuery, zipDataResult };
|
package/package.json
CHANGED
|
@@ -93,7 +93,7 @@ export const cache = <H extends HookContext = HookContext>(
|
|
|
93
93
|
options: CacheOptions,
|
|
94
94
|
) => {
|
|
95
95
|
const cacheMap = new ContextCacheMap(options)
|
|
96
|
-
return async (context: H, next?: NextFunction) => {
|
|
96
|
+
return async (context: H, next?: NextFunction): Promise<void> => {
|
|
97
97
|
if (context.type === 'before') {
|
|
98
98
|
return await cacheBefore(context, cacheMap)
|
|
99
99
|
}
|
|
@@ -110,25 +110,27 @@ export const cache = <H extends HookContext = HookContext>(
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
const cacheBefore = async (
|
|
113
|
+
const cacheBefore = async (
|
|
114
|
+
context: HookContext,
|
|
115
|
+
cacheMap: ContextCacheMap,
|
|
116
|
+
): Promise<void> => {
|
|
114
117
|
if (context.method === 'get' || context.method === 'find') {
|
|
115
118
|
const value = await cacheMap.get(context)
|
|
116
119
|
if (value) {
|
|
117
120
|
context.result = value
|
|
118
121
|
}
|
|
119
122
|
}
|
|
120
|
-
|
|
121
|
-
return context
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
const cacheAfter = async (
|
|
125
|
+
const cacheAfter = async (
|
|
126
|
+
context: HookContext,
|
|
127
|
+
cacheMap: ContextCacheMap,
|
|
128
|
+
): Promise<void> => {
|
|
125
129
|
if (context.method === 'get' || context.method === 'find') {
|
|
126
130
|
await cacheMap.set(context)
|
|
127
131
|
} else {
|
|
128
132
|
await cacheMap.clear(context)
|
|
129
133
|
}
|
|
130
|
-
|
|
131
|
-
return context
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
class ContextCacheMap {
|
|
@@ -31,7 +31,9 @@ export type CheckMultiOptions = {
|
|
|
31
31
|
export function checkMulti<H extends HookContext = HookContext>(
|
|
32
32
|
options?: CheckMultiOptions,
|
|
33
33
|
) {
|
|
34
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
23
|
-
(context: H, next
|
|
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
|
|
39
|
+
return
|
|
39
40
|
}
|
|
41
|
+
return hook
|
|
42
|
+
}
|
|
@@ -28,7 +28,9 @@ export const disallow = <H extends HookContext = HookContext>(
|
|
|
28
28
|
transports?: MaybeArray<TransportName>,
|
|
29
29
|
) => {
|
|
30
30
|
const transportsArr = toArray(transports)
|
|
31
|
-
|
|
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> {
|
|
32
34
|
if (!transports) {
|
|
33
35
|
throw new MethodNotAllowed('Method not allowed')
|
|
34
36
|
}
|
|
@@ -39,6 +41,9 @@ export const disallow = <H extends HookContext = HookContext>(
|
|
|
39
41
|
)
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
if (next) return next()
|
|
44
|
+
if (next) return next()
|
|
45
|
+
|
|
46
|
+
return
|
|
43
47
|
}
|
|
48
|
+
return hook
|
|
44
49
|
}
|
|
@@ -72,7 +72,7 @@ export const onDelete = <H extends HookContext = HookContext>(
|
|
|
72
72
|
) => {
|
|
73
73
|
const optionsMulti = Array.isArray(options) ? options : [options]
|
|
74
74
|
|
|
75
|
-
return async (context: H, next?: NextFunction) => {
|
|
75
|
+
return async (context: H, next?: NextFunction): Promise<void> => {
|
|
76
76
|
checkContext(context, {
|
|
77
77
|
type: ['after', 'around'],
|
|
78
78
|
method: 'remove',
|
|
@@ -97,7 +97,7 @@ export const onDelete = <H extends HookContext = HookContext>(
|
|
|
97
97
|
ids = [...new Set(ids)]
|
|
98
98
|
|
|
99
99
|
if (!ids || ids.length <= 0) {
|
|
100
|
-
return
|
|
100
|
+
return
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
const params = {
|
|
@@ -35,7 +35,15 @@ export const paramsForServer = (
|
|
|
35
35
|
|
|
36
36
|
const { keyToHide = FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } = options || {}
|
|
37
37
|
|
|
38
|
-
|
|
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
|
|
|
@@ -67,10 +75,9 @@ export const paramsForServer = (
|
|
|
67
75
|
context.params = clonedParams
|
|
68
76
|
}
|
|
69
77
|
|
|
70
|
-
if (next)
|
|
71
|
-
return next()
|
|
72
|
-
}
|
|
78
|
+
if (next) return next()
|
|
73
79
|
|
|
74
|
-
return
|
|
80
|
+
return
|
|
75
81
|
}
|
|
82
|
+
return hook
|
|
76
83
|
}
|
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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)
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
114
|
+
return
|
|
115
115
|
}
|
|
116
|
+
return hook
|
|
116
117
|
}
|
|
@@ -42,14 +42,15 @@ export interface SetFieldOptions {
|
|
|
42
42
|
*
|
|
43
43
|
* @see https://utils.feathersjs.com/hooks/set-field.html
|
|
44
44
|
*/
|
|
45
|
-
export const setField =
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
(context: H, next
|
|
45
|
+
export const setField = <H extends HookContext = HookContext>({
|
|
46
|
+
as,
|
|
47
|
+
from,
|
|
48
|
+
allowUndefined = false,
|
|
49
|
+
error,
|
|
50
|
+
}: SetFieldOptions) => {
|
|
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> {
|
|
53
54
|
const { params } = context
|
|
54
55
|
|
|
55
56
|
checkContext(context, { type: ['before', 'around'], label: 'setField' })
|
|
@@ -59,7 +60,7 @@ export const setField =
|
|
|
59
60
|
if (value === undefined) {
|
|
60
61
|
if (!params.provider || allowUndefined) {
|
|
61
62
|
if (next) return next()
|
|
62
|
-
return
|
|
63
|
+
return
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
throw error
|
|
@@ -67,9 +68,11 @@ export const setField =
|
|
|
67
68
|
: new Forbidden(`Expected field ${as} not available`)
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
_setWith(context, as, value, _clone)
|
|
71
72
|
|
|
72
73
|
if (next) return next()
|
|
73
74
|
|
|
74
|
-
return
|
|
75
|
+
return
|
|
75
76
|
}
|
|
77
|
+
return hook
|
|
78
|
+
}
|
|
@@ -118,11 +118,17 @@ export function setResult<H extends HookContext = HookContext>(
|
|
|
118
118
|
return forResultOrDispatch(context, !!options?.dispatch)
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
function hook(context: H): void
|
|
122
|
+
function hook(context: H, next: NextFunction): Promise<void>
|
|
123
|
+
function hook(context: H, next?: NextFunction): void | Promise<void> {
|
|
122
124
|
if (next) {
|
|
123
|
-
return next().then(() =>
|
|
125
|
+
return next().then(() => {
|
|
126
|
+
fn(context)
|
|
127
|
+
})
|
|
124
128
|
}
|
|
125
129
|
|
|
126
|
-
|
|
130
|
+
fn(context)
|
|
131
|
+
return
|
|
127
132
|
}
|
|
133
|
+
return hook
|
|
128
134
|
}
|