feathers-utils 5.0.1 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,6 +25,8 @@ npm i feathers-utils
25
25
  - `createRelated`: simply create related items from a hook.
26
26
  - `forEach`
27
27
  - `onDelete`: simply remove/set null related items from a hook.
28
+ - `paramsForServer`
29
+ - `paramsFromClient`
28
30
  - `parseFields`
29
31
  - `removeRelated`: simple remove related items from a hook. Basically `cascade` at feathers level.
30
32
  - `runPerItem`: run a function for every item. Meant for `multi:true`.
package/dist/index.cjs CHANGED
@@ -688,6 +688,9 @@ const forEach = (actionPerItem, options) => {
688
688
  if (shouldSkip("forEach", context)) {
689
689
  return context;
690
690
  }
691
+ if (options?.skip && await options.skip(context)) {
692
+ return context;
693
+ }
691
694
  const { items } = getItemsIsArray(context, { from });
692
695
  const forAll = options?.forAll ? await options.forAll(items, context) : {};
693
696
  const promises = [];
@@ -874,6 +877,77 @@ function setData(from, to, _options) {
874
877
  };
875
878
  }
876
879
 
880
+ const FROM_CLIENT_FOR_SERVER_DEFAULT_KEY = "_$client";
881
+
882
+ function defineParamsForServer(keyToHide) {
883
+ return function paramsForServer2(...whitelist) {
884
+ return (context) => {
885
+ let clonedParams;
886
+ Object.keys(context.params).forEach((key) => {
887
+ if (key === "query") {
888
+ return;
889
+ }
890
+ if (whitelist.includes(key)) {
891
+ if (!clonedParams) {
892
+ clonedParams = {
893
+ ...context.params,
894
+ query: {
895
+ ...context.params.query
896
+ }
897
+ };
898
+ }
899
+ if (!clonedParams.query[keyToHide]) {
900
+ clonedParams.query[keyToHide] = {};
901
+ }
902
+ clonedParams.query[keyToHide][key] = clonedParams[key];
903
+ delete clonedParams[key];
904
+ }
905
+ });
906
+ if (clonedParams) {
907
+ context.params = clonedParams;
908
+ }
909
+ return context;
910
+ };
911
+ };
912
+ }
913
+ const paramsForServer = defineParamsForServer(
914
+ FROM_CLIENT_FOR_SERVER_DEFAULT_KEY
915
+ );
916
+
917
+ function defineParamsFromClient(keyToHide) {
918
+ return function paramsFromClient2(...whitelist) {
919
+ return (context) => {
920
+ if (!context.params?.query?.[keyToHide] || typeof context.params.query[keyToHide] !== "object") {
921
+ return context;
922
+ }
923
+ const params = {
924
+ ...context.params,
925
+ query: {
926
+ ...context.params.query,
927
+ [keyToHide]: {
928
+ ...context.params.query[keyToHide]
929
+ }
930
+ }
931
+ };
932
+ const client = params.query[keyToHide];
933
+ whitelist.forEach((key) => {
934
+ if (key in client) {
935
+ params[key] = client[key];
936
+ delete client[key];
937
+ }
938
+ });
939
+ if (Object.keys(client).length === 0) {
940
+ delete params.query[keyToHide];
941
+ }
942
+ context.params = params;
943
+ return context;
944
+ };
945
+ };
946
+ }
947
+ const paramsFromClient = defineParamsFromClient(
948
+ FROM_CLIENT_FOR_SERVER_DEFAULT_KEY
949
+ );
950
+
877
951
  var __defProp = Object.defineProperty;
