@strapi/utils 5.12.1 → 5.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/dist/async.js +28 -0
  2. package/dist/async.js.map +1 -0
  3. package/dist/async.mjs +24 -0
  4. package/dist/async.mjs.map +1 -0
  5. package/dist/content-types.js +201 -0
  6. package/dist/content-types.js.map +1 -0
  7. package/dist/content-types.mjs +167 -0
  8. package/dist/content-types.mjs.map +1 -0
  9. package/dist/convert-query-params.js +512 -0
  10. package/dist/convert-query-params.js.map +1 -0
  11. package/dist/convert-query-params.mjs +510 -0
  12. package/dist/convert-query-params.mjs.map +1 -0
  13. package/dist/env-helper.js +81 -0
  14. package/dist/env-helper.js.map +1 -0
  15. package/dist/env-helper.mjs +79 -0
  16. package/dist/env-helper.mjs.map +1 -0
  17. package/dist/errors.js +104 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/errors.mjs +88 -0
  20. package/dist/errors.mjs.map +1 -0
  21. package/dist/file.js +57 -0
  22. package/dist/file.js.map +1 -0
  23. package/dist/file.mjs +50 -0
  24. package/dist/file.mjs.map +1 -0
  25. package/dist/format-yup-error.js +19 -0
  26. package/dist/format-yup-error.js.map +1 -0
  27. package/dist/format-yup-error.mjs +17 -0
  28. package/dist/format-yup-error.mjs.map +1 -0
  29. package/dist/hooks.js +86 -0
  30. package/dist/hooks.js.map +1 -0
  31. package/dist/hooks.mjs +80 -0
  32. package/dist/hooks.mjs.map +1 -0
  33. package/dist/import-default.js +9 -0
  34. package/dist/import-default.js.map +1 -0
  35. package/dist/import-default.mjs +7 -0
  36. package/dist/import-default.mjs.map +1 -0
  37. package/dist/index.js +54 -4358
  38. package/dist/index.js.map +1 -1
  39. package/dist/index.mjs +48 -4317
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/machine-id.js +17 -0
  42. package/dist/machine-id.js.map +1 -0
  43. package/dist/machine-id.mjs +15 -0
  44. package/dist/machine-id.mjs.map +1 -0
  45. package/dist/operators.js +79 -0
  46. package/dist/operators.js.map +1 -0
  47. package/dist/operators.mjs +76 -0
  48. package/dist/operators.mjs.map +1 -0
  49. package/dist/package-manager.js +36 -0
  50. package/dist/package-manager.js.map +1 -0
  51. package/dist/package-manager.mjs +33 -0
  52. package/dist/package-manager.mjs.map +1 -0
  53. package/dist/pagination.js +163 -0
  54. package/dist/pagination.js.map +1 -0
  55. package/dist/pagination.mjs +159 -0
  56. package/dist/pagination.mjs.map +1 -0
  57. package/dist/parse-type.js +140 -0
  58. package/dist/parse-type.js.map +1 -0
  59. package/dist/parse-type.mjs +118 -0
  60. package/dist/parse-type.mjs.map +1 -0
  61. package/dist/policy.js +33 -0
  62. package/dist/policy.js.map +1 -0
  63. package/dist/policy.mjs +30 -0
  64. package/dist/policy.mjs.map +1 -0
  65. package/dist/primitives/arrays.js +7 -0
  66. package/dist/primitives/arrays.js.map +1 -0
  67. package/dist/primitives/arrays.mjs +5 -0
  68. package/dist/primitives/arrays.mjs.map +1 -0
  69. package/dist/primitives/dates.js +11 -0
  70. package/dist/primitives/dates.js.map +1 -0
  71. package/dist/primitives/dates.mjs +9 -0
  72. package/dist/primitives/dates.mjs.map +1 -0
  73. package/dist/primitives/objects.js +13 -0
  74. package/dist/primitives/objects.js.map +1 -0
  75. package/dist/primitives/objects.mjs +11 -0
  76. package/dist/primitives/objects.mjs.map +1 -0
  77. package/dist/primitives/strings.js +49 -0
  78. package/dist/primitives/strings.js.map +1 -0
  79. package/dist/primitives/strings.mjs +38 -0
  80. package/dist/primitives/strings.mjs.map +1 -0
  81. package/dist/print-value.js +42 -0
  82. package/dist/print-value.js.map +1 -0
  83. package/dist/print-value.mjs +40 -0
  84. package/dist/print-value.mjs.map +1 -0
  85. package/dist/provider-factory.js +82 -0
  86. package/dist/provider-factory.js.map +1 -0
  87. package/dist/provider-factory.mjs +80 -0
  88. package/dist/provider-factory.mjs.map +1 -0
  89. package/dist/relations.js +54 -0
  90. package/dist/relations.js.map +1 -0
  91. package/dist/relations.mjs +45 -0
  92. package/dist/relations.mjs.map +1 -0
  93. package/dist/sanitize/index.js +195 -0
  94. package/dist/sanitize/index.js.map +1 -0
  95. package/dist/sanitize/index.mjs +194 -0
  96. package/dist/sanitize/index.mjs.map +1 -0
  97. package/dist/sanitize/sanitizers.js +173 -0
  98. package/dist/sanitize/sanitizers.js.map +1 -0
  99. package/dist/sanitize/sanitizers.mjs +166 -0
  100. package/dist/sanitize/sanitizers.mjs.map +1 -0
  101. package/dist/sanitize/visitors/expand-wildcard-populate.js +20 -0
  102. package/dist/sanitize/visitors/expand-wildcard-populate.js.map +1 -0
  103. package/dist/sanitize/visitors/expand-wildcard-populate.mjs +18 -0
  104. package/dist/sanitize/visitors/expand-wildcard-populate.mjs.map +1 -0
  105. package/dist/sanitize/visitors/index.js +22 -0
  106. package/dist/sanitize/visitors/index.js.map +1 -0
  107. package/dist/sanitize/visitors/index.mjs +9 -0
  108. package/dist/sanitize/visitors/index.mjs.map +1 -0
  109. package/dist/sanitize/visitors/remove-disallowed-fields.js +87 -0
  110. package/dist/sanitize/visitors/remove-disallowed-fields.js.map +1 -0
  111. package/dist/sanitize/visitors/remove-disallowed-fields.mjs +85 -0
  112. package/dist/sanitize/visitors/remove-disallowed-fields.mjs.map +1 -0
  113. package/dist/sanitize/visitors/remove-dynamic-zones.js +12 -0
  114. package/dist/sanitize/visitors/remove-dynamic-zones.js.map +1 -0
  115. package/dist/sanitize/visitors/remove-dynamic-zones.mjs +10 -0
  116. package/dist/sanitize/visitors/remove-dynamic-zones.mjs.map +1 -0
  117. package/dist/sanitize/visitors/remove-morph-to-relations.js +12 -0
  118. package/dist/sanitize/visitors/remove-morph-to-relations.js.map +1 -0
  119. package/dist/sanitize/visitors/remove-morph-to-relations.mjs +10 -0
  120. package/dist/sanitize/visitors/remove-morph-to-relations.mjs.map +1 -0
  121. package/dist/sanitize/visitors/remove-password.js +10 -0
  122. package/dist/sanitize/visitors/remove-password.js.map +1 -0
  123. package/dist/sanitize/visitors/remove-password.mjs +8 -0
  124. package/dist/sanitize/visitors/remove-password.mjs.map +1 -0
  125. package/dist/sanitize/visitors/remove-private.js +16 -0
  126. package/dist/sanitize/visitors/remove-private.js.map +1 -0
  127. package/dist/sanitize/visitors/remove-private.mjs +14 -0
  128. package/dist/sanitize/visitors/remove-private.mjs.map +1 -0
  129. package/dist/sanitize/visitors/remove-restricted-fields.js +28 -0
  130. package/dist/sanitize/visitors/remove-restricted-fields.js.map +1 -0
  131. package/dist/sanitize/visitors/remove-restricted-fields.mjs +26 -0
  132. package/dist/sanitize/visitors/remove-restricted-fields.mjs.map +1 -0
  133. package/dist/sanitize/visitors/remove-restricted-relations.js +116 -0
  134. package/dist/sanitize/visitors/remove-restricted-relations.js.map +1 -0
  135. package/dist/sanitize/visitors/remove-restricted-relations.mjs +114 -0
  136. package/dist/sanitize/visitors/remove-restricted-relations.mjs.map +1 -0
  137. package/dist/set-creator-fields.js +18 -0
  138. package/dist/set-creator-fields.js.map +1 -0
  139. package/dist/set-creator-fields.mjs +16 -0
  140. package/dist/set-creator-fields.mjs.map +1 -0
  141. package/dist/template.js +18 -0
  142. package/dist/template.js.map +1 -0
  143. package/dist/template.mjs +15 -0
  144. package/dist/template.mjs.map +1 -0
  145. package/dist/traverse/factory.js +158 -0
  146. package/dist/traverse/factory.js.map +1 -0
  147. package/dist/traverse/factory.mjs +156 -0
  148. package/dist/traverse/factory.mjs.map +1 -0
  149. package/dist/traverse/index.js +14 -0
  150. package/dist/traverse/index.js.map +1 -0
  151. package/dist/traverse/index.mjs +5 -0
  152. package/dist/traverse/index.mjs.map +1 -0
  153. package/dist/traverse/query-fields.js +41 -0
  154. package/dist/traverse/query-fields.js.map +1 -0
  155. package/dist/traverse/query-fields.mjs +39 -0
  156. package/dist/traverse/query-fields.mjs.map +1 -0
  157. package/dist/traverse/query-filters.js +114 -0
  158. package/dist/traverse/query-filters.js.map +1 -0
  159. package/dist/traverse/query-filters.mjs +112 -0
  160. package/dist/traverse/query-filters.mjs.map +1 -0
  161. package/dist/traverse/query-populate.js +280 -0
  162. package/dist/traverse/query-populate.js.map +1 -0
  163. package/dist/traverse/query-populate.mjs +278 -0
  164. package/dist/traverse/query-populate.mjs.map +1 -0
  165. package/dist/traverse/query-sort.js +144 -0
  166. package/dist/traverse/query-sort.js.map +1 -0
  167. package/dist/traverse/query-sort.mjs +142 -0
  168. package/dist/traverse/query-sort.mjs.map +1 -0
  169. package/dist/traverse-entity.js +170 -0
  170. package/dist/traverse-entity.js.map +1 -0
  171. package/dist/traverse-entity.mjs +168 -0
  172. package/dist/traverse-entity.mjs.map +1 -0
  173. package/dist/validate/index.js +218 -0
  174. package/dist/validate/index.js.map +1 -0
  175. package/dist/validate/index.mjs +217 -0
  176. package/dist/validate/index.mjs.map +1 -0
  177. package/dist/validate/utils.js +27 -0
  178. package/dist/validate/utils.js.map +1 -0
  179. package/dist/validate/utils.mjs +24 -0
  180. package/dist/validate/utils.mjs.map +1 -0
  181. package/dist/validate/validators.js +369 -0
  182. package/dist/validate/validators.js.map +1 -0
  183. package/dist/validate/validators.mjs +356 -0
  184. package/dist/validate/validators.mjs.map +1 -0
  185. package/dist/validate/visitors/index.js +22 -0
  186. package/dist/validate/visitors/index.js.map +1 -0
  187. package/dist/validate/visitors/index.mjs +9 -0
  188. package/dist/validate/visitors/index.mjs.map +1 -0
  189. package/dist/validate/visitors/throw-disallowed-fields.js +91 -0
  190. package/dist/validate/visitors/throw-disallowed-fields.js.map +1 -0
  191. package/dist/validate/visitors/throw-disallowed-fields.mjs +89 -0
  192. package/dist/validate/visitors/throw-disallowed-fields.mjs.map +1 -0
  193. package/dist/validate/visitors/throw-dynamic-zones.js +16 -0
  194. package/dist/validate/visitors/throw-dynamic-zones.js.map +1 -0
  195. package/dist/validate/visitors/throw-dynamic-zones.mjs +14 -0
  196. package/dist/validate/visitors/throw-dynamic-zones.mjs.map +1 -0
  197. package/dist/validate/visitors/throw-morph-to-relations.js +16 -0
  198. package/dist/validate/visitors/throw-morph-to-relations.js.map +1 -0
  199. package/dist/validate/visitors/throw-morph-to-relations.mjs +14 -0
  200. package/dist/validate/visitors/throw-morph-to-relations.mjs.map +1 -0
  201. package/dist/validate/visitors/throw-password.js +15 -0
  202. package/dist/validate/visitors/throw-password.js.map +1 -0
  203. package/dist/validate/visitors/throw-password.mjs +13 -0
  204. package/dist/validate/visitors/throw-password.mjs.map +1 -0
  205. package/dist/validate/visitors/throw-private.js +20 -0
  206. package/dist/validate/visitors/throw-private.js.map +1 -0
  207. package/dist/validate/visitors/throw-private.mjs +18 -0
  208. package/dist/validate/visitors/throw-private.mjs.map +1 -0
  209. package/dist/validate/visitors/throw-restricted-fields.js +36 -0
  210. package/dist/validate/visitors/throw-restricted-fields.js.map +1 -0
  211. package/dist/validate/visitors/throw-restricted-fields.mjs +34 -0
  212. package/dist/validate/visitors/throw-restricted-fields.mjs.map +1 -0
  213. package/dist/validate/visitors/throw-restricted-relations.js +125 -0
  214. package/dist/validate/visitors/throw-restricted-relations.js.map +1 -0
  215. package/dist/validate/visitors/throw-restricted-relations.mjs +123 -0
  216. package/dist/validate/visitors/throw-restricted-relations.mjs.map +1 -0
  217. package/dist/validate/visitors/throw-unrecognized-fields.js +66 -0
  218. package/dist/validate/visitors/throw-unrecognized-fields.js.map +1 -0
  219. package/dist/validate/visitors/throw-unrecognized-fields.mjs +64 -0
  220. package/dist/validate/visitors/throw-unrecognized-fields.mjs.map +1 -0
  221. package/dist/validators.js +60 -0
  222. package/dist/validators.js.map +1 -0
  223. package/dist/validators.mjs +37 -0
  224. package/dist/validators.mjs.map +1 -0
  225. package/dist/yup.js +101 -0
  226. package/dist/yup.js.map +1 -0
  227. package/dist/yup.mjs +74 -0
  228. package/dist/yup.mjs.map +1 -0
  229. package/dist/zod.js +31 -0
  230. package/dist/zod.js.map +1 -0
  231. package/dist/zod.mjs +29 -0
  232. package/dist/zod.mjs.map +1 -0
  233. package/package.json +3 -3
