@strapi/utils 5.56.0 → 5.58.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/dist/async.js +2 -2
- package/dist/async.js.map +1 -1
- package/dist/async.mjs +1 -1
- package/dist/async.mjs.map +1 -1
- package/dist/content-types.d.ts.map +1 -1
- package/dist/content-types.js +8 -9
- package/dist/content-types.js.map +1 -1
- package/dist/content-types.mjs +6 -7
- package/dist/content-types.mjs.map +1 -1
- package/dist/convert-query-params.d.ts.map +1 -1
- package/dist/convert-query-params.js +33 -34
- package/dist/convert-query-params.js.map +1 -1
- package/dist/convert-query-params.mjs +23 -24
- package/dist/convert-query-params.mjs.map +1 -1
- package/dist/format-yup-error.js +3 -3
- package/dist/format-yup-error.js.map +1 -1
- package/dist/format-yup-error.mjs +1 -1
- package/dist/format-yup-error.mjs.map +1 -1
- package/dist/hooks.js +3 -3
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.mjs +2 -2
- package/dist/hooks.mjs.map +1 -1
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +15 -18
- package/dist/pagination.js.map +1 -1
- package/dist/pagination.mjs +15 -18
- package/dist/pagination.mjs.map +1 -1
- package/dist/policy.d.ts +1 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +1 -3
- package/dist/policy.js.map +1 -1
- package/dist/policy.mjs +1 -3
- package/dist/policy.mjs.map +1 -1
- package/dist/primitives/objects.d.ts +7 -1
- package/dist/primitives/objects.d.ts.map +1 -1
- package/dist/primitives/objects.js +5 -0
- package/dist/primitives/objects.js.map +1 -1
- package/dist/primitives/objects.mjs +5 -1
- package/dist/primitives/objects.mjs.map +1 -1
- package/dist/primitives/strings.d.ts.map +1 -1
- package/dist/primitives/strings.js +3 -7
- package/dist/primitives/strings.js.map +1 -1
- package/dist/primitives/strings.mjs +3 -7
- package/dist/primitives/strings.mjs.map +1 -1
- package/dist/provider-factory.js +4 -4
- package/dist/provider-factory.js.map +1 -1
- package/dist/provider-factory.mjs +1 -1
- package/dist/provider-factory.mjs.map +1 -1
- package/dist/relations.js +2 -2
- package/dist/relations.js.map +1 -1
- package/dist/relations.mjs +1 -1
- package/dist/relations.mjs.map +1 -1
- package/dist/sanitize/index.d.ts.map +1 -1
- package/dist/sanitize/index.js +8 -8
- package/dist/sanitize/index.js.map +1 -1
- package/dist/sanitize/index.mjs +7 -7
- package/dist/sanitize/index.mjs.map +1 -1
- package/dist/sanitize/sanitizers.js +10 -10
- package/dist/sanitize/sanitizers.js.map +1 -1
- package/dist/sanitize/sanitizers.mjs +4 -4
- package/dist/sanitize/sanitizers.mjs.map +1 -1
- package/dist/sanitize/visitors/remove-disallowed-fields.js +4 -4
- package/dist/sanitize/visitors/remove-disallowed-fields.js.map +1 -1
- package/dist/sanitize/visitors/remove-disallowed-fields.mjs +3 -3
- package/dist/sanitize/visitors/remove-disallowed-fields.mjs.map +1 -1
- package/dist/sanitize/visitors/remove-restricted-fields.js +2 -2
- package/dist/sanitize/visitors/remove-restricted-fields.js.map +1 -1
- package/dist/sanitize/visitors/remove-restricted-fields.mjs +2 -2
- package/dist/sanitize/visitors/remove-restricted-fields.mjs.map +1 -1
- package/dist/sanitize/visitors/remove-restricted-relations.js +9 -9
- package/dist/sanitize/visitors/remove-restricted-relations.js.map +1 -1
- package/dist/sanitize/visitors/remove-restricted-relations.mjs +4 -4
- package/dist/sanitize/visitors/remove-restricted-relations.mjs.map +1 -1
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +3 -3
- package/dist/security.js.map +1 -1
- package/dist/security.mjs +3 -3
- package/dist/security.mjs.map +1 -1
- package/dist/set-creator-fields.d.ts +4 -1
- package/dist/set-creator-fields.d.ts.map +1 -1
- package/dist/set-creator-fields.js +7 -4
- package/dist/set-creator-fields.js.map +1 -1
- package/dist/set-creator-fields.mjs +7 -4
- package/dist/set-creator-fields.mjs.map +1 -1
- package/dist/traverse/factory.js +8 -8
- package/dist/traverse/factory.js.map +1 -1
- package/dist/traverse/factory.mjs +8 -8
- package/dist/traverse/factory.mjs.map +1 -1
- package/dist/traverse/query-fields.js +7 -7
- package/dist/traverse/query-fields.js.map +1 -1
- package/dist/traverse/query-fields.mjs +3 -3
- package/dist/traverse/query-fields.mjs.map +1 -1
- package/dist/traverse/query-filters.js +12 -12
- package/dist/traverse/query-filters.js.map +1 -1
- package/dist/traverse/query-filters.mjs +7 -7
- package/dist/traverse/query-filters.mjs.map +1 -1
- package/dist/traverse/query-populate.d.ts.map +1 -1
- package/dist/traverse/query-populate.js +21 -21
- package/dist/traverse/query-populate.js.map +1 -1
- package/dist/traverse/query-populate.mjs +12 -12
- package/dist/traverse/query-populate.mjs.map +1 -1
- package/dist/traverse/query-sort.d.ts.map +1 -1
- package/dist/traverse/query-sort.js +16 -16
- package/dist/traverse/query-sort.js.map +1 -1
- package/dist/traverse/query-sort.mjs +6 -6
- package/dist/traverse/query-sort.mjs.map +1 -1
- package/dist/traverse-entity.d.ts.map +1 -1
- package/dist/traverse-entity.js +18 -18
- package/dist/traverse-entity.js.map +1 -1
- package/dist/traverse-entity.mjs +16 -16
- package/dist/traverse-entity.mjs.map +1 -1
- package/dist/validate/index.d.ts.map +1 -1
- package/dist/validate/index.js +5 -5
- package/dist/validate/index.js.map +1 -1
- package/dist/validate/index.mjs +3 -3
- package/dist/validate/index.mjs.map +1 -1
- package/dist/validate/utils.d.ts +2 -1
- package/dist/validate/utils.d.ts.map +1 -1
- package/dist/validate/utils.js +4 -4
- package/dist/validate/utils.js.map +1 -1
- package/dist/validate/utils.mjs +4 -4
- package/dist/validate/utils.mjs.map +1 -1
- package/dist/validate/validators.d.ts.map +1 -1
- package/dist/validate/validators.js +17 -9
- package/dist/validate/validators.js.map +1 -1
- package/dist/validate/validators.mjs +14 -6
- package/dist/validate/validators.mjs.map +1 -1
- package/dist/validate/visitors/throw-disallowed-fields.js +4 -4
- package/dist/validate/visitors/throw-disallowed-fields.js.map +1 -1
- package/dist/validate/visitors/throw-disallowed-fields.mjs +3 -3
- package/dist/validate/visitors/throw-disallowed-fields.mjs.map +1 -1
- package/dist/validate/visitors/throw-restricted-fields.js +2 -2
- package/dist/validate/visitors/throw-restricted-fields.js.map +1 -1
- package/dist/validate/visitors/throw-restricted-fields.mjs +2 -2
- package/dist/validate/visitors/throw-restricted-fields.mjs.map +1 -1
- package/dist/validate/visitors/throw-restricted-relations.js +6 -6
- package/dist/validate/visitors/throw-restricted-relations.js.map +1 -1
- package/dist/validate/visitors/throw-restricted-relations.mjs +2 -2
- package/dist/validate/visitors/throw-restricted-relations.mjs.map +1 -1
- package/dist/validators.js +3 -3
- package/dist/validators.js.map +1 -1
- package/dist/validators.mjs +3 -3
- package/dist/validators.mjs.map +1 -1
- package/dist/yup.d.ts.map +1 -1
- package/dist/yup.js +2 -3
- package/dist/yup.js.map +1 -1
- package/dist/yup.mjs +3 -4
- package/dist/yup.mjs.map +1 -1
- package/package.json +4 -4
package/dist/sanitize/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _ = require('lodash');
|
|
4
4
|
var contentTypes = require('../content-types.js');
|
|
5
5
|
var contentApiConstants = require('../content-api-constants.js');
|
|
6
6
|
var contentApiRouteParams = require('../content-api-route-params.js');
|
|
@@ -24,7 +24,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
24
24
|
if (!schema) {
|
|
25
25
|
throw new Error('Missing schema in sanitizeInput');
|
|
26
26
|
}
|
|
27
|
-
if (
|
|
27
|
+
if (Array.isArray(data)) {
|
|
28
28
|
return Promise.all(data.map((entry)=>sanitizeInput(entry, schema, {
|
|
29
29
|
auth,
|
|
30
30
|
strictParams,
|
|
@@ -35,8 +35,8 @@ const createAPISanitizers = (opts)=>{
|
|
|
35
35
|
const nonWritableAttributes = contentTypes.getNonWritableAttributes(schema);
|
|
36
36
|
const transforms = [
|
|
37
37
|
// Remove first level ID in inputs
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
(value)=>_.omit(value, contentTypes.constants.ID_ATTRIBUTE),
|
|
39
|
+
(value)=>_.omit(value, contentTypes.constants.DOC_ID_ATTRIBUTE),
|
|
40
40
|
// Remove non-writable attributes
|
|
41
41
|
traverseEntity(removeRestrictedFields(nonWritableAttributes), {
|
|
42
42
|
schema,
|
|
@@ -98,7 +98,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
98
98
|
if (!schema) {
|
|
99
99
|
throw new Error('Missing schema in sanitizeOutput');
|
|
100
100
|
}
|
|
101
|
-
if (
|
|
101
|
+
if (Array.isArray(data)) {
|
|
102
102
|
const res = Array.from({
|
|
103
103
|
length: data.length
|
|
104
104
|
});
|
|
@@ -130,7 +130,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
130
130
|
throw new Error('Missing schema in sanitizeQuery');
|
|
131
131
|
}
|
|
132
132
|
const { filters, sort, fields, populate } = query;
|
|
133
|
-
const sanitizedQuery =
|
|
133
|
+
const sanitizedQuery = _.cloneDeep(query);
|
|
134
134
|
if ('publicationFilter' in sanitizedQuery) {
|
|
135
135
|
publicationFilter.validatePublicationFilterQueryParam(sanitizedQuery.publicationFilter);
|
|
136
136
|
}
|
|
@@ -184,7 +184,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
184
184
|
...contentApiConstants.ALLOWED_QUERY_PARAM_KEYS,
|
|
185
185
|
...extraQueryKeys
|
|
186
186
|
];
|
|
187
|
-
return
|
|
187
|
+
return _.pick(sanitizedQuery, allowedKeys);
|
|
188
188
|
}
|
|
189
189
|
return sanitizedQuery;
|
|
190
190
|
};
|
|
@@ -192,7 +192,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
192
192
|
if (!schema) {
|
|
193
193
|
throw new Error('Missing schema in sanitizeFilters');
|
|
194
194
|
}
|
|
195
|
-
if (
|
|
195
|
+
if (Array.isArray(filters)) {
|
|
196
196
|
return Promise.all(filters.map((filter)=>sanitizeFilters(filter, schema, {
|
|
197
197
|
auth
|
|
198
198
|
})));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/sanitize/index.ts"],"sourcesContent":["import { CurriedFunction1 } from 'lodash';\nimport { isArray, cloneDeep, omit, pick } from 'lodash/fp';\nimport type { z } from 'zod/v4';\n\nimport { constants, getNonWritableAttributes } from '../content-types';\nimport { ALLOWED_QUERY_PARAM_KEYS } from '../content-api-constants';\nimport {\n type RouteLike,\n getExtraQueryKeysFromRoute,\n getExtraRootKeysFromRouteBody,\n} from '../content-api-route-params';\nimport { pipe as pipeAsync } from '../async';\n\nimport * as visitors from './visitors';\nimport * as sanitizers from './sanitizers';\nimport traverseEntity from '../traverse-entity';\n\nimport { traverseQueryFilters, traverseQuerySort, traverseQueryPopulate } from '../traverse';\nimport type { Model, Data } from '../types';\nimport { validatePublicationFilterQueryParam } from '../publication-filter';\nimport { hasSort } from '../sort-query';\n\nexport interface Options {\n auth?: unknown;\n /**\n * If true, removes fields that are not declared in the schema (input) or keeps only allowed query param keys (query).\n * Defaults to false for backward compatibility.\n * TODO: In Strapi 6, strictParams will default to true (and may be removed as an option)\n */\n strictParams?: boolean;\n /**\n * When set, extra query/input params are derived from the route's request schema (and validated/sanitized with Zod).\n * When absent, no extra params are allowed in strict mode.\n */\n route?: RouteLike;\n}\n\nexport interface Sanitizer {\n (schema: Model): CurriedFunction1<Data, Promise<Data>>;\n}\nexport interface SanitizeFunc {\n (data: unknown, schema: Model, options?: Options): Promise<unknown>;\n}\n\nexport type SanitizeQueryParamHandler = (\n value: unknown,\n schema: Model,\n options?: Options\n) => Promise<unknown>;\n\nexport type SanitizeBodyParamHandler = (\n value: unknown,\n schema: Model,\n options?: Options\n) => Promise<unknown>;\n\nexport interface APIOptions {\n sanitizers?: Sanitizers;\n getModel: (model: string) => Model;\n}\n\nexport interface Sanitizers {\n input?: Sanitizer[];\n output?: Sanitizer[];\n}\n\nconst createAPISanitizers = (opts: APIOptions) => {\n const { getModel } = opts;\n\n const sanitizeInput: SanitizeFunc = (\n data: unknown,\n schema: Model,\n { auth, strictParams = false, route } = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeInput');\n }\n if (isArray(data)) {\n return Promise.all(\n data.map((entry) => sanitizeInput(entry, schema, { auth, strictParams, route }))\n );\n }\n\n const allowedExtraRootKeys = getExtraRootKeysFromRouteBody(route);\n\n const nonWritableAttributes = getNonWritableAttributes(schema);\n\n const transforms = [\n // Remove first level ID in inputs\n omit(constants.ID_ATTRIBUTE),\n omit(constants.DOC_ID_ATTRIBUTE),\n // Remove non-writable attributes\n traverseEntity(visitors.removeRestrictedFields(nonWritableAttributes), { schema, getModel }),\n ];\n\n if (strictParams) {\n // Remove unrecognized fields (allowedExtraRootKeys = registered input param keys)\n transforms.push(\n traverseEntity(visitors.removeUnrecognizedFields, {\n schema,\n getModel,\n allowedExtraRootKeys,\n })\n );\n }\n\n if (auth) {\n // Remove restricted relations\n transforms.push(\n traverseEntity(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n // Apply sanitizers from registry if exists\n opts?.sanitizers?.input?.forEach((sanitizer: Sanitizer) => transforms.push(sanitizer(schema)));\n\n /**\n * For each extra root key from the route's body schema present in data, run Zod safeParse.\n * If parsing fails, the key is removed from the output.\n *\n * Content-api sends the document payload as body.data; the controller calls sanitizeInput(body.data, ctx),\n * so the input we receive here is the inner payload (keys like \"relatedMedia\", \"name\"), not the full body.\n * The route's body schema is z.object({ data: ... }), so its shape includes \"data\". We skip \"data\" because\n * the main document payload is already sanitized above by traverseEntity (removeUnrecognizedFields, etc.);\n * relation ops (connect/disconnect/set) are handled there, not by the route's Zod schema. We only run\n * Zod here for truly extra root keys added via addInputParams (e.g. clientMutationId).\n */\n const routeBodySanitizeTransform = async (data: Data): Promise<Data> => {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return data;\n const obj = data as Record<string, unknown>;\n const bodySchema = route?.request?.body?.['application/json'];\n if (bodySchema && typeof bodySchema === 'object' && 'shape' in bodySchema) {\n const shape = (bodySchema as { shape: Record<string, z.ZodTypeAny> }).shape;\n for (const key of Object.keys(shape)) {\n if (key === 'data' || !(key in obj)) continue;\n const zodSchema = shape[key];\n if (zodSchema && typeof (zodSchema as z.ZodTypeAny).safeParse === 'function') {\n const result = (zodSchema as z.ZodTypeAny).safeParse(obj[key]);\n if (result.success) {\n obj[key] = result.data;\n } else {\n delete obj[key];\n }\n }\n }\n }\n return data;\n };\n (transforms as Array<(data: Data) => Data | Promise<Data>>).push(routeBodySanitizeTransform);\n\n return pipeAsync(...transforms)(data as Data);\n };\n\n const sanitizeOutput: SanitizeFunc = async (data, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeOutput');\n }\n if (isArray(data)) {\n const res: unknown[] = Array.from({ length: data.length });\n for (let i = 0; i < data.length; i += 1) {\n res[i] = await sanitizeOutput(data[i], schema, { auth });\n }\n return res;\n }\n\n const transforms = [\n (data: Data) => sanitizers.defaultSanitizeOutput({ schema, getModel }, data),\n ];\n\n if (auth) {\n transforms.push(\n traverseEntity(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n // Apply sanitizers from registry if exists\n opts?.sanitizers?.output?.forEach((sanitizer: Sanitizer) => transforms.push(sanitizer(schema)));\n\n return pipeAsync(...transforms)(data as Data);\n };\n\n const sanitizeQuery = async (\n query: Record<string, unknown>,\n schema: Model,\n { auth, strictParams = false, route }: Options = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeQuery');\n }\n const { filters, sort, fields, populate } = query;\n\n const sanitizedQuery = cloneDeep(query);\n\n if ('publicationFilter' in sanitizedQuery) {\n validatePublicationFilterQueryParam(sanitizedQuery.publicationFilter);\n }\n\n if (filters) {\n Object.assign(sanitizedQuery, { filters: await sanitizeFilters(filters, schema, { auth }) });\n }\n\n if (hasSort(sort)) {\n Object.assign(sanitizedQuery, { sort: await sanitizeSort(sort, schema, { auth }) });\n } else if ('sort' in sanitizedQuery) {\n delete sanitizedQuery.sort;\n }\n\n if (fields) {\n Object.assign(sanitizedQuery, { fields: await sanitizeFields(fields, schema) });\n }\n\n if (populate) {\n Object.assign(sanitizedQuery, {\n populate: await sanitizePopulate(populate, schema, { auth }),\n });\n }\n\n const extraQueryKeys = getExtraQueryKeysFromRoute(route);\n const routeQuerySchema = route?.request?.query;\n if (routeQuerySchema) {\n for (const key of extraQueryKeys) {\n if (key in query) {\n const zodSchema = routeQuerySchema[key];\n if (zodSchema && typeof (zodSchema as z.ZodTypeAny).safeParse === 'function') {\n const result = (zodSchema as z.ZodTypeAny).safeParse(query[key]);\n if (result.success) {\n sanitizedQuery[key] = result.data;\n } else {\n delete sanitizedQuery[key];\n }\n }\n }\n }\n }\n\n if (strictParams) {\n const allowedKeys = [...ALLOWED_QUERY_PARAM_KEYS, ...extraQueryKeys];\n return pick(allowedKeys, sanitizedQuery) as Record<string, unknown>;\n }\n\n return sanitizedQuery;\n };\n\n const sanitizeFilters: SanitizeFunc = (filters, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeFilters');\n }\n if (isArray(filters)) {\n return Promise.all(filters.map((filter) => sanitizeFilters(filter, schema, { auth })));\n }\n\n const transforms = [sanitizers.defaultSanitizeFilters({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryFilters(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(filters);\n };\n\n const sanitizeSort: SanitizeFunc = (sort, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeSort');\n }\n const transforms = [sanitizers.defaultSanitizeSort({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQuerySort(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(sort);\n };\n\n const sanitizeFields: SanitizeFunc = (fields, schema: Model) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeFields');\n }\n const transforms = [sanitizers.defaultSanitizeFields({ schema, getModel })];\n\n return pipeAsync(...transforms)(fields);\n };\n\n const sanitizePopulate: SanitizeFunc = (populate, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizePopulate');\n }\n const transforms = [sanitizers.defaultSanitizePopulate({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryPopulate(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(populate);\n };\n\n return {\n input: sanitizeInput,\n output: sanitizeOutput,\n query: sanitizeQuery,\n filters: sanitizeFilters,\n sort: sanitizeSort,\n fields: sanitizeFields,\n populate: sanitizePopulate,\n };\n};\n\nexport { createAPISanitizers, sanitizers, visitors };\n\nexport type APISanitiers = ReturnType<typeof createAPISanitizers>;\n"],"names":["createAPISanitizers","opts","getModel","sanitizeInput","data","schema","auth","strictParams","route","Error","isArray","Promise","all","map","entry","allowedExtraRootKeys","getExtraRootKeysFromRouteBody","nonWritableAttributes","getNonWritableAttributes","transforms","omit","constants","ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","traverseEntity","visitors","push","sanitizers","input","forEach","sanitizer","routeBodySanitizeTransform","Array","obj","bodySchema","request","body","shape","key","Object","keys","zodSchema","safeParse","result","success","pipeAsync","sanitizeOutput","res","from","length","i","output","sanitizeQuery","query","filters","sort","fields","populate","sanitizedQuery","cloneDeep","validatePublicationFilterQueryParam","publicationFilter","assign","sanitizeFilters","hasSort","sanitizeSort","sanitizeFields","sanitizePopulate","extraQueryKeys","getExtraQueryKeysFromRoute","routeQuerySchema","allowedKeys","ALLOWED_QUERY_PARAM_KEYS","pick","filter","traverseQueryFilters","traverseQuerySort","traverseQueryPopulate"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/sanitize/index.ts"],"sourcesContent":["import { CurriedFunction1, cloneDeep, omit, pick } from 'lodash';\nimport type { z } from 'zod/v4';\n\nimport { constants, getNonWritableAttributes } from '../content-types';\nimport { ALLOWED_QUERY_PARAM_KEYS } from '../content-api-constants';\nimport {\n type RouteLike,\n getExtraQueryKeysFromRoute,\n getExtraRootKeysFromRouteBody,\n} from '../content-api-route-params';\nimport { pipe as pipeAsync } from '../async';\n\nimport * as visitors from './visitors';\nimport * as sanitizers from './sanitizers';\nimport traverseEntity from '../traverse-entity';\n\nimport { traverseQueryFilters, traverseQuerySort, traverseQueryPopulate } from '../traverse';\nimport type { Model, Data } from '../types';\nimport { validatePublicationFilterQueryParam } from '../publication-filter';\nimport { hasSort } from '../sort-query';\n\nexport interface Options {\n auth?: unknown;\n /**\n * If true, removes fields that are not declared in the schema (input) or keeps only allowed query param keys (query).\n * Defaults to false for backward compatibility.\n * TODO: In Strapi 6, strictParams will default to true (and may be removed as an option)\n */\n strictParams?: boolean;\n /**\n * When set, extra query/input params are derived from the route's request schema (and validated/sanitized with Zod).\n * When absent, no extra params are allowed in strict mode.\n */\n route?: RouteLike;\n}\n\nexport interface Sanitizer {\n (schema: Model): CurriedFunction1<Data, Promise<Data>>;\n}\nexport interface SanitizeFunc {\n (data: unknown, schema: Model, options?: Options): Promise<unknown>;\n}\n\nexport type SanitizeQueryParamHandler = (\n value: unknown,\n schema: Model,\n options?: Options\n) => Promise<unknown>;\n\nexport type SanitizeBodyParamHandler = (\n value: unknown,\n schema: Model,\n options?: Options\n) => Promise<unknown>;\n\nexport interface APIOptions {\n sanitizers?: Sanitizers;\n getModel: (model: string) => Model;\n}\n\nexport interface Sanitizers {\n input?: Sanitizer[];\n output?: Sanitizer[];\n}\n\nconst createAPISanitizers = (opts: APIOptions) => {\n const { getModel } = opts;\n\n const sanitizeInput: SanitizeFunc = (\n data: unknown,\n schema: Model,\n { auth, strictParams = false, route } = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeInput');\n }\n if (Array.isArray(data)) {\n return Promise.all(\n data.map((entry) => sanitizeInput(entry, schema, { auth, strictParams, route }))\n );\n }\n\n const allowedExtraRootKeys = getExtraRootKeysFromRouteBody(route);\n\n const nonWritableAttributes = getNonWritableAttributes(schema);\n\n const transforms = [\n // Remove first level ID in inputs\n (value: Record<string, unknown>) => omit(value, constants.ID_ATTRIBUTE),\n (value: Record<string, unknown>) => omit(value, constants.DOC_ID_ATTRIBUTE),\n // Remove non-writable attributes\n traverseEntity(visitors.removeRestrictedFields(nonWritableAttributes), { schema, getModel }),\n ];\n\n if (strictParams) {\n // Remove unrecognized fields (allowedExtraRootKeys = registered input param keys)\n transforms.push(\n traverseEntity(visitors.removeUnrecognizedFields, {\n schema,\n getModel,\n allowedExtraRootKeys,\n })\n );\n }\n\n if (auth) {\n // Remove restricted relations\n transforms.push(\n traverseEntity(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n // Apply sanitizers from registry if exists\n opts?.sanitizers?.input?.forEach((sanitizer: Sanitizer) => transforms.push(sanitizer(schema)));\n\n /**\n * For each extra root key from the route's body schema present in data, run Zod safeParse.\n * If parsing fails, the key is removed from the output.\n *\n * Content-api sends the document payload as body.data; the controller calls sanitizeInput(body.data, ctx),\n * so the input we receive here is the inner payload (keys like \"relatedMedia\", \"name\"), not the full body.\n * The route's body schema is z.object({ data: ... }), so its shape includes \"data\". We skip \"data\" because\n * the main document payload is already sanitized above by traverseEntity (removeUnrecognizedFields, etc.);\n * relation ops (connect/disconnect/set) are handled there, not by the route's Zod schema. We only run\n * Zod here for truly extra root keys added via addInputParams (e.g. clientMutationId).\n */\n const routeBodySanitizeTransform = async (data: Data): Promise<Data> => {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return data;\n const obj = data as Record<string, unknown>;\n const bodySchema = route?.request?.body?.['application/json'];\n if (bodySchema && typeof bodySchema === 'object' && 'shape' in bodySchema) {\n const shape = (bodySchema as { shape: Record<string, z.ZodTypeAny> }).shape;\n for (const key of Object.keys(shape)) {\n if (key === 'data' || !(key in obj)) continue;\n const zodSchema = shape[key];\n if (zodSchema && typeof (zodSchema as z.ZodTypeAny).safeParse === 'function') {\n const result = (zodSchema as z.ZodTypeAny).safeParse(obj[key]);\n if (result.success) {\n obj[key] = result.data;\n } else {\n delete obj[key];\n }\n }\n }\n }\n return data;\n };\n (transforms as Array<(data: Data) => Data | Promise<Data>>).push(routeBodySanitizeTransform);\n\n return pipeAsync(...transforms)(data as Data);\n };\n\n const sanitizeOutput: SanitizeFunc = async (data, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeOutput');\n }\n if (Array.isArray(data)) {\n const res: unknown[] = Array.from({ length: data.length });\n for (let i = 0; i < data.length; i += 1) {\n res[i] = await sanitizeOutput(data[i], schema, { auth });\n }\n return res;\n }\n\n const transforms = [\n (data: Data) => sanitizers.defaultSanitizeOutput({ schema, getModel }, data),\n ];\n\n if (auth) {\n transforms.push(\n traverseEntity(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n // Apply sanitizers from registry if exists\n opts?.sanitizers?.output?.forEach((sanitizer: Sanitizer) => transforms.push(sanitizer(schema)));\n\n return pipeAsync(...transforms)(data as Data);\n };\n\n const sanitizeQuery = async (\n query: Record<string, unknown>,\n schema: Model,\n { auth, strictParams = false, route }: Options = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeQuery');\n }\n const { filters, sort, fields, populate } = query;\n\n const sanitizedQuery = cloneDeep(query);\n\n if ('publicationFilter' in sanitizedQuery) {\n validatePublicationFilterQueryParam(sanitizedQuery.publicationFilter);\n }\n\n if (filters) {\n Object.assign(sanitizedQuery, { filters: await sanitizeFilters(filters, schema, { auth }) });\n }\n\n if (hasSort(sort)) {\n Object.assign(sanitizedQuery, { sort: await sanitizeSort(sort, schema, { auth }) });\n } else if ('sort' in sanitizedQuery) {\n delete sanitizedQuery.sort;\n }\n\n if (fields) {\n Object.assign(sanitizedQuery, { fields: await sanitizeFields(fields, schema) });\n }\n\n if (populate) {\n Object.assign(sanitizedQuery, {\n populate: await sanitizePopulate(populate, schema, { auth }),\n });\n }\n\n const extraQueryKeys = getExtraQueryKeysFromRoute(route);\n const routeQuerySchema = route?.request?.query;\n if (routeQuerySchema) {\n for (const key of extraQueryKeys) {\n if (key in query) {\n const zodSchema = routeQuerySchema[key];\n if (zodSchema && typeof (zodSchema as z.ZodTypeAny).safeParse === 'function') {\n const result = (zodSchema as z.ZodTypeAny).safeParse(query[key]);\n if (result.success) {\n sanitizedQuery[key] = result.data;\n } else {\n delete sanitizedQuery[key];\n }\n }\n }\n }\n }\n\n if (strictParams) {\n const allowedKeys = [...ALLOWED_QUERY_PARAM_KEYS, ...extraQueryKeys];\n return pick(sanitizedQuery, allowedKeys) as Record<string, unknown>;\n }\n\n return sanitizedQuery;\n };\n\n const sanitizeFilters: SanitizeFunc = (filters, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeFilters');\n }\n if (Array.isArray(filters)) {\n return Promise.all(filters.map((filter) => sanitizeFilters(filter, schema, { auth })));\n }\n\n const transforms = [sanitizers.defaultSanitizeFilters({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryFilters(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(filters);\n };\n\n const sanitizeSort: SanitizeFunc = (sort, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeSort');\n }\n const transforms = [sanitizers.defaultSanitizeSort({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQuerySort(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(sort);\n };\n\n const sanitizeFields: SanitizeFunc = (fields, schema: Model) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeFields');\n }\n const transforms = [sanitizers.defaultSanitizeFields({ schema, getModel })];\n\n return pipeAsync(...transforms)(fields);\n };\n\n const sanitizePopulate: SanitizeFunc = (populate, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizePopulate');\n }\n const transforms = [sanitizers.defaultSanitizePopulate({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryPopulate(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(populate);\n };\n\n return {\n input: sanitizeInput,\n output: sanitizeOutput,\n query: sanitizeQuery,\n filters: sanitizeFilters,\n sort: sanitizeSort,\n fields: sanitizeFields,\n populate: sanitizePopulate,\n };\n};\n\nexport { createAPISanitizers, sanitizers, visitors };\n\nexport type APISanitiers = ReturnType<typeof createAPISanitizers>;\n"],"names":["createAPISanitizers","opts","getModel","sanitizeInput","data","schema","auth","strictParams","route","Error","Array","isArray","Promise","all","map","entry","allowedExtraRootKeys","getExtraRootKeysFromRouteBody","nonWritableAttributes","getNonWritableAttributes","transforms","value","omit","constants","ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","traverseEntity","visitors","push","sanitizers","input","forEach","sanitizer","routeBodySanitizeTransform","obj","bodySchema","request","body","shape","key","Object","keys","zodSchema","safeParse","result","success","pipeAsync","sanitizeOutput","res","from","length","i","output","sanitizeQuery","query","filters","sort","fields","populate","sanitizedQuery","cloneDeep","validatePublicationFilterQueryParam","publicationFilter","assign","sanitizeFilters","hasSort","sanitizeSort","sanitizeFields","sanitizePopulate","extraQueryKeys","getExtraQueryKeysFromRoute","routeQuerySchema","allowedKeys","ALLOWED_QUERY_PARAM_KEYS","pick","filter","traverseQueryFilters","traverseQuerySort","traverseQueryPopulate"],"mappings":";;;;;;;;;;;;;;;;;;;;AAiEA,MAAMA,sBAAsB,CAACC,IAAAA,GAAAA;IAC3B,MAAM,EAAEC,QAAQ,EAAE,GAAGD,IAAAA;AAErB,IAAA,MAAME,aAAAA,GAA8B,CAClCC,IAAAA,EACAC,MAAAA,EACA,EAAEC,IAAI,EAAEC,YAAAA,GAAe,KAAK,EAAEC,KAAK,EAAE,GAAG,EAAE,GAAA;AAE1C,QAAA,IAAI,CAACH,MAAAA,EAAQ;AACX,YAAA,MAAM,IAAII,KAAAA,CAAM,iCAAA,CAAA;AAClB,QAAA;QACA,IAAIC,KAAAA,CAAMC,OAAO,CAACP,IAAAA,CAAAA,EAAO;YACvB,OAAOQ,OAAAA,CAAQC,GAAG,CAChBT,IAAAA,CAAKU,GAAG,CAAC,CAACC,KAAAA,GAAUZ,aAAAA,CAAcY,KAAAA,EAAOV,MAAAA,EAAQ;AAAEC,oBAAAA,IAAAA;AAAMC,oBAAAA,YAAAA;AAAcC,oBAAAA;AAAM,iBAAA,CAAA,CAAA,CAAA;AAEjF,QAAA;AAEA,QAAA,MAAMQ,uBAAuBC,mDAAAA,CAA8BT,KAAAA,CAAAA;AAE3D,QAAA,MAAMU,wBAAwBC,qCAAAA,CAAyBd,MAAAA,CAAAA;AAEvD,QAAA,MAAMe,UAAAA,GAAa;;AAEjB,YAAA,CAACC,KAAAA,GAAmCC,MAAAA,CAAKD,KAAAA,EAAOE,sBAAAA,CAAUC,YAAY,CAAA;AACtE,YAAA,CAACH,KAAAA,GAAmCC,MAAAA,CAAKD,KAAAA,EAAOE,sBAAAA,CAAUE,gBAAgB,CAAA;;YAE1EC,cAAAA,CAAeC,sBAA+B,CAACT,qBAAAA,CAAAA,EAAwB;AAAEb,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAC3F,SAAA;AAED,QAAA,IAAIK,YAAAA,EAAc;;AAEhBa,YAAAA,UAAAA,CAAWQ,IAAI,CACbF,cAAAA,CAAeC,wBAAiC,EAAE;AAChDtB,gBAAAA,MAAAA;AACAH,gBAAAA,QAAAA;AACAc,gBAAAA;AACF,aAAA,CAAA,CAAA;AAEJ,QAAA;AAEA,QAAA,IAAIV,IAAAA,EAAM;;AAERc,YAAAA,UAAAA,CAAWQ,IAAI,CACbF,cAAAA,CAAeC,yBAAkC,CAACrB,IAAAA,CAAAA,EAAO;AAAED,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA,CAAA,CAAA;AAEhF,QAAA;;QAGAD,IAAAA,EAAM4B,UAAAA,EAAYC,OAAOC,OAAAA,CAAQ,CAACC,YAAyBZ,UAAAA,CAAWQ,IAAI,CAACI,SAAAA,CAAU3B,MAAAA,CAAAA,CAAAA,CAAAA;AAErF;;;;;;;;;;QAWA,MAAM4B,6BAA6B,OAAO7B,IAAAA,GAAAA;YACxC,IAAI,CAACA,QAAQ,OAAOA,IAAAA,KAAS,YAAYM,KAAAA,CAAMC,OAAO,CAACP,IAAAA,CAAAA,EAAO,OAAOA,IAAAA;AACrE,YAAA,MAAM8B,GAAAA,GAAM9B,IAAAA;AACZ,YAAA,MAAM+B,UAAAA,GAAa3B,KAAAA,EAAO4B,OAAAA,EAASC,IAAAA,GAAO,kBAAA,CAAmB;AAC7D,YAAA,IAAIF,UAAAA,IAAc,OAAOA,UAAAA,KAAe,QAAA,IAAY,WAAWA,UAAAA,EAAY;gBACzE,MAAMG,KAAAA,GAAQ,UAACH,CAAuDG,KAAK;AAC3E,gBAAA,KAAK,MAAMC,GAAAA,IAAOC,MAAAA,CAAOC,IAAI,CAACH,KAAAA,CAAAA,CAAQ;AACpC,oBAAA,IAAIC,QAAQ,MAAA,IAAU,EAAEA,GAAAA,IAAOL,GAAE,CAAA,EAAI;oBACrC,MAAMQ,SAAAA,GAAYJ,KAAK,CAACC,GAAAA,CAAI;AAC5B,oBAAA,IAAIG,aAAa,OAAQA,SAAAA,CAA2BC,SAAS,KAAK,UAAA,EAAY;AAC5E,wBAAA,MAAMC,SAAS,SAACF,CAA2BC,SAAS,CAACT,GAAG,CAACK,GAAAA,CAAI,CAAA;wBAC7D,IAAIK,MAAAA,CAAOC,OAAO,EAAE;AAClBX,4BAAAA,GAAG,CAACK,GAAAA,CAAI,GAAGK,MAAAA,CAAOxC,IAAI;wBACxB,CAAA,MAAO;4BACL,OAAO8B,GAAG,CAACK,GAAAA,CAAI;AACjB,wBAAA;AACF,oBAAA;AACF,gBAAA;AACF,YAAA;YACA,OAAOnC,IAAAA;AACT,QAAA,CAAA;AACCgB,QAAAA,UAAAA,CAA2DQ,IAAI,CAACK,0BAAAA,CAAAA;AAEjE,QAAA,OAAOa,cAAa1B,UAAAA,CAAAA,CAAYhB,IAAAA,CAAAA;AAClC,IAAA,CAAA;IAEA,MAAM2C,cAAAA,GAA+B,OAAO3C,IAAAA,EAAMC,MAAAA,EAAe,EAAEC,IAAI,EAAE,GAAG,EAAE,GAAA;AAC5E,QAAA,IAAI,CAACD,MAAAA,EAAQ;AACX,YAAA,MAAM,IAAII,KAAAA,CAAM,kCAAA,CAAA;AAClB,QAAA;QACA,IAAIC,KAAAA,CAAMC,OAAO,CAACP,IAAAA,CAAAA,EAAO;YACvB,MAAM4C,GAAAA,GAAiBtC,KAAAA,CAAMuC,IAAI,CAAC;AAAEC,gBAAAA,MAAAA,EAAQ9C,KAAK8C;AAAO,aAAA,CAAA;YACxD,IAAK,IAAIC,IAAI,CAAA,EAAGA,CAAAA,GAAI/C,KAAK8C,MAAM,EAAEC,KAAK,CAAA,CAAG;gBACvCH,GAAG,CAACG,EAAE,GAAG,MAAMJ,eAAe3C,IAAI,CAAC+C,CAAAA,CAAE,EAAE9C,MAAAA,EAAQ;AAAEC,oBAAAA;AAAK,iBAAA,CAAA;AACxD,YAAA;YACA,OAAO0C,GAAAA;AACT,QAAA;AAEA,QAAA,MAAM5B,UAAAA,GAAa;YACjB,CAAChB,IAAAA,GAAeyB,gCAAgC,CAAC;AAAExB,oBAAAA,MAAAA;AAAQH,oBAAAA;iBAAS,EAAGE,IAAAA;AACxE,SAAA;AAED,QAAA,IAAIE,IAAAA,EAAM;AACRc,YAAAA,UAAAA,CAAWQ,IAAI,CACbF,cAAAA,CAAeC,yBAAkC,CAACrB,IAAAA,CAAAA,EAAO;AAAED,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA,CAAA,CAAA;AAEhF,QAAA;;QAGAD,IAAAA,EAAM4B,UAAAA,EAAYuB,QAAQrB,OAAAA,CAAQ,CAACC,YAAyBZ,UAAAA,CAAWQ,IAAI,CAACI,SAAAA,CAAU3B,MAAAA,CAAAA,CAAAA,CAAAA;AAEtF,QAAA,OAAOyC,cAAa1B,UAAAA,CAAAA,CAAYhB,IAAAA,CAAAA;AAClC,IAAA,CAAA;AAEA,IAAA,MAAMiD,aAAAA,GAAgB,OACpBC,KAAAA,EACAjD,MAAAA,EACA,EAAEC,IAAI,EAAEC,YAAAA,GAAe,KAAK,EAAEC,KAAK,EAAW,GAAG,EAAE,GAAA;AAEnD,QAAA,IAAI,CAACH,MAAAA,EAAQ;AACX,YAAA,MAAM,IAAII,KAAAA,CAAM,iCAAA,CAAA;AAClB,QAAA;QACA,MAAM,EAAE8C,OAAO,EAAEC,IAAI,EAAEC,MAAM,EAAEC,QAAQ,EAAE,GAAGJ,KAAAA;AAE5C,QAAA,MAAMK,iBAAiBC,WAAAA,CAAUN,KAAAA,CAAAA;AAEjC,QAAA,IAAI,uBAAuBK,cAAAA,EAAgB;AACzCE,YAAAA,qDAAAA,CAAoCF,eAAeG,iBAAiB,CAAA;AACtE,QAAA;AAEA,QAAA,IAAIP,OAAAA,EAAS;YACXf,MAAAA,CAAOuB,MAAM,CAACJ,cAAAA,EAAgB;gBAAEJ,OAAAA,EAAS,MAAMS,eAAAA,CAAgBT,OAAAA,EAASlD,MAAAA,EAAQ;AAAEC,oBAAAA;AAAK,iBAAA;AAAG,aAAA,CAAA;AAC5F,QAAA;AAEA,QAAA,IAAI2D,kBAAQT,IAAAA,CAAAA,EAAO;YACjBhB,MAAAA,CAAOuB,MAAM,CAACJ,cAAAA,EAAgB;gBAAEH,IAAAA,EAAM,MAAMU,YAAAA,CAAaV,IAAAA,EAAMnD,MAAAA,EAAQ;AAAEC,oBAAAA;AAAK,iBAAA;AAAG,aAAA,CAAA;QACnF,CAAA,MAAO,IAAI,UAAUqD,cAAAA,EAAgB;AACnC,YAAA,OAAOA,eAAeH,IAAI;AAC5B,QAAA;AAEA,QAAA,IAAIC,MAAAA,EAAQ;YACVjB,MAAAA,CAAOuB,MAAM,CAACJ,cAAAA,EAAgB;gBAAEF,MAAAA,EAAQ,MAAMU,eAAeV,MAAAA,EAAQpD,MAAAA;AAAQ,aAAA,CAAA;AAC/E,QAAA;AAEA,QAAA,IAAIqD,QAAAA,EAAU;YACZlB,MAAAA,CAAOuB,MAAM,CAACJ,cAAAA,EAAgB;gBAC5BD,QAAAA,EAAU,MAAMU,gBAAAA,CAAiBV,QAAAA,EAAUrD,MAAAA,EAAQ;AAAEC,oBAAAA;AAAK,iBAAA;AAC5D,aAAA,CAAA;AACF,QAAA;AAEA,QAAA,MAAM+D,iBAAiBC,gDAAAA,CAA2B9D,KAAAA,CAAAA;QAClD,MAAM+D,gBAAAA,GAAmB/D,OAAO4B,OAAAA,EAASkB,KAAAA;AACzC,QAAA,IAAIiB,gBAAAA,EAAkB;YACpB,KAAK,MAAMhC,OAAO8B,cAAAA,CAAgB;AAChC,gBAAA,IAAI9B,OAAOe,KAAAA,EAAO;oBAChB,MAAMZ,SAAAA,GAAY6B,gBAAgB,CAAChC,GAAAA,CAAI;AACvC,oBAAA,IAAIG,aAAa,OAAQA,SAAAA,CAA2BC,SAAS,KAAK,UAAA,EAAY;AAC5E,wBAAA,MAAMC,SAAS,SAACF,CAA2BC,SAAS,CAACW,KAAK,CAACf,GAAAA,CAAI,CAAA;wBAC/D,IAAIK,MAAAA,CAAOC,OAAO,EAAE;AAClBc,4BAAAA,cAAc,CAACpB,GAAAA,CAAI,GAAGK,MAAAA,CAAOxC,IAAI;wBACnC,CAAA,MAAO;4BACL,OAAOuD,cAAc,CAACpB,GAAAA,CAAI;AAC5B,wBAAA;AACF,oBAAA;AACF,gBAAA;AACF,YAAA;AACF,QAAA;AAEA,QAAA,IAAIhC,YAAAA,EAAc;AAChB,YAAA,MAAMiE,WAAAA,GAAc;AAAIC,gBAAAA,GAAAA,4CAAAA;AAA6BJ,gBAAAA,GAAAA;AAAe,aAAA;AACpE,YAAA,OAAOK,OAAKf,cAAAA,EAAgBa,WAAAA,CAAAA;AAC9B,QAAA;QAEA,OAAOb,cAAAA;AACT,IAAA,CAAA;IAEA,MAAMK,eAAAA,GAAgC,CAACT,OAAAA,EAASlD,MAAAA,EAAe,EAAEC,IAAI,EAAE,GAAG,EAAE,GAAA;AAC1E,QAAA,IAAI,CAACD,MAAAA,EAAQ;AACX,YAAA,MAAM,IAAII,KAAAA,CAAM,mCAAA,CAAA;AAClB,QAAA;QACA,IAAIC,KAAAA,CAAMC,OAAO,CAAC4C,OAAAA,CAAAA,EAAU;YAC1B,OAAO3C,OAAAA,CAAQC,GAAG,CAAC0C,OAAAA,CAAQzC,GAAG,CAAC,CAAC6D,MAAAA,GAAWX,eAAAA,CAAgBW,MAAAA,EAAQtE,MAAAA,EAAQ;AAAEC,oBAAAA;AAAK,iBAAA,CAAA,CAAA,CAAA;AACpF,QAAA;AAEA,QAAA,MAAMc,UAAAA,GAAa;AAACS,YAAAA,iCAAiC,CAAC;AAAExB,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAAG,SAAA;AAE5E,QAAA,IAAII,IAAAA,EAAM;AACRc,YAAAA,UAAAA,CAAWQ,IAAI,CACbgD,YAAAA,CAAqBjD,yBAAkC,CAACrB,IAAAA,CAAAA,EAAO;AAAED,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA,CAAA,CAAA;AAEtF,QAAA;AAEA,QAAA,OAAO4C,cAAa1B,UAAAA,CAAAA,CAAYmC,OAAAA,CAAAA;AAClC,IAAA,CAAA;IAEA,MAAMW,YAAAA,GAA6B,CAACV,IAAAA,EAAMnD,MAAAA,EAAe,EAAEC,IAAI,EAAE,GAAG,EAAE,GAAA;AACpE,QAAA,IAAI,CAACD,MAAAA,EAAQ;AACX,YAAA,MAAM,IAAII,KAAAA,CAAM,gCAAA,CAAA;AAClB,QAAA;AACA,QAAA,MAAMW,UAAAA,GAAa;AAACS,YAAAA,8BAA8B,CAAC;AAAExB,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAAG,SAAA;AAEzE,QAAA,IAAII,IAAAA,EAAM;AACRc,YAAAA,UAAAA,CAAWQ,IAAI,CACbiD,SAAAA,CAAkBlD,yBAAkC,CAACrB,IAAAA,CAAAA,EAAO;AAAED,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA,CAAA,CAAA;AAEnF,QAAA;AAEA,QAAA,OAAO4C,cAAa1B,UAAAA,CAAAA,CAAYoC,IAAAA,CAAAA;AAClC,IAAA,CAAA;IAEA,MAAMW,cAAAA,GAA+B,CAACV,MAAAA,EAAQpD,MAAAA,GAAAA;AAC5C,QAAA,IAAI,CAACA,MAAAA,EAAQ;AACX,YAAA,MAAM,IAAII,KAAAA,CAAM,kCAAA,CAAA;AAClB,QAAA;AACA,QAAA,MAAMW,UAAAA,GAAa;AAACS,YAAAA,gCAAgC,CAAC;AAAExB,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAAG,SAAA;AAE3E,QAAA,OAAO4C,cAAa1B,UAAAA,CAAAA,CAAYqC,MAAAA,CAAAA;AAClC,IAAA,CAAA;IAEA,MAAMW,gBAAAA,GAAiC,CAACV,QAAAA,EAAUrD,MAAAA,EAAe,EAAEC,IAAI,EAAE,GAAG,EAAE,GAAA;AAC5E,QAAA,IAAI,CAACD,MAAAA,EAAQ;AACX,YAAA,MAAM,IAAII,KAAAA,CAAM,oCAAA,CAAA;AAClB,QAAA;AACA,QAAA,MAAMW,UAAAA,GAAa;AAACS,YAAAA,kCAAkC,CAAC;AAAExB,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA;AAAG,SAAA;AAE7E,QAAA,IAAII,IAAAA,EAAM;AACRc,YAAAA,UAAAA,CAAWQ,IAAI,CACbkD,aAAAA,CAAsBnD,yBAAkC,CAACrB,IAAAA,CAAAA,EAAO;AAAED,gBAAAA,MAAAA;AAAQH,gBAAAA;AAAS,aAAA,CAAA,CAAA;AAEvF,QAAA;AAEA,QAAA,OAAO4C,cAAa1B,UAAAA,CAAAA,CAAYsC,QAAAA,CAAAA;AAClC,IAAA,CAAA;IAEA,OAAO;QACL5B,KAAAA,EAAO3B,aAAAA;QACPiD,MAAAA,EAAQL,cAAAA;QACRO,KAAAA,EAAOD,aAAAA;QACPE,OAAAA,EAASS,eAAAA;QACTR,IAAAA,EAAMU,YAAAA;QACNT,MAAAA,EAAQU,cAAAA;QACRT,QAAAA,EAAUU;AACZ,KAAA;AACF;;;;;;"}
|
package/dist/sanitize/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cloneDeep, pick, omit } from 'lodash';
|
|
2
2
|
import { getNonWritableAttributes, constants } from '../content-types.mjs';
|
|
3
3
|
import { ALLOWED_QUERY_PARAM_KEYS } from '../content-api-constants.mjs';
|
|
4
4
|
import { getExtraQueryKeysFromRoute, getExtraRootKeysFromRouteBody } from '../content-api-route-params.mjs';
|
|
@@ -25,7 +25,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
25
25
|
if (!schema) {
|
|
26
26
|
throw new Error('Missing schema in sanitizeInput');
|
|
27
27
|
}
|
|
28
|
-
if (isArray(data)) {
|
|
28
|
+
if (Array.isArray(data)) {
|
|
29
29
|
return Promise.all(data.map((entry)=>sanitizeInput(entry, schema, {
|
|
30
30
|
auth,
|
|
31
31
|
strictParams,
|
|
@@ -36,8 +36,8 @@ const createAPISanitizers = (opts)=>{
|
|
|
36
36
|
const nonWritableAttributes = getNonWritableAttributes(schema);
|
|
37
37
|
const transforms = [
|
|
38
38
|
// Remove first level ID in inputs
|
|
39
|
-
omit(constants.ID_ATTRIBUTE),
|
|
40
|
-
omit(constants.DOC_ID_ATTRIBUTE),
|
|
39
|
+
(value)=>omit(value, constants.ID_ATTRIBUTE),
|
|
40
|
+
(value)=>omit(value, constants.DOC_ID_ATTRIBUTE),
|
|
41
41
|
// Remove non-writable attributes
|
|
42
42
|
traverseEntity(removeRestrictedFields(nonWritableAttributes), {
|
|
43
43
|
schema,
|
|
@@ -99,7 +99,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
99
99
|
if (!schema) {
|
|
100
100
|
throw new Error('Missing schema in sanitizeOutput');
|
|
101
101
|
}
|
|
102
|
-
if (isArray(data)) {
|
|
102
|
+
if (Array.isArray(data)) {
|
|
103
103
|
const res = Array.from({
|
|
104
104
|
length: data.length
|
|
105
105
|
});
|
|
@@ -185,7 +185,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
185
185
|
...ALLOWED_QUERY_PARAM_KEYS,
|
|
186
186
|
...extraQueryKeys
|
|
187
187
|
];
|
|
188
|
-
return pick(
|
|
188
|
+
return pick(sanitizedQuery, allowedKeys);
|
|
189
189
|
}
|
|
190
190
|
return sanitizedQuery;
|
|
191
191
|
};
|
|
@@ -193,7 +193,7 @@ const createAPISanitizers = (opts)=>{
|
|
|
193
193
|
if (!schema) {
|
|
194
194
|
throw new Error('Missing schema in sanitizeFilters');
|
|
195
195
|
}
|
|
196
|
-
if (isArray(filters)) {
|
|
196
|
+
if (Array.isArray(filters)) {
|
|
197
197
|
return Promise.all(filters.map((filter)=>sanitizeFilters(filter, schema, {
|
|
198
198
|
auth
|
|
199
199
|
})));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../src/sanitize/index.ts"],"sourcesContent":["import { CurriedFunction1 } from 'lodash';\nimport { isArray, cloneDeep, omit, pick } from 'lodash/fp';\nimport type { z } from 'zod/v4';\n\nimport { constants, getNonWritableAttributes } from '../content-types';\nimport { ALLOWED_QUERY_PARAM_KEYS } from '../content-api-constants';\nimport {\n type RouteLike,\n getExtraQueryKeysFromRoute,\n getExtraRootKeysFromRouteBody,\n} from '../content-api-route-params';\nimport { pipe as pipeAsync } from '../async';\n\nimport * as visitors from './visitors';\nimport * as sanitizers from './sanitizers';\nimport traverseEntity from '../traverse-entity';\n\nimport { traverseQueryFilters, traverseQuerySort, traverseQueryPopulate } from '../traverse';\nimport type { Model, Data } from '../types';\nimport { validatePublicationFilterQueryParam } from '../publication-filter';\nimport { hasSort } from '../sort-query';\n\nexport interface Options {\n auth?: unknown;\n /**\n * If true, removes fields that are not declared in the schema (input) or keeps only allowed query param keys (query).\n * Defaults to false for backward compatibility.\n * TODO: In Strapi 6, strictParams will default to true (and may be removed as an option)\n */\n strictParams?: boolean;\n /**\n * When set, extra query/input params are derived from the route's request schema (and validated/sanitized with Zod).\n * When absent, no extra params are allowed in strict mode.\n */\n route?: RouteLike;\n}\n\nexport interface Sanitizer {\n (schema: Model): CurriedFunction1<Data, Promise<Data>>;\n}\nexport interface SanitizeFunc {\n (data: unknown, schema: Model, options?: Options): Promise<unknown>;\n}\n\nexport type SanitizeQueryParamHandler = (\n value: unknown,\n schema: Model,\n options?: Options\n) => Promise<unknown>;\n\nexport type SanitizeBodyParamHandler = (\n value: unknown,\n schema: Model,\n options?: Options\n) => Promise<unknown>;\n\nexport interface APIOptions {\n sanitizers?: Sanitizers;\n getModel: (model: string) => Model;\n}\n\nexport interface Sanitizers {\n input?: Sanitizer[];\n output?: Sanitizer[];\n}\n\nconst createAPISanitizers = (opts: APIOptions) => {\n const { getModel } = opts;\n\n const sanitizeInput: SanitizeFunc = (\n data: unknown,\n schema: Model,\n { auth, strictParams = false, route } = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeInput');\n }\n if (isArray(data)) {\n return Promise.all(\n data.map((entry) => sanitizeInput(entry, schema, { auth, strictParams, route }))\n );\n }\n\n const allowedExtraRootKeys = getExtraRootKeysFromRouteBody(route);\n\n const nonWritableAttributes = getNonWritableAttributes(schema);\n\n const transforms = [\n // Remove first level ID in inputs\n omit(constants.ID_ATTRIBUTE),\n omit(constants.DOC_ID_ATTRIBUTE),\n // Remove non-writable attributes\n traverseEntity(visitors.removeRestrictedFields(nonWritableAttributes), { schema, getModel }),\n ];\n\n if (strictParams) {\n // Remove unrecognized fields (allowedExtraRootKeys = registered input param keys)\n transforms.push(\n traverseEntity(visitors.removeUnrecognizedFields, {\n schema,\n getModel,\n allowedExtraRootKeys,\n })\n );\n }\n\n if (auth) {\n // Remove restricted relations\n transforms.push(\n traverseEntity(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n // Apply sanitizers from registry if exists\n opts?.sanitizers?.input?.forEach((sanitizer: Sanitizer) => transforms.push(sanitizer(schema)));\n\n /**\n * For each extra root key from the route's body schema present in data, run Zod safeParse.\n * If parsing fails, the key is removed from the output.\n *\n * Content-api sends the document payload as body.data; the controller calls sanitizeInput(body.data, ctx),\n * so the input we receive here is the inner payload (keys like \"relatedMedia\", \"name\"), not the full body.\n * The route's body schema is z.object({ data: ... }), so its shape includes \"data\". We skip \"data\" because\n * the main document payload is already sanitized above by traverseEntity (removeUnrecognizedFields, etc.);\n * relation ops (connect/disconnect/set) are handled there, not by the route's Zod schema. We only run\n * Zod here for truly extra root keys added via addInputParams (e.g. clientMutationId).\n */\n const routeBodySanitizeTransform = async (data: Data): Promise<Data> => {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return data;\n const obj = data as Record<string, unknown>;\n const bodySchema = route?.request?.body?.['application/json'];\n if (bodySchema && typeof bodySchema === 'object' && 'shape' in bodySchema) {\n const shape = (bodySchema as { shape: Record<string, z.ZodTypeAny> }).shape;\n for (const key of Object.keys(shape)) {\n if (key === 'data' || !(key in obj)) continue;\n const zodSchema = shape[key];\n if (zodSchema && typeof (zodSchema as z.ZodTypeAny).safeParse === 'function') {\n const result = (zodSchema as z.ZodTypeAny).safeParse(obj[key]);\n if (result.success) {\n obj[key] = result.data;\n } else {\n delete obj[key];\n }\n }\n }\n }\n return data;\n };\n (transforms as Array<(data: Data) => Data | Promise<Data>>).push(routeBodySanitizeTransform);\n\n return pipeAsync(...transforms)(data as Data);\n };\n\n const sanitizeOutput: SanitizeFunc = async (data, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeOutput');\n }\n if (isArray(data)) {\n const res: unknown[] = Array.from({ length: data.length });\n for (let i = 0; i < data.length; i += 1) {\n res[i] = await sanitizeOutput(data[i], schema, { auth });\n }\n return res;\n }\n\n const transforms = [\n (data: Data) => sanitizers.defaultSanitizeOutput({ schema, getModel }, data),\n ];\n\n if (auth) {\n transforms.push(\n traverseEntity(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n // Apply sanitizers from registry if exists\n opts?.sanitizers?.output?.forEach((sanitizer: Sanitizer) => transforms.push(sanitizer(schema)));\n\n return pipeAsync(...transforms)(data as Data);\n };\n\n const sanitizeQuery = async (\n query: Record<string, unknown>,\n schema: Model,\n { auth, strictParams = false, route }: Options = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeQuery');\n }\n const { filters, sort, fields, populate } = query;\n\n const sanitizedQuery = cloneDeep(query);\n\n if ('publicationFilter' in sanitizedQuery) {\n validatePublicationFilterQueryParam(sanitizedQuery.publicationFilter);\n }\n\n if (filters) {\n Object.assign(sanitizedQuery, { filters: await sanitizeFilters(filters, schema, { auth }) });\n }\n\n if (hasSort(sort)) {\n Object.assign(sanitizedQuery, { sort: await sanitizeSort(sort, schema, { auth }) });\n } else if ('sort' in sanitizedQuery) {\n delete sanitizedQuery.sort;\n }\n\n if (fields) {\n Object.assign(sanitizedQuery, { fields: await sanitizeFields(fields, schema) });\n }\n\n if (populate) {\n Object.assign(sanitizedQuery, {\n populate: await sanitizePopulate(populate, schema, { auth }),\n });\n }\n\n const extraQueryKeys = getExtraQueryKeysFromRoute(route);\n const routeQuerySchema = route?.request?.query;\n if (routeQuerySchema) {\n for (const key of extraQueryKeys) {\n if (key in query) {\n const zodSchema = routeQuerySchema[key];\n if (zodSchema && typeof (zodSchema as z.ZodTypeAny).safeParse === 'function') {\n const result = (zodSchema as z.ZodTypeAny).safeParse(query[key]);\n if (result.success) {\n sanitizedQuery[key] = result.data;\n } else {\n delete sanitizedQuery[key];\n }\n }\n }\n }\n }\n\n if (strictParams) {\n const allowedKeys = [...ALLOWED_QUERY_PARAM_KEYS, ...extraQueryKeys];\n return pick(allowedKeys, sanitizedQuery) as Record<string, unknown>;\n }\n\n return sanitizedQuery;\n };\n\n const sanitizeFilters: SanitizeFunc = (filters, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeFilters');\n }\n if (isArray(filters)) {\n return Promise.all(filters.map((filter) => sanitizeFilters(filter, schema, { auth })));\n }\n\n const transforms = [sanitizers.defaultSanitizeFilters({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryFilters(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(filters);\n };\n\n const sanitizeSort: SanitizeFunc = (sort, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeSort');\n }\n const transforms = [sanitizers.defaultSanitizeSort({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQuerySort(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(sort);\n };\n\n const sanitizeFields: SanitizeFunc = (fields, schema: Model) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeFields');\n }\n const transforms = [sanitizers.defaultSanitizeFields({ schema, getModel })];\n\n return pipeAsync(...transforms)(fields);\n };\n\n const sanitizePopulate: SanitizeFunc = (populate, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizePopulate');\n }\n const transforms = [sanitizers.defaultSanitizePopulate({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryPopulate(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(populate);\n };\n\n return {\n input: sanitizeInput,\n output: sanitizeOutput,\n query: sanitizeQuery,\n filters: sanitizeFilters,\n sort: sanitizeSort,\n fields: sanitizeFields,\n populate: sanitizePopulate,\n };\n};\n\nexport { createAPISanitizers, sanitizers, visitors };\n\nexport type APISanitiers = ReturnType<typeof createAPISanitizers>;\n"],"names":["createAPISanitizers","opts","getModel","sanitizeInput","data","schema","auth","strictParams","route","Error","isArray","Promise","all","map","entry","allowedExtraRootKeys","getExtraRootKeysFromRouteBody","nonWritableAttributes","getNonWritableAttributes","transforms","omit","constants","ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","traverseEntity","visitors","push","sanitizers","input","forEach","sanitizer","routeBodySanitizeTransform","Array","obj","bodySchema","request","body","shape","key","Object","keys","zodSchema","safeParse","result","success","pipeAsync","sanitizeOutput","res","from","length","i","output","sanitizeQuery","query","filters","sort","fields","populate","sanitizedQuery","cloneDeep","validatePublicationFilterQueryParam","publicationFilter","assign","sanitizeFilters","hasSort","sanitizeSort","sanitizeFields","sanitizePopulate","extraQueryKeys","getExtraQueryKeysFromRoute","routeQuerySchema","allowedKeys","ALLOWED_QUERY_PARAM_KEYS","pick","filter","traverseQueryFilters","traverseQuerySort","traverseQueryPopulate"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/sanitize/index.ts"],"sourcesContent":["import { CurriedFunction1, cloneDeep, omit, pick } from 'lodash';\nimport type { z } from 'zod/v4';\n\nimport { constants, getNonWritableAttributes } from '../content-types';\nimport { ALLOWED_QUERY_PARAM_KEYS } from '../content-api-constants';\nimport {\n type RouteLike,\n getExtraQueryKeysFromRoute,\n getExtraRootKeysFromRouteBody,\n} from '../content-api-route-params';\nimport { pipe as pipeAsync } from '../async';\n\nimport * as visitors from './visitors';\nimport * as sanitizers from './sanitizers';\nimport traverseEntity from '../traverse-entity';\n\nimport { traverseQueryFilters, traverseQuerySort, traverseQueryPopulate } from '../traverse';\nimport type { Model, Data } from '../types';\nimport { validatePublicationFilterQueryParam } from '../publication-filter';\nimport { hasSort } from '../sort-query';\n\nexport interface Options {\n auth?: unknown;\n /**\n * If true, removes fields that are not declared in the schema (input) or keeps only allowed query param keys (query).\n * Defaults to false for backward compatibility.\n * TODO: In Strapi 6, strictParams will default to true (and may be removed as an option)\n */\n strictParams?: boolean;\n /**\n * When set, extra query/input params are derived from the route's request schema (and validated/sanitized with Zod).\n * When absent, no extra params are allowed in strict mode.\n */\n route?: RouteLike;\n}\n\nexport interface Sanitizer {\n (schema: Model): CurriedFunction1<Data, Promise<Data>>;\n}\nexport interface SanitizeFunc {\n (data: unknown, schema: Model, options?: Options): Promise<unknown>;\n}\n\nexport type SanitizeQueryParamHandler = (\n value: unknown,\n schema: Model,\n options?: Options\n) => Promise<unknown>;\n\nexport type SanitizeBodyParamHandler = (\n value: unknown,\n schema: Model,\n options?: Options\n) => Promise<unknown>;\n\nexport interface APIOptions {\n sanitizers?: Sanitizers;\n getModel: (model: string) => Model;\n}\n\nexport interface Sanitizers {\n input?: Sanitizer[];\n output?: Sanitizer[];\n}\n\nconst createAPISanitizers = (opts: APIOptions) => {\n const { getModel } = opts;\n\n const sanitizeInput: SanitizeFunc = (\n data: unknown,\n schema: Model,\n { auth, strictParams = false, route } = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeInput');\n }\n if (Array.isArray(data)) {\n return Promise.all(\n data.map((entry) => sanitizeInput(entry, schema, { auth, strictParams, route }))\n );\n }\n\n const allowedExtraRootKeys = getExtraRootKeysFromRouteBody(route);\n\n const nonWritableAttributes = getNonWritableAttributes(schema);\n\n const transforms = [\n // Remove first level ID in inputs\n (value: Record<string, unknown>) => omit(value, constants.ID_ATTRIBUTE),\n (value: Record<string, unknown>) => omit(value, constants.DOC_ID_ATTRIBUTE),\n // Remove non-writable attributes\n traverseEntity(visitors.removeRestrictedFields(nonWritableAttributes), { schema, getModel }),\n ];\n\n if (strictParams) {\n // Remove unrecognized fields (allowedExtraRootKeys = registered input param keys)\n transforms.push(\n traverseEntity(visitors.removeUnrecognizedFields, {\n schema,\n getModel,\n allowedExtraRootKeys,\n })\n );\n }\n\n if (auth) {\n // Remove restricted relations\n transforms.push(\n traverseEntity(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n // Apply sanitizers from registry if exists\n opts?.sanitizers?.input?.forEach((sanitizer: Sanitizer) => transforms.push(sanitizer(schema)));\n\n /**\n * For each extra root key from the route's body schema present in data, run Zod safeParse.\n * If parsing fails, the key is removed from the output.\n *\n * Content-api sends the document payload as body.data; the controller calls sanitizeInput(body.data, ctx),\n * so the input we receive here is the inner payload (keys like \"relatedMedia\", \"name\"), not the full body.\n * The route's body schema is z.object({ data: ... }), so its shape includes \"data\". We skip \"data\" because\n * the main document payload is already sanitized above by traverseEntity (removeUnrecognizedFields, etc.);\n * relation ops (connect/disconnect/set) are handled there, not by the route's Zod schema. We only run\n * Zod here for truly extra root keys added via addInputParams (e.g. clientMutationId).\n */\n const routeBodySanitizeTransform = async (data: Data): Promise<Data> => {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return data;\n const obj = data as Record<string, unknown>;\n const bodySchema = route?.request?.body?.['application/json'];\n if (bodySchema && typeof bodySchema === 'object' && 'shape' in bodySchema) {\n const shape = (bodySchema as { shape: Record<string, z.ZodTypeAny> }).shape;\n for (const key of Object.keys(shape)) {\n if (key === 'data' || !(key in obj)) continue;\n const zodSchema = shape[key];\n if (zodSchema && typeof (zodSchema as z.ZodTypeAny).safeParse === 'function') {\n const result = (zodSchema as z.ZodTypeAny).safeParse(obj[key]);\n if (result.success) {\n obj[key] = result.data;\n } else {\n delete obj[key];\n }\n }\n }\n }\n return data;\n };\n (transforms as Array<(data: Data) => Data | Promise<Data>>).push(routeBodySanitizeTransform);\n\n return pipeAsync(...transforms)(data as Data);\n };\n\n const sanitizeOutput: SanitizeFunc = async (data, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeOutput');\n }\n if (Array.isArray(data)) {\n const res: unknown[] = Array.from({ length: data.length });\n for (let i = 0; i < data.length; i += 1) {\n res[i] = await sanitizeOutput(data[i], schema, { auth });\n }\n return res;\n }\n\n const transforms = [\n (data: Data) => sanitizers.defaultSanitizeOutput({ schema, getModel }, data),\n ];\n\n if (auth) {\n transforms.push(\n traverseEntity(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n // Apply sanitizers from registry if exists\n opts?.sanitizers?.output?.forEach((sanitizer: Sanitizer) => transforms.push(sanitizer(schema)));\n\n return pipeAsync(...transforms)(data as Data);\n };\n\n const sanitizeQuery = async (\n query: Record<string, unknown>,\n schema: Model,\n { auth, strictParams = false, route }: Options = {}\n ) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeQuery');\n }\n const { filters, sort, fields, populate } = query;\n\n const sanitizedQuery = cloneDeep(query);\n\n if ('publicationFilter' in sanitizedQuery) {\n validatePublicationFilterQueryParam(sanitizedQuery.publicationFilter);\n }\n\n if (filters) {\n Object.assign(sanitizedQuery, { filters: await sanitizeFilters(filters, schema, { auth }) });\n }\n\n if (hasSort(sort)) {\n Object.assign(sanitizedQuery, { sort: await sanitizeSort(sort, schema, { auth }) });\n } else if ('sort' in sanitizedQuery) {\n delete sanitizedQuery.sort;\n }\n\n if (fields) {\n Object.assign(sanitizedQuery, { fields: await sanitizeFields(fields, schema) });\n }\n\n if (populate) {\n Object.assign(sanitizedQuery, {\n populate: await sanitizePopulate(populate, schema, { auth }),\n });\n }\n\n const extraQueryKeys = getExtraQueryKeysFromRoute(route);\n const routeQuerySchema = route?.request?.query;\n if (routeQuerySchema) {\n for (const key of extraQueryKeys) {\n if (key in query) {\n const zodSchema = routeQuerySchema[key];\n if (zodSchema && typeof (zodSchema as z.ZodTypeAny).safeParse === 'function') {\n const result = (zodSchema as z.ZodTypeAny).safeParse(query[key]);\n if (result.success) {\n sanitizedQuery[key] = result.data;\n } else {\n delete sanitizedQuery[key];\n }\n }\n }\n }\n }\n\n if (strictParams) {\n const allowedKeys = [...ALLOWED_QUERY_PARAM_KEYS, ...extraQueryKeys];\n return pick(sanitizedQuery, allowedKeys) as Record<string, unknown>;\n }\n\n return sanitizedQuery;\n };\n\n const sanitizeFilters: SanitizeFunc = (filters, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeFilters');\n }\n if (Array.isArray(filters)) {\n return Promise.all(filters.map((filter) => sanitizeFilters(filter, schema, { auth })));\n }\n\n const transforms = [sanitizers.defaultSanitizeFilters({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryFilters(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(filters);\n };\n\n const sanitizeSort: SanitizeFunc = (sort, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeSort');\n }\n const transforms = [sanitizers.defaultSanitizeSort({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQuerySort(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(sort);\n };\n\n const sanitizeFields: SanitizeFunc = (fields, schema: Model) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizeFields');\n }\n const transforms = [sanitizers.defaultSanitizeFields({ schema, getModel })];\n\n return pipeAsync(...transforms)(fields);\n };\n\n const sanitizePopulate: SanitizeFunc = (populate, schema: Model, { auth } = {}) => {\n if (!schema) {\n throw new Error('Missing schema in sanitizePopulate');\n }\n const transforms = [sanitizers.defaultSanitizePopulate({ schema, getModel })];\n\n if (auth) {\n transforms.push(\n traverseQueryPopulate(visitors.removeRestrictedRelations(auth), { schema, getModel })\n );\n }\n\n return pipeAsync(...transforms)(populate);\n };\n\n return {\n input: sanitizeInput,\n output: sanitizeOutput,\n query: sanitizeQuery,\n filters: sanitizeFilters,\n sort: sanitizeSort,\n fields: sanitizeFields,\n populate: sanitizePopulate,\n };\n};\n\nexport { createAPISanitizers, sanitizers, visitors };\n\nexport type APISanitiers = ReturnType<typeof createAPISanitizers>;\n"],"names":["createAPISanitizers","opts","getModel","sanitizeInput","data","schema","auth","strictParams","route","Error","Array","isArray","Promise","all","map","entry","allowedExtraRootKeys","getExtraRootKeysFromRouteBody","nonWritableAttributes","getNonWritableAttributes","transforms","value","omit","constants","ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","traverseEntity","visitors","push","sanitizers","input","forEach","sanitizer","routeBodySanitizeTransform","obj","bodySchema","request","body","shape","key","Object","keys","zodSchema","safeParse","result","success","pipeAsync","sanitizeOutput","res","from","length","i","output","sanitizeQuery","query","filters","sort","fields","populate","sanitizedQuery","cloneDeep","validatePublicationFilterQueryParam","publicationFilter","assign","sanitizeFilters","hasSort","sanitizeSort","sanitizeFields","sanitizePopulate","extraQueryKeys","getExtraQueryKeysFromRoute","routeQuerySchema","allowedKeys","ALLOWED_QUERY_PARAM_KEYS","pick","filter","traverseQueryFilters","traverseQuerySort","traverseQueryPopulate"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _ = require('lodash');
|
|
4
4
|
var async = require('../async.js');
|
|
5
5
|
var traverseEntity = require('../traverse-entity.js');
|
|
6
6
|
var contentTypes = require('../content-types.js');
|
|
@@ -34,7 +34,7 @@ const defaultSanitizeOutput = async (ctx, entity)=>{
|
|
|
34
34
|
removePrivate(visitorOptions, visitorUtils);
|
|
35
35
|
}, ctx, entity);
|
|
36
36
|
};
|
|
37
|
-
const defaultSanitizeFilters =
|
|
37
|
+
const defaultSanitizeFilters = _.curry((ctx, filters)=>{
|
|
38
38
|
if (!ctx.schema) {
|
|
39
39
|
throw new Error('Missing schema in defaultSanitizeFilters');
|
|
40
40
|
}
|
|
@@ -59,14 +59,14 @@ const defaultSanitizeFilters = fp.curry((ctx, filters)=>{
|
|
|
59
59
|
queryFilters(removePrivate, ctx), // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no
|
|
60
60
|
// enumerable keys (Date, RegExp, boxed primitives, etc.) are "empty" and would wrongly drop valid operands.
|
|
61
61
|
queryFilters(({ key, value }, { remove })=>{
|
|
62
|
-
const isEmptyPlainObject =
|
|
63
|
-
const isEmptyArrayOperand =
|
|
62
|
+
const isEmptyPlainObject = _.isPlainObject(value) && _.isEmpty(value);
|
|
63
|
+
const isEmptyArrayOperand = Array.isArray(value) && value.length === 0;
|
|
64
64
|
if (isEmptyPlainObject || isEmptyArrayOperand) {
|
|
65
65
|
remove(key);
|
|
66
66
|
}
|
|
67
67
|
}, ctx))(filters);
|
|
68
68
|
});
|
|
69
|
-
const defaultSanitizeSort =
|
|
69
|
+
const defaultSanitizeSort = _.curry((ctx, sort)=>{
|
|
70
70
|
if (!ctx.schema) {
|
|
71
71
|
throw new Error('Missing schema in defaultSanitizeSort');
|
|
72
72
|
}
|
|
@@ -97,12 +97,12 @@ const defaultSanitizeSort = fp.curry((ctx, sort)=>{
|
|
|
97
97
|
].includes(key)) {
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
|
-
if (!contentTypes.isScalarAttribute(attribute) &&
|
|
100
|
+
if (!contentTypes.isScalarAttribute(attribute) && _.isEmpty(value)) {
|
|
101
101
|
remove(key);
|
|
102
102
|
}
|
|
103
103
|
}, ctx))(sort);
|
|
104
104
|
});
|
|
105
|
-
const defaultSanitizeFields =
|
|
105
|
+
const defaultSanitizeFields = _.curry((ctx, fields)=>{
|
|
106
106
|
if (!ctx.schema) {
|
|
107
107
|
throw new Error('Missing schema in defaultSanitizeFields');
|
|
108
108
|
}
|
|
@@ -116,15 +116,15 @@ const defaultSanitizeFields = fp.curry((ctx, fields)=>{
|
|
|
116
116
|
].includes(key)) {
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
|
-
if (
|
|
119
|
+
if (attribute == null || !contentTypes.isScalarAttribute(attribute)) {
|
|
120
120
|
remove(key);
|
|
121
121
|
}
|
|
122
122
|
}, ctx), // Remove private fields
|
|
123
123
|
queryFields(removePrivate, ctx), // Remove password fields
|
|
124
124
|
queryFields(removePassword, ctx), // Remove nil values from fields array
|
|
125
|
-
(value)=>
|
|
125
|
+
(value)=>Array.isArray(value) ? value.filter((field)=>field != null) : value)(fields);
|
|
126
126
|
});
|
|
127
|
-
const defaultSanitizePopulate =
|
|
127
|
+
const defaultSanitizePopulate = _.curry((ctx, populate)=>{
|
|
128
128
|
if (!ctx.schema) {
|
|
129
129
|
throw new Error('Missing schema in defaultSanitizePopulate');
|
|
130
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizers.js","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { curry, isEmpty, isNil, isArray, isPlainObject } from 'lodash/fp';\n\nimport { pipe as pipeAsync } from '../async';\nimport traverseEntity from '../traverse-entity';\nimport { isScalarAttribute, constants } from '../content-types';\n\nimport {\n traverseQueryFilters,\n traverseQuerySort,\n traverseQueryPopulate,\n traverseQueryFields,\n} from '../traverse';\n\nimport {\n removePassword,\n removePrivate,\n removeDynamicZones,\n removeMorphToRelations,\n expandWildcardPopulate,\n} from './visitors';\nimport { isOperator } from '../operators';\n\nimport type { Model, Data } from '../types';\nimport type { Parent } from '../traverse/factory';\n\ninterface Context {\n schema: Model;\n getModel: (model: string) => Model;\n parent?: Parent;\n}\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nconst sanitizePasswords = (ctx: Context) => async (entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in sanitizePasswords');\n }\n\n return traverseEntity(removePassword, ctx, entity);\n};\n\nconst defaultSanitizeOutput = async (ctx: Context, entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeOutput');\n }\n\n // Named parameters rather than a rest-spread: this runs once per key, per node, per\n // entity, and `(...args)` allocated a fresh array on every call.\n return traverseEntity(\n (visitorOptions, visitorUtils) => {\n removePassword(visitorOptions, visitorUtils);\n removePrivate(visitorOptions, visitorUtils);\n },\n ctx,\n entity\n );\n};\n\nconst defaultSanitizeFilters = curry((ctx: Context, filters: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFilters');\n }\n\n return pipeAsync(\n // Remove keys that are not attributes or valid operators\n traverseQueryFilters(({ key, attribute }, { remove }) => {\n const isAttribute = !!attribute;\n\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isAttribute && !isOperator(key)) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from filters\n traverseQueryFilters(removeDynamicZones, ctx),\n // Remove morpTo relations from filters\n traverseQueryFilters(removeMorphToRelations, ctx),\n // Remove passwords from filters\n traverseQueryFilters(removePassword, ctx),\n // Remove private from filters\n traverseQueryFilters(removePrivate, ctx),\n // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no\n // enumerable keys (Date, RegExp, boxed primitives, etc.) are \"empty\" and would wrongly drop valid operands.\n traverseQueryFilters(({ key, value }, { remove }) => {\n const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);\n const isEmptyArrayOperand = isArray(value) && isEmpty(value);\n if (isEmptyPlainObject || isEmptyArrayOperand) {\n remove(key);\n }\n }, ctx)\n )(filters);\n});\n\nconst defaultSanitizeSort = curry((ctx: Context, sort: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeSort');\n }\n\n return pipeAsync(\n // Remove non attribute keys\n traverseQuerySort(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!attribute) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from sort\n traverseQuerySort(removeDynamicZones, ctx),\n // Remove morpTo relations from sort\n traverseQuerySort(removeMorphToRelations, ctx),\n // Remove private from sort\n traverseQuerySort(removePrivate, ctx),\n // Remove passwords from filters\n traverseQuerySort(removePassword, ctx),\n // Remove keys for empty non-scalar values\n traverseQuerySort(({ key, attribute, value }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not removing it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isScalarAttribute(attribute) && isEmpty(value)) {\n remove(key);\n }\n }, ctx)\n )(sort);\n});\n\nconst defaultSanitizeFields = curry((ctx: Context, fields: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFields');\n }\n\n return pipeAsync(\n // Only keep scalar attributes\n traverseQueryFields(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (isNil(attribute) || !isScalarAttribute(attribute)) {\n remove(key);\n }\n }, ctx),\n // Remove private fields\n traverseQueryFields(removePrivate, ctx),\n // Remove password fields\n traverseQueryFields(removePassword, ctx),\n // Remove nil values from fields array\n (value) => (isArray(value) ? value.filter((field) => !isNil(field)) : value)\n )(fields);\n});\n\nconst defaultSanitizePopulate = curry((ctx: Context, populate: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizePopulate');\n }\n\n return pipeAsync(\n traverseQueryPopulate(expandWildcardPopulate, ctx),\n traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set }) => {\n if (attribute) {\n return;\n }\n\n const parent = { key, path, schema, attribute } satisfies Parent;\n\n if (key === 'sort') {\n set(key, await defaultSanitizeSort({ schema, getModel, parent }, value));\n }\n\n if (key === 'filters') {\n set(key, await defaultSanitizeFilters({ schema, getModel, parent }, value));\n }\n\n if (key === 'fields') {\n set(key, await defaultSanitizeFields({ schema, getModel, parent }, value));\n }\n\n if (key === 'populate') {\n set(key, await defaultSanitizePopulate({ schema, getModel, parent }, value));\n }\n }, ctx),\n // Remove private fields\n traverseQueryPopulate(removePrivate, ctx)\n )(populate);\n});\n\nexport {\n sanitizePasswords,\n defaultSanitizeOutput,\n defaultSanitizeFilters,\n defaultSanitizeSort,\n defaultSanitizeFields,\n defaultSanitizePopulate,\n};\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","sanitizePasswords","ctx","entity","schema","Error","traverseEntity","removePassword","defaultSanitizeOutput","visitorOptions","visitorUtils","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isEmptyPlainObject","isPlainObject","isEmpty","isEmptyArrayOperand","isArray","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","isNil","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":";;;;;;;;;;;;;;;;;;AA+BA,MAAM,EAAEA,YAAY,EAAEC,gBAAgB,EAAE,GAAGC,sBAAAA;AAE3C,MAAMC,iBAAAA,GAAoB,CAACC,GAAAA,GAAiB,OAAOC,MAAAA,GAAAA;QACjD,IAAI,CAACD,GAAAA,CAAIE,MAAM,EAAE;AACf,YAAA,MAAM,IAAIC,KAAAA,CAAM,qCAAA,CAAA;AAClB,QAAA;QAEA,OAAOC,cAAAA,CAAeC,gBAAgBL,GAAAA,EAAKC,MAAAA,CAAAA;AAC7C,IAAA;AAEA,MAAMK,qBAAAA,GAAwB,OAAON,GAAAA,EAAcC,MAAAA,GAAAA;IACjD,IAAI,CAACD,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,yCAAA,CAAA;AAClB,IAAA;;;IAIA,OAAOC,cAAAA,CACL,CAACG,cAAAA,EAAgBC,YAAAA,GAAAA;AACfH,QAAAA,cAAAA,CAAeE,cAAAA,EAAgBC,YAAAA,CAAAA;AAC/BC,QAAAA,aAAAA,CAAcF,cAAAA,EAAgBC,YAAAA,CAAAA;AAChC,IAAA,CAAA,EACAR,GAAAA,EACAC,MAAAA,CAAAA;AAEJ;AAEA,MAAMS,sBAAAA,GAAyBC,QAAAA,CAAM,CAACX,GAAAA,EAAcY,OAAAA,GAAAA;IAClD,IAAI,CAACZ,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,0CAAA,CAAA;AAClB,IAAA;AAEA,IAAA,OAAOU;IAELC,YAAAA,CAAqB,CAAC,EAAEC,GAAG,EAAEC,SAAS,EAAE,EAAE,EAAEC,MAAM,EAAE,GAAA;QAClD,MAAMC,WAAAA,GAAc,CAAC,CAACF,SAAAA;;;QAItB,IAAI;AAACpB,YAAAA,YAAAA;AAAcC,YAAAA;SAAiB,CAACsB,QAAQ,CAACJ,GAAAA,CAAAA,EAAM;AAClD,YAAA;AACF,QAAA;AAEA,QAAA,IAAI,CAACG,WAAAA,IAAe,CAACE,oBAAAA,CAAWL,GAAAA,CAAAA,EAAM;YACpCE,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf;IAEHc,YAAAA,CAAqBO,kBAAAA,EAAoBrB;IAEzCc,YAAAA,CAAqBQ,sBAAAA,EAAwBtB;IAE7Cc,YAAAA,CAAqBT,cAAAA,EAAgBL;IAErCc,YAAAA,CAAqBL,aAAAA,EAAeT;;IAGpCc,YAAAA,CAAqB,CAAC,EAAEC,GAAG,EAAEQ,KAAK,EAAE,EAAE,EAAEN,MAAM,EAAE,GAAA;QAC9C,MAAMO,kBAAAA,GAAqBC,gBAAAA,CAAcF,KAAAA,CAAAA,IAAUG,UAAAA,CAAQH,KAAAA,CAAAA;QAC3D,MAAMI,mBAAAA,GAAsBC,UAAAA,CAAQL,KAAAA,CAAAA,IAAUG,UAAAA,CAAQH,KAAAA,CAAAA;AACtD,QAAA,IAAIC,sBAAsBG,mBAAAA,EAAqB;YAC7CV,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf,GAAAA,CAAAA,CAAAA,CACHY,OAAAA,CAAAA;AACJ,CAAA;AAEA,MAAMiB,mBAAAA,GAAsBlB,QAAAA,CAAM,CAACX,GAAAA,EAAc8B,IAAAA,GAAAA;IAC/C,IAAI,CAAC9B,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,uCAAA,CAAA;AAClB,IAAA;AAEA,IAAA,OAAOU;IAELkB,SAAAA,CAAkB,CAAC,EAAEhB,GAAG,EAAEC,SAAS,EAAE,EAAE,EAAEC,MAAM,EAAE,GAAA;;;QAG/C,IAAI;AAACrB,YAAAA,YAAAA;AAAcC,YAAAA;SAAiB,CAACsB,QAAQ,CAACJ,GAAAA,CAAAA,EAAM;AAClD,YAAA;AACF,QAAA;AAEA,QAAA,IAAI,CAACC,SAAAA,EAAW;YACdC,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf;IAEH+B,SAAAA,CAAkBV,kBAAAA,EAAoBrB;IAEtC+B,SAAAA,CAAkBT,sBAAAA,EAAwBtB;IAE1C+B,SAAAA,CAAkBtB,aAAAA,EAAeT;IAEjC+B,SAAAA,CAAkB1B,cAAAA,EAAgBL;IAElC+B,SAAAA,CAAkB,CAAC,EAAEhB,GAAG,EAAEC,SAAS,EAAEO,KAAK,EAAE,EAAE,EAAEN,MAAM,EAAE,GAAA;;;QAGtD,IAAI;AAACrB,YAAAA,YAAAA;AAAcC,YAAAA;SAAiB,CAACsB,QAAQ,CAACJ,GAAAA,CAAAA,EAAM;AAClD,YAAA;AACF,QAAA;AAEA,QAAA,IAAI,CAACiB,8BAAAA,CAAkBhB,SAAAA,CAAAA,IAAcU,UAAAA,CAAQH,KAAAA,CAAAA,EAAQ;YACnDN,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf,GAAAA,CAAAA,CAAAA,CACH8B,IAAAA,CAAAA;AACJ,CAAA;AAEA,MAAMG,qBAAAA,GAAwBtB,QAAAA,CAAM,CAACX,GAAAA,EAAckC,MAAAA,GAAAA;IACjD,IAAI,CAAClC,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,yCAAA,CAAA;AAClB,IAAA;AAEA,IAAA,OAAOU;IAELsB,WAAAA,CAAoB,CAAC,EAAEpB,GAAG,EAAEC,SAAS,EAAE,EAAE,EAAEC,MAAM,EAAE,GAAA;;;QAGjD,IAAI;AAACrB,YAAAA,YAAAA;AAAcC,YAAAA;SAAiB,CAACsB,QAAQ,CAACJ,GAAAA,CAAAA,EAAM;AAClD,YAAA;AACF,QAAA;AAEA,QAAA,IAAIqB,QAAAA,CAAMpB,SAAAA,CAAAA,IAAc,CAACgB,8BAAAA,CAAkBhB,SAAAA,CAAAA,EAAY;YACrDC,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf;IAEHmC,WAAAA,CAAoB1B,aAAAA,EAAeT;IAEnCmC,WAAAA,CAAoB9B,cAAAA,EAAgBL;IAEpC,CAACuB,KAAAA,GAAWK,UAAAA,CAAQL,KAAAA,CAAAA,GAASA,KAAAA,CAAMc,MAAM,CAAC,CAACC,KAAAA,GAAU,CAACF,QAAAA,CAAME,KAAAA,CAAAA,CAAAA,GAAUf,KAAAA,CAAAA,CACtEW,MAAAA,CAAAA;AACJ,CAAA;AAEA,MAAMK,uBAAAA,GAA0B5B,QAAAA,CAAM,CAACX,GAAAA,EAAcwC,QAAAA,GAAAA;IACnD,IAAI,CAACxC,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,2CAAA,CAAA;AAClB,IAAA;IAEA,OAAOU,UAAAA,CACL4B,cAAsBC,sBAAAA,EAAwB1C,GAAAA,CAAAA,EAC9CyC,cAAsB,OAAO,EAAE1B,GAAG,EAAEQ,KAAK,EAAErB,MAAM,EAAEc,SAAS,EAAE2B,QAAQ,EAAEC,IAAI,EAAE,EAAE,EAAEC,GAAG,EAAE,GAAA;AACrF,QAAA,IAAI7B,SAAAA,EAAW;AACb,YAAA;AACF,QAAA;AAEA,QAAA,MAAM8B,MAAAA,GAAS;AAAE/B,YAAAA,GAAAA;AAAK6B,YAAAA,IAAAA;AAAM1C,YAAAA,MAAAA;AAAQc,YAAAA;AAAU,SAAA;AAE9C,QAAA,IAAID,QAAQ,MAAA,EAAQ;YAClB8B,GAAAA,CAAI9B,GAAAA,EAAK,MAAMc,mBAAAA,CAAoB;AAAE3B,gBAAAA,MAAAA;AAAQyC,gBAAAA,QAAAA;AAAUG,gBAAAA;aAAO,EAAGvB,KAAAA,CAAAA,CAAAA;AACnE,QAAA;AAEA,QAAA,IAAIR,QAAQ,SAAA,EAAW;YACrB8B,GAAAA,CAAI9B,GAAAA,EAAK,MAAML,sBAAAA,CAAuB;AAAER,gBAAAA,MAAAA;AAAQyC,gBAAAA,QAAAA;AAAUG,gBAAAA;aAAO,EAAGvB,KAAAA,CAAAA,CAAAA;AACtE,QAAA;AAEA,QAAA,IAAIR,QAAQ,QAAA,EAAU;YACpB8B,GAAAA,CAAI9B,GAAAA,EAAK,MAAMkB,qBAAAA,CAAsB;AAAE/B,gBAAAA,MAAAA;AAAQyC,gBAAAA,QAAAA;AAAUG,gBAAAA;aAAO,EAAGvB,KAAAA,CAAAA,CAAAA;AACrE,QAAA;AAEA,QAAA,IAAIR,QAAQ,UAAA,EAAY;YACtB8B,GAAAA,CAAI9B,GAAAA,EAAK,MAAMwB,uBAAAA,CAAwB;AAAErC,gBAAAA,MAAAA;AAAQyC,gBAAAA,QAAAA;AAAUG,gBAAAA;aAAO,EAAGvB,KAAAA,CAAAA,CAAAA;AACvE,QAAA;AACF,IAAA,CAAA,EAAGvB;AAEHyC,IAAAA,aAAAA,CAAsBhC,eAAeT,GAAAA,CAAAA,CAAAA,CACrCwC,QAAAA,CAAAA;AACJ,CAAA;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"sanitizers.js","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { curry, isEmpty, isPlainObject } from 'lodash';\n\nimport { pipe as pipeAsync } from '../async';\nimport traverseEntity from '../traverse-entity';\nimport { isScalarAttribute, constants } from '../content-types';\n\nimport {\n traverseQueryFilters,\n traverseQuerySort,\n traverseQueryPopulate,\n traverseQueryFields,\n} from '../traverse';\n\nimport {\n removePassword,\n removePrivate,\n removeDynamicZones,\n removeMorphToRelations,\n expandWildcardPopulate,\n} from './visitors';\nimport { isOperator } from '../operators';\n\nimport type { Model, Data } from '../types';\nimport type { Parent } from '../traverse/factory';\n\ninterface Context {\n schema: Model;\n getModel: (model: string) => Model;\n parent?: Parent;\n}\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nconst sanitizePasswords = (ctx: Context) => async (entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in sanitizePasswords');\n }\n\n return traverseEntity(removePassword, ctx, entity);\n};\n\nconst defaultSanitizeOutput = async (ctx: Context, entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeOutput');\n }\n\n // Named parameters rather than a rest-spread: this runs once per key, per node, per\n // entity, and `(...args)` allocated a fresh array on every call.\n return traverseEntity(\n (visitorOptions, visitorUtils) => {\n removePassword(visitorOptions, visitorUtils);\n removePrivate(visitorOptions, visitorUtils);\n },\n ctx,\n entity\n );\n};\n\nconst defaultSanitizeFilters = curry((ctx: Context, filters: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFilters');\n }\n\n return pipeAsync(\n // Remove keys that are not attributes or valid operators\n traverseQueryFilters(({ key, attribute }, { remove }) => {\n const isAttribute = !!attribute;\n\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isAttribute && !isOperator(key)) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from filters\n traverseQueryFilters(removeDynamicZones, ctx),\n // Remove morpTo relations from filters\n traverseQueryFilters(removeMorphToRelations, ctx),\n // Remove passwords from filters\n traverseQueryFilters(removePassword, ctx),\n // Remove private from filters\n traverseQueryFilters(removePrivate, ctx),\n // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no\n // enumerable keys (Date, RegExp, boxed primitives, etc.) are \"empty\" and would wrongly drop valid operands.\n traverseQueryFilters(({ key, value }, { remove }) => {\n const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);\n const isEmptyArrayOperand = Array.isArray(value) && value.length === 0;\n if (isEmptyPlainObject || isEmptyArrayOperand) {\n remove(key);\n }\n }, ctx)\n )(filters);\n});\n\nconst defaultSanitizeSort = curry((ctx: Context, sort: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeSort');\n }\n\n return pipeAsync(\n // Remove non attribute keys\n traverseQuerySort(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!attribute) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from sort\n traverseQuerySort(removeDynamicZones, ctx),\n // Remove morpTo relations from sort\n traverseQuerySort(removeMorphToRelations, ctx),\n // Remove private from sort\n traverseQuerySort(removePrivate, ctx),\n // Remove passwords from filters\n traverseQuerySort(removePassword, ctx),\n // Remove keys for empty non-scalar values\n traverseQuerySort(({ key, attribute, value }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not removing it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isScalarAttribute(attribute) && isEmpty(value)) {\n remove(key);\n }\n }, ctx)\n )(sort);\n});\n\nconst defaultSanitizeFields = curry((ctx: Context, fields: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFields');\n }\n\n return pipeAsync(\n // Only keep scalar attributes\n traverseQueryFields(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (attribute == null || !isScalarAttribute(attribute)) {\n remove(key);\n }\n }, ctx),\n // Remove private fields\n traverseQueryFields(removePrivate, ctx),\n // Remove password fields\n traverseQueryFields(removePassword, ctx),\n // Remove nil values from fields array\n (value) => (Array.isArray(value) ? value.filter((field) => field != null) : value)\n )(fields);\n});\n\nconst defaultSanitizePopulate = curry((ctx: Context, populate: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizePopulate');\n }\n\n return pipeAsync(\n traverseQueryPopulate(expandWildcardPopulate, ctx),\n traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set }) => {\n if (attribute) {\n return;\n }\n\n const parent = { key, path, schema, attribute } satisfies Parent;\n\n if (key === 'sort') {\n set(key, await defaultSanitizeSort({ schema, getModel, parent }, value));\n }\n\n if (key === 'filters') {\n set(key, await defaultSanitizeFilters({ schema, getModel, parent }, value));\n }\n\n if (key === 'fields') {\n set(key, await defaultSanitizeFields({ schema, getModel, parent }, value));\n }\n\n if (key === 'populate') {\n set(key, await defaultSanitizePopulate({ schema, getModel, parent }, value));\n }\n }, ctx),\n // Remove private fields\n traverseQueryPopulate(removePrivate, ctx)\n )(populate);\n});\n\nexport {\n sanitizePasswords,\n defaultSanitizeOutput,\n defaultSanitizeFilters,\n defaultSanitizeSort,\n defaultSanitizeFields,\n defaultSanitizePopulate,\n};\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","sanitizePasswords","ctx","entity","schema","Error","traverseEntity","removePassword","defaultSanitizeOutput","visitorOptions","visitorUtils","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isEmptyPlainObject","isPlainObject","isEmpty","isEmptyArrayOperand","Array","isArray","length","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { curry, isPlainObject, isEmpty
|
|
1
|
+
import { curry, isPlainObject, isEmpty } from 'lodash';
|
|
2
2
|
import { pipe } from '../async.mjs';
|
|
3
3
|
import traverseEntity from '../traverse-entity.mjs';
|
|
4
4
|
import { constants, isScalarAttribute } from '../content-types.mjs';
|
|
@@ -58,7 +58,7 @@ const defaultSanitizeFilters = curry((ctx, filters)=>{
|
|
|
58
58
|
// enumerable keys (Date, RegExp, boxed primitives, etc.) are "empty" and would wrongly drop valid operands.
|
|
59
59
|
traverseQueryFilters(({ key, value }, { remove })=>{
|
|
60
60
|
const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);
|
|
61
|
-
const isEmptyArrayOperand = isArray(value) &&
|
|
61
|
+
const isEmptyArrayOperand = Array.isArray(value) && value.length === 0;
|
|
62
62
|
if (isEmptyPlainObject || isEmptyArrayOperand) {
|
|
63
63
|
remove(key);
|
|
64
64
|
}
|
|
@@ -114,13 +114,13 @@ const defaultSanitizeFields = curry((ctx, fields)=>{
|
|
|
114
114
|
].includes(key)) {
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
|
-
if (
|
|
117
|
+
if (attribute == null || !isScalarAttribute(attribute)) {
|
|
118
118
|
remove(key);
|
|
119
119
|
}
|
|
120
120
|
}, ctx), // Remove private fields
|
|
121
121
|
traverseQueryFields(visitor, ctx), // Remove password fields
|
|
122
122
|
traverseQueryFields(visitor$1, ctx), // Remove nil values from fields array
|
|
123
|
-
(value)=>isArray(value) ? value.filter((field)
|
|
123
|
+
(value)=>Array.isArray(value) ? value.filter((field)=>field != null) : value)(fields);
|
|
124
124
|
});
|
|
125
125
|
const defaultSanitizePopulate = curry((ctx, populate)=>{
|
|
126
126
|
if (!ctx.schema) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizers.mjs","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { curry, isEmpty, isNil, isArray, isPlainObject } from 'lodash/fp';\n\nimport { pipe as pipeAsync } from '../async';\nimport traverseEntity from '../traverse-entity';\nimport { isScalarAttribute, constants } from '../content-types';\n\nimport {\n traverseQueryFilters,\n traverseQuerySort,\n traverseQueryPopulate,\n traverseQueryFields,\n} from '../traverse';\n\nimport {\n removePassword,\n removePrivate,\n removeDynamicZones,\n removeMorphToRelations,\n expandWildcardPopulate,\n} from './visitors';\nimport { isOperator } from '../operators';\n\nimport type { Model, Data } from '../types';\nimport type { Parent } from '../traverse/factory';\n\ninterface Context {\n schema: Model;\n getModel: (model: string) => Model;\n parent?: Parent;\n}\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nconst sanitizePasswords = (ctx: Context) => async (entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in sanitizePasswords');\n }\n\n return traverseEntity(removePassword, ctx, entity);\n};\n\nconst defaultSanitizeOutput = async (ctx: Context, entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeOutput');\n }\n\n // Named parameters rather than a rest-spread: this runs once per key, per node, per\n // entity, and `(...args)` allocated a fresh array on every call.\n return traverseEntity(\n (visitorOptions, visitorUtils) => {\n removePassword(visitorOptions, visitorUtils);\n removePrivate(visitorOptions, visitorUtils);\n },\n ctx,\n entity\n );\n};\n\nconst defaultSanitizeFilters = curry((ctx: Context, filters: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFilters');\n }\n\n return pipeAsync(\n // Remove keys that are not attributes or valid operators\n traverseQueryFilters(({ key, attribute }, { remove }) => {\n const isAttribute = !!attribute;\n\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isAttribute && !isOperator(key)) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from filters\n traverseQueryFilters(removeDynamicZones, ctx),\n // Remove morpTo relations from filters\n traverseQueryFilters(removeMorphToRelations, ctx),\n // Remove passwords from filters\n traverseQueryFilters(removePassword, ctx),\n // Remove private from filters\n traverseQueryFilters(removePrivate, ctx),\n // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no\n // enumerable keys (Date, RegExp, boxed primitives, etc.) are \"empty\" and would wrongly drop valid operands.\n traverseQueryFilters(({ key, value }, { remove }) => {\n const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);\n const isEmptyArrayOperand = isArray(value) && isEmpty(value);\n if (isEmptyPlainObject || isEmptyArrayOperand) {\n remove(key);\n }\n }, ctx)\n )(filters);\n});\n\nconst defaultSanitizeSort = curry((ctx: Context, sort: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeSort');\n }\n\n return pipeAsync(\n // Remove non attribute keys\n traverseQuerySort(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!attribute) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from sort\n traverseQuerySort(removeDynamicZones, ctx),\n // Remove morpTo relations from sort\n traverseQuerySort(removeMorphToRelations, ctx),\n // Remove private from sort\n traverseQuerySort(removePrivate, ctx),\n // Remove passwords from filters\n traverseQuerySort(removePassword, ctx),\n // Remove keys for empty non-scalar values\n traverseQuerySort(({ key, attribute, value }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not removing it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isScalarAttribute(attribute) && isEmpty(value)) {\n remove(key);\n }\n }, ctx)\n )(sort);\n});\n\nconst defaultSanitizeFields = curry((ctx: Context, fields: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFields');\n }\n\n return pipeAsync(\n // Only keep scalar attributes\n traverseQueryFields(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (isNil(attribute) || !isScalarAttribute(attribute)) {\n remove(key);\n }\n }, ctx),\n // Remove private fields\n traverseQueryFields(removePrivate, ctx),\n // Remove password fields\n traverseQueryFields(removePassword, ctx),\n // Remove nil values from fields array\n (value) => (isArray(value) ? value.filter((field) => !isNil(field)) : value)\n )(fields);\n});\n\nconst defaultSanitizePopulate = curry((ctx: Context, populate: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizePopulate');\n }\n\n return pipeAsync(\n traverseQueryPopulate(expandWildcardPopulate, ctx),\n traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set }) => {\n if (attribute) {\n return;\n }\n\n const parent = { key, path, schema, attribute } satisfies Parent;\n\n if (key === 'sort') {\n set(key, await defaultSanitizeSort({ schema, getModel, parent }, value));\n }\n\n if (key === 'filters') {\n set(key, await defaultSanitizeFilters({ schema, getModel, parent }, value));\n }\n\n if (key === 'fields') {\n set(key, await defaultSanitizeFields({ schema, getModel, parent }, value));\n }\n\n if (key === 'populate') {\n set(key, await defaultSanitizePopulate({ schema, getModel, parent }, value));\n }\n }, ctx),\n // Remove private fields\n traverseQueryPopulate(removePrivate, ctx)\n )(populate);\n});\n\nexport {\n sanitizePasswords,\n defaultSanitizeOutput,\n defaultSanitizeFilters,\n defaultSanitizeSort,\n defaultSanitizeFields,\n defaultSanitizePopulate,\n};\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","sanitizePasswords","ctx","entity","schema","Error","traverseEntity","removePassword","defaultSanitizeOutput","visitorOptions","visitorUtils","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isEmptyPlainObject","isPlainObject","isEmpty","isEmptyArrayOperand","isArray","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","isNil","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sanitizers.mjs","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { curry, isEmpty, isPlainObject } from 'lodash';\n\nimport { pipe as pipeAsync } from '../async';\nimport traverseEntity from '../traverse-entity';\nimport { isScalarAttribute, constants } from '../content-types';\n\nimport {\n traverseQueryFilters,\n traverseQuerySort,\n traverseQueryPopulate,\n traverseQueryFields,\n} from '../traverse';\n\nimport {\n removePassword,\n removePrivate,\n removeDynamicZones,\n removeMorphToRelations,\n expandWildcardPopulate,\n} from './visitors';\nimport { isOperator } from '../operators';\n\nimport type { Model, Data } from '../types';\nimport type { Parent } from '../traverse/factory';\n\ninterface Context {\n schema: Model;\n getModel: (model: string) => Model;\n parent?: Parent;\n}\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nconst sanitizePasswords = (ctx: Context) => async (entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in sanitizePasswords');\n }\n\n return traverseEntity(removePassword, ctx, entity);\n};\n\nconst defaultSanitizeOutput = async (ctx: Context, entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeOutput');\n }\n\n // Named parameters rather than a rest-spread: this runs once per key, per node, per\n // entity, and `(...args)` allocated a fresh array on every call.\n return traverseEntity(\n (visitorOptions, visitorUtils) => {\n removePassword(visitorOptions, visitorUtils);\n removePrivate(visitorOptions, visitorUtils);\n },\n ctx,\n entity\n );\n};\n\nconst defaultSanitizeFilters = curry((ctx: Context, filters: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFilters');\n }\n\n return pipeAsync(\n // Remove keys that are not attributes or valid operators\n traverseQueryFilters(({ key, attribute }, { remove }) => {\n const isAttribute = !!attribute;\n\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isAttribute && !isOperator(key)) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from filters\n traverseQueryFilters(removeDynamicZones, ctx),\n // Remove morpTo relations from filters\n traverseQueryFilters(removeMorphToRelations, ctx),\n // Remove passwords from filters\n traverseQueryFilters(removePassword, ctx),\n // Remove private from filters\n traverseQueryFilters(removePrivate, ctx),\n // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no\n // enumerable keys (Date, RegExp, boxed primitives, etc.) are \"empty\" and would wrongly drop valid operands.\n traverseQueryFilters(({ key, value }, { remove }) => {\n const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);\n const isEmptyArrayOperand = Array.isArray(value) && value.length === 0;\n if (isEmptyPlainObject || isEmptyArrayOperand) {\n remove(key);\n }\n }, ctx)\n )(filters);\n});\n\nconst defaultSanitizeSort = curry((ctx: Context, sort: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeSort');\n }\n\n return pipeAsync(\n // Remove non attribute keys\n traverseQuerySort(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!attribute) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from sort\n traverseQuerySort(removeDynamicZones, ctx),\n // Remove morpTo relations from sort\n traverseQuerySort(removeMorphToRelations, ctx),\n // Remove private from sort\n traverseQuerySort(removePrivate, ctx),\n // Remove passwords from filters\n traverseQuerySort(removePassword, ctx),\n // Remove keys for empty non-scalar values\n traverseQuerySort(({ key, attribute, value }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not removing it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isScalarAttribute(attribute) && isEmpty(value)) {\n remove(key);\n }\n }, ctx)\n )(sort);\n});\n\nconst defaultSanitizeFields = curry((ctx: Context, fields: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFields');\n }\n\n return pipeAsync(\n // Only keep scalar attributes\n traverseQueryFields(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (attribute == null || !isScalarAttribute(attribute)) {\n remove(key);\n }\n }, ctx),\n // Remove private fields\n traverseQueryFields(removePrivate, ctx),\n // Remove password fields\n traverseQueryFields(removePassword, ctx),\n // Remove nil values from fields array\n (value) => (Array.isArray(value) ? value.filter((field) => field != null) : value)\n )(fields);\n});\n\nconst defaultSanitizePopulate = curry((ctx: Context, populate: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizePopulate');\n }\n\n return pipeAsync(\n traverseQueryPopulate(expandWildcardPopulate, ctx),\n traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set }) => {\n if (attribute) {\n return;\n }\n\n const parent = { key, path, schema, attribute } satisfies Parent;\n\n if (key === 'sort') {\n set(key, await defaultSanitizeSort({ schema, getModel, parent }, value));\n }\n\n if (key === 'filters') {\n set(key, await defaultSanitizeFilters({ schema, getModel, parent }, value));\n }\n\n if (key === 'fields') {\n set(key, await defaultSanitizeFields({ schema, getModel, parent }, value));\n }\n\n if (key === 'populate') {\n set(key, await defaultSanitizePopulate({ schema, getModel, parent }, value));\n }\n }, ctx),\n // Remove private fields\n traverseQueryPopulate(removePrivate, ctx)\n )(populate);\n});\n\nexport {\n sanitizePasswords,\n defaultSanitizeOutput,\n defaultSanitizeFilters,\n defaultSanitizeSort,\n defaultSanitizeFields,\n defaultSanitizePopulate,\n};\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","sanitizePasswords","ctx","entity","schema","Error","traverseEntity","removePassword","defaultSanitizeOutput","visitorOptions","visitorUtils","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isEmptyPlainObject","isPlainObject","isEmpty","isEmptyArrayOperand","Array","isArray","length","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _ = require('lodash');
|
|
4
4
|
|
|
5
5
|
var removeDisallowedFields = ((allowedFields = null)=>({ key, path: { attribute: path } }, { remove })=>{
|
|
6
6
|
// All fields are allowed
|
|
@@ -8,10 +8,10 @@ var removeDisallowedFields = ((allowedFields = null)=>({ key, path: { attribute:
|
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
// Throw on invalid formats
|
|
11
|
-
if (!(
|
|
11
|
+
if (!(Array.isArray(allowedFields) && allowedFields.every(_.isString))) {
|
|
12
12
|
throw new TypeError(`Expected array of strings for allowedFields but got "${typeof allowedFields}"`);
|
|
13
13
|
}
|
|
14
|
-
if (
|
|
14
|
+
if (path == null) {
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
const containedPaths = getContainedPaths(path);
|
|
@@ -74,7 +74,7 @@ var removeDisallowedFields = ((allowedFields = null)=>({ key, path: { attribute:
|
|
|
74
74
|
* // ['foo', 'foo.bar', 'foo.bar.field']
|
|
75
75
|
* ```
|
|
76
76
|
*/ const getContainedPaths = (path)=>{
|
|
77
|
-
const parts =
|
|
77
|
+
const parts = _.toPath(path);
|
|
78
78
|
return parts.reduce((acc, value, index, list)=>{
|
|
79
79
|
return [
|
|
80
80
|
...acc,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-disallowed-fields.js","sources":["../../../src/sanitize/visitors/remove-disallowed-fields.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"remove-disallowed-fields.js","sources":["../../../src/sanitize/visitors/remove-disallowed-fields.ts"],"sourcesContent":["import { isString, toPath } from 'lodash';\nimport type { Visitor } from '../../traverse/factory';\n\nexport default (allowedFields: string[] | null = null): Visitor =>\n ({ key, path: { attribute: path } }, { remove }) => {\n // All fields are allowed\n if (allowedFields === null) {\n return;\n }\n\n // Throw on invalid formats\n if (!(Array.isArray(allowedFields) && allowedFields.every(isString))) {\n throw new TypeError(\n `Expected array of strings for allowedFields but got \"${typeof allowedFields}\"`\n );\n }\n\n if (path == null) {\n return;\n }\n\n const containedPaths = getContainedPaths(path);\n\n /**\n * Tells if the current path should be kept or not based\n * on the success of the check functions for any of the allowed paths.\n *\n * The check functions are defined as follow:\n *\n * `containedPaths.includes(p)`\n * @example\n * ```js\n * const path = 'foo.bar.field';\n * const p = 'foo.bar';\n * // it should match\n *\n * const path = 'foo.bar.field';\n * const p = 'bar.foo';\n * // it shouldn't match\n *\n * const path = 'foo.bar';\n * const p = 'foo.bar.field';\n * // it should match but isn't handled by this check\n * ```\n *\n * `p.startsWith(`${path}.`)`\n * @example\n * ```js\n * const path = 'foo.bar';\n * const p = 'foo.bar.field';\n * // it should match\n *\n * const path = 'foo.bar.field';\n * const p = 'bar.foo';\n * // it shouldn't match\n *\n * const path = 'foo.bar.field';\n * const p = 'foo.bar';\n * // it should match but isn't handled by this check\n * ```\n */\n const isPathAllowed = allowedFields.some(\n (p) => containedPaths.includes(p) || p.startsWith(`${path}.`)\n );\n\n if (isPathAllowed) {\n return;\n }\n\n // Remove otherwise\n remove(key);\n };\n\n/**\n * Retrieve the list of allowed paths based on the given path\n *\n * @example\n * ```js\n * const containedPaths = getContainedPaths('foo');\n * // ['foo']\n *\n * * const containedPaths = getContainedPaths('foo.bar');\n * // ['foo', 'foo.bar']\n *\n * * const containedPaths = getContainedPaths('foo.bar.field');\n * // ['foo', 'foo.bar', 'foo.bar.field']\n * ```\n */\nconst getContainedPaths = (path: string) => {\n const parts = toPath(path);\n\n return parts.reduce((acc, value, index, list) => {\n return [...acc, list.slice(0, index + 1).join('.')];\n }, [] as string[]);\n};\n"],"names":["allowedFields","key","path","attribute","remove","Array","isArray","every","isString","TypeError","containedPaths","getContainedPaths","isPathAllowed","some","p","includes","startsWith","parts","toPath","reduce","acc","value","index","list","slice","join"],"mappings":";;;;AAGA,6BAAe,CAAA,CAACA,aAAAA,GAAiC,IAAI,GACnD,CAAC,EAAEC,GAAG,EAAEC,IAAAA,EAAM,EAAEC,WAAWD,IAAI,EAAE,EAAE,EAAE,EAAEE,MAAM,EAAE,GAAA;;AAE7C,QAAA,IAAIJ,kBAAkB,IAAA,EAAM;AAC1B,YAAA;AACF,QAAA;;QAGA,IAAI,EAAEK,KAAAA,CAAMC,OAAO,CAACN,kBAAkBA,aAAAA,CAAcO,KAAK,CAACC,UAAAA,CAAQ,CAAA,EAAI;YACpE,MAAM,IAAIC,UACR,CAAC,qDAAqD,EAAE,OAAOT,aAAAA,CAAc,CAAC,CAAC,CAAA;AAEnF,QAAA;AAEA,QAAA,IAAIE,QAAQ,IAAA,EAAM;AAChB,YAAA;AACF,QAAA;AAEA,QAAA,MAAMQ,iBAAiBC,iBAAAA,CAAkBT,IAAAA,CAAAA;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCC,QACD,MAAMU,aAAAA,GAAgBZ,aAAAA,CAAca,IAAI,CACtC,CAACC,CAAAA,GAAMJ,cAAAA,CAAeK,QAAQ,CAACD,MAAMA,CAAAA,CAAEE,UAAU,CAAC,CAAA,EAAGd,IAAAA,CAAK,CAAC,CAAC,CAAA,CAAA;AAG9D,QAAA,IAAIU,aAAAA,EAAe;AACjB,YAAA;AACF,QAAA;;QAGAR,MAAAA,CAAOH,GAAAA,CAAAA;AACT,IAAA,CAAA;AAEF;;;;;;;;;;;;;;IAeA,MAAMU,oBAAoB,CAACT,IAAAA,GAAAA;AACzB,IAAA,MAAMe,QAAQC,QAAAA,CAAOhB,IAAAA,CAAAA;AAErB,IAAA,OAAOe,MAAME,MAAM,CAAC,CAACC,GAAAA,EAAKC,OAAOC,KAAAA,EAAOC,IAAAA,GAAAA;QACtC,OAAO;AAAIH,YAAAA,GAAAA,GAAAA;AAAKG,YAAAA,IAAAA,CAAKC,KAAK,CAAC,CAAA,EAAGF,KAAAA,GAAQ,CAAA,CAAA,CAAGG,IAAI,CAAC,GAAA;AAAK,SAAA;AACrD,IAAA,CAAA,EAAG,EAAE,CAAA;AACP,CAAA;;;;"}
|