@strapi/utils 5.49.0 → 5.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/async.d.ts +2 -1
  2. package/dist/async.d.ts.map +1 -1
  3. package/dist/content-api-router.d.ts.map +1 -1
  4. package/dist/content-types.d.ts +5 -5
  5. package/dist/content-types.d.ts.map +1 -1
  6. package/dist/convert-query-params.d.ts.map +1 -1
  7. package/dist/convert-query-params.js +9 -11
  8. package/dist/convert-query-params.js.map +1 -1
  9. package/dist/convert-query-params.mjs +9 -11
  10. package/dist/convert-query-params.mjs.map +1 -1
  11. package/dist/errors.d.ts.map +1 -1
  12. package/dist/file.d.ts +0 -10
  13. package/dist/file.d.ts.map +1 -1
  14. package/dist/format-yup-error.d.ts.map +1 -1
  15. package/dist/has-published-version-param.d.ts +1 -1
  16. package/dist/has-published-version-param.d.ts.map +1 -1
  17. package/dist/hooks.d.ts.map +1 -1
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +9 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +3 -0
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/install-id.d.ts.map +1 -1
  25. package/dist/model-cache.d.ts.map +1 -1
  26. package/dist/operators.d.ts.map +1 -1
  27. package/dist/package-manager.d.ts.map +1 -1
  28. package/dist/pagination.d.ts.map +1 -1
  29. package/dist/parse-type.d.ts.map +1 -1
  30. package/dist/policy.d.ts.map +1 -1
  31. package/dist/primitives/arrays.d.ts.map +1 -1
  32. package/dist/primitives/dates.d.ts.map +1 -1
  33. package/dist/primitives/objects.d.ts.map +1 -1
  34. package/dist/primitives/strings.d.ts.map +1 -1
  35. package/dist/provider-factory.d.ts.map +1 -1
  36. package/dist/publication-filter.d.ts +1 -1
  37. package/dist/publication-filter.d.ts.map +1 -1
  38. package/dist/publication-filter.js +12 -12
  39. package/dist/publication-filter.js.map +1 -1
  40. package/dist/publication-filter.mjs +12 -12
  41. package/dist/publication-filter.mjs.map +1 -1
  42. package/dist/relations.d.ts.map +1 -1
  43. package/dist/route-serialization.d.ts.map +1 -1
  44. package/dist/sanitize/index.d.ts.map +1 -1
  45. package/dist/sanitize/index.js +4 -1
  46. package/dist/sanitize/index.js.map +1 -1
  47. package/dist/sanitize/index.mjs +4 -1
  48. package/dist/sanitize/index.mjs.map +1 -1
  49. package/dist/sanitize/sanitizers.d.ts +0 -1
  50. package/dist/sanitize/sanitizers.d.ts.map +1 -1
  51. package/dist/sanitize/visitors/remove-disallowed-fields.d.ts.map +1 -1
  52. package/dist/sanitize/visitors/remove-restricted-fields.d.ts.map +1 -1
  53. package/dist/sanitize/visitors/remove-restricted-relations.d.ts.map +1 -1
  54. package/dist/security.d.ts +1 -1
  55. package/dist/security.d.ts.map +1 -1
  56. package/dist/sessions.d.ts +35 -0
  57. package/dist/sessions.d.ts.map +1 -0
  58. package/dist/sessions.js +46 -0
  59. package/dist/sessions.js.map +1 -0
  60. package/dist/sessions.mjs +42 -0
  61. package/dist/sessions.mjs.map +1 -0
  62. package/dist/set-creator-fields.d.ts.map +1 -1
  63. package/dist/template.d.ts.map +1 -1
  64. package/dist/traverse/factory.d.ts +108 -9
  65. package/dist/traverse/factory.d.ts.map +1 -1
  66. package/dist/traverse/query-fields.d.ts +0 -1
  67. package/dist/traverse/query-fields.d.ts.map +1 -1
  68. package/dist/traverse/query-filters.d.ts +0 -1
  69. package/dist/traverse/query-filters.d.ts.map +1 -1
  70. package/dist/traverse/query-populate.d.ts +0 -1
  71. package/dist/traverse/query-populate.d.ts.map +1 -1
  72. package/dist/traverse/query-sort.d.ts +0 -1
  73. package/dist/traverse/query-sort.d.ts.map +1 -1
  74. package/dist/traverse-entity.d.ts +0 -1
  75. package/dist/traverse-entity.d.ts.map +1 -1
  76. package/dist/traverse-entity.js +7 -0
  77. package/dist/traverse-entity.js.map +1 -1
  78. package/dist/traverse-entity.mjs +7 -0
  79. package/dist/traverse-entity.mjs.map +1 -1
  80. package/dist/types.d.ts +0 -25
  81. package/dist/types.d.ts.map +1 -1
  82. package/dist/user-agent.d.ts +23 -0
  83. package/dist/user-agent.d.ts.map +1 -0
  84. package/dist/user-agent.js +74 -0
  85. package/dist/user-agent.js.map +1 -0
  86. package/dist/user-agent.mjs +71 -0
  87. package/dist/user-agent.mjs.map +1 -0
  88. package/dist/validate/index.d.ts.map +1 -1
  89. package/dist/validate/utils.d.ts.map +1 -1
  90. package/dist/validate/validators.d.ts +4 -4
  91. package/dist/validate/validators.d.ts.map +1 -1
  92. package/dist/validate/validators.js +152 -0
  93. package/dist/validate/validators.js.map +1 -1
  94. package/dist/validate/validators.mjs +154 -2
  95. package/dist/validate/validators.mjs.map +1 -1
  96. package/dist/validate/visitors/throw-disallowed-fields.d.ts.map +1 -1
  97. package/dist/validate/visitors/throw-restricted-fields.d.ts.map +1 -1
  98. package/dist/validate/visitors/throw-restricted-relations.d.ts.map +1 -1
  99. package/dist/validation/utilities.d.ts +5 -5
  100. package/dist/validation/utilities.d.ts.map +1 -1
  101. package/dist/validators.d.ts.map +1 -1
  102. package/dist/yup.d.ts.map +1 -1
  103. package/dist/zod.d.ts +1 -1
  104. package/dist/zod.d.ts.map +1 -1
  105. package/package.json +9 -5