@@ -0,0 +1,218 @@
1
+ 'use strict';
2
+
3
+ var fp = require('lodash/fp');
4
+ var contentTypes = require('../content-types.js');
5
+ var async = require('../async.js');
6
+ var utils = require('./utils.js');
7
+ var index = require('./visitors/index.js');
8
+ var validators = require('./validators.js');
9
+ var traverseEntity = require('../traverse-entity.js');
10
+ var queryFilters = require('../traverse/query-filters.js');
11
+ var querySort = require('../traverse/query-sort.js');
12
+ var queryPopulate = require('../traverse/query-populate.js');
13
+ require('../traverse/query-fields.js');
14
+ var errors = require('../errors.js');
15
+ var throwUnrecognizedFields = require('./visitors/throw-unrecognized-fields.js');
16
+ var throwRestrictedFields = require('./visitors/throw-restricted-fields.js');
17
+ var throwRestrictedRelations = require('./visitors/throw-restricted-relations.js');
18
+
19
+ const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = contentTypes.constants;
20
+ const createAPIValidators = (opts)=>{
21
+ const { getModel } = opts || {};
22
+ const validateInput = async (data, schema, { auth } = {})=>{
23
+ if (!schema) {
24
+ throw new Error('Missing schema in validateInput');
25
+ }
26
+ if (fp.isArray(data)) {
27
+ await Promise.all(data.map((entry)=>validateInput(entry, schema, {
28
+ auth
29
+ })));
30
+ return;
31
+ }
32
+ const nonWritableAttributes = contentTypes.getNonWritableAttributes(schema);
33
+ const transforms = [
34
+ (data)=>{
35
+ if (fp.isObject(data)) {
36
+ if (ID_ATTRIBUTE in data) {
37
+ utils.throwInvalidKey({
38
+ key: ID_ATTRIBUTE
39
+ });
40
+ }
41
+ if (DOC_ID_ATTRIBUTE in data) {
42
+ utils.throwInvalidKey({
43
+ key: DOC_ID_ATTRIBUTE
44
+ });
45
+ }
46
+ }
47
+ return data;
48
+ },
49
+ // non-writable attributes
50
+ traverseEntity(throwRestrictedFields(nonWritableAttributes), {
51
+ schema,
52
+ getModel
53
+ }),
54
+ // unrecognized attributes
55
+ traverseEntity(throwUnrecognizedFields, {
56
+ schema,
57
+ getModel
58
+ })
59
+ ];
60
+ if (auth) {
61
+ // restricted relations
62
+ transforms.push(traverseEntity(throwRestrictedRelations(auth), {
63
+ schema,
64
+ getModel
65
+ }));
66
+ }
67
+ // Apply validators from registry if exists
68
+ opts?.validators?.input?.forEach((validator)=>transforms.push(validator(schema)));
69
+ try {
70
+ await async.pipe(...transforms)(data);
71
+ } catch (e) {
72
+ if (e instanceof errors.ValidationError) {
73
+ e.details.source = 'body';
74
+ }
75
+ throw e;
76
+ }
77
+ };
78
+ const validateQuery = async (query, schema, { auth } = {})=>{
79
+ if (!schema) {
80
+ throw new Error('Missing schema in validateQuery');
81
+ }
82
+ const { filters, sort, fields, populate } = query;
83
+ if (filters) {
84
+ await validateFilters(filters, schema, {
85
+ auth
86
+ });
87
+ }
88
+ if (sort) {
89
+ await validateSort(sort, schema, {
90
+ auth
91
+ });
92
+ }
93
+ if (fields) {
94
+ await validateFields(fields, schema);
95
+ }
96
+ // a wildcard is always valid; its conversion will be handled by the entity service and can be optimized with sanitizer
97
+ if (populate && populate !== '*') {
98
+ await validatePopulate(populate, schema);
99
+ }
100
+ };
101
+ const validateFilters = async (filters, schema, { auth } = {})=>{
102
+ if (!schema) {
103
+ throw new Error('Missing schema in validateFilters');
104
+ }
105
+ if (fp.isArray(filters)) {
106
+ await Promise.all(filters.map((filter)=>validateFilters(filter, schema, {
107
+ auth
108
+ })));
109
+ return;
110
+ }
111
+ const transforms = [
112
+ validators.defaultValidateFilters({
113
+ schema,
114
+ getModel
115
+ })
116
+ ];
117
+ if (auth) {
118
+ transforms.push(queryFilters(throwRestrictedRelations(auth), {
119
+ schema,
120
+ getModel
121
+ }));
122
+ }
123
+ try {
124
+ await async.pipe(...transforms)(filters);
125
+ } catch (e) {
126
+ if (e instanceof errors.ValidationError) {
127
+ e.details.source = 'query';
128
+ e.details.param = 'filters';
129
+ }
130
+ throw e;
131
+ }
132
+ };
133
+ const validateSort = async (sort, schema, { auth } = {})=>{
134
+ if (!schema) {
135
+ throw new Error('Missing schema in validateSort');
136
+ }
137
+ const transforms = [
138
+ validators.defaultValidateSort({
139
+ schema,
140
+ getModel
141
+ })
142
+ ];
143
+ if (auth) {
144
+ transforms.push(querySort(throwRestrictedRelations(auth), {
145
+ schema,
146
+ getModel
147
+ }));
148
+ }
149
+ try {
150
+ await async.pipe(...transforms)(sort);
151
+ } catch (e) {
152
+ if (e instanceof errors.ValidationError) {
153
+ e.details.source = 'query';
154
+ e.details.param = 'sort';
155
+ }
156
+ throw e;
157
+ }
158
+ };
159
+ const validateFields = async (fields, schema)=>{
160
+ if (!schema) {
161
+ throw new Error('Missing schema in validateFields');
162
+ }
163
+ const transforms = [
164
+ validators.defaultValidateFields({
165
+ schema,
166
+ getModel
167
+ })
168
+ ];
169
+ try {
170
+ await async.pipe(...transforms)(fields);
171
+ } catch (e) {
172
+ if (e instanceof errors.ValidationError) {
173
+ e.details.source = 'query';
174
+ e.details.param = 'fields';
175
+ }
176
+ throw e;
177
+ }
178
+ };
179
+ const validatePopulate = async (populate, schema, { auth } = {})=>{
180
+ if (!schema) {
181
+ throw new Error('Missing schema in sanitizePopulate');
182
+ }
183
+ const transforms = [
184
+ validators.defaultValidatePopulate({
185
+ schema,
186
+ getModel
187
+ })
188
+ ];
189
+ if (auth) {
190
+ transforms.push(queryPopulate(throwRestrictedRelations(auth), {
191
+ schema,
192
+ getModel
193
+ }));
194
+ }
195
+ try {
196
+ await async.pipe(...transforms)(populate);
197
+ } catch (e) {
198
+ if (e instanceof errors.ValidationError) {
199
+ e.details.source = 'query';
200
+ e.details.param = 'populate';
201
+ }
202
+ throw e;
203
+ }
204
+ };
205
+ return {
206
+ input: validateInput,
207
+ query: validateQuery,
208
+ filters: validateFilters,
209
+ sort: validateSort,
210
+ fields: validateFields,
211
+ populate: validatePopulate
212
+ };
213
+ };
214
+
215
+ exports.visitors = index;
216
+ exports.validators = validators;
217
+ exports.createAPIValidators = createAPIValidators;
218
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/validate/index.ts"],"sourcesContent":["import { CurriedFunction1 } from 'lodash';\nimport { isArray, isObject } from 'lodash/fp';\n\nimport { getNonWritableAttributes, constants } from '../content-types';\nimport { pipe as pipeAsync } from '../async';\nimport { throwInvalidKey } from './utils';\n\nimport * as visitors from './visitors';\nimport * as validators from './validators';\nimport traverseEntity from '../traverse-entity';\n\nimport { traverseQueryFilters, traverseQuerySort, traverseQueryPopulate } from '../traverse';\n\nimport { Model, Data } from '../types';\nimport { ValidationError } from '../errors';\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nexport interface Options {\n auth?: unknown;\n}\n\nexport interface Validator {\n (schema: Model): CurriedFunction1<Data, Promise<Data>>;\n}\nexport interface ValidateFunc {\n (data: unknown, schema: Model, options?: Options): Promise<void>;\n}\n\ninterface APIOptions {\n validators?: Validators;\n getModel: (model: string) => Model;\n}\n\nexport interface Validators {\n input?: Validator[];\n}\n\nconst createAPIValidators = (opts: APIOptions) => {\n const { getModel } = opts || {};\n\n const validateInput: ValidateFunc = async (data: unknown, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in validateInput');\n }\n\n if (isArray(data)) {\n await Promise.all(data.map((entry) => validateInput(entry, schema, { auth })));\n return;\n }\n\n const nonWritableAttributes = getNonWritableAttributes(schema);\n\n const transforms = [\n (data: unknown) => {\n if (isObject(data)) {\n if (ID_ATTRIBUTE in data) {\n throwInvalidKey({ key: ID_ATTRIBUTE });\n }\n\n if (DOC_ID_ATTRIBUTE in data) {\n throwInvalidKey({ key: DOC_ID_ATTRIBUTE });\n }\n }\n return data;\n },\n // non-writable attributes\n traverseEntity(visitors.throwRestrictedFields(nonWritableAttributes), { schema, getModel }),\n // unrecognized attributes\n traverseEntity(visitors.throwUnrecognizedFields, { schema, getModel }),\n ];\n\n if (auth) {\n // restricted relations\n transforms.push(\n traverseEntity(visitors.throwRestrictedRelations(auth), {\n schema,\n getModel,\n })\n );\n }\n\n // Apply validators from registry if exists\n opts?.validators?.input?.forEach((validator: Validator) => transforms.push(validator(schema)));\n\n try {\n await pipeAsync(...transforms)(data as Data);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'body';\n }\n throw e;\n }\n };\n\n const validateQuery = async (\n query: Record<string, unknown>,\n schema: Model,\n { auth }: Options = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in validateQuery');\n }\n const { filters, sort, fields, populate } = query;\n\n if (filters) {\n await validateFilters(filters, schema, { auth });\n }\n\n if (sort) {\n await validateSort(sort, schema, { auth });\n }\n\n if (fields) {\n await validateFields(fields, schema);\n }\n\n // a wildcard is always valid; its conversion will be handled by the entity service and can be optimized with sanitizer\n if (populate && populate !== '*') {\n await validatePopulate(populate, schema);\n }\n };\n\n const validateFilters: ValidateFunc = async (filters, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in validateFilters');\n }\n if (isArray(filters)) {\n await Promise.all(filters.map((filter) => validateFilters(filter, schema, { auth })));\n return;\n }\n\n const transforms = [validators.defaultValidateFilters({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryFilters(visitors.throwRestrictedRelations(auth), {\n schema,\n getModel,\n })\n );\n }\n\n try {\n await pipeAsync(...transforms)(filters);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'query';\n e.details.param = 'filters';\n }\n throw e;\n }\n };\n\n const validateSort: ValidateFunc = async (sort, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in validateSort');\n }\n const transforms = [validators.defaultValidateSort({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQuerySort(visitors.throwRestrictedRelations(auth), {\n schema,\n getModel,\n })\n );\n }\n\n try {\n await pipeAsync(...transforms)(sort);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'query';\n e.details.param = 'sort';\n }\n throw e;\n }\n };\n\n const validateFields: ValidateFunc = async (fields, schema: Model) => {\n if (!schema) {\n throw new Error('Missing schema in validateFields');\n }\n const transforms = [validators.defaultValidateFields({ schema, getModel })];\n\n try {\n await pipeAsync(...transforms)(fields);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'query';\n e.details.param = 'fields';\n }\n throw e;\n }\n };\n\n const validatePopulate: ValidateFunc = async (populate, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizePopulate');\n }\n const transforms = [validators.defaultValidatePopulate({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryPopulate(visitors.throwRestrictedRelations(auth), {\n schema,\n getModel,\n })\n );\n }\n\n try {\n await pipeAsync(...transforms)(populate);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'query';\n e.details.param = 'populate';\n }\n throw e;\n }\n };\n\n return {\n input: validateInput,\n query: validateQuery,\n filters: validateFilters,\n sort: validateSort,\n fields: validateFields,\n populate: validatePopulate,\n };\n};\n\nexport { createAPIValidators, validators, visitors };\n\nexport type APIValidators = ReturnType<typeof createAPIValidators>;\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","createAPIValidators","opts","getModel","validateInput","data","schema","auth","Error","isArray","Promise","all","map","entry","nonWritableAttributes","getNonWritableAttributes","transforms","isObject","throwInvalidKey","key","traverseEntity","visitors","push","validators","input","forEach","validator","pipeAsync","e","ValidationError","details","source","validateQuery","query","filters","sort","fields","populate","validateFilters","validateSort","validateFields","validatePopulate","filter","traverseQueryFilters","param","traverseQuerySort","traverseQueryPopulate"],"mappings":";;;;;;;;;;;;;;;;;;AAgBA,MAAM,EAAEA,YAAY,EAAEC,gBAAgB,EAAE,GAAGC,sBAAAA;AAsB3C,MAAMC,sBAAsB,CAACC,IAAAA,GAAAA;AAC3B,IAAA,MAAM,EAAEC,QAAQ,EAAE,GAAGD,QAAQ,EAAC;IAE9B,MAAME,aAAAA,GAA8B,OAAOC,IAAeC,EAAAA,MAAAA,EAAe,EAAEC,IAAI,EAAE,GAAG,EAAE,GAAA;AACpF,QAAA,IAAI,CAACD,MAAQ,EAAA;AACX,YAAA,MAAM,IAAIE,KAAM,CAAA,iCAAA,CAAA;AAClB;AAEA,QAAA,IAAIC,WAAQJ,IAAO,CAAA,EAAA;YACjB,MAAMK,OAAAA,CAAQC,GAAG,CAACN,IAAKO,CAAAA,GAAG,CAAC,CAACC,KAAAA,GAAUT,aAAcS,CAAAA,KAAAA,EAAOP,MAAQ,EAAA;AAAEC,oBAAAA;AAAK,iBAAA,CAAA,CAAA,CAAA;AAC1E,YAAA;AACF;AAEA,QAAA,MAAMO,wBAAwBC,qCAAyBT,CAAAA,MAAAA,CAAAA;AAEvD,QAAA,MAAMU,UAAa,GAAA;YACjB,CAACX,IAAAA,GAAAA;AACC,gBAAA,IAAIY,YAASZ,IAAO,CAAA,EAAA;AAClB,oBAAA,IAAIP,gBAAgBO,IAAM,EAAA;wBACxBa,qBAAgB,CAAA;4BAAEC,GAAKrB,EAAAA;AAAa,yBAAA,CAAA;AACtC;AAEA,oBAAA,IAAIC,oBAAoBM,IAAM,EAAA;wBAC5Ba,qBAAgB,CAAA;4BAAEC,GAAKpB,EAAAA;AAAiB,yBAAA,CAAA;AAC1C;AACF;gBACA,OAAOM,IAAAA;AACT,aAAA;;YAEAe,cAAeC,CAAAA,qBAA8B,CAACP,qBAAwB,CAAA,EAAA;AAAER,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA,CAAA;;YAEzFiB,cAAeC,CAAAA,uBAAgC,EAAE;AAAEf,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AACrE,SAAA;AAED,QAAA,IAAII,IAAM,EAAA;;AAERS,YAAAA,UAAAA,CAAWM,IAAI,CACbF,cAAAA,CAAeC,wBAAiC,CAACd,IAAO,CAAA,EAAA;AACtDD,gBAAAA,MAAAA;AACAH,gBAAAA;AACF,aAAA,CAAA,CAAA;AAEJ;;QAGAD,IAAMqB,EAAAA,UAAAA,EAAYC,OAAOC,OAAQ,CAAA,CAACC,YAAyBV,UAAWM,CAAAA,IAAI,CAACI,SAAUpB,CAAAA,MAAAA,CAAAA,CAAAA,CAAAA;QAErF,IAAI;AACF,YAAA,MAAMqB,cAAaX,UAAYX,CAAAA,CAAAA,IAAAA,CAAAA;AACjC,SAAA,CAAE,OAAOuB,CAAG,EAAA;AACV,YAAA,IAAIA,aAAaC,sBAAiB,EAAA;gBAChCD,CAAEE,CAAAA,OAAO,CAACC,MAAM,GAAG,MAAA;AACrB;YACA,MAAMH,CAAAA;AACR;AACF,KAAA;IAEA,MAAMI,aAAAA,GAAgB,OACpBC,KACA3B,EAAAA,MAAAA,EACA,EAAEC,IAAI,EAAW,GAAG,EAAE,GAAA;AAEtB,QAAA,IAAI,CAACD,MAAQ,EAAA;AACX,YAAA,MAAM,IAAIE,KAAM,CAAA,iCAAA,CAAA;AAClB;QACA,MAAM,EAAE0B,OAAO,EAAEC,IAAI,EAAEC,MAAM,EAAEC,QAAQ,EAAE,GAAGJ,KAAAA;AAE5C,QAAA,IAAIC,OAAS,EAAA;YACX,MAAMI,eAAAA,CAAgBJ,SAAS5B,MAAQ,EAAA;AAAEC,gBAAAA;AAAK,aAAA,CAAA;AAChD;AAEA,QAAA,IAAI4B,IAAM,EAAA;YACR,MAAMI,YAAAA,CAAaJ,MAAM7B,MAAQ,EAAA;AAAEC,gBAAAA;AAAK,aAAA,CAAA;AAC1C;AAEA,QAAA,IAAI6B,MAAQ,EAAA;AACV,YAAA,MAAMI,eAAeJ,MAAQ9B,EAAAA,MAAAA,CAAAA;AAC/B;;QAGA,IAAI+B,QAAAA,IAAYA,aAAa,GAAK,EAAA;AAChC,YAAA,MAAMI,iBAAiBJ,QAAU/B,EAAAA,MAAAA,CAAAA;AACnC;AACF,KAAA;IAEA,MAAMgC,eAAAA,GAAgC,OAAOJ,OAAS5B,EAAAA,MAAAA,EAAe,EAAEC,IAAI,EAAE,GAAG,EAAE,GAAA;AAChF,QAAA,IAAI,CAACD,MAAQ,EAAA;AACX,YAAA,MAAM,IAAIE,KAAM,CAAA,mCAAA,CAAA;AAClB;AACA,QAAA,IAAIC,WAAQyB,OAAU,CAAA,EAAA;YACpB,MAAMxB,OAAAA,CAAQC,GAAG,CAACuB,OAAQtB,CAAAA,GAAG,CAAC,CAAC8B,MAAAA,GAAWJ,eAAgBI,CAAAA,MAAAA,EAAQpC,MAAQ,EAAA;AAAEC,oBAAAA;AAAK,iBAAA,CAAA,CAAA,CAAA;AACjF,YAAA;AACF;AAEA,QAAA,MAAMS,UAAa,GAAA;AAACO,YAAAA,iCAAiC,CAAC;AAAEjB,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAAG,SAAA;AAE5E,QAAA,IAAII,IAAM,EAAA;AACRS,YAAAA,UAAAA,CAAWM,IAAI,CACbqB,YAAAA,CAAqBtB,wBAAiC,CAACd,IAAO,CAAA,EAAA;AAC5DD,gBAAAA,MAAAA;AACAH,gBAAAA;AACF,aAAA,CAAA,CAAA;AAEJ;QAEA,IAAI;AACF,YAAA,MAAMwB,cAAaX,UAAYkB,CAAAA,CAAAA,OAAAA,CAAAA;AACjC,SAAA,CAAE,OAAON,CAAG,EAAA;AACV,YAAA,IAAIA,aAAaC,sBAAiB,EAAA;gBAChCD,CAAEE,CAAAA,OAAO,CAACC,MAAM,GAAG,OAAA;gBACnBH,CAAEE,CAAAA,OAAO,CAACc,KAAK,GAAG,SAAA;AACpB;YACA,MAAMhB,CAAAA;AACR;AACF,KAAA;IAEA,MAAMW,YAAAA,GAA6B,OAAOJ,IAAM7B,EAAAA,MAAAA,EAAe,EAAEC,IAAI,EAAE,GAAG,EAAE,GAAA;AAC1E,QAAA,IAAI,CAACD,MAAQ,EAAA;AACX,YAAA,MAAM,IAAIE,KAAM,CAAA,gCAAA,CAAA;AAClB;AACA,QAAA,MAAMQ,UAAa,GAAA;AAACO,YAAAA,8BAA8B,CAAC;AAAEjB,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAAG,SAAA;AAEzE,QAAA,IAAII,IAAM,EAAA;AACRS,YAAAA,UAAAA,CAAWM,IAAI,CACbuB,SAAAA,CAAkBxB,wBAAiC,CAACd,IAAO,CAAA,EAAA;AACzDD,gBAAAA,MAAAA;AACAH,gBAAAA;AACF,aAAA,CAAA,CAAA;AAEJ;QAEA,IAAI;AACF,YAAA,MAAMwB,cAAaX,UAAYmB,CAAAA,CAAAA,IAAAA,CAAAA;AACjC,SAAA,CAAE,OAAOP,CAAG,EAAA;AACV,YAAA,IAAIA,aAAaC,sBAAiB,EAAA;gBAChCD,CAAEE,CAAAA,OAAO,CAACC,MAAM,GAAG,OAAA;gBACnBH,CAAEE,CAAAA,OAAO,CAACc,KAAK,GAAG,MAAA;AACpB;YACA,MAAMhB,CAAAA;AACR;AACF,KAAA;IAEA,MAAMY,cAAAA,GAA+B,OAAOJ,MAAQ9B,EAAAA,MAAAA,GAAAA;AAClD,QAAA,IAAI,CAACA,MAAQ,EAAA;AACX,YAAA,MAAM,IAAIE,KAAM,CAAA,kCAAA,CAAA;AAClB;AACA,QAAA,MAAMQ,UAAa,GAAA;AAACO,YAAAA,gCAAgC,CAAC;AAAEjB,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAAG,SAAA;QAE3E,IAAI;AACF,YAAA,MAAMwB,cAAaX,UAAYoB,CAAAA,CAAAA,MAAAA,CAAAA;AACjC,SAAA,CAAE,OAAOR,CAAG,EAAA;AACV,YAAA,IAAIA,aAAaC,sBAAiB,EAAA;gBAChCD,CAAEE,CAAAA,OAAO,CAACC,MAAM,GAAG,OAAA;gBACnBH,CAAEE,CAAAA,OAAO,CAACc,KAAK,GAAG,QAAA;AACpB;YACA,MAAMhB,CAAAA;AACR;AACF,KAAA;IAEA,MAAMa,gBAAAA,GAAiC,OAAOJ,QAAU/B,EAAAA,MAAAA,EAAe,EAAEC,IAAI,EAAE,GAAG,EAAE,GAAA;AAClF,QAAA,IAAI,CAACD,MAAQ,EAAA;AACX,YAAA,MAAM,IAAIE,KAAM,CAAA,oCAAA,CAAA;AAClB;AACA,QAAA,MAAMQ,UAAa,GAAA;AAACO,YAAAA,kCAAkC,CAAC;AAAEjB,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAAG,SAAA;AAE7E,QAAA,IAAII,IAAM,EAAA;AACRS,YAAAA,UAAAA,CAAWM,IAAI,CACbwB,aAAAA,CAAsBzB,wBAAiC,CAACd,IAAO,CAAA,EAAA;AAC7DD,gBAAAA,MAAAA;AACAH,gBAAAA;AACF,aAAA,CAAA,CAAA;AAEJ;QAEA,IAAI;AACF,YAAA,MAAMwB,cAAaX,UAAYqB,CAAAA,CAAAA,QAAAA,CAAAA;AACjC,SAAA,CAAE,OAAOT,CAAG,EAAA;AACV,YAAA,IAAIA,aAAaC,sBAAiB,EAAA;gBAChCD,CAAEE,CAAAA,OAAO,CAACC,MAAM,GAAG,OAAA;gBACnBH,CAAEE,CAAAA,OAAO,CAACc,KAAK,GAAG,UAAA;AACpB;YACA,MAAMhB,CAAAA;AACR;AACF,KAAA;IAEA,OAAO;QACLJ,KAAOpB,EAAAA,aAAAA;QACP6B,KAAOD,EAAAA,aAAAA;QACPE,OAASI,EAAAA,eAAAA;QACTH,IAAMI,EAAAA,YAAAA;QACNH,MAAQI,EAAAA,cAAAA;QACRH,QAAUI,EAAAA;AACZ,KAAA;AACF;;;;;;"}
@@ -0,0 +1,217 @@
1
+ import { isArray, isObject } from 'lodash/fp';
2
+ import { getNonWritableAttributes, constants } from '../content-types.mjs';
3
+ import { pipe } from '../async.mjs';
4
+ import { throwInvalidKey } from './utils.mjs';
5
+ import * as index from './visitors/index.mjs';
6
+ export { index as visitors };
7
+ import { defaultValidateFilters, defaultValidateSort, defaultValidateFields, defaultValidatePopulate } from './validators.mjs';
8
+ import * as validators from './validators.mjs';
9
+ export { validators };
10
+ import traverseEntity from '../traverse-entity.mjs';
11
+ import traverseQueryFilters from '../traverse/query-filters.mjs';
12
+ import traverseQuerySort from '../traverse/query-sort.mjs';
13
+ import traverseQueryPopulate from '../traverse/query-populate.mjs';
14
+ import '../traverse/query-fields.mjs';
15
+ import { ValidationError } from '../errors.mjs';
16
+ import throwUnrecognizedFields from './visitors/throw-unrecognized-fields.mjs';
17
+ import throwRestrictedFields from './visitors/throw-restricted-fields.mjs';
18
+ import throwRestrictedRelations from './visitors/throw-restricted-relations.mjs';
19
+
20
+ const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;
21
+ const createAPIValidators = (opts)=>{
22
+ const { getModel } = opts || {};
23
+ const validateInput = async (data, schema, { auth } = {})=>{
24
+ if (!schema) {
25
+ throw new Error('Missing schema in validateInput');
26
+ }
27
+ if (isArray(data)) {
28
+ await Promise.all(data.map((entry)=>validateInput(entry, schema, {
29
+ auth
30
+ })));
31
+ return;
32
+ }
33
+ const nonWritableAttributes = getNonWritableAttributes(schema);
34
+ const transforms = [
35
+ (data)=>{
36
+ if (isObject(data)) {
37
+ if (ID_ATTRIBUTE in data) {
38
+ throwInvalidKey({
39
+ key: ID_ATTRIBUTE
40
+ });
41
+ }
42
+ if (DOC_ID_ATTRIBUTE in data) {
43
+ throwInvalidKey({
44
+ key: DOC_ID_ATTRIBUTE
45
+ });
46
+ }
47
+ }
48
+ return data;
49
+ },
50
+ // non-writable attributes
51
+ traverseEntity(throwRestrictedFields(nonWritableAttributes), {
52
+ schema,
53
+ getModel
54
+ }),
55
+ // unrecognized attributes
56
+ traverseEntity(throwUnrecognizedFields, {
57
+ schema,
58
+ getModel
59
+ })
60
+ ];
61
+ if (auth) {
62
+ // restricted relations
63
+ transforms.push(traverseEntity(throwRestrictedRelations(auth), {
64
+ schema,
65
+ getModel
66
+ }));
67
+ }
68
+ // Apply validators from registry if exists
69
+ opts?.validators?.input?.forEach((validator)=>transforms.push(validator(schema)));
70
+ try {
71
+ await pipe(...transforms)(data);
72
+ } catch (e) {
73
+ if (e instanceof ValidationError) {
74
+ e.details.source = 'body';
75
+ }
76
+ throw e;
77
+ }
78
+ };
79
+ const validateQuery = async (query, schema, { auth } = {})=>{
80
+ if (!schema) {
81
+ throw new Error('Missing schema in validateQuery');
82
+ }
83
+ const { filters, sort, fields, populate } = query;
84
+ if (filters) {
85
+ await validateFilters(filters, schema, {
86
+ auth
87
+ });
88
+ }
89
+ if (sort) {
90
+ await validateSort(sort, schema, {
91
+ auth
92
+ });
93
+ }
94
+ if (fields) {
95
+ await validateFields(fields, schema);
96
+ }
97
+ // a wildcard is always valid; its conversion will be handled by the entity service and can be optimized with sanitizer
98
+ if (populate && populate !== '*') {
99
+ await validatePopulate(populate, schema);
100
+ }
101
+ };
102
+ const validateFilters = async (filters, schema, { auth } = {})=>{
103
+ if (!schema) {
104
+ throw new Error('Missing schema in validateFilters');
105
+ }
106
+ if (isArray(filters)) {
107
+ await Promise.all(filters.map((filter)=>validateFilters(filter, schema, {
108
+ auth
109
+ })));
110
+ return;
111
+ }
112
+ const transforms = [
113
+ defaultValidateFilters({
114
+ schema,
115
+ getModel
116
+ })
117
+ ];
118
+ if (auth) {
119
+ transforms.push(traverseQueryFilters(throwRestrictedRelations(auth), {
120
+ schema,
121
+ getModel
122
+ }));
123
+ }
124
+ try {
125
+ await pipe(...transforms)(filters);
126
+ } catch (e) {
127
+ if (e instanceof ValidationError) {
128
+ e.details.source = 'query';
129
+ e.details.param = 'filters';
130
+ }
131
+ throw e;
132
+ }
133
+ };
134
+ const validateSort = async (sort, schema, { auth } = {})=>{
135
+ if (!schema) {
136
+ throw new Error('Missing schema in validateSort');
137
+ }
138
+ const transforms = [
139
+ defaultValidateSort({
140
+ schema,
141
+ getModel
142
+ })
143
+ ];
144
+ if (auth) {
145
+ transforms.push(traverseQuerySort(throwRestrictedRelations(auth), {
146
+ schema,
147
+ getModel
148
+ }));
149
+ }
150
+ try {
151
+ await pipe(...transforms)(sort);
152
+ } catch (e) {
153
+ if (e instanceof ValidationError) {
154
+ e.details.source = 'query';
155
+ e.details.param = 'sort';
156
+ }
157
+ throw e;
158
+ }
159
+ };
160
+ const validateFields = async (fields, schema)=>{
161
+ if (!schema) {
162
+ throw new Error('Missing schema in validateFields');
163
+ }
164
+ const transforms = [
165
+ defaultValidateFields({
166
+ schema,
167
+ getModel
168
+ })
169
+ ];
170
+ try {
171
+ await pipe(...transforms)(fields);
172
+ } catch (e) {
173
+ if (e instanceof ValidationError) {
174
+ e.details.source = 'query';
175
+ e.details.param = 'fields';
176
+ }
177
+ throw e;
178
+ }
179
+ };
180
+ const validatePopulate = async (populate, schema, { auth } = {})=>{
181
+ if (!schema) {
182
+ throw new Error('Missing schema in sanitizePopulate');
183
+ }
184
+ const transforms = [
185
+ defaultValidatePopulate({
186
+ schema,
187
+ getModel
188
+ })
189
+ ];
190
+ if (auth) {
191
+ transforms.push(traverseQueryPopulate(throwRestrictedRelations(auth), {
192
+ schema,
193
+ getModel
194
+ }));
195
+ }
196
+ try {
197
+ await pipe(...transforms)(populate);
198
+ } catch (e) {
199
+ if (e instanceof ValidationError) {
200
+ e.details.source = 'query';
201
+ e.details.param = 'populate';
202
+ }
203
+ throw e;
204
+ }
205
+ };
206
+ return {
207
+ input: validateInput,
208
+ query: validateQuery,
209
+ filters: validateFilters,
210
+ sort: validateSort,
211
+ fields: validateFields,
212
+ populate: validatePopulate
213
+ };
214
+ };
215
+
216
+ export { createAPIValidators };
217
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../../src/validate/index.ts"],"sourcesContent":["import { CurriedFunction1 } from 'lodash';\nimport { isArray, isObject } from 'lodash/fp';\n\nimport { getNonWritableAttributes, constants } from '../content-types';\nimport { pipe as pipeAsync } from '../async';\nimport { throwInvalidKey } from './utils';\n\nimport * as visitors from './visitors';\nimport * as validators from './validators';\nimport traverseEntity from '../traverse-entity';\n\nimport { traverseQueryFilters, traverseQuerySort, traverseQueryPopulate } from '../traverse';\n\nimport { Model, Data } from '../types';\nimport { ValidationError } from '../errors';\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nexport interface Options {\n auth?: unknown;\n}\n\nexport interface Validator {\n (schema: Model): CurriedFunction1<Data, Promise<Data>>;\n}\nexport interface ValidateFunc {\n (data: unknown, schema: Model, options?: Options): Promise<void>;\n}\n\ninterface APIOptions {\n validators?: Validators;\n getModel: (model: string) => Model;\n}\n\nexport interface Validators {\n input?: Validator[];\n}\n\nconst createAPIValidators = (opts: APIOptions) => {\n const { getModel } = opts || {};\n\n const validateInput: ValidateFunc = async (data: unknown, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in validateInput');\n }\n\n if (isArray(data)) {\n await Promise.all(data.map((entry) => validateInput(entry, schema, { auth })));\n return;\n }\n\n const nonWritableAttributes = getNonWritableAttributes(schema);\n\n const transforms = [\n (data: unknown) => {\n if (isObject(data)) {\n if (ID_ATTRIBUTE in data) {\n throwInvalidKey({ key: ID_ATTRIBUTE });\n }\n\n if (DOC_ID_ATTRIBUTE in data) {\n throwInvalidKey({ key: DOC_ID_ATTRIBUTE });\n }\n }\n return data;\n },\n // non-writable attributes\n traverseEntity(visitors.throwRestrictedFields(nonWritableAttributes), { schema, getModel }),\n // unrecognized attributes\n traverseEntity(visitors.throwUnrecognizedFields, { schema, getModel }),\n ];\n\n if (auth) {\n // restricted relations\n transforms.push(\n traverseEntity(visitors.throwRestrictedRelations(auth), {\n schema,\n getModel,\n })\n );\n }\n\n // Apply validators from registry if exists\n opts?.validators?.input?.forEach((validator: Validator) => transforms.push(validator(schema)));\n\n try {\n await pipeAsync(...transforms)(data as Data);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'body';\n }\n throw e;\n }\n };\n\n const validateQuery = async (\n query: Record<string, unknown>,\n schema: Model,\n { auth }: Options = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in validateQuery');\n }\n const { filters, sort, fields, populate } = query;\n\n if (filters) {\n await validateFilters(filters, schema, { auth });\n }\n\n if (sort) {\n await validateSort(sort, schema, { auth });\n }\n\n if (fields) {\n await validateFields(fields, schema);\n }\n\n // a wildcard is always valid; its conversion will be handled by the entity service and can be optimized with sanitizer\n if (populate && populate !== '*') {\n await validatePopulate(populate, schema);\n }\n };\n\n const validateFilters: ValidateFunc = async (filters, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in validateFilters');\n }\n if (isArray(filters)) {\n await Promise.all(filters.map((filter) => validateFilters(filter, schema, { auth })));\n return;\n }\n\n const transforms = [validators.defaultValidateFilters({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryFilters(visitors.throwRestrictedRelations(auth), {\n schema,\n getModel,\n })\n );\n }\n\n try {\n await pipeAsync(...transforms)(filters);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'query';\n e.details.param = 'filters';\n }\n throw e;\n }\n };\n\n const validateSort: ValidateFunc = async (sort, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in validateSort');\n }\n const transforms = [validators.defaultValidateSort({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQuerySort(visitors.throwRestrictedRelations(auth), {\n schema,\n getModel,\n })\n );\n }\n\n try {\n await pipeAsync(...transforms)(sort);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'query';\n e.details.param = 'sort';\n }\n throw e;\n }\n };\n\n const validateFields: ValidateFunc = async (fields, schema: Model) => {\n if (!schema) {\n throw new Error('Missing schema in validateFields');\n }\n const transforms = [validators.defaultValidateFields({ schema, getModel })];\n\n try {\n await pipeAsync(...transforms)(fields);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'query';\n e.details.param = 'fields';\n }\n throw e;\n }\n };\n\n const validatePopulate: ValidateFunc = async (populate, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizePopulate');\n }\n const transforms = [validators.defaultValidatePopulate({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryPopulate(visitors.throwRestrictedRelations(auth), {\n schema,\n getModel,\n })\n );\n }\n\n try {\n await pipeAsync(...transforms)(populate);\n } catch (e) {\n if (e instanceof ValidationError) {\n e.details.source = 'query';\n e.details.param = 'populate';\n }\n throw e;\n }\n };\n\n return {\n input: validateInput,\n query: validateQuery,\n filters: validateFilters,\n sort: validateSort,\n fields: validateFields,\n populate: validatePopulate,\n };\n};\n\nexport { createAPIValidators, validators, visitors };\n\nexport type APIValidators = ReturnType<typeof createAPIValidators>;\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","createAPIValidators","opts","getModel","validateInput","data","schema","auth","Error","isArray","Promise","all","map","entry","nonWritableAttributes","getNonWritableAttributes","transforms","isObject","throwInvalidKey","key","traverseEntity","visitors","push","validators","input","forEach","validator","pipeAsync","e","ValidationError","details","source","validateQuery","query","filters","sort","fields","populate","validateFilters","validateSort","validateFields","validatePopulate","filter","traverseQueryFilters","param","traverseQuerySort","traverseQueryPopulate"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+
3
+ var errors = require('../errors.js');
4
+
5
+ // lodash/fp curry does not handle async functions properly, and creates very "ugly" types,
6
+ // so we will use our own version to ensure curried functions are typed correctly
7
+ // TODO: Export this from root @strapi/utils so we don't have copies of it between packages
8
+ const throwInvalidKey = ({ key, path })=>{
9
+ const msg = path && path !== key ? `Invalid key ${key} at ${path}` : `Invalid key ${key}`;
10
+ throw new errors.ValidationError(msg, {
11
+ key,
12
+ path
13
+ });
14
+ };
15
+ const asyncCurry = (fn)=>{
16
+ const curried = (...args)=>{
17
+ if (args.length >= fn.length) {
18
+ return fn(...args);
19
+ }
20
+ return (...moreArgs)=>curried(...args, ...moreArgs);
21
+ };
22
+ return curried;
23
+ };
24
+
25
+ exports.asyncCurry = asyncCurry;
26
+ exports.throwInvalidKey = throwInvalidKey;
27
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../src/validate/utils.ts"],"sourcesContent":["// lodash/fp curry does not handle async functions properly, and creates very \"ugly\" types,\n// so we will use our own version to ensure curried functions are typed correctly\n// TODO: Export this from root @strapi/utils so we don't have copies of it between packages\n\nimport { ValidationError } from '../errors';\n\nexport const throwInvalidKey = ({ key, path }: { key: string; path?: string | null }): never => {\n const msg = path && path !== key ? `Invalid key ${key} at ${path}` : `Invalid key ${key}`;\n\n throw new ValidationError(msg, {\n key,\n path,\n });\n};\n\nexport const asyncCurry = <A extends unknown[], R>(\n fn: (...args: A) => Promise<R>\n): ((...args: Partial<A>) => any) => {\n const curried = (...args: unknown[]): unknown => {\n if (args.length >= fn.length) {\n return fn(...(args as A));\n }\n return (...moreArgs: unknown[]) => curried(...args, ...moreArgs);\n };\n\n return curried;\n};\n"],"names":["throwInvalidKey","key","path","msg","ValidationError","asyncCurry","fn","curried","args","length","moreArgs"],"mappings":";;;;AAAA;AACA;AACA;MAIaA,eAAkB,GAAA,CAAC,EAAEC,GAAG,EAAEC,IAAI,EAAyC,GAAA;AAClF,IAAA,MAAMC,MAAMD,IAAQA,IAAAA,IAAAA,KAASD,GAAM,GAAA,CAAC,YAAY,EAAEA,GAAAA,CAAI,IAAI,EAAEC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAED,IAAI,CAAC;IAEzF,MAAM,IAAIG,uBAAgBD,GAAK,EAAA;AAC7BF,QAAAA,GAAAA;AACAC,QAAAA;AACF,KAAA,CAAA;AACF;AAEO,MAAMG,aAAa,CACxBC,EAAAA,GAAAA;IAEA,MAAMC,OAAAA,GAAU,CAAC,GAAGC,IAAAA,GAAAA;AAClB,QAAA,IAAIA,IAAKC,CAAAA,MAAM,IAAIH,EAAAA,CAAGG,MAAM,EAAE;AAC5B,YAAA,OAAOH,EAAOE,CAAAA,GAAAA,IAAAA,CAAAA;AAChB;AACA,QAAA,OAAO,CAAC,GAAGE,QAAwBH,GAAAA,OAAAA,CAAAA,GAAWC,IAASE,EAAAA,GAAAA,QAAAA,CAAAA;AACzD,KAAA;IAEA,OAAOH,OAAAA;AACT;;;;;"}
@@ -0,0 +1,24 @@
1
+ import { ValidationError } from '../errors.mjs';
2
+
3
+ // lodash/fp curry does not handle async functions properly, and creates very "ugly" types,
4
+ // so we will use our own version to ensure curried functions are typed correctly
5
+ // TODO: Export this from root @strapi/utils so we don't have copies of it between packages
6
+ const throwInvalidKey = ({ key, path })=>{
7
+ const msg = path && path !== key ? `Invalid key ${key} at ${path}` : `Invalid key ${key}`;
8
+ throw new ValidationError(msg, {
9
+ key,
10
+ path
11
+ });
12
+ };
13
+ const asyncCurry = (fn)=>{
14
+ const curried = (...args)=>{
15
+ if (args.length >= fn.length) {
16
+ return fn(...args);
17
+ }
18
+ return (...moreArgs)=>curried(...args, ...moreArgs);
19
+ };
20
+ return curried;
21
+ };
22
+
23
+ export { asyncCurry, throwInvalidKey };
24
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.mjs","sources":["../../src/validate/utils.ts"],"sourcesContent":["// lodash/fp curry does not handle async functions properly, and creates very \"ugly\" types,\n// so we will use our own version to ensure curried functions are typed correctly\n// TODO: Export this from root @strapi/utils so we don't have copies of it between packages\n\nimport { ValidationError } from '../errors';\n\nexport const throwInvalidKey = ({ key, path }: { key: string; path?: string | null }): never => {\n const msg = path && path !== key ? `Invalid key ${key} at ${path}` : `Invalid key ${key}`;\n\n throw new ValidationError(msg, {\n key,\n path,\n });\n};\n\nexport const asyncCurry = <A extends unknown[], R>(\n fn: (...args: A) => Promise<R>\n): ((...args: Partial<A>) => any) => {\n const curried = (...args: unknown[]): unknown => {\n if (args.length >= fn.length) {\n return fn(...(args as A));\n }\n return (...moreArgs: unknown[]) => curried(...args, ...moreArgs);\n };\n\n return curried;\n};\n"],"names":["throwInvalidKey","key","path","msg","ValidationError","asyncCurry","fn","curried","args","length","moreArgs"],"mappings":";;AAAA;AACA;AACA;MAIaA,eAAkB,GAAA,CAAC,EAAEC,GAAG,EAAEC,IAAI,EAAyC,GAAA;AAClF,IAAA,MAAMC,MAAMD,IAAQA,IAAAA,IAAAA,KAASD,GAAM,GAAA,CAAC,YAAY,EAAEA,GAAAA,CAAI,IAAI,EAAEC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAED,IAAI,CAAC;IAEzF,MAAM,IAAIG,gBAAgBD,GAAK,EAAA;AAC7BF,QAAAA,GAAAA;AACAC,QAAAA;AACF,KAAA,CAAA;AACF;AAEO,MAAMG,aAAa,CACxBC,EAAAA,GAAAA;IAEA,MAAMC,OAAAA,GAAU,CAAC,GAAGC,IAAAA,GAAAA;AAClB,QAAA,IAAIA,IAAKC,CAAAA,MAAM,IAAIH,EAAAA,CAAGG,MAAM,EAAE;AAC5B,YAAA,OAAOH,EAAOE,CAAAA,GAAAA,IAAAA,CAAAA;AAChB;AACA,QAAA,OAAO,CAAC,GAAGE,QAAwBH,GAAAA,OAAAA,CAAAA,GAAWC,IAASE,EAAAA,GAAAA,QAAAA,CAAAA;AACzD,KAAA;IAEA,OAAOH,OAAAA;AACT;;;;"}