@strapi/utils 5.23.1 → 5.23.2

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/index.d.ts CHANGED
@@ -24,6 +24,7 @@ export * as relations from './relations';
24
24
  export * as hooks from './hooks';
25
25
  export * from './zod';
26
26
  export * from './validation';
27
+ export * from './route-serialization';
27
28
  export * from './primitives';
28
29
  export * from './content-api-router';
29
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,KAAK,WAAW,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,cAAc,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,YAAY,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAE7B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,KAAK,WAAW,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,cAAc,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,YAAY,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AAEtC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ var zod = require('./zod.js');
28
28
  var base = require('./validation/route-validators/base.js');
29
29
  var queryParams = require('./validation/route-validators/query-params.js');
30
30
  var utilities = require('./validation/utilities.js');
31
+ var routeSerialization = require('./route-serialization.js');
31
32
  var strings = require('./primitives/strings.js');
32
33
  var arrays = require('./primitives/arrays.js');
33
34
  var objects = require('./primitives/objects.js');
@@ -79,6 +80,9 @@ exports.maybeRequired = utilities.maybeRequired;
79
80
  exports.maybeWithDefault = utilities.maybeWithDefault;
80
81
  exports.maybeWithMinMax = utilities.maybeWithMinMax;
81
82
  exports.transformUidToValidOpenApiName = utilities.transformUidToValidOpenApiName;
83
+ exports.sanitizeRouteForSerialization = routeSerialization.sanitizeRouteForSerialization;
84
+ exports.sanitizeRoutesArrayForSerialization = routeSerialization.sanitizeRoutesArrayForSerialization;
85
+ exports.sanitizeRoutesMapForSerialization = routeSerialization.sanitizeRoutesMapForSerialization;
82
86
  exports.strings = strings;
83
87
  exports.arrays = arrays;
84
88
  exports.objects = objects;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.mjs CHANGED
@@ -41,6 +41,7 @@ export { validateZod } from './zod.mjs';
41
41
  export { AbstractRouteValidator } from './validation/route-validators/base.mjs';
42
42
  export { filtersSchema, localeSchema, paginationSchema, queryFieldsSchema, queryParameterSchemas, queryPopulateSchema, querySortSchema, searchQuerySchema, statusSchema } from './validation/route-validators/query-params.mjs';
43
43
  export { augmentSchema, maybeReadonly, maybeRequired, maybeWithDefault, maybeWithMinMax, transformUidToValidOpenApiName } from './validation/utilities.mjs';
44
+ export { sanitizeRouteForSerialization, sanitizeRoutesArrayForSerialization, sanitizeRoutesMapForSerialization } from './route-serialization.mjs';
44
45
  import * as strings from './primitives/strings.mjs';
45
46
  export { strings };
46
47
  import * as arrays from './primitives/arrays.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,4 @@