@@ -1 +1 @@
1
- {"version":3,"file":"traverse-entity.mjs","sources":["../src/traverse-entity.ts"],"sourcesContent":["import { clone, isObject, isArray, isNil, curry } from 'lodash/fp';\n\nimport type { Attribute, AnyAttribute, Model, Data } from './types';\nimport { isRelationalAttribute, isMediaAttribute } from './content-types';\n\n/**\n * Execute promises in parallel but throw errors in array index order.\n */\nconst parallelWithOrderedErrors = async <T>(promises: Promise<T>[]): Promise<T[]> => {\n const results = await Promise.allSettled(promises);\n\n // Throw first error in array index order (matches sequential behavior)\n for (let i = 0; i < results.length; i += 1) {\n const result = results[i];\n if (result.status === 'rejected') {\n throw result.reason;\n }\n }\n\n return results.map((r) => (r as PromiseFulfilledResult<T>).value);\n};\n\nexport type VisitorUtils = ReturnType<typeof createVisitorUtils>;\n\nexport interface VisitorOptions {\n data: Record<string, unknown>;\n schema: Model;\n key: string;\n value: Data[keyof Data];\n attribute?: AnyAttribute;\n path: Path;\n getModel(uid: string): Model;\n parent?: Parent;\n /** Extra root-level keys allowed (e.g. registered input params). Only used when path.attribute === null. */\n allowedExtraRootKeys?: string[];\n}\n\nexport type Visitor = (visitorOptions: VisitorOptions, visitorUtils: VisitorUtils) => void;\n\nexport interface Path {\n raw: string | null;\n attribute: string | null;\n rawWithIndices?: string | null;\n}\n\nexport interface TraverseOptions {\n schema: Model;\n path?: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n /** Extra root-level keys allowed (e.g. registered input params). Only used when path.attribute === null. */\n allowedExtraRootKeys?: string[];\n}\n\nexport interface Parent {\n attribute?: Attribute;\n key: string | null;\n path: Path;\n schema: Model;\n}\n\nconst traverseEntity = async (\n visitor: Visitor,\n options: TraverseOptions,\n entity: Data\n): Promise<Data> => {\n const {\n path = { raw: null, attribute: null, rawWithIndices: null },\n schema,\n getModel,\n allowedExtraRootKeys,\n } = options;\n\n let parent = options.parent;\n\n const traverseMorphRelationTarget = async (visitor: Visitor, path: Path, entry: Data) => {\n const targetSchema = getModel(entry.__type!);\n\n const traverseOptions: TraverseOptions = {\n schema: targetSchema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n const traverseRelationTarget =\n (schema: Model) => async (visitor: Visitor, path: Path, entry: Data) => {\n const traverseOptions: TraverseOptions = {\n schema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n const traverseMediaTarget = async (visitor: Visitor, path: Path, entry: Data) => {\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const traverseOptions: TraverseOptions = {\n schema: targetSchema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n const traverseComponent = async (visitor: Visitor, path: Path, schema: Model, entry: Data) => {\n const traverseOptions: TraverseOptions = {\n schema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n const visitDynamicZoneEntry = async (visitor: Visitor, path: Path, entry: Data) => {\n const targetSchema = getModel(entry.__component!);\n const traverseOptions: TraverseOptions = {\n schema: targetSchema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n // End recursion\n if (!isObject(entity) || isNil(schema)) {\n return entity;\n }\n\n // Don't mutate the original entity object\n // only clone at 1st level as the next level will get clone when traversed\n const copy = clone(entity);\n const visitorUtils = createVisitorUtils({ data: copy });\n\n const keys = Object.keys(copy);\n for (let i = 0; i < keys.length; i += 1) {\n const key = keys[i];\n // Retrieve the attribute definition associated to the key from the schema\n const attribute = schema.attributes[key] as AnyAttribute | undefined;\n\n const newPath = { ...path };\n\n newPath.raw = isNil(path.raw) ? key : `${path.raw}.${key}`;\n newPath.rawWithIndices = isNil(path.rawWithIndices) ? key : `${path.rawWithIndices}.${key}`;\n\n if (!isNil(attribute)) {\n newPath.attribute = isNil(path.attribute) ? key : `${path.attribute}.${key}`;\n }\n\n // Visit the current attribute\n const visitorOptions: VisitorOptions = {\n data: copy,\n schema,\n key,\n value: copy[key],\n attribute,\n path: newPath,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n await visitor(visitorOptions, visitorUtils);\n\n // Extract the value for the current key (after calling the visitor)\n const value = copy[key];\n\n // Ignore Nil values or attributes\n if (isNil(value) || isNil(attribute)) {\n continue;\n }\n\n if (isRelationalAttribute(attribute)) {\n parent = { schema, key, attribute, path: newPath };\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n const method = isMorphRelation\n ? traverseMorphRelationTarget\n : traverseRelationTarget(getModel(attribute.target!));\n\n if (isArray(value)) {\n // Process array items in parallel with ordered error handling\n copy[key] = await parallelWithOrderedErrors(\n value.map((item, i) => {\n const arrayPath = {\n ...newPath,\n rawWithIndices: isNil(newPath.rawWithIndices)\n ? `${i}`\n : `${newPath.rawWithIndices}.${i}`,\n };\n return method(visitor, arrayPath, item);\n })\n );\n } else {\n copy[key] = await method(visitor, newPath, value as Data);\n }\n\n continue;\n }\n\n if (isMediaAttribute(attribute)) {\n parent = { schema, key, attribute, path: newPath };\n\n if (isArray(value)) {\n // Process media array items in parallel with ordered error handling\n copy[key] = await parallelWithOrderedErrors(\n value.map((item, i) => {\n const arrayPath = {\n ...newPath,\n rawWithIndices: isNil(newPath.rawWithIndices)\n ? `${i}`\n : `${newPath.rawWithIndices}.${i}`,\n };\n return traverseMediaTarget(visitor, arrayPath, item);\n })\n );\n } else {\n copy[key] = await traverseMediaTarget(visitor, newPath, value as Data);\n }\n\n continue;\n }\n\n if (attribute.type === 'component') {\n parent = { schema, key, attribute, path: newPath };\n const targetSchema = getModel(attribute.component);\n\n if (isArray(value)) {\n // Process component array items in parallel with ordered error handling\n copy[key] = await parallelWithOrderedErrors(\n value.map((item, i) => {\n const arrayPath = {\n ...newPath,\n rawWithIndices: isNil(newPath.rawWithIndices)\n ? `${i}`\n : `${newPath.rawWithIndices}.${i}`,\n };\n return traverseComponent(visitor, arrayPath, targetSchema, item);\n })\n );\n } else {\n copy[key] = await traverseComponent(visitor, newPath, targetSchema, value as Data);\n }\n\n continue;\n }\n\n if (attribute.type === 'dynamiczone' && isArray(value)) {\n parent = { schema, key, attribute, path: newPath };\n\n // Process dynamic zone items in parallel with ordered error handling\n copy[key] = await parallelWithOrderedErrors(\n value.map((item, i) => {\n const arrayPath = {\n ...newPath,\n rawWithIndices: isNil(newPath.rawWithIndices)\n ? `${i}`\n : `${newPath.rawWithIndices}.${i}`,\n };\n return visitDynamicZoneEntry(visitor, arrayPath, item);\n })\n );\n\n continue;\n }\n }\n\n return copy;\n};\n\nconst createVisitorUtils = ({ data }: { data: Data }) => ({\n remove(key: string) {\n delete data[key];\n },\n\n set(key: string, value: Data) {\n data[key] = value;\n },\n});\n\nexport default curry(traverseEntity);\n"],"names":["parallelWithOrderedErrors","promises","results","Promise","allSettled","i","length","result","status","reason","map","r","value","traverseEntity","visitor","options","entity","path","raw","attribute","rawWithIndices","schema","getModel","allowedExtraRootKeys","parent","traverseMorphRelationTarget","entry","targetSchema","__type","traverseOptions","traverseRelationTarget","traverseMediaTarget","targetSchemaUID","traverseComponent","visitDynamicZoneEntry","__component","isObject","isNil","copy","clone","visitorUtils","createVisitorUtils","data","keys","Object","key","attributes","newPath","visitorOptions","isRelationalAttribute","isMorphRelation","relation","toLowerCase","startsWith","method","target","isArray","item","arrayPath","isMediaAttribute","type","component","remove","set","curry"],"mappings":";;;AAKA;;IAGA,MAAMA,4BAA4B,OAAUC,QAAAA,GAAAA;AAC1C,IAAA,MAAMC,OAAAA,GAAU,MAAMC,OAAAA,CAAQC,UAAU,CAACH,QAAAA,CAAAA;;IAGzC,IAAK,IAAII,IAAI,CAAA,EAAGA,CAAAA,GAAIH,QAAQI,MAAM,EAAED,KAAK,CAAA,CAAG;QAC1C,MAAME,MAAAA,GAASL,OAAO,CAACG,CAAAA,CAAE;QACzB,IAAIE,MAAAA,CAAOC,MAAM,KAAK,UAAA,EAAY;AAChC,YAAA,MAAMD,OAAOE,MAAM;AACrB,QAAA;AACF,IAAA;AAEA,IAAA,OAAOP,QAAQQ,GAAG,CAAC,CAACC,CAAAA,GAAOA,EAAgCC,KAAK,CAAA;AAClE,CAAA;AAyCA,MAAMC,gBAAAA,GAAiB,OACrBC,OAAAA,EACAC,OAAAA,EACAC,MAAAA,GAAAA;AAEA,IAAA,MAAM,EACJC,IAAAA,GAAO;QAAEC,GAAAA,EAAK,IAAA;QAAMC,SAAAA,EAAW,IAAA;QAAMC,cAAAA,EAAgB;AAAK,KAAC,EAC3DC,MAAM,EACNC,QAAQ,EACRC,oBAAoB,EACrB,GAAGR,OAAAA;IAEJ,IAAIS,MAAAA,GAAST,QAAQS,MAAM;IAE3B,MAAMC,2BAAAA,GAA8B,OAAOX,OAAAA,EAAkBG,IAAAA,EAAYS,KAAAA,GAAAA;QACvE,MAAMC,YAAAA,GAAeL,QAAAA,CAASI,KAAAA,CAAME,MAAM,CAAA;AAE1C,QAAA,MAAMC,eAAAA,GAAmC;YACvCR,MAAAA,EAAQM,YAAAA;AACRV,YAAAA,IAAAA;AACAK,YAAAA,QAAAA;AACAE,YAAAA,MAAAA;AACAD,YAAAA;AACF,SAAA;QAEA,OAAOV,gBAAAA,CAAeC,SAASe,eAAAA,EAAiBH,KAAAA,CAAAA;AAClD,IAAA,CAAA;AAEA,IAAA,MAAMI,sBAAAA,GACJ,CAACT,MAAAA,GAAkB,OAAOP,SAAkBG,IAAAA,EAAYS,KAAAA,GAAAA;AACtD,YAAA,MAAMG,eAAAA,GAAmC;AACvCR,gBAAAA,MAAAA;AACAJ,gBAAAA,IAAAA;AACAK,gBAAAA,QAAAA;AACAE,gBAAAA,MAAAA;AACAD,gBAAAA;AACF,aAAA;YAEA,OAAOV,gBAAAA,CAAeC,SAASe,eAAAA,EAAiBH,KAAAA,CAAAA;AAClD,QAAA,CAAA;IAEF,MAAMK,mBAAAA,GAAsB,OAAOjB,OAAAA,EAAkBG,IAAAA,EAAYS,KAAAA,GAAAA;AAC/D,QAAA,MAAMM,eAAAA,GAAkB,qBAAA;AACxB,QAAA,MAAML,eAAeL,QAAAA,CAASU,eAAAA,CAAAA;AAE9B,QAAA,MAAMH,eAAAA,GAAmC;YACvCR,MAAAA,EAAQM,YAAAA;AACRV,YAAAA,IAAAA;AACAK,YAAAA,QAAAA;AACAE,YAAAA,MAAAA;AACAD,YAAAA;AACF,SAAA;QAEA,OAAOV,gBAAAA,CAAeC,SAASe,eAAAA,EAAiBH,KAAAA,CAAAA;AAClD,IAAA,CAAA;AAEA,IAAA,MAAMO,iBAAAA,GAAoB,OAAOnB,OAAAA,EAAkBG,IAAAA,EAAYI,MAAAA,EAAeK,KAAAA,GAAAA;AAC5E,QAAA,MAAMG,eAAAA,GAAmC;AACvCR,YAAAA,MAAAA;AACAJ,YAAAA,IAAAA;AACAK,YAAAA,QAAAA;AACAE,YAAAA,MAAAA;AACAD,YAAAA;AACF,SAAA;QAEA,OAAOV,gBAAAA,CAAeC,SAASe,eAAAA,EAAiBH,KAAAA,CAAAA;AAClD,IAAA,CAAA;IAEA,MAAMQ,qBAAAA,GAAwB,OAAOpB,OAAAA,EAAkBG,IAAAA,EAAYS,KAAAA,GAAAA;QACjE,MAAMC,YAAAA,GAAeL,QAAAA,CAASI,KAAAA,CAAMS,WAAW,CAAA;AAC/C,QAAA,MAAMN,eAAAA,GAAmC;YACvCR,MAAAA,EAAQM,YAAAA;AACRV,YAAAA,IAAAA;AACAK,YAAAA,QAAAA;AACAE,YAAAA,MAAAA;AACAD,YAAAA;AACF,SAAA;QAEA,OAAOV,gBAAAA,CAAeC,SAASe,eAAAA,EAAiBH,KAAAA,CAAAA;AAClD,IAAA,CAAA;;AAGA,IAAA,IAAI,CAACU,QAAAA,CAASpB,MAAAA,CAAAA,IAAWqB,KAAAA,CAAMhB,MAAAA,CAAAA,EAAS;QACtC,OAAOL,MAAAA;AACT,IAAA;;;AAIA,IAAA,MAAMsB,OAAOC,KAAAA,CAAMvB,MAAAA,CAAAA;AACnB,IAAA,MAAMwB,eAAeC,kBAAAA,CAAmB;QAAEC,IAAAA,EAAMJ;AAAK,KAAA,CAAA;IAErD,MAAMK,IAAAA,GAAOC,MAAAA,CAAOD,IAAI,CAACL,IAAAA,CAAAA;IACzB,IAAK,IAAIjC,IAAI,CAAA,EAAGA,CAAAA,GAAIsC,KAAKrC,MAAM,EAAED,KAAK,CAAA,CAAG;QACvC,MAAMwC,GAAAA,GAAMF,IAAI,CAACtC,CAAAA,CAAE;;AAEnB,QAAA,MAAMc,SAAAA,GAAYE,MAAAA,CAAOyB,UAAU,CAACD,GAAAA,CAAI;AAExC,QAAA,MAAME,OAAAA,GAAU;AAAE,YAAA,GAAG9B;AAAK,SAAA;AAE1B8B,QAAAA,OAAAA,CAAQ7B,GAAG,GAAGmB,KAAAA,CAAMpB,IAAAA,CAAKC,GAAG,CAAA,GAAI2B,GAAAA,GAAM,CAAA,EAAG5B,IAAAA,CAAKC,GAAG,CAAC,CAAC,EAAE2B,GAAAA,CAAAA,CAAK;AAC1DE,QAAAA,OAAAA,CAAQ3B,cAAc,GAAGiB,KAAAA,CAAMpB,IAAAA,CAAKG,cAAc,CAAA,GAAIyB,GAAAA,GAAM,CAAA,EAAG5B,IAAAA,CAAKG,cAAc,CAAC,CAAC,EAAEyB,GAAAA,CAAAA,CAAK;QAE3F,IAAI,CAACR,MAAMlB,SAAAA,CAAAA,EAAY;AACrB4B,YAAAA,OAAAA,CAAQ5B,SAAS,GAAGkB,KAAAA,CAAMpB,IAAAA,CAAKE,SAAS,CAAA,GAAI0B,GAAAA,GAAM,CAAA,EAAG5B,IAAAA,CAAKE,SAAS,CAAC,CAAC,EAAE0B,GAAAA,CAAAA,CAAK;AAC9E,QAAA;;AAGA,QAAA,MAAMG,cAAAA,GAAiC;YACrCN,IAAAA,EAAMJ,IAAAA;AACNjB,YAAAA,MAAAA;AACAwB,YAAAA,GAAAA;YACAjC,KAAAA,EAAO0B,IAAI,CAACO,GAAAA,CAAI;AAChB1B,YAAAA,SAAAA;YACAF,IAAAA,EAAM8B,OAAAA;AACNzB,YAAAA,QAAAA;AACAE,YAAAA,MAAAA;AACAD,YAAAA;AACF,SAAA;AAEA,QAAA,MAAMT,QAAQkC,cAAAA,EAAgBR,YAAAA,CAAAA;;QAG9B,MAAM5B,KAAAA,GAAQ0B,IAAI,CAACO,GAAAA,CAAI;;QAGvB,IAAIR,KAAAA,CAAMzB,KAAAA,CAAAA,IAAUyB,KAAAA,CAAMlB,SAAAA,CAAAA,EAAY;AACpC,YAAA;AACF,QAAA;AAEA,QAAA,IAAI8B,sBAAsB9B,SAAAA,CAAAA,EAAY;YACpCK,MAAAA,GAAS;AAAEH,gBAAAA,MAAAA;AAAQwB,gBAAAA,GAAAA;AAAK1B,gBAAAA,SAAAA;gBAAWF,IAAAA,EAAM8B;AAAQ,aAAA;AACjD,YAAA,MAAMG,kBAAkB/B,SAAAA,CAAUgC,QAAQ,CAACC,WAAW,EAAA,CAAGC,UAAU,CAAC,OAAA,CAAA;AAEpE,YAAA,MAAMC,SAASJ,eAAAA,GACXzB,2BAAAA,GACAK,sBAAAA,CAAuBR,QAAAA,CAASH,UAAUoC,MAAM,CAAA,CAAA;AAEpD,YAAA,IAAIC,QAAQ5C,KAAAA,CAAAA,EAAQ;;gBAElB0B,IAAI,CAACO,IAAI,GAAG,MAAM7C,0BAChBY,KAAAA,CAAMF,GAAG,CAAC,CAAC+C,IAAAA,EAAMpD,CAAAA,GAAAA;AACf,oBAAA,MAAMqD,SAAAA,GAAY;AAChB,wBAAA,GAAGX,OAAO;AACV3B,wBAAAA,cAAAA,EAAgBiB,KAAAA,CAAMU,OAAAA,CAAQ3B,cAAc,CAAA,GACxC,CAAA,EAAGf,CAAAA,CAAAA,CAAG,GACN,CAAA,EAAG0C,OAAAA,CAAQ3B,cAAc,CAAC,CAAC,EAAEf,CAAAA,CAAAA;AACnC,qBAAA;oBACA,OAAOiD,MAAAA,CAAOxC,SAAS4C,SAAAA,EAAWD,IAAAA,CAAAA;AACpC,gBAAA,CAAA,CAAA,CAAA;YAEJ,CAAA,MAAO;AACLnB,gBAAAA,IAAI,CAACO,GAAAA,CAAI,GAAG,MAAMS,MAAAA,CAAOxC,SAASiC,OAAAA,EAASnC,KAAAA,CAAAA;AAC7C,YAAA;AAEA,YAAA;AACF,QAAA;AAEA,QAAA,IAAI+C,iBAAiBxC,SAAAA,CAAAA,EAAY;YAC/BK,MAAAA,GAAS;AAAEH,gBAAAA,MAAAA;AAAQwB,gBAAAA,GAAAA;AAAK1B,gBAAAA,SAAAA;gBAAWF,IAAAA,EAAM8B;AAAQ,aAAA;AAEjD,YAAA,IAAIS,QAAQ5C,KAAAA,CAAAA,EAAQ;;gBAElB0B,IAAI,CAACO,IAAI,GAAG,MAAM7C,0BAChBY,KAAAA,CAAMF,GAAG,CAAC,CAAC+C,IAAAA,EAAMpD,CAAAA,GAAAA;AACf,oBAAA,MAAMqD,SAAAA,GAAY;AAChB,wBAAA,GAAGX,OAAO;AACV3B,wBAAAA,cAAAA,EAAgBiB,KAAAA,CAAMU,OAAAA,CAAQ3B,cAAc,CAAA,GACxC,CAAA,EAAGf,CAAAA,CAAAA,CAAG,GACN,CAAA,EAAG0C,OAAAA,CAAQ3B,cAAc,CAAC,CAAC,EAAEf,CAAAA,CAAAA;AACnC,qBAAA;oBACA,OAAO0B,mBAAAA,CAAoBjB,SAAS4C,SAAAA,EAAWD,IAAAA,CAAAA;AACjD,gBAAA,CAAA,CAAA,CAAA;YAEJ,CAAA,MAAO;AACLnB,gBAAAA,IAAI,CAACO,GAAAA,CAAI,GAAG,MAAMd,mBAAAA,CAAoBjB,SAASiC,OAAAA,EAASnC,KAAAA,CAAAA;AAC1D,YAAA;AAEA,YAAA;AACF,QAAA;QAEA,IAAIO,SAAAA,CAAUyC,IAAI,KAAK,WAAA,EAAa;YAClCpC,MAAAA,GAAS;AAAEH,gBAAAA,MAAAA;AAAQwB,gBAAAA,GAAAA;AAAK1B,gBAAAA,SAAAA;gBAAWF,IAAAA,EAAM8B;AAAQ,aAAA;YACjD,MAAMpB,YAAAA,GAAeL,QAAAA,CAASH,SAAAA,CAAU0C,SAAS,CAAA;AAEjD,YAAA,IAAIL,QAAQ5C,KAAAA,CAAAA,EAAQ;;gBAElB0B,IAAI,CAACO,IAAI,GAAG,MAAM7C,0BAChBY,KAAAA,CAAMF,GAAG,CAAC,CAAC+C,IAAAA,EAAMpD,CAAAA,GAAAA;AACf,oBAAA,MAAMqD,SAAAA,GAAY;AAChB,wBAAA,GAAGX,OAAO;AACV3B,wBAAAA,cAAAA,EAAgBiB,KAAAA,CAAMU,OAAAA,CAAQ3B,cAAc,CAAA,GACxC,CAAA,EAAGf,CAAAA,CAAAA,CAAG,GACN,CAAA,EAAG0C,OAAAA,CAAQ3B,cAAc,CAAC,CAAC,EAAEf,CAAAA,CAAAA;AACnC,qBAAA;oBACA,OAAO4B,iBAAAA,CAAkBnB,OAAAA,EAAS4C,SAAAA,EAAW/B,YAAAA,EAAc8B,IAAAA,CAAAA;AAC7D,gBAAA,CAAA,CAAA,CAAA;YAEJ,CAAA,MAAO;AACLnB,gBAAAA,IAAI,CAACO,GAAAA,CAAI,GAAG,MAAMZ,iBAAAA,CAAkBnB,OAAAA,EAASiC,SAASpB,YAAAA,EAAcf,KAAAA,CAAAA;AACtE,YAAA;AAEA,YAAA;AACF,QAAA;AAEA,QAAA,IAAIO,SAAAA,CAAUyC,IAAI,KAAK,aAAA,IAAiBJ,QAAQ5C,KAAAA,CAAAA,EAAQ;YACtDY,MAAAA,GAAS;AAAEH,gBAAAA,MAAAA;AAAQwB,gBAAAA,GAAAA;AAAK1B,gBAAAA,SAAAA;gBAAWF,IAAAA,EAAM8B;AAAQ,aAAA;;YAGjDT,IAAI,CAACO,IAAI,GAAG,MAAM7C,0BAChBY,KAAAA,CAAMF,GAAG,CAAC,CAAC+C,IAAAA,EAAMpD,CAAAA,GAAAA;AACf,gBAAA,MAAMqD,SAAAA,GAAY;AAChB,oBAAA,GAAGX,OAAO;AACV3B,oBAAAA,cAAAA,EAAgBiB,KAAAA,CAAMU,OAAAA,CAAQ3B,cAAc,CAAA,GACxC,CAAA,EAAGf,CAAAA,CAAAA,CAAG,GACN,CAAA,EAAG0C,OAAAA,CAAQ3B,cAAc,CAAC,CAAC,EAAEf,CAAAA,CAAAA;AACnC,iBAAA;gBACA,OAAO6B,qBAAAA,CAAsBpB,SAAS4C,SAAAA,EAAWD,IAAAA,CAAAA;AACnD,YAAA,CAAA,CAAA,CAAA;AAGF,YAAA;AACF,QAAA;AACF,IAAA;IAEA,OAAOnB,IAAAA;AACT,CAAA;AAEA,MAAMG,qBAAqB,CAAC,EAAEC,IAAI,EAAkB,IAAM;AACxDoB,QAAAA,MAAAA,CAAAA,CAAOjB,GAAW,EAAA;YAChB,OAAOH,IAAI,CAACG,GAAAA,CAAI;AAClB,QAAA,CAAA;QAEAkB,GAAAA,CAAAA,CAAIlB,GAAW,EAAEjC,KAAW,EAAA;YAC1B8B,IAAI,CAACG,IAAI,GAAGjC,KAAAA;AACd,QAAA;KACF,CAAA;AAEA,qBAAeoD,MAAMnD,gBAAAA,CAAAA;;;;"}
1
+ {"version":3,"file":"traverse-entity.mjs","sources":["../src/traverse-entity.ts"],"sourcesContent":["import { clone, isObject, isArray, isNil, curry } from 'lodash/fp';\n\nimport type { Attribute, AnyAttribute, Model, Data } from './types';\nimport { isRelationalAttribute, isMediaAttribute } from './content-types';\n\n/**\n * Execute promises in parallel but throw errors in array index order.\n */\nconst parallelWithOrderedErrors = async <T>(promises: Promise<T>[]): Promise<T[]> => {\n const results = await Promise.allSettled(promises);\n\n // Throw first error in array index order (matches sequential behavior)\n for (let i = 0; i < results.length; i += 1) {\n const result = results[i];\n if (result.status === 'rejected') {\n throw result.reason;\n }\n }\n\n return results.map((r) => (r as PromiseFulfilledResult<T>).value);\n};\n\nexport type VisitorUtils = ReturnType<typeof createVisitorUtils>;\n\nexport interface VisitorOptions {\n data: Record<string, unknown>;\n schema: Model;\n key: string;\n value: Data[keyof Data];\n attribute?: AnyAttribute;\n path: Path;\n getModel(uid: string): Model;\n parent?: Parent;\n /** Extra root-level keys allowed (e.g. registered input params). Only used when path.attribute === null. */\n allowedExtraRootKeys?: string[];\n}\n\nexport type Visitor = (visitorOptions: VisitorOptions, visitorUtils: VisitorUtils) => void;\n\nexport interface Path {\n raw: string | null;\n attribute: string | null;\n rawWithIndices?: string | null;\n}\n\nexport interface TraverseOptions {\n schema: Model;\n path?: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n /** Extra root-level keys allowed (e.g. registered input params). Only used when path.attribute === null. */\n allowedExtraRootKeys?: string[];\n}\n\nexport interface Parent {\n attribute?: Attribute;\n key: string | null;\n path: Path;\n schema: Model;\n}\n\nconst traverseEntity = async (\n visitor: Visitor,\n options: TraverseOptions,\n entity: Data\n): Promise<Data> => {\n const {\n path = { raw: null, attribute: null, rawWithIndices: null },\n schema,\n getModel,\n allowedExtraRootKeys,\n } = options;\n\n let parent = options.parent;\n\n const traverseMorphRelationTarget = async (visitor: Visitor, path: Path, entry: Data) => {\n const targetSchema = getModel(entry.__type!);\n\n const traverseOptions: TraverseOptions = {\n schema: targetSchema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n const traverseRelationTarget =\n (schema: Model) => async (visitor: Visitor, path: Path, entry: Data) => {\n const traverseOptions: TraverseOptions = {\n schema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n const traverseMediaTarget = async (visitor: Visitor, path: Path, entry: Data) => {\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const traverseOptions: TraverseOptions = {\n schema: targetSchema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n const traverseComponent = async (visitor: Visitor, path: Path, schema: Model, entry: Data) => {\n const traverseOptions: TraverseOptions = {\n schema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n const visitDynamicZoneEntry = async (visitor: Visitor, path: Path, entry: Data) => {\n // A dynamic zone array can contain a `null` entry (for example a relation\n // created inline inside a dynamic zone component can leave a null item).\n // Reading `__component` on it crashed traversal; pass nil entries through\n // untouched, consistent with how `traverseEntity` ends recursion on nil. (#24303)\n if (isNil(entry)) {\n return entry;\n }\n\n const targetSchema = getModel(entry.__component!);\n const traverseOptions: TraverseOptions = {\n schema: targetSchema,\n path,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n return traverseEntity(visitor, traverseOptions, entry);\n };\n\n // End recursion\n if (!isObject(entity) || isNil(schema)) {\n return entity;\n }\n\n // Don't mutate the original entity object\n // only clone at 1st level as the next level will get clone when traversed\n const copy = clone(entity);\n const visitorUtils = createVisitorUtils({ data: copy });\n\n const keys = Object.keys(copy);\n for (let i = 0; i < keys.length; i += 1) {\n const key = keys[i];\n // Retrieve the attribute definition associated to the key from the schema\n const attribute = schema.attributes[key] as AnyAttribute | undefined;\n\n const newPath = { ...path };\n\n newPath.raw = isNil(path.raw) ? key : `${path.raw}.${key}`;\n newPath.rawWithIndices = isNil(path.rawWithIndices) ? key : `${path.rawWithIndices}.${key}`;\n\n if (!isNil(attribute)) {\n newPath.attribute = isNil(path.attribute) ? key : `${path.attribute}.${key}`;\n }\n\n // Visit the current attribute\n const visitorOptions: VisitorOptions = {\n data: copy,\n schema,\n key,\n value: copy[key],\n attribute,\n path: newPath,\n getModel,\n parent,\n allowedExtraRootKeys,\n };\n\n await visitor(visitorOptions, visitorUtils);\n\n // Extract the value for the current key (after calling the visitor)\n const value = copy[key];\n\n // Ignore Nil values or attributes\n if (isNil(value) || isNil(attribute)) {\n continue;\n }\n\n if (isRelationalAttribute(attribute)) {\n parent = { schema, key, attribute, path: newPath };\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n const method = isMorphRelation\n ? traverseMorphRelationTarget\n : traverseRelationTarget(getModel(attribute.target!));\n\n if (isArray(value)) {\n // Process array items in parallel with ordered error handling\n copy[key] = await parallelWithOrderedErrors(\n value.map((item, i) => {\n const arrayPath = {\n ...newPath,\n rawWithIndices: isNil(newPath.rawWithIndices)\n ? `${i}`\n : `${newPath.rawWithIndices}.${i}`,\n };\n return method(visitor, arrayPath, item);\n })\n );\n } else {\n copy[key] = await method(visitor, newPath, value as Data);\n }\n\n continue;\n }\n\n if (isMediaAttribute(attribute)) {\n parent = { schema, key, attribute, path: newPath };\n\n if (isArray(value)) {\n // Process media array items in parallel with ordered error handling\n copy[key] = await parallelWithOrderedErrors(\n value.map((item, i) => {\n const arrayPath = {\n ...newPath,\n rawWithIndices: isNil(newPath.rawWithIndices)\n ? `${i}`\n : `${newPath.rawWithIndices}.${i}`,\n };\n return traverseMediaTarget(visitor, arrayPath, item);\n })\n );\n } else {\n copy[key] = await traverseMediaTarget(visitor, newPath, value as Data);\n }\n\n continue;\n }\n\n if (attribute.type === 'component') {\n parent = { schema, key, attribute, path: newPath };\n const targetSchema = getModel(attribute.component);\n\n if (isArray(value)) {\n // Process component array items in parallel with ordered error handling\n copy[key] = await parallelWithOrderedErrors(\n value.map((item, i) => {\n const arrayPath = {\n ...newPath,\n rawWithIndices: isNil(newPath.rawWithIndices)\n ? `${i}`\n : `${newPath.rawWithIndices}.${i}`,\n };\n return traverseComponent(visitor, arrayPath, targetSchema, item);\n })\n );\n } else {\n copy[key] = await traverseComponent(visitor, newPath, targetSchema, value as Data);\n }\n\n continue;\n }\n\n if (attribute.type === 'dynamiczone' && isArray(value)) {\n parent = { schema, key, attribute, path: newPath };\n\n // Process dynamic zone items in parallel with ordered error handling\n copy[key] = await parallelWithOrderedErrors(\n value.map((item, i) => {\n const arrayPath = {\n ...newPath,\n rawWithIndices: isNil(newPath.rawWithIndices)\n ? `${i}`\n : `${newPath.rawWithIndices}.${i}`,\n };\n return visitDynamicZoneEntry(visitor, arrayPath, item);\n })\n );\n\n continue;\n }\n }\n\n return copy;\n};\n\nconst createVisitorUtils = ({ data }: { data: Data }) => ({\n remove(key: string) {\n delete data[key];\n },\n\n set(key: string, value: Data) {\n data[key] = value;\n },\n});\n\nexport default curry(traverseEntity);\n"],"names":["parallelWithOrderedErrors","promises","results","Promise","allSettled","i","length","result","status","reason","map","r","value","traverseEntity","visitor","options","entity","path","raw","attribute","rawWithIndices","schema","getModel","allowedExtraRootKeys","parent","traverseMorphRelationTarget","entry","targetSchema","__type","traverseOptions","traverseRelationTarget","traverseMediaTarget","targetSchemaUID","traverseComponent","visitDynamicZoneEntry","isNil","__component","isObject","copy","clone","visitorUtils","createVisitorUtils","data","keys","Object","key","attributes","newPath","visitorOptions","isRelationalAttribute","isMorphRelation","relation","toLowerCase","startsWith","method","target","isArray","item","arrayPath","isMediaAttribute","type","component","remove","set","curry"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import type * as Koa from 'koa';
2
1
  type ID = number | string;
3
2
  export type Data = {
4
3
  id?: ID;
@@ -53,30 +52,6 @@ export interface Model {
53
52
  privateAttributes?: string[];
54
53
  attributes: Record<string, AnyAttribute>;
55
54
  }
56
- declare module 'koa' {
57
- interface Request extends Koa.BaseRequest {
58
- route: RouteInfo;
59
- }
60
- interface ExtendableContext {
61
- ok: (response?: string | object, details?: object) => Koa.Context;
62
- created: (response?: string | object, details?: object) => Koa.Context;
63
- noContent: (response?: string | object, details?: object) => Koa.Context;
64
- badRequest: (response?: string | object, details?: object) => Koa.Context;
65
- unauthorized: (response?: string | object, details?: object) => Koa.Context;
66
- forbidden: (response?: string | object, details?: object) => Koa.Context;
67
- notFound: (response?: string | object, details?: object) => Koa.Context;
68
- locked: (response?: string | object, details?: object) => Koa.Context;
69
- internalServerError: (response?: string | object, details?: object) => Koa.Context;
70
- notImplemented: (response?: string | object, data?: Record<string, unknown>) => Koa.Context;
71
- }
72
- }
73
- export interface RouteInfo {
74
- endpoint: string;
75
- controller: string;
76
- action: string;
77
- verb: string;
78
- plugin: string;
79
- }
80
55
  export type WithRequired<T, K extends keyof T> = T & {
81
56
  [P in K]-?: T[P];
82
57
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,KAAK,EAAE,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1B,MAAM,MAAM,IAAI,GAAG;IACjB,EAAE,CAAC,EAAE,EAAE,CAAC;IACR,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,EAAE,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;CACzF,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7C,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,mBAAoB,SAAQ,SAAS;IACpD,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,IAAI,EACA,QAAQ,GACR,MAAM,GACN,UAAU,GACV,SAAS,GACT,YAAY,GACZ,OAAO,GACP,SAAS,GACT,MAAM,GACN,MAAM,GACN,UAAU,GACV,WAAW,GACX,aAAa,GACb,SAAS,GACT,MAAM,GACN,QAAQ,GACR,KAAK,GACL,UAAU,GACV,OAAO,GACP,OAAO,CAAC;CACb;AAED,MAAM,MAAM,YAAY,GACpB,eAAe,GACf,mBAAmB,GACnB,kBAAkB,GAClB,oBAAoB,CAAC;AAEzB,MAAM,MAAM,IAAI,GAAG,YAAY,GAAG,gBAAgB,CAAC;AAEnD,MAAM,WAAW,KAAK;IACpB,SAAS,EAAE,aAAa,GAAG,WAAW,CAAC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE;QACL,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,qBAAqB,CAAC,EAAE,OAAO,CAAC;QAChC,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC1C;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG;KAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Minimal, dependency-free User-Agent parsing.
3
+ *
4
+ * This is intentionally heuristic and only aims to produce a human-readable label
5
+ * (e.g. "Chrome on macOS") for displaying active sessions/devices. It is not a full
6
+ * UA parser and should not be relied upon for feature detection.
7
+ */
8
+ export interface ParsedUserAgent {
9
+ browser?: string;
10
+ os?: string;
11
+ /** Human-readable label combining browser and OS, e.g. "Chrome on macOS". */
12
+ deviceName?: string;
13
+ }
14
+ /**
15
+ * Parses a User-Agent string into a best-effort browser/OS and a display label.
16
+ * Returns an empty object when the input is missing or unrecognized.
17
+ */
18
+ export declare const parseUserAgent: (userAgent?: string | null) => ParsedUserAgent;
19
+ /**
20
+ * Convenience helper returning only the human-readable device label, or undefined.
21
+ */
22
+ export declare const getDeviceName: (userAgent?: string | null) => string | undefined;
23
+ //# sourceMappingURL=user-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-agent.d.ts","sourceRoot":"","sources":["../src/user-agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAwCD;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,MAAM,GAAG,IAAI,KAAG,eAqB1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,YAAY,MAAM,GAAG,IAAI,KAAG,MAAM,GAAG,SAC7B,CAAC"}
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Minimal, dependency-free User-Agent parsing.
5
+ *
6
+ * This is intentionally heuristic and only aims to produce a human-readable label
7
+ * (e.g. "Chrome on macOS") for displaying active sessions/devices. It is not a full
8
+ * UA parser and should not be relied upon for feature detection.
9
+ */ /**
10
+ * Upper bound on the User-Agent length we are willing to scan. Real-world UA
11
+ * strings are comfortably under this, and browser/OS tokens always appear early,
12
+ * so clamping protects against pathologically large attacker-controlled headers
13
+ * without losing accuracy for legitimate clients.
14
+ */ const MAX_UA_LENGTH = 1024;
15
+ const detectBrowser = (ua)=>{
16
+ // Order matters: more specific tokens must be checked first.
17
+ if (/\bEdg(?:e|A|iOS)?\//.test(ua)) return 'Edge';
18
+ if (/\b(?:OPR|Opera)\//.test(ua)) return 'Opera';
19
+ if (/\b(?:SamsungBrowser)\//.test(ua)) return 'Samsung Internet';
20
+ // Chromium forks below ship a "Chrome/" token too, so they must be matched
21
+ // before the generic Chrome check or they'd all collapse into "Chrome".
22
+ if (/\bVivaldi\//.test(ua)) return 'Vivaldi';
23
+ if (/\b(?:YaBrowser|Yowser)\//.test(ua)) return 'Yandex Browser';
24
+ if (/\bBrave\//.test(ua)) return 'Brave';
25
+ if (/\b(?:Firefox|FxiOS)\//.test(ua)) return 'Firefox';
26
+ if (/\b(?:Chrome|CriOS|Chromium)\//.test(ua)) return 'Chrome';
27
+ // Safari ships "Safari/xxx" but so do Chrome/Edge; only treat as Safari when no Chrome token.
28
+ if (/\bVersion\/[\d.]+ (?:Mobile\/\S+ )?Safari\//.test(ua) || /\bSafari\//.test(ua)) {
29
+ return 'Safari';
30
+ }
31
+ return undefined;
32
+ };
33
+ const detectOS = (ua)=>{
34
+ if (/\bWindows NT\b/.test(ua)) return 'Windows';
35
+ if (/\b(?:iPhone|iPad|iPod)\b/.test(ua)) return 'iOS';
36
+ if (/\bAndroid\b/.test(ua)) return 'Android';
37
+ // "Mac OS X" appears on iOS too, so this must come after the iOS check.
38
+ if (/\b(?:Macintosh|Mac OS X)\b/.test(ua)) return 'macOS';
39
+ if (/\bCrOS\b/.test(ua)) return 'ChromeOS';
40
+ if (/\bLinux\b/.test(ua)) return 'Linux';
41
+ return undefined;
42
+ };
43
+ /**
44
+ * Parses a User-Agent string into a best-effort browser/OS and a display label.
45
+ * Returns an empty object when the input is missing or unrecognized.
46
+ */ const parseUserAgent = (userAgent)=>{
47
+ if (!userAgent || typeof userAgent !== 'string') {
48
+ return {};
49
+ }
50
+ // Clamp before scanning so an oversized header cannot drive the regex work.
51
+ const ua = userAgent.length > MAX_UA_LENGTH ? userAgent.slice(0, MAX_UA_LENGTH) : userAgent;
52
+ const browser = detectBrowser(ua);
53
+ const os = detectOS(ua);
54
+ let deviceName;
55
+ if (browser && os) {
56
+ deviceName = `${browser} on ${os}`;
57
+ } else if (browser) {
58
+ deviceName = browser;
59
+ } else if (os) {
60
+ deviceName = os;
61
+ }
62
+ return {
63
+ browser,
64
+ os,
65
+ deviceName
66
+ };
67
+ };
68
+ /**
69
+ * Convenience helper returning only the human-readable device label, or undefined.
70
+ */ const getDeviceName = (userAgent)=>parseUserAgent(userAgent).deviceName;
71
+
72
+ exports.getDeviceName = getDeviceName;
73
+ exports.parseUserAgent = parseUserAgent;
74
+ //# sourceMappingURL=user-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-agent.js","sources":["../src/user-agent.ts"],"sourcesContent":["/**\n * Minimal, dependency-free User-Agent parsing.\n *\n * This is intentionally heuristic and only aims to produce a human-readable label\n * (e.g. \"Chrome on macOS\") for displaying active sessions/devices. It is not a full\n * UA parser and should not be relied upon for feature detection.\n */\n\nexport interface ParsedUserAgent {\n browser?: string;\n os?: string;\n /** Human-readable label combining browser and OS, e.g. \"Chrome on macOS\". */\n deviceName?: string;\n}\n\n/**\n * Upper bound on the User-Agent length we are willing to scan. Real-world UA\n * strings are comfortably under this, and browser/OS tokens always appear early,\n * so clamping protects against pathologically large attacker-controlled headers\n * without losing accuracy for legitimate clients.\n */\nconst MAX_UA_LENGTH = 1024;\n\nconst detectBrowser = (ua: string): string | undefined => {\n // Order matters: more specific tokens must be checked first.\n if (/\\bEdg(?:e|A|iOS)?\\//.test(ua)) return 'Edge';\n if (/\\b(?:OPR|Opera)\\//.test(ua)) return 'Opera';\n if (/\\b(?:SamsungBrowser)\\//.test(ua)) return 'Samsung Internet';\n // Chromium forks below ship a \"Chrome/\" token too, so they must be matched\n // before the generic Chrome check or they'd all collapse into \"Chrome\".\n if (/\\bVivaldi\\//.test(ua)) return 'Vivaldi';\n if (/\\b(?:YaBrowser|Yowser)\\//.test(ua)) return 'Yandex Browser';\n if (/\\bBrave\\//.test(ua)) return 'Brave';\n if (/\\b(?:Firefox|FxiOS)\\//.test(ua)) return 'Firefox';\n if (/\\b(?:Chrome|CriOS|Chromium)\\//.test(ua)) return 'Chrome';\n // Safari ships \"Safari/xxx\" but so do Chrome/Edge; only treat as Safari when no Chrome token.\n if (/\\bVersion\\/[\\d.]+ (?:Mobile\\/\\S+ )?Safari\\//.test(ua) || /\\bSafari\\//.test(ua)) {\n return 'Safari';\n }\n return undefined;\n};\n\nconst detectOS = (ua: string): string | undefined => {\n if (/\\bWindows NT\\b/.test(ua)) return 'Windows';\n if (/\\b(?:iPhone|iPad|iPod)\\b/.test(ua)) return 'iOS';\n if (/\\bAndroid\\b/.test(ua)) return 'Android';\n // \"Mac OS X\" appears on iOS too, so this must come after the iOS check.\n if (/\\b(?:Macintosh|Mac OS X)\\b/.test(ua)) return 'macOS';\n if (/\\bCrOS\\b/.test(ua)) return 'ChromeOS';\n if (/\\bLinux\\b/.test(ua)) return 'Linux';\n return undefined;\n};\n\n/**\n * Parses a User-Agent string into a best-effort browser/OS and a display label.\n * Returns an empty object when the input is missing or unrecognized.\n */\nexport const parseUserAgent = (userAgent?: string | null): ParsedUserAgent => {\n if (!userAgent || typeof userAgent !== 'string') {\n return {};\n }\n\n // Clamp before scanning so an oversized header cannot drive the regex work.\n const ua = userAgent.length > MAX_UA_LENGTH ? userAgent.slice(0, MAX_UA_LENGTH) : userAgent;\n\n const browser = detectBrowser(ua);\n const os = detectOS(ua);\n\n let deviceName: string | undefined;\n if (browser && os) {\n deviceName = `${browser} on ${os}`;\n } else if (browser) {\n deviceName = browser;\n } else if (os) {\n deviceName = os;\n }\n\n return { browser, os, deviceName };\n};\n\n/**\n * Convenience helper returning only the human-readable device label, or undefined.\n */\nexport const getDeviceName = (userAgent?: string | null): string | undefined =>\n parseUserAgent(userAgent).deviceName;\n"],"names":["MAX_UA_LENGTH","detectBrowser","ua","test","undefined","detectOS","parseUserAgent","userAgent","length","slice","browser","os","deviceName","getDeviceName"],"mappings":";;AAAA;;;;;;;;;;;AAoBC,IACD,MAAMA,aAAAA,GAAgB,IAAA;AAEtB,MAAMC,gBAAgB,CAACC,EAAAA,GAAAA;;AAErB,IAAA,IAAI,qBAAA,CAAsBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,MAAA;AAC3C,IAAA,IAAI,mBAAA,CAAoBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,OAAA;AACzC,IAAA,IAAI,wBAAA,CAAyBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,kBAAA;;;AAG9C,IAAA,IAAI,aAAA,CAAcC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,SAAA;AACnC,IAAA,IAAI,0BAAA,CAA2BC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,gBAAA;AAChD,IAAA,IAAI,WAAA,CAAYC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,OAAA;AACjC,IAAA,IAAI,uBAAA,CAAwBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,SAAA;AAC7C,IAAA,IAAI,+BAAA,CAAgCC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,QAAA;;AAErD,IAAA,IAAI,8CAA8CC,IAAI,CAACD,OAAO,YAAA,CAAaC,IAAI,CAACD,EAAAA,CAAAA,EAAK;QACnF,OAAO,QAAA;AACT,IAAA;IACA,OAAOE,SAAAA;AACT,CAAA;AAEA,MAAMC,WAAW,CAACH,EAAAA,GAAAA;AAChB,IAAA,IAAI,gBAAA,CAAiBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,SAAA;AACtC,IAAA,IAAI,0BAAA,CAA2BC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,KAAA;AAChD,IAAA,IAAI,aAAA,CAAcC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,SAAA;;AAEnC,IAAA,IAAI,4BAAA,CAA6BC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,OAAA;AAClD,IAAA,IAAI,UAAA,CAAWC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,UAAA;AAChC,IAAA,IAAI,WAAA,CAAYC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,OAAA;IACjC,OAAOE,SAAAA;AACT,CAAA;AAEA;;;IAIO,MAAME,cAAAA,GAAiB,CAACC,SAAAA,GAAAA;AAC7B,IAAA,IAAI,CAACA,SAAAA,IAAa,OAAOA,SAAAA,KAAc,QAAA,EAAU;AAC/C,QAAA,OAAO,EAAC;AACV,IAAA;;IAGA,MAAML,EAAAA,GAAKK,UAAUC,MAAM,GAAGR,gBAAgBO,SAAAA,CAAUE,KAAK,CAAC,CAAA,EAAGT,aAAAA,CAAAA,GAAiBO,SAAAA;AAElF,IAAA,MAAMG,UAAUT,aAAAA,CAAcC,EAAAA,CAAAA;AAC9B,IAAA,MAAMS,KAAKN,QAAAA,CAASH,EAAAA,CAAAA;IAEpB,IAAIU,UAAAA;AACJ,IAAA,IAAIF,WAAWC,EAAAA,EAAI;AACjBC,QAAAA,UAAAA,GAAa,CAAA,EAAGF,OAAAA,CAAQ,IAAI,EAAEC,EAAAA,CAAAA,CAAI;AACpC,IAAA,CAAA,MAAO,IAAID,OAAAA,EAAS;QAClBE,UAAAA,GAAaF,OAAAA;AACf,IAAA,CAAA,MAAO,IAAIC,EAAAA,EAAI;QACbC,UAAAA,GAAaD,EAAAA;AACf,IAAA;IAEA,OAAO;AAAED,QAAAA,OAAAA;AAASC,QAAAA,EAAAA;AAAIC,QAAAA;AAAW,KAAA;AACnC;AAEA;;UAGaC,aAAAA,GAAgB,CAACN,YAC5BD,cAAAA,CAAeC,SAAAA,CAAAA,CAAWK;;;;;"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Minimal, dependency-free User-Agent parsing.
3
+ *
4
+ * This is intentionally heuristic and only aims to produce a human-readable label
5
+ * (e.g. "Chrome on macOS") for displaying active sessions/devices. It is not a full
6
+ * UA parser and should not be relied upon for feature detection.
7
+ */ /**
8
+ * Upper bound on the User-Agent length we are willing to scan. Real-world UA
9
+ * strings are comfortably under this, and browser/OS tokens always appear early,
10
+ * so clamping protects against pathologically large attacker-controlled headers
11
+ * without losing accuracy for legitimate clients.
12
+ */ const MAX_UA_LENGTH = 1024;
13
+ const detectBrowser = (ua)=>{
14
+ // Order matters: more specific tokens must be checked first.
15
+ if (/\bEdg(?:e|A|iOS)?\//.test(ua)) return 'Edge';
16
+ if (/\b(?:OPR|Opera)\//.test(ua)) return 'Opera';
17
+ if (/\b(?:SamsungBrowser)\//.test(ua)) return 'Samsung Internet';
18
+ // Chromium forks below ship a "Chrome/" token too, so they must be matched
19
+ // before the generic Chrome check or they'd all collapse into "Chrome".
20
+ if (/\bVivaldi\//.test(ua)) return 'Vivaldi';
21
+ if (/\b(?:YaBrowser|Yowser)\//.test(ua)) return 'Yandex Browser';
22
+ if (/\bBrave\//.test(ua)) return 'Brave';
23
+ if (/\b(?:Firefox|FxiOS)\//.test(ua)) return 'Firefox';
24
+ if (/\b(?:Chrome|CriOS|Chromium)\//.test(ua)) return 'Chrome';
25
+ // Safari ships "Safari/xxx" but so do Chrome/Edge; only treat as Safari when no Chrome token.
26
+ if (/\bVersion\/[\d.]+ (?:Mobile\/\S+ )?Safari\//.test(ua) || /\bSafari\//.test(ua)) {
27
+ return 'Safari';
28
+ }
29
+ return undefined;
30
+ };
31
+ const detectOS = (ua)=>{
32
+ if (/\bWindows NT\b/.test(ua)) return 'Windows';
33
+ if (/\b(?:iPhone|iPad|iPod)\b/.test(ua)) return 'iOS';
34
+ if (/\bAndroid\b/.test(ua)) return 'Android';
35
+ // "Mac OS X" appears on iOS too, so this must come after the iOS check.
36
+ if (/\b(?:Macintosh|Mac OS X)\b/.test(ua)) return 'macOS';
37
+ if (/\bCrOS\b/.test(ua)) return 'ChromeOS';
38
+ if (/\bLinux\b/.test(ua)) return 'Linux';
39
+ return undefined;
40
+ };
41
+ /**
42
+ * Parses a User-Agent string into a best-effort browser/OS and a display label.
43
+ * Returns an empty object when the input is missing or unrecognized.
44
+ */ const parseUserAgent = (userAgent)=>{
45
+ if (!userAgent || typeof userAgent !== 'string') {
46
+ return {};
47
+ }
48
+ // Clamp before scanning so an oversized header cannot drive the regex work.
49
+ const ua = userAgent.length > MAX_UA_LENGTH ? userAgent.slice(0, MAX_UA_LENGTH) : userAgent;
50
+ const browser = detectBrowser(ua);
51
+ const os = detectOS(ua);
52
+ let deviceName;
53
+ if (browser && os) {
54
+ deviceName = `${browser} on ${os}`;
55
+ } else if (browser) {
56
+ deviceName = browser;
57
+ } else if (os) {
58
+ deviceName = os;
59
+ }
60
+ return {
61
+ browser,
62
+ os,
63
+ deviceName
64
+ };
65
+ };
66
+ /**
67
+ * Convenience helper returning only the human-readable device label, or undefined.
68
+ */ const getDeviceName = (userAgent)=>parseUserAgent(userAgent).deviceName;
69
+
70
+ export { getDeviceName, parseUserAgent };
71
+ //# sourceMappingURL=user-agent.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-agent.mjs","sources":["../src/user-agent.ts"],"sourcesContent":["/**\n * Minimal, dependency-free User-Agent parsing.\n *\n * This is intentionally heuristic and only aims to produce a human-readable label\n * (e.g. \"Chrome on macOS\") for displaying active sessions/devices. It is not a full\n * UA parser and should not be relied upon for feature detection.\n */\n\nexport interface ParsedUserAgent {\n browser?: string;\n os?: string;\n /** Human-readable label combining browser and OS, e.g. \"Chrome on macOS\". */\n deviceName?: string;\n}\n\n/**\n * Upper bound on the User-Agent length we are willing to scan. Real-world UA\n * strings are comfortably under this, and browser/OS tokens always appear early,\n * so clamping protects against pathologically large attacker-controlled headers\n * without losing accuracy for legitimate clients.\n */\nconst MAX_UA_LENGTH = 1024;\n\nconst detectBrowser = (ua: string): string | undefined => {\n // Order matters: more specific tokens must be checked first.\n if (/\\bEdg(?:e|A|iOS)?\\//.test(ua)) return 'Edge';\n if (/\\b(?:OPR|Opera)\\//.test(ua)) return 'Opera';\n if (/\\b(?:SamsungBrowser)\\//.test(ua)) return 'Samsung Internet';\n // Chromium forks below ship a \"Chrome/\" token too, so they must be matched\n // before the generic Chrome check or they'd all collapse into \"Chrome\".\n if (/\\bVivaldi\\//.test(ua)) return 'Vivaldi';\n if (/\\b(?:YaBrowser|Yowser)\\//.test(ua)) return 'Yandex Browser';\n if (/\\bBrave\\//.test(ua)) return 'Brave';\n if (/\\b(?:Firefox|FxiOS)\\//.test(ua)) return 'Firefox';\n if (/\\b(?:Chrome|CriOS|Chromium)\\//.test(ua)) return 'Chrome';\n // Safari ships \"Safari/xxx\" but so do Chrome/Edge; only treat as Safari when no Chrome token.\n if (/\\bVersion\\/[\\d.]+ (?:Mobile\\/\\S+ )?Safari\\//.test(ua) || /\\bSafari\\//.test(ua)) {\n return 'Safari';\n }\n return undefined;\n};\n\nconst detectOS = (ua: string): string | undefined => {\n if (/\\bWindows NT\\b/.test(ua)) return 'Windows';\n if (/\\b(?:iPhone|iPad|iPod)\\b/.test(ua)) return 'iOS';\n if (/\\bAndroid\\b/.test(ua)) return 'Android';\n // \"Mac OS X\" appears on iOS too, so this must come after the iOS check.\n if (/\\b(?:Macintosh|Mac OS X)\\b/.test(ua)) return 'macOS';\n if (/\\bCrOS\\b/.test(ua)) return 'ChromeOS';\n if (/\\bLinux\\b/.test(ua)) return 'Linux';\n return undefined;\n};\n\n/**\n * Parses a User-Agent string into a best-effort browser/OS and a display label.\n * Returns an empty object when the input is missing or unrecognized.\n */\nexport const parseUserAgent = (userAgent?: string | null): ParsedUserAgent => {\n if (!userAgent || typeof userAgent !== 'string') {\n return {};\n }\n\n // Clamp before scanning so an oversized header cannot drive the regex work.\n const ua = userAgent.length > MAX_UA_LENGTH ? userAgent.slice(0, MAX_UA_LENGTH) : userAgent;\n\n const browser = detectBrowser(ua);\n const os = detectOS(ua);\n\n let deviceName: string | undefined;\n if (browser && os) {\n deviceName = `${browser} on ${os}`;\n } else if (browser) {\n deviceName = browser;\n } else if (os) {\n deviceName = os;\n }\n\n return { browser, os, deviceName };\n};\n\n/**\n * Convenience helper returning only the human-readable device label, or undefined.\n */\nexport const getDeviceName = (userAgent?: string | null): string | undefined =>\n parseUserAgent(userAgent).deviceName;\n"],"names":["MAX_UA_LENGTH","detectBrowser","ua","test","undefined","detectOS","parseUserAgent","userAgent","length","slice","browser","os","deviceName","getDeviceName"],"mappings":"AAAA;;;;;;;;;;;AAoBC,IACD,MAAMA,aAAAA,GAAgB,IAAA;AAEtB,MAAMC,gBAAgB,CAACC,EAAAA,GAAAA;;AAErB,IAAA,IAAI,qBAAA,CAAsBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,MAAA;AAC3C,IAAA,IAAI,mBAAA,CAAoBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,OAAA;AACzC,IAAA,IAAI,wBAAA,CAAyBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,kBAAA;;;AAG9C,IAAA,IAAI,aAAA,CAAcC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,SAAA;AACnC,IAAA,IAAI,0BAAA,CAA2BC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,gBAAA;AAChD,IAAA,IAAI,WAAA,CAAYC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,OAAA;AACjC,IAAA,IAAI,uBAAA,CAAwBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,SAAA;AAC7C,IAAA,IAAI,+BAAA,CAAgCC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,QAAA;;AAErD,IAAA,IAAI,8CAA8CC,IAAI,CAACD,OAAO,YAAA,CAAaC,IAAI,CAACD,EAAAA,CAAAA,EAAK;QACnF,OAAO,QAAA;AACT,IAAA;IACA,OAAOE,SAAAA;AACT,CAAA;AAEA,MAAMC,WAAW,CAACH,EAAAA,GAAAA;AAChB,IAAA,IAAI,gBAAA,CAAiBC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,SAAA;AACtC,IAAA,IAAI,0BAAA,CAA2BC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,KAAA;AAChD,IAAA,IAAI,aAAA,CAAcC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,SAAA;;AAEnC,IAAA,IAAI,4BAAA,CAA6BC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,OAAA;AAClD,IAAA,IAAI,UAAA,CAAWC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,UAAA;AAChC,IAAA,IAAI,WAAA,CAAYC,IAAI,CAACD,EAAAA,CAAAA,EAAK,OAAO,OAAA;IACjC,OAAOE,SAAAA;AACT,CAAA;AAEA;;;IAIO,MAAME,cAAAA,GAAiB,CAACC,SAAAA,GAAAA;AAC7B,IAAA,IAAI,CAACA,SAAAA,IAAa,OAAOA,SAAAA,KAAc,QAAA,EAAU;AAC/C,QAAA,OAAO,EAAC;AACV,IAAA;;IAGA,MAAML,EAAAA,GAAKK,UAAUC,MAAM,GAAGR,gBAAgBO,SAAAA,CAAUE,KAAK,CAAC,CAAA,EAAGT,aAAAA,CAAAA,GAAiBO,SAAAA;AAElF,IAAA,MAAMG,UAAUT,aAAAA,CAAcC,EAAAA,CAAAA;AAC9B,IAAA,MAAMS,KAAKN,QAAAA,CAASH,EAAAA,CAAAA;IAEpB,IAAIU,UAAAA;AACJ,IAAA,IAAIF,WAAWC,EAAAA,EAAI;AACjBC,QAAAA,UAAAA,GAAa,CAAA,EAAGF,OAAAA,CAAQ,IAAI,EAAEC,EAAAA,CAAAA,CAAI;AACpC,IAAA,CAAA,MAAO,IAAID,OAAAA,EAAS;QAClBE,UAAAA,GAAaF,OAAAA;AACf,IAAA,CAAA,MAAO,IAAIC,EAAAA,EAAI;QACbC,UAAAA,GAAaD,EAAAA;AACf,IAAA;IAEA,OAAO;AAAED,QAAAA,OAAAA;AAASC,QAAAA,EAAAA;AAAIC,QAAAA;AAAW,KAAA;AACnC;AAEA;;UAGaC,aAAAA,GAAgB,CAACN,YAC5BD,cAAAA,CAAeC,SAAAA,CAAAA,CAAWK;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAM1C,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,6BAA6B,CAAC;AAIrC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAK3C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAMvC,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,CAAC,MAAM,EAAE,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CACxD;AACD,MAAM,WAAW,YAAY;IAC3B,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,KAAK,EACb,OAAO,CAAC,EAAE,OAAO,KACd,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,wBAAwB,GAAG,CACrC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,KAAK,EACb,OAAO,CAAC,EAAE,OAAO,KACd,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,UAAU,UAAU;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,QAAA,MAAM,mBAAmB,SAAU,UAAU;;mBA8FlC,OAAO,MAAM,EAAE,OAAO,CAAC,UACtB,KAAK,kCAC0B,OAAO;;;;;CA+KjD,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAM1C,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,6BAA6B,CAAC;AAIrC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAK3C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAMvC,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,CAAC,MAAM,EAAE,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CACxD;AACD,MAAM,WAAW,YAAY;IAC3B,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,KAAK,EACb,OAAO,CAAC,EAAE,OAAO,KACd,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,wBAAwB,GAAG,CACrC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,KAAK,EACb,OAAO,CAAC,EAAE,OAAO,KACd,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,UAAU,UAAU;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,QAAA,MAAM,mBAAmB,GAAI,MAAM,UAAU;;mBA8FlC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,UACtB,KAAK,kCAC0B,OAAO;;;;;CA+KjD,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/validate/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,eAAe,kBAAmB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,KAAG,KAOtF,CAAC;AAEF,eAAO,MAAM,UAAU,+BACjB,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,KAC7B,CAAC,CAAC,GAAG,IAAI,EAAE,QAAQ,CAAC,CAAC,KAAK,GAAG,CAS/B,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/validate/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,eAAe,GAAI,eAAe;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,KAAG,KAOtF,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,EAC/C,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,KAC7B,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAS/B,CAAC"}
@@ -19,10 +19,10 @@ export declare const validateFields: (ctx?: Context | undefined, fields?: unknow
19
19
  export declare const defaultValidateFields: (ctx?: Context | undefined, fields?: unknown) => any;
20
20
  export declare const POPULATE_TRAVERSALS: string[];
21
21
  export declare const validatePopulate: (ctx?: PopulateContext | undefined, populate?: unknown, includes?: {
22
- fields?: string[] | undefined;
23
- sort?: string[] | undefined;
24
- filters?: string[] | undefined;
25
- populate?: string[] | undefined;
22
+ fields?: (typeof FIELDS_TRAVERSALS)[number][];
23
+ sort?: (typeof SORT_TRAVERSALS)[number][];
24
+ filters?: (typeof FILTER_TRAVERSALS)[number][];
25
+ populate?: (typeof POPULATE_TRAVERSALS)[number][];
26
26
  } | undefined) => any;
27
27
  export declare const defaultValidatePopulate: (ctx?: Context | undefined, populate?: unknown) => any;
28
28
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/validate/validators.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAIxD,UAAU,OAAO;IACf,MAAM,EAAE,KAAK,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;CACpC;AAED,UAAU,eAAgB,SAAQ,OAAO;IACvC,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,eAAO,MAAM,iBAAiB,UAM7B,CAAC;AAEF,eAAO,MAAM,eAAe,uFAoD3B,CAAC;AAEF,eAAO,MAAM,sBAAsB,uDAEjC,CAAC;AAEH,eAAO,MAAM,eAAe,UAO3B,CAAC;AAEF,eAAO,MAAM,YAAY,oFA2ExB,CAAC;AAEF,eAAO,MAAM,mBAAmB,oDAE9B,CAAC;AAEH,eAAO,MAAM,iBAAiB,UAA0D,CAAC;AAEzF,eAAO,MAAM,cAAc,sFA0C1B,CAAC;AAEF,eAAO,MAAM,qBAAqB,sDAEhC,CAAC;AAEH,eAAO,MAAM,mBAAmB,UAAwC,CAAC;AAEzE,eAAO,MAAM,gBAAgB;;;;;qBAiL5B,CAAC;AAEF,eAAO,MAAM,uBAAuB,wDAYlC,CAAC"}
1
+ {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/validate/validators.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAa,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAIxD,UAAU,OAAO;IACf,MAAM,EAAE,KAAK,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;CACpC;AAED,UAAU,eAAgB,SAAQ,OAAO;IACvC,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,eAAO,MAAM,iBAAiB,UAM7B,CAAC;AAEF,eAAO,MAAM,eAAe,uFAoD3B,CAAC;AAEF,eAAO,MAAM,sBAAsB,uDAEjC,CAAC;AAEH,eAAO,MAAM,eAAe,UAO3B,CAAC;AAEF,eAAO,MAAM,YAAY,oFA2ExB,CAAC;AAEF,eAAO,MAAM,mBAAmB,oDAE9B,CAAC;AAEH,eAAO,MAAM,iBAAiB,UAA0D,CAAC;AAEzF,eAAO,MAAM,cAAc,sFA0C1B,CAAC;AAEF,eAAO,MAAM,qBAAqB,sDAEhC,CAAC;AAsKH,eAAO,MAAM,mBAAmB,UAAwC,CAAC;AAEzE,eAAO,MAAM,gBAAgB;aAKd,CAAC,OAAO,iBAAiB,EAAE,MAAM,CAAC,EAAE;WACtC,CAAC,OAAO,eAAe,EAAE,MAAM,CAAC,EAAE;cAC/B,CAAC,OAAO,iBAAiB,EAAE,MAAM,CAAC,EAAE;eACnC,CAAC,OAAO,mBAAmB,EAAE,MAAM,CAAC,EAAE;qBA0LtD,CAAC;AAEF,eAAO,MAAM,uBAAuB,wDAYlC,CAAC"}
@@ -200,6 +200,143 @@ const validateFields = utils.asyncCurry(async (ctx, fields, include)=>{
200
200
  const defaultValidateFields = utils.asyncCurry(async (ctx, fields)=>{
201
201
  return validateFields(ctx, fields, FIELDS_TRAVERSALS);
202
202
  });
203
+ const isMorphLikeAttribute = (attribute)=>contentTypes.isDynamicZoneAttribute(attribute) || contentTypes.isMorphToRelationalAttribute(attribute);
204
+ const isPopulatableAttribute = (attribute)=>!!attribute && [
205
+ 'relation',
206
+ 'dynamiczone',
207
+ 'component',
208
+ 'media'
209
+ ].includes(attribute.type);
210
+ const isDotNotationPopulate = (populate)=>{
211
+ if (populate === '*') {
212
+ return false;
213
+ }
214
+ if (typeof populate === 'string') {
215
+ return true;
216
+ }
217
+ return Array.isArray(populate) && populate.length > 0 && populate.every((p)=>typeof p === 'string');
218
+ };
219
+ const flattenDotPopulatePaths = (populate)=>{
220
+ const items = Array.isArray(populate) ? populate : [
221
+ populate
222
+ ];
223
+ return items.flatMap((item)=>item.split(',').map((segment)=>fp.trim(segment)).filter(Boolean));
224
+ };
225
+ const validatePopulateDotPathSegments = ({ schema, getModel }, segments, pathPrefix)=>{
226
+ if (!segments.length) {
227
+ return;
228
+ }
229
+ const [head, ...tail] = segments;
230
+ const fullPath = pathPrefix ? `${pathPrefix}.${head}` : head;
231
+ const attribute = schema.attributes[head];
232
+ if (!attribute || !isPopulatableAttribute(attribute)) {
233
+ utils.throwInvalidKey({
234
+ key: head,
235
+ path: fullPath
236
+ });
237
+ }
238
+ if (!tail.length) {
239
+ return;
240
+ }
241
+ if (attribute.type === 'component') {
242
+ if (!attribute.component) {
243
+ utils.throwInvalidKey({
244
+ key: head,
245
+ path: fullPath
246
+ });
247
+ }
248
+ validatePopulateDotPathSegments({
249
+ schema: getModel(attribute.component),
250
+ getModel
251
+ }, tail, fullPath);
252
+ return;
253
+ }
254
+ if (attribute.type === 'relation') {
255
+ if (isMorphLikeAttribute(attribute)) {
256
+ utils.throwInvalidKey({
257
+ key: head,
258
+ path: fullPath
259
+ });
260
+ }
261
+ if (!attribute.target) {
262
+ utils.throwInvalidKey({
263
+ key: head,
264
+ path: fullPath
265
+ });
266
+ }
267
+ validatePopulateDotPathSegments({
268
+ schema: getModel(attribute.target),
269
+ getModel
270
+ }, tail, fullPath);
271
+ return;
272
+ }
273
+ if (attribute.type === 'media') {
274
+ utils.throwInvalidKey({
275
+ key: head,
276
+ path: fullPath
277
+ });
278
+ }
279
+ if (attribute.type === 'dynamiczone') {
280
+ const [nextSegment, ...rest] = tail;
281
+ const nextPath = `${fullPath}.${nextSegment}`;
282
+ const candidates = (attribute.components ?? []).map((uid)=>getModel(uid)).filter((model)=>model?.attributes?.[nextSegment]);
283
+ if (!candidates.length) {
284
+ utils.throwInvalidKey({
285
+ key: nextSegment,
286
+ path: nextPath
287
+ });
288
+ }
289
+ let validated = false;
290
+ for (const componentSchema of candidates){
291
+ const nestedAttribute = componentSchema.attributes[nextSegment];
292
+ try {
293
+ if (!rest.length) {
294
+ if (nestedAttribute) {
295
+ validated = true;
296
+ break;
297
+ }
298
+ } else if (nestedAttribute?.type === 'component' && nestedAttribute.component) {
299
+ validatePopulateDotPathSegments({
300
+ schema: getModel(nestedAttribute.component),
301
+ getModel
302
+ }, rest, nextPath);
303
+ validated = true;
304
+ break;
305
+ } else if (nestedAttribute?.type === 'relation' && !isMorphLikeAttribute(nestedAttribute) && nestedAttribute.target) {
306
+ validatePopulateDotPathSegments({
307
+ schema: getModel(nestedAttribute.target),
308
+ getModel
309
+ }, rest, nextPath);
310
+ validated = true;
311
+ break;
312
+ }
313
+ } catch {
314
+ // Try the next dynamic-zone component type.
315
+ }
316
+ }
317
+ if (!validated) {
318
+ utils.throwInvalidKey({
319
+ key: nextSegment,
320
+ path: nextPath
321
+ });
322
+ }
323
+ }
324
+ };
325
+ const validatePopulateDotPaths = (ctx, populate)=>{
326
+ for (const path of flattenDotPopulatePaths(populate)){
327
+ const segments = path.split('.').map((segment)=>fp.trim(segment)).filter(Boolean);
328
+ validatePopulateDotPathSegments(ctx, segments, '');
329
+ }
330
+ };
331
+ const validateMorphLikeNestedPopulate = (populateValue, { path })=>{
332
+ // Keep in sync with convert-query-params polymorphic nested populate handling.
333
+ if (!fp.isNil(populateValue) && populateValue !== '*') {
334
+ utils.throwInvalidKey({
335
+ key: 'populate',
336
+ path
337
+ });
338
+ }
339
+ };
203
340
  const POPULATE_TRAVERSALS = [
204
341
  'nonAttributesOperators',
205
342
  'private'
@@ -208,6 +345,16 @@ const validatePopulate = utils.asyncCurry(async (ctx, populate, includes)=>{
208
345
  if (!ctx.schema) {
209
346
  throw new Error('Missing schema in defaultValidatePopulate');
210
347
  }
348
+ if (isDotNotationPopulate(populate)) {
349
+ validatePopulateDotPaths({
350
+ schema: ctx.schema,
351
+ getModel: ctx.getModel
352
+ }, populate);
353
+ if (includes?.populate?.includes('private')) {
354
+ return queryPopulate(throwPrivate, ctx)(populate);
355
+ }
356
+ return populate;
357
+ }
211
358
  // Build the list of functions conditionally based on the include array
212
359
  const functionsToApply = [];
213
360
  // Always include the main traversal function
@@ -224,6 +371,11 @@ const validatePopulate = utils.asyncCurry(async (ctx, populate, includes)=>{
224
371
  'component',
225
372
  'media'
226
373
  ].includes(attribute.type);
374
+ if (isMorphLikeAttribute(attribute) && fp.isObject(value) && 'populate' in value) {
375
+ validateMorphLikeNestedPopulate(value.populate, {
376
+ path: path.raw
377
+ });
378
+ }
227
379
  // Throw on non-populate attributes
228
380
  if (!isPopulatableAttribute) {
229
381
  utils.throwInvalidKey({