878
952
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
879
953
  var __publicField = (obj, key, value) => {
@@ -1000,6 +1074,8 @@ exports.checkMulti = checkMulti;
1000
1074
  exports.createRelated = createRelated;
1001
1075
  exports.debounceMixin = debounceMixin;
1002
1076
  exports.defineHooks = defineHooks;
1077
+ exports.defineParamsForServer = defineParamsForServer;
1078
+ exports.defineParamsFromClient = defineParamsFromClient;
1003
1079
  exports.filterArray = filterArray;
1004
1080
  exports.filterObject = filterObject;
1005
1081
  exports.filterQuery = filterQuery;
@@ -1014,6 +1090,8 @@ exports.mergeArrays = mergeArrays;
1014
1090
  exports.mergeQuery = mergeQuery;
1015
1091
  exports.onDelete = onDelete;
1016
1092
  exports.optimizeBatchPatch = optimizeBatchPatch;
1093
+ exports.paramsForServer = paramsForServer;
1094
+ exports.paramsFromClient = paramsFromClient;
1017
1095
  exports.parseFields = parseFields;
1018
1096
  exports.pushSet = pushSet;
1019
1097
  exports.removeRelated = removeRelated;
package/dist/index.d.cts CHANGED
@@ -40,6 +40,7 @@ type HookForEachOptions<T = any, H = HookContext, R = any> = {
40
40
  wait?: "sequential" | "parallel" | false;
41
41
  items?: GetItemsIsArrayOptions["from"];
42
42
  forAll?: (items: T[], context: H) => Promisable<R>;
43
+ skip?: (context: H) => Promisable<boolean>;
43
44
  };
44
45
  type ActionPerItem<T, H, R> = (item: T, options: {
45
46
  context: H;
@@ -101,6 +102,18 @@ interface HookSetDataOptions {
101
102
  */
102
103
  declare function setData<H extends HookContext = HookContext>(from: PropertyPath, to: PropertyPath, _options?: HookSetDataOptions): (context: H) => H;
103
104
 
105
+ declare function defineParamsForServer(keyToHide: string): (...whitelist: string[]) => <H extends HookContext<_feathersjs_feathers.Application<any, any>, any>>(context: H) => H;
106
+ /**
107
+ * a hook to move params to query._$client
108
+ * the server only receives 'query' from params. All other params are ignored.
109
+ * So, to use `$populateParams` on the server, we need to move the params to query._$client
110
+ * the server will move them back to params
111
+ */
112
+ declare const paramsForServer: (...whitelist: string[]) => <H extends HookContext<_feathersjs_feathers.Application<any, any>, any>>(context: H) => H;
113
+
114
+ declare function defineParamsFromClient(keyToHide: string): (...whitelist: string[]) => (context: HookContext) => HookContext;
115
+ declare const paramsFromClient: (...whitelist: string[]) => (context: HookContext) => HookContext;
116
+
104
117
  interface InitDebounceMixinOptions {
105
118
  default: Partial<DebouncedStoreOptions>;
106
119
  blacklist: string[];
@@ -297,4 +310,4 @@ type InferRemoveResultFromPath<App extends Application, Path extends string, IdO
297
310
  type InferDataFromPath<App extends Application, Path extends string, Method extends "create" | "update" | "patch"> = Method extends "create" ? InferCreateDataFromPath<App, Path> : Method extends "update" ? InferUpdateDataFromPath<App, Path> : Method extends "patch" ? InferPatchDataFromPath<App, Path> : never;
298
311
  type InferResultFromPath<App extends Application, Path extends string, Method extends "get" | "find" | "create" | "update" | "patch" | "remove"> = Method extends "get" ? InferGetResultFromPath<App, Path> : Method extends "find" ? InferFindResultFromPath<App, Path> : Method extends "create" ? InferCreateResultFromPath<App, Path> : Method extends "update" ? InferUpdateResultFromPath<App, Path> : Method extends "patch" ? InferPatchResultFromPath<App, Path> : Method extends "remove" ? InferRemoveResultFromPath<App, Path> : never;
299
312
 
300
- export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
313
+ export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, defineParamsForServer, defineParamsFromClient, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, paramsForServer, paramsFromClient, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
package/dist/index.d.mts CHANGED
@@ -40,6 +40,7 @@ type HookForEachOptions<T = any, H = HookContext, R = any> = {
40
40
  wait?: "sequential" | "parallel" | false;
41
41
  items?: GetItemsIsArrayOptions["from"];
42
42
  forAll?: (items: T[], context: H) => Promisable<R>;
43
+ skip?: (context: H) => Promisable<boolean>;
43
44
  };
44
45
  type ActionPerItem<T, H, R> = (item: T, options: {
45
46
  context: H;
@@ -101,6 +102,18 @@ interface HookSetDataOptions {
101
102
  */
102
103
  declare function setData<H extends HookContext = HookContext>(from: PropertyPath, to: PropertyPath, _options?: HookSetDataOptions): (context: H) => H;
103
104
 
105
+ declare function defineParamsForServer(keyToHide: string): (...whitelist: string[]) => <H extends HookContext<_feathersjs_feathers.Application<any, any>, any>>(context: H) => H;
106
+ /**
107
+ * a hook to move params to query._$client
108
+ * the server only receives 'query' from params. All other params are ignored.
109
+ * So, to use `$populateParams` on the server, we need to move the params to query._$client
110
+ * the server will move them back to params
111
+ */
112
+ declare const paramsForServer: (...whitelist: string[]) => <H extends HookContext<_feathersjs_feathers.Application<any, any>, any>>(context: H) => H;
113
+
114
+ declare function defineParamsFromClient(keyToHide: string): (...whitelist: string[]) => (context: HookContext) => HookContext;
115
+ declare const paramsFromClient: (...whitelist: string[]) => (context: HookContext) => HookContext;
116
+
104
117
  interface InitDebounceMixinOptions {
105
118
  default: Partial<DebouncedStoreOptions>;
106
119
  blacklist: string[];
@@ -297,4 +310,4 @@ type InferRemoveResultFromPath<App extends Application, Path extends string, IdO
297
310
  type InferDataFromPath<App extends Application, Path extends string, Method extends "create" | "update" | "patch"> = Method extends "create" ? InferCreateDataFromPath<App, Path> : Method extends "update" ? InferUpdateDataFromPath<App, Path> : Method extends "patch" ? InferPatchDataFromPath<App, Path> : never;
298
311
  type InferResultFromPath<App extends Application, Path extends string, Method extends "get" | "find" | "create" | "update" | "patch" | "remove"> = Method extends "get" ? InferGetResultFromPath<App, Path> : Method extends "find" ? InferFindResultFromPath<App, Path> : Method extends "create" ? InferCreateResultFromPath<App, Path> : Method extends "update" ? InferUpdateResultFromPath<App, Path> : Method extends "patch" ? InferPatchResultFromPath<App, Path> : Method extends "remove" ? InferRemoveResultFromPath<App, Path> : never;
299
312
 
300
- export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
313
+ export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, defineParamsForServer, defineParamsFromClient, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, paramsForServer, paramsFromClient, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
package/dist/index.d.ts CHANGED
@@ -40,6 +40,7 @@ type HookForEachOptions<T = any, H = HookContext, R = any> = {
40
40
  wait?: "sequential" | "parallel" | false;
41
41
  items?: GetItemsIsArrayOptions["from"];
42
42
  forAll?: (items: T[], context: H) => Promisable<R>;
43
+ skip?: (context: H) => Promisable<boolean>;
43
44
  };
44
45
  type ActionPerItem<T, H, R> = (item: T, options: {
45
46
  context: H;
@@ -101,6 +102,18 @@ interface HookSetDataOptions {
101
102
  */
102
103
  declare function setData<H extends HookContext = HookContext>(from: PropertyPath, to: PropertyPath, _options?: HookSetDataOptions): (context: H) => H;
103
104
 
105
+ declare function defineParamsForServer(keyToHide: string): (...whitelist: string[]) => <H extends HookContext<_feathersjs_feathers.Application<any, any>, any>>(context: H) => H;
106
+ /**
107
+ * a hook to move params to query._$client
108
+ * the server only receives 'query' from params. All other params are ignored.
109
+ * So, to use `$populateParams` on the server, we need to move the params to query._$client
110
+ * the server will move them back to params
111
+ */
112
+ declare const paramsForServer: (...whitelist: string[]) => <H extends HookContext<_feathersjs_feathers.Application<any, any>, any>>(context: H) => H;
113
+
114
+ declare function defineParamsFromClient(keyToHide: string): (...whitelist: string[]) => (context: HookContext) => HookContext;
115
+ declare const paramsFromClient: (...whitelist: string[]) => (context: HookContext) => HookContext;
116
+
104
117
  interface InitDebounceMixinOptions {
105
118
  default: Partial<DebouncedStoreOptions>;
106
119
  blacklist: string[];
@@ -297,4 +310,4 @@ type InferRemoveResultFromPath<App extends Application, Path extends string, IdO
297
310
  type InferDataFromPath<App extends Application, Path extends string, Method extends "create" | "update" | "patch"> = Method extends "create" ? InferCreateDataFromPath<App, Path> : Method extends "update" ? InferUpdateDataFromPath<App, Path> : Method extends "patch" ? InferPatchDataFromPath<App, Path> : never;
298
311
  type InferResultFromPath<App extends Application, Path extends string, Method extends "get" | "find" | "create" | "update" | "patch" | "remove"> = Method extends "get" ? InferGetResultFromPath<App, Path> : Method extends "find" ? InferFindResultFromPath<App, Path> : Method extends "create" ? InferCreateResultFromPath<App, Path> : Method extends "update" ? InferUpdateResultFromPath<App, Path> : Method extends "patch" ? InferPatchResultFromPath<App, Path> : Method extends "remove" ? InferRemoveResultFromPath<App, Path> : never;
299
312
 
300
- export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
313
+ export { type ActionOnEmptyIntersect, type CreateRelatedOptions, type DebouncedFunctionApp, type DebouncedService, DebouncedStore, type DebouncedStoreOptions, type FirstLast, type GetItemsIsArrayFrom, type GetItemsIsArrayOptions, type GetItemsIsArrayResult, type GetService, type Handle, type HookForEachOptions, type HookRunPerItemOptions, type HookSetDataOptions, type InferCreateData, type InferCreateDataFromPath, type InferCreateDataSingle, type InferCreateDataSingleFromPath, type InferCreateResult, type InferCreateResultFromPath, type InferCreateResultSingle, type InferCreateResultSingleFromPath, type InferDataFromPath, type InferFindResult, type InferFindResultFromPath, type InferGetResult, type InferGetResultFromPath, type InferPatchData, type InferPatchDataFromPath, type InferPatchResult, type InferPatchResultFromPath, type InferRemoveResult, type InferRemoveResultFromPath, type InferResultFromPath, type InferUpdateData, type InferUpdateDataFromPath, type InferUpdateResult, type InferUpdateResultFromPath, type InitDebounceMixinOptions, type MergeQueryOptions, type OnDeleteAction, type OnDeleteOptions, type OptimizeBatchPatchOptions, type OptimizeBatchPatchResultItem, type Predicate, type PredicateWithContext, type PushSetOptions, type RemoveRelatedOptions, type SetQueryKeySafelyOptions, type ShouldSkipOptions, checkMulti, createRelated, debounceMixin, defineHooks, defineParamsForServer, defineParamsFromClient, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, paramsForServer, paramsFromClient, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
package/dist/index.mjs CHANGED
@@ -674,6 +674,9 @@ const forEach = (actionPerItem, options) => {
674
674
  if (shouldSkip("forEach", context)) {
675
675
  return context;
676
676
  }
677
+ if (options?.skip && await options.skip(context)) {
678
+ return context;
679
+ }
677
680
  const { items } = getItemsIsArray(context, { from });
678
681
  const forAll = options?.forAll ? await options.forAll(items, context) : {};
679
682
  const promises = [];
@@ -860,6 +863,77 @@ function setData(from, to, _options) {
860
863
  };
861
864
  }
862
865
 
866
+ const FROM_CLIENT_FOR_SERVER_DEFAULT_KEY = "_$client";
867
+
868
+ function defineParamsForServer(keyToHide) {
869
+ return function paramsForServer2(...whitelist) {
870
+ return (context) => {
871
+ let clonedParams;
872
+ Object.keys(context.params).forEach((key) => {
873
+ if (key === "query") {
874
+ return;
875
+ }
876
+ if (whitelist.includes(key)) {
877
+ if (!clonedParams) {
878
+ clonedParams = {
879
+ ...context.params,
880
+ query: {
881
+ ...context.params.query
882
+ }
883
+ };
884
+ }
885
+ if (!clonedParams.query[keyToHide]) {
886
+ clonedParams.query[keyToHide] = {};
887
+ }
888
+ clonedParams.query[keyToHide][key] = clonedParams[key];
889
+ delete clonedParams[key];
890
+ }
891
+ });
892
+ if (clonedParams) {
893
+ context.params = clonedParams;
894
+ }
895
+ return context;
896
+ };
897
+ };
898
+ }
899
+ const paramsForServer = defineParamsForServer(
900
+ FROM_CLIENT_FOR_SERVER_DEFAULT_KEY
901
+ );
902
+
903
+ function defineParamsFromClient(keyToHide) {
904
+ return function paramsFromClient2(...whitelist) {
905
+ return (context) => {
906
+ if (!context.params?.query?.[keyToHide] || typeof context.params.query[keyToHide] !== "object") {
907
+ return context;
908
+ }
909
+ const params = {
910
+ ...context.params,
911
+ query: {
912
+ ...context.params.query,
913
+ [keyToHide]: {
914
+ ...context.params.query[keyToHide]
915
+ }
916
+ }
917
+ };
918
+ const client = params.query[keyToHide];
919
+ whitelist.forEach((key) => {
920
+ if (key in client) {
921
+ params[key] = client[key];
922
+ delete client[key];
923
+ }
924
+ });
925
+ if (Object.keys(client).length === 0) {
926
+ delete params.query[keyToHide];
927
+ }
928
+ context.params = params;
929
+ return context;
930
+ };
931
+ };
932
+ }
933
+ const paramsFromClient = defineParamsFromClient(
934
+ FROM_CLIENT_FOR_SERVER_DEFAULT_KEY
935
+ );
936
+
863
937
  var __defProp = Object.defineProperty;
864
938
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
865
939
  var __publicField = (obj, key, value) => {
@@ -981,4 +1055,4 @@ const filterObject = (...keys) => {
981
1055
  return result;
982
1056
  };
983
1057
 
984
- export { DebouncedStore, checkMulti, createRelated, debounceMixin, defineHooks, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
1058
+ export { DebouncedStore, checkMulti, createRelated, debounceMixin, defineHooks, defineParamsForServer, defineParamsFromClient, filterArray, filterObject, filterQuery, forEach, getItemsIsArray, getPaginate, isMulti, isPaginated, makeDefaultOptions, markHookForSkip, mergeArrays, mergeQuery, onDelete, optimizeBatchPatch, paramsForServer, paramsFromClient, parseFields, pushSet, removeRelated, runPerItem, setData, setQueryKeySafely, setResultEmpty, shouldSkip, toJSON, validateQueryProperty };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feathers-utils",
3
- "version": "5.0.1",
3
+ "version": "5.1.0",
4
4
  "description": "Some utils for projects using '@feathersjs/feathers'",
5
5
  "author": "fratzinger",
6
6
  "repository": {
@@ -9,6 +9,7 @@ export type HookForEachOptions<T = any, H = HookContext, R = any> = {
9
9
  wait?: "sequential" | "parallel" | false;
10
10
  items?: GetItemsIsArrayOptions["from"];
11
11
  forAll?: (items: T[], context: H) => Promisable<R>;
12
+ skip?: (context: H) => Promisable<boolean>;
12
13
  };
13
14
 
14
15
  type ActionPerItem<T, H, R> = (
@@ -31,6 +32,10 @@ export const forEach = <H extends HookContext = HookContext, T = any, R = any>(
31
32
  return context;
32
33
  }
33
34
 
35
+ if (options?.skip && (await options.skip(context))) {
36
+ return context;
37
+ }
38
+
34
39
  const { items } = getItemsIsArray(context, { from });
35
40
 
36
41
  const forAll = options?.forAll
@@ -0,0 +1 @@
1
+ export const FROM_CLIENT_FOR_SERVER_DEFAULT_KEY = "_$client" as const;
@@ -0,0 +1,2 @@
1
+ export * from "./paramsForServer";
2
+ export * from "./paramsFromClient";
@@ -0,0 +1,100 @@
1
+ import type { HookContext } from "@feathersjs/feathers";
2
+ import { FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } from "./common";
3
+
4
+ export function defineParamsForServer(keyToHide: string) {
5
+ return function paramsForServer(...whitelist: string[]) {
6
+ return <H extends HookContext>(context: H) => {
7
+ // clone params on demand
8
+ let clonedParams;
9
+
10
+ Object.keys(context.params).forEach((key) => {
11
+ if (key === "query") {
12
+ return;
13
+ }
14
+
15
+ if (whitelist.includes(key)) {
16
+ if (!clonedParams) {
17
+ clonedParams = {
18
+ ...context.params,
19
+ query: {
20
+ ...context.params.query,
21
+ },
22
+ };
23
+ }
24
+
25
+ if (!clonedParams.query[keyToHide]) {
26
+ clonedParams.query[keyToHide] = {};
27
+ }
28
+
29
+ clonedParams.query[keyToHide][key] = clonedParams[key];
30
+ delete clonedParams[key];
31
+ }
32
+ });
33
+
34
+ if (clonedParams) {
35
+ context.params = clonedParams;
36
+ }
37
+
38
+ return context;
39
+ };
40
+ };
41
+ }
42
+
43
+ /**
44
+ * a hook to move params to query._$client
45
+ * the server only receives 'query' from params. All other params are ignored.
46
+ * So, to use `$populateParams` on the server, we need to move the params to query._$client
47
+ * the server will move them back to params
48
+ */
49
+ export const paramsForServer = defineParamsForServer(
50
+ FROM_CLIENT_FOR_SERVER_DEFAULT_KEY,
51
+ );
52
+
53
+ if (import.meta.vitest) {
54
+ const { it, expect } = import.meta.vitest;
55
+
56
+ it("should move params to query._$client", () => {
57
+ expect(
58
+ paramsForServer(
59
+ "a",
60
+ "b",
61
+ )({
62
+ params: {
63
+ a: 1,
64
+ b: 2,
65
+ query: {},
66
+ },
67
+ } as HookContext),
68
+ ).toEqual({
69
+ params: {
70
+ query: {
71
+ _$client: {
72
+ a: 1,
73
+ b: 2,
74
+ },
75
+ },
76
+ },
77
+ });
78
+ });
79
+
80
+ it("should move params to query._$client and leave remaining", () => {
81
+ expect(
82
+ paramsForServer("a")({
83
+ params: {
84
+ a: 1,
85
+ b: 2,
86
+ query: {},
87
+ },
88
+ } as HookContext),
89
+ ).toEqual({
90
+ params: {
91
+ b: 2,
92
+ query: {
93
+ _$client: {
94
+ a: 1,
95
+ },
96
+ },
97
+ },
98
+ });
99
+ });
100
+ }
@@ -0,0 +1,105 @@
1
+ import type { HookContext } from "@feathersjs/feathers";
2
+ import { FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } from "./common";
3
+
4
+ export function defineParamsFromClient(keyToHide: string) {
5
+ return function paramsFromClient(
6
+ ...whitelist: string[]
7
+ ): (context: HookContext) => HookContext {
8
+ return (context: HookContext): HookContext => {
9
+ if (
10
+ !context.params?.query?.[keyToHide] ||
11
+ typeof context.params.query[keyToHide] !== "object"
12
+ ) {
13
+ return context;
14
+ }
15
+
16
+ const params = {
17
+ ...context.params,
18
+ query: {
19
+ ...context.params.query,
20
+ [keyToHide]: {
21
+ ...context.params.query[keyToHide],
22
+ },
23
+ },
24
+ };
25
+
26
+ const client = params.query[keyToHide];
27
+
28
+ whitelist.forEach((key) => {
29
+ if (key in client) {
30
+ params[key] = client[key];
31
+ delete client[key];
32
+ }
33
+ });
34
+
35
+ if (Object.keys(client).length === 0) {
36
+ delete params.query[keyToHide];
37
+ }
38
+
39
+ context.params = params;
40
+
41
+ return context;
42
+ };
43
+ };
44
+ }
45
+
46
+ export const paramsFromClient = defineParamsFromClient(
47
+ FROM_CLIENT_FOR_SERVER_DEFAULT_KEY,
48
+ );
49
+
50
+ if (import.meta.vitest) {
51
+ const { it, expect } = import.meta.vitest;
52
+
53
+ it("should move params to query._$client", () => {
54
+ expect(
55
+ paramsFromClient(
56
+ "a",
57
+ "b",
58
+ )({
59
+ params: {
60
+ query: {
61
+ _$client: {
62
+ a: 1,
63
+ b: 2,
64
+ },
65
+ c: 3,
66
+ },
67
+ },
68
+ } as HookContext),
69
+ ).toEqual({
70
+ params: {
71
+ a: 1,
72
+ b: 2,
73
+ query: {
74
+ c: 3,
75
+ },
76
+ },
77
+ });
78
+ });
79
+
80
+ it("should move params to query._$client and leave remaining", () => {
81
+ expect(
82
+ paramsFromClient("a")({
83
+ params: {
84
+ query: {
85
+ _$client: {
86
+ a: 1,
87
+ b: 2,
88
+ },
89
+ c: 3,
90
+ },
91
+ },
92
+ } as HookContext),
93
+ ).toEqual({
94
+ params: {
95
+ a: 1,
96
+ query: {
97
+ _$client: {
98
+ b: 2,
99
+ },
100
+ c: 3,
101
+ },
102
+ },
103
+ });
104
+ });
105
+ }
@@ -6,3 +6,4 @@ export * from "./parseFields";
6
6
  export * from "./removeRelated";
7
7
  export * from "./runPerItem";
8
8
  export * from "./setData";
9
+ export * from "./from-client-for-server";