1
+ export declare const sanitizeRouteForSerialization: ({ request, response, ...rest }: Record<string, unknown>) => Record<string, unknown>;
2
+ export declare const sanitizeRoutesArrayForSerialization: (routes: unknown[]) => Record<string, unknown>[];
3
+ export declare const sanitizeRoutesMapForSerialization: (map: Record<string, unknown[]>) => Record<string, unknown>;
4
+ //# sourceMappingURL=route-serialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-serialization.d.ts","sourceRoot":"","sources":["../src/route-serialization.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,6BAA6B,mCAIvC,OAAO,MAAM,EAAE,OAAO,CAAC,4BAAoC,CAAC;AAE/D,eAAO,MAAM,mCAAmC,WAAY,OAAO,EAAE,KAAG,OAAO,MAAM,EAAE,OAAO,CAAC,EAGxD,CAAC;AAExC,eAAO,MAAM,iCAAiC,QACvC,OAAO,MAAM,EAAE,OAAO,EAAE,CAAC,KAC7B,OAAO,MAAM,EAAE,OAAO,CAOtB,CAAC"}
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ /*
4
+ * Utility to sanitize content API route objects for safe JSON serialization.
5
+ * Removes Zod validation fields (request/response) for safe serialization.
6
+ *
7
+ * NOTE: some content API routes are returned to the admin panel e.g. to
8
+ * populate the users and permissions roles page. We need to ensure that the
9
+ * routes can be serialized to JSON without errors.
10
+ */ const sanitizeRouteForSerialization = ({ request, response, ...rest })=>rest;
11
+ const sanitizeRoutesArrayForSerialization = (routes)=>routes.filter((route)=>!!route && typeof route === 'object').map(sanitizeRouteForSerialization);
12
+ const sanitizeRoutesMapForSerialization = (map)=>Object.entries(map).reduce((acc, [key, value])=>({
13
+ ...acc,
14
+ [key]: Array.isArray(value) ? sanitizeRoutesArrayForSerialization(value) : value
15
+ }), {});
16
+
17
+ exports.sanitizeRouteForSerialization = sanitizeRouteForSerialization;
18
+ exports.sanitizeRoutesArrayForSerialization = sanitizeRoutesArrayForSerialization;
19
+ exports.sanitizeRoutesMapForSerialization = sanitizeRoutesMapForSerialization;
20
+ //# sourceMappingURL=route-serialization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-serialization.js","sources":["../src/route-serialization.ts"],"sourcesContent":["/*\n * Utility to sanitize content API route objects for safe JSON serialization.\n * Removes Zod validation fields (request/response) for safe serialization.\n *\n * NOTE: some content API routes are returned to the admin panel e.g. to\n * populate the users and permissions roles page. We need to ensure that the\n * routes can be serialized to JSON without errors.\n */\n\nexport const sanitizeRouteForSerialization = ({\n request,\n response,\n ...rest\n}: Record<string, unknown>) => rest as Record<string, unknown>;\n\nexport const sanitizeRoutesArrayForSerialization = (routes: unknown[]): Record<string, unknown>[] =>\n routes\n .filter((route): route is Record<string, unknown> => !!route && typeof route === 'object')\n .map(sanitizeRouteForSerialization);\n\nexport const sanitizeRoutesMapForSerialization = (\n map: Record<string, unknown[]>\n): Record<string, unknown> =>\n Object.entries(map).reduce(\n (acc, [key, value]) => ({\n ...acc,\n [key]: Array.isArray(value) ? sanitizeRoutesArrayForSerialization(value) : value,\n }),\n {}\n );\n"],"names":["sanitizeRouteForSerialization","request","response","rest","sanitizeRoutesArrayForSerialization","routes","filter","route","map","sanitizeRoutesMapForSerialization","Object","entries","reduce","acc","key","value","Array","isArray"],"mappings":";;AAAA;;;;;;;AAOC,IAEM,MAAMA,6BAAgC,GAAA,CAAC,EAC5CC,OAAO,EACPC,QAAQ,EACR,GAAGC,IACqB,EAAA,GAAKA;MAElBC,mCAAsC,GAAA,CAACC,MAClDA,GAAAA,MAAAA,CACGC,MAAM,CAAC,CAACC,KAA4C,GAAA,CAAC,CAACA,KAAS,IAAA,OAAOA,UAAU,QAChFC,CAAAA,CAAAA,GAAG,CAACR,6BAA+B;MAE3BS,iCAAoC,GAAA,CAC/CD,GAEAE,GAAAA,MAAAA,CAAOC,OAAO,CAACH,GAAAA,CAAAA,CAAKI,MAAM,CACxB,CAACC,GAAK,EAAA,CAACC,GAAKC,EAAAA,KAAAA,CAAM,IAAM;AACtB,YAAA,GAAGF,GAAG;AACN,YAAA,CAACC,MAAME,KAAAA,CAAMC,OAAO,CAACF,KAAAA,CAAAA,GAASX,oCAAoCW,KAASA,CAAAA,GAAAA;SAC7E,CAAA,EACA,EACA;;;;;;"}
@@ -0,0 +1,16 @@
1
+ /*
2
+ * Utility to sanitize content API route objects for safe JSON serialization.
3
+ * Removes Zod validation fields (request/response) for safe serialization.
4
+ *
5
+ * NOTE: some content API routes are returned to the admin panel e.g. to
6
+ * populate the users and permissions roles page. We need to ensure that the
7
+ * routes can be serialized to JSON without errors.
8
+ */ const sanitizeRouteForSerialization = ({ request, response, ...rest })=>rest;
9
+ const sanitizeRoutesArrayForSerialization = (routes)=>routes.filter((route)=>!!route && typeof route === 'object').map(sanitizeRouteForSerialization);
10
+ const sanitizeRoutesMapForSerialization = (map)=>Object.entries(map).reduce((acc, [key, value])=>({
11
+ ...acc,
12
+ [key]: Array.isArray(value) ? sanitizeRoutesArrayForSerialization(value) : value
13
+ }), {});
14
+
15
+ export { sanitizeRouteForSerialization, sanitizeRoutesArrayForSerialization, sanitizeRoutesMapForSerialization };
16
+ //# sourceMappingURL=route-serialization.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-serialization.mjs","sources":["../src/route-serialization.ts"],"sourcesContent":["/*\n * Utility to sanitize content API route objects for safe JSON serialization.\n * Removes Zod validation fields (request/response) for safe serialization.\n *\n * NOTE: some content API routes are returned to the admin panel e.g. to\n * populate the users and permissions roles page. We need to ensure that the\n * routes can be serialized to JSON without errors.\n */\n\nexport const sanitizeRouteForSerialization = ({\n request,\n response,\n ...rest\n}: Record<string, unknown>) => rest as Record<string, unknown>;\n\nexport const sanitizeRoutesArrayForSerialization = (routes: unknown[]): Record<string, unknown>[] =>\n routes\n .filter((route): route is Record<string, unknown> => !!route && typeof route === 'object')\n .map(sanitizeRouteForSerialization);\n\nexport const sanitizeRoutesMapForSerialization = (\n map: Record<string, unknown[]>\n): Record<string, unknown> =>\n Object.entries(map).reduce(\n (acc, [key, value]) => ({\n ...acc,\n [key]: Array.isArray(value) ? sanitizeRoutesArrayForSerialization(value) : value,\n }),\n {}\n );\n"],"names":["sanitizeRouteForSerialization","request","response","rest","sanitizeRoutesArrayForSerialization","routes","filter","route","map","sanitizeRoutesMapForSerialization","Object","entries","reduce","acc","key","value","Array","isArray"],"mappings":"AAAA;;;;;;;AAOC,IAEM,MAAMA,6BAAgC,GAAA,CAAC,EAC5CC,OAAO,EACPC,QAAQ,EACR,GAAGC,IACqB,EAAA,GAAKA;MAElBC,mCAAsC,GAAA,CAACC,MAClDA,GAAAA,MAAAA,CACGC,MAAM,CAAC,CAACC,KAA4C,GAAA,CAAC,CAACA,KAAS,IAAA,OAAOA,UAAU,QAChFC,CAAAA,CAAAA,GAAG,CAACR,6BAA+B;MAE3BS,iCAAoC,GAAA,CAC/CD,GAEAE,GAAAA,MAAAA,CAAOC,OAAO,CAACH,GAAAA,CAAAA,CAAKI,MAAM,CACxB,CAACC,GAAK,EAAA,CAACC,GAAKC,EAAAA,KAAAA,CAAM,IAAM;AACtB,YAAA,GAAGF,GAAG;AACN,YAAA,CAACC,MAAME,KAAAA,CAAMC,OAAO,CAACF,KAAAA,CAAAA,GAASX,oCAAoCW,KAASA,CAAAA,GAAAA;SAC7E,CAAA,EACA,EACA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"remove-restricted-relations.d.ts","sourceRoot":"","sources":["../../../src/sanitize/visitors/remove-restricted-relations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;+BAShC,OAAO,KAAG,OAAO;AAAvC,wBAsHI"}
1
+ {"version":3,"file":"remove-restricted-relations.d.ts","sourceRoot":"","sources":["../../../src/sanitize/visitors/remove-restricted-relations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;+BAShC,OAAO,KAAG,OAAO;AAAvC,wBA0HI"}
@@ -18,6 +18,9 @@ var removeRestrictedRelations = ((auth)=>async ({ data, key, attribute, schema }
18
18
  }
19
19
  const handleMorphRelation = async ()=>{
20
20
  const elements = data[key];
21
+ if (!elements) {
22
+ return;
23
+ }
21
24
  if ('connect' in elements || 'set' in elements || 'disconnect' in elements) {
22
25
  const newValue = {};
23
26
  const connect = await handleMorphElements(elements.connect || []);
@@ -1 +1 @@
1
- {"version":3,"file":"remove-restricted-relations.js","sources":["../../../src/sanitize/visitors/remove-restricted-relations.ts"],"sourcesContent":["import { isArray, isObject } from 'lodash/fp';\nimport * as contentTypeUtils from '../../content-types';\nimport type { Visitor } from '../../traverse/factory';\nimport { RelationOrderingOptions } from '../../types';\nimport { VALID_RELATION_ORDERING_KEYS } from '../../relations';\n\nconst ACTIONS_TO_VERIFY = ['find'];\nconst { CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE } = contentTypeUtils.constants;\n\ntype MorphArray = Array<{ __type: string }>;\n\nexport default (auth: unknown): Visitor =>\n async ({ data, key, attribute, schema }, { remove, set }) => {\n if (!attribute) {\n return;\n }\n\n const isRelation = attribute.type === 'relation';\n\n if (!isRelation) {\n return;\n }\n\n const handleMorphRelation = async () => {\n const elements: any = (data as Record<string, MorphArray>)[key];\n\n if ('connect' in elements || 'set' in elements || 'disconnect' in elements) {\n const newValue: Record<string, unknown> = {};\n\n const connect = await handleMorphElements(elements.connect || []);\n const relSet = await handleMorphElements(elements.set || []);\n const disconnect = await handleMorphElements(elements.disconnect || []);\n\n if (connect.length > 0) {\n newValue.connect = connect;\n }\n\n if (relSet.length > 0) {\n newValue.set = relSet;\n }\n\n if (disconnect.length > 0) {\n newValue.disconnect = disconnect;\n }\n\n // TODO: this should technically be in its own visitor to check morph options, but for now we'll handle it here\n if (\n 'options' in elements &&\n typeof elements.options === 'object' &&\n elements.options !== null\n ) {\n const filteredOptions: RelationOrderingOptions = {};\n\n // Iterate through the keys of elements.options\n Object.keys(elements.options).forEach((key) => {\n const validator = VALID_RELATION_ORDERING_KEYS[key as keyof RelationOrderingOptions];\n\n // Ensure the key exists in VALID_RELATION_ORDERING_KEYS and the validator is defined before calling it\n if (validator && validator(elements.options[key])) {\n filteredOptions[key as keyof RelationOrderingOptions] = elements.options[key];\n }\n });\n\n // Assign the filtered options back to newValue\n newValue.options = filteredOptions;\n } else {\n newValue.options = {};\n }\n\n set(key, newValue);\n } else {\n const newMorphValue = await handleMorphElements(elements);\n\n if (newMorphValue.length) {\n set(key, newMorphValue);\n }\n }\n };\n\n const handleMorphElements = async (elements: any[]) => {\n const allowedElements: Record<string, unknown>[] = [];\n\n if (!isArray(elements)) {\n return allowedElements;\n }\n\n for (const element of elements) {\n if (!isObject(element) || !('__type' in element)) {\n continue;\n }\n\n const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);\n const isAllowed = await hasAccessToSomeScopes(scopes, auth);\n\n if (isAllowed) {\n allowedElements.push(element);\n }\n }\n\n return allowedElements;\n };\n\n const handleRegularRelation = async () => {\n const scopes = ACTIONS_TO_VERIFY.map((action) => `${attribute.target}.${action}`);\n\n const isAllowed = await hasAccessToSomeScopes(scopes, auth);\n\n // If the authenticated user don't have access to any of the scopes, then remove the field\n if (!isAllowed) {\n remove(key);\n }\n };\n\n const isCreatorRelation = [CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE].includes(key);\n\n // Polymorphic relations\n if (contentTypeUtils.isMorphToRelationalAttribute(attribute)) {\n await handleMorphRelation();\n return;\n }\n\n // Creator relations\n if (isCreatorRelation && schema.options?.populateCreatorFields) {\n // do nothing\n return;\n }\n\n // Regular relations\n await handleRegularRelation();\n };\n\nconst hasAccessToSomeScopes = async (scopes: string[], auth: unknown) => {\n for (const scope of scopes) {\n try {\n await strapi.auth.verify(auth, { scope });\n return true;\n } catch {\n continue;\n }\n }\n\n return false;\n};\n"],"names":["ACTIONS_TO_VERIFY","CREATED_BY_ATTRIBUTE","UPDATED_BY_ATTRIBUTE","contentTypeUtils","auth","data","key","attribute","schema","remove","set","isRelation","type","handleMorphRelation","elements","newValue","connect","handleMorphElements","relSet","disconnect","length","options","filteredOptions","Object","keys","forEach","validator","VALID_RELATION_ORDERING_KEYS","newMorphValue","allowedElements","isArray","element","isObject","scopes","map","action","__type","isAllowed","hasAccessToSomeScopes","push","handleRegularRelation","target","isCreatorRelation","includes","populateCreatorFields","scope","strapi","verify"],"mappings":"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"}
1
+ {"version":3,"file":"remove-restricted-relations.js","sources":["../../../src/sanitize/visitors/remove-restricted-relations.ts"],"sourcesContent":["import { isArray, isObject } from 'lodash/fp';\nimport * as contentTypeUtils from '../../content-types';\nimport type { Visitor } from '../../traverse/factory';\nimport { RelationOrderingOptions } from '../../types';\nimport { VALID_RELATION_ORDERING_KEYS } from '../../relations';\n\nconst ACTIONS_TO_VERIFY = ['find'];\nconst { CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE } = contentTypeUtils.constants;\n\ntype MorphArray = Array<{ __type: string }>;\n\nexport default (auth: unknown): Visitor =>\n async ({ data, key, attribute, schema }, { remove, set }) => {\n if (!attribute) {\n return;\n }\n\n const isRelation = attribute.type === 'relation';\n\n if (!isRelation) {\n return;\n }\n\n const handleMorphRelation = async () => {\n const elements: any = (data as Record<string, MorphArray>)[key];\n\n if (!elements) {\n return;\n }\n\n if ('connect' in elements || 'set' in elements || 'disconnect' in elements) {\n const newValue: Record<string, unknown> = {};\n\n const connect = await handleMorphElements(elements.connect || []);\n const relSet = await handleMorphElements(elements.set || []);\n const disconnect = await handleMorphElements(elements.disconnect || []);\n\n if (connect.length > 0) {\n newValue.connect = connect;\n }\n\n if (relSet.length > 0) {\n newValue.set = relSet;\n }\n\n if (disconnect.length > 0) {\n newValue.disconnect = disconnect;\n }\n\n // TODO: this should technically be in its own visitor to check morph options, but for now we'll handle it here\n if (\n 'options' in elements &&\n typeof elements.options === 'object' &&\n elements.options !== null\n ) {\n const filteredOptions: RelationOrderingOptions = {};\n\n // Iterate through the keys of elements.options\n Object.keys(elements.options).forEach((key) => {\n const validator = VALID_RELATION_ORDERING_KEYS[key as keyof RelationOrderingOptions];\n\n // Ensure the key exists in VALID_RELATION_ORDERING_KEYS and the validator is defined before calling it\n if (validator && validator(elements.options[key])) {\n filteredOptions[key as keyof RelationOrderingOptions] = elements.options[key];\n }\n });\n\n // Assign the filtered options back to newValue\n newValue.options = filteredOptions;\n } else {\n newValue.options = {};\n }\n\n set(key, newValue);\n } else {\n const newMorphValue = await handleMorphElements(elements);\n\n if (newMorphValue.length) {\n set(key, newMorphValue);\n }\n }\n };\n\n const handleMorphElements = async (elements: any[]) => {\n const allowedElements: Record<string, unknown>[] = [];\n\n if (!isArray(elements)) {\n return allowedElements;\n }\n\n for (const element of elements) {\n if (!isObject(element) || !('__type' in element)) {\n continue;\n }\n\n const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);\n const isAllowed = await hasAccessToSomeScopes(scopes, auth);\n\n if (isAllowed) {\n allowedElements.push(element);\n }\n }\n\n return allowedElements;\n };\n\n const handleRegularRelation = async () => {\n const scopes = ACTIONS_TO_VERIFY.map((action) => `${attribute.target}.${action}`);\n\n const isAllowed = await hasAccessToSomeScopes(scopes, auth);\n\n // If the authenticated user don't have access to any of the scopes, then remove the field\n if (!isAllowed) {\n remove(key);\n }\n };\n\n const isCreatorRelation = [CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE].includes(key);\n\n // Polymorphic relations\n if (contentTypeUtils.isMorphToRelationalAttribute(attribute)) {\n await handleMorphRelation();\n return;\n }\n\n // Creator relations\n if (isCreatorRelation && schema.options?.populateCreatorFields) {\n // do nothing\n return;\n }\n\n // Regular relations\n await handleRegularRelation();\n };\n\nconst hasAccessToSomeScopes = async (scopes: string[], auth: unknown) => {\n for (const scope of scopes) {\n try {\n await strapi.auth.verify(auth, { scope });\n return true;\n } catch {\n continue;\n }\n }\n\n return false;\n};\n"],"names":["ACTIONS_TO_VERIFY","CREATED_BY_ATTRIBUTE","UPDATED_BY_ATTRIBUTE","contentTypeUtils","auth","data","key","attribute","schema","remove","set","isRelation","type","handleMorphRelation","elements","newValue","connect","handleMorphElements","relSet","disconnect","length","options","filteredOptions","Object","keys","forEach","validator","VALID_RELATION_ORDERING_KEYS","newMorphValue","allowedElements","isArray","element","isObject","scopes","map","action","__type","isAllowed","hasAccessToSomeScopes","push","handleRegularRelation","target","isCreatorRelation","includes","populateCreatorFields","scope","strapi","verify"],"mappings":"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"}
@@ -16,6 +16,9 @@ var removeRestrictedRelations = ((auth)=>async ({ data, key, attribute, schema }
16
16
  }
17
17
  const handleMorphRelation = async ()=>{
18
18
  const elements = data[key];
19
+ if (!elements) {
20
+ return;
21
+ }
19
22
  if ('connect' in elements || 'set' in elements || 'disconnect' in elements) {
20
23
  const newValue = {};
21
24
  const connect = await handleMorphElements(elements.connect || []);
@@ -1 +1 @@
1
- {"version":3,"file":"remove-restricted-relations.mjs","sources":["../../../src/sanitize/visitors/remove-restricted-relations.ts"],"sourcesContent":["import { isArray, isObject } from 'lodash/fp';\nimport * as contentTypeUtils from '../../content-types';\nimport type { Visitor } from '../../traverse/factory';\nimport { RelationOrderingOptions } from '../../types';\nimport { VALID_RELATION_ORDERING_KEYS } from '../../relations';\n\nconst ACTIONS_TO_VERIFY = ['find'];\nconst { CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE } = contentTypeUtils.constants;\n\ntype MorphArray = Array<{ __type: string }>;\n\nexport default (auth: unknown): Visitor =>\n async ({ data, key, attribute, schema }, { remove, set }) => {\n if (!attribute) {\n return;\n }\n\n const isRelation = attribute.type === 'relation';\n\n if (!isRelation) {\n return;\n }\n\n const handleMorphRelation = async () => {\n const elements: any = (data as Record<string, MorphArray>)[key];\n\n if ('connect' in elements || 'set' in elements || 'disconnect' in elements) {\n const newValue: Record<string, unknown> = {};\n\n const connect = await handleMorphElements(elements.connect || []);\n const relSet = await handleMorphElements(elements.set || []);\n const disconnect = await handleMorphElements(elements.disconnect || []);\n\n if (connect.length > 0) {\n newValue.connect = connect;\n }\n\n if (relSet.length > 0) {\n newValue.set = relSet;\n }\n\n if (disconnect.length > 0) {\n newValue.disconnect = disconnect;\n }\n\n // TODO: this should technically be in its own visitor to check morph options, but for now we'll handle it here\n if (\n 'options' in elements &&\n typeof elements.options === 'object' &&\n elements.options !== null\n ) {\n const filteredOptions: RelationOrderingOptions = {};\n\n // Iterate through the keys of elements.options\n Object.keys(elements.options).forEach((key) => {\n const validator = VALID_RELATION_ORDERING_KEYS[key as keyof RelationOrderingOptions];\n\n // Ensure the key exists in VALID_RELATION_ORDERING_KEYS and the validator is defined before calling it\n if (validator && validator(elements.options[key])) {\n filteredOptions[key as keyof RelationOrderingOptions] = elements.options[key];\n }\n });\n\n // Assign the filtered options back to newValue\n newValue.options = filteredOptions;\n } else {\n newValue.options = {};\n }\n\n set(key, newValue);\n } else {\n const newMorphValue = await handleMorphElements(elements);\n\n if (newMorphValue.length) {\n set(key, newMorphValue);\n }\n }\n };\n\n const handleMorphElements = async (elements: any[]) => {\n const allowedElements: Record<string, unknown>[] = [];\n\n if (!isArray(elements)) {\n return allowedElements;\n }\n\n for (const element of elements) {\n if (!isObject(element) || !('__type' in element)) {\n continue;\n }\n\n const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);\n const isAllowed = await hasAccessToSomeScopes(scopes, auth);\n\n if (isAllowed) {\n allowedElements.push(element);\n }\n }\n\n return allowedElements;\n };\n\n const handleRegularRelation = async () => {\n const scopes = ACTIONS_TO_VERIFY.map((action) => `${attribute.target}.${action}`);\n\n const isAllowed = await hasAccessToSomeScopes(scopes, auth);\n\n // If the authenticated user don't have access to any of the scopes, then remove the field\n if (!isAllowed) {\n remove(key);\n }\n };\n\n const isCreatorRelation = [CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE].includes(key);\n\n // Polymorphic relations\n if (contentTypeUtils.isMorphToRelationalAttribute(attribute)) {\n await handleMorphRelation();\n return;\n }\n\n // Creator relations\n if (isCreatorRelation && schema.options?.populateCreatorFields) {\n // do nothing\n return;\n }\n\n // Regular relations\n await handleRegularRelation();\n };\n\nconst hasAccessToSomeScopes = async (scopes: string[], auth: unknown) => {\n for (const scope of scopes) {\n try {\n await strapi.auth.verify(auth, { scope });\n return true;\n } catch {\n continue;\n }\n }\n\n return false;\n};\n"],"names":["ACTIONS_TO_VERIFY","CREATED_BY_ATTRIBUTE","UPDATED_BY_ATTRIBUTE","contentTypeUtils","auth","data","key","attribute","schema","remove","set","isRelation","type","handleMorphRelation","elements","newValue","connect","handleMorphElements","relSet","disconnect","length","options","filteredOptions","Object","keys","forEach","validator","VALID_RELATION_ORDERING_KEYS","newMorphValue","allowedElements","isArray","element","isObject","scopes","map","action","__type","isAllowed","hasAccessToSomeScopes","push","handleRegularRelation","target","isCreatorRelation","includes","populateCreatorFields","scope","strapi","verify"],"mappings":"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"}
1
+ {"version":3,"file":"remove-restricted-relations.mjs","sources":["../../../src/sanitize/visitors/remove-restricted-relations.ts"],"sourcesContent":["import { isArray, isObject } from 'lodash/fp';\nimport * as contentTypeUtils from '../../content-types';\nimport type { Visitor } from '../../traverse/factory';\nimport { RelationOrderingOptions } from '../../types';\nimport { VALID_RELATION_ORDERING_KEYS } from '../../relations';\n\nconst ACTIONS_TO_VERIFY = ['find'];\nconst { CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE } = contentTypeUtils.constants;\n\ntype MorphArray = Array<{ __type: string }>;\n\nexport default (auth: unknown): Visitor =>\n async ({ data, key, attribute, schema }, { remove, set }) => {\n if (!attribute) {\n return;\n }\n\n const isRelation = attribute.type === 'relation';\n\n if (!isRelation) {\n return;\n }\n\n const handleMorphRelation = async () => {\n const elements: any = (data as Record<string, MorphArray>)[key];\n\n if (!elements) {\n return;\n }\n\n if ('connect' in elements || 'set' in elements || 'disconnect' in elements) {\n const newValue: Record<string, unknown> = {};\n\n const connect = await handleMorphElements(elements.connect || []);\n const relSet = await handleMorphElements(elements.set || []);\n const disconnect = await handleMorphElements(elements.disconnect || []);\n\n if (connect.length > 0) {\n newValue.connect = connect;\n }\n\n if (relSet.length > 0) {\n newValue.set = relSet;\n }\n\n if (disconnect.length > 0) {\n newValue.disconnect = disconnect;\n }\n\n // TODO: this should technically be in its own visitor to check morph options, but for now we'll handle it here\n if (\n 'options' in elements &&\n typeof elements.options === 'object' &&\n elements.options !== null\n ) {\n const filteredOptions: RelationOrderingOptions = {};\n\n // Iterate through the keys of elements.options\n Object.keys(elements.options).forEach((key) => {\n const validator = VALID_RELATION_ORDERING_KEYS[key as keyof RelationOrderingOptions];\n\n // Ensure the key exists in VALID_RELATION_ORDERING_KEYS and the validator is defined before calling it\n if (validator && validator(elements.options[key])) {\n filteredOptions[key as keyof RelationOrderingOptions] = elements.options[key];\n }\n });\n\n // Assign the filtered options back to newValue\n newValue.options = filteredOptions;\n } else {\n newValue.options = {};\n }\n\n set(key, newValue);\n } else {\n const newMorphValue = await handleMorphElements(elements);\n\n if (newMorphValue.length) {\n set(key, newMorphValue);\n }\n }\n };\n\n const handleMorphElements = async (elements: any[]) => {\n const allowedElements: Record<string, unknown>[] = [];\n\n if (!isArray(elements)) {\n return allowedElements;\n }\n\n for (const element of elements) {\n if (!isObject(element) || !('__type' in element)) {\n continue;\n }\n\n const scopes = ACTIONS_TO_VERIFY.map((action) => `${element.__type}.${action}`);\n const isAllowed = await hasAccessToSomeScopes(scopes, auth);\n\n if (isAllowed) {\n allowedElements.push(element);\n }\n }\n\n return allowedElements;\n };\n\n const handleRegularRelation = async () => {\n const scopes = ACTIONS_TO_VERIFY.map((action) => `${attribute.target}.${action}`);\n\n const isAllowed = await hasAccessToSomeScopes(scopes, auth);\n\n // If the authenticated user don't have access to any of the scopes, then remove the field\n if (!isAllowed) {\n remove(key);\n }\n };\n\n const isCreatorRelation = [CREATED_BY_ATTRIBUTE, UPDATED_BY_ATTRIBUTE].includes(key);\n\n // Polymorphic relations\n if (contentTypeUtils.isMorphToRelationalAttribute(attribute)) {\n await handleMorphRelation();\n return;\n }\n\n // Creator relations\n if (isCreatorRelation && schema.options?.populateCreatorFields) {\n // do nothing\n return;\n }\n\n // Regular relations\n await handleRegularRelation();\n };\n\nconst hasAccessToSomeScopes = async (scopes: string[], auth: unknown) => {\n for (const scope of scopes) {\n try {\n await strapi.auth.verify(auth, { scope });\n return true;\n } catch {\n continue;\n }\n }\n\n return false;\n};\n"],"names":["ACTIONS_TO_VERIFY","CREATED_BY_ATTRIBUTE","UPDATED_BY_ATTRIBUTE","contentTypeUtils","auth","data","key","attribute","schema","remove","set","isRelation","type","handleMorphRelation","elements","newValue","connect","handleMorphElements","relSet","disconnect","length","options","filteredOptions","Object","keys","forEach","validator","VALID_RELATION_ORDERING_KEYS","newMorphValue","allowedElements","isArray","element","isObject","scopes","map","action","__type","isAllowed","hasAccessToSomeScopes","push","handleRegularRelation","target","isCreatorRelation","includes","populateCreatorFields","scope","strapi","verify"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/utils",
3
- "version": "5.23.1",
3
+ "version": "5.23.2",
4
4
  "description": "Shared utilities for the Strapi packages",
5
5
  "keywords": [
6
6
  "strapi",
@@ -61,10 +61,10 @@
61
61
  "@types/http-errors": "2.0.4",
62
62
  "@types/koa": "2.13.4",
63
63
  "@types/node": "18.19.24",
64
- "eslint-config-custom": "5.23.1",
64
+ "eslint-config-custom": "5.23.2",
65
65
  "koa": "2.16.1",
66
66
  "koa-body": "6.0.1",
67
- "tsconfig": "5.23.1"
67
+ "tsconfig": "5.23.2"
68
68
  },
69
69
  "engines": {
70
70
  "node": ">=18.0.0 <=22.x.x",