@strapi/utils 5.41.1 → 5.42.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.
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizers.d.ts","sourceRoot":"","sources":["../../src/sanitize/sanitizers.ts"],"names":[],"mappings":";AAsBA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,UAAU,OAAO;IACf,MAAM,EAAE,KAAK,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,QAAA,MAAM,iBAAiB,QAAS,OAAO,cAAoB,IAAI,kBAM9D,CAAC;AAEF,QAAA,MAAM,qBAAqB,QAAe,OAAO,UAAU,IAAI,kBAa9D,CAAC;AAEF,QAAA,MAAM,sBAAsB,uEAmC1B,CAAC;AAEH,QAAA,MAAM,mBAAmB,uEAuCvB,CAAC;AAEH,QAAA,MAAM,qBAAqB,uEAyBzB,CAAC;AAEH,QAAA,MAAM,uBAAuB,uEAiC3B,CAAC;AAEH,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,GACxB,CAAC"}
1
+ {"version":3,"file":"sanitizers.d.ts","sourceRoot":"","sources":["../../src/sanitize/sanitizers.ts"],"names":[],"mappings":";AAsBA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,UAAU,OAAO;IACf,MAAM,EAAE,KAAK,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,QAAA,MAAM,iBAAiB,QAAS,OAAO,cAAoB,IAAI,kBAM9D,CAAC;AAEF,QAAA,MAAM,qBAAqB,QAAe,OAAO,UAAU,IAAI,kBAa9D,CAAC;AAEF,QAAA,MAAM,sBAAsB,uEAsC1B,CAAC;AAEH,QAAA,MAAM,mBAAmB,uEAuCvB,CAAC;AAEH,QAAA,MAAM,qBAAqB,uEAyBzB,CAAC;AAEH,QAAA,MAAM,uBAAuB,uEAiC3B,CAAC;AAEH,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,GACxB,CAAC"}
@@ -54,9 +54,12 @@ const defaultSanitizeFilters = fp.curry((ctx, filters)=>{
54
54
  queryFilters(removeDynamicZones, ctx), // Remove morpTo relations from filters
55
55
  queryFilters(removeMorphToRelations, ctx), // Remove passwords from filters
56
56
  queryFilters(removePassword, ctx), // Remove private from filters
57
- queryFilters(removePrivate, ctx), // Remove empty objects
57
+ queryFilters(removePrivate, ctx), // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no
58
+ // enumerable keys (Date, RegExp, boxed primitives, etc.) are "empty" and would wrongly drop valid operands.
58
59
  queryFilters(({ key, value }, { remove })=>{
59
- if (fp.isObject(value) && fp.isEmpty(value)) {
60
+ const isEmptyPlainObject = fp.isPlainObject(value) && fp.isEmpty(value);
61
+ const isEmptyArrayOperand = fp.isArray(value) && fp.isEmpty(value);
62
+ if (isEmptyPlainObject || isEmptyArrayOperand) {
60
63
  remove(key);
61
64
  }
62
65
  }, ctx))(filters);
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizers.js","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { curry, isEmpty, isNil, isArray, isObject } 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 return traverseEntity(\n (...args) => {\n removePassword(...args);\n removePrivate(...args);\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 objects\n traverseQueryFilters(({ key, value }, { remove }) => {\n if (isObject(value) && isEmpty(value)) {\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","args","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isObject","isEmpty","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","isNil","isArray","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":"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"}
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 return traverseEntity(\n (...args) => {\n removePassword(...args);\n removePrivate(...args);\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","args","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,4 +1,4 @@
1
- import { curry, isObject, isEmpty, isNil, isArray } from 'lodash/fp';
1
+ import { curry, isPlainObject, isEmpty, isArray, isNil } from 'lodash/fp';
2
2
  import { pipe } from '../async.mjs';
3
3
  import traverseEntity from '../traverse-entity.mjs';
4
4
  import { constants, isScalarAttribute } from '../content-types.mjs';
@@ -52,9 +52,12 @@ const defaultSanitizeFilters = curry((ctx, filters)=>{
52
52
  traverseQueryFilters(visitor$3, ctx), // Remove morpTo relations from filters
53
53
  traverseQueryFilters(visitor$2, ctx), // Remove passwords from filters
54
54
  traverseQueryFilters(visitor$1, ctx), // Remove private from filters
55
- traverseQueryFilters(visitor, ctx), // Remove empty objects
55
+ traverseQueryFilters(visitor, ctx), // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no
56
+ // enumerable keys (Date, RegExp, boxed primitives, etc.) are "empty" and would wrongly drop valid operands.
56
57
  traverseQueryFilters(({ key, value }, { remove })=>{
57
- if (isObject(value) && isEmpty(value)) {
58
+ const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);
59
+ const isEmptyArrayOperand = isArray(value) && isEmpty(value);
60
+ if (isEmptyPlainObject || isEmptyArrayOperand) {
58
61
  remove(key);
59
62
  }
60
63
  }, ctx))(filters);
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizers.mjs","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { curry, isEmpty, isNil, isArray, isObject } 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 return traverseEntity(\n (...args) => {\n removePassword(...args);\n removePrivate(...args);\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 objects\n traverseQueryFilters(({ key, value }, { remove }) => {\n if (isObject(value) && isEmpty(value)) {\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","args","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isObject","isEmpty","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","isNil","isArray","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, 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 return traverseEntity(\n (...args) => {\n removePassword(...args);\n removePrivate(...args);\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","args","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 +1 @@
1
- {"version":3,"file":"query-filters.d.ts","sourceRoot":"","sources":["../../src/traverse/query-filters.ts"],"names":[],"mappings":";;AAoHA,wBAAuC"}
1
+ {"version":3,"file":"query-filters.d.ts","sourceRoot":"","sources":["../../src/traverse/query-filters.ts"],"names":[],"mappings":";;AAqJA,wBAAuC"}
@@ -1,9 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var fp = require('lodash/fp');
4
+ var contentTypes = require('../content-types.js');
5
+ var operators = require('../operators.js');
4
6
  var factory = require('./factory.js');
5
7
 
6
8
  const isObj = (value)=>fp.isObject(value);
9
+ /** True if this object should be walked as a filter subtree (operators / attributes), not an opaque operand. */ const isFilterLikeObject = (value, schema)=>Object.keys(value).some((k)=>operators.isOperator(k) || Boolean(schema?.attributes?.[k]));
7
10
  const filters = factory().intercept(// Intercept filters arrays and apply the traversal to each one individually
8
11
  fp.isArray, async (visitor, options, filters, { recurse })=>{
9
12
  return Promise.all(filters.map((filter, i)=>{
@@ -48,6 +51,15 @@ fp.isArray, async (visitor, options, filters, { recurse })=>{
48
51
  schema,
49
52
  attribute
50
53
  };
54
+ // Operator operands that are plain objects (not arrays) are only traversed when they look like
55
+ // filter subtrees (nested operators or schema attributes). Otherwise treat as opaque operands
56
+ // (e.g. GraphQL DateTime / Date for $gt, $null / $notNull booleans, or { $null: { anything } }).
57
+ // Without this, traversing into e.g. { $null: { anything: 'x' } } makes validate throw on "anything".
58
+ // $not is excluded: its value is always a nested filter map, not an opaque scalar operand.
59
+ if (operators.isOperator(key) && key !== '$not' && isObj(value) && !fp.isArray(value) && !isFilterLikeObject(value, schema)) {
60
+ set(key, value);
61
+ return;
62
+ }
51
63
  set(key, await recurse(visitor, {
52
64
  schema,
53
65
  path,
@@ -107,6 +119,20 @@ fp.isArray, async (visitor, options, filters, { recurse })=>{
107
119
  parent
108
120
  }, value);
109
121
  set(key, newValue);
122
+ })// Scalar fields: recurse into operator maps (e.g. { $contains: 'x' }) so visitors see nested keys.
123
+ .onAttribute(({ attribute, value })=>Boolean(contentTypes.isScalarAttribute(attribute)) && isObj(value) && !fp.isArray(value), async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse })=>{
124
+ const parent = {
125
+ key,
126
+ path,
127
+ schema,
128
+ attribute
129
+ };
130
+ set(key, await recurse(visitor, {
131
+ schema,
132
+ path,
133
+ getModel,
134
+ parent
135
+ }, value));
110
136
  });
111
137
  var traverseQueryFilters = fp.curry(filters.traverse);
112
138
 
@@ -1 +1 @@
1
- {"version":3,"file":"query-filters.js","sources":["../../src/traverse/query-filters.ts"],"sourcesContent":["import { curry, isObject, isEmpty, isArray, isNil, cloneDeep, omit } from 'lodash/fp';\n\nimport traverseFactory, { type Parent } from './factory';\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\nconst filters = traverseFactory()\n .intercept(\n // Intercept filters arrays and apply the traversal to each one individually\n isArray,\n async (visitor, options, filters, { recurse }) => {\n return Promise.all(\n filters.map((filter, i) => {\n // In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]\n // can have a value array, thus we can update the raw path but not the attribute one\n const newPath = options.path\n ? { ...options.path, raw: `${options.path.raw}[${i}]` }\n : options.path;\n\n return recurse(visitor, { ...options, path: newPath }, filter);\n })\n // todo: move that to the visitors\n ).then((res) => res.filter((val) => !(isObject(val) && isEmpty(val))));\n }\n )\n .intercept(\n // Ignore non object filters and return the value as-is\n (filters): filters is unknown => !isObject(filters),\n (_, __, filters) => {\n return filters;\n }\n )\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n return omit(key, data);\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n // Ignore null or undefined values\n .ignore(({ value }) => isNil(value))\n // Recursion on operators (non attributes)\n .on(\n ({ attribute }) => isNil(attribute),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n set(key, await recurse(visitor, { schema, path, getModel, parent }, value));\n }\n )\n // Handle relation recursion\n .onRelation(\n async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse }) => {\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n if (isMorphRelation) {\n return;\n }\n\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = attribute.target;\n const targetSchema = getModel(targetSchemaUID!);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n .onComponent(\n async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n const targetSchema = getModel(attribute.component);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n // Handle media recursion\n .onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n });\n\nexport default curry(filters.traverse);\n"],"names":["isObj","value","isObject","filters","traverseFactory","intercept","isArray","visitor","options","recurse","Promise","all","map","filter","i","newPath","path","raw","then","res","val","isEmpty","_","__","parse","transform","cloneDeep","remove","key","data","omit","set","keys","Object","get","ignore","isNil","on","attribute","schema","getModel","parent","onRelation","isMorphRelation","relation","toLowerCase","startsWith","targetSchemaUID","target","targetSchema","newValue","onComponent","component","onMedia","curry","traverse"],"mappings":"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"}
1
+ {"version":3,"file":"query-filters.js","sources":["../../src/traverse/query-filters.ts"],"sourcesContent":["import { curry, isObject, isEmpty, isArray, isNil, cloneDeep, omit } from 'lodash/fp';\n\nimport { isScalarAttribute } from '../content-types';\nimport { isOperator } from '../operators';\nimport traverseFactory, { type Parent } from './factory';\nimport type { Model } from '../types';\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\n/** True if this object should be walked as a filter subtree (operators / attributes), not an opaque operand. */\nconst isFilterLikeObject = (value: Record<string, unknown>, schema?: Model) =>\n Object.keys(value).some((k) => isOperator(k) || Boolean(schema?.attributes?.[k]));\n\nconst filters = traverseFactory()\n .intercept(\n // Intercept filters arrays and apply the traversal to each one individually\n isArray,\n async (visitor, options, filters, { recurse }) => {\n return Promise.all(\n filters.map((filter, i) => {\n // In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]\n // can have a value array, thus we can update the raw path but not the attribute one\n const newPath = options.path\n ? { ...options.path, raw: `${options.path.raw}[${i}]` }\n : options.path;\n\n return recurse(visitor, { ...options, path: newPath }, filter);\n })\n // todo: move that to the visitors\n ).then((res) => res.filter((val) => !(isObject(val) && isEmpty(val))));\n }\n )\n .intercept(\n // Ignore non object filters and return the value as-is\n (filters): filters is unknown => !isObject(filters),\n (_, __, filters) => {\n return filters;\n }\n )\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n return omit(key, data);\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n // Ignore null or undefined values\n .ignore(({ value }) => isNil(value))\n // Recursion on operators (non attributes)\n .on(\n ({ attribute }) => isNil(attribute),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n // Operator operands that are plain objects (not arrays) are only traversed when they look like\n // filter subtrees (nested operators or schema attributes). Otherwise treat as opaque operands\n // (e.g. GraphQL DateTime / Date for $gt, $null / $notNull booleans, or { $null: { anything } }).\n // Without this, traversing into e.g. { $null: { anything: 'x' } } makes validate throw on \"anything\".\n // $not is excluded: its value is always a nested filter map, not an opaque scalar operand.\n if (\n isOperator(key) &&\n key !== '$not' &&\n isObj(value) &&\n !isArray(value) &&\n !isFilterLikeObject(value, schema)\n ) {\n set(key, value);\n return;\n }\n\n set(key, await recurse(visitor, { schema, path, getModel, parent }, value));\n }\n )\n // Handle relation recursion\n .onRelation(\n async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse }) => {\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n if (isMorphRelation) {\n return;\n }\n\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = attribute.target;\n const targetSchema = getModel(targetSchemaUID!);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n .onComponent(\n async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n const targetSchema = getModel(attribute.component);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n // Handle media recursion\n .onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n })\n // Scalar fields: recurse into operator maps (e.g. { $contains: 'x' }) so visitors see nested keys.\n .onAttribute(\n ({ attribute, value }) =>\n Boolean(isScalarAttribute(attribute)) && isObj(value) && !isArray(value),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n set(key, await recurse(visitor, { schema, path, getModel, parent }, value));\n }\n );\n\nexport default curry(filters.traverse);\n"],"names":["isObj","value","isObject","isFilterLikeObject","schema","Object","keys","some","k","isOperator","Boolean","attributes","filters","traverseFactory","intercept","isArray","visitor","options","recurse","Promise","all","map","filter","i","newPath","path","raw","then","res","val","isEmpty","_","__","parse","transform","cloneDeep","remove","key","data","omit","set","get","ignore","isNil","on","attribute","getModel","parent","onRelation","isMorphRelation","relation","toLowerCase","startsWith","targetSchemaUID","target","targetSchema","newValue","onComponent","component","onMedia","onAttribute","isScalarAttribute","curry","traverse"],"mappings":"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"}
@@ -1,7 +1,10 @@
1
1
  import { isArray, isObject, isEmpty, cloneDeep, omit, isNil, curry } from 'lodash/fp';
2
+ import { isScalarAttribute } from '../content-types.mjs';
3
+ import { isOperator } from '../operators.mjs';
2
4
  import traverseFactory from './factory.mjs';
3
5
 
4
6
  const isObj = (value)=>isObject(value);
7
+ /** True if this object should be walked as a filter subtree (operators / attributes), not an opaque operand. */ const isFilterLikeObject = (value, schema)=>Object.keys(value).some((k)=>isOperator(k) || Boolean(schema?.attributes?.[k]));
5
8
  const filters = traverseFactory().intercept(// Intercept filters arrays and apply the traversal to each one individually
6
9
  isArray, async (visitor, options, filters, { recurse })=>{
7
10
  return Promise.all(filters.map((filter, i)=>{
@@ -46,6 +49,15 @@ isArray, async (visitor, options, filters, { recurse })=>{
46
49
  schema,
47
50
  attribute
48
51
  };
52
+ // Operator operands that are plain objects (not arrays) are only traversed when they look like
53
+ // filter subtrees (nested operators or schema attributes). Otherwise treat as opaque operands
54
+ // (e.g. GraphQL DateTime / Date for $gt, $null / $notNull booleans, or { $null: { anything } }).
55
+ // Without this, traversing into e.g. { $null: { anything: 'x' } } makes validate throw on "anything".
56
+ // $not is excluded: its value is always a nested filter map, not an opaque scalar operand.
57
+ if (isOperator(key) && key !== '$not' && isObj(value) && !isArray(value) && !isFilterLikeObject(value, schema)) {
58
+ set(key, value);
59
+ return;
60
+ }
49
61
  set(key, await recurse(visitor, {
50
62
  schema,
51
63
  path,
@@ -105,6 +117,20 @@ isArray, async (visitor, options, filters, { recurse })=>{
105
117
  parent
106
118
  }, value);
107
119
  set(key, newValue);
120
+ })// Scalar fields: recurse into operator maps (e.g. { $contains: 'x' }) so visitors see nested keys.
121
+ .onAttribute(({ attribute, value })=>Boolean(isScalarAttribute(attribute)) && isObj(value) && !isArray(value), async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse })=>{
122
+ const parent = {
123
+ key,
124
+ path,
125
+ schema,
126
+ attribute
127
+ };
128
+ set(key, await recurse(visitor, {
129
+ schema,
130
+ path,
131
+ getModel,
132
+ parent
133
+ }, value));
108
134
  });
109
135
  var traverseQueryFilters = curry(filters.traverse);
110
136
 
@@ -1 +1 @@
1
- {"version":3,"file":"query-filters.mjs","sources":["../../src/traverse/query-filters.ts"],"sourcesContent":["import { curry, isObject, isEmpty, isArray, isNil, cloneDeep, omit } from 'lodash/fp';\n\nimport traverseFactory, { type Parent } from './factory';\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\nconst filters = traverseFactory()\n .intercept(\n // Intercept filters arrays and apply the traversal to each one individually\n isArray,\n async (visitor, options, filters, { recurse }) => {\n return Promise.all(\n filters.map((filter, i) => {\n // In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]\n // can have a value array, thus we can update the raw path but not the attribute one\n const newPath = options.path\n ? { ...options.path, raw: `${options.path.raw}[${i}]` }\n : options.path;\n\n return recurse(visitor, { ...options, path: newPath }, filter);\n })\n // todo: move that to the visitors\n ).then((res) => res.filter((val) => !(isObject(val) && isEmpty(val))));\n }\n )\n .intercept(\n // Ignore non object filters and return the value as-is\n (filters): filters is unknown => !isObject(filters),\n (_, __, filters) => {\n return filters;\n }\n )\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n return omit(key, data);\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n // Ignore null or undefined values\n .ignore(({ value }) => isNil(value))\n // Recursion on operators (non attributes)\n .on(\n ({ attribute }) => isNil(attribute),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n set(key, await recurse(visitor, { schema, path, getModel, parent }, value));\n }\n )\n // Handle relation recursion\n .onRelation(\n async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse }) => {\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n if (isMorphRelation) {\n return;\n }\n\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = attribute.target;\n const targetSchema = getModel(targetSchemaUID!);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n .onComponent(\n async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n const targetSchema = getModel(attribute.component);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n // Handle media recursion\n .onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n });\n\nexport default curry(filters.traverse);\n"],"names":["isObj","value","isObject","filters","traverseFactory","intercept","isArray","visitor","options","recurse","Promise","all","map","filter","i","newPath","path","raw","then","res","val","isEmpty","_","__","parse","transform","cloneDeep","remove","key","data","omit","set","keys","Object","get","ignore","isNil","on","attribute","schema","getModel","parent","onRelation","isMorphRelation","relation","toLowerCase","startsWith","targetSchemaUID","target","targetSchema","newValue","onComponent","component","onMedia","curry","traverse"],"mappings":"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"}
1
+ {"version":3,"file":"query-filters.mjs","sources":["../../src/traverse/query-filters.ts"],"sourcesContent":["import { curry, isObject, isEmpty, isArray, isNil, cloneDeep, omit } from 'lodash/fp';\n\nimport { isScalarAttribute } from '../content-types';\nimport { isOperator } from '../operators';\nimport traverseFactory, { type Parent } from './factory';\nimport type { Model } from '../types';\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\n/** True if this object should be walked as a filter subtree (operators / attributes), not an opaque operand. */\nconst isFilterLikeObject = (value: Record<string, unknown>, schema?: Model) =>\n Object.keys(value).some((k) => isOperator(k) || Boolean(schema?.attributes?.[k]));\n\nconst filters = traverseFactory()\n .intercept(\n // Intercept filters arrays and apply the traversal to each one individually\n isArray,\n async (visitor, options, filters, { recurse }) => {\n return Promise.all(\n filters.map((filter, i) => {\n // In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]\n // can have a value array, thus we can update the raw path but not the attribute one\n const newPath = options.path\n ? { ...options.path, raw: `${options.path.raw}[${i}]` }\n : options.path;\n\n return recurse(visitor, { ...options, path: newPath }, filter);\n })\n // todo: move that to the visitors\n ).then((res) => res.filter((val) => !(isObject(val) && isEmpty(val))));\n }\n )\n .intercept(\n // Ignore non object filters and return the value as-is\n (filters): filters is unknown => !isObject(filters),\n (_, __, filters) => {\n return filters;\n }\n )\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n return omit(key, data);\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n // Ignore null or undefined values\n .ignore(({ value }) => isNil(value))\n // Recursion on operators (non attributes)\n .on(\n ({ attribute }) => isNil(attribute),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n // Operator operands that are plain objects (not arrays) are only traversed when they look like\n // filter subtrees (nested operators or schema attributes). Otherwise treat as opaque operands\n // (e.g. GraphQL DateTime / Date for $gt, $null / $notNull booleans, or { $null: { anything } }).\n // Without this, traversing into e.g. { $null: { anything: 'x' } } makes validate throw on \"anything\".\n // $not is excluded: its value is always a nested filter map, not an opaque scalar operand.\n if (\n isOperator(key) &&\n key !== '$not' &&\n isObj(value) &&\n !isArray(value) &&\n !isFilterLikeObject(value, schema)\n ) {\n set(key, value);\n return;\n }\n\n set(key, await recurse(visitor, { schema, path, getModel, parent }, value));\n }\n )\n // Handle relation recursion\n .onRelation(\n async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse }) => {\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n if (isMorphRelation) {\n return;\n }\n\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = attribute.target;\n const targetSchema = getModel(targetSchemaUID!);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n .onComponent(\n async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n const targetSchema = getModel(attribute.component);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n // Handle media recursion\n .onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n })\n // Scalar fields: recurse into operator maps (e.g. { $contains: 'x' }) so visitors see nested keys.\n .onAttribute(\n ({ attribute, value }) =>\n Boolean(isScalarAttribute(attribute)) && isObj(value) && !isArray(value),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n set(key, await recurse(visitor, { schema, path, getModel, parent }, value));\n }\n );\n\nexport default curry(filters.traverse);\n"],"names":["isObj","value","isObject","isFilterLikeObject","schema","Object","keys","some","k","isOperator","Boolean","attributes","filters","traverseFactory","intercept","isArray","visitor","options","recurse","Promise","all","map","filter","i","newPath","path","raw","then","res","val","isEmpty","_","__","parse","transform","cloneDeep","remove","key","data","omit","set","get","ignore","isNil","on","attribute","getModel","parent","onRelation","isMorphRelation","relation","toLowerCase","startsWith","targetSchemaUID","target","targetSchema","newValue","onComponent","component","onMedia","onAttribute","isScalarAttribute","curry","traverse"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/utils",
3
- "version": "5.41.1",
3
+ "version": "5.42.0",
4
4
  "description": "Shared utilities for the Strapi packages",
5
5
  "keywords": [
6
6
  "strapi",
@@ -62,10 +62,10 @@
62
62
  "@types/http-errors": "2.0.4",
63
63
  "@types/koa": "2.13.4",
64
64
  "@types/node": "24.10.0",
65
- "eslint-config-custom": "5.41.1",
65
+ "eslint-config-custom": "5.42.0",
66
66
  "koa": "2.16.4",
67
67
  "koa-body": "6.0.1",
68
- "tsconfig": "5.41.1"
68
+ "tsconfig": "5.42.0"
69
69
  },
70
70
  "engines": {
71
71
  "node": ">=20.0.0 <=24.x.